Merge pull request #464 from arvidn/listen-multi-homed

improve support for listening on multiple sockets and interfaces
This commit is contained in:
Arvid Norberg 2016-02-13 13:40:09 -08:00
commit a69de84482
20 changed files with 799 additions and 594 deletions

View File

@ -1,3 +1,6 @@
* improved support for bind-to-device
* deprecated ssl_listen, SSL sockets are specified in listen_interfaces now
* improved support for listening on multiple sockets and interfaces
* resume data no longer has timestamps of files
1.1.0 release

View File

@ -588,13 +588,11 @@ int print_peer_info(std::string& out
return pos;
}
int listen_port = 6881;
int allocation_mode = libtorrent::storage_mode_sparse;
std::string save_path(".");
int torrent_upload_limit = 0;
int torrent_download_limit = 0;
std::string monitor_dir;
std::string bind_to_interface = "";
int poll_interval = 5;
int max_connections_per_torrent = 50;
bool seed_mode = false;
@ -1238,7 +1236,6 @@ int main(int argc, char* argv[])
" -v <limit> Set the max number of active downloads\n"
" -^ <limit> Set the max number of active seeds\n"
"\n NETWORK OPTIONS\n"
" -p <port> sets the listen port\n"
#ifndef TORRENT_NO_DEPRECATE
" -o <limit> limits the number of simultaneous\n"
" half-open TCP connections to the\n"
@ -1257,10 +1254,14 @@ int main(int argc, char* argv[])
" incoming TCP connections)\n"
" -J Disable uTP connections (disable outgoing uTP and reject\n"
" incoming uTP connections)\n"
" -b <IP> sets IP of the interface to bind the\n"
" -b <iface-list> sets the listen interfaces string. This is a\n"
" comma separated list of IP:port pairs. Instead\n"
" of an IP, a network interface device name can\n"
" be specified\n"
" listen socket to\n"
" -I <IP> sets the IP of the interface to bind\n"
" outgoing peer connections to\n"
" -I <iface-list> sets the IPs or network interface devices to bind\n"
" outgoing peer connections to. This can be a\n"
" comma-separated list"
#if TORRENT_USE_I2P
" -i <i2p-host> the hostname to an I2P SAM bridge to use\n"
#endif
@ -1361,7 +1362,6 @@ int main(int argc, char* argv[])
case 'o': settings.set_int(settings_pack::half_open_limit, atoi(arg)); break;
#endif
case 'h': settings.set_bool(settings_pack::allow_multiple_connections_per_ip, true); --i; break;
case 'p': listen_port = atoi(arg); break;
case 'k': high_performance_seed(settings); --i; break;
case 'j': settings.set_bool(settings_pack::use_disk_read_ahead, false); --i; break;
case 'z': settings.set_bool(settings_pack::disable_hash_checks, true); --i; break;
@ -1386,7 +1386,7 @@ int main(int argc, char* argv[])
case 'D': torrent_download_limit = atoi(arg) * 1000; break;
case 'm': monitor_dir = arg; break;
case 'Q': share_mode = true; --i; break;
case 'b': bind_to_interface = arg; break;
case 'b': settings.set_str(settings_pack::listen_interfaces, arg); break;
case 'w': settings.set_int(settings_pack::urlseed_wait_retry, atoi(arg)); break;
case 't': poll_interval = atoi(arg); break;
case 'F': refresh_delay = atoi(arg); break;
@ -1533,12 +1533,6 @@ int main(int argc, char* argv[])
fprintf(stderr, "failed to create resume file directory: (%d) %s\n"
, errno, strerror(errno));
if (bind_to_interface.empty()) bind_to_interface = "0.0.0.0";
char iface_str[100];
snprintf(iface_str, sizeof(iface_str), "%s:%d", bind_to_interface.c_str()
, listen_port);
settings.set_str(settings_pack::listen_interfaces, iface_str);
settings.set_str(settings_pack::user_agent, "client_test/" LIBTORRENT_VERSION);
settings.set_int(settings_pack::alert_mask, alert::all_categories
& ~(alert::dht_notification

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

@ -1268,7 +1268,7 @@ namespace libtorrent
listen_failed_alert(
aux::stack_allocator& alloc
, std::string const& iface
, int port
, tcp::endpoint const& ep
, int op
, error_code const& ec
, socket_type_t t);
@ -1278,7 +1278,7 @@ namespace libtorrent
static const int static_category = alert::status_notification | alert::error_notification;
virtual std::string message() const TORRENT_OVERRIDE;
// the interface libtorrent attempted to listen on that failed.
// the network device libtorrent attempted to listen on, or the IP address
char const* listen_interface() const;
// the error the system returned
@ -1286,7 +1286,7 @@ namespace libtorrent
enum op_t
{
parse_addr, open, bind, listen, get_peer_name, accept
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

@ -124,12 +124,21 @@ namespace libtorrent
struct listen_socket_t
{
listen_socket_t(): external_port(0), ssl(false) {}
listen_socket_t()
: tcp_external_port(0)
, ssl(false)
{
tcp_port_mapping[0] = -1;
tcp_port_mapping[1] = -1;
}
// this is typically empty but can be set
// to the WAN IP address of NAT-PMP or UPnP router
address external_address;
// this is a cached local endpoint for the listen socket
tcp::endpoint local_endpoint;
// this is typically set to the same as the local
// listen port. In case a NAT port forward was
// successfully opened, this will be set to the
@ -137,7 +146,10 @@ namespace libtorrent
// on the NAT box itself. This is the port that has
// to be published to peers, since this is the port
// the client is reachable through.
int external_port;
int tcp_external_port;
// 0 is natpmp 1 is upnp
int tcp_port_mapping[2];
// set to true if this is an SSL listen socket
bool ssl;
@ -616,6 +628,11 @@ namespace libtorrent
libtorrent::utp_socket_manager* utp_socket_manager() TORRENT_OVERRIDE
{ return &m_utp_socket_manager; }
#ifdef TORRENT_USE_OPENSSL
libtorrent::utp_socket_manager* ssl_utp_socket_manager() TORRENT_OVERRIDE
{ return &m_ssl_utp_socket_manager; }
#endif
void inc_boost_connections() TORRENT_OVERRIDE { ++m_boost_connections; }
#ifndef TORRENT_NO_DEPRECATE
@ -625,6 +642,13 @@ namespace libtorrent
// update any rss feeds that need updating and
// recalculate m_next_rss_update
void update_rss_feeds();
void update_ssl_listen();
void update_dht_upload_rate_limit();
void update_local_download_rate();
void update_local_upload_rate();
void update_rate_limit_utp();
void update_ignore_rate_limits_on_local_network();
#endif
void update_proxy();
@ -635,9 +659,6 @@ namespace libtorrent
void update_connection_speed();
void update_queued_disk_bytes();
void update_alert_queue_size();
#ifndef TORRENT_NO_DEPRECATE
void update_dht_upload_rate_limit();
#endif
void update_disk_threads();
void update_network_threads();
void update_cache_buffer_chunk_size();
@ -662,12 +683,6 @@ namespace libtorrent
void update_download_rate();
void update_upload_rate();
void update_connections_limit();
#ifndef TORRENT_NO_DEPRECATE
void update_local_download_rate();
void update_local_upload_rate();
void update_rate_limit_utp();
void update_ignore_rate_limits_on_local_network();
#endif
void update_alert_mask();
void trigger_auto_manage() TORRENT_OVERRIDE;
@ -835,11 +850,7 @@ namespace libtorrent
// 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
std::vector<std::pair<std::string, int> > m_listen_interfaces;
// keep this around until everything uses the list of interfaces
// instead.
tcp::endpoint m_listen_interface;
std::vector<listen_interface_t> m_listen_interfaces;
// the network interfaces outgoing connections are opened through. If
// there is more then one, they are used in a round-robin fashion
@ -850,12 +861,6 @@ namespace libtorrent
// socket fails.
std::vector<std::string> m_outgoing_interfaces;
// if we're listening on an IPv6 interface
// this is one of the non local IPv6 interfaces
// on this machine
tcp::endpoint m_ipv6_interface;
tcp::endpoint m_ipv4_interface;
// since we might be listening on multiple interfaces
// we might need more than one listen socket
std::list<listen_socket_t> m_listen_sockets;
@ -887,8 +892,7 @@ namespace libtorrent
};
listen_socket_t setup_listener(std::string const& device
, boost::asio::ip::tcp const& protocol, int port, int flags
, error_code& ec);
, tcp::endpoint bind_ep, int flags, error_code& ec);
#ifndef TORRENT_DISABLE_DHT
entry m_dht_state;
@ -1026,6 +1030,7 @@ namespace libtorrent
// see m_external_listen_port. This is the same
// but for the udp port used by the DHT.
// TODO: 3 once udp sockets are part of m_listen_sockets, remove this
int m_external_udp_port;
udp_socket m_udp_socket;
@ -1046,18 +1051,18 @@ namespace libtorrent
boost::shared_ptr<upnp> m_upnp;
boost::shared_ptr<lsd> m_lsd;
// TODO: 3 once the udp socket is in listen_socket_t, these should
// move in there too
// 0 is natpmp 1 is upnp
int m_udp_mapping[2];
#ifdef TORRENT_USE_OPENSSL
int m_ssl_udp_mapping[2];
#endif
// mask is a bitmask of which protocols to remap on:
// 1: NAT-PMP
// 2: UPnP
void remap_tcp_ports(boost::uint32_t mask, int tcp_port, int ssl_port);
// 0 is natpmp 1 is upnp
int m_tcp_mapping[2];
int m_udp_mapping[2];
#ifdef TORRENT_USE_OPENSSL
int m_ssl_tcp_mapping[2];
int m_ssl_udp_mapping[2];
#endif
void remap_ports(boost::uint32_t mask, listen_socket_t& s);
// the timer used to fire the tick
deadline_timer m_timer;

View File

@ -246,6 +246,7 @@ namespace libtorrent { namespace aux
virtual void prioritize_connections(boost::weak_ptr<torrent> t) = 0;
// TODO: 3 these should go away!
virtual tcp::endpoint get_ipv6_interface() const = 0;
virtual tcp::endpoint get_ipv4_interface() const = 0;
@ -318,6 +319,7 @@ namespace libtorrent { namespace aux
virtual std::vector<block_info>& block_info_storage() = 0;
#ifdef TORRENT_USE_OPENSSL
virtual libtorrent::utp_socket_manager* ssl_utp_socket_manager() = 0;
virtual boost::asio::ssl::context* ssl_ctx() = 0 ;
#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

@ -163,20 +163,29 @@ namespace libtorrent
// connections.
outgoing_interfaces,
// a comma-separated list of IP port-pairs. These
// are the listen ports that will be opened for accepting incoming uTP
// and TCP connections. It is possible to listen on multiple
// IPs and multiple ports. Binding to port 0 will make the
// operating system pick the port. The default is "0.0.0.0:6881", which
// binds to all interfaces on port 6881.
//
// if binding fails, the listen_failed_alert is posted, potentially
// more than once. Once/if binding the listen socket(s) succeed,
// listen_succeeded_alert is posted.
//
// Each port will attempt to open both a UDP and a TCP listen socket,
// to allow accepting uTP connections as well as TCP. If using the DHT,
// this will also make the DHT use the same UDP ports.
// a comma-separated list of (IP or device name, port) pairs. These are
// the listen ports that will be opened for accepting incoming uTP and
// TCP connections. It is possible to listen on multiple interfaces and
// multiple ports. Binding to port 0 will make the operating system
// pick the port. The default is "0.0.0.0:6881,[::]:6881", which binds
// to all interfaces on port 6881.
//
// a port that has an "s" suffix will accept SSL connections. (note
// that SSL sockets are not enabled by default).
//
// if binding fails, the listen_failed_alert is posted. If or once a
// socket binding succeeds, the listen_succeeded_alert is posted. There
// may be multiple failures before a success.
//
// For example:
// ``[::1]:8888`` - will only accept connections on the IPv6 loopback
// address on port 8888.
//
// ``eth0:4444,eth1:4444`` - will accept connections on port 4444 on
// any IP address bound to device ``eth0`` or ``eth1``.
//
// ``[::]:0s`` - will accept SSL connections on a port chosen by the
// OS. And not accept non-SSL connections at all.
//
// .. note::
// The current support for opening arbitrary UDP sockets is limited.
@ -1418,12 +1427,17 @@ namespace libtorrent
// SSL encryption as well.
network_threads,
#ifndef TORRENT_NO_DEPRECATE
// ``ssl_listen`` sets the listen port for SSL connections. If this is
// set to 0, no SSL listen port is opened. Otherwise a socket is
// opened on this port. This setting is only taken into account when
// opening the regular listen port, and won't re-open the listen
// socket simply by changing this setting.
ssl_listen,
#else
// hidden
deprecated9,
#endif
// ``tracker_backoff`` determines how aggressively to back off from
// retrying failing trackers. This value determines *x* in the

View File

@ -67,11 +67,21 @@ namespace libtorrent
TORRENT_EXTRA_EXPORT void url_random(char* begin, char* end);
struct listen_interface_t
{
std::string device;
int port;
bool ssl;
};
// this parses the string that's used as the liste_interfaces setting.
// it is a comma-separated list of IP or device names with ports. For
// example: "eth0:6881,eth1:6881" or "127.0.0.1:6881"
TORRENT_EXTRA_EXPORT void parse_comma_separated_string_port(
std::string const& in, std::vector<std::pair<std::string, int> >& out);
TORRENT_EXTRA_EXPORT void parse_listen_interfaces(
std::string const& in, std::vector<listen_interface_t>& out);
TORRENT_EXTRA_EXPORT std::string print_listen_interfaces(
std::vector<listen_interface_t> const& in);
// this parses the string that's used as the outgoing_interfaces setting.
// it is a comma separated list of IPs and device names. For example:

View File

@ -723,8 +723,7 @@ namespace libtorrent
void force_tracker_request(time_point, int tracker_idx);
void scrape_tracker(int idx, bool user_triggered);
void announce_with_tracker(boost::uint8_t e
= tracker_request::none
, address const& bind_interface = address_v4::any());
= tracker_request::none);
int seconds_since_last_scrape() const
{
return m_last_scrape == (std::numeric_limits<boost::int16_t>::min)()

View File

@ -134,7 +134,7 @@ class TORRENT_EXTRA_EXPORT upnp : public boost::enable_shared_from_this<upnp>
{
public:
upnp(io_service& ios
, address const& listen_interface, std::string const& user_agent
, std::string const& user_agent
, portmap_callback_t const& cb, log_callback_t const& lcb
, bool ignore_nonrouters);
~upnp();

View File

@ -786,26 +786,19 @@ namespace libtorrent {
"HTTPS",
"SSL/uTP"
};
tcp::endpoint parse_interface(std::string const& iface, int port)
{
// ignore errors
error_code ec;
return tcp::endpoint(address::from_string(iface, ec), port);
}
}
listen_failed_alert::listen_failed_alert(
aux::stack_allocator& alloc
, std::string const& iface
, int prt
, tcp::endpoint const& ep
, int op
, error_code const& ec
, socket_type_t t)
: error(ec)
, operation(op)
, sock_type(t)
, endpoint(parse_interface(iface, prt))
, endpoint(ep)
, m_alloc(alloc)
, m_interface_idx(alloc.copy_string(iface))
{}
@ -823,11 +816,14 @@ namespace libtorrent {
"open",
"bind",
"listen",
"get_peer_name",
"accept"
"get_socket_name",
"accept",
"enum_if",
"bind_to_device"
};
char ret[300];
snprintf(ret, sizeof(ret), "listening on %s failed: [%s] [%s] %s"
snprintf(ret, sizeof(ret), "listening on %s (device: %s) failed: [%s] [%s] %s"
, print_endpoint(endpoint).c_str()
, listen_interface()
, op_str[operation]
, sock_type_str[sock_type]

File diff suppressed because it is too large Load Diff

View File

@ -125,6 +125,12 @@ namespace libtorrent
using aux::session_impl;
#if TORRENT_USE_IPV6
#define DEFAULT_LISTEN_INTERFACE "0.0.0.0:6881,[::]:6881"
#else
#define DEFAULT_LISTEN_INTERFACE "0.0.0.0:6881"
#endif
str_setting_entry_t str_settings[settings_pack::num_string_settings] =
{
SET(user_agent, "libtorrent/" LIBTORRENT_VERSION, &session_impl::update_user_agent),
@ -132,7 +138,7 @@ namespace libtorrent
SET(mmap_cache, 0, 0),
SET(handshake_client_version, 0, 0),
SET_NOPREV(outgoing_interfaces, "", &session_impl::update_outgoing_interfaces),
SET_NOPREV(listen_interfaces, "0.0.0.0:6881", &session_impl::update_listen_interfaces),
SET_NOPREV(listen_interfaces, DEFAULT_LISTEN_INTERFACE, &session_impl::update_listen_interfaces),
SET_NOPREV(proxy_hostname, "", &session_impl::update_proxy),
SET_NOPREV(proxy_username, "", &session_impl::update_proxy),
SET_NOPREV(proxy_password, "", &session_impl::update_proxy),
@ -140,6 +146,8 @@ namespace libtorrent
SET_NOPREV(peer_fingerprint, "-LT1100-", &session_impl::update_peer_fingerprint)
};
#undef DEFAULT_LISTEN_INTERFACE
bool_setting_entry_t bool_settings[settings_pack::num_bool_settings] =
{
SET(allow_multiple_connections_per_ip, false, 0),
@ -322,7 +330,7 @@ namespace libtorrent
SET(aio_threads, 4, &session_impl::update_disk_threads),
SET(aio_max, 300, 0),
SET(network_threads, 0, &session_impl::update_network_threads),
SET(ssl_listen, 4433, 0),
DEPRECATED_SET(ssl_listen, 4433, &session_impl::update_ssl_listen),
SET(tracker_backoff, 250, 0),
SET_NOPREV(share_ratio_limit, 200, 0),
SET_NOPREV(seed_time_ratio_limit, 700, 0),

View File

@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/random.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/parse_url.hpp"
#include "libtorrent/address.hpp"
#include "libtorrent/aux_/disable_warnings_push.hpp"
@ -168,11 +169,42 @@ namespace libtorrent
return static_cast<char*>(p) + (8 - offset);
}
std::string print_listen_interfaces(std::vector<listen_interface_t> const& in)
{
std::string ret;
for (std::vector<listen_interface_t>::const_iterator i = in.begin()
, end(in.end()); i != end; ++i)
{
if (i != in.begin()) ret += ",";
#if TORRENT_USE_IPV6
error_code ec;
address_v6::from_string(i->device, ec);
if (!ec)
{
// IPv6 addresses must be wrapped in square brackets
ret += "[";
ret += i->device;
ret += "]";
}
else
#endif
{
ret += i->device;
}
ret += ":";
ret += to_string(i->port).elems;
if (i->ssl) ret += "s";
}
return ret;
}
// this parses the string that's used as the liste_interfaces setting.
// it is a comma-separated list of IP or device names with ports. For
// example: "eth0:6881,eth1:6881" or "127.0.0.1:6881"
void parse_comma_separated_string_port(std::string const& in
, std::vector<std::pair<std::string, int> >& out)
void parse_listen_interfaces(std::string const& in
, std::vector<listen_interface_t>& out)
{
out.clear();
@ -193,7 +225,11 @@ namespace libtorrent
if (colon != std::string::npos && colon > start)
{
int port = atoi(in.substr(colon + 1, end - colon - 1).c_str());
listen_interface_t iface;
std::string port_string = in.substr(colon + 1, end - colon - 1);
iface.ssl = !port_string.empty() && port_string[port_string.size()-1] == 's';
iface.port = atoi(port_string.c_str());
// skip trailing spaces
std::string::size_type soft_end = colon;
@ -206,7 +242,8 @@ namespace libtorrent
if (in[start] == '[') ++start;
if (soft_end > start && in[soft_end-1] == ']') --soft_end;
out.push_back(std::make_pair(in.substr(start, soft_end - start), port));
iface.device = in.substr(start, soft_end - start);
out.push_back(iface);
}
start = end + 1;

View File

@ -3058,8 +3058,7 @@ namespace libtorrent
#endif
void torrent::announce_with_tracker(boost::uint8_t e
, address const& bind_interface)
void torrent::announce_with_tracker(boost::uint8_t e)
{
TORRENT_ASSERT(is_single_thread());
INVARIANT_CHECK;
@ -3183,8 +3182,6 @@ namespace libtorrent
req.triggered_manually = ae.triggered_manually;
ae.triggered_manually = false;
req.bind_ip = bind_interface;
if (settings().get_bool(settings_pack::force_proxy))
{
// in force_proxy mode we don't talk directly to trackers
@ -3574,6 +3571,8 @@ namespace libtorrent
// matches one of the listen interfaces, since that means this
// announce was the second one
// TODO: 3 instead of announcing once per IP version, announce once per
// listen interface (i.e. m_listen_sockets)
if (((!is_any(m_ses.get_ipv6_interface().address()) && tracker_ip.is_v4())
|| (!is_any(m_ses.get_ipv4_interface().address()) && tracker_ip.is_v6()))
&& r.bind_ip != m_ses.get_ipv4_interface().address()
@ -7630,6 +7629,9 @@ namespace libtorrent
if (is_ssl_torrent() && settings().get_int(settings_pack::ssl_listen) != 0)
{
userdata = m_ssl_ctx.get();
// if we're creating a uTP socket, since this is SSL now, make sure
// to pass in the corresponding utp socket manager
if (sm) sm = m_ses.ssl_utp_socket_manager();
}
#endif

View File

@ -69,8 +69,11 @@ namespace upnp_errors
static error_code ignore_error;
// TODO: 3 bind the broadcast socket. it would probably have to be changed to a vector of interfaces to
// bind to, since the broadcast socket opens one socket per local
// interface by default
upnp::upnp(io_service& ios
, address const& listen_interface, std::string const& user_agent
, std::string const& user_agent
, portmap_callback_t const& cb, log_callback_t const& lcb
, bool ignore_nonrouters)
: m_user_agent(user_agent)
@ -90,12 +93,6 @@ upnp::upnp(io_service& ios
, m_last_if_update(min_time())
{
TORRENT_ASSERT(cb);
// TODO: 3 listen_interface is not used. It's meant to bind the broadcast
// socket. it would probably have to be changed to a vector of interfaces to
// bind to though, since the broadcast socket opens one socket per local
// interface by default
TORRENT_UNUSED(listen_interface);
}
void upnp::start()

View File

@ -100,8 +100,11 @@ bool on_alert(alert const* a)
if (peer_disconnected_alert const* e = alert_cast<peer_disconnected_alert>(a))
{
++peer_disconnects;
if (e->error.category() == boost::asio::error::get_ssl_category())
if (strcmp(e->error.category().name(), boost::asio::error::get_ssl_category().name()) == 0)
++ssl_peer_disconnects;
fprintf(stderr, "--- peer_errors: %d ssl_disconnects: %d\n"
, peer_errors, ssl_peer_disconnects);
}
if (peer_error_alert const* e = alert_cast<peer_error_alert>(a))
@ -109,8 +112,11 @@ bool on_alert(alert const* a)
++peer_disconnects;
++peer_errors;
if (e->error.category() == boost::asio::error::get_ssl_category())
if (strcmp(e->error.category().name(), boost::asio::error::get_ssl_category().name()) == 0)
++ssl_peer_disconnects;
fprintf(stderr, "--- peer_errors: %d ssl_disconnects: %d\n"
, peer_errors, ssl_peer_disconnects);
}
return false;
}
@ -132,11 +138,14 @@ void test_ssl(int test_idx, bool use_utp)
remove_all("tmp1_ssl", ec);
remove_all("tmp2_ssl", ec);
int ssl_port = 1024 + rand() % 50000;
int port = 1024 + rand() % 50000;
settings_pack sett;
sett.set_int(settings_pack::alert_mask, alert_mask);
sett.set_int(settings_pack::max_retry_port_bind, 100);
sett.set_str(settings_pack::listen_interfaces, "0.0.0.0:48075");
char listen_iface[100];
snprintf(listen_iface, sizeof(listen_iface), "0.0.0.0:%ds", port);
sett.set_str(settings_pack::listen_interfaces, listen_iface);
sett.set_bool(settings_pack::enable_incoming_utp, use_utp);
sett.set_bool(settings_pack::enable_outgoing_utp, use_utp);
sett.set_bool(settings_pack::enable_incoming_tcp, !use_utp);
@ -147,14 +156,19 @@ void test_ssl(int test_idx, bool use_utp)
sett.set_bool(settings_pack::enable_natpmp, false);
// if a peer fails once, don't try it again
sett.set_int(settings_pack::max_failcount, 1);
sett.set_int(settings_pack::ssl_listen, ssl_port);
libtorrent::session ses1(sett, 0);
// this +20 is here to use a different port as ses1
port += 20;
// the +20 below is the port we use for non-SSL connections
if (test.downloader_has_ssl_listen_port)
sett.set_int(settings_pack::ssl_listen, ssl_port + 20);
snprintf(listen_iface, sizeof(listen_iface), "0.0.0.0:%d,0.0.0.0:%ds", port + 20, port);
else
sett.set_int(settings_pack::ssl_listen, 0);
snprintf(listen_iface, sizeof(listen_iface), "0.0.0.0:%d", port + 20);
sett.set_str(settings_pack::listen_interfaces, listen_iface);
libtorrent::session ses2(sett, 0);
@ -213,15 +227,7 @@ void test_ssl(int test_idx, bool use_utp)
wait_for_downloading(ses2, "ses2");
// connect the peers after setting the certificates
int port = 0;
if (test.use_ssl_ports)
if (test.downloader_has_ssl_listen_port)
port = ses2.ssl_listen_port();
else
port = 13512;
else
port = ses2.listen_port();
if (test.use_ssl_ports == false) port += 20;
fprintf(stderr, "\n\n%s: ses1: connecting peer port: %d\n\n\n"
, time_now_string(), port);
tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1", ec)
@ -541,12 +547,14 @@ void test_malicious_peer()
remove_all("tmp3_ssl", ec);
// set up session
int ssl_port = 1024 + rand() % 50000;
int port = 1024 + rand() % 50000;
settings_pack sett;
sett.set_int(settings_pack::alert_mask, alert_mask);
sett.set_int(settings_pack::max_retry_port_bind, 100);
sett.set_str(settings_pack::listen_interfaces, "0.0.0.0:48075");
sett.set_int(settings_pack::ssl_listen, ssl_port);
char listen_iface[100];
snprintf(listen_iface, sizeof(listen_iface), "0.0.0.0:%ds", port);
sett.set_str(settings_pack::listen_interfaces, listen_iface);
sett.set_bool(settings_pack::enable_dht, false);
sett.set_bool(settings_pack::enable_lsd, false);
sett.set_bool(settings_pack::enable_upnp, false);
@ -588,7 +596,7 @@ void test_malicious_peer()
for (int i = 0; i < num_attacks; ++i)
{
bool success = try_connect(ses1, ssl_port, t, attacks[i].flags);
bool const success = try_connect(ses1, port, t, attacks[i].flags);
TEST_EQUAL(success, attacks[i].expect);
}
}

View File

@ -257,24 +257,34 @@ TORRENT_TEST(string)
TEST_EQUAL(list[5], "foobar");
TEST_EQUAL(list[6], "[::1]");
std::vector<std::pair<std::string, int> > list2;
parse_comma_separated_string_port(" a:4,b:35, c : 1000, d: 351 ,e \t:42,foobar:1337\n\r,[2001::1]:6881", list2);
std::vector<listen_interface_t> list2;
parse_listen_interfaces(" a:4,b:35, c : 1000s, d: 351 ,e \t:42,foobar:1337s\n\r,[2001::1]:6881", list2);
TEST_EQUAL(list2.size(), 7);
TEST_EQUAL(list2[0].first, "a");
TEST_EQUAL(list2[1].first, "b");
TEST_EQUAL(list2[2].first, "c");
TEST_EQUAL(list2[3].first, "d");
TEST_EQUAL(list2[4].first, "e");
TEST_EQUAL(list2[5].first, "foobar");
TEST_EQUAL(list2[6].first, "2001::1");
TEST_EQUAL(list2[0].device, "a");
TEST_EQUAL(list2[1].device, "b");
TEST_EQUAL(list2[2].device, "c");
TEST_EQUAL(list2[3].device, "d");
TEST_EQUAL(list2[4].device, "e");
TEST_EQUAL(list2[5].device, "foobar");
TEST_EQUAL(list2[6].device, "2001::1");
TEST_EQUAL(list2[0].second, 4);
TEST_EQUAL(list2[1].second, 35);
TEST_EQUAL(list2[2].second, 1000);
TEST_EQUAL(list2[3].second, 351);
TEST_EQUAL(list2[4].second, 42);
TEST_EQUAL(list2[5].second, 1337);
TEST_EQUAL(list2[6].second, 6881);
TEST_EQUAL(list2[0].port, 4);
TEST_EQUAL(list2[1].port, 35);
TEST_EQUAL(list2[2].port, 1000);
TEST_EQUAL(list2[3].port, 351);
TEST_EQUAL(list2[4].port, 42);
TEST_EQUAL(list2[5].port, 1337);
TEST_EQUAL(list2[6].port, 6881);
TEST_EQUAL(list2[0].ssl, false);
TEST_EQUAL(list2[1].ssl, false);
TEST_EQUAL(list2[2].ssl, true);
TEST_EQUAL(list2[3].ssl, false);
TEST_EQUAL(list2[4].ssl, false);
TEST_EQUAL(list2[5].ssl, true);
TEST_EQUAL(list2[6].ssl, false);
TEST_EQUAL(print_listen_interfaces(list2), "a:4,b:35,c:1000s,d:351,e:42,foobar:1337s,[2001::1]:6881");
// test string_tokenize