2006-10-11 22:57:54 +02:00
|
|
|
/*
|
|
|
|
|
2016-01-18 00:57:46 +01:00
|
|
|
Copyright (c) 2006-2016, Arvid Norberg, Magnus Jonsson
|
2006-10-11 22:57:54 +02:00
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2015-04-26 03:25:45 +02:00
|
|
|
#include "libtorrent/config.hpp"
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
#include <ctime>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cctype>
|
2016-05-18 04:36:45 +02:00
|
|
|
#include <cstdio> // for snprintf
|
|
|
|
#include <cinttypes> // for PRId64 et.al.
|
2016-05-25 06:31:52 +02:00
|
|
|
#include <functional>
|
2016-09-16 15:53:17 +02:00
|
|
|
#include <type_traits>
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2016-07-02 01:46:59 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2016-04-30 22:53:20 +02:00
|
|
|
#include <unordered_set>
|
2016-07-02 01:46:59 +02:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-05-23 14:15:39 +02:00
|
|
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
|
|
|
|
2016-02-01 01:40:31 +01:00
|
|
|
#include <boost/asio/ip/v6_only.hpp>
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2015-08-18 16:42:03 +02:00
|
|
|
#if TORRENT_USE_RLIMIT
|
2015-09-06 22:47:10 +02:00
|
|
|
|
|
|
|
#include <sys/resource.h>
|
2015-08-18 16:42:03 +02:00
|
|
|
// capture this here where warnings are disabled (the macro generates warnings)
|
|
|
|
const rlim_t rlim_infinity = RLIM_INFINITY;
|
2015-09-06 22:47:10 +02:00
|
|
|
#endif // TORRENT_USE_RLIMIT
|
2015-08-18 16:42:03 +02:00
|
|
|
|
2015-04-21 03:16:28 +02:00
|
|
|
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2015-09-07 23:00:27 +02:00
|
|
|
#include "libtorrent/aux_/openssl.hpp"
|
2006-10-11 22:57:54 +02:00
|
|
|
#include "libtorrent/peer_id.hpp"
|
|
|
|
#include "libtorrent/torrent_info.hpp"
|
|
|
|
#include "libtorrent/tracker_manager.hpp"
|
|
|
|
#include "libtorrent/bencode.hpp"
|
|
|
|
#include "libtorrent/hasher.hpp"
|
|
|
|
#include "libtorrent/entry.hpp"
|
|
|
|
#include "libtorrent/session.hpp"
|
|
|
|
#include "libtorrent/fingerprint.hpp"
|
|
|
|
#include "libtorrent/alert_types.hpp"
|
|
|
|
#include "libtorrent/invariant_check.hpp"
|
|
|
|
#include "libtorrent/file.hpp"
|
|
|
|
#include "libtorrent/bt_peer_connection.hpp"
|
2015-07-25 17:58:32 +02:00
|
|
|
#include "libtorrent/peer_connection_handle.hpp"
|
2006-10-11 22:57:54 +02:00
|
|
|
#include "libtorrent/ip_filter.hpp"
|
|
|
|
#include "libtorrent/socket.hpp"
|
2016-01-11 08:10:42 +01:00
|
|
|
#include "libtorrent/session_stats.hpp"
|
2006-10-11 22:57:54 +02:00
|
|
|
#include "libtorrent/aux_/session_impl.hpp"
|
2010-12-29 03:17:44 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2006-10-11 22:57:54 +02:00
|
|
|
#include "libtorrent/kademlia/dht_tracker.hpp"
|
2016-07-24 00:57:04 +02:00
|
|
|
#include "libtorrent/kademlia/types.hpp"
|
2016-09-29 14:25:51 +02:00
|
|
|
#include "libtorrent/kademlia/node_entry.hpp"
|
2010-12-29 03:17:44 +01:00
|
|
|
#endif
|
2007-09-22 18:27:29 +02:00
|
|
|
#include "libtorrent/enum_net.hpp"
|
2008-12-21 20:15:53 +01:00
|
|
|
#include "libtorrent/utf8.hpp"
|
2008-12-26 08:00:21 +01:00
|
|
|
#include "libtorrent/upnp.hpp"
|
|
|
|
#include "libtorrent/natpmp.hpp"
|
|
|
|
#include "libtorrent/lsd.hpp"
|
2009-04-09 03:04:49 +02:00
|
|
|
#include "libtorrent/instantiate_connection.hpp"
|
2009-11-26 06:45:43 +01:00
|
|
|
#include "libtorrent/peer_info.hpp"
|
2010-10-24 02:44:07 +02:00
|
|
|
#include "libtorrent/build_config.hpp"
|
2011-02-26 08:55:51 +01:00
|
|
|
#include "libtorrent/random.hpp"
|
2012-03-08 10:54:44 +01:00
|
|
|
#include "libtorrent/magnet_uri.hpp"
|
2014-07-06 21:18:00 +02:00
|
|
|
#include "libtorrent/aux_/session_settings.hpp"
|
|
|
|
#include "libtorrent/torrent_peer.hpp"
|
2015-07-25 18:39:25 +02:00
|
|
|
#include "libtorrent/torrent_handle.hpp"
|
2014-10-23 00:06:56 +02:00
|
|
|
#include "libtorrent/choker.hpp"
|
2015-07-12 04:04:04 +02:00
|
|
|
#include "libtorrent/error.hpp"
|
2015-12-02 06:45:34 +01:00
|
|
|
#include "libtorrent/platform_util.hpp"
|
2016-02-09 00:11:00 +01:00
|
|
|
#include "libtorrent/aux_/bind_to_device.hpp"
|
2016-05-26 19:34:13 +02:00
|
|
|
#include "libtorrent/hex.hpp" // to_hex, from_hex
|
2016-10-19 07:18:05 +02:00
|
|
|
#include "libtorrent/aux_/scope_end.hpp"
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2014-12-09 10:08:26 +01:00
|
|
|
|
|
|
|
#include "libtorrent/socket_io.hpp"
|
2010-04-14 20:52:13 +02:00
|
|
|
|
2010-10-22 07:39:32 +02:00
|
|
|
// for logging stat layout
|
|
|
|
#include "libtorrent/stat.hpp"
|
|
|
|
|
2010-04-14 20:52:13 +02:00
|
|
|
// for logging the size of DHT structures
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
#include <libtorrent/kademlia/find_data.hpp>
|
|
|
|
#include <libtorrent/kademlia/refresh.hpp>
|
|
|
|
#include <libtorrent/kademlia/node.hpp>
|
|
|
|
#include <libtorrent/kademlia/observer.hpp>
|
2014-02-24 01:31:13 +01:00
|
|
|
#include <libtorrent/kademlia/item.hpp>
|
2010-04-14 20:52:13 +02:00
|
|
|
#endif // TORRENT_DISABLE_DHT
|
|
|
|
|
2010-11-16 07:41:35 +01:00
|
|
|
#include "libtorrent/http_tracker_connection.hpp"
|
|
|
|
#include "libtorrent/udp_tracker_connection.hpp"
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#endif // TORRENT_DISABLE_LOGGING
|
2010-04-14 20:52:13 +02:00
|
|
|
|
2016-06-23 19:20:35 +02:00
|
|
|
#ifdef TORRENT_USE_LIBGCRYPT
|
2009-11-08 04:09:19 +01:00
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
GCRY_THREAD_OPTION_PTHREAD_IMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
// libgcrypt requires this to initialize the library
|
|
|
|
struct gcrypt_setup
|
|
|
|
{
|
|
|
|
gcrypt_setup()
|
|
|
|
{
|
|
|
|
gcry_check_version(0);
|
|
|
|
gcry_error_t e = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
|
2016-05-17 15:24:06 +02:00
|
|
|
if (e != 0) std::fprintf(stderr, "libcrypt ERROR: %s\n", gcry_strerror(e));
|
2009-11-08 04:09:19 +01:00
|
|
|
e = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
2016-05-17 15:24:06 +02:00
|
|
|
if (e != 0) std::fprintf(stderr, "initialization finished error: %s\n", gcry_strerror(e));
|
2009-11-08 04:09:19 +01:00
|
|
|
}
|
|
|
|
} gcrypt_global_constructor;
|
|
|
|
}
|
|
|
|
|
2016-06-23 19:20:35 +02:00
|
|
|
#endif // TORRENT_USE_LIBGCRYPT
|
2009-11-08 04:09:19 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2007-07-07 01:06:58 +02:00
|
|
|
|
|
|
|
#include <openssl/crypto.h>
|
2014-12-25 12:24:02 +01:00
|
|
|
#include <openssl/rand.h>
|
2007-07-07 01:06:58 +02:00
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
// openssl requires this to clean up internal
|
|
|
|
// structures it allocates
|
|
|
|
struct openssl_cleanup
|
|
|
|
{
|
2016-09-07 23:51:18 +02:00
|
|
|
#ifdef TORRENT_MACOS_DEPRECATED_LIBCRYPTO
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
#endif
|
2007-07-07 01:06:58 +02:00
|
|
|
~openssl_cleanup() { CRYPTO_cleanup_all_ex_data(); }
|
2016-09-07 23:51:18 +02:00
|
|
|
#ifdef TORRENT_MACOS_DEPRECATED_LIBCRYPTO
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
#endif
|
2007-07-07 01:06:58 +02:00
|
|
|
} openssl_global_destructor;
|
|
|
|
}
|
|
|
|
|
2009-11-08 04:09:19 +01:00
|
|
|
#endif // TORRENT_USE_OPENSSL
|
|
|
|
|
2009-07-01 01:03:54 +02:00
|
|
|
#ifdef TORRENT_WINDOWS
|
2007-10-15 21:02:54 +02:00
|
|
|
// for ERROR_SEM_TIMEOUT
|
|
|
|
#include <winerror.h>
|
2007-07-07 01:06:58 +02:00
|
|
|
#endif
|
|
|
|
|
2016-05-25 06:31:52 +02:00
|
|
|
using namespace std::placeholders;
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2009-02-11 18:45:12 +01:00
|
|
|
#ifdef BOOST_NO_EXCEPTIONS
|
|
|
|
namespace boost {
|
|
|
|
void throw_exception(std::exception const& e) { ::abort(); }
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-06-10 22:46:09 +02:00
|
|
|
namespace libtorrent {
|
|
|
|
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
std::map<std::string, async_t> _async_ops;
|
2014-07-06 21:18:00 +02:00
|
|
|
std::deque<wakeup_t> _wakeups;
|
2010-12-24 19:15:01 +01:00
|
|
|
int _async_ops_nthreads = 0;
|
2016-05-01 00:54:23 +02:00
|
|
|
std::mutex _async_ops_mutex;
|
2010-11-28 02:47:30 +01:00
|
|
|
#endif
|
|
|
|
|
2008-03-08 07:06:31 +01:00
|
|
|
namespace aux {
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2016-10-06 06:08:14 +02:00
|
|
|
// TODO: 3 move this out of this file
|
2016-09-17 15:42:04 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
dht_settings read_dht_settings(bdecode_node const& e)
|
|
|
|
{
|
|
|
|
dht_settings sett;
|
|
|
|
|
|
|
|
if (e.type() != bdecode_node::dict_t) return sett;
|
|
|
|
|
|
|
|
bdecode_node val;
|
|
|
|
val = e.dict_find_int("max_peers_reply");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) sett.max_peers_reply = int(val.int_value());
|
2016-09-17 15:42:04 +02:00
|
|
|
val = e.dict_find_int("search_branching");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) sett.search_branching = int(val.int_value());
|
2016-09-17 15:42:04 +02:00
|
|
|
val = e.dict_find_int("max_fail_count");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) sett.max_fail_count = int(val.int_value());
|
2016-09-17 15:42:04 +02:00
|
|
|
val = e.dict_find_int("max_torrents");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) sett.max_torrents = int(val.int_value());
|
2016-09-17 15:42:04 +02:00
|
|
|
val = e.dict_find_int("max_dht_items");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) sett.max_dht_items = int(val.int_value());
|
2016-09-17 15:42:04 +02:00
|
|
|
val = e.dict_find_int("max_peers");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) sett.max_peers = int(val.int_value());
|
2016-09-17 15:42:04 +02:00
|
|
|
val = e.dict_find_int("max_torrent_search_reply");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) sett.max_torrent_search_reply = int(val.int_value());
|
2016-09-17 15:42:04 +02:00
|
|
|
val = e.dict_find_int("restrict_routing_ips");
|
|
|
|
if (val) sett.restrict_routing_ips = (val.int_value() != 0);
|
|
|
|
val = e.dict_find_int("restrict_search_ips");
|
|
|
|
if (val) sett.restrict_search_ips = (val.int_value() != 0);
|
|
|
|
val = e.dict_find_int("extended_routing_table");
|
|
|
|
if (val) sett.extended_routing_table = (val.int_value() != 0);
|
|
|
|
val = e.dict_find_int("aggressive_lookups");
|
|
|
|
if (val) sett.aggressive_lookups = (val.int_value() != 0);
|
|
|
|
val = e.dict_find_int("privacy_lookups");
|
|
|
|
if (val) sett.privacy_lookups = (val.int_value() != 0);
|
|
|
|
val = e.dict_find_int("enforce_node_id");
|
|
|
|
if (val) sett.enforce_node_id = (val.int_value() != 0);
|
|
|
|
val = e.dict_find_int("ignore_dark_internet");
|
|
|
|
if (val) sett.ignore_dark_internet = (val.int_value() != 0);
|
|
|
|
val = e.dict_find_int("block_timeout");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) sett.block_timeout = int(val.int_value());
|
2016-09-17 15:42:04 +02:00
|
|
|
val = e.dict_find_int("block_ratelimit");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) sett.block_ratelimit = int(val.int_value());
|
2016-09-17 15:42:04 +02:00
|
|
|
val = e.dict_find_int("read_only");
|
|
|
|
if (val) sett.read_only = (val.int_value() != 0);
|
|
|
|
val = e.dict_find_int("item_lifetime");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) sett.item_lifetime = int(val.int_value());
|
2016-09-17 15:42:04 +02:00
|
|
|
|
|
|
|
return sett;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry save_dht_settings(dht_settings const& settings)
|
|
|
|
{
|
|
|
|
entry e;
|
|
|
|
entry::dictionary_type& dht_sett = e.dict();
|
|
|
|
|
|
|
|
dht_sett["max_peers_reply"] = settings.max_peers_reply;
|
|
|
|
dht_sett["search_branching"] = settings.search_branching;
|
|
|
|
dht_sett["max_fail_count"] = settings.max_fail_count;
|
|
|
|
dht_sett["max_torrents"] = settings.max_torrents;
|
|
|
|
dht_sett["max_dht_items"] = settings.max_dht_items;
|
|
|
|
dht_sett["max_peers"] = settings.max_peers;
|
|
|
|
dht_sett["max_torrent_search_reply"] = settings.max_torrent_search_reply;
|
|
|
|
dht_sett["restrict_routing_ips"] = settings.restrict_routing_ips;
|
|
|
|
dht_sett["restrict_search_ips"] = settings.restrict_search_ips;
|
|
|
|
dht_sett["extended_routing_table"] = settings.extended_routing_table;
|
|
|
|
dht_sett["aggressive_lookups"] = settings.aggressive_lookups;
|
|
|
|
dht_sett["privacy_lookups"] = settings.privacy_lookups;
|
|
|
|
dht_sett["enforce_node_id"] = settings.enforce_node_id;
|
|
|
|
dht_sett["ignore_dark_internet"] = settings.ignore_dark_internet;
|
|
|
|
dht_sett["block_timeout"] = settings.block_timeout;
|
|
|
|
dht_sett["block_ratelimit"] = settings.block_ratelimit;
|
|
|
|
dht_sett["read_only"] = settings.read_only;
|
|
|
|
dht_sett["item_lifetime"] = settings.item_lifetime;
|
|
|
|
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
#endif // TORRENT_DISABLE_DHT
|
|
|
|
|
2016-11-21 02:06:52 +01:00
|
|
|
std::list<listen_socket_t>::iterator partition_listen_sockets(
|
|
|
|
std::vector<listen_endpoint_t>& eps
|
|
|
|
, std::list<listen_socket_t>& sockets)
|
|
|
|
{
|
|
|
|
return std::partition(sockets.begin(), sockets.end()
|
|
|
|
, [&eps](listen_socket_t const& sock)
|
|
|
|
{
|
|
|
|
auto match = std::find_if(eps.begin(), eps.end()
|
|
|
|
, [&sock](listen_endpoint_t const& ep)
|
|
|
|
{
|
|
|
|
return ep.ssl == sock.ssl
|
|
|
|
&& ep.port == sock.original_port
|
|
|
|
&& ep.device == sock.device
|
|
|
|
&& ep.addr == sock.local_endpoint.address();
|
|
|
|
});
|
|
|
|
|
|
|
|
if (match != eps.end())
|
|
|
|
{
|
|
|
|
// remove the matched endpoint so that another socket can't match it
|
|
|
|
// this also signals to the caller that it doesn't need to create a
|
|
|
|
// socket for the endpoint
|
|
|
|
eps.erase(match);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::init_peer_class_filter(bool unlimited_local)
|
2009-12-03 06:11:57 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
// set the default peer_class_filter to use the local peer class
|
|
|
|
// for peers on local networks
|
2017-01-22 04:40:19 +01:00
|
|
|
std::uint32_t lfilter = 1 << static_cast<std::uint32_t>(m_local_peer_class);
|
|
|
|
std::uint32_t gfilter = 1 << static_cast<std::uint32_t>(m_global_class);
|
2009-12-03 06:11:57 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
struct class_mapping
|
|
|
|
{
|
|
|
|
char const* first;
|
|
|
|
char const* last;
|
2016-06-18 20:01:38 +02:00
|
|
|
std::uint32_t filter;
|
2014-07-06 21:18:00 +02:00
|
|
|
};
|
2009-12-03 06:11:57 +01:00
|
|
|
|
2015-03-14 01:42:27 +01:00
|
|
|
static const class_mapping v4_classes[] =
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
// everything
|
|
|
|
{"0.0.0.0", "255.255.255.255", gfilter},
|
|
|
|
// local networks
|
|
|
|
{"10.0.0.0", "10.255.255.255", lfilter},
|
|
|
|
{"172.16.0.0", "172.16.255.255", lfilter},
|
|
|
|
{"192.168.0.0", "192.168.255.255", lfilter},
|
|
|
|
// link-local
|
|
|
|
{"169.254.0.0", "169.254.255.255", lfilter},
|
|
|
|
// loop-back
|
|
|
|
{"127.0.0.0", "127.255.255.255", lfilter},
|
|
|
|
};
|
2010-10-10 04:22:57 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
2015-03-14 01:42:27 +01:00
|
|
|
static const class_mapping v6_classes[] =
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
// everything
|
|
|
|
{"::0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", gfilter},
|
|
|
|
// link-local
|
|
|
|
{"fe80::", "febf::ffff:ffff:ffff:ffff:ffff:ffff:ffff", lfilter},
|
|
|
|
// loop-back
|
|
|
|
{"::1", "::1", lfilter},
|
|
|
|
};
|
2010-10-10 04:22:57 +02:00
|
|
|
#endif
|
2010-03-10 03:28:40 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
class_mapping const* p = v4_classes;
|
|
|
|
int len = sizeof(v4_classes) / sizeof(v4_classes[0]);
|
|
|
|
if (!unlimited_local) len = 1;
|
|
|
|
for (int i = 0; i < len; ++i)
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
address_v4 begin = address_v4::from_string(p[i].first, ec);
|
|
|
|
address_v4 end = address_v4::from_string(p[i].last, ec);
|
|
|
|
if (ec) continue;
|
|
|
|
m_peer_class_filter.add_rule(begin, end, p[i].filter);
|
|
|
|
}
|
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
p = v6_classes;
|
|
|
|
len = sizeof(v6_classes) / sizeof(v6_classes[0]);
|
|
|
|
if (!unlimited_local) len = 1;
|
|
|
|
for (int i = 0; i < len; ++i)
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
address_v6 begin = address_v6::from_string(p[i].first, ec);
|
|
|
|
address_v6 end = address_v6::from_string(p[i].last, ec);
|
|
|
|
if (ec) continue;
|
|
|
|
m_peer_class_filter.add_rule(begin, end, p[i].filter);
|
|
|
|
}
|
2010-03-10 03:28:40 +01:00
|
|
|
#endif
|
2010-12-26 09:03:02 +01:00
|
|
|
}
|
2009-05-07 22:30:20 +02:00
|
|
|
|
2016-08-26 06:14:11 +02:00
|
|
|
#if defined TORRENT_USE_OPENSSL && OPENSSL_VERSION_NUMBER >= 0x90812f
|
2016-09-07 23:51:18 +02:00
|
|
|
#ifdef TORRENT_MACOS_DEPRECATED_LIBCRYPTO
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
#endif
|
2015-09-02 07:30:40 +02:00
|
|
|
namespace {
|
2012-01-14 17:04:25 +01:00
|
|
|
// when running bittorrent over SSL, the SNI (server name indication)
|
|
|
|
// extension is used to know which torrent the incoming connection is
|
|
|
|
// trying to connect to. The 40 first bytes in the name is expected to
|
|
|
|
// be the hex encoded info-hash
|
2015-09-02 07:30:40 +02:00
|
|
|
int servername_callback(SSL* s, int* ad, void* arg)
|
2012-01-14 17:04:25 +01:00
|
|
|
{
|
2015-08-21 10:05:51 +02:00
|
|
|
TORRENT_UNUSED(ad);
|
|
|
|
|
2015-09-02 07:30:40 +02:00
|
|
|
session_impl* ses = reinterpret_cast<session_impl*>(arg);
|
2012-01-14 17:04:25 +01:00
|
|
|
const char* servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2012-01-14 17:04:25 +01:00
|
|
|
if (!servername || strlen(servername) < 40)
|
|
|
|
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
|
|
|
|
|
|
sha1_hash info_hash;
|
2016-07-30 02:24:11 +02:00
|
|
|
bool valid = aux::from_hex({servername, 40}, info_hash.data());
|
2012-01-14 17:04:25 +01:00
|
|
|
|
|
|
|
// the server name is not a valid hex-encoded info-hash
|
|
|
|
if (!valid)
|
|
|
|
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
|
|
|
|
|
|
// see if there is a torrent with this info-hash
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> t = ses->find_torrent(info_hash).lock();
|
2012-01-14 17:04:25 +01:00
|
|
|
|
|
|
|
// if there isn't, fail
|
|
|
|
if (!t) return SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
|
|
|
|
|
|
// if the torrent we found isn't an SSL torrent, also fail.
|
|
|
|
if (!t->is_ssl_torrent()) return SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
|
|
|
2013-07-28 17:06:28 +02:00
|
|
|
// if the torrent doesn't have an SSL context and should not allow
|
|
|
|
// incoming SSL connections
|
|
|
|
if (!t->ssl_ctx()) return SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
|
|
|
2012-01-14 17:04:25 +01:00
|
|
|
// use this torrent's certificate
|
2013-08-05 18:20:25 +02:00
|
|
|
SSL_CTX *torrent_context = t->ssl_ctx()->native_handle();
|
|
|
|
|
|
|
|
SSL_set_SSL_CTX(s, torrent_context);
|
2016-10-08 20:07:11 +02:00
|
|
|
SSL_set_verify(s, SSL_CTX_get_verify_mode(torrent_context)
|
|
|
|
, SSL_CTX_get_verify_callback(torrent_context));
|
2012-01-14 17:04:25 +01:00
|
|
|
|
|
|
|
return SSL_TLSEXT_ERR_OK;
|
|
|
|
}
|
2016-08-13 01:24:03 +02:00
|
|
|
} // anonymous namespace
|
2016-09-07 23:51:18 +02:00
|
|
|
#ifdef TORRENT_MACOS_DEPRECATED_LIBCRYPTO
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
#endif
|
2012-01-14 17:04:25 +01:00
|
|
|
#endif
|
|
|
|
|
2015-06-03 05:04:44 +02:00
|
|
|
session_impl::session_impl(io_service& ios)
|
2016-08-30 02:29:27 +02:00
|
|
|
: m_io_service(ios)
|
2010-10-12 10:57:43 +02:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2015-06-06 08:10:53 +02:00
|
|
|
, m_ssl_ctx(m_io_service, boost::asio::ssl::context::sslv23)
|
2010-10-12 10:57:43 +02:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_alerts(m_settings.get_int(settings_pack::alert_queue_size), alert::all_categories)
|
2016-10-30 23:21:07 +01:00
|
|
|
, m_disk_thread(m_io_service, m_stats_counters)
|
2009-04-26 02:21:59 +02:00
|
|
|
, m_download_rate(peer_connection::download_channel)
|
|
|
|
, m_upload_rate(peer_connection::upload_channel)
|
2016-04-24 21:26:28 +02:00
|
|
|
, m_tracker_manager(
|
2016-05-25 06:31:52 +02:00
|
|
|
std::bind(&session_impl::send_udp_packet, this, false, _1, _2, _3, _4)
|
|
|
|
, std::bind(&session_impl::send_udp_packet_hostname, this, _1, _2, _3, _4, _5)
|
2016-04-24 21:26:28 +02:00
|
|
|
, m_stats_counters
|
|
|
|
, m_host_resolver
|
2015-05-16 08:33:37 +02:00
|
|
|
, m_settings
|
2015-04-17 03:15:33 +02:00
|
|
|
#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
|
2015-02-01 15:30:43 +01:00
|
|
|
, *this
|
|
|
|
#endif
|
|
|
|
)
|
2016-09-05 03:49:11 +02:00
|
|
|
, m_work(new io_service::work(m_io_service))
|
2016-11-07 13:40:09 +01:00
|
|
|
, m_ip_notifier(m_io_service)
|
2009-08-20 05:19:12 +02:00
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
, m_i2p_conn(m_io_service)
|
|
|
|
#endif
|
2015-03-12 05:34:54 +01:00
|
|
|
, m_created(clock_type::now())
|
2009-04-30 07:49:46 +02:00
|
|
|
, m_last_tick(m_created)
|
2010-10-17 20:36:37 +02:00
|
|
|
, m_last_second_tick(m_created - milliseconds(900))
|
2009-04-30 07:49:46 +02:00
|
|
|
, m_last_choke(m_created)
|
2015-04-05 21:35:58 +02:00
|
|
|
, m_last_auto_manage(m_created)
|
2007-03-15 23:03:56 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2010-02-14 02:39:55 +01:00
|
|
|
, m_dht_announce_timer(m_io_service)
|
2007-03-15 23:03:56 +01:00
|
|
|
#endif
|
2016-04-24 21:26:28 +02:00
|
|
|
, m_utp_socket_manager(
|
2016-05-25 06:31:52 +02:00
|
|
|
std::bind(&session_impl::send_udp_packet, this, false, _1, _2, _3, _4)
|
|
|
|
, std::bind(&session_impl::incoming_connection, this, _1)
|
2016-04-24 21:26:28 +02:00
|
|
|
, m_io_service
|
2016-06-20 17:32:06 +02:00
|
|
|
, m_settings, m_stats_counters, nullptr)
|
2014-10-06 05:03:01 +02:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2016-04-24 21:26:28 +02:00
|
|
|
, m_ssl_utp_socket_manager(
|
2016-05-25 06:31:52 +02:00
|
|
|
std::bind(&session_impl::send_udp_packet, this, true, _1, _2, _3, _4)
|
|
|
|
, std::bind(&session_impl::on_incoming_utp_ssl, this, _1)
|
2016-04-24 21:26:28 +02:00
|
|
|
, m_io_service
|
|
|
|
, m_settings, m_stats_counters
|
|
|
|
, &m_ssl_ctx)
|
2014-10-06 05:03:01 +02:00
|
|
|
#endif
|
2006-12-15 18:47:21 +01:00
|
|
|
, m_timer(m_io_service)
|
2010-02-05 09:23:17 +01:00
|
|
|
, m_lsd_announce_timer(m_io_service)
|
2010-02-14 02:39:55 +01:00
|
|
|
, m_host_resolver(m_io_service)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2016-04-29 03:59:41 +02:00
|
|
|
update_time_now();
|
2013-03-10 10:19:58 +01:00
|
|
|
}
|
|
|
|
|
2016-10-06 06:08:14 +02:00
|
|
|
template <typename Fun, typename... Args>
|
|
|
|
void session_impl::wrap(Fun f, Args&&... a)
|
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
|
|
|
try
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
(this->*f)(std::forward<Args>(a)...);
|
|
|
|
}
|
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
|
|
|
catch (system_error const& e) {
|
|
|
|
alerts().emplace_alert<session_error_alert>(e.code(), e.what());
|
|
|
|
pause();
|
|
|
|
} catch (std::exception const& e) {
|
|
|
|
alerts().emplace_alert<session_error_alert>(error_code(), e.what());
|
|
|
|
pause();
|
|
|
|
} catch (...) {
|
|
|
|
alerts().emplace_alert<session_error_alert>(error_code(), "unknown error");
|
|
|
|
pause();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-05-29 07:27:53 +02:00
|
|
|
// This function is called by the creating thread, not in the message loop's
|
2016-06-02 13:25:06 +02:00
|
|
|
// io_service thread.
|
2015-05-29 07:27:53 +02:00
|
|
|
// TODO: 2 is there a reason not to move all of this into init()? and just
|
|
|
|
// post it to the io_service?
|
2016-09-28 19:28:43 +02:00
|
|
|
void session_impl::start_session(settings_pack pack)
|
2013-03-10 10:19:58 +01:00
|
|
|
{
|
2016-02-03 05:17:51 +01:00
|
|
|
if (pack.has_val(settings_pack::alert_mask))
|
|
|
|
{
|
|
|
|
m_alerts.set_alert_mask(pack.get_int(settings_pack::alert_mask));
|
|
|
|
}
|
2014-12-10 10:45:38 +01:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2014-12-09 10:08:26 +01:00
|
|
|
session_log("start session");
|
2010-05-09 08:03:52 +02:00
|
|
|
#endif
|
|
|
|
|
2010-10-12 10:57:43 +02:00
|
|
|
error_code ec;
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2015-06-06 08:10:53 +02:00
|
|
|
m_ssl_ctx.set_verify_mode(boost::asio::ssl::context::verify_none, ec);
|
2012-04-06 06:11:04 +02:00
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x90812f
|
2015-09-07 23:00:27 +02:00
|
|
|
aux::openssl_set_tlsext_servername_callback(m_ssl_ctx.native_handle()
|
2015-09-02 07:30:40 +02:00
|
|
|
, servername_callback);
|
2015-09-07 23:00:27 +02:00
|
|
|
aux::openssl_set_tlsext_servername_arg(m_ssl_ctx.native_handle(), this);
|
2012-04-06 06:11:04 +02:00
|
|
|
#endif // OPENSSL_VERSION_NUMBER
|
2010-10-12 10:57:43 +02:00
|
|
|
#endif
|
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
m_next_dht_torrent = m_torrents.begin();
|
|
|
|
#endif
|
2010-02-05 09:23:17 +01:00
|
|
|
m_next_lsd_torrent = m_torrents.begin();
|
2007-09-10 03:57:40 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_global_class = m_classes.new_peer_class("global");
|
|
|
|
m_tcp_peer_class = m_classes.new_peer_class("tcp");
|
|
|
|
m_local_peer_class = m_classes.new_peer_class("local");
|
|
|
|
// local peers are always unchoked
|
|
|
|
m_classes.at(m_local_peer_class)->ignore_unchoke_slots = true;
|
|
|
|
// local peers are allowed to exceed the normal connection
|
|
|
|
// limit by 50%
|
|
|
|
m_classes.at(m_local_peer_class)->connection_limit_factor = 150;
|
|
|
|
|
|
|
|
TORRENT_ASSERT(m_global_class == session::global_peer_class_id);
|
|
|
|
TORRENT_ASSERT(m_tcp_peer_class == session::tcp_peer_class_id);
|
|
|
|
TORRENT_ASSERT(m_local_peer_class == session::local_peer_class_id);
|
|
|
|
|
|
|
|
init_peer_class_filter(true);
|
|
|
|
|
|
|
|
// TCP, SSL/TCP and I2P connections should be assigned the TCP peer class
|
|
|
|
m_peer_class_type_filter.add(peer_class_type_filter::tcp_socket, m_tcp_peer_class);
|
|
|
|
m_peer_class_type_filter.add(peer_class_type_filter::ssl_tcp_socket, m_tcp_peer_class);
|
|
|
|
m_peer_class_type_filter.add(peer_class_type_filter::i2p_socket, m_tcp_peer_class);
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2010-10-24 02:44:07 +02:00
|
|
|
|
2015-07-06 00:44:02 +02:00
|
|
|
session_log("config: %s version: %s revision: %s"
|
2015-05-16 08:33:37 +02:00
|
|
|
, TORRENT_CFG_STRING
|
2010-11-15 05:43:53 +01:00
|
|
|
, LIBTORRENT_VERSION
|
|
|
|
, LIBTORRENT_REVISION);
|
2010-10-24 02:44:07 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#endif // TORRENT_DISABLE_LOGGING
|
2007-05-14 00:01:21 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// ---- auto-cap max connections ----
|
2015-12-02 06:45:34 +01:00
|
|
|
int max_files = max_open_files();
|
|
|
|
// deduct some margin for epoll/kqueue, log files,
|
|
|
|
// futexes, shared objects etc.
|
|
|
|
// 80% of the available file descriptors should go to connections
|
|
|
|
m_settings.set_int(settings_pack::connections_limit, (std::min)(
|
|
|
|
m_settings.get_int(settings_pack::connections_limit)
|
|
|
|
, (std::max)(5, (max_files - 20) * 8 / 10)));
|
|
|
|
// 20% goes towards regular files (see disk_io_thread)
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log(" max connections: %d", m_settings.get_int(settings_pack::connections_limit));
|
|
|
|
session_log(" max files: %d", max_files);
|
|
|
|
session_log(" generated peer ID: %s", m_peer_id.to_string().c_str());
|
|
|
|
}
|
2010-12-24 01:37:01 +01:00
|
|
|
#endif
|
|
|
|
|
2016-10-06 06:08:14 +02:00
|
|
|
// TODO: 3 make this move all the way through to the init() call
|
|
|
|
// if we're in C++14
|
2016-09-28 19:28:43 +02:00
|
|
|
auto copy = std::make_shared<settings_pack>(std::move(pack));
|
2016-10-06 06:08:14 +02:00
|
|
|
m_io_service.post([this, copy] { this->wrap(&session_impl::init, copy); });
|
2015-06-03 05:04:44 +02:00
|
|
|
}
|
|
|
|
|
2016-09-01 03:42:18 +02:00
|
|
|
void session_impl::init(std::shared_ptr<settings_pack> pack)
|
2015-06-03 05:04:44 +02:00
|
|
|
{
|
2016-12-26 17:09:52 +01:00
|
|
|
INVARIANT_CHECK;
|
2015-06-03 05:04:44 +02:00
|
|
|
// this is a debug facility
|
|
|
|
// see single_threaded in debug.hpp
|
|
|
|
thread_started();
|
|
|
|
|
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2014-10-21 02:28:51 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-06-11 21:37:28 +02:00
|
|
|
// this alert is a bit special. Since it's so verbose it's not only
|
|
|
|
// filtered by its own alert type (log_alert) but also whether session
|
|
|
|
// stats alerts are actually enabled. Without session_stats alerts the
|
|
|
|
// headers aren't very useful anyway
|
|
|
|
if (m_alerts.should_post<log_alert>()
|
|
|
|
&& m_alerts.should_post<session_stats_alert>())
|
2016-01-11 08:10:42 +01:00
|
|
|
{
|
|
|
|
session_log(" *** session thread init");
|
|
|
|
|
|
|
|
// this specific output is parsed by tools/parse_session_stats.py
|
|
|
|
// if this is changed, that parser should also be changed
|
|
|
|
std::vector<stats_metric> stats = session_stats_metrics();
|
|
|
|
std::sort(stats.begin(), stats.end()
|
2016-05-25 06:31:52 +02:00
|
|
|
, [] (stats_metric const& lhs, stats_metric const& rhs)
|
|
|
|
{ return lhs.value_index < rhs.value_index; });
|
2016-11-27 14:46:53 +01:00
|
|
|
std::string stats_header = "session stats header: ";
|
|
|
|
bool first = true;
|
|
|
|
for (auto const& s : stats)
|
2016-01-11 08:10:42 +01:00
|
|
|
{
|
2016-11-27 14:46:53 +01:00
|
|
|
if (!first) stats_header += ", ";
|
|
|
|
stats_header += s.name;
|
|
|
|
first = false;
|
2016-01-11 08:10:42 +01:00
|
|
|
}
|
|
|
|
m_alerts.emplace_alert<log_alert>(stats_header.c_str());
|
|
|
|
}
|
2014-10-21 02:28:51 +02:00
|
|
|
#endif
|
|
|
|
|
2015-06-03 05:04:44 +02:00
|
|
|
// this is where we should set up all async operations. This
|
|
|
|
// is called from within the network thread as opposed to the
|
|
|
|
// constructor which is called from the main thread
|
|
|
|
|
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
async_inc_threads();
|
|
|
|
add_outstanding_async("session_impl::on_tick");
|
|
|
|
#endif
|
2016-10-06 06:08:14 +02:00
|
|
|
m_io_service.post([this]{ this->wrap(&session_impl::on_tick, error_code()); });
|
2015-06-03 05:04:44 +02:00
|
|
|
|
2016-10-08 20:07:11 +02:00
|
|
|
int const lsd_announce_interval
|
|
|
|
= m_settings.get_int(settings_pack::local_service_announce_interval);
|
|
|
|
int const delay = std::max(lsd_announce_interval
|
|
|
|
/ std::max(static_cast<int>(m_torrents.size()), 1), 1);
|
2016-10-06 06:08:14 +02:00
|
|
|
error_code ec;
|
2015-06-03 05:04:44 +02:00
|
|
|
m_lsd_announce_timer.expires_from_now(seconds(delay), ec);
|
2016-10-08 20:07:11 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_lsd_announce");
|
2016-10-06 06:08:14 +02:00
|
|
|
m_lsd_announce_timer.async_wait([this](error_code const& e) {
|
|
|
|
this->wrap(&session_impl::on_lsd_announce, e); } );
|
2015-06-03 05:04:44 +02:00
|
|
|
TORRENT_ASSERT(!ec);
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
|
|
|
session_log(" done starting session");
|
|
|
|
#endif
|
|
|
|
|
2016-11-07 13:40:09 +01:00
|
|
|
m_ip_notifier.async_wait([this](error_code const& e)
|
|
|
|
{ this->wrap(&session_impl::on_ip_change, e); });
|
|
|
|
|
2016-06-23 23:54:31 +02:00
|
|
|
apply_settings_pack_impl(*pack, true);
|
2015-06-03 05:04:44 +02:00
|
|
|
|
|
|
|
// call update_* after settings set initialized
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
update_local_download_rate();
|
|
|
|
update_local_upload_rate();
|
|
|
|
#endif
|
|
|
|
update_download_rate();
|
|
|
|
update_upload_rate();
|
|
|
|
update_connections_limit();
|
2014-10-23 00:06:56 +02:00
|
|
|
update_unchoke_limit();
|
2014-07-06 21:18:00 +02:00
|
|
|
update_disk_threads();
|
|
|
|
update_upnp();
|
|
|
|
update_natpmp();
|
|
|
|
update_lsd();
|
|
|
|
update_dht();
|
2014-12-31 16:51:45 +01:00
|
|
|
update_peer_fingerprint();
|
2016-08-21 18:15:19 +02:00
|
|
|
update_dht_bootstrap_nodes();
|
2016-06-02 13:25:06 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
update_dht_announce_interval();
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
2014-10-05 03:23:22 +02:00
|
|
|
void session_impl::async_resolve(std::string const& host, int flags
|
|
|
|
, session_interface::callback_t const& h)
|
|
|
|
{
|
|
|
|
m_host_resolver.async_resolve(host, flags, h);
|
|
|
|
}
|
|
|
|
|
2016-06-18 20:01:38 +02:00
|
|
|
void session_impl::save_state(entry* eptr, std::uint32_t flags) const
|
2009-12-03 06:11:57 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2010-09-25 22:07:27 +02:00
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
entry& e = *eptr;
|
2016-03-05 21:15:22 +01:00
|
|
|
// make it a dict
|
|
|
|
e.dict();
|
2010-07-14 06:16:38 +02:00
|
|
|
|
2016-03-05 21:15:22 +01:00
|
|
|
if (flags & session::save_settings)
|
|
|
|
{
|
|
|
|
entry::dictionary_type& sett = e["settings"].dict();
|
|
|
|
save_settings_to_dict(m_settings, sett);
|
|
|
|
}
|
2010-10-10 04:22:57 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (flags & session::save_dht_settings)
|
2010-03-06 08:49:40 +01:00
|
|
|
{
|
2016-09-17 15:42:04 +02:00
|
|
|
e["dht"] = save_dht_settings(m_dht_settings);
|
2010-03-06 08:49:40 +01:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2010-03-06 08:49:40 +01:00
|
|
|
if (m_dht && (flags & session::save_dht_state))
|
2010-03-04 17:42:39 +01:00
|
|
|
{
|
2016-09-17 15:42:04 +02:00
|
|
|
e["dht state"] = dht::save_dht_state(m_dht->state());
|
2010-03-04 17:42:39 +01:00
|
|
|
}
|
2009-12-03 06:11:57 +01:00
|
|
|
#endif
|
2010-03-10 03:28:40 +01:00
|
|
|
|
2011-01-29 11:37:21 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2016-08-30 19:28:46 +02:00
|
|
|
for (auto const& ext : m_ses_extensions[plugins_all_idx])
|
2011-01-29 11:37:21 +01:00
|
|
|
{
|
2016-10-23 04:00:47 +02:00
|
|
|
ext->save_state(*eptr);
|
2011-01-29 11:37:21 +01:00
|
|
|
}
|
|
|
|
#endif
|
2009-12-03 06:11:57 +01:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
proxy_settings session_impl::proxy() const
|
2010-08-23 08:27:18 +02:00
|
|
|
{
|
2014-10-21 02:28:51 +02:00
|
|
|
return proxy_settings(m_settings);
|
2010-08-23 08:27:18 +02:00
|
|
|
}
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2016-03-05 21:15:22 +01:00
|
|
|
void session_impl::load_state(bdecode_node const* e
|
2016-09-09 01:13:47 +02:00
|
|
|
, std::uint32_t const flags)
|
2009-12-03 06:11:57 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2010-09-25 22:07:27 +02:00
|
|
|
|
2015-03-12 06:20:12 +01:00
|
|
|
bdecode_node settings;
|
|
|
|
if (e->type() != bdecode_node::dict_t) return;
|
2010-03-04 17:42:39 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2015-09-08 21:15:51 +02:00
|
|
|
bool need_update_dht = false;
|
2016-09-17 15:42:04 +02:00
|
|
|
if (flags & session_handle::save_dht_settings)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-03-05 21:15:22 +01:00
|
|
|
settings = e->dict_find_dict("dht");
|
|
|
|
if (settings)
|
|
|
|
{
|
2016-09-17 15:42:04 +02:00
|
|
|
m_dht_settings = read_dht_settings(settings);
|
2016-03-05 21:15:22 +01:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2015-09-08 21:15:51 +02:00
|
|
|
|
2016-09-17 15:42:04 +02:00
|
|
|
if (flags & session_handle::save_dht_state)
|
2015-09-08 21:15:51 +02:00
|
|
|
{
|
2016-03-05 21:15:22 +01:00
|
|
|
settings = e->dict_find_dict("dht state");
|
|
|
|
if (settings)
|
|
|
|
{
|
2016-09-17 15:42:04 +02:00
|
|
|
m_dht_state = dht::read_dht_state(settings);
|
2016-03-05 21:15:22 +01:00
|
|
|
need_update_dht = true;
|
|
|
|
}
|
2015-09-08 21:15:51 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2015-09-08 21:15:51 +02:00
|
|
|
bool need_update_proxy = false;
|
2016-09-17 15:42:04 +02:00
|
|
|
if (flags & session_handle::save_proxy)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-03-05 21:15:22 +01:00
|
|
|
settings = e->dict_find_dict("proxy");
|
|
|
|
if (settings)
|
|
|
|
{
|
|
|
|
bdecode_node val;
|
|
|
|
val = settings.dict_find_int("port");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) m_settings.set_int(settings_pack::proxy_port, int(val.int_value()));
|
2016-03-05 21:15:22 +01:00
|
|
|
val = settings.dict_find_int("type");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) m_settings.set_int(settings_pack::proxy_type, int(val.int_value()));
|
2016-03-05 21:15:22 +01:00
|
|
|
val = settings.dict_find_int("proxy_hostnames");
|
2016-04-25 23:22:09 +02:00
|
|
|
if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val.int_value() != 0);
|
2016-03-05 21:15:22 +01:00
|
|
|
val = settings.dict_find_int("proxy_peer_connections");
|
2016-04-25 23:22:09 +02:00
|
|
|
if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val.int_value() != 0);
|
2016-03-05 21:15:22 +01:00
|
|
|
val = settings.dict_find_string("hostname");
|
2016-08-13 13:04:53 +02:00
|
|
|
if (val) m_settings.set_str(settings_pack::proxy_hostname, val.string_value().to_string());
|
2016-03-05 21:15:22 +01:00
|
|
|
val = settings.dict_find_string("password");
|
2016-08-13 13:04:53 +02:00
|
|
|
if (val) m_settings.set_str(settings_pack::proxy_password, val.string_value().to_string());
|
2016-03-05 21:15:22 +01:00
|
|
|
val = settings.dict_find_string("username");
|
2016-08-13 13:04:53 +02:00
|
|
|
if (val) m_settings.set_str(settings_pack::proxy_username, val.string_value().to_string());
|
2016-03-05 21:15:22 +01:00
|
|
|
need_update_proxy = true;
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
settings = e->dict_find_dict("encryption");
|
|
|
|
if (settings)
|
2009-12-03 06:11:57 +01:00
|
|
|
{
|
2015-03-12 06:20:12 +01:00
|
|
|
bdecode_node val;
|
|
|
|
val = settings.dict_find_int("prefer_rc4");
|
2016-04-25 23:22:09 +02:00
|
|
|
if (val) m_settings.set_bool(settings_pack::prefer_rc4, val.int_value() != 0);
|
2015-03-12 06:20:12 +01:00
|
|
|
val = settings.dict_find_int("out_enc_policy");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) m_settings.set_int(settings_pack::out_enc_policy, int(val.int_value()));
|
2015-03-12 06:20:12 +01:00
|
|
|
val = settings.dict_find_int("in_enc_policy");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) m_settings.set_int(settings_pack::in_enc_policy, int(val.int_value()));
|
2015-03-12 06:20:12 +01:00
|
|
|
val = settings.dict_find_int("allowed_enc_level");
|
2016-12-06 14:24:01 +01:00
|
|
|
if (val) m_settings.set_int(settings_pack::allowed_enc_level, int(val.int_value()));
|
2009-12-03 06:11:57 +01:00
|
|
|
}
|
2015-03-28 18:31:27 +01:00
|
|
|
#endif
|
2011-01-29 11:37:21 +01:00
|
|
|
|
2016-09-17 15:42:04 +02:00
|
|
|
if (flags & session_handle::save_settings)
|
2015-09-08 21:15:51 +02:00
|
|
|
{
|
2016-03-05 21:15:22 +01:00
|
|
|
settings = e->dict_find_dict("settings");
|
|
|
|
if (settings)
|
|
|
|
{
|
|
|
|
// apply_settings_pack will update dht and proxy
|
2016-09-11 07:58:48 +02:00
|
|
|
settings_pack pack = load_pack_from_dict(settings);
|
2017-01-15 07:21:52 +01:00
|
|
|
|
|
|
|
// these settings are not loaded from state
|
|
|
|
// they are set by the client software, not configured by users
|
2017-01-21 08:28:29 +01:00
|
|
|
pack.clear(settings_pack::user_agent);
|
|
|
|
pack.clear(settings_pack::peer_fingerprint);
|
2017-01-15 07:21:52 +01:00
|
|
|
|
2016-09-11 07:58:48 +02:00
|
|
|
apply_settings_pack_impl(pack);
|
2015-09-08 21:15:51 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2016-03-05 21:15:22 +01:00
|
|
|
need_update_dht = false;
|
2015-09-08 21:15:51 +02:00
|
|
|
#endif
|
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2016-03-05 21:15:22 +01:00
|
|
|
need_update_proxy = false;
|
2015-09-08 21:15:51 +02:00
|
|
|
#endif
|
2016-03-05 21:15:22 +01:00
|
|
|
}
|
2015-09-08 21:15:51 +02:00
|
|
|
}
|
|
|
|
|
2016-03-05 21:15:22 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (need_update_dht) update_dht();
|
|
|
|
#endif
|
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
if (need_update_proxy) update_proxy();
|
|
|
|
#endif
|
|
|
|
|
2011-01-29 11:37:21 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2016-06-18 04:02:21 +02:00
|
|
|
for (auto& ext : m_ses_extensions[plugins_all_idx])
|
2011-01-29 11:37:21 +01:00
|
|
|
{
|
2016-10-23 04:00:47 +02:00
|
|
|
ext->load_state(*e);
|
2011-01-29 11:37:21 +01:00
|
|
|
}
|
|
|
|
#endif
|
2009-12-03 06:11:57 +01:00
|
|
|
}
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2013-01-07 05:19:19 +01:00
|
|
|
|
|
|
|
void session_impl::add_extension(ext_function_t ext)
|
2006-11-14 01:08:16 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2016-08-13 03:31:55 +02:00
|
|
|
TORRENT_ASSERT(ext);
|
2008-09-22 01:19:58 +02:00
|
|
|
|
2016-08-17 20:30:24 +02:00
|
|
|
add_ses_extension(std::make_shared<session_plugin_wrapper>(ext));
|
2006-11-14 01:08:16 +01:00
|
|
|
}
|
2011-01-29 11:37:21 +01:00
|
|
|
|
2016-08-17 20:30:24 +02:00
|
|
|
void session_impl::add_ses_extension(std::shared_ptr<plugin> ext)
|
2011-01-29 11:37:21 +01:00
|
|
|
{
|
2016-12-29 17:54:28 +01:00
|
|
|
// this is called during startup of the session, from the thread creating
|
|
|
|
// it, not its own thread
|
|
|
|
// TORRENT_ASSERT(is_single_thread());
|
2011-01-29 11:37:21 +01:00
|
|
|
TORRENT_ASSERT_VAL(ext, ext);
|
|
|
|
|
2016-06-18 20:01:38 +02:00
|
|
|
std::uint32_t const features = ext->implemented_features();
|
2014-02-17 06:56:49 +01:00
|
|
|
|
2016-06-18 04:02:21 +02:00
|
|
|
m_ses_extensions[plugins_all_idx].push_back(ext);
|
|
|
|
|
|
|
|
if (features & plugin::optimistic_unchoke_feature)
|
|
|
|
m_ses_extensions[plugins_optimistic_unchoke_idx].push_back(ext);
|
|
|
|
if (features & plugin::tick_feature)
|
|
|
|
m_ses_extensions[plugins_tick_idx].push_back(ext);
|
|
|
|
if (features & plugin::dht_request_feature)
|
|
|
|
m_ses_extensions[plugins_dht_request_idx].push_back(ext);
|
|
|
|
if (features & plugin::alert_feature)
|
|
|
|
m_alerts.add_extension(ext);
|
2016-08-17 20:30:24 +02:00
|
|
|
session_handle h(this);
|
|
|
|
ext->added(h);
|
2011-01-29 11:37:21 +01:00
|
|
|
}
|
2014-02-17 06:56:49 +01:00
|
|
|
|
2015-05-28 16:46:12 +02:00
|
|
|
#endif // TORRENT_DISABLE_EXTENSIONS
|
2006-11-14 01:08:16 +01:00
|
|
|
|
2008-06-29 21:08:30 +02:00
|
|
|
void session_impl::pause()
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2010-09-25 22:07:27 +02:00
|
|
|
|
2008-06-29 21:08:30 +02:00
|
|
|
if (m_paused) return;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" *** session paused ***");
|
2008-12-30 09:20:25 +01:00
|
|
|
#endif
|
2008-06-29 21:08:30 +02:00
|
|
|
m_paused = true;
|
2016-06-03 13:32:48 +02:00
|
|
|
for (auto& te : m_torrents)
|
2008-06-29 21:08:30 +02:00
|
|
|
{
|
2016-06-03 13:32:48 +02:00
|
|
|
te.second->set_session_paused(true);
|
2008-06-29 21:08:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::resume()
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2010-09-25 22:07:27 +02:00
|
|
|
|
2008-06-29 21:08:30 +02:00
|
|
|
if (!m_paused) return;
|
|
|
|
m_paused = false;
|
2016-06-03 13:32:48 +02:00
|
|
|
|
|
|
|
for (auto& te : m_torrents)
|
2008-06-29 21:08:30 +02:00
|
|
|
{
|
2016-06-03 13:32:48 +02:00
|
|
|
te.second->set_session_paused(false);
|
2008-06-29 21:08:30 +02:00
|
|
|
}
|
|
|
|
}
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
void session_impl::abort()
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2010-09-25 22:07:27 +02:00
|
|
|
|
2007-10-07 20:06:56 +02:00
|
|
|
if (m_abort) return;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" *** ABORT CALLED ***");
|
2007-10-07 20:06:56 +02:00
|
|
|
#endif
|
2014-12-17 03:44:27 +01:00
|
|
|
|
2016-08-20 17:04:44 +02:00
|
|
|
// at this point we cannot call the notify function anymore, since the
|
|
|
|
// session will become invalid.
|
2016-08-21 22:28:49 +02:00
|
|
|
m_alerts.set_notify_function(std::function<void()>());
|
2016-08-20 17:04:44 +02:00
|
|
|
|
2014-12-17 03:44:27 +01:00
|
|
|
// this will cancel requests that are not critical for shutting down
|
|
|
|
// cleanly. i.e. essentially tracker hostname lookups that we're not
|
|
|
|
// about to send event=stopped to
|
|
|
|
m_host_resolver.abort();
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
// abort the main thread
|
|
|
|
m_abort = true;
|
2009-09-16 05:46:36 +02:00
|
|
|
error_code ec;
|
2016-11-07 13:40:09 +01:00
|
|
|
|
|
|
|
m_ip_notifier.cancel();
|
|
|
|
|
2009-08-20 05:19:12 +02:00
|
|
|
#if TORRENT_USE_I2P
|
2009-09-16 05:46:36 +02:00
|
|
|
m_i2p_conn.close(ec);
|
2009-08-20 05:19:12 +02:00
|
|
|
#endif
|
2011-10-25 07:55:32 +02:00
|
|
|
stop_lsd();
|
|
|
|
stop_upnp();
|
|
|
|
stop_natpmp();
|
2007-10-07 20:06:56 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2012-06-25 05:31:11 +02:00
|
|
|
stop_dht();
|
2010-02-14 02:39:55 +01:00
|
|
|
m_dht_announce_timer.cancel(ec);
|
2007-10-07 20:06:56 +02:00
|
|
|
#endif
|
2010-02-05 09:23:17 +01:00
|
|
|
m_lsd_announce_timer.cancel(ec);
|
2007-10-26 09:14:19 +02:00
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
for (auto const& s : m_incoming_sockets)
|
2013-08-21 17:55:24 +02:00
|
|
|
{
|
2016-08-31 18:45:45 +02:00
|
|
|
s->close(ec);
|
2013-09-14 12:26:55 +02:00
|
|
|
TORRENT_ASSERT(!ec);
|
2013-08-21 17:55:24 +02:00
|
|
|
}
|
|
|
|
m_incoming_sockets.clear();
|
|
|
|
|
2007-10-26 09:14:19 +02:00
|
|
|
// close the listen sockets
|
2016-09-05 03:49:11 +02:00
|
|
|
for (auto const& l : m_listen_sockets)
|
2007-10-26 09:14:19 +02:00
|
|
|
{
|
2016-09-05 03:49:11 +02:00
|
|
|
if (l.sock)
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
2016-09-05 03:49:11 +02:00
|
|
|
l.sock->close(ec);
|
2016-04-24 21:26:28 +02:00
|
|
|
TORRENT_ASSERT(!ec);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: 3 closing the udp sockets here means that
|
|
|
|
// the uTP connections cannot be closed gracefully
|
2016-09-05 03:49:11 +02:00
|
|
|
if (l.udp_sock)
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
2016-09-05 03:49:11 +02:00
|
|
|
l.udp_sock->close();
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
2007-10-26 09:14:19 +02:00
|
|
|
}
|
2012-07-15 04:30:13 +02:00
|
|
|
if (m_socks_listen_socket && m_socks_listen_socket->is_open())
|
2013-09-14 12:26:55 +02:00
|
|
|
{
|
|
|
|
m_socks_listen_socket->close(ec);
|
|
|
|
TORRENT_ASSERT(!ec);
|
|
|
|
}
|
2012-07-15 04:30:13 +02:00
|
|
|
m_socks_listen_socket.reset();
|
2012-07-31 18:53:37 +02:00
|
|
|
|
|
|
|
#if TORRENT_USE_I2P
|
2012-07-15 04:30:13 +02:00
|
|
|
if (m_i2p_listen_socket && m_i2p_listen_socket->is_open())
|
2013-09-14 12:26:55 +02:00
|
|
|
{
|
|
|
|
m_i2p_listen_socket->close(ec);
|
|
|
|
TORRENT_ASSERT(!ec);
|
|
|
|
}
|
2012-07-15 04:30:13 +02:00
|
|
|
m_i2p_listen_socket.reset();
|
2012-07-31 18:53:37 +02:00
|
|
|
#endif
|
2007-10-26 09:14:19 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-04-25 06:22:51 +02:00
|
|
|
session_log(" aborting all torrents (%d)", int(m_torrents.size()));
|
2007-10-29 01:29:43 +01:00
|
|
|
#endif
|
2007-10-07 20:06:56 +02:00
|
|
|
// abort all torrents
|
2016-09-05 03:49:11 +02:00
|
|
|
for (auto const& te : m_torrents)
|
2007-10-07 20:06:56 +02:00
|
|
|
{
|
2016-09-05 03:49:11 +02:00
|
|
|
te.second->abort();
|
2007-10-07 20:06:56 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
m_torrents.clear();
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" aborting all tracker requests");
|
2007-10-29 01:29:43 +01:00
|
|
|
#endif
|
2007-11-02 01:27:53 +01:00
|
|
|
m_tracker_manager.abort_all_requests();
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-04-25 06:22:51 +02:00
|
|
|
session_log(" aborting all connections (%d)", int(m_connections.size()));
|
2007-11-02 01:27:53 +01:00
|
|
|
#endif
|
|
|
|
// abort all connections
|
|
|
|
while (!m_connections.empty())
|
|
|
|
{
|
2014-01-19 20:45:50 +01:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2016-05-13 03:24:45 +02:00
|
|
|
int conn = int(m_connections.size());
|
2007-11-02 01:27:53 +01:00
|
|
|
#endif
|
2015-02-15 06:17:09 +01:00
|
|
|
(*m_connections.begin())->disconnect(errors::stopping_torrent, op_bittorrent);
|
2010-09-25 19:46:13 +02:00
|
|
|
TORRENT_ASSERT_VAL(conn == int(m_connections.size()) + 1, conn);
|
2007-11-02 01:27:53 +01:00
|
|
|
}
|
2007-10-26 09:14:19 +02:00
|
|
|
|
2015-11-28 20:06:40 +01:00
|
|
|
// we need to give all the sockets an opportunity to actually have their handlers
|
|
|
|
// called and cancelled before we continue the shutdown. This is a bit
|
|
|
|
// complicated, if there are no "undead" peers, it's safe tor resume the
|
|
|
|
// shutdown, but if there are, we have to wait for them to be cleared out
|
|
|
|
// first. In session_impl::on_tick() we check them periodically. If we're
|
|
|
|
// shutting down and we remove the last one, we'll initiate
|
|
|
|
// shutdown_stage2 from there.
|
|
|
|
if (m_undead_peers.empty())
|
|
|
|
{
|
2016-05-25 06:31:52 +02:00
|
|
|
m_io_service.post(std::bind(&session_impl::abort_stage2, this));
|
2015-11-28 20:06:40 +01:00
|
|
|
}
|
2015-06-14 22:00:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::abort_stage2()
|
|
|
|
{
|
2016-03-16 02:10:58 +01:00
|
|
|
m_download_rate.close();
|
|
|
|
m_upload_rate.close();
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// it's OK to detach the threads here. The disk_io_thread
|
|
|
|
// has an internal counter and won't release the network
|
|
|
|
// thread until they're all dead (via m_work).
|
2015-06-14 22:00:04 +02:00
|
|
|
m_disk_thread.abort(false);
|
2015-06-03 05:04:44 +02:00
|
|
|
|
|
|
|
// now it's OK for the network thread to exit
|
|
|
|
m_work.reset();
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool session_impl::has_connection(peer_connection* p) const
|
|
|
|
{
|
|
|
|
return m_connections.find(p->self()) != m_connections.end();
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2016-09-01 03:42:18 +02:00
|
|
|
void session_impl::insert_peer(std::shared_ptr<peer_connection> const& c)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(!c->m_in_constructor);
|
|
|
|
m_connections.insert(c);
|
|
|
|
}
|
2015-05-16 08:33:37 +02:00
|
|
|
|
2007-06-01 03:05:57 +02:00
|
|
|
void session_impl::set_port_filter(port_filter const& f)
|
|
|
|
{
|
|
|
|
m_port_filter = f;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::no_connect_privileged_ports))
|
|
|
|
m_port_filter.add_rule(0, 1024, port_filter::blocked);
|
|
|
|
// Close connections whose endpoint is filtered
|
|
|
|
// by the new ip-filter
|
2016-09-09 01:13:47 +02:00
|
|
|
for (auto const& t : m_torrents)
|
|
|
|
t.second->port_filter_updated();
|
2007-06-01 03:05:57 +02:00
|
|
|
}
|
|
|
|
|
2016-09-01 03:42:18 +02:00
|
|
|
void session_impl::set_ip_filter(std::shared_ptr<ip_filter> const& f)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
m_ip_filter = f;
|
|
|
|
|
|
|
|
// Close connections whose endpoint is filtered
|
|
|
|
// by the new ip-filter
|
2007-07-26 09:04:35 +02:00
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
2015-05-16 08:33:37 +02:00
|
|
|
i->second->set_ip_filter(m_ip_filter);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2015-05-16 08:33:37 +02:00
|
|
|
void session_impl::ban_ip(address addr)
|
2009-07-21 03:52:37 +02:00
|
|
|
{
|
2015-05-16 08:33:37 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2016-09-01 03:42:18 +02:00
|
|
|
if (!m_ip_filter) m_ip_filter = std::make_shared<ip_filter>();
|
2015-05-16 08:33:37 +02:00
|
|
|
m_ip_filter->add_rule(addr, addr, ip_filter::blocked);
|
2015-11-12 02:43:42 +01:00
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
i->second->set_ip_filter(m_ip_filter);
|
2015-05-16 08:33:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ip_filter const& session_impl::get_ip_filter()
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2016-09-01 03:42:18 +02:00
|
|
|
if (!m_ip_filter) m_ip_filter = std::make_shared<ip_filter>();
|
2015-05-16 08:33:37 +02:00
|
|
|
return *m_ip_filter;
|
2009-07-21 03:52:37 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
port_filter const& session_impl::get_port_filter() const
|
2010-03-10 08:14:10 +01:00
|
|
|
{
|
2015-05-16 08:33:37 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2014-07-06 21:18:00 +02:00
|
|
|
return m_port_filter;
|
2010-03-10 08:14:10 +01:00
|
|
|
}
|
|
|
|
|
2015-05-16 08:33:37 +02:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
2013-09-03 10:39:30 +02:00
|
|
|
template <class Socket>
|
2015-05-16 08:33:37 +02:00
|
|
|
void set_socket_buffer_size(Socket& s, session_settings const& sett, error_code& ec)
|
2013-09-03 10:39:30 +02:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
int const snd_size = sett.get_int(settings_pack::send_socket_buffer_size);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (snd_size)
|
2013-09-03 10:39:30 +02:00
|
|
|
{
|
2015-07-12 05:01:27 +02:00
|
|
|
typename Socket::send_buffer_size prev_option;
|
2013-09-03 10:39:30 +02:00
|
|
|
s.get_option(prev_option, ec);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!ec && prev_option.value() != snd_size)
|
2013-09-03 10:39:30 +02:00
|
|
|
{
|
2015-07-12 05:01:27 +02:00
|
|
|
typename Socket::send_buffer_size option(snd_size);
|
2013-09-03 10:39:30 +02:00
|
|
|
s.set_option(option, ec);
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
// restore previous value
|
|
|
|
s.set_option(prev_option, ec);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
int const recv_size = sett.get_int(settings_pack::recv_socket_buffer_size);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (recv_size)
|
2013-09-03 10:39:30 +02:00
|
|
|
{
|
2015-07-12 05:01:27 +02:00
|
|
|
typename Socket::receive_buffer_size prev_option;
|
2013-09-03 10:39:30 +02:00
|
|
|
s.get_option(prev_option, ec);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!ec && prev_option.value() != recv_size)
|
2013-09-03 10:39:30 +02:00
|
|
|
{
|
2015-07-12 05:01:27 +02:00
|
|
|
typename Socket::receive_buffer_size option(recv_size);
|
2013-09-03 10:39:30 +02:00
|
|
|
s.set_option(option, ec);
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
// restore previous value
|
|
|
|
s.set_option(prev_option, ec);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-16 08:33:37 +02:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2017-01-22 04:40:19 +01:00
|
|
|
peer_class_t session_impl::create_peer_class(char const* name)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2015-05-16 08:33:37 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2014-07-06 21:18:00 +02:00
|
|
|
return m_classes.new_peer_class(name);
|
|
|
|
}
|
2010-10-09 21:09:38 +02:00
|
|
|
|
2017-01-22 18:06:52 +01:00
|
|
|
void session_impl::delete_peer_class(peer_class_t cid)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2015-05-16 08:33:37 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2014-07-06 21:18:00 +02:00
|
|
|
// if you hit this assert, you're deleting a non-existent peer class
|
2017-01-22 18:06:52 +01:00
|
|
|
TORRENT_ASSERT(m_classes.at(cid));
|
|
|
|
if (m_classes.at(cid) == nullptr) return;
|
|
|
|
m_classes.decref(cid);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2010-02-09 04:04:41 +01:00
|
|
|
|
2017-01-22 18:06:52 +01:00
|
|
|
peer_class_info session_impl::get_peer_class(peer_class_t cid)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
peer_class_info ret;
|
2017-01-22 18:06:52 +01:00
|
|
|
peer_class* pc = m_classes.at(cid);
|
2014-07-06 21:18:00 +02:00
|
|
|
// if you hit this assert, you're passing in an invalid cid
|
|
|
|
TORRENT_ASSERT(pc);
|
2016-07-09 22:26:26 +02:00
|
|
|
if (pc == nullptr)
|
2010-01-31 17:35:38 +01:00
|
|
|
{
|
2016-07-02 01:46:59 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2014-07-06 21:18:00 +02:00
|
|
|
// make it obvious that the return value is undefined
|
2015-05-04 00:21:19 +02:00
|
|
|
ret.upload_limit = 0xf0f0f0f;
|
|
|
|
ret.download_limit = 0xf0f0f0f;
|
2014-07-06 21:18:00 +02:00
|
|
|
ret.label.resize(20);
|
|
|
|
url_random(&ret.label[0], &ret.label[0] + 20);
|
|
|
|
ret.ignore_unchoke_slots = false;
|
2015-05-04 00:21:19 +02:00
|
|
|
ret.connection_limit_factor = 0xf0f0f0f;
|
|
|
|
ret.upload_priority = 0xf0f0f0f;
|
|
|
|
ret.download_priority = 0xf0f0f0f;
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
return ret;
|
2010-01-31 17:35:38 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
pc->get_info(&ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2010-02-09 04:04:41 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::queue_tracker_request(tracker_request& req
|
2016-08-31 14:27:36 +02:00
|
|
|
, std::weak_ptr<request_callback> c)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
req.listen_port = listen_port();
|
2015-02-01 15:30:43 +01:00
|
|
|
if (m_key) req.key = m_key;
|
2010-02-14 02:39:55 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
// SSL torrents use the SSL listen port
|
2016-02-08 08:01:25 +01:00
|
|
|
// TODO: 2 this need to be more thought through. There isn't necessarily
|
|
|
|
// just _one_ SSL listen port, which one we use depends on which interface
|
|
|
|
// we announce from.
|
2014-07-06 21:18:00 +02:00
|
|
|
if (req.ssl_ctx) req.listen_port = ssl_listen_port();
|
|
|
|
req.ssl_ctx = &m_ssl_ctx;
|
2010-11-28 02:47:30 +01:00
|
|
|
#endif
|
2015-02-01 15:30:43 +01:00
|
|
|
#if TORRENT_USE_I2P
|
2015-08-28 13:20:21 +02:00
|
|
|
if (!m_settings.get_str(settings_pack::i2p_hostname).empty())
|
|
|
|
{
|
|
|
|
req.i2pconn = &m_i2p_conn;
|
|
|
|
}
|
2015-02-01 15:30:43 +01:00
|
|
|
#endif
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
//TODO: should there be an option to announce once per listen interface?
|
|
|
|
|
2015-02-01 15:30:43 +01:00
|
|
|
m_tracker_manager.queue_request(get_io_service(), req, c);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2010-02-13 17:29:17 +01:00
|
|
|
|
2017-01-22 18:06:52 +01:00
|
|
|
void session_impl::set_peer_class(peer_class_t cid, peer_class_info const& pci)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2017-01-22 18:06:52 +01:00
|
|
|
peer_class* pc = m_classes.at(cid);
|
2014-07-06 21:18:00 +02:00
|
|
|
// if you hit this assert, you're passing in an invalid cid
|
|
|
|
TORRENT_ASSERT(pc);
|
2016-07-09 22:26:26 +02:00
|
|
|
if (pc == nullptr) return;
|
2010-04-13 06:30:34 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
pc->set_info(&pci);
|
|
|
|
}
|
2010-07-15 08:27:44 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::set_peer_class_filter(ip_filter const& f)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
m_peer_class_filter = f;
|
|
|
|
}
|
2011-01-23 19:00:52 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
ip_filter const& session_impl::get_peer_class_filter() const
|
|
|
|
{
|
|
|
|
return m_peer_class_filter;
|
|
|
|
}
|
2011-03-14 08:47:24 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::set_peer_class_type_filter(peer_class_type_filter f)
|
|
|
|
{
|
|
|
|
m_peer_class_type_filter = f;
|
|
|
|
}
|
|
|
|
|
|
|
|
peer_class_type_filter session_impl::get_peer_class_type_filter()
|
|
|
|
{
|
|
|
|
return m_peer_class_type_filter;
|
|
|
|
}
|
|
|
|
|
2017-02-08 16:54:55 +01:00
|
|
|
void session_impl::set_peer_classes(peer_class_set* s, address const& a, int const st)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-06-18 20:01:38 +02:00
|
|
|
std::uint32_t peer_class_mask = m_peer_class_filter.access(a);
|
2012-01-29 21:59:20 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// assign peer class based on socket type
|
2015-03-14 01:42:27 +01:00
|
|
|
static const int mapping[] = { 0, 0, 0, 0, 1, 4, 2, 2, 2, 3};
|
2014-07-06 21:18:00 +02:00
|
|
|
int socket_type = mapping[st];
|
|
|
|
// filter peer classes based on type
|
|
|
|
peer_class_mask = m_peer_class_type_filter.apply(socket_type, peer_class_mask);
|
|
|
|
|
2017-01-22 04:40:19 +01:00
|
|
|
for (peer_class_t i{0}; peer_class_mask; peer_class_mask >>= 1, ++i)
|
2013-09-02 11:24:34 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if ((peer_class_mask & 1) == 0) continue;
|
|
|
|
|
|
|
|
// if you hit this assert, your peer class filter contains
|
|
|
|
// a bitmask referencing a non-existent peer class
|
|
|
|
TORRENT_ASSERT_PRECOND(m_classes.at(i));
|
|
|
|
|
2016-07-09 22:26:26 +02:00
|
|
|
if (m_classes.at(i) == nullptr) continue;
|
2014-07-06 21:18:00 +02:00
|
|
|
s->add_class(m_classes, i);
|
2013-09-02 11:24:34 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2013-09-02 11:24:34 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
bool session_impl::ignore_unchoke_slots_set(peer_class_set const& set) const
|
|
|
|
{
|
|
|
|
int num = set.num_classes();
|
|
|
|
for (int i = 0; i < num; ++i)
|
|
|
|
{
|
|
|
|
peer_class const* pc = m_classes.at(set.class_at(i));
|
2016-07-09 22:26:26 +02:00
|
|
|
if (pc == nullptr) continue;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (pc->ignore_unchoke_slots) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2013-08-18 00:29:34 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
bandwidth_manager* session_impl::get_bandwidth_manager(int channel)
|
|
|
|
{
|
|
|
|
return (channel == peer_connection::download_channel)
|
|
|
|
? &m_download_rate : &m_upload_rate;
|
|
|
|
}
|
2010-04-13 06:30:34 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::deferred_submit_jobs()
|
|
|
|
{
|
|
|
|
if (m_deferred_submit_disk_jobs) return;
|
|
|
|
m_deferred_submit_disk_jobs = true;
|
2016-10-06 06:08:14 +02:00
|
|
|
m_io_service.post([this] { this->wrap(&session_impl::submit_disk_jobs); } );
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::submit_disk_jobs()
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(m_deferred_submit_disk_jobs);
|
|
|
|
m_deferred_submit_disk_jobs = false;
|
|
|
|
m_disk_thread.submit_jobs();
|
|
|
|
}
|
|
|
|
|
|
|
|
// copies pointers to bandwidth channels from the peer classes
|
|
|
|
// into the array. Only bandwidth channels with a bandwidth limit
|
|
|
|
// is considered pertinent and copied
|
|
|
|
// returns the number of pointers copied
|
|
|
|
// channel is upload_channel or download_channel
|
|
|
|
int session_impl::copy_pertinent_channels(peer_class_set const& set
|
|
|
|
, int channel, bandwidth_channel** dst, int max)
|
|
|
|
{
|
|
|
|
int num_channels = set.num_classes();
|
|
|
|
int num_copied = 0;
|
|
|
|
for (int i = 0; i < num_channels; ++i)
|
|
|
|
{
|
|
|
|
peer_class* pc = m_classes.at(set.class_at(i));
|
|
|
|
TORRENT_ASSERT(pc);
|
2016-07-09 22:26:26 +02:00
|
|
|
if (pc == nullptr) continue;
|
2014-07-06 21:18:00 +02:00
|
|
|
bandwidth_channel* chan = &pc->channel[channel];
|
|
|
|
// no need to include channels that don't have any bandwidth limits
|
|
|
|
if (chan->throttle() == 0) continue;
|
|
|
|
dst[num_copied] = chan;
|
|
|
|
++num_copied;
|
|
|
|
if (num_copied == max) break;
|
|
|
|
}
|
|
|
|
return num_copied;
|
|
|
|
}
|
|
|
|
|
2015-05-19 05:13:49 +02:00
|
|
|
bool session_impl::use_quota_overhead(bandwidth_channel* ch, int amount)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
ch->use_quota(amount);
|
|
|
|
return (ch->throttle() > 0 && ch->throttle() < amount);
|
|
|
|
}
|
|
|
|
|
|
|
|
int session_impl::use_quota_overhead(peer_class_set& set, int amount_down, int amount_up)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int num = set.num_classes();
|
|
|
|
for (int i = 0; i < num; ++i)
|
|
|
|
{
|
|
|
|
peer_class* p = m_classes.at(set.class_at(i));
|
2016-07-09 22:26:26 +02:00
|
|
|
if (p == nullptr) continue;
|
2015-05-19 05:13:49 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
bandwidth_channel* ch = &p->channel[peer_connection::download_channel];
|
2015-05-19 05:13:49 +02:00
|
|
|
if (use_quota_overhead(ch, amount_down))
|
2014-07-06 21:18:00 +02:00
|
|
|
ret |= 1 << peer_connection::download_channel;
|
|
|
|
ch = &p->channel[peer_connection::upload_channel];
|
2015-05-19 05:13:49 +02:00
|
|
|
if (use_quota_overhead(ch, amount_up))
|
2014-07-06 21:18:00 +02:00
|
|
|
ret |= 1 << peer_connection::upload_channel;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-05-29 07:27:53 +02:00
|
|
|
// session_impl is responsible for deleting 'pack'
|
2016-09-01 03:42:18 +02:00
|
|
|
void session_impl::apply_settings_pack(std::shared_ptr<settings_pack> pack)
|
2015-05-29 07:27:53 +02:00
|
|
|
{
|
2016-12-26 17:09:52 +01:00
|
|
|
INVARIANT_CHECK;
|
2015-05-29 07:27:53 +02:00
|
|
|
apply_settings_pack_impl(*pack);
|
|
|
|
}
|
|
|
|
|
2015-06-07 06:23:30 +02:00
|
|
|
settings_pack session_impl::get_settings() const
|
|
|
|
{
|
|
|
|
settings_pack ret;
|
|
|
|
// TODO: it would be nice to reserve() these vectors up front
|
|
|
|
for (int i = settings_pack::string_type_base;
|
|
|
|
i < settings_pack::max_string_setting_internal; ++i)
|
|
|
|
{
|
|
|
|
ret.set_str(i, m_settings.get_str(i));
|
|
|
|
}
|
|
|
|
for (int i = settings_pack::int_type_base;
|
|
|
|
i < settings_pack::max_int_setting_internal; ++i)
|
|
|
|
{
|
|
|
|
ret.set_int(i, m_settings.get_int(i));
|
|
|
|
}
|
|
|
|
for (int i = settings_pack::bool_type_base;
|
|
|
|
i < settings_pack::max_bool_setting_internal; ++i)
|
|
|
|
{
|
|
|
|
ret.set_bool(i, m_settings.get_bool(i));
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-06-23 23:54:31 +02:00
|
|
|
void session_impl::apply_settings_pack_impl(settings_pack const& pack
|
|
|
|
, bool const init)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-06-23 23:54:31 +02:00
|
|
|
bool const reopen_listen_port =
|
2016-02-08 08:01:25 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2015-05-29 07:27:53 +02:00
|
|
|
(pack.has_val(settings_pack::ssl_listen)
|
|
|
|
&& pack.get_int(settings_pack::ssl_listen)
|
2014-07-06 21:18:00 +02:00
|
|
|
!= m_settings.get_int(settings_pack::ssl_listen))
|
2016-02-08 08:01:25 +01:00
|
|
|
||
|
|
|
|
#endif
|
|
|
|
(pack.has_val(settings_pack::listen_interfaces)
|
2015-05-29 07:27:53 +02:00
|
|
|
&& pack.get_str(settings_pack::listen_interfaces)
|
2014-07-06 21:18:00 +02:00
|
|
|
!= m_settings.get_str(settings_pack::listen_interfaces));
|
|
|
|
|
2016-09-20 17:24:24 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
|
|
|
session_log("applying settings pack, init=%s, reopen_listen_port=%s"
|
|
|
|
, init ? "true" : "false", reopen_listen_port ? "true" : "false");
|
|
|
|
#endif
|
|
|
|
|
2015-05-29 07:27:53 +02:00
|
|
|
apply_pack(&pack, m_settings, this);
|
2016-12-26 01:07:31 +01:00
|
|
|
m_disk_thread.set_settings(&pack);
|
2013-08-18 00:29:34 +02:00
|
|
|
|
2016-09-20 17:24:24 +02:00
|
|
|
if (init && !reopen_listen_port)
|
2016-11-06 19:39:09 +01:00
|
|
|
{
|
|
|
|
// no need to call this if reopen_listen_port is true
|
2016-09-20 17:24:24 +02:00
|
|
|
// since the apply_pack will do it
|
2016-06-23 23:54:31 +02:00
|
|
|
update_listen_interfaces();
|
2016-09-20 17:24:24 +02:00
|
|
|
}
|
2016-06-23 23:54:31 +02:00
|
|
|
|
|
|
|
if (init || reopen_listen_port)
|
2013-08-18 00:29:34 +02:00
|
|
|
{
|
2016-02-09 00:15:47 +01:00
|
|
|
reopen_listen_sockets();
|
2013-08-18 00:29:34 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// TODO: 3 try to remove these functions. They are misleading and not very
|
|
|
|
// useful. Anything using these should probably be fixed to do something more
|
|
|
|
// multi-homed friendly
|
2007-09-22 18:27:29 +02:00
|
|
|
tcp::endpoint session_impl::get_ipv6_interface() const
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
2016-02-07 08:09:19 +01:00
|
|
|
for (std::list<listen_socket_t>::const_iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
if (!i->local_endpoint.address().is_v6()) continue;
|
2016-11-25 17:17:25 +01:00
|
|
|
return tcp::endpoint(i->local_endpoint.address(), std::uint16_t(i->tcp_external_port));
|
2016-02-07 08:09:19 +01:00
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
#endif
|
2016-02-07 08:09:19 +01:00
|
|
|
return tcp::endpoint();
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2009-04-12 02:37:06 +02:00
|
|
|
tcp::endpoint session_impl::get_ipv4_interface() const
|
|
|
|
{
|
2016-02-07 08:09:19 +01:00
|
|
|
for (std::list<listen_socket_t>::const_iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
if (!i->local_endpoint.address().is_v4()) continue;
|
2016-11-25 17:17:25 +01:00
|
|
|
return tcp::endpoint(i->local_endpoint.address(), std::uint16_t(i->tcp_external_port));
|
2016-02-07 08:09:19 +01:00
|
|
|
}
|
|
|
|
return tcp::endpoint();
|
2009-04-12 02:37:06 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
enum { listen_no_system_port = 0x02 };
|
|
|
|
|
2014-10-22 00:08:48 +02:00
|
|
|
listen_socket_t session_impl::setup_listener(std::string const& device
|
2016-02-07 08:09:19 +01:00
|
|
|
, tcp::endpoint bind_ep, int flags, error_code& ec)
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
2015-06-30 05:10:09 +02:00
|
|
|
int retries = m_settings.get_int(settings_pack::max_retry_port_bind);
|
|
|
|
|
2016-02-07 08:09:19 +01:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
2016-09-23 22:49:39 +02:00
|
|
|
session_log("attempting to open listen socket to: %s on device: %s flags: %x"
|
2016-09-14 04:46:07 +02:00
|
|
|
, print_endpoint(bind_ep).c_str(), device.c_str(), flags);
|
|
|
|
}
|
2016-02-07 08:09:19 +01:00
|
|
|
#endif
|
|
|
|
|
2014-10-22 00:08:48 +02:00
|
|
|
listen_socket_t ret;
|
2016-04-17 22:56:07 +02:00
|
|
|
ret.ssl = (flags & open_ssl_socket) != 0;
|
2016-11-21 02:06:52 +01:00
|
|
|
ret.original_port = bind_ep.port();
|
2013-06-04 02:35:42 +02:00
|
|
|
int last_op = 0;
|
2016-10-19 07:32:15 +02:00
|
|
|
socket_type_t const sock_type
|
2016-02-07 08:09:19 +01:00
|
|
|
= (flags & open_ssl_socket)
|
2016-10-19 07:32:15 +02:00
|
|
|
? socket_type_t::tcp_ssl
|
|
|
|
: socket_type_t::tcp;
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
// if we're in force-proxy mode, don't open TCP listen sockets. We cannot
|
|
|
|
// accept connections on our local machine in this case.
|
|
|
|
// TODO: 3 the logic in this if-block should be factored out into a
|
|
|
|
// separate function. At least most of it
|
|
|
|
if (!m_settings.get_bool(settings_pack::force_proxy))
|
2010-08-25 08:22:49 +02:00
|
|
|
{
|
2016-08-31 18:45:45 +02:00
|
|
|
ret.sock = std::make_shared<tcp::acceptor>(m_io_service);
|
2016-04-24 21:26:28 +02:00
|
|
|
ret.sock->open(bind_ep.protocol(), ec);
|
|
|
|
last_op = listen_failed_alert::open;
|
|
|
|
if (ec)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("failed to open socket: %s"
|
|
|
|
, ec.message().c_str());
|
|
|
|
}
|
2010-08-25 08:22:49 +02:00
|
|
|
#endif
|
2016-02-07 08:09:19 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
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;
|
|
|
|
}
|
2012-06-28 08:51:18 +02:00
|
|
|
|
2016-02-07 08:09:19 +01:00
|
|
|
#ifdef TORRENT_WINDOWS
|
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
// this is best-effort. ignore errors
|
|
|
|
error_code err;
|
|
|
|
ret.sock->set_option(exclusive_address_use(true), err);
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (err && should_log())
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
|
|
|
session_log("failed enable exclusive address use on listen socket: %s"
|
|
|
|
, err.message().c_str());
|
|
|
|
}
|
2016-02-07 08:09:19 +01:00
|
|
|
#endif // TORRENT_DISABLE_LOGGING
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
2016-02-07 08:09:19 +01:00
|
|
|
#endif // TORRENT_WINDOWS
|
|
|
|
|
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
// this is best-effort. ignore errors
|
|
|
|
error_code err;
|
|
|
|
ret.sock->set_option(tcp::acceptor::reuse_address(true), err);
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (err && should_log())
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
|
|
|
session_log("failed enable reuse-address on listen socket: %s"
|
|
|
|
, err.message().c_str());
|
|
|
|
}
|
2016-02-07 08:09:19 +01:00
|
|
|
#endif // TORRENT_DISABLE_LOGGING
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
2012-06-28 08:51:18 +02:00
|
|
|
|
2009-04-04 18:59:53 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
2016-04-24 21:26:28 +02:00
|
|
|
if (bind_ep.address().is_v6())
|
2016-02-07 08:09:19 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
error_code err; // ignore errors here
|
|
|
|
ret.sock->set_option(boost::asio::ip::v6_only(true), err);
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (err && should_log())
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
|
|
|
session_log("failed enable v6 only on listen socket: %s"
|
|
|
|
, err.message().c_str());
|
|
|
|
}
|
2016-02-07 08:09:19 +01:00
|
|
|
#endif // LOGGING
|
|
|
|
|
2009-01-21 02:39:13 +01:00
|
|
|
#ifdef TORRENT_WINDOWS
|
2016-04-24 21:26:28 +02:00
|
|
|
// enable Teredo on windows
|
|
|
|
ret.sock->set_option(v6_protection_level(PROTECTION_LEVEL_UNRESTRICTED), err);
|
2016-02-07 08:09:19 +01:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (err && should_log())
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
|
|
|
session_log("failed enable IPv6 unrestricted protection level on "
|
|
|
|
"listen socket: %s", err.message().c_str());
|
|
|
|
}
|
2016-02-07 08:09:19 +01:00
|
|
|
#endif // TORRENT_DISABLE_LOGGING
|
2016-01-31 09:06:24 +01:00
|
|
|
#endif // TORRENT_WINDOWS
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif // TORRENT_USE_IPV6
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
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
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("bind to device failed (device: %s): %s"
|
|
|
|
, device.c_str(), ec.message().c_str());
|
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
#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;
|
|
|
|
|
|
|
|
while (ec == error_code(error::address_in_use) && retries > 0)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT_VAL(ec, ec);
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("failed to bind listen socket to: %s on device: %s :"
|
|
|
|
" [%s] (%d) %s (retries: %d)"
|
|
|
|
, print_endpoint(bind_ep).c_str()
|
|
|
|
, device.c_str()
|
|
|
|
, ec.category().name(), ec.value(), ec.message().c_str()
|
|
|
|
, retries);
|
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
#endif
|
|
|
|
ec.clear();
|
|
|
|
--retries;
|
|
|
|
bind_ep.port(bind_ep.port() + 1);
|
|
|
|
ret.sock->bind(bind_ep, ec);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ec == error_code(error::address_in_use)
|
2016-09-20 17:11:24 +02:00
|
|
|
&& !(flags & listen_no_system_port)
|
|
|
|
&& bind_ep.port() != 0)
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
|
|
|
// instead of giving up, try let the OS pick a port
|
|
|
|
bind_ep.port(0);
|
|
|
|
ec.clear();
|
|
|
|
ret.sock->bind(bind_ep, ec);
|
|
|
|
last_op = listen_failed_alert::bind;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
// not even that worked, give up
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("failed to bind listen socket to: %s on device: %s :"
|
|
|
|
" [%s] (%d) %s (giving up)"
|
|
|
|
, print_endpoint(bind_ep).c_str()
|
|
|
|
, device.c_str()
|
|
|
|
, ec.category().name(), ec.value(), ec.message().c_str());
|
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
#endif
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
{
|
|
|
|
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep
|
|
|
|
, last_op, ec, sock_type);
|
|
|
|
}
|
|
|
|
ret.sock.reset();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret.local_endpoint = ret.sock->local_endpoint(ec);
|
2016-11-20 04:48:24 +01:00
|
|
|
ret.device = device;
|
2016-04-24 21:26:28 +02:00
|
|
|
last_op = listen_failed_alert::get_socket_name;
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("get_sockname failed on listen socket: %s"
|
|
|
|
, ec.message().c_str());
|
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
#endif
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
ret.tcp_external_port = ret.local_endpoint.port();
|
|
|
|
TORRENT_ASSERT(ret.tcp_external_port == bind_ep.port()
|
|
|
|
|| bind_ep.port() == 0);
|
|
|
|
|
|
|
|
ret.sock->listen(m_settings.get_int(settings_pack::listen_queue_size), ec);
|
|
|
|
last_op = listen_failed_alert::listen;
|
|
|
|
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("cannot listen on interface \"%s\": %s"
|
|
|
|
, device.c_str(), ec.message().c_str());
|
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
#endif
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
} // force-proxy mode
|
|
|
|
|
2016-11-27 22:19:39 +01:00
|
|
|
socket_type_t const udp_sock_type
|
|
|
|
= (flags & open_ssl_socket)
|
|
|
|
? socket_type_t::utp_ssl
|
|
|
|
: socket_type_t::udp;
|
2016-12-10 20:31:09 +01:00
|
|
|
udp::endpoint const udp_bind_ep(bind_ep.address(), bind_ep.port());
|
2016-11-27 22:19:39 +01:00
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
ret.udp_sock = std::make_shared<udp_socket>(m_io_service);
|
2016-12-10 20:31:09 +01:00
|
|
|
ret.udp_sock->open(udp_bind_ep.protocol(), ec);
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("failed to open UDP socket: %s: %s"
|
|
|
|
, device.c_str(), ec.message().c_str());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
last_op = listen_failed_alert::open;
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
m_alerts.emplace_alert<listen_failed_alert>(device
|
|
|
|
, bind_ep, last_op, ec, udp_sock_type);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
#if TORRENT_HAS_BINDTODEVICE
|
2016-02-09 00:11:00 +01:00
|
|
|
if (!device.empty())
|
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
ret.udp_sock->set_option(bind_to_device(device.c_str()), ec);
|
2016-02-09 00:11:00 +01:00
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("bind to device failed (device: %s): %s"
|
|
|
|
, device.c_str(), ec.message().c_str());
|
|
|
|
}
|
2016-02-09 00:11:00 +01:00
|
|
|
#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
|
2016-11-27 22:19:39 +01:00
|
|
|
, last_op, ec, udp_sock_type);
|
2016-02-09 00:11:00 +01:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
#endif
|
2016-12-10 20:31:09 +01:00
|
|
|
ret.udp_sock->bind(udp_bind_ep, ec);
|
2016-02-09 00:11:00 +01:00
|
|
|
|
2016-02-07 08:09:19 +01:00
|
|
|
last_op = listen_failed_alert::bind;
|
2016-04-24 21:26:28 +02:00
|
|
|
if (ec)
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
2016-12-10 20:31:09 +01:00
|
|
|
session_log("failed to bind UDP socket: %s: %s"
|
2016-09-14 04:46:07 +02:00
|
|
|
, device.c_str(), ec.message().c_str());
|
|
|
|
}
|
2010-08-25 08:22:49 +02:00
|
|
|
#endif
|
2016-02-07 08:09:19 +01:00
|
|
|
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
2016-04-24 21:26:28 +02:00
|
|
|
m_alerts.emplace_alert<listen_failed_alert>(device
|
|
|
|
, bind_ep, last_op, ec, udp_sock_type);
|
|
|
|
|
2014-10-22 00:08:48 +02:00
|
|
|
return ret;
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
ret.udp_external_port = ret.udp_sock->local_port();
|
|
|
|
|
|
|
|
error_code err;
|
|
|
|
set_socket_buffer_size(*ret.udp_sock, m_settings, err);
|
|
|
|
if (err)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
if (m_alerts.should_post<udp_error_alert>())
|
|
|
|
m_alerts.emplace_alert<udp_error_alert>(ret.udp_sock->local_endpoint(ec), err);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
ret.udp_sock->set_force_proxy(m_settings.get_bool(settings_pack::force_proxy));
|
2017-01-17 23:04:52 +01:00
|
|
|
// this call is necessary here because, unless the settings actually
|
|
|
|
// change after the session is up and listening, at no other point
|
|
|
|
// set_proxy_settings is called with the correct proxy configuration,
|
|
|
|
// internally, this method handle the SOCKS5's connection logic
|
|
|
|
ret.udp_sock->set_proxy_settings(proxy());
|
2016-02-07 08:09:19 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// TODO: 2 use a handler allocator here
|
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_udp_packet");
|
2016-05-25 06:31:52 +02:00
|
|
|
ret.udp_sock->async_read(std::bind(&session_impl::on_udp_packet
|
2016-08-31 18:45:45 +02:00
|
|
|
, this, std::weak_ptr<udp_socket>(ret.udp_sock), ret.ssl, _1));
|
2011-03-07 08:02:30 +01:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log(" listening on: %s TCP port: %d UDP port: %d"
|
|
|
|
, bind_ep.address().to_string().c_str()
|
|
|
|
, ret.tcp_external_port, ret.udp_external_port);
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2014-10-22 00:08:48 +02:00
|
|
|
return ret;
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
2015-05-16 08:33:37 +02:00
|
|
|
|
2016-09-25 15:50:48 +02:00
|
|
|
void session_impl::on_exception(std::exception const& e)
|
|
|
|
{
|
|
|
|
TORRENT_UNUSED(e);
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
|
|
|
session_log("FATAL SESSION ERROR [%s]", e.what());
|
|
|
|
#endif
|
|
|
|
this->abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::on_error(error_code const& ec)
|
|
|
|
{
|
|
|
|
TORRENT_UNUSED(ec);
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
|
|
|
session_log("FATAL SESSION ERROR (%s : %d) [%s]"
|
|
|
|
, ec.category().name(), ec.value(), ec.message().c_str());
|
|
|
|
#endif
|
|
|
|
this->abort();
|
|
|
|
}
|
|
|
|
|
2016-11-07 13:40:09 +01:00
|
|
|
void session_impl::on_ip_change(error_code const& ec)
|
|
|
|
{
|
|
|
|
if (ec || m_abort) return;
|
|
|
|
m_ip_notifier.async_wait([this] (error_code const& e)
|
|
|
|
{ this->wrap(&session_impl::on_ip_change, e); });
|
|
|
|
reopen_listen_sockets();
|
|
|
|
}
|
|
|
|
|
2016-02-09 00:15:47 +01:00
|
|
|
void session_impl::reopen_listen_sockets()
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-20 17:24:24 +02:00
|
|
|
session_log("reopen listen sockets");
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2010-09-25 22:07:27 +02:00
|
|
|
|
2012-10-15 08:20:42 +02:00
|
|
|
TORRENT_ASSERT(!m_abort);
|
2015-05-16 08:33:37 +02:00
|
|
|
int flags = m_settings.get_bool(settings_pack::listen_system_port_fallback)
|
|
|
|
? 0 : listen_no_system_port;
|
2016-02-07 08:09:19 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stats_counters.set_value(counters::has_incoming_connections, 0);
|
2016-11-20 04:48:24 +01:00
|
|
|
error_code ec;
|
2012-10-15 08:20:42 +02:00
|
|
|
|
|
|
|
if (m_abort) return;
|
2007-09-22 18:27:29 +02:00
|
|
|
|
2016-11-20 04:48:24 +01:00
|
|
|
// first build a list of endpoints we should be listening on
|
2016-11-25 17:17:25 +01:00
|
|
|
// we need to remove any unneeded sockets first to avoid the possibility
|
2016-11-20 04:48:24 +01:00
|
|
|
// of a new socket failing to bind due to a conflict with a stale socket
|
|
|
|
std::vector<listen_endpoint_t> eps;
|
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
for (auto const& iface : m_listen_interfaces)
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
2016-11-27 14:46:53 +01:00
|
|
|
std::string const& device = iface.device;
|
|
|
|
int const port = iface.port;
|
|
|
|
bool const ssl = iface.ssl;
|
2012-01-14 17:04:25 +01:00
|
|
|
|
2016-06-23 19:20:35 +02:00
|
|
|
#ifndef TORRENT_USE_OPENSSL
|
|
|
|
if (ssl)
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
|
|
|
session_log("attempted to listen ssl with no library support on device: \"%s\""
|
|
|
|
, device.c_str());
|
|
|
|
#endif
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
{
|
|
|
|
m_alerts.emplace_alert<listen_failed_alert>(device
|
|
|
|
, listen_failed_alert::open
|
|
|
|
, boost::asio::error::operation_not_supported
|
2016-10-19 07:32:15 +02:00
|
|
|
, socket_type_t::tcp_ssl);
|
2016-06-23 19:20:35 +02:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-02-07 08:09:19 +01:00
|
|
|
// now we have a device to bind to. This device may actually just be an
|
|
|
|
// IP address or a device name. In case it's a device name, we want to
|
|
|
|
// (potentially) end up binding a socket for each IP address associated
|
|
|
|
// with that device.
|
2016-02-08 08:01:25 +01:00
|
|
|
|
2016-02-07 08:09:19 +01:00
|
|
|
// First, check to see if it's an IP address
|
|
|
|
error_code err;
|
2016-04-24 21:26:28 +02:00
|
|
|
address const adr = address::from_string(device.c_str(), err);
|
2016-02-07 08:09:19 +01:00
|
|
|
if (!err)
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
2016-11-20 04:48:24 +01:00
|
|
|
eps.emplace_back(adr, port, std::string(), ssl);
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
2016-02-07 08:09:19 +01:00
|
|
|
else
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-02-07 08:09:19 +01:00
|
|
|
// this is the case where device names a network device. We need to
|
|
|
|
// enumerate all IPs associated with this device
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// TODO: 3 only run this once, not every turn through the loop
|
2016-09-20 17:24:24 +02:00
|
|
|
std::vector<ip_interface> const ifs = enum_net_interfaces(m_io_service, ec);
|
2016-02-07 08:09:19 +01:00
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("failed to enumerate IPs on device: \"%s\": %s"
|
|
|
|
, device.c_str(), ec.message().c_str());
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
2016-02-07 08:09:19 +01:00
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
{
|
|
|
|
m_alerts.emplace_alert<listen_failed_alert>(device
|
2016-06-03 04:38:56 +02:00
|
|
|
, listen_failed_alert::enum_if, ec
|
2016-10-19 07:32:15 +02:00
|
|
|
, socket_type_t::tcp);
|
2016-02-07 08:09:19 +01:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2016-02-01 01:40:31 +01:00
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
for (auto const& ipface : ifs)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-02-07 08:09:19 +01:00
|
|
|
// we're looking for a specific interface, and its address
|
|
|
|
// (which must be of the same family as the address we're
|
|
|
|
// connecting to)
|
2016-11-27 14:46:53 +01:00
|
|
|
if (device != ipface.name) continue;
|
|
|
|
eps.emplace_back(ipface.interface_address, port, device, ssl);
|
2016-11-20 04:48:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-04-12 02:37:06 +02:00
|
|
|
|
2016-11-21 02:06:52 +01:00
|
|
|
auto remove_iter = partition_listen_sockets(eps, m_listen_sockets);
|
2016-11-20 04:48:24 +01:00
|
|
|
|
2016-11-21 02:06:52 +01:00
|
|
|
while (remove_iter != m_listen_sockets.end())
|
2016-11-20 04:48:24 +01:00
|
|
|
{
|
|
|
|
// TODO notify interested parties of this socket's demise
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-11-27 14:46:53 +01:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("Closing listen socket for %s on device \"%s\""
|
|
|
|
, print_endpoint(remove_iter->local_endpoint).c_str()
|
|
|
|
, remove_iter->device.c_str());
|
|
|
|
}
|
2016-11-20 04:48:24 +01:00
|
|
|
#endif
|
2016-11-21 02:06:52 +01:00
|
|
|
if (remove_iter->sock) remove_iter->sock->close(ec);
|
|
|
|
if (remove_iter->udp_sock) remove_iter->udp_sock->close();
|
|
|
|
remove_iter = m_listen_sockets.erase(remove_iter);
|
2016-11-20 04:48:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// open new sockets on any endpoints that didn't match with
|
|
|
|
// an existing socket
|
|
|
|
for (auto const& ep : eps)
|
|
|
|
{
|
|
|
|
listen_socket_t const s = setup_listener(ep.device
|
2016-11-25 17:17:25 +01:00
|
|
|
, tcp::endpoint(ep.addr, std::uint16_t(ep.port))
|
2016-11-20 04:48:24 +01:00
|
|
|
, flags | (ep.ssl ? open_ssl_socket : 0), ec);
|
|
|
|
|
2017-01-13 06:55:54 +01:00
|
|
|
if (!ec && (s.sock || s.udp_sock))
|
2016-11-20 04:48:24 +01:00
|
|
|
{
|
|
|
|
// TODO notify interested parties of this socket's creation
|
|
|
|
m_listen_sockets.push_back(s);
|
2012-01-14 17:04:25 +01:00
|
|
|
}
|
2010-05-30 03:33:03 +02:00
|
|
|
}
|
|
|
|
|
2016-02-07 08:09:19 +01:00
|
|
|
if (m_listen_sockets.empty())
|
2014-08-16 09:46:06 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-02-07 08:09:19 +01:00
|
|
|
session_log("giving up on binding listen sockets");
|
2014-08-16 09:46:06 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
// now, send out listen_succeeded_alert for the listen sockets we are
|
|
|
|
// listening on
|
2016-11-20 04:48:24 +01:00
|
|
|
// TODO only post alerts for new sockets?
|
2016-04-24 21:26:28 +02:00
|
|
|
if (m_alerts.should_post<listen_succeeded_alert>())
|
2014-10-06 05:03:01 +02:00
|
|
|
{
|
2016-09-20 17:24:24 +02:00
|
|
|
for (auto const& l : m_listen_sockets)
|
2015-01-06 09:16:03 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
error_code err;
|
2016-09-20 17:24:24 +02:00
|
|
|
if (l.sock)
|
2016-02-07 08:09:19 +01:00
|
|
|
{
|
2016-09-20 17:24:24 +02:00
|
|
|
tcp::endpoint const tcp_ep = l.sock->local_endpoint(err);
|
2016-04-24 21:26:28 +02:00
|
|
|
if (!err)
|
2016-02-07 08:09:19 +01:00
|
|
|
{
|
2016-10-19 07:32:15 +02:00
|
|
|
socket_type_t const socket_type
|
2016-09-20 17:24:24 +02:00
|
|
|
= l.ssl
|
2016-10-19 07:32:15 +02:00
|
|
|
? socket_type_t::tcp_ssl
|
|
|
|
: socket_type_t::tcp;
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
m_alerts.emplace_alert<listen_succeeded_alert>(
|
2016-09-20 17:24:24 +02:00
|
|
|
tcp_ep, socket_type);
|
2016-02-07 08:09:19 +01:00
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
2014-10-06 05:03:01 +02:00
|
|
|
|
2016-09-20 17:24:24 +02:00
|
|
|
if (l.udp_sock)
|
2016-02-08 08:01:25 +01:00
|
|
|
{
|
2016-09-20 17:24:24 +02:00
|
|
|
udp::endpoint const udp_ep = l.udp_sock->local_endpoint(err);
|
|
|
|
if (!err && l.udp_sock->is_open())
|
2016-02-08 08:01:25 +01:00
|
|
|
{
|
2016-10-19 07:32:15 +02:00
|
|
|
socket_type_t const socket_type
|
2016-09-20 17:24:24 +02:00
|
|
|
= l.ssl
|
2016-10-19 07:32:15 +02:00
|
|
|
? socket_type_t::utp_ssl
|
|
|
|
: socket_type_t::udp;
|
2015-09-06 02:58:15 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
m_alerts.emplace_alert<listen_succeeded_alert>(
|
2016-06-03 04:38:56 +02:00
|
|
|
udp_ep, socket_type);
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2015-09-06 02:58:15 +02:00
|
|
|
}
|
|
|
|
|
2015-01-14 02:59:23 +01:00
|
|
|
if (m_settings.get_int(settings_pack::peer_tos) != 0)
|
|
|
|
{
|
2014-08-22 09:56:10 +02:00
|
|
|
update_peer_tos();
|
2014-06-15 19:44:27 +02:00
|
|
|
}
|
2014-08-22 09:56:10 +02:00
|
|
|
|
2012-01-29 21:59:20 +01:00
|
|
|
ec.clear();
|
2013-09-03 10:39:30 +02:00
|
|
|
|
2012-10-18 09:42:15 +02:00
|
|
|
// initiate accepting on the listen sockets
|
2016-09-09 01:13:47 +02:00
|
|
|
for (auto& s : m_listen_sockets)
|
2016-02-07 08:09:19 +01:00
|
|
|
{
|
2016-09-09 01:13:47 +02:00
|
|
|
if (s.sock) async_accept(s.sock, s.ssl);
|
|
|
|
remap_ports(remap_natpmp_and_upnp, s);
|
2016-02-07 08:09:19 +01:00
|
|
|
}
|
2012-10-18 09:42:15 +02:00
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
open_new_incoming_socks_connection();
|
2009-08-20 05:19:12 +02:00
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
open_new_incoming_i2p_connection();
|
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
namespace {
|
|
|
|
template <typename MapProtocol, typename ProtoType, typename EndpointType>
|
|
|
|
void map_port(MapProtocol& m, ProtoType protocol, EndpointType const& ep
|
|
|
|
, int& map_handle)
|
|
|
|
{
|
|
|
|
if (map_handle != -1) m.delete_mapping(map_handle);
|
|
|
|
map_handle = -1;
|
|
|
|
|
|
|
|
// only update this mapping if we actually have a socket listening
|
2016-12-17 23:50:03 +01:00
|
|
|
if (ep != EndpointType())
|
2016-04-24 21:26:28 +02:00
|
|
|
map_handle = m.add_mapping(protocol, ep.port(), ep.port());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::remap_ports(remap_port_mask_t const mask
|
|
|
|
, listen_socket_t& s)
|
2012-01-14 17:04:25 +01:00
|
|
|
{
|
2016-09-16 14:21:07 +02:00
|
|
|
tcp::endpoint const tcp_ep = s.sock ? s.sock->local_endpoint() : tcp::endpoint();
|
|
|
|
udp::endpoint const udp_ep = s.udp_sock ? s.udp_sock->local_endpoint() : udp::endpoint();
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
if ((mask & remap_natpmp) && m_natpmp)
|
2012-01-14 17:04:25 +01:00
|
|
|
{
|
2016-09-18 16:11:56 +02:00
|
|
|
map_port(*m_natpmp, portmap_protocol::tcp, tcp_ep, s.tcp_port_mapping[0]);
|
|
|
|
map_port(*m_natpmp, portmap_protocol::udp, udp_ep, s.udp_port_mapping[0]);
|
2012-01-14 17:04:25 +01:00
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
if ((mask & remap_upnp) && m_upnp)
|
2012-01-14 17:04:25 +01:00
|
|
|
{
|
2016-09-18 16:11:56 +02:00
|
|
|
map_port(*m_upnp, portmap_protocol::tcp, tcp_ep, s.tcp_port_mapping[1]);
|
|
|
|
map_port(*m_upnp, portmap_protocol::udp, udp_ep, s.udp_port_mapping[1]);
|
2012-01-14 17:04:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
void session_impl::open_new_incoming_socks_connection()
|
|
|
|
{
|
2016-02-24 06:03:56 +01:00
|
|
|
int const proxy_type = m_settings.get_int(settings_pack::proxy_type);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
if (proxy_type != settings_pack::socks5
|
|
|
|
&& proxy_type != settings_pack::socks5_pw
|
|
|
|
&& proxy_type != settings_pack::socks4)
|
2009-04-09 03:04:49 +02:00
|
|
|
return;
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
if (m_socks_listen_socket) return;
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
m_socks_listen_socket = std::make_shared<socket_type>(m_io_service);
|
2016-02-24 06:03:56 +01:00
|
|
|
bool const ret = instantiate_connection(m_io_service, proxy()
|
2016-06-20 17:32:06 +02:00
|
|
|
, *m_socks_listen_socket, nullptr, nullptr, false, false);
|
2010-09-25 19:46:13 +02:00
|
|
|
TORRENT_ASSERT_VAL(ret, ret);
|
2015-05-19 06:59:31 +02:00
|
|
|
TORRENT_UNUSED(ret);
|
2009-04-09 03:04:49 +02:00
|
|
|
|
2016-05-06 07:08:05 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_socks_listen");
|
2009-04-09 03:04:49 +02:00
|
|
|
socks5_stream& s = *m_socks_listen_socket->get<socks5_stream>();
|
2016-02-07 08:09:19 +01:00
|
|
|
|
2016-12-21 07:00:49 +01:00
|
|
|
// figure out which port to ask the socks5 proxy to open or us.
|
|
|
|
m_socks_listen_port = (m_listen_sockets.empty()
|
|
|
|
|| m_settings.get_bool(settings_pack::anonymous_mode))
|
|
|
|
? std::uint16_t(2000 + random(60000))
|
|
|
|
: std::uint16_t(m_listen_sockets.front().tcp_external_port);
|
|
|
|
|
2016-05-05 23:09:11 +02:00
|
|
|
s.async_listen(tcp::endpoint(address_v4::any(), m_socks_listen_port)
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&session_impl::on_socks_listen, this
|
2016-05-05 23:09:11 +02:00
|
|
|
, m_socks_listen_socket, _1));
|
|
|
|
}
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
void session_impl::on_socks_listen(std::shared_ptr<socket_type> const& sock
|
2016-05-05 23:09:11 +02:00
|
|
|
, error_code const& e)
|
|
|
|
{
|
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
complete_async("session_impl::on_socks_listen");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
TORRENT_ASSERT(sock == m_socks_listen_socket || !m_socks_listen_socket);
|
|
|
|
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
m_socks_listen_socket.reset();
|
|
|
|
if (e == boost::asio::error::operation_aborted) return;
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
m_alerts.emplace_alert<listen_failed_alert>("socks5"
|
2016-06-03 04:38:56 +02:00
|
|
|
, listen_failed_alert::accept, e
|
2016-10-19 07:32:15 +02:00
|
|
|
, socket_type_t::socks5);
|
2016-05-05 23:09:11 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-24 19:47:17 +02:00
|
|
|
if (m_abort) return;
|
|
|
|
|
2016-05-05 23:09:11 +02:00
|
|
|
error_code ec;
|
|
|
|
tcp::endpoint ep = sock->local_endpoint(ec);
|
|
|
|
TORRENT_ASSERT(!ec);
|
|
|
|
TORRENT_UNUSED(ec);
|
|
|
|
|
|
|
|
if (m_alerts.should_post<listen_succeeded_alert>())
|
|
|
|
m_alerts.emplace_alert<listen_succeeded_alert>(
|
2016-10-19 07:32:15 +02:00
|
|
|
ep, socket_type_t::socks5);
|
2016-05-05 23:09:11 +02:00
|
|
|
|
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::on_socks_accept");
|
|
|
|
#endif
|
|
|
|
socks5_stream& s = *m_socks_listen_socket->get<socks5_stream>();
|
2016-05-25 06:31:52 +02:00
|
|
|
s.async_accept(std::bind(&session_impl::on_socks_accept, this
|
2016-05-05 23:09:11 +02:00
|
|
|
, m_socks_listen_socket, _1));
|
|
|
|
}
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
void session_impl::on_socks_accept(std::shared_ptr<socket_type> const& s
|
2016-05-05 23:09:11 +02:00
|
|
|
, error_code const& e)
|
|
|
|
{
|
2016-05-06 07:08:05 +02:00
|
|
|
COMPLETE_ASYNC("session_impl::on_socks_accept");
|
2016-05-05 23:09:11 +02:00
|
|
|
TORRENT_ASSERT(s == m_socks_listen_socket || !m_socks_listen_socket);
|
|
|
|
m_socks_listen_socket.reset();
|
|
|
|
if (e == boost::asio::error::operation_aborted) return;
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
m_alerts.emplace_alert<listen_failed_alert>("socks5"
|
2016-06-03 04:38:56 +02:00
|
|
|
, listen_failed_alert::accept, e
|
2016-10-19 07:32:15 +02:00
|
|
|
, socket_type_t::socks5);
|
2016-05-05 23:09:11 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-09-24 19:47:17 +02:00
|
|
|
if (m_abort) return;
|
2016-05-05 23:09:11 +02:00
|
|
|
open_new_incoming_socks_connection();
|
|
|
|
incoming_connection(s);
|
2009-04-09 03:04:49 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_i2p_bridge()
|
2013-10-27 20:56:37 +01:00
|
|
|
{
|
|
|
|
// we need this socket to be open before we
|
|
|
|
// can make name lookups for trackers for instance.
|
|
|
|
// pause the session now and resume it once we've
|
|
|
|
// established the i2p SAM connection
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_I2P
|
2014-09-02 08:28:27 +02:00
|
|
|
if (m_settings.get_str(settings_pack::i2p_hostname).empty())
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
m_i2p_conn.close(ec);
|
|
|
|
return;
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
m_i2p_conn.open(m_settings.get_str(settings_pack::i2p_hostname)
|
|
|
|
, m_settings.get_int(settings_pack::i2p_port)
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&session_impl::on_i2p_open, this, _1));
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
|
|
|
|
proxy_settings session_impl::i2p_proxy() const
|
|
|
|
{
|
|
|
|
proxy_settings ret;
|
|
|
|
|
|
|
|
ret.hostname = m_settings.get_str(settings_pack::i2p_hostname);
|
|
|
|
ret.type = settings_pack::i2p_proxy;
|
2016-11-25 17:17:25 +01:00
|
|
|
ret.port = std::uint16_t(m_settings.get_int(settings_pack::i2p_port));
|
2014-07-06 21:18:00 +02:00
|
|
|
return ret;
|
2013-10-27 20:56:37 +01:00
|
|
|
}
|
|
|
|
|
2009-08-20 05:19:12 +02:00
|
|
|
void session_impl::on_i2p_open(error_code const& ec)
|
|
|
|
{
|
2013-10-27 20:56:37 +01:00
|
|
|
if (ec)
|
|
|
|
{
|
2014-03-15 23:20:19 +01:00
|
|
|
if (m_alerts.should_post<i2p_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<i2p_alert>(ec);
|
2014-03-15 23:20:19 +01:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
session_log("i2p open failed (%d) %s", ec.value(), ec.message().c_str());
|
2013-10-27 20:56:37 +01:00
|
|
|
#endif
|
|
|
|
}
|
2013-10-28 03:41:54 +01:00
|
|
|
// now that we have our i2p connection established
|
|
|
|
// it's OK to start torrents and use this socket to
|
|
|
|
// do i2p name lookups
|
2013-10-27 20:56:37 +01:00
|
|
|
|
2009-08-20 05:19:12 +02:00
|
|
|
open_new_incoming_i2p_connection();
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::open_new_incoming_i2p_connection()
|
|
|
|
{
|
|
|
|
if (!m_i2p_conn.is_open()) return;
|
|
|
|
|
|
|
|
if (m_i2p_listen_socket) return;
|
|
|
|
|
2016-11-17 20:34:49 +01:00
|
|
|
m_i2p_listen_socket = std::make_shared<socket_type>(m_io_service);
|
2009-08-20 05:19:12 +02:00
|
|
|
bool ret = instantiate_connection(m_io_service, m_i2p_conn.proxy()
|
2016-06-20 17:32:06 +02:00
|
|
|
, *m_i2p_listen_socket, nullptr, nullptr, true, false);
|
2010-09-25 19:46:13 +02:00
|
|
|
TORRENT_ASSERT_VAL(ret, ret);
|
2015-05-19 06:59:31 +02:00
|
|
|
TORRENT_UNUSED(ret);
|
2009-08-20 05:19:12 +02:00
|
|
|
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_i2p_accept");
|
2009-08-20 05:19:12 +02:00
|
|
|
i2p_stream& s = *m_i2p_listen_socket->get<i2p_stream>();
|
|
|
|
s.set_command(i2p_stream::cmd_accept);
|
|
|
|
s.set_session_id(m_i2p_conn.session_id());
|
2016-02-07 08:09:19 +01:00
|
|
|
|
|
|
|
s.async_connect(tcp::endpoint()
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&session_impl::on_i2p_accept, this, m_i2p_listen_socket, _1));
|
2009-08-20 05:19:12 +02:00
|
|
|
}
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
void session_impl::on_i2p_accept(std::shared_ptr<socket_type> const& s
|
2009-08-20 05:19:12 +02:00
|
|
|
, error_code const& e)
|
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
COMPLETE_ASYNC("session_impl::on_i2p_accept");
|
2009-08-20 05:19:12 +02:00
|
|
|
m_i2p_listen_socket.reset();
|
2015-06-06 08:10:53 +02:00
|
|
|
if (e == boost::asio::error::operation_aborted) return;
|
2009-08-20 05:19:12 +02:00
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
2016-02-07 08:09:19 +01:00
|
|
|
{
|
2016-01-31 05:23:12 +01:00
|
|
|
m_alerts.emplace_alert<listen_failed_alert>("i2p"
|
|
|
|
, listen_failed_alert::accept
|
2016-10-19 07:32:15 +02:00
|
|
|
, e, socket_type_t::i2p);
|
2016-02-07 08:09:19 +01:00
|
|
|
}
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
session_log("i2p SAM connection failure: %s", e.message().c_str());
|
2010-05-30 03:33:03 +02:00
|
|
|
#endif
|
2009-08-20 05:19:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
open_new_incoming_i2p_connection();
|
|
|
|
incoming_connection(s);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
void session_impl::send_udp_packet_hostname(char const* hostname
|
|
|
|
, int const port
|
2016-07-22 18:31:42 +02:00
|
|
|
, span<char const> p
|
2016-04-24 21:26:28 +02:00
|
|
|
, error_code& ec
|
|
|
|
, int const flags)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
// for now, just pick the first socket with a matching address family
|
|
|
|
// TODO: 3 for proper multi-homed support, we may want to do something
|
|
|
|
// else here. Probably let the caller decide which interface to send over
|
|
|
|
for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if (!i->udp_sock) continue;
|
|
|
|
if (i->ssl) continue;
|
|
|
|
|
|
|
|
i->udp_sock->send_hostname(hostname, port, p, ec, flags);
|
2008-05-08 02:22:17 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if ((ec == error::would_block
|
|
|
|
|| ec == error::try_again)
|
|
|
|
&& !i->udp_write_blocked)
|
|
|
|
{
|
|
|
|
i->udp_write_blocked = true;
|
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_udp_writeable");
|
2016-05-25 06:31:52 +02:00
|
|
|
i->udp_sock->async_write(std::bind(&session_impl::on_udp_writeable
|
2016-08-31 18:45:45 +02:00
|
|
|
, this, std::weak_ptr<udp_socket>(i->udp_sock), _1));
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ec = boost::asio::error::operation_not_supported;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::send_udp_packet(bool const ssl
|
|
|
|
, udp::endpoint const& ep
|
2016-07-22 18:31:42 +02:00
|
|
|
, span<char const> p
|
2016-04-24 21:26:28 +02:00
|
|
|
, error_code& ec
|
|
|
|
, int const flags)
|
|
|
|
{
|
|
|
|
// for now, just pick the first socket with a matching address family
|
|
|
|
// TODO: 3 for proper multi-homed support, we may want to do something
|
|
|
|
// else here. Probably let the caller decide which interface to send over
|
|
|
|
for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if (i->ssl != ssl) continue;
|
|
|
|
if (!i->udp_sock) continue;
|
|
|
|
if (i->local_endpoint.address().is_v4() != ep.address().is_v4())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
i->udp_sock->send(ep, p, ec, flags);
|
|
|
|
|
|
|
|
if ((ec == error::would_block
|
|
|
|
|| ec == error::try_again)
|
|
|
|
&& !i->udp_write_blocked)
|
|
|
|
{
|
|
|
|
i->udp_write_blocked = true;
|
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_udp_writeable");
|
2016-05-25 06:31:52 +02:00
|
|
|
i->udp_sock->async_write(std::bind(&session_impl::on_udp_writeable
|
2016-08-31 18:45:45 +02:00
|
|
|
, this, std::weak_ptr<udp_socket>(i->udp_sock), _1));
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ec = boost::asio::error::operation_not_supported;
|
|
|
|
}
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
void session_impl::on_udp_writeable(std::weak_ptr<udp_socket> s, error_code const& ec)
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
|
|
|
COMPLETE_ASYNC("session_impl::on_udp_writeable");
|
|
|
|
if (ec) return;
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
std::shared_ptr<udp_socket> sock = s.lock();
|
2016-04-24 21:26:28 +02:00
|
|
|
if (!sock) return;
|
|
|
|
|
|
|
|
std::list<listen_socket_t>::iterator i = std::find_if(
|
|
|
|
m_listen_sockets.begin(), m_listen_sockets.end()
|
2016-05-25 06:31:52 +02:00
|
|
|
, [&sock] (listen_socket_t const& ls) { return ls.udp_sock == sock; });
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
if (i == m_listen_sockets.end()) return;
|
|
|
|
|
|
|
|
i->udp_write_blocked = false;
|
|
|
|
|
|
|
|
// notify the utp socket manager it can start sending on the socket again
|
|
|
|
struct utp_socket_manager& mgr =
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
i->ssl ? m_ssl_utp_socket_manager :
|
|
|
|
#endif
|
|
|
|
m_utp_socket_manager;
|
|
|
|
|
|
|
|
mgr.writable();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
void session_impl::on_udp_packet(std::weak_ptr<udp_socket> const& socket
|
2016-04-24 21:26:28 +02:00
|
|
|
, bool const ssl, error_code const& ec)
|
|
|
|
{
|
|
|
|
COMPLETE_ASYNC("session_impl::on_udp_packet");
|
2012-06-22 06:21:20 +02:00
|
|
|
if (ec)
|
|
|
|
{
|
2016-08-31 18:45:45 +02:00
|
|
|
std::shared_ptr<udp_socket> s = socket.lock();
|
2016-04-24 21:26:28 +02:00
|
|
|
udp::endpoint ep;
|
2016-09-16 14:21:07 +02:00
|
|
|
if (s) ep = s->local_endpoint();
|
2016-04-24 21:26:28 +02:00
|
|
|
|
2011-08-21 03:55:38 +02:00
|
|
|
// don't bubble up operation aborted errors to the user
|
2015-06-06 08:10:53 +02:00
|
|
|
if (ec != boost::asio::error::operation_aborted
|
2016-04-24 21:26:28 +02:00
|
|
|
&& ec != boost::asio::error::bad_descriptor
|
2011-08-21 03:55:38 +02:00
|
|
|
&& m_alerts.should_post<udp_error_alert>())
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<udp_error_alert>(ep, ec);
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
2012-09-25 04:49:40 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("UDP error: %s (%d) %s"
|
|
|
|
, print_endpoint(ep).c_str(), ec.value(), ec.message().c_str());
|
|
|
|
}
|
2012-09-25 04:49:40 +02:00
|
|
|
#endif
|
2016-04-24 21:26:28 +02:00
|
|
|
return;
|
2010-08-03 11:08:37 +02:00
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
m_stats_counters.inc_stats_counter(counters::on_udp_counter);
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
std::shared_ptr<udp_socket> s = socket.lock();
|
2016-04-24 21:26:28 +02:00
|
|
|
if (!s) return;
|
|
|
|
|
|
|
|
struct utp_socket_manager& mgr =
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
ssl ? m_ssl_utp_socket_manager :
|
|
|
|
#endif
|
|
|
|
m_utp_socket_manager;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
2017-02-08 16:54:55 +01:00
|
|
|
aux::array<udp_socket::packet, 50> p;
|
2016-04-24 21:26:28 +02:00
|
|
|
error_code err;
|
2016-04-28 14:20:10 +02:00
|
|
|
int const num_packets = s->read(p, err);
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < num_packets; ++i)
|
|
|
|
{
|
|
|
|
udp_socket::packet& packet = p[i];
|
|
|
|
|
|
|
|
if (packet.error)
|
|
|
|
{
|
|
|
|
// TODO: 3 it would be neat if the utp socket manager would
|
|
|
|
// handle ICMP errors too
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (m_dht)
|
|
|
|
m_dht->incoming_error(packet.error, packet.from);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
m_tracker_manager.incoming_error(packet.error, packet.from);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-22 18:31:42 +02:00
|
|
|
span<char const> const buf = packet.data;
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
// give the uTP socket manager first dis on the packet. Presumably
|
|
|
|
// the majority of packets are uTP packets.
|
2016-04-28 14:20:10 +02:00
|
|
|
if (!mgr.incoming_packet(packet.from, buf))
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
|
|
|
// if it wasn't a uTP packet, try the other users of the UDP
|
|
|
|
// socket
|
|
|
|
bool handled = false;
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2016-04-28 14:20:10 +02:00
|
|
|
if (m_dht && buf.size() > 20 && buf.front() == 'd' && buf.back() == 'e')
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
2016-09-11 07:58:48 +02:00
|
|
|
handled = m_dht->incoming_packet(packet.from, buf);
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!handled)
|
|
|
|
{
|
2016-04-28 14:20:10 +02:00
|
|
|
m_tracker_manager.incoming_packet(packet.from, buf);
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err == error::would_block || err == error::try_again)
|
|
|
|
{
|
|
|
|
// there are no more packets on the socket
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
{
|
2016-09-16 14:21:07 +02:00
|
|
|
udp::endpoint const ep = s->local_endpoint();
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
if (err != boost::asio::error::operation_aborted
|
|
|
|
&& m_alerts.should_post<udp_error_alert>())
|
|
|
|
m_alerts.emplace_alert<udp_error_alert>(ep, err);
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("UDP error: %s (%d) %s"
|
|
|
|
, print_endpoint(ep).c_str(), ec.value(), ec.message().c_str());
|
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// any error other than these ones are considered fatal errors, and
|
|
|
|
// we won't read from the socket again
|
|
|
|
if (err != boost::asio::error::host_unreachable
|
|
|
|
&& err != boost::asio::error::fault
|
|
|
|
&& err != boost::asio::error::connection_reset
|
|
|
|
&& err != boost::asio::error::connection_refused
|
|
|
|
&& err != boost::asio::error::connection_aborted
|
|
|
|
&& err != boost::asio::error::operation_aborted
|
|
|
|
&& err != boost::asio::error::network_reset
|
|
|
|
&& err != boost::asio::error::network_unreachable
|
2016-05-27 21:35:53 +02:00
|
|
|
#ifdef _WIN32
|
2016-04-24 21:26:28 +02:00
|
|
|
// ERROR_MORE_DATA means the same thing as EMSGSIZE
|
|
|
|
&& err != error_code(ERROR_MORE_DATA, system_category())
|
|
|
|
&& err != error_code(ERROR_HOST_UNREACHABLE, system_category())
|
|
|
|
&& err != error_code(ERROR_PORT_UNREACHABLE, system_category())
|
|
|
|
&& err != error_code(ERROR_RETRY, system_category())
|
|
|
|
&& err != error_code(ERROR_NETWORK_UNREACHABLE, system_category())
|
|
|
|
&& err != error_code(ERROR_CONNECTION_REFUSED, system_category())
|
|
|
|
&& err != error_code(ERROR_CONNECTION_ABORTED, system_category())
|
|
|
|
#endif
|
|
|
|
&& err != boost::asio::error::message_size)
|
|
|
|
{
|
|
|
|
// fatal errors. Don't try to read from this socket again
|
|
|
|
mgr.socket_drained();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// non-fatal UDP errors get here, we should re-issue the read.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mgr.socket_drained();
|
|
|
|
|
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_udp_packet");
|
2016-05-25 06:31:52 +02:00
|
|
|
s->async_read(std::bind(&session_impl::on_udp_packet
|
2016-04-24 21:26:28 +02:00
|
|
|
, this, socket, ssl, _1));
|
2010-08-03 11:08:37 +02:00
|
|
|
}
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
void session_impl::async_accept(std::shared_ptr<tcp::acceptor> const& listener, bool ssl)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2010-12-24 19:15:01 +01:00
|
|
|
TORRENT_ASSERT(!m_abort);
|
2016-08-31 18:45:45 +02:00
|
|
|
std::shared_ptr<socket_type> c = std::make_shared<socket_type>(m_io_service);
|
2016-07-09 22:26:26 +02:00
|
|
|
tcp::socket* str = nullptr;
|
2012-01-14 17:04:25 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
if (ssl)
|
|
|
|
{
|
|
|
|
// accept connections initializing the SSL connection to
|
|
|
|
// use the generic m_ssl_ctx context. However, since it has
|
|
|
|
// the servername callback set on it, we will switch away from
|
|
|
|
// this context into a specific torrent once we start handshaking
|
2016-10-25 23:27:48 +02:00
|
|
|
c->instantiate<ssl_stream<tcp::socket>>(m_io_service, &m_ssl_ctx);
|
|
|
|
str = &c->get<ssl_stream<tcp::socket>>()->next_layer();
|
2012-01-14 17:04:25 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2015-06-06 19:49:18 +02:00
|
|
|
c->instantiate<tcp::socket>(m_io_service);
|
|
|
|
str = c->get<tcp::socket>();
|
2012-01-14 17:04:25 +01:00
|
|
|
}
|
|
|
|
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_accept_connection");
|
2015-01-04 02:04:56 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
TORRENT_ASSERT(ssl == is_ssl(*c));
|
|
|
|
#endif
|
|
|
|
|
2012-01-14 17:04:25 +01:00
|
|
|
listener->async_accept(*str
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&session_impl::on_accept_connection, this, c
|
2016-08-31 18:45:45 +02:00
|
|
|
, std::weak_ptr<tcp::acceptor>(listener), _1, ssl));
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
void session_impl::on_accept_connection(std::shared_ptr<socket_type> const& s
|
|
|
|
, std::weak_ptr<tcp::acceptor> listen_socket, error_code const& e
|
2016-04-24 21:26:28 +02:00
|
|
|
, bool const ssl)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
COMPLETE_ASYNC("session_impl::on_accept_connection");
|
2014-07-13 06:56:53 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::on_accept_counter);
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2016-08-31 18:45:45 +02:00
|
|
|
std::shared_ptr<tcp::acceptor> listener = listen_socket.lock();
|
2007-09-22 18:27:29 +02:00
|
|
|
if (!listener) return;
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2015-06-06 08:10:53 +02:00
|
|
|
if (e == boost::asio::error::operation_aborted) return;
|
2006-10-11 22:57:54 +02:00
|
|
|
|
|
|
|
if (m_abort) return;
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
error_code ec;
|
2006-10-11 22:57:54 +02:00
|
|
|
if (e)
|
|
|
|
{
|
2007-09-22 18:27:29 +02:00
|
|
|
tcp::endpoint ep = listener->local_endpoint(ec);
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("error accepting connection on '%s': %s"
|
|
|
|
, print_endpoint(ep).c_str(), e.message().c_str());
|
|
|
|
}
|
2007-10-15 21:02:54 +02:00
|
|
|
#endif
|
2008-04-24 05:28:48 +02:00
|
|
|
#ifdef TORRENT_WINDOWS
|
2007-10-15 21:02:54 +02:00
|
|
|
// Windows sometimes generates this error. It seems to be
|
|
|
|
// non-fatal and we have to do another async_accept.
|
|
|
|
if (e.value() == ERROR_SEM_TIMEOUT)
|
|
|
|
{
|
2012-01-14 17:04:25 +01:00
|
|
|
async_accept(listener, ssl);
|
2007-10-15 21:02:54 +02:00
|
|
|
return;
|
|
|
|
}
|
2008-04-03 06:35:56 +02:00
|
|
|
#endif
|
|
|
|
#ifdef TORRENT_BSD
|
|
|
|
// Leopard sometimes generates an "invalid argument" error. It seems to be
|
|
|
|
// non-fatal and we have to do another async_accept.
|
|
|
|
if (e.value() == EINVAL)
|
|
|
|
{
|
2012-01-14 17:04:25 +01:00
|
|
|
async_accept(listener, ssl);
|
2008-04-03 06:35:56 +02:00
|
|
|
return;
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2010-03-09 18:50:10 +01:00
|
|
|
if (e == boost::system::errc::too_many_files_open)
|
|
|
|
{
|
|
|
|
// if we failed to accept an incoming connection
|
|
|
|
// because we have too many files open, try again
|
|
|
|
// and lower the number of file descriptors used
|
|
|
|
// elsewere.
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::connections_limit) > 10)
|
2011-03-23 09:49:26 +01:00
|
|
|
{
|
|
|
|
// now, disconnect a random peer
|
2016-05-25 06:31:52 +02:00
|
|
|
torrent_map::iterator i = std::max_element(m_torrents.begin(), m_torrents.end()
|
|
|
|
, [](torrent_map::value_type const& lhs, torrent_map::value_type const& rhs)
|
|
|
|
{ return lhs.second->num_peers() < rhs.second->num_peers(); });
|
2011-03-23 09:49:26 +01:00
|
|
|
|
2012-03-04 12:18:27 +01:00
|
|
|
if (m_alerts.should_post<performance_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<performance_alert>(
|
|
|
|
torrent_handle(), performance_alert::too_few_file_descriptors);
|
2012-03-04 12:18:27 +01:00
|
|
|
|
2011-03-23 09:49:26 +01:00
|
|
|
if (i != m_torrents.end())
|
|
|
|
{
|
2012-03-04 11:54:55 +01:00
|
|
|
i->second->disconnect_peers(1, e);
|
2011-03-23 09:49:26 +01:00
|
|
|
}
|
|
|
|
|
2017-02-01 04:59:51 +01:00
|
|
|
m_settings.set_int(settings_pack::connections_limit
|
|
|
|
, std::max(10, int(m_connections.size())));
|
2011-03-23 09:49:26 +01:00
|
|
|
}
|
2010-03-09 18:50:10 +01:00
|
|
|
// try again, but still alert the user of the problem
|
2012-01-14 17:04:25 +01:00
|
|
|
async_accept(listener, ssl);
|
2010-03-09 18:50:10 +01:00
|
|
|
}
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
error_code err;
|
2016-02-07 08:09:19 +01:00
|
|
|
m_alerts.emplace_alert<listen_failed_alert>(ep.address().to_string(err)
|
|
|
|
, ep, listen_failed_alert::accept, e
|
2016-10-19 07:32:15 +02:00
|
|
|
, ssl ? socket_type_t::tcp_ssl : socket_type_t::tcp);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
return;
|
|
|
|
}
|
2012-01-14 17:04:25 +01:00
|
|
|
async_accept(listener, ssl);
|
|
|
|
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
if (ssl)
|
|
|
|
{
|
2015-01-04 02:04:56 +01:00
|
|
|
TORRENT_ASSERT(is_ssl(*s));
|
|
|
|
|
2012-01-14 17:04:25 +01:00
|
|
|
// for SSL connections, incoming_connection() is called
|
|
|
|
// after the handshake is done
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::ssl_handshake");
|
2016-08-30 23:36:44 +02:00
|
|
|
s->get<ssl_stream<tcp::socket>>()->async_accept_handshake(
|
2016-05-25 06:31:52 +02:00
|
|
|
std::bind(&session_impl::ssl_handshake, this, _1, s));
|
2013-08-21 17:55:24 +02:00
|
|
|
m_incoming_sockets.insert(s);
|
2012-01-14 17:04:25 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
incoming_connection(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
void session_impl::on_incoming_utp_ssl(std::shared_ptr<socket_type> const& s)
|
2015-01-04 02:04:56 +01:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(is_ssl(*s));
|
|
|
|
|
|
|
|
// for SSL connections, incoming_connection() is called
|
|
|
|
// after the handshake is done
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::ssl_handshake");
|
2016-08-31 18:45:45 +02:00
|
|
|
s->get<ssl_stream<utp_stream>>()->async_accept_handshake(
|
2016-05-25 06:31:52 +02:00
|
|
|
std::bind(&session_impl::ssl_handshake, this, _1, s));
|
2015-01-04 02:04:56 +01:00
|
|
|
m_incoming_sockets.insert(s);
|
|
|
|
}
|
|
|
|
|
2012-01-14 17:04:25 +01:00
|
|
|
// to test SSL connections, one can use this openssl command template:
|
2015-05-22 04:42:26 +02:00
|
|
|
//
|
2014-07-05 16:10:25 +02:00
|
|
|
// openssl s_client -cert <client-cert>.pem -key <client-private-key>.pem
|
|
|
|
// -CAfile <torrent-cert>.pem -debug -connect 127.0.0.1:4433 -tls1
|
2012-01-14 17:04:25 +01:00
|
|
|
// -servername <hex-encoded-info-hash>
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
void session_impl::ssl_handshake(error_code const& ec, std::shared_ptr<socket_type> s)
|
2012-01-14 17:04:25 +01:00
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
COMPLETE_ASYNC("session_impl::ssl_handshake");
|
2015-01-04 02:04:56 +01:00
|
|
|
TORRENT_ASSERT(is_ssl(*s));
|
|
|
|
|
2013-08-21 17:55:24 +02:00
|
|
|
m_incoming_sockets.erase(s);
|
|
|
|
|
2012-01-14 17:04:25 +01:00
|
|
|
error_code e;
|
|
|
|
tcp::endpoint endp = s->remote_endpoint(e);
|
|
|
|
if (e) return;
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log(" *** peer SSL handshake done [ ip: %s ec: %s socket: %s ]"
|
|
|
|
, print_endpoint(endp).c_str(), ec.message().c_str(), s->type_name());
|
|
|
|
}
|
2012-01-14 17:04:25 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<peer_error_alert>())
|
|
|
|
{
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<peer_error_alert>(torrent_handle(), endp
|
|
|
|
, peer_id(), op_ssl_handshake, ec);
|
2012-01-14 17:04:25 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
incoming_connection(s);
|
|
|
|
}
|
|
|
|
|
2012-01-14 17:04:25 +01:00
|
|
|
#endif // TORRENT_USE_OPENSSL
|
|
|
|
|
2016-08-31 18:45:45 +02:00
|
|
|
void session_impl::incoming_connection(std::shared_ptr<socket_type> const& s)
|
2009-04-09 03:04:49 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2010-12-04 23:20:31 +01:00
|
|
|
|
2012-01-16 00:34:43 +01:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2016-09-07 23:51:18 +02:00
|
|
|
#ifdef TORRENT_MACOS_DEPRECATED_LIBCRYPTO
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
#endif
|
2012-01-16 00:34:43 +01:00
|
|
|
// add the current time to the PRNG, to add more unpredictability
|
2016-06-18 20:01:38 +02:00
|
|
|
std::uint64_t now = clock_type::now().time_since_epoch().count();
|
2012-01-16 00:34:43 +01:00
|
|
|
// assume 12 bits of entropy (i.e. about 8 milliseconds)
|
|
|
|
RAND_add(&now, 8, 1.5);
|
2016-09-07 23:51:18 +02:00
|
|
|
#ifdef TORRENT_MACOS_DEPRECATED_LIBCRYPTO
|
|
|
|
#pragma clang diagnostic pop
|
2012-01-16 00:34:43 +01:00
|
|
|
#endif
|
2016-09-07 23:51:18 +02:00
|
|
|
#endif // TORRENT_USE_OPENSSL
|
2012-01-16 00:34:43 +01:00
|
|
|
|
2011-01-23 19:00:52 +01:00
|
|
|
if (m_paused)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" <== INCOMING CONNECTION [ ignored, paused ]");
|
2011-01-23 19:00:52 +01:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
error_code ec;
|
2006-10-11 22:57:54 +02:00
|
|
|
// we got a connection request!
|
2007-09-22 18:27:29 +02:00
|
|
|
tcp::endpoint endp = s->remote_endpoint(ec);
|
|
|
|
|
|
|
|
if (ec)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log(" <== INCOMING CONNECTION FAILED, could "
|
|
|
|
"not retrieve remote endpoint: %s"
|
|
|
|
, ec.message().c_str());
|
|
|
|
}
|
2007-09-22 18:27:29 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log(" <== INCOMING CONNECTION %s type: %s"
|
|
|
|
, print_endpoint(endp).c_str(), s->type_name());
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2007-11-19 19:05:47 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!m_settings.get_bool(settings_pack::enable_incoming_utp)
|
|
|
|
&& is_utp(*s))
|
2010-11-29 02:33:05 +01:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" rejected uTP connection");
|
2010-11-29 02:33:05 +01:00
|
|
|
#endif
|
|
|
|
if (m_alerts.should_post<peer_blocked_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<peer_blocked_alert>(torrent_handle()
|
2016-05-23 01:56:14 +02:00
|
|
|
, endp, peer_blocked_alert::utp_disabled);
|
2010-11-29 02:33:05 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!m_settings.get_bool(settings_pack::enable_incoming_tcp)
|
2015-06-06 19:49:18 +02:00
|
|
|
&& s->get<tcp::socket>())
|
2010-11-29 02:33:05 +01:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" rejected TCP connection");
|
2010-11-29 02:33:05 +01:00
|
|
|
#endif
|
|
|
|
if (m_alerts.should_post<peer_blocked_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<peer_blocked_alert>(torrent_handle()
|
2016-05-23 01:56:14 +02:00
|
|
|
, endp, peer_blocked_alert::tcp_disabled);
|
2010-11-29 02:33:05 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// if there are outgoing interfaces specified, verify this
|
|
|
|
// peer is correctly bound to on of them
|
|
|
|
if (!m_settings.get_str(settings_pack::outgoing_interfaces).empty())
|
|
|
|
{
|
|
|
|
tcp::endpoint local = s->local_endpoint(ec);
|
|
|
|
if (ec)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log(" rejected connection: (%d) %s", ec.value()
|
|
|
|
, ec.message().c_str());
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!verify_bound_address(local.address()
|
|
|
|
, is_utp(*s), ec))
|
|
|
|
{
|
|
|
|
if (ec)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log(" rejected connection, not allowed local interface: (%d) %s"
|
|
|
|
, ec.value(), ec.message().c_str());
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
error_code err;
|
|
|
|
session_log(" rejected connection, not allowed local interface: %s"
|
|
|
|
, local.address().to_string(err).c_str());
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
if (m_alerts.should_post<peer_blocked_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<peer_blocked_alert>(torrent_handle()
|
2016-05-23 01:56:14 +02:00
|
|
|
, endp, peer_blocked_alert::invalid_local_interface);
|
2014-07-06 21:18:00 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-19 19:05:47 +01:00
|
|
|
// local addresses do not count, since it's likely
|
|
|
|
// coming from our own client through local service discovery
|
|
|
|
// and it does not reflect whether or not a router is open
|
|
|
|
// for incoming connections or not.
|
|
|
|
if (!is_local(endp.address()))
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stats_counters.set_value(counters::has_incoming_connections, 1);
|
2007-11-19 19:05:47 +01:00
|
|
|
|
2011-03-02 18:37:10 +01:00
|
|
|
// this filter is ignored if a single torrent
|
|
|
|
// is set to ignore the filter, since this peer might be
|
|
|
|
// for that torrent
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_stats_counters[counters::non_filter_torrents] == 0
|
2015-05-16 08:33:37 +02:00
|
|
|
&& m_ip_filter
|
|
|
|
&& (m_ip_filter->access(endp.address()) & ip_filter::blocked))
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log("filtered blocked ip");
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<peer_blocked_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<peer_blocked_alert>(torrent_handle()
|
2016-05-23 01:56:14 +02:00
|
|
|
, endp, peer_blocked_alert::ip_filter);
|
2006-10-11 22:57:54 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-31 07:54:54 +01:00
|
|
|
// check if we have any active torrents
|
|
|
|
// if we don't reject the connection
|
|
|
|
if (m_torrents.empty())
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-12-31 07:54:54 +01:00
|
|
|
session_log(" There are no torrents, disconnect");
|
|
|
|
#endif
|
2015-05-17 04:00:43 +02:00
|
|
|
return;
|
2012-12-31 07:54:54 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// figure out which peer classes this is connections has,
|
|
|
|
// to get connection_limit_factor
|
|
|
|
peer_class_set pcs;
|
|
|
|
set_peer_classes(&pcs, endp.address(), s->type());
|
|
|
|
int connection_limit_factor = 0;
|
|
|
|
for (int i = 0; i < pcs.num_classes(); ++i)
|
|
|
|
{
|
2016-11-25 17:17:25 +01:00
|
|
|
peer_class_t pc = pcs.class_at(i);
|
2016-06-20 17:32:06 +02:00
|
|
|
if (m_classes.at(pc) == nullptr) continue;
|
2014-07-06 21:18:00 +02:00
|
|
|
int f = m_classes.at(pc)->connection_limit_factor;
|
|
|
|
if (connection_limit_factor < f) connection_limit_factor = f;
|
|
|
|
}
|
|
|
|
if (connection_limit_factor == 0) connection_limit_factor = 100;
|
|
|
|
|
2016-11-21 07:49:56 +01:00
|
|
|
std::int64_t limit = m_settings.get_int(settings_pack::connections_limit);
|
2014-07-06 21:18:00 +02:00
|
|
|
limit = limit * 100 / connection_limit_factor;
|
|
|
|
|
2007-10-27 23:21:44 +02:00
|
|
|
// don't allow more connections than the max setting
|
2014-07-06 21:18:00 +02:00
|
|
|
// weighed by the peer class' setting
|
|
|
|
bool reject = num_connections() >= limit + m_settings.get_int(settings_pack::connections_slack);
|
2010-01-31 19:35:46 +01:00
|
|
|
|
|
|
|
if (reject)
|
2007-10-27 23:21:44 +02:00
|
|
|
{
|
2010-02-06 22:40:55 +01:00
|
|
|
if (m_alerts.should_post<peer_disconnected_alert>())
|
|
|
|
{
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<peer_disconnected_alert>(torrent_handle(), endp, peer_id()
|
2015-02-15 06:17:09 +01:00
|
|
|
, op_bittorrent, s->type()
|
2016-10-02 21:27:50 +02:00
|
|
|
, error_code(errors::too_many_connections)
|
2017-02-04 02:27:31 +01:00
|
|
|
, close_reason_t::none);
|
2010-02-06 22:40:55 +01:00
|
|
|
}
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("number of connections limit exceeded (conns: %d, limit: %d, slack: %d), connection rejected"
|
|
|
|
, num_connections(), m_settings.get_int(settings_pack::connections_limit)
|
|
|
|
, m_settings.get_int(settings_pack::connections_slack));
|
|
|
|
}
|
2007-10-27 23:21:44 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-02-11 05:39:04 +01:00
|
|
|
// if we don't have any active torrents, there's no
|
|
|
|
// point in accepting this connection. If, however,
|
|
|
|
// the setting to start up queued torrents when they
|
|
|
|
// get an incoming connection is enabled, we cannot
|
|
|
|
// perform this check.
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!m_settings.get_bool(settings_pack::incoming_starts_queued_torrents))
|
2007-09-04 00:27:52 +02:00
|
|
|
{
|
2010-02-11 05:39:04 +01:00
|
|
|
bool has_active_torrent = false;
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
2007-09-04 00:27:52 +02:00
|
|
|
{
|
2016-06-01 07:05:32 +02:00
|
|
|
if (!i->second->is_torrent_paused())
|
2010-02-11 05:39:04 +01:00
|
|
|
{
|
|
|
|
has_active_torrent = true;
|
|
|
|
break;
|
|
|
|
}
|
2007-09-04 00:27:52 +02:00
|
|
|
}
|
2010-02-11 05:39:04 +01:00
|
|
|
if (!has_active_torrent)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" There are no _active_ torrents, disconnect");
|
2008-05-12 12:10:39 +02:00
|
|
|
#endif
|
2015-05-17 04:00:43 +02:00
|
|
|
return;
|
2010-02-11 05:39:04 +01:00
|
|
|
}
|
2008-05-12 12:10:39 +02:00
|
|
|
}
|
2007-09-04 00:27:52 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::incoming_connections);
|
|
|
|
|
|
|
|
if (m_alerts.should_post<incoming_connection_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<incoming_connection_alert>(s->type(), endp);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2009-05-01 06:59:15 +02:00
|
|
|
setup_socket_buffers(*s);
|
|
|
|
|
2014-07-14 06:32:41 +02:00
|
|
|
peer_connection_args pack;
|
|
|
|
pack.ses = this;
|
|
|
|
pack.sett = &m_settings;
|
|
|
|
pack.stats_counters = &m_stats_counters;
|
|
|
|
pack.disk_thread = &m_disk_thread;
|
|
|
|
pack.ios = &m_io_service;
|
2016-08-31 14:27:36 +02:00
|
|
|
pack.tor = std::weak_ptr<torrent>();
|
2014-07-14 06:32:41 +02:00
|
|
|
pack.s = s;
|
2014-09-28 06:05:44 +02:00
|
|
|
pack.endp = endp;
|
2016-07-09 22:26:26 +02:00
|
|
|
pack.peerinfo = nullptr;
|
2014-07-14 06:32:41 +02:00
|
|
|
|
2016-09-01 03:42:18 +02:00
|
|
|
std::shared_ptr<peer_connection> c
|
|
|
|
= std::make_shared<bt_peer_connection>(pack, get_peer_id());
|
2014-01-19 20:45:50 +01:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2006-10-11 22:57:54 +02:00
|
|
|
c->m_in_constructor = false;
|
|
|
|
#endif
|
|
|
|
|
2008-03-31 06:46:24 +02:00
|
|
|
if (!c->is_disconnecting())
|
|
|
|
{
|
2012-12-31 07:54:54 +01:00
|
|
|
// in case we've exceeded the limit, let this peer know that
|
|
|
|
// as soon as it's received the handshake, it needs to either
|
|
|
|
// disconnect or pick another peer to disconnect
|
2014-07-06 21:18:00 +02:00
|
|
|
if (num_connections() >= limit)
|
2012-12-31 07:54:54 +01:00
|
|
|
c->peer_exceeds_limit();
|
|
|
|
|
2013-11-02 04:26:53 +01:00
|
|
|
TORRENT_ASSERT(!c->m_in_constructor);
|
2008-03-31 06:46:24 +02:00
|
|
|
m_connections.insert(c);
|
|
|
|
c->start();
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2009-04-09 03:04:49 +02:00
|
|
|
|
2009-05-01 06:59:15 +02:00
|
|
|
void session_impl::setup_socket_buffers(socket_type& s)
|
|
|
|
{
|
|
|
|
error_code ec;
|
2013-09-03 10:39:30 +02:00
|
|
|
set_socket_buffer_size(s, m_settings, ec);
|
2009-05-01 06:59:15 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// if cancel_with_cq is set, the peer connection is
|
|
|
|
// currently expected to be scheduled for a connection
|
|
|
|
// with the connection queue, and should be cancelled
|
|
|
|
// TODO: should this function take a shared_ptr instead?
|
|
|
|
void session_impl::close_connection(peer_connection* p
|
2014-10-03 22:56:57 +02:00
|
|
|
, error_code const& ec)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2016-09-01 03:42:18 +02:00
|
|
|
std::shared_ptr<peer_connection> sp(p->self());
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2013-12-05 08:42:32 +01:00
|
|
|
// someone else is holding a reference, it's important that
|
|
|
|
// it's destructed from the network thread. Make sure the
|
|
|
|
// last reference is held by the network thread.
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!sp.unique())
|
|
|
|
m_undead_peers.push_back(sp);
|
2013-12-05 08:42:32 +01:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log(" CLOSING CONNECTION %s : %s"
|
|
|
|
, print_endpoint(p->remote()).c_str(), ec.message().c_str());
|
|
|
|
}
|
2015-08-22 00:28:12 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(ec);
|
2007-12-19 22:36:54 +01:00
|
|
|
#endif
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(p->is_disconnecting());
|
2008-01-07 02:10:46 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(sp.use_count() > 0);
|
2011-01-25 09:03:35 +01:00
|
|
|
|
|
|
|
connection_map::iterator i = m_connections.find(sp);
|
2011-03-27 22:35:38 +02:00
|
|
|
// make sure the next disk peer round-robin cursor stays valid
|
2008-01-07 02:10:46 +01:00
|
|
|
if (i != m_connections.end()) m_connections.erase(i);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_peer_id(peer_id const& id)
|
|
|
|
{
|
|
|
|
m_peer_id = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_key(int key)
|
|
|
|
{
|
|
|
|
m_key = key;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int session_impl::next_port() const
|
2008-02-28 08:34:07 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
int start = m_settings.get_int(settings_pack::outgoing_port);
|
|
|
|
int num = m_settings.get_int(settings_pack::num_outgoing_ports);
|
|
|
|
std::pair<int, int> out_ports(start, start + num);
|
2008-02-28 08:34:07 +01:00
|
|
|
if (m_next_port < out_ports.first || m_next_port > out_ports.second)
|
|
|
|
m_next_port = out_ports.first;
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2008-02-28 08:34:07 +01:00
|
|
|
int port = m_next_port;
|
|
|
|
++m_next_port;
|
|
|
|
if (m_next_port > out_ports.second) m_next_port = out_ports.first;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" *** BINDING OUTGOING CONNECTION [ port: %d ]", port);
|
2008-02-28 08:34:07 +01:00
|
|
|
#endif
|
|
|
|
return port;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int session_impl::rate_limit(peer_class_t c, int channel) const
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(channel >= 0 && channel <= 1);
|
|
|
|
if (channel < 0 || channel > 1) return 0;
|
2011-10-17 07:17:21 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
peer_class const* pc = m_classes.at(c);
|
2016-07-09 22:26:26 +02:00
|
|
|
if (pc == nullptr) return 0;
|
2014-07-06 21:18:00 +02:00
|
|
|
return pc->channel[channel].throttle();
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int session_impl::upload_rate_limit(peer_class_t c) const
|
|
|
|
{
|
|
|
|
return rate_limit(c, peer_connection::upload_channel);
|
|
|
|
}
|
|
|
|
|
|
|
|
int session_impl::download_rate_limit(peer_class_t c) const
|
|
|
|
{
|
|
|
|
return rate_limit(c, peer_connection::download_channel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_rate_limit(peer_class_t c, int channel, int limit)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(is_single_thread());
|
|
|
|
TORRENT_ASSERT(limit >= -1);
|
|
|
|
TORRENT_ASSERT(channel >= 0 && channel <= 1);
|
|
|
|
|
|
|
|
if (channel < 0 || channel > 1) return;
|
|
|
|
|
|
|
|
peer_class* pc = m_classes.at(c);
|
2016-07-09 22:26:26 +02:00
|
|
|
if (pc == nullptr) return;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (limit <= 0) limit = 0;
|
2017-02-02 15:19:17 +01:00
|
|
|
else limit = std::min(limit, std::numeric_limits<int>::max() - 1);
|
2014-07-06 21:18:00 +02:00
|
|
|
pc->channel[channel].throttle(limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_upload_rate_limit(peer_class_t c, int limit)
|
|
|
|
{
|
|
|
|
set_rate_limit(c, peer_connection::upload_channel, limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_download_rate_limit(peer_class_t c, int limit)
|
|
|
|
{
|
|
|
|
set_rate_limit(c, peer_connection::download_channel, limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if TORRENT_USE_ASSERTS
|
|
|
|
bool session_impl::has_peer(peer_connection const* p) const
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2016-05-25 06:31:52 +02:00
|
|
|
return std::any_of(m_connections.begin(), m_connections.end()
|
2016-09-01 03:42:18 +02:00
|
|
|
, [p] (std::shared_ptr<peer_connection> const& pr)
|
2016-05-25 06:31:52 +02:00
|
|
|
{ return pr.get() == p; });
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool session_impl::any_torrent_has_peer(peer_connection const* p) const
|
|
|
|
{
|
2016-05-25 06:31:52 +02:00
|
|
|
for (auto& pe : m_torrents)
|
|
|
|
if (pe.second->has_peer(p)) return true;
|
2014-07-06 21:18:00 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void session_impl::sent_bytes(int bytes_payload, int bytes_protocol)
|
|
|
|
{
|
2014-12-10 06:49:17 +01:00
|
|
|
m_stats_counters.inc_stats_counter(counters::sent_bytes
|
|
|
|
, bytes_payload + bytes_protocol);
|
|
|
|
m_stats_counters.inc_stats_counter(counters::sent_payload_bytes
|
|
|
|
, bytes_payload);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stat.sent_bytes(bytes_payload, bytes_protocol);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::received_bytes(int bytes_payload, int bytes_protocol)
|
|
|
|
{
|
2014-12-10 06:49:17 +01:00
|
|
|
m_stats_counters.inc_stats_counter(counters::recv_bytes
|
|
|
|
, bytes_payload + bytes_protocol);
|
|
|
|
m_stats_counters.inc_stats_counter(counters::recv_payload_bytes
|
|
|
|
, bytes_payload);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stat.received_bytes(bytes_payload, bytes_protocol);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::trancieve_ip_packet(int bytes, bool ipv6)
|
|
|
|
{
|
2017-01-11 01:53:56 +01:00
|
|
|
// one TCP/IP packet header for the packet
|
|
|
|
// sent or received, and one for the ACK
|
|
|
|
// The IPv4 header is 20 bytes
|
|
|
|
// and IPv6 header is 40 bytes
|
|
|
|
int const header = (ipv6 ? 40 : 20) + 20;
|
|
|
|
int const mtu = 1500;
|
|
|
|
int const packet_size = mtu - header;
|
|
|
|
int const overhead = std::max(1, (bytes + packet_size - 1) / packet_size) * header;
|
|
|
|
m_stats_counters.inc_stats_counter(counters::sent_ip_overhead_bytes
|
|
|
|
, overhead);
|
|
|
|
m_stats_counters.inc_stats_counter(counters::recv_ip_overhead_bytes
|
|
|
|
, overhead);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stat.trancieve_ip_packet(bytes, ipv6);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::sent_syn(bool ipv6)
|
|
|
|
{
|
2017-01-11 01:53:56 +01:00
|
|
|
int const overhead = ipv6 ? 60 : 40;
|
|
|
|
m_stats_counters.inc_stats_counter(counters::sent_ip_overhead_bytes
|
|
|
|
, overhead);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stat.sent_syn(ipv6);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::received_synack(bool ipv6)
|
|
|
|
{
|
2017-01-11 01:53:56 +01:00
|
|
|
int const overhead = ipv6 ? 60 : 40;
|
|
|
|
m_stats_counters.inc_stats_counter(counters::sent_ip_overhead_bytes
|
|
|
|
, overhead);
|
|
|
|
m_stats_counters.inc_stats_counter(counters::recv_ip_overhead_bytes
|
|
|
|
, overhead);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stat.received_synack(ipv6);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::on_tick(error_code const& e)
|
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
COMPLETE_ASYNC("session_impl::on_tick");
|
2014-07-13 06:56:53 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::on_tick_counter);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
TORRENT_ASSERT(is_single_thread());
|
|
|
|
|
|
|
|
// submit all disk jobs when we leave this function
|
|
|
|
deferred_submit_jobs();
|
|
|
|
|
2015-05-16 20:35:47 +02:00
|
|
|
aux::update_time_now();
|
|
|
|
time_point now = aux::time_now();
|
|
|
|
|
2015-11-28 20:06:40 +01:00
|
|
|
// remove undead peers that only have this list as their reference keeping them alive
|
|
|
|
if (!m_undead_peers.empty())
|
|
|
|
{
|
2016-10-25 23:27:48 +02:00
|
|
|
auto const remove_it = std::remove_if(m_undead_peers.begin(), m_undead_peers.end()
|
2016-09-01 03:42:18 +02:00
|
|
|
, std::bind(&std::shared_ptr<peer_connection>::unique, _1));
|
2015-11-28 20:06:40 +01:00
|
|
|
m_undead_peers.erase(remove_it, m_undead_peers.end());
|
|
|
|
if (m_undead_peers.empty())
|
|
|
|
{
|
|
|
|
// we just removed our last "undead" peer (i.e. a peer connection
|
|
|
|
// that had some external reference to it). It's now safe to
|
|
|
|
// shut-down
|
|
|
|
if (m_abort)
|
|
|
|
{
|
2016-05-25 06:31:52 +02:00
|
|
|
m_io_service.post(std::bind(&session_impl::abort_stage2, this));
|
2015-11-28 20:06:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// too expensive
|
2007-09-29 18:14:03 +02:00
|
|
|
// INVARIANT_CHECK;
|
2007-08-21 20:33:28 +02:00
|
|
|
|
2012-01-23 06:02:12 +01:00
|
|
|
// we have to keep ticking the utp socket manager
|
|
|
|
// until they're all closed
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_abort)
|
2012-01-23 06:02:12 +01:00
|
|
|
{
|
2015-11-28 20:06:40 +01:00
|
|
|
if (m_utp_socket_manager.num_sockets() == 0
|
2016-04-24 21:26:28 +02:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
&& m_ssl_utp_socket_manager.num_sockets() == 0
|
|
|
|
#endif
|
2015-11-28 20:06:40 +01:00
|
|
|
&& m_undead_peers.empty())
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
return;
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
2012-01-23 06:02:12 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
2016-05-17 15:24:06 +02:00
|
|
|
std::fprintf(stderr, "uTP sockets: %d ssl-uTP sockets: %d undead-peers left: %d\n"
|
2015-11-28 20:06:40 +01:00
|
|
|
, m_utp_socket_manager.num_sockets()
|
2016-04-24 21:26:28 +02:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
, m_ssl_utp_socket_manager.num_sockets()
|
|
|
|
#else
|
|
|
|
, 0
|
|
|
|
#endif
|
2015-11-28 20:06:40 +01:00
|
|
|
, int(m_undead_peers.size()));
|
2012-01-23 06:02:12 +01:00
|
|
|
#endif
|
|
|
|
}
|
2007-10-07 20:06:56 +02:00
|
|
|
|
2015-06-06 08:10:53 +02:00
|
|
|
if (e == boost::asio::error::operation_aborted) return;
|
2010-03-17 20:01:08 +01:00
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
if (e)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
session_log("*** TICK TIMER FAILED %s", e.message().c_str());
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2015-08-18 16:42:03 +02:00
|
|
|
std::abort();
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_tick");
|
2008-05-03 18:05:42 +02:00
|
|
|
error_code ec;
|
2014-07-06 21:18:00 +02:00
|
|
|
m_timer.expires_at(now + milliseconds(m_settings.get_int(settings_pack::tick_interval)), ec);
|
2016-10-06 06:08:14 +02:00
|
|
|
m_timer.async_wait(make_tick_handler([this](error_code const& err) {
|
|
|
|
this->wrap(&session_impl::on_tick, err); }));
|
2009-04-26 02:21:59 +02:00
|
|
|
|
|
|
|
m_download_rate.update_quotas(now - m_last_tick);
|
|
|
|
m_upload_rate.update_quotas(now - m_last_tick);
|
|
|
|
|
|
|
|
m_last_tick = now;
|
|
|
|
|
2010-11-29 02:33:05 +01:00
|
|
|
m_utp_socket_manager.tick(now);
|
2016-04-09 16:50:45 +02:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
m_ssl_utp_socket_manager.tick(now);
|
|
|
|
#endif
|
2010-11-29 02:33:05 +01:00
|
|
|
|
2009-04-30 07:49:46 +02:00
|
|
|
// only tick the following once per second
|
2009-04-26 02:21:59 +02:00
|
|
|
if (now - m_last_second_tick < seconds(1)) return;
|
|
|
|
|
2012-08-03 07:13:40 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2015-01-06 09:08:49 +01:00
|
|
|
if (m_dht
|
|
|
|
&& m_dht_interval_update_torrents < 40
|
2014-07-05 16:10:25 +02:00
|
|
|
&& m_dht_interval_update_torrents != int(m_torrents.size()))
|
2012-08-03 07:13:40 +02:00
|
|
|
update_dht_announce_interval();
|
|
|
|
#endif
|
|
|
|
|
2014-05-10 05:23:05 +02:00
|
|
|
int tick_interval_ms = int(total_milliseconds(now - m_last_second_tick));
|
2009-04-26 02:21:59 +02:00
|
|
|
m_last_second_tick = now;
|
2010-02-14 02:39:55 +01:00
|
|
|
m_tick_residual += tick_interval_ms - 1000;
|
2007-05-14 00:01:21 +02:00
|
|
|
|
2016-06-18 20:01:38 +02:00
|
|
|
std::int32_t const stime = session_time();
|
2016-01-31 03:33:47 +01:00
|
|
|
if (stime > 65000)
|
2009-04-30 07:49:46 +02:00
|
|
|
{
|
|
|
|
// we're getting close to the point where our timestamps
|
2014-07-06 21:18:00 +02:00
|
|
|
// in torrent_peer are wrapping. We need to step all counters back
|
2009-04-30 07:49:46 +02:00
|
|
|
// four hours. This means that any timestamp that refers to a time
|
|
|
|
// more than 18.2 - 4 = 14.2 hours ago, will be incremented to refer to
|
|
|
|
// 14.2 hours ago.
|
|
|
|
|
|
|
|
m_created += hours(4);
|
|
|
|
|
|
|
|
const int four_hours = 60 * 60 * 4;
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
i->second->step_session_time(four_hours);
|
2009-04-30 07:49:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-29 11:37:21 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2016-06-18 04:02:21 +02:00
|
|
|
for (auto& ext : m_ses_extensions[plugins_tick_idx])
|
2011-01-29 11:37:21 +01:00
|
|
|
{
|
2016-10-23 04:00:47 +02:00
|
|
|
ext->on_tick();
|
2011-01-29 11:37:21 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-02-21 00:44:34 +01:00
|
|
|
// don't do any of the following while we're shutting down
|
|
|
|
if (m_abort) return;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
switch (m_settings.get_int(settings_pack::mixed_mode_algorithm))
|
2010-11-29 02:33:05 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
case settings_pack::prefer_tcp:
|
|
|
|
set_upload_rate_limit(m_tcp_peer_class, 0);
|
|
|
|
set_download_rate_limit(m_tcp_peer_class, 0);
|
2010-11-29 02:33:05 +01:00
|
|
|
break;
|
2014-07-06 21:18:00 +02:00
|
|
|
case settings_pack::peer_proportional:
|
2010-11-29 02:33:05 +01:00
|
|
|
{
|
2011-10-11 07:00:35 +02:00
|
|
|
int num_peers[2][2] = {{0, 0}, {0, 0}};
|
2010-11-29 02:33:05 +01:00
|
|
|
for (connection_map::iterator i = m_connections.begin()
|
|
|
|
, end(m_connections.end());i != end; ++i)
|
|
|
|
{
|
|
|
|
peer_connection& p = *(*i);
|
|
|
|
if (p.in_handshake()) continue;
|
2011-10-11 07:00:35 +02:00
|
|
|
int protocol = 0;
|
2012-10-05 05:20:40 +02:00
|
|
|
if (is_utp(*p.get_socket())) protocol = 1;
|
2010-11-29 02:33:05 +01:00
|
|
|
|
2011-10-11 07:00:35 +02:00
|
|
|
if (p.download_queue().size() + p.request_queue().size() > 0)
|
|
|
|
++num_peers[protocol][peer_connection::download_channel];
|
|
|
|
if (p.upload_queue().size() > 0)
|
|
|
|
++num_peers[protocol][peer_connection::upload_channel];
|
2010-11-29 02:33:05 +01:00
|
|
|
}
|
2011-10-11 07:00:35 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
peer_class* pc = m_classes.at(m_tcp_peer_class);
|
|
|
|
bandwidth_channel* tcp_channel = pc->channel;
|
2011-10-11 07:00:35 +02:00
|
|
|
int stat_rate[] = {m_stat.upload_rate(), m_stat.download_rate() };
|
2011-10-11 07:05:09 +02:00
|
|
|
// never throttle below this
|
|
|
|
int lower_limit[] = {5000, 30000};
|
2011-10-11 07:00:35 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < 2; ++i)
|
2010-11-29 02:33:05 +01:00
|
|
|
{
|
2011-10-11 07:00:35 +02:00
|
|
|
// if there are no uploading uTP peers, don't throttle TCP up
|
|
|
|
if (num_peers[1][i] == 0)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
tcp_channel[i].throttle(0);
|
2011-10-11 07:00:35 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (num_peers[0][i] == 0) num_peers[0][i] = 1;
|
|
|
|
int total_peers = num_peers[0][i] + num_peers[1][i];
|
|
|
|
// this are 64 bits since it's multiplied by the number
|
|
|
|
// of peers, which otherwise might overflow an int
|
2017-02-08 16:54:55 +01:00
|
|
|
std::int64_t rate = stat_rate[i];
|
|
|
|
tcp_channel[i].throttle(std::max(int(rate * num_peers[0][i] / total_peers), lower_limit[i]));
|
2011-10-11 07:00:35 +02:00
|
|
|
}
|
2010-11-29 02:33:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-03-25 08:49:32 +01:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// auto managed torrent
|
|
|
|
// --------------------------------------------------------------
|
2011-12-24 21:15:22 +01:00
|
|
|
if (!m_paused) m_auto_manage_time_scaler--;
|
2011-12-23 21:02:59 +01:00
|
|
|
if (m_auto_manage_time_scaler < 0)
|
2011-03-25 08:49:32 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
m_auto_manage_time_scaler = settings().get_int(settings_pack::auto_manage_interval);
|
2011-03-25 08:49:32 +01:00
|
|
|
recalculate_auto_managed_torrents();
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
// check for incoming connections that might have timed out
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
|
|
|
|
for (connection_map::iterator i = m_connections.begin();
|
|
|
|
i != m_connections.end();)
|
|
|
|
{
|
|
|
|
peer_connection* p = (*i).get();
|
|
|
|
++i;
|
|
|
|
// ignore connections that already have a torrent, since they
|
|
|
|
// are ticked through the torrents' second_tick
|
|
|
|
if (!p->associated_torrent().expired()) continue;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2013-02-07 07:41:11 +01:00
|
|
|
// TODO: have a separate list for these connections, instead of having to loop through all of them
|
2015-06-17 07:18:38 +02:00
|
|
|
int timeout = m_settings.get_int(settings_pack::handshake_timeout);
|
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
timeout *= is_i2p(*p->get_socket()) ? 4 : 1;
|
|
|
|
#endif
|
|
|
|
if (m_last_tick - p->connected_time () > seconds(timeout))
|
2015-02-15 06:17:09 +01:00
|
|
|
p->disconnect(errors::timed_out, op_bittorrent);
|
2011-03-25 08:49:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------
|
2014-07-06 21:18:00 +02:00
|
|
|
// second_tick every torrent (that wants it)
|
2011-03-25 08:49:32 +01:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
|
2014-06-06 03:26:18 +02:00
|
|
|
#if TORRENT_DEBUG_STREAMING > 0
|
2016-05-17 15:24:06 +02:00
|
|
|
std::printf("\033[2J\033[0;0H");
|
2014-06-06 03:26:18 +02:00
|
|
|
#endif
|
|
|
|
|
2017-02-08 16:54:55 +01:00
|
|
|
aux::vector<torrent*>& want_tick = m_torrent_lists[torrent_want_tick];
|
2014-07-06 21:18:00 +02:00
|
|
|
for (int i = 0; i < int(want_tick.size()); ++i)
|
2011-03-25 08:49:32 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent& t = *want_tick[i];
|
|
|
|
TORRENT_ASSERT(t.want_tick());
|
2011-03-25 08:49:32 +01:00
|
|
|
TORRENT_ASSERT(!t.is_aborted());
|
|
|
|
|
2015-08-29 22:07:19 +02:00
|
|
|
t.second_tick(tick_interval_ms);
|
2011-03-25 08:49:32 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// if the call to second_tick caused the torrent
|
|
|
|
// to no longer want to be ticked (i.e. it was
|
|
|
|
// removed from the list) we need to back up the counter
|
|
|
|
// to not miss the torrent after it
|
|
|
|
if (!t.want_tick()) --i;
|
2011-03-25 08:49:32 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// TODO: this should apply to all bandwidth channels
|
|
|
|
if (m_settings.get_bool(settings_pack::rate_limit_ip_overhead))
|
2011-03-25 08:49:32 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
int up_limit = upload_rate_limit(m_global_class);
|
|
|
|
int down_limit = download_rate_limit(m_global_class);
|
2011-03-25 08:49:32 +01:00
|
|
|
|
|
|
|
if (down_limit > 0
|
|
|
|
&& m_stat.download_ip_overhead() >= down_limit
|
|
|
|
&& m_alerts.should_post<performance_alert>())
|
|
|
|
{
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<performance_alert>(torrent_handle()
|
|
|
|
, performance_alert::download_limit_too_low);
|
2011-03-25 08:49:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (up_limit > 0
|
|
|
|
&& m_stat.upload_ip_overhead() >= up_limit
|
|
|
|
&& m_alerts.should_post<performance_alert>())
|
|
|
|
{
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<performance_alert>(torrent_handle()
|
|
|
|
, performance_alert::upload_limit_too_low);
|
2011-03-25 08:49:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_peak_up_rate = (std::max)(m_stat.upload_rate(), m_peak_up_rate);
|
|
|
|
m_peak_down_rate = (std::max)(m_stat.download_rate(), m_peak_down_rate);
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2011-03-25 08:49:32 +01:00
|
|
|
m_stat.second_tick(tick_interval_ms);
|
|
|
|
|
2011-04-06 08:27:42 +02:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// scrape paused torrents that are auto managed
|
|
|
|
// (unless the session is paused)
|
|
|
|
// --------------------------------------------------------------
|
2016-06-03 13:32:48 +02:00
|
|
|
if (!m_paused)
|
2011-04-06 08:27:42 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
INVARIANT_CHECK;
|
2011-04-06 08:27:42 +02:00
|
|
|
--m_auto_scrape_time_scaler;
|
|
|
|
if (m_auto_scrape_time_scaler <= 0)
|
2011-02-06 04:07:00 +01:00
|
|
|
{
|
2017-02-08 16:54:55 +01:00
|
|
|
aux::vector<torrent*>& want_scrape = m_torrent_lists[torrent_want_scrape];
|
2014-07-06 21:18:00 +02:00
|
|
|
m_auto_scrape_time_scaler = m_settings.get_int(settings_pack::auto_scrape_interval)
|
|
|
|
/ (std::max)(1, int(want_scrape.size()));
|
|
|
|
if (m_auto_scrape_time_scaler < m_settings.get_int(settings_pack::auto_scrape_min_interval))
|
|
|
|
m_auto_scrape_time_scaler = m_settings.get_int(settings_pack::auto_scrape_min_interval);
|
2011-04-06 08:27:42 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!want_scrape.empty() && !m_abort)
|
2011-02-06 04:07:00 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_next_scrape_torrent >= int(want_scrape.size()))
|
|
|
|
m_next_scrape_torrent = 0;
|
|
|
|
|
|
|
|
torrent& t = *want_scrape[m_next_scrape_torrent];
|
|
|
|
TORRENT_ASSERT(t.is_paused() && t.is_auto_managed());
|
|
|
|
|
2016-01-17 03:24:04 +01:00
|
|
|
// false means it's not triggered by the user, but automatically
|
|
|
|
// by libtorrent
|
2016-01-25 06:51:20 +01:00
|
|
|
t.scrape_tracker(-1, false);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
++m_next_scrape_torrent;
|
|
|
|
if (m_next_scrape_torrent >= int(want_scrape.size()))
|
|
|
|
m_next_scrape_torrent = 0;
|
|
|
|
|
2011-02-06 04:07:00 +01:00
|
|
|
}
|
|
|
|
}
|
2007-05-14 00:01:21 +02:00
|
|
|
}
|
2011-04-06 08:27:42 +02:00
|
|
|
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
// connect new peers
|
|
|
|
// --------------------------------------------------------------
|
2011-02-03 07:22:22 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
try_connect_more_peers();
|
2007-05-05 02:29:33 +02:00
|
|
|
|
2007-08-16 14:41:46 +02:00
|
|
|
// --------------------------------------------------------------
|
2008-10-19 00:35:10 +02:00
|
|
|
// unchoke set calculations
|
2007-08-16 14:41:46 +02:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
m_unchoke_time_scaler--;
|
|
|
|
if (m_unchoke_time_scaler <= 0 && !m_connections.empty())
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
m_unchoke_time_scaler = settings().get_int(settings_pack::unchoke_interval);
|
|
|
|
recalculate_unchoke_slots();
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
2007-08-16 14:41:46 +02:00
|
|
|
|
2008-10-19 00:35:10 +02:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// optimistic unchoke calculation
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
m_optimistic_unchoke_time_scaler--;
|
|
|
|
if (m_optimistic_unchoke_time_scaler <= 0)
|
|
|
|
{
|
|
|
|
m_optimistic_unchoke_time_scaler
|
2014-07-06 21:18:00 +02:00
|
|
|
= settings().get_int(settings_pack::optimistic_unchoke_interval);
|
2010-02-02 19:39:32 +01:00
|
|
|
recalculate_optimistic_unchoke_slots();
|
2008-10-19 00:35:10 +02:00
|
|
|
}
|
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// disconnect peers when we have too many
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
--m_disconnect_time_scaler;
|
|
|
|
if (m_disconnect_time_scaler <= 0)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
m_disconnect_time_scaler = m_settings.get_int(settings_pack::peer_turnover_interval);
|
2008-04-24 05:28:48 +02:00
|
|
|
|
2014-08-16 09:46:06 +02:00
|
|
|
// if the connections_limit is too low, the disconnect
|
|
|
|
// logic is disabled, since it is too disruptive
|
|
|
|
if (m_settings.get_int(settings_pack::connections_limit) > 5)
|
2008-05-12 07:17:11 +02:00
|
|
|
{
|
2014-08-16 09:46:06 +02:00
|
|
|
if (num_connections() >= m_settings.get_int(settings_pack::connections_limit)
|
|
|
|
* m_settings.get_int(settings_pack::peer_turnover_cutoff) / 100
|
|
|
|
&& !m_torrents.empty())
|
2008-05-12 07:17:11 +02:00
|
|
|
{
|
2014-08-16 09:46:06 +02:00
|
|
|
// every 90 seconds, disconnect the worst peers
|
|
|
|
// if we have reached the connection limit
|
|
|
|
torrent_map::iterator i = std::max_element(m_torrents.begin(), m_torrents.end()
|
2016-05-25 06:31:52 +02:00
|
|
|
, [] (torrent_map::value_type const& lhs, torrent_map::value_type const& rhs)
|
|
|
|
{ return lhs.second->num_peers() < rhs.second->num_peers(); });
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2014-08-16 09:46:06 +02:00
|
|
|
TORRENT_ASSERT(i != m_torrents.end());
|
|
|
|
int peers_to_disconnect = (std::min)((std::max)(
|
|
|
|
int(i->second->num_peers() * m_settings.get_int(settings_pack::peer_turnover) / 100), 1)
|
2014-07-06 21:18:00 +02:00
|
|
|
, i->second->num_connect_candidates());
|
2014-08-16 09:46:06 +02:00
|
|
|
i->second->disconnect_peers(peers_to_disconnect
|
2016-10-02 21:27:50 +02:00
|
|
|
, error_code(errors::optimistic_disconnect));
|
2008-05-12 07:17:11 +02:00
|
|
|
}
|
2014-08-16 09:46:06 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// if we haven't reached the global max. see if any torrent
|
|
|
|
// has reached its local limit
|
2016-10-25 23:27:48 +02:00
|
|
|
for (auto const& pt : m_torrents)
|
2014-08-16 09:46:06 +02:00
|
|
|
{
|
2016-10-25 23:27:48 +02:00
|
|
|
std::shared_ptr<torrent> t = pt.second;
|
2014-08-16 09:46:06 +02:00
|
|
|
|
|
|
|
// ths disconnect logic is disabled for torrents with
|
|
|
|
// too low connection limit
|
|
|
|
if (t->num_peers() < t->max_connections()
|
|
|
|
* m_settings.get_int(settings_pack::peer_turnover_cutoff) / 100
|
|
|
|
|| t->max_connections() < 6)
|
|
|
|
continue;
|
|
|
|
|
2016-10-25 23:27:48 +02:00
|
|
|
int peers_to_disconnect = (std::min)((std::max)(t->num_peers()
|
|
|
|
* m_settings.get_int(settings_pack::peer_turnover) / 100, 1)
|
2014-08-16 09:46:06 +02:00
|
|
|
, t->num_connect_candidates());
|
2016-10-25 23:27:48 +02:00
|
|
|
t->disconnect_peers(peers_to_disconnect, errors::optimistic_disconnect);
|
2014-08-16 09:46:06 +02:00
|
|
|
}
|
|
|
|
}
|
2007-08-16 14:41:46 +02:00
|
|
|
}
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
2009-05-11 22:23:47 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_tick_residual = m_tick_residual % 1000;
|
2009-05-11 22:23:47 +02:00
|
|
|
// m_peer_pool.release_memory();
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
2007-08-16 14:41:46 +02:00
|
|
|
|
2015-04-20 02:01:27 +02:00
|
|
|
namespace {
|
2014-07-06 21:18:00 +02:00
|
|
|
// returns the index of the first set bit.
|
2016-06-18 20:01:38 +02:00
|
|
|
int log2(std::uint32_t v)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
|
2015-05-17 04:00:43 +02:00
|
|
|
static const int MultiplyDeBruijnBitPosition[32] =
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
|
|
|
|
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
|
|
|
|
};
|
|
|
|
|
2016-02-07 08:09:19 +01:00
|
|
|
v |= v >> 1; // first round down to one less than a power of 2
|
2014-07-06 21:18:00 +02:00
|
|
|
v |= v >> 2;
|
|
|
|
v |= v >> 4;
|
|
|
|
v |= v >> 8;
|
|
|
|
v |= v >> 16;
|
|
|
|
|
2016-06-18 20:01:38 +02:00
|
|
|
return MultiplyDeBruijnBitPosition[std::uint32_t(v * 0x07C4ACDDU) >> 27];
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
2015-04-20 02:01:27 +02:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::received_buffer(int s)
|
|
|
|
{
|
2017-02-08 16:54:55 +01:00
|
|
|
int index = std::min(log2(std::uint32_t(s >> 3)), 17);
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::socket_recv_size3 + index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::sent_buffer(int s)
|
|
|
|
{
|
2017-02-08 16:54:55 +01:00
|
|
|
int index = std::min(log2(std::uint32_t(s >> 3)), 17);
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::socket_send_size3 + index);
|
|
|
|
}
|
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
void session_impl::prioritize_connections(std::weak_ptr<torrent> t)
|
2012-11-03 04:50:12 +01:00
|
|
|
{
|
|
|
|
m_prio_torrents.push_back(std::make_pair(t, 10));
|
|
|
|
}
|
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
|
2016-09-09 21:02:20 +02:00
|
|
|
void session_impl::add_dht_node(udp::endpoint const& n)
|
2012-11-03 04:50:12 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2012-11-03 04:50:12 +01:00
|
|
|
|
|
|
|
if (m_dht) m_dht->add_node(n);
|
2015-08-18 23:35:27 +02:00
|
|
|
else m_dht_nodes.push_back(n);
|
2012-11-03 04:50:12 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
bool session_impl::has_dht() const
|
|
|
|
{
|
2016-06-20 17:32:06 +02:00
|
|
|
return m_dht.get() != nullptr;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
void session_impl::prioritize_dht(std::weak_ptr<torrent> t)
|
2012-11-03 04:50:12 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(!m_abort);
|
|
|
|
if (m_abort) return;
|
|
|
|
|
2013-10-10 11:08:56 +02:00
|
|
|
TORRENT_ASSERT(m_dht);
|
2012-11-03 04:50:12 +01:00
|
|
|
m_dht_torrents.push_back(t);
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> tor = t.lock();
|
2016-09-14 04:46:07 +02:00
|
|
|
if (tor && should_log())
|
2014-07-06 21:18:00 +02:00
|
|
|
session_log("prioritizing DHT announce: \"%s\"", tor->name().c_str());
|
|
|
|
#endif
|
2014-11-01 23:47:56 +01:00
|
|
|
// trigger a DHT announce right away if we just added a new torrent and
|
|
|
|
// there's no back-log. in the timer handler, as long as there are more
|
|
|
|
// high priority torrents to be announced to the DHT, it will keep the
|
|
|
|
// timer interval short until all torrents have been announced.
|
2012-11-03 04:50:12 +01:00
|
|
|
if (m_dht_torrents.size() == 1)
|
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_dht_announce");
|
2012-11-03 04:50:12 +01:00
|
|
|
error_code ec;
|
|
|
|
m_dht_announce_timer.expires_from_now(seconds(0), ec);
|
2016-10-06 06:08:14 +02:00
|
|
|
m_dht_announce_timer.async_wait([this](error_code const& err) {
|
|
|
|
this->wrap(&session_impl::on_dht_announce, err); });
|
2012-11-03 04:50:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
void session_impl::on_dht_announce(error_code const& e)
|
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
COMPLETE_ASYNC("session_impl::on_dht_announce");
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
|
|
|
if (e)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("aborting DHT announce timer (%d): %s"
|
|
|
|
, e.value(), e.message().c_str());
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2010-02-14 02:39:55 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_abort)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2014-07-06 21:18:00 +02:00
|
|
|
session_log("aborting DHT announce timer: m_abort set");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_dht)
|
|
|
|
{
|
|
|
|
m_dht_torrents.clear();
|
|
|
|
return;
|
|
|
|
}
|
2010-02-14 02:39:55 +01:00
|
|
|
|
2013-10-10 11:08:56 +02:00
|
|
|
TORRENT_ASSERT(m_dht);
|
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
// announce to DHT every 15 minutes
|
2014-07-06 21:18:00 +02:00
|
|
|
int delay = (std::max)(m_settings.get_int(settings_pack::dht_announce_interval)
|
2010-02-14 02:39:55 +01:00
|
|
|
/ (std::max)(int(m_torrents.size()), 1), 1);
|
2012-11-03 04:50:12 +01:00
|
|
|
|
|
|
|
if (!m_dht_torrents.empty())
|
|
|
|
{
|
|
|
|
// we have prioritized torrents that need
|
|
|
|
// an initial DHT announce. Don't wait too long
|
|
|
|
// until we announce those.
|
|
|
|
delay = (std::min)(4, delay);
|
|
|
|
}
|
|
|
|
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_dht_announce");
|
2010-02-14 02:39:55 +01:00
|
|
|
error_code ec;
|
|
|
|
m_dht_announce_timer.expires_from_now(seconds(delay), ec);
|
2016-10-06 06:08:14 +02:00
|
|
|
m_dht_announce_timer.async_wait([this](error_code const& err) {
|
|
|
|
this->wrap(&session_impl::on_dht_announce, err); }
|
|
|
|
);
|
2010-02-14 02:39:55 +01:00
|
|
|
|
2012-08-03 07:13:40 +02:00
|
|
|
if (!m_dht_torrents.empty())
|
|
|
|
{
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> t;
|
2012-08-03 07:13:40 +02:00
|
|
|
do
|
|
|
|
{
|
2015-05-16 08:33:37 +02:00
|
|
|
t = m_dht_torrents.front().lock();
|
2012-08-03 07:13:40 +02:00
|
|
|
m_dht_torrents.pop_front();
|
2014-07-06 21:18:00 +02:00
|
|
|
} while (!t && !m_dht_torrents.empty());
|
|
|
|
|
2012-08-03 07:13:40 +02:00
|
|
|
if (t)
|
|
|
|
{
|
|
|
|
t->dht_announce();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2010-02-14 18:24:53 +01:00
|
|
|
if (m_torrents.empty()) return;
|
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
if (m_next_dht_torrent == m_torrents.end())
|
|
|
|
m_next_dht_torrent = m_torrents.begin();
|
|
|
|
m_next_dht_torrent->second->dht_announce();
|
2014-07-06 21:18:00 +02:00
|
|
|
// TODO: 2 make a list for torrents that want to be announced on the DHT so we
|
|
|
|
// don't have to loop over all torrents, just to find the ones that want to announce
|
2010-02-14 02:39:55 +01:00
|
|
|
++m_next_dht_torrent;
|
|
|
|
if (m_next_dht_torrent == m_torrents.end())
|
|
|
|
m_next_dht_torrent = m_torrents.begin();
|
2015-05-16 08:33:37 +02:00
|
|
|
}
|
2010-02-14 02:39:55 +01:00
|
|
|
#endif
|
|
|
|
|
2010-02-05 09:23:17 +01:00
|
|
|
void session_impl::on_lsd_announce(error_code const& e)
|
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
COMPLETE_ASYNC("session_impl::on_lsd_announce");
|
2014-07-13 06:56:53 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::on_lsd_counter);
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2010-02-05 09:23:17 +01:00
|
|
|
if (e) return;
|
|
|
|
|
2010-02-13 17:29:17 +01:00
|
|
|
if (m_abort) return;
|
2010-02-05 09:23:17 +01:00
|
|
|
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_lsd_announce");
|
2010-02-05 09:23:17 +01:00
|
|
|
// announce on local network every 5 minutes
|
2014-07-06 21:18:00 +02:00
|
|
|
int delay = (std::max)(m_settings.get_int(settings_pack::local_service_announce_interval)
|
2010-02-05 09:23:17 +01:00
|
|
|
/ (std::max)(int(m_torrents.size()), 1), 1);
|
|
|
|
error_code ec;
|
|
|
|
m_lsd_announce_timer.expires_from_now(seconds(delay), ec);
|
2016-10-06 06:08:14 +02:00
|
|
|
m_lsd_announce_timer.async_wait([this](error_code const& err) {
|
|
|
|
this->wrap(&session_impl::on_lsd_announce, err); });
|
2010-02-05 09:23:17 +01:00
|
|
|
|
2010-02-14 18:24:53 +01:00
|
|
|
if (m_torrents.empty()) return;
|
|
|
|
|
2010-02-13 17:29:17 +01:00
|
|
|
if (m_next_lsd_torrent == m_torrents.end())
|
|
|
|
m_next_lsd_torrent = m_torrents.begin();
|
2010-02-05 09:23:17 +01:00
|
|
|
m_next_lsd_torrent->second->lsd_announce();
|
|
|
|
++m_next_lsd_torrent;
|
|
|
|
if (m_next_lsd_torrent == m_torrents.end())
|
|
|
|
m_next_lsd_torrent = m_torrents.begin();
|
|
|
|
}
|
|
|
|
|
2015-05-26 20:39:49 +02:00
|
|
|
void session_impl::auto_manage_checking_torrents(std::vector<torrent*>& list
|
|
|
|
, int& limit)
|
2009-05-27 21:27:12 +02:00
|
|
|
{
|
|
|
|
for (std::vector<torrent*>::iterator i = list.begin()
|
|
|
|
, end(list.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
torrent* t = *i;
|
2011-02-04 07:55:05 +01:00
|
|
|
|
2015-05-26 20:39:49 +02:00
|
|
|
TORRENT_ASSERT(t->state() == torrent_status::checking_files);
|
2015-09-19 23:49:01 +02:00
|
|
|
TORRENT_ASSERT(t->is_auto_managed());
|
|
|
|
if (limit <= 0)
|
|
|
|
{
|
|
|
|
t->pause();
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2015-09-19 23:49:01 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
t->resume();
|
|
|
|
t->start_checking();
|
|
|
|
--limit;
|
|
|
|
}
|
|
|
|
}
|
2015-05-26 20:39:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::auto_manage_torrents(std::vector<torrent*>& list
|
|
|
|
, int& dht_limit, int& tracker_limit
|
|
|
|
, int& lsd_limit, int& hard_limit, int type_limit)
|
|
|
|
{
|
|
|
|
for (std::vector<torrent*>::iterator i = list.begin()
|
|
|
|
, end(list.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
torrent* t = *i;
|
|
|
|
|
|
|
|
TORRENT_ASSERT(t->state() != torrent_status::checking_files);
|
2011-02-04 07:55:05 +01:00
|
|
|
|
2015-09-20 03:06:56 +02:00
|
|
|
// inactive torrents don't count (and if you configured them to do so,
|
|
|
|
// the torrent won't say it's inactive)
|
|
|
|
if (hard_limit > 0 && t->is_inactive())
|
|
|
|
{
|
|
|
|
t->set_announce_to_dht(--dht_limit >= 0);
|
|
|
|
t->set_announce_to_trackers(--tracker_limit >= 0);
|
|
|
|
t->set_announce_to_lsd(--lsd_limit >= 0);
|
|
|
|
|
|
|
|
--hard_limit;
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-06-01 07:05:32 +02:00
|
|
|
if (t->is_torrent_paused())
|
2015-09-20 03:06:56 +02:00
|
|
|
t->log_to_all_peers("auto manager starting (inactive) torrent");
|
|
|
|
#endif
|
2016-06-01 07:05:32 +02:00
|
|
|
t->set_paused(false);
|
2015-09-20 03:06:56 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-05-27 21:27:12 +02:00
|
|
|
if (type_limit > 0 && hard_limit > 0)
|
|
|
|
{
|
2015-09-19 08:10:50 +02:00
|
|
|
t->set_announce_to_dht(--dht_limit >= 0);
|
|
|
|
t->set_announce_to_trackers(--tracker_limit >= 0);
|
|
|
|
t->set_announce_to_lsd(--lsd_limit >= 0);
|
|
|
|
|
2009-05-27 21:27:12 +02:00
|
|
|
--hard_limit;
|
|
|
|
--type_limit;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-06-01 07:05:32 +02:00
|
|
|
if (t->is_torrent_paused())
|
2015-05-03 04:53:54 +02:00
|
|
|
t->log_to_all_peers("auto manager starting torrent");
|
2010-08-18 19:14:40 +02:00
|
|
|
#endif
|
2016-06-01 07:05:32 +02:00
|
|
|
t->set_paused(false);
|
2015-09-20 03:06:56 +02:00
|
|
|
continue;
|
2009-05-27 21:27:12 +02:00
|
|
|
}
|
2015-09-20 03:06:56 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-06-01 07:05:32 +02:00
|
|
|
if (!t->is_torrent_paused())
|
2015-09-20 03:06:56 +02:00
|
|
|
t->log_to_all_peers("auto manager pausing torrent");
|
|
|
|
#endif
|
|
|
|
// use graceful pause for auto-managed torrents
|
2016-06-01 07:05:32 +02:00
|
|
|
t->set_paused(true, torrent::flag_graceful_pause
|
2016-03-07 03:42:18 +01:00
|
|
|
| torrent::flag_clear_disk_cache);
|
2015-09-20 03:06:56 +02:00
|
|
|
t->set_announce_to_dht(false);
|
|
|
|
t->set_announce_to_trackers(false);
|
|
|
|
t->set_announce_to_lsd(false);
|
2009-05-27 21:27:12 +02:00
|
|
|
}
|
|
|
|
}
|
2008-06-21 14:31:28 +02:00
|
|
|
|
2016-03-27 18:09:53 +02:00
|
|
|
int session_impl::get_int_setting(int n) const
|
|
|
|
{
|
|
|
|
int const v = settings().get_int(n);
|
|
|
|
if (v < 0) return (std::numeric_limits<int>::max)();
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
void session_impl::recalculate_auto_managed_torrents()
|
|
|
|
{
|
2012-06-21 05:51:39 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2015-04-06 02:06:26 +02:00
|
|
|
m_last_auto_manage = time_now();
|
2012-11-03 04:50:12 +01:00
|
|
|
m_need_auto_manage = false;
|
|
|
|
|
2016-06-03 13:32:48 +02:00
|
|
|
if (m_paused) return;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-05-25 23:46:42 +02:00
|
|
|
// make copies of the lists of torrents that we want to consider for auto
|
|
|
|
// management. We need copies because they will be sorted.
|
|
|
|
std::vector<torrent*> checking
|
|
|
|
= torrent_list(session_interface::torrent_checking_auto_managed);
|
|
|
|
std::vector<torrent*> downloaders
|
|
|
|
= torrent_list(session_interface::torrent_downloading_auto_managed);
|
|
|
|
std::vector<torrent*> seeds
|
|
|
|
= torrent_list(session_interface::torrent_seeding_auto_managed);
|
2007-08-16 14:41:46 +02:00
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
// these counters are set to the number of torrents
|
|
|
|
// of each kind we're allowed to have active
|
2016-03-27 18:09:53 +02:00
|
|
|
int downloading_limit = get_int_setting(settings_pack::active_downloads);
|
|
|
|
int seeding_limit = get_int_setting(settings_pack::active_seeds);
|
|
|
|
int checking_limit = get_int_setting(settings_pack::active_checking);
|
|
|
|
int dht_limit = get_int_setting(settings_pack::active_dht_limit);
|
|
|
|
int tracker_limit = get_int_setting(settings_pack::active_tracker_limit);
|
|
|
|
int lsd_limit = get_int_setting(settings_pack::active_lsd_limit);
|
|
|
|
int hard_limit = get_int_setting(settings_pack::active_limit);
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2015-05-26 20:39:49 +02:00
|
|
|
// if hard_limit is <= 0, all torrents in these lists should be paused.
|
|
|
|
// The order is not relevant
|
|
|
|
if (hard_limit > 0)
|
|
|
|
{
|
|
|
|
// we only need to sort the first n torrents here, where n is the number
|
|
|
|
// of checking torrents we allow. The rest of the list is still used to
|
|
|
|
// make sure the remaining torrents are paused, but their order is not
|
|
|
|
// relevant
|
|
|
|
std::partial_sort(checking.begin(), checking.begin() +
|
|
|
|
(std::min)(checking_limit, int(checking.size())), checking.end()
|
2016-05-25 06:31:52 +02:00
|
|
|
, [](torrent const* lhs, torrent const* rhs)
|
|
|
|
{ return lhs->sequence_number() < rhs->sequence_number(); });
|
2008-04-24 05:28:48 +02:00
|
|
|
|
2015-05-26 20:39:49 +02:00
|
|
|
std::partial_sort(downloaders.begin(), downloaders.begin() +
|
|
|
|
(std::min)(hard_limit, int(downloaders.size())), downloaders.end()
|
2016-05-25 06:31:52 +02:00
|
|
|
, [](torrent const* lhs, torrent const* rhs)
|
|
|
|
{ return lhs->sequence_number() < rhs->sequence_number(); });
|
2008-04-24 05:28:48 +02:00
|
|
|
|
2015-05-26 20:39:49 +02:00
|
|
|
std::partial_sort(seeds.begin(), seeds.begin() +
|
|
|
|
(std::min)(hard_limit, int(seeds.size())), seeds.end()
|
2016-05-25 06:31:52 +02:00
|
|
|
, [this](torrent const* lhs, torrent const* rhs)
|
|
|
|
{ return lhs->seed_rank(m_settings) > rhs->seed_rank(m_settings); });
|
2015-05-26 20:39:49 +02:00
|
|
|
}
|
2008-04-24 05:28:48 +02:00
|
|
|
|
2015-05-26 20:39:49 +02:00
|
|
|
auto_manage_checking_torrents(checking, checking_limit);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
if (settings().get_bool(settings_pack::auto_manage_prefer_seeds))
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
2015-05-26 20:39:49 +02:00
|
|
|
auto_manage_torrents(seeds, dht_limit, tracker_limit, lsd_limit
|
2015-09-19 23:49:01 +02:00
|
|
|
, hard_limit, seeding_limit);
|
2015-05-26 20:39:49 +02:00
|
|
|
auto_manage_torrents(downloaders, dht_limit, tracker_limit, lsd_limit
|
2015-09-19 23:49:01 +02:00
|
|
|
, hard_limit, downloading_limit);
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
2009-05-27 21:27:12 +02:00
|
|
|
else
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
2015-05-26 20:39:49 +02:00
|
|
|
auto_manage_torrents(downloaders, dht_limit, tracker_limit, lsd_limit
|
2015-09-19 23:49:01 +02:00
|
|
|
, hard_limit, downloading_limit);
|
2015-05-26 20:39:49 +02:00
|
|
|
auto_manage_torrents(seeds, dht_limit, tracker_limit, lsd_limit
|
2015-09-19 23:49:01 +02:00
|
|
|
, hard_limit, seeding_limit);
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
|
|
|
}
|
2007-08-16 14:41:46 +02:00
|
|
|
|
2015-07-24 05:48:35 +02:00
|
|
|
namespace {
|
2016-12-22 16:42:33 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2016-07-07 14:34:52 +02:00
|
|
|
uint64_t const priority_undetermined = std::numeric_limits<uint64_t>::max() - 1;
|
2016-12-22 16:42:33 +01:00
|
|
|
#endif
|
2016-07-07 14:34:52 +02:00
|
|
|
|
|
|
|
struct opt_unchoke_candidate
|
2015-07-24 05:48:35 +02:00
|
|
|
{
|
2016-09-01 03:42:18 +02:00
|
|
|
explicit opt_unchoke_candidate(std::shared_ptr<peer_connection> const* tp)
|
2016-07-07 14:34:52 +02:00
|
|
|
: peer(tp)
|
|
|
|
{}
|
|
|
|
|
2016-09-01 03:42:18 +02:00
|
|
|
std::shared_ptr<peer_connection> const* peer;
|
2016-07-07 14:34:52 +02:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
// this is mutable because comparison functors passed to std::partial_sort
|
|
|
|
// are not supposed to modify the elements they are sorting. Here the mutation
|
|
|
|
// being applied is idempotent so it should not pose a problem.
|
|
|
|
mutable uint64_t ext_priority = priority_undetermined;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
struct last_optimistic_unchoke_cmp
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2016-08-17 20:30:24 +02:00
|
|
|
explicit last_optimistic_unchoke_cmp(std::vector<std::shared_ptr<plugin>>& ps)
|
2016-07-07 14:34:52 +02:00
|
|
|
: plugins(ps)
|
|
|
|
{}
|
|
|
|
|
2016-08-17 20:30:24 +02:00
|
|
|
std::vector<std::shared_ptr<plugin>>& plugins;
|
2016-07-07 14:34:52 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
uint64_t get_ext_priority(opt_unchoke_candidate const& peer) const
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
if (peer.ext_priority == priority_undetermined)
|
|
|
|
{
|
|
|
|
peer.ext_priority = std::numeric_limits<uint64_t>::max();
|
|
|
|
for (auto& e : plugins)
|
|
|
|
{
|
|
|
|
uint64_t const priority = e->get_unchoke_priority(peer_connection_handle(*peer.peer));
|
|
|
|
peer.ext_priority = (std::min)(priority, peer.ext_priority);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return peer.ext_priority;
|
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(peer);
|
|
|
|
return std::numeric_limits<uint64_t>::max();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(opt_unchoke_candidate const& l
|
|
|
|
, opt_unchoke_candidate const& r) const
|
|
|
|
{
|
|
|
|
torrent_peer* pil = (*l.peer)->peer_info_struct();
|
|
|
|
torrent_peer* pir = (*r.peer)->peer_info_struct();
|
|
|
|
if (pil->last_optimistically_unchoked
|
|
|
|
!= pir->last_optimistically_unchoked)
|
|
|
|
{
|
|
|
|
return pil->last_optimistically_unchoked
|
|
|
|
< pir->last_optimistically_unchoked;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return get_ext_priority(l) < get_ext_priority(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2015-07-24 05:48:35 +02:00
|
|
|
}
|
|
|
|
|
2010-02-02 19:39:32 +01:00
|
|
|
void session_impl::recalculate_optimistic_unchoke_slots()
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
2016-01-23 19:37:50 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2015-01-04 23:26:26 +01:00
|
|
|
if (m_stats_counters[counters::num_unchoke_slots] == 0) return;
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2016-07-07 14:34:52 +02:00
|
|
|
std::vector<opt_unchoke_candidate> opt_unchoke;
|
2008-10-19 00:35:10 +02:00
|
|
|
|
2016-01-23 19:37:50 +01:00
|
|
|
// collect the currently optimistically unchoked peers here, so we can
|
|
|
|
// choke them when we've found new optimistic unchoke candidates.
|
|
|
|
std::vector<torrent_peer*> prev_opt_unchoke;
|
2008-10-19 00:35:10 +02:00
|
|
|
|
2016-01-23 19:37:50 +01:00
|
|
|
// TODO: 3 it would probably make sense to have a separate list of peers
|
|
|
|
// that are eligible for optimistic unchoke, similar to the torrents
|
|
|
|
// perhaps this could even iterate over the pool allocators of
|
|
|
|
// torrent_peer objects. It could probably be done in a single pass and
|
2016-03-27 18:09:53 +02:00
|
|
|
// collect the n best candidates. maybe just a queue of peers would make
|
|
|
|
// even more sense, just pick the next peer in the queue for unchoking. It
|
|
|
|
// would be O(1).
|
2016-07-07 14:34:52 +02:00
|
|
|
for (auto& i : m_connections)
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
2016-07-07 14:34:52 +02:00
|
|
|
peer_connection* p = i.get();
|
2008-10-14 04:03:54 +02:00
|
|
|
TORRENT_ASSERT(p);
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent_peer* pi = p->peer_info_struct();
|
2008-10-19 00:35:10 +02:00
|
|
|
if (!pi) continue;
|
2012-04-12 02:02:35 +02:00
|
|
|
if (pi->web_seed) continue;
|
2008-10-19 00:35:10 +02:00
|
|
|
|
|
|
|
if (pi->optimistically_unchoked)
|
|
|
|
{
|
2016-01-23 19:37:50 +01:00
|
|
|
prev_opt_unchoke.push_back(pi);
|
2008-10-19 00:35:10 +02:00
|
|
|
}
|
|
|
|
|
2016-01-23 19:37:50 +01:00
|
|
|
torrent* t = p->associated_torrent().lock().get();
|
|
|
|
if (!t) continue;
|
|
|
|
|
|
|
|
// TODO: 3 peers should know whether their torrent is paused or not,
|
|
|
|
// instead of having to ask it over and over again
|
|
|
|
if (t->is_paused()) continue;
|
|
|
|
|
2010-02-02 19:39:32 +01:00
|
|
|
if (!p->is_connecting()
|
2008-10-19 00:35:10 +02:00
|
|
|
&& !p->is_disconnecting()
|
|
|
|
&& p->is_peer_interested()
|
|
|
|
&& t->free_upload_slots()
|
2016-01-23 19:37:50 +01:00
|
|
|
&& (p->is_choked() || pi->optimistically_unchoked)
|
2009-01-28 07:14:21 +01:00
|
|
|
&& !p->ignore_unchoke_slots()
|
2008-10-19 00:35:10 +02:00
|
|
|
&& t->valid_metadata())
|
|
|
|
{
|
2016-07-07 14:34:52 +02:00
|
|
|
opt_unchoke.emplace_back(&i);
|
2008-10-19 00:35:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-02 19:39:32 +01:00
|
|
|
// find the peers that has been waiting the longest to be optimistically
|
|
|
|
// unchoked
|
|
|
|
|
2016-01-23 19:37:50 +01:00
|
|
|
int num_opt_unchoke = m_settings.get_int(settings_pack::num_optimistic_unchoke_slots);
|
2016-12-06 14:24:01 +01:00
|
|
|
int const allowed_unchoke_slots = int(m_stats_counters[counters::num_unchoke_slots]);
|
2016-01-23 19:37:50 +01:00
|
|
|
if (num_opt_unchoke == 0) num_opt_unchoke = (std::max)(1, allowed_unchoke_slots / 5);
|
|
|
|
if (num_opt_unchoke > int(opt_unchoke.size())) num_opt_unchoke =
|
|
|
|
int(opt_unchoke.size());
|
2010-02-02 19:39:32 +01:00
|
|
|
|
2016-01-23 19:37:50 +01:00
|
|
|
// find the n best optimistic unchoke candidates
|
|
|
|
std::partial_sort(opt_unchoke.begin()
|
|
|
|
, opt_unchoke.begin() + num_opt_unchoke
|
2016-07-07 14:34:52 +02:00
|
|
|
, opt_unchoke.end()
|
2014-05-12 09:28:34 +02:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2016-07-07 14:34:52 +02:00
|
|
|
, last_optimistic_unchoke_cmp(m_ses_extensions[plugins_optimistic_unchoke_idx])
|
|
|
|
#else
|
|
|
|
, last_optimistic_unchoke_cmp()
|
2014-05-12 09:28:34 +02:00
|
|
|
#endif
|
2016-07-07 14:34:52 +02:00
|
|
|
);
|
2014-05-12 09:28:34 +02:00
|
|
|
|
2010-02-02 19:39:32 +01:00
|
|
|
// unchoke the first num_opt_unchoke peers in the candidate set
|
|
|
|
// and make sure that the others are choked
|
2016-07-07 14:34:52 +02:00
|
|
|
auto opt_unchoke_end = opt_unchoke.begin()
|
2016-01-23 19:37:50 +01:00
|
|
|
+ num_opt_unchoke;
|
|
|
|
|
2016-07-07 14:34:52 +02:00
|
|
|
for (auto i = opt_unchoke.begin(); i != opt_unchoke_end; ++i)
|
2008-10-19 00:35:10 +02:00
|
|
|
{
|
2016-07-07 14:34:52 +02:00
|
|
|
torrent_peer* pi = (*i->peer)->peer_info_struct();
|
2016-01-31 03:33:47 +01:00
|
|
|
peer_connection* p = static_cast<peer_connection*>(pi->connection);
|
2016-01-23 19:37:50 +01:00
|
|
|
if (pi->optimistically_unchoked)
|
2008-10-19 00:35:10 +02:00
|
|
|
{
|
2016-01-31 03:33:47 +01:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
|
|
|
p->peer_log(peer_log_alert::info, "OPTIMISTIC UNCHOKE"
|
|
|
|
, "already unchoked | session-time: %d"
|
|
|
|
, pi->last_optimistically_unchoked);
|
|
|
|
#endif
|
2016-01-23 19:37:50 +01:00
|
|
|
TORRENT_ASSERT(!pi->connection->is_choked());
|
|
|
|
// remove this peer from prev_opt_unchoke, to prevent us from
|
|
|
|
// choking it later. This peer gets another round of optimistic
|
|
|
|
// unchoke
|
|
|
|
std::vector<torrent_peer*>::iterator existing =
|
|
|
|
std::find(prev_opt_unchoke.begin(), prev_opt_unchoke.end(), pi);
|
|
|
|
TORRENT_ASSERT(existing != prev_opt_unchoke.end());
|
|
|
|
prev_opt_unchoke.erase(existing);
|
2008-10-19 00:35:10 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-01-23 19:37:50 +01:00
|
|
|
TORRENT_ASSERT(p->is_choked());
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> t = p->associated_torrent().lock();
|
2016-01-23 19:37:50 +01:00
|
|
|
bool ret = t->unchoke_peer(*p, true);
|
|
|
|
TORRENT_ASSERT(ret);
|
|
|
|
if (ret)
|
2010-02-02 19:39:32 +01:00
|
|
|
{
|
2016-01-23 19:37:50 +01:00
|
|
|
pi->optimistically_unchoked = true;
|
|
|
|
m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic);
|
2016-06-18 20:01:38 +02:00
|
|
|
pi->last_optimistically_unchoked = std::uint16_t(session_time());
|
2016-01-31 03:33:47 +01:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
|
|
|
p->peer_log(peer_log_alert::info, "OPTIMISTIC UNCHOKE"
|
|
|
|
, "session-time: %d", pi->last_optimistically_unchoked);
|
|
|
|
#endif
|
2015-05-17 04:00:43 +02:00
|
|
|
}
|
2008-10-19 00:35:10 +02:00
|
|
|
}
|
|
|
|
}
|
2016-01-23 19:37:50 +01:00
|
|
|
|
|
|
|
// now, choke all the previous optimistically unchoked peers
|
2016-07-07 14:34:52 +02:00
|
|
|
for (torrent_peer* pi : prev_opt_unchoke)
|
2016-01-23 19:37:50 +01:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(pi->optimistically_unchoked);
|
|
|
|
peer_connection* p = static_cast<peer_connection*>(pi->connection);
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> t = p->associated_torrent().lock();
|
2016-01-23 19:37:50 +01:00
|
|
|
pi->optimistically_unchoked = false;
|
|
|
|
m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic, -1);
|
|
|
|
t->choke_peer(*p);
|
|
|
|
}
|
2016-01-31 03:33:47 +01:00
|
|
|
|
|
|
|
// if we have too many unchoked peers now, we need to trigger the regular
|
|
|
|
// choking logic to choke some
|
|
|
|
if (m_stats_counters[counters::num_unchoke_slots]
|
|
|
|
< m_stats_counters[counters::num_peers_up_unchoked_all])
|
|
|
|
{
|
|
|
|
m_unchoke_time_scaler = 0;
|
|
|
|
}
|
2008-10-19 00:35:10 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::try_connect_more_peers()
|
2012-07-04 22:41:22 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_abort) return;
|
|
|
|
|
|
|
|
if (num_connections() >= m_settings.get_int(settings_pack::connections_limit))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// this is the maximum number of connections we will
|
|
|
|
// attempt this tick
|
|
|
|
int max_connections = m_settings.get_int(settings_pack::connection_speed);
|
|
|
|
|
|
|
|
// zero connections speeds are allowed, we just won't make any connections
|
|
|
|
if (max_connections <= 0) return;
|
2012-07-04 22:41:22 +02:00
|
|
|
|
2014-10-03 22:56:57 +02:00
|
|
|
// this loop will "hand out" connection_speed to the torrents, in a round
|
|
|
|
// robin fashion, so that every torrent is equally likely to connect to a
|
|
|
|
// peer
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2012-07-04 22:41:22 +02:00
|
|
|
// boost connections are connections made by torrent connection
|
|
|
|
// boost, which are done immediately on a tracker response. These
|
|
|
|
// connections needs to be deducted from this second
|
|
|
|
if (m_boost_connections > 0)
|
|
|
|
{
|
|
|
|
if (m_boost_connections > max_connections)
|
|
|
|
{
|
|
|
|
m_boost_connections -= max_connections;
|
|
|
|
max_connections = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
max_connections -= m_boost_connections;
|
|
|
|
m_boost_connections = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// TODO: use a lower limit than m_settings.connections_limit
|
|
|
|
// to allocate the to 10% or so of connection slots for incoming
|
|
|
|
// connections
|
2017-02-02 15:19:17 +01:00
|
|
|
// cap this at max - 1, since we may add one below
|
|
|
|
int const limit = std::min(m_settings.get_int(settings_pack::connections_limit)
|
|
|
|
- num_connections(), std::numeric_limits<int>::max() - 1);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2012-07-04 22:41:22 +02:00
|
|
|
// this logic is here to smooth out the number of new connection
|
|
|
|
// attempts over time, to prevent connecting a large number of
|
|
|
|
// sockets, wait 10 seconds, and then try again
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::smooth_connects) && max_connections > (limit+1) / 2)
|
2017-02-08 16:54:55 +01:00
|
|
|
max_connections = (limit + 1) / 2;
|
2012-07-04 22:41:22 +02:00
|
|
|
|
2017-02-08 16:54:55 +01:00
|
|
|
aux::vector<torrent*>& want_peers_download = m_torrent_lists[torrent_want_peers_download];
|
|
|
|
aux::vector<torrent*>& want_peers_finished = m_torrent_lists[torrent_want_peers_finished];
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// if no torrent want any peers, just return
|
|
|
|
if (want_peers_download.empty() && want_peers_finished.empty()) return;
|
|
|
|
|
|
|
|
// if we don't have any connection attempt quota, return
|
|
|
|
if (max_connections <= 0) return;
|
|
|
|
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
int steps_since_last_connect = 0;
|
|
|
|
int num_torrents = int(want_peers_finished.size() + want_peers_download.size());
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (m_next_downloading_connect_torrent >= int(want_peers_download.size()))
|
|
|
|
m_next_downloading_connect_torrent = 0;
|
|
|
|
|
|
|
|
if (m_next_finished_connect_torrent >= int(want_peers_finished.size()))
|
|
|
|
m_next_finished_connect_torrent = 0;
|
|
|
|
|
2016-06-20 17:32:06 +02:00
|
|
|
torrent* t = nullptr;
|
2014-07-06 21:18:00 +02:00
|
|
|
// there are prioritized torrents. Pick one of those
|
|
|
|
while (!m_prio_torrents.empty())
|
|
|
|
{
|
|
|
|
t = m_prio_torrents.front().first.lock().get();
|
|
|
|
--m_prio_torrents.front().second;
|
|
|
|
if (m_prio_torrents.front().second > 0
|
2016-06-20 17:32:06 +02:00
|
|
|
&& t != nullptr
|
2014-07-06 21:18:00 +02:00
|
|
|
&& t->want_peers()) break;
|
|
|
|
m_prio_torrents.pop_front();
|
2016-06-20 17:32:06 +02:00
|
|
|
t = nullptr;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2016-06-20 17:32:06 +02:00
|
|
|
if (t == nullptr)
|
2012-07-04 22:41:22 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if ((m_download_connect_attempts >= m_settings.get_int(
|
|
|
|
settings_pack::connect_seed_every_n_download)
|
|
|
|
&& want_peers_finished.size())
|
|
|
|
|| want_peers_download.empty())
|
2012-07-04 22:41:22 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
// pick a finished torrent to give a peer to
|
|
|
|
t = want_peers_finished[m_next_finished_connect_torrent];
|
|
|
|
TORRENT_ASSERT(t->want_peers_finished());
|
|
|
|
m_download_connect_attempts = 0;
|
|
|
|
++m_next_finished_connect_torrent;
|
2012-07-04 22:41:22 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// pick a downloading torrent to give a peer to
|
|
|
|
t = want_peers_download[m_next_downloading_connect_torrent];
|
|
|
|
TORRENT_ASSERT(t->want_peers_download());
|
|
|
|
++m_download_connect_attempts;
|
|
|
|
++m_next_downloading_connect_torrent;
|
|
|
|
}
|
|
|
|
}
|
2012-07-04 22:41:22 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(t->want_peers());
|
2016-06-01 07:05:32 +02:00
|
|
|
TORRENT_ASSERT(!t->is_torrent_paused());
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-10-23 04:00:47 +02:00
|
|
|
if (t->try_connect_peer())
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-10-23 04:00:47 +02:00
|
|
|
--max_connections;
|
|
|
|
steps_since_last_connect = 0;
|
|
|
|
m_stats_counters.inc_stats_counter(counters::connection_attempts);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
++steps_since_last_connect;
|
|
|
|
|
|
|
|
// if there are no more free connection slots, abort
|
|
|
|
if (max_connections == 0) return;
|
|
|
|
// there are no more torrents that want peers
|
|
|
|
if (want_peers_download.empty() && want_peers_finished.empty()) break;
|
|
|
|
// if we have gone a whole loop without
|
|
|
|
// handing out a single connection, break
|
|
|
|
if (steps_since_last_connect > num_torrents + 1) break;
|
|
|
|
// maintain the global limit on number of connections
|
|
|
|
if (num_connections() >= m_settings.get_int(settings_pack::connections_limit)) break;
|
2012-07-04 22:41:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::recalculate_unchoke_slots()
|
2008-10-19 00:35:10 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2008-10-19 00:35:10 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2016-03-27 18:09:53 +02:00
|
|
|
time_point const now = aux::time_now();
|
|
|
|
time_duration const unchoke_interval = now - m_last_choke;
|
2009-04-04 09:55:34 +02:00
|
|
|
m_last_choke = now;
|
|
|
|
|
|
|
|
// build list of all peers that are
|
2011-04-30 22:33:35 +02:00
|
|
|
// unchokable.
|
2016-01-31 03:33:47 +01:00
|
|
|
// TODO: 3 there should be a pre-calculated list of all peers eligible for
|
|
|
|
// unchoking
|
2008-10-19 00:35:10 +02:00
|
|
|
std::vector<peer_connection*> peers;
|
|
|
|
for (connection_map::iterator i = m_connections.begin();
|
|
|
|
i != m_connections.end();)
|
|
|
|
{
|
2016-09-01 03:42:18 +02:00
|
|
|
std::shared_ptr<peer_connection> p = *i;
|
2008-10-19 00:35:10 +02:00
|
|
|
TORRENT_ASSERT(p);
|
|
|
|
++i;
|
2016-03-27 18:09:53 +02:00
|
|
|
torrent* const t = p->associated_torrent().lock().get();
|
|
|
|
torrent_peer* const pi = p->peer_info_struct();
|
2010-02-09 04:04:41 +01:00
|
|
|
|
2016-07-09 22:26:26 +02:00
|
|
|
if (p->ignore_unchoke_slots() || t == nullptr || pi == nullptr
|
2014-10-23 00:06:56 +02:00
|
|
|
|| pi->web_seed || t->is_paused())
|
2015-06-19 07:31:06 +02:00
|
|
|
{
|
|
|
|
p->reset_choke_counters();
|
2012-04-12 02:02:35 +02:00
|
|
|
continue;
|
2015-06-19 07:31:06 +02:00
|
|
|
}
|
2009-04-04 09:55:34 +02:00
|
|
|
|
|
|
|
if (!p->is_peer_interested()
|
2008-04-24 05:28:48 +02:00
|
|
|
|| p->is_disconnecting()
|
2014-05-03 19:11:55 +02:00
|
|
|
|| p->is_connecting())
|
2007-08-16 14:41:46 +02:00
|
|
|
{
|
2009-04-04 09:55:34 +02:00
|
|
|
// this peer is not unchokable. So, if it's unchoked
|
|
|
|
// already, make sure to choke it.
|
2015-06-19 07:31:06 +02:00
|
|
|
if (p->is_choked())
|
|
|
|
{
|
|
|
|
p->reset_choke_counters();
|
|
|
|
continue;
|
|
|
|
}
|
2009-04-04 09:55:34 +02:00
|
|
|
if (pi && pi->optimistically_unchoked)
|
2007-08-16 14:41:46 +02:00
|
|
|
{
|
2014-09-22 05:47:43 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic, -1);
|
2009-04-04 09:55:34 +02:00
|
|
|
pi->optimistically_unchoked = false;
|
|
|
|
// force a new optimistic unchoke
|
|
|
|
m_optimistic_unchoke_time_scaler = 0;
|
2014-05-03 19:11:55 +02:00
|
|
|
// TODO: post a message to have this happen
|
|
|
|
// immediately instead of waiting for the next tick
|
2007-08-16 14:41:46 +02:00
|
|
|
}
|
2009-04-04 09:55:34 +02:00
|
|
|
t->choke_peer(*p);
|
2015-06-19 07:31:06 +02:00
|
|
|
p->reset_choke_counters();
|
2009-05-02 05:15:52 +02:00
|
|
|
continue;
|
2007-08-16 14:41:46 +02:00
|
|
|
}
|
2014-10-23 00:06:56 +02:00
|
|
|
|
2008-10-19 00:35:10 +02:00
|
|
|
peers.push_back(p.get());
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
2007-08-16 14:41:46 +02:00
|
|
|
|
2014-10-23 00:06:56 +02:00
|
|
|
// the unchoker wants an estimate of our upload rate capacity
|
|
|
|
// (used by bittyrant)
|
|
|
|
int max_upload_rate = upload_rate_limit(m_global_class);
|
|
|
|
if (m_settings.get_int(settings_pack::choking_algorithm)
|
|
|
|
== settings_pack::bittyrant_choker
|
|
|
|
&& max_upload_rate == 0)
|
2009-04-04 09:55:34 +02:00
|
|
|
{
|
2014-10-23 00:06:56 +02:00
|
|
|
// we don't know at what rate we can upload. If we have a
|
|
|
|
// measurement of the peak, use that + 10kB/s, otherwise
|
|
|
|
// assume 20 kB/s
|
|
|
|
max_upload_rate = (std::max)(20000, m_peak_up_rate + 10000);
|
|
|
|
if (m_alerts.should_post<performance_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<performance_alert>(torrent_handle()
|
|
|
|
, performance_alert::bittyrant_with_no_uplimit);
|
2009-04-04 09:55:34 +02:00
|
|
|
}
|
|
|
|
|
2016-01-31 03:33:47 +01:00
|
|
|
int const allowed_upload_slots = unchoke_sort(peers, max_upload_rate
|
2014-10-23 00:06:56 +02:00
|
|
|
, unchoke_interval, m_settings);
|
2016-03-02 07:39:46 +01:00
|
|
|
|
2015-01-04 22:31:02 +01:00
|
|
|
m_stats_counters.set_value(counters::num_unchoke_slots
|
2015-01-04 23:26:26 +01:00
|
|
|
, allowed_upload_slots);
|
2007-08-17 09:37:08 +02:00
|
|
|
|
2015-06-19 07:31:06 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("RECALCULATE UNCHOKE SLOTS: [ peers: %d "
|
|
|
|
"eligible-peers: %d"
|
|
|
|
" max_upload_rate: %d"
|
|
|
|
" allowed-slots: %d ]"
|
|
|
|
, int(m_connections.size())
|
|
|
|
, int(peers.size())
|
|
|
|
, max_upload_rate
|
|
|
|
, allowed_upload_slots);
|
|
|
|
}
|
2015-06-19 07:31:06 +02:00
|
|
|
#endif
|
|
|
|
|
2016-03-27 18:09:53 +02:00
|
|
|
int const unchoked_counter_optimistic
|
2016-12-06 14:24:01 +01:00
|
|
|
= int(m_stats_counters[counters::num_peers_up_unchoked_optimistic]);
|
2016-03-27 18:09:53 +02:00
|
|
|
int const num_opt_unchoke = (unchoked_counter_optimistic == 0)
|
|
|
|
? (std::max)(1, allowed_upload_slots / 5) : unchoked_counter_optimistic;
|
|
|
|
|
2016-01-31 03:33:47 +01:00
|
|
|
int unchoke_set_size = allowed_upload_slots - num_opt_unchoke;
|
2010-02-09 04:04:41 +01:00
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
// go through all the peers and unchoke the first ones and choke
|
|
|
|
// all the other ones.
|
2016-12-12 02:50:30 +01:00
|
|
|
for (auto p : peers)
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
2016-12-12 02:24:26 +01:00
|
|
|
TORRENT_ASSERT(p != nullptr);
|
2009-04-04 09:55:34 +02:00
|
|
|
TORRENT_ASSERT(!p->ignore_unchoke_slots());
|
2009-05-02 05:15:52 +02:00
|
|
|
|
|
|
|
// this will update the m_uploaded_at_last_unchoke
|
|
|
|
p->reset_choke_counters();
|
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
torrent* t = p->associated_torrent().lock().get();
|
|
|
|
TORRENT_ASSERT(t);
|
2010-02-09 04:04:41 +01:00
|
|
|
|
2014-10-23 00:06:56 +02:00
|
|
|
if (unchoke_set_size > 0)
|
2010-02-09 04:04:41 +01:00
|
|
|
{
|
2009-04-04 09:55:34 +02:00
|
|
|
// yes, this peer should be unchoked
|
2008-04-24 05:28:48 +02:00
|
|
|
if (p->is_choked())
|
|
|
|
{
|
|
|
|
if (!t->unchoke_peer(*p))
|
|
|
|
continue;
|
2007-08-16 14:41:46 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
--unchoke_set_size;
|
2007-08-16 14:41:46 +02:00
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
TORRENT_ASSERT(p->peer_info_struct());
|
|
|
|
if (p->peer_info_struct()->optimistically_unchoked)
|
|
|
|
{
|
|
|
|
// force a new optimistic unchoke
|
2008-10-14 02:56:44 +02:00
|
|
|
// since this one just got promoted into the
|
|
|
|
// proper unchoke set
|
2008-04-24 05:28:48 +02:00
|
|
|
m_optimistic_unchoke_time_scaler = 0;
|
|
|
|
p->peer_info_struct()->optimistically_unchoked = false;
|
2014-09-22 05:47:43 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic, -1);
|
2007-08-16 14:41:46 +02:00
|
|
|
}
|
|
|
|
}
|
2008-04-24 05:28:48 +02:00
|
|
|
else
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
// no, this peer should be choked
|
2008-04-24 05:28:48 +02:00
|
|
|
TORRENT_ASSERT(p->peer_info_struct());
|
|
|
|
if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked)
|
|
|
|
t->choke_peer(*p);
|
|
|
|
}
|
2007-08-16 14:41:46 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2006-12-21 23:20:28 +01:00
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> session_impl::delay_load_torrent(sha1_hash const& info_hash
|
2014-07-06 21:18:00 +02:00
|
|
|
, peer_connection* pc)
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2016-06-18 04:02:21 +02:00
|
|
|
for (auto& e : m_ses_extensions[plugins_all_idx])
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
add_torrent_params p;
|
2016-05-08 00:46:42 +02:00
|
|
|
if (e->on_unknown_torrent(info_hash, peer_connection_handle(pc->self()), p))
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
torrent_handle handle = add_torrent(p, ec);
|
|
|
|
|
|
|
|
return handle.native_handle();
|
|
|
|
}
|
|
|
|
}
|
2015-08-22 00:28:12 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(pc);
|
|
|
|
TORRENT_UNUSED(info_hash);
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
2016-08-31 14:27:36 +02:00
|
|
|
return std::shared_ptr<torrent>();
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
|
|
|
// the return value from this function is valid only as long as the
|
|
|
|
// session is locked!
|
2016-08-31 14:27:36 +02:00
|
|
|
std::weak_ptr<torrent> session_impl::find_torrent(sha1_hash const& info_hash) const
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2010-07-14 06:16:38 +02:00
|
|
|
|
2013-01-02 09:09:21 +01:00
|
|
|
torrent_map::const_iterator i = m_torrents.find(info_hash);
|
2016-07-02 01:46:59 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2016-09-01 21:04:58 +02:00
|
|
|
for (auto const& te : m_torrents)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2016-09-01 21:04:58 +02:00
|
|
|
TORRENT_ASSERT(te.second);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (i != m_torrents.end()) return i->second;
|
2016-08-31 14:27:36 +02:00
|
|
|
return std::weak_ptr<torrent>();
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
void session_impl::insert_torrent(sha1_hash const& ih, std::shared_ptr<torrent> const& t
|
2014-07-06 21:18:00 +02:00
|
|
|
, std::string uuid)
|
|
|
|
{
|
|
|
|
m_torrents.insert(std::make_pair(ih, t));
|
2016-02-20 21:49:49 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
//deprecated in 1.2
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!uuid.empty()) m_uuids.insert(std::make_pair(uuid, t));
|
2016-02-20 21:49:49 +01:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(uuid);
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_queue_position(torrent* me, int p)
|
|
|
|
{
|
2016-10-06 06:08:14 +02:00
|
|
|
// TODO: Maybe the queue position should be maintained as a vector of
|
|
|
|
// torrent pointers. Maybe this logic could be simplified
|
2014-07-06 21:18:00 +02:00
|
|
|
if (p >= 0 && me->queue_position() == -1)
|
|
|
|
{
|
|
|
|
for (session_impl::torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
torrent* t = i->second.get();
|
|
|
|
if (t->queue_position() >= p)
|
|
|
|
{
|
|
|
|
t->set_queue_position_impl(t->queue_position()+1);
|
|
|
|
t->state_updated();
|
|
|
|
}
|
|
|
|
if (t->queue_position() >= p) t->set_queue_position_impl(t->queue_position()+1);
|
|
|
|
}
|
|
|
|
++m_max_queue_pos;
|
|
|
|
me->set_queue_position_impl((std::min)(m_max_queue_pos, p));
|
|
|
|
}
|
|
|
|
else if (p < 0)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(me->queue_position() >= 0);
|
|
|
|
TORRENT_ASSERT(p == -1);
|
|
|
|
for (session_impl::torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
torrent* t = i->second.get();
|
|
|
|
if (t == me) continue;
|
|
|
|
if (t->queue_position() == -1) continue;
|
|
|
|
if (t->queue_position() >= me->queue_position())
|
|
|
|
{
|
|
|
|
t->set_queue_position_impl(t->queue_position()-1);
|
|
|
|
t->state_updated();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
--m_max_queue_pos;
|
|
|
|
me->set_queue_position_impl(p);
|
|
|
|
}
|
|
|
|
else if (p < me->queue_position())
|
|
|
|
{
|
|
|
|
for (session_impl::torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
torrent* t = i->second.get();
|
|
|
|
if (t == me) continue;
|
|
|
|
if (t->queue_position() == -1) continue;
|
2015-05-17 04:00:43 +02:00
|
|
|
if (t->queue_position() >= p
|
2014-07-06 21:18:00 +02:00
|
|
|
&& t->queue_position() < me->queue_position())
|
|
|
|
{
|
|
|
|
t->set_queue_position_impl(t->queue_position()+1);
|
|
|
|
t->state_updated();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
me->set_queue_position_impl(p);
|
|
|
|
}
|
|
|
|
else if (p > me->queue_position())
|
|
|
|
{
|
|
|
|
for (session_impl::torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
torrent* t = i->second.get();
|
|
|
|
int pos = t->queue_position();
|
|
|
|
if (t == me) continue;
|
|
|
|
if (pos == -1) continue;
|
|
|
|
|
|
|
|
if (pos <= p
|
|
|
|
&& pos > me->queue_position()
|
|
|
|
&& pos != -1)
|
|
|
|
{
|
|
|
|
t->set_queue_position_impl(t->queue_position()-1);
|
|
|
|
t->state_updated();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
me->set_queue_position_impl((std::min)(m_max_queue_pos, p));
|
|
|
|
}
|
|
|
|
|
|
|
|
trigger_auto_manage();
|
|
|
|
}
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent const* session_impl::find_encrypted_torrent(sha1_hash const& info_hash
|
|
|
|
, sha1_hash const& xor_mask)
|
|
|
|
{
|
|
|
|
sha1_hash obfuscated = info_hash;
|
|
|
|
obfuscated ^= xor_mask;
|
|
|
|
|
|
|
|
torrent_map::iterator i = m_obfuscated_torrents.find(obfuscated);
|
2016-06-20 17:32:06 +02:00
|
|
|
if (i == m_obfuscated_torrents.end()) return nullptr;
|
2014-07-06 21:18:00 +02:00
|
|
|
return i->second.get();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-02-20 21:49:49 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
//deprecated in 1.2
|
2016-08-31 14:27:36 +02:00
|
|
|
std::weak_ptr<torrent> session_impl::find_torrent(std::string const& uuid) const
|
2011-01-18 04:41:54 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2011-01-18 04:41:54 +01:00
|
|
|
|
2016-10-25 23:27:48 +02:00
|
|
|
auto const i = m_uuids.find(uuid);
|
2011-01-18 04:41:54 +01:00
|
|
|
if (i != m_uuids.end()) return i->second;
|
2016-08-31 14:27:36 +02:00
|
|
|
return std::weak_ptr<torrent>();
|
2011-01-18 04:41:54 +01:00
|
|
|
}
|
2016-02-20 21:49:49 +01:00
|
|
|
#endif
|
2011-01-18 04:41:54 +01:00
|
|
|
|
2015-03-21 01:12:40 +01:00
|
|
|
#ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
|
2016-10-25 23:27:48 +02:00
|
|
|
std::vector<std::shared_ptr<torrent>> session_impl::find_collection(
|
2015-03-21 01:12:40 +01:00
|
|
|
std::string const& collection) const
|
|
|
|
{
|
2016-10-25 23:27:48 +02:00
|
|
|
std::vector<std::shared_ptr<torrent>> ret;
|
|
|
|
for (auto const& tp : m_torrents)
|
2015-03-21 01:12:40 +01:00
|
|
|
{
|
2016-10-25 23:27:48 +02:00
|
|
|
std::shared_ptr<torrent> t = tp.second;
|
2015-03-21 01:12:40 +01:00
|
|
|
if (!t) continue;
|
|
|
|
std::vector<std::string> const& c = t->torrent_file().collections();
|
2016-09-22 01:51:51 +02:00
|
|
|
if (std::find(c.begin(), c.end(), collection) == c.end()) continue;
|
2015-03-21 01:12:40 +01:00
|
|
|
ret.push_back(t);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif //TORRENT_DISABLE_MUTABLE_TORRENTS
|
|
|
|
|
2015-04-21 06:30:34 +02:00
|
|
|
namespace {
|
|
|
|
|
2013-01-02 08:48:09 +01:00
|
|
|
// returns true if lhs is a better disconnect candidate than rhs
|
|
|
|
bool compare_disconnect_torrent(session_impl::torrent_map::value_type const& lhs
|
|
|
|
, session_impl::torrent_map::value_type const& rhs)
|
|
|
|
{
|
|
|
|
// a torrent with 0 peers is never a good disconnect candidate
|
|
|
|
// since there's nothing to disconnect
|
2013-01-02 09:09:21 +01:00
|
|
|
if ((lhs.second->num_peers() == 0) != (rhs.second->num_peers() == 0))
|
2013-01-02 08:48:09 +01:00
|
|
|
return lhs.second->num_peers() != 0;
|
|
|
|
|
|
|
|
// other than that, always prefer to disconnect peers from seeding torrents
|
|
|
|
// in order to not harm downloading ones
|
|
|
|
if (lhs.second->is_seed() != rhs.second->is_seed())
|
|
|
|
return lhs.second->is_seed();
|
|
|
|
|
|
|
|
return lhs.second->num_peers() > rhs.second->num_peers();
|
|
|
|
}
|
|
|
|
|
2015-04-21 06:30:34 +02:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
std::weak_ptr<torrent> session_impl::find_disconnect_candidate_torrent() const
|
2015-05-16 08:33:37 +02:00
|
|
|
{
|
2016-09-20 17:24:24 +02:00
|
|
|
auto const i = std::min_element(m_torrents.begin(), m_torrents.end()
|
2015-12-25 21:59:50 +01:00
|
|
|
, &compare_disconnect_torrent);
|
2013-01-02 08:39:02 +01:00
|
|
|
|
|
|
|
TORRENT_ASSERT(i != m_torrents.end());
|
2016-08-31 14:27:36 +02:00
|
|
|
if (i == m_torrents.end()) return std::shared_ptr<torrent>();
|
2013-01-02 08:39:02 +01:00
|
|
|
|
|
|
|
return i->second;
|
|
|
|
}
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
bool session_impl::should_log() const
|
|
|
|
{
|
|
|
|
return m_alerts.should_post<log_alert>();
|
|
|
|
}
|
|
|
|
|
2015-05-10 07:11:51 +02:00
|
|
|
TORRENT_FORMAT(2,3)
|
2012-10-18 17:14:18 +02:00
|
|
|
void session_impl::session_log(char const* fmt, ...) const
|
|
|
|
{
|
2014-12-09 10:08:26 +01:00
|
|
|
if (!m_alerts.should_post<log_alert>()) return;
|
2012-10-18 17:14:18 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
va_list v;
|
2012-10-18 17:14:18 +02:00
|
|
|
va_start(v, fmt);
|
2016-06-29 00:52:51 +02:00
|
|
|
m_alerts.emplace_alert<log_alert>(fmt, v);
|
2016-09-14 04:46:07 +02:00
|
|
|
va_end(v);
|
2012-10-18 17:14:18 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
|
|
|
|
2011-02-01 10:48:28 +01:00
|
|
|
void session_impl::get_torrent_status(std::vector<torrent_status>* ret
|
2016-08-13 03:31:55 +02:00
|
|
|
, std::function<bool(torrent_status const&)> const& pred
|
2016-10-06 06:08:14 +02:00
|
|
|
, std::uint32_t const flags) const
|
2011-02-01 10:48:28 +01:00
|
|
|
{
|
2016-10-06 06:08:14 +02:00
|
|
|
for (auto const& t : m_torrents)
|
2011-02-01 10:48:28 +01:00
|
|
|
{
|
2016-10-06 06:08:14 +02:00
|
|
|
if (t.second->is_aborted()) continue;
|
2011-02-01 10:48:28 +01:00
|
|
|
torrent_status st;
|
2016-10-06 06:08:14 +02:00
|
|
|
t.second->status(&st, flags);
|
2011-02-01 10:48:28 +01:00
|
|
|
if (!pred(st)) continue;
|
2016-10-06 06:08:14 +02:00
|
|
|
ret->push_back(std::move(st));
|
2011-02-01 10:48:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::refresh_torrent_status(std::vector<torrent_status>* ret
|
2016-10-06 06:08:14 +02:00
|
|
|
, std::uint32_t const flags) const
|
2011-02-01 10:48:28 +01:00
|
|
|
{
|
2016-10-06 06:08:14 +02:00
|
|
|
for (auto& st : *ret)
|
2011-02-01 10:48:28 +01:00
|
|
|
{
|
2016-10-06 06:08:14 +02:00
|
|
|
auto t = st.handle.m_torrent.lock();
|
2011-02-01 10:48:28 +01:00
|
|
|
if (!t) continue;
|
2016-10-06 06:08:14 +02:00
|
|
|
t->status(&st, flags);
|
2011-02-01 10:48:28 +01:00
|
|
|
}
|
|
|
|
}
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2016-09-23 22:51:20 +02:00
|
|
|
void session_impl::post_torrent_updates(std::uint32_t const flags)
|
2011-11-15 03:34:00 +01:00
|
|
|
{
|
2012-01-20 06:40:32 +01:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2012-01-20 06:40:32 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
std::vector<torrent*>& state_updates
|
|
|
|
= m_torrent_lists[aux::session_impl::torrent_state_updates];
|
|
|
|
|
2014-01-19 20:45:50 +01:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2012-10-06 16:31:14 +02:00
|
|
|
m_posting_torrent_updates = true;
|
|
|
|
#endif
|
|
|
|
|
2015-04-03 22:15:48 +02:00
|
|
|
std::vector<torrent_status> status;
|
|
|
|
status.reserve(state_updates.size());
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// TODO: it might be a nice feature here to limit the number of torrents
|
|
|
|
// to send in a single update. By just posting the first n torrents, they
|
|
|
|
// would nicely be round-robined because the torrent lists are always
|
2015-04-03 22:15:48 +02:00
|
|
|
// pushed back. Perhaps the status_update_alert could even have a fixed
|
|
|
|
// array of n entries rather than a vector, to further improve memory
|
|
|
|
// locality.
|
2016-09-23 22:51:20 +02:00
|
|
|
for (auto& t : state_updates)
|
2011-11-15 03:34:00 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(t->m_links[aux::session_impl::torrent_state_updates].in_list());
|
2015-04-03 22:15:48 +02:00
|
|
|
status.push_back(torrent_status());
|
2014-07-06 21:18:00 +02:00
|
|
|
// querying accurate download counters may require
|
|
|
|
// the torrent to be loaded. Loading a torrent, and evicting another
|
|
|
|
// one will lead to calling state_updated(), which screws with
|
|
|
|
// this list while we're working on it, and break things
|
2015-04-03 22:15:48 +02:00
|
|
|
t->status(&status.back(), flags);
|
2012-01-20 06:40:32 +01:00
|
|
|
t->clear_in_state_update();
|
2011-11-15 03:34:00 +01:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
state_updates.clear();
|
2011-11-15 03:34:00 +01:00
|
|
|
|
2014-01-19 20:45:50 +01:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2012-10-06 16:31:14 +02:00
|
|
|
m_posting_torrent_updates = false;
|
|
|
|
#endif
|
|
|
|
|
2016-05-04 15:50:44 +02:00
|
|
|
m_alerts.emplace_alert<state_update_alert>(std::move(status));
|
2011-11-15 03:34:00 +01:00
|
|
|
}
|
2011-02-01 10:48:28 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::post_session_stats()
|
|
|
|
{
|
|
|
|
m_disk_thread.update_stats_counters(m_stats_counters);
|
|
|
|
|
2015-09-17 17:11:46 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (m_dht)
|
|
|
|
m_dht->update_stats_counters(m_stats_counters);
|
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stats_counters.set_value(counters::limiter_up_queue
|
|
|
|
, m_upload_rate.queue_size());
|
|
|
|
m_stats_counters.set_value(counters::limiter_down_queue
|
|
|
|
, m_download_rate.queue_size());
|
|
|
|
|
|
|
|
m_stats_counters.set_value(counters::limiter_up_bytes
|
|
|
|
, m_upload_rate.queued_bytes());
|
|
|
|
m_stats_counters.set_value(counters::limiter_down_bytes
|
|
|
|
, m_download_rate.queued_bytes());
|
|
|
|
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<session_stats_alert>(m_stats_counters);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
2015-01-17 18:02:58 +01:00
|
|
|
void session_impl::post_dht_stats()
|
|
|
|
{
|
2015-04-03 22:15:48 +02:00
|
|
|
std::vector<dht_lookup> requests;
|
|
|
|
std::vector<dht_routing_bucket> table;
|
|
|
|
|
2015-01-17 18:02:58 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (m_dht)
|
2015-04-03 22:15:48 +02:00
|
|
|
m_dht->dht_status(table, requests);
|
2015-01-17 18:02:58 +01:00
|
|
|
#endif
|
|
|
|
|
2016-05-04 15:50:44 +02:00
|
|
|
m_alerts.emplace_alert<dht_stats_alert>(std::move(table), std::move(requests));
|
2015-01-17 18:02:58 +01:00
|
|
|
}
|
|
|
|
|
2011-02-01 10:48:28 +01:00
|
|
|
std::vector<torrent_handle> session_impl::get_torrents() const
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
|
|
|
std::vector<torrent_handle> ret;
|
2006-11-14 01:08:16 +01:00
|
|
|
|
2011-12-21 22:21:19 +01:00
|
|
|
for (torrent_map::const_iterator i
|
2006-10-11 22:57:54 +02:00
|
|
|
= m_torrents.begin(), end(m_torrents.end());
|
|
|
|
i != end; ++i)
|
|
|
|
{
|
|
|
|
if (i->second->is_aborted()) continue;
|
2008-04-09 22:09:36 +02:00
|
|
|
ret.push_back(torrent_handle(i->second));
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
torrent_handle session_impl::find_torrent_handle(sha1_hash const& info_hash)
|
|
|
|
{
|
2008-04-09 22:09:36 +02:00
|
|
|
return torrent_handle(find_torrent(info_hash));
|
2006-11-14 01:08:16 +01:00
|
|
|
}
|
|
|
|
|
2011-10-12 12:27:17 +02:00
|
|
|
void session_impl::async_add_torrent(add_torrent_params* params)
|
|
|
|
{
|
2016-10-19 07:18:05 +02:00
|
|
|
std::unique_ptr<add_torrent_params> holder(params);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (string_begins_no_case("file://", params->url.c_str()) && !params->ti)
|
|
|
|
{
|
2016-11-02 06:01:04 +01:00
|
|
|
if (!m_torrent_load_thread)
|
|
|
|
m_torrent_load_thread.reset(new work_thread_t());
|
|
|
|
|
|
|
|
m_torrent_load_thread->ios.post([params, this]
|
|
|
|
{
|
|
|
|
std::unique_ptr<add_torrent_params> holder2(params);
|
|
|
|
error_code ec;
|
|
|
|
params->ti = std::make_shared<torrent_info>(resolve_file_url(params->url), ec);
|
|
|
|
this->m_io_service.post(std::bind(&session_impl::on_async_load_torrent
|
|
|
|
, this, params, ec));
|
|
|
|
holder2.release();
|
|
|
|
});
|
2016-10-19 07:18:05 +02:00
|
|
|
holder.release();
|
2014-07-06 21:18:00 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-10-12 12:27:17 +02:00
|
|
|
error_code ec;
|
2016-09-23 22:51:20 +02:00
|
|
|
add_torrent(*params, ec);
|
2011-10-12 12:27:17 +02:00
|
|
|
}
|
|
|
|
|
2016-11-02 06:01:04 +01:00
|
|
|
void session_impl::on_async_load_torrent(add_torrent_params* params, error_code ec)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-10-19 07:18:05 +02:00
|
|
|
std::unique_ptr<add_torrent_params> holder(params);
|
2016-09-23 22:51:20 +02:00
|
|
|
|
2016-11-02 06:01:04 +01:00
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
m_alerts.emplace_alert<add_torrent_alert>(torrent_handle()
|
|
|
|
, *params, ec);
|
2016-11-12 07:03:38 +01:00
|
|
|
return;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2017-01-28 20:36:23 +01:00
|
|
|
TORRENT_ASSERT(params->ti->is_valid());
|
|
|
|
TORRENT_ASSERT(params->ti->num_files() > 0);
|
2016-11-12 07:03:38 +01:00
|
|
|
add_torrent(*params, ec);
|
|
|
|
params->url.clear();
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
void session_impl::add_extensions_to_torrent(
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> const& torrent_ptr, void* userdata)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-06-18 04:02:21 +02:00
|
|
|
for (auto& e : m_ses_extensions[plugins_all_idx])
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-08-17 20:30:24 +02:00
|
|
|
std::shared_ptr<torrent_plugin> tp(e->new_torrent(
|
2016-05-08 00:46:42 +02:00
|
|
|
torrent_ptr->get_handle(), userdata));
|
2016-08-13 01:24:03 +02:00
|
|
|
if (tp) torrent_ptr->add_extension(std::move(tp));
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-03-08 10:54:44 +01:00
|
|
|
torrent_handle session_impl::add_torrent(add_torrent_params const& p
|
2009-02-23 02:21:19 +01:00
|
|
|
, error_code& ec)
|
2012-11-08 03:07:10 +01:00
|
|
|
{
|
2016-05-09 05:48:27 +02:00
|
|
|
// params is updated by add_torrent_impl()
|
2012-03-08 10:54:44 +01:00
|
|
|
add_torrent_params params = p;
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> torrent_ptr;
|
2016-10-19 07:18:05 +02:00
|
|
|
|
|
|
|
// in case there's an error, make sure to abort the torrent before leaving
|
|
|
|
// the scope
|
|
|
|
auto abort_torrent = aux::scope_end([&]{ if (torrent_ptr) torrent_ptr->abort(); });
|
|
|
|
|
2016-06-23 19:19:35 +02:00
|
|
|
bool added;
|
2016-09-06 04:25:20 +02:00
|
|
|
std::tie(torrent_ptr, added) = add_torrent_impl(params, ec);
|
2011-01-18 04:41:54 +01:00
|
|
|
|
2016-05-09 05:48:27 +02:00
|
|
|
torrent_handle const handle(torrent_ptr);
|
|
|
|
m_alerts.emplace_alert<add_torrent_alert>(handle, params, ec);
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2016-05-09 05:48:27 +02:00
|
|
|
if (!torrent_ptr) return handle;
|
2008-05-29 05:37:19 +02:00
|
|
|
|
2016-05-09 05:48:27 +02:00
|
|
|
// params.info_hash should have been initialized by add_torrent_impl()
|
2016-07-09 22:26:26 +02:00
|
|
|
TORRENT_ASSERT(params.info_hash != sha1_hash(nullptr));
|
2016-02-08 21:28:13 +01:00
|
|
|
|
2016-06-23 19:19:35 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (params.ti)
|
|
|
|
{
|
2016-08-20 17:29:31 +02:00
|
|
|
for (auto const& n : params.ti->nodes())
|
|
|
|
add_dht_node_name(n);
|
2016-06-23 19:19:35 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-02-08 21:28:13 +01:00
|
|
|
if (m_alerts.should_post<torrent_added_alert>())
|
2016-05-09 05:48:27 +02:00
|
|
|
m_alerts.emplace_alert<torrent_added_alert>(handle);
|
2016-02-08 21:28:13 +01:00
|
|
|
|
2016-06-23 19:19:35 +02:00
|
|
|
// if this was an existing torrent, we can't start it again, or add
|
|
|
|
// another set of plugins etc. we're done
|
|
|
|
if (!added) return handle;
|
|
|
|
|
2015-11-12 02:43:42 +01:00
|
|
|
torrent_ptr->set_ip_filter(m_ip_filter);
|
2015-06-21 00:17:49 +02:00
|
|
|
torrent_ptr->start(params);
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2016-08-13 01:24:03 +02:00
|
|
|
for (auto& ext : params.extensions)
|
2013-08-02 11:42:51 +02:00
|
|
|
{
|
2016-08-17 20:30:24 +02:00
|
|
|
std::shared_ptr<torrent_plugin> tp(ext(handle, params.userdata));
|
2016-08-13 01:24:03 +02:00
|
|
|
if (tp) torrent_ptr->add_extension(std::move(tp));
|
2013-08-02 11:42:51 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
add_extensions_to_torrent(torrent_ptr, params.userdata);
|
2006-11-14 01:08:16 +01:00
|
|
|
#endif
|
|
|
|
|
2016-07-09 22:26:26 +02:00
|
|
|
sha1_hash next_lsd(nullptr);
|
|
|
|
sha1_hash next_dht(nullptr);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_next_lsd_torrent != m_torrents.end())
|
|
|
|
next_lsd = m_next_lsd_torrent->first;
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (m_next_dht_torrent != m_torrents.end())
|
|
|
|
next_dht = m_next_dht_torrent->first;
|
|
|
|
#endif
|
2016-10-19 07:18:05 +02:00
|
|
|
float const load_factor = m_torrents.load_factor();
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-05-09 05:48:27 +02:00
|
|
|
m_torrents.insert(std::make_pair(params.info_hash, torrent_ptr));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2016-07-24 00:57:04 +02:00
|
|
|
static char const req2[4] = {'r', 'e', 'q', '2'};
|
|
|
|
hasher h(req2);
|
|
|
|
h.update(params.info_hash);
|
2014-07-06 21:18:00 +02:00
|
|
|
// this is SHA1("req2" + info-hash), used for
|
|
|
|
// encrypted hand shakes
|
|
|
|
m_obfuscated_torrents.insert(std::make_pair(h.final(), torrent_ptr));
|
|
|
|
#endif
|
|
|
|
|
2016-10-19 07:18:05 +02:00
|
|
|
// once we successfully add the torrent, we can disarm the abort action
|
|
|
|
abort_torrent.disarm();
|
|
|
|
torrent_ptr->added();
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// if this insert made the hash grow, the iterators became invalid
|
|
|
|
// we need to reset them
|
|
|
|
if (m_torrents.load_factor() < load_factor)
|
|
|
|
{
|
|
|
|
// this indicates the hash table re-hashed
|
|
|
|
if (!next_lsd.is_all_zeros())
|
|
|
|
m_next_lsd_torrent = m_torrents.find(next_lsd);
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (!next_dht.is_all_zeros())
|
|
|
|
m_next_dht_torrent = m_torrents.find(next_dht);
|
|
|
|
#endif
|
|
|
|
}
|
2016-02-20 21:49:49 +01:00
|
|
|
|
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
//deprecated in 1.2
|
2011-01-18 04:41:54 +01:00
|
|
|
if (!params.uuid.empty() || !params.url.empty())
|
|
|
|
m_uuids.insert(std::make_pair(params.uuid.empty()
|
|
|
|
? params.url : params.uuid, torrent_ptr));
|
2016-02-20 21:49:49 +01:00
|
|
|
#endif
|
2008-03-08 07:06:31 +01:00
|
|
|
|
2011-12-21 22:21:19 +01:00
|
|
|
// recalculate auto-managed torrents sooner (or put it off)
|
|
|
|
// if another torrent will be added within one second from now
|
|
|
|
// we want to put it off again anyway. So that while we're adding
|
|
|
|
// a boat load of torrents, we postpone the recalculation until
|
|
|
|
// we're done adding them all (since it's kind of an expensive operation)
|
|
|
|
if (params.flags & add_torrent_params::flag_auto_managed)
|
2015-05-27 22:21:50 +02:00
|
|
|
{
|
|
|
|
const int max_downloading = settings().get_int(settings_pack::active_downloads);
|
|
|
|
const int max_seeds = settings().get_int(settings_pack::active_seeds);
|
|
|
|
const int max_active = settings().get_int(settings_pack::active_limit);
|
|
|
|
|
|
|
|
const int num_downloading
|
|
|
|
= int(torrent_list(session_interface::torrent_downloading_auto_managed).size());
|
|
|
|
const int num_seeds
|
|
|
|
= int(torrent_list(session_interface::torrent_seeding_auto_managed).size());
|
|
|
|
const int num_active = num_downloading + num_seeds;
|
|
|
|
|
|
|
|
// there's no point in triggering the auto manage logic early if we
|
|
|
|
// don't have a reason to believe anything will change. It's kind of
|
|
|
|
// expensive.
|
|
|
|
if ((num_downloading < max_downloading
|
|
|
|
|| num_seeds < max_seeds)
|
|
|
|
&& num_active < max_active)
|
|
|
|
{
|
|
|
|
trigger_auto_manage();
|
|
|
|
}
|
|
|
|
}
|
2011-03-04 07:03:45 +01:00
|
|
|
|
2016-05-09 05:48:27 +02:00
|
|
|
return handle;
|
2012-11-08 03:07:10 +01:00
|
|
|
}
|
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
std::pair<std::shared_ptr<torrent>, bool>
|
2016-06-23 19:19:35 +02:00
|
|
|
session_impl::add_torrent_impl(
|
2016-05-09 05:48:27 +02:00
|
|
|
add_torrent_params& params
|
2012-11-08 03:07:10 +01:00
|
|
|
, error_code& ec)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2016-05-09 05:48:27 +02:00
|
|
|
TORRENT_ASSERT(!params.save_path.empty());
|
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
using ptr_t = std::shared_ptr<torrent>;
|
2007-09-22 18:27:29 +02:00
|
|
|
|
2012-03-08 10:54:44 +01:00
|
|
|
if (string_begins_no_case("magnet:", params.url.c_str()))
|
|
|
|
{
|
|
|
|
parse_magnet_uri(params.url, params, ec);
|
2016-06-23 19:19:35 +02:00
|
|
|
if (ec) return std::make_pair(ptr_t(), false);
|
2012-03-08 10:54:44 +01:00
|
|
|
params.url.clear();
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (string_begins_no_case("file://", params.url.c_str()) && !params.ti)
|
|
|
|
{
|
2016-05-17 22:49:11 +02:00
|
|
|
std::string const filename = resolve_file_url(params.url);
|
2016-08-17 23:26:35 +02:00
|
|
|
auto t = std::make_shared<torrent_info>(filename, std::ref(ec), 0);
|
2016-06-23 19:19:35 +02:00
|
|
|
if (ec) return std::make_pair(ptr_t(), false);
|
2014-07-06 21:18:00 +02:00
|
|
|
params.url.clear();
|
|
|
|
params.ti = t;
|
|
|
|
}
|
|
|
|
|
2016-05-14 19:24:29 +02:00
|
|
|
if (params.ti && !params.ti->is_valid())
|
|
|
|
{
|
|
|
|
ec = errors::no_metadata;
|
2016-06-23 19:19:35 +02:00
|
|
|
return std::make_pair(ptr_t(), false);
|
2016-05-14 19:24:29 +02:00
|
|
|
}
|
|
|
|
|
2011-02-21 04:07:37 +01:00
|
|
|
if (params.ti && params.ti->is_valid() && params.ti->num_files() == 0)
|
2008-04-07 03:22:26 +02:00
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::no_files_in_torrent;
|
2016-06-23 19:19:35 +02:00
|
|
|
return std::make_pair(ptr_t(), false);
|
2008-04-07 03:22:26 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2015-05-16 08:33:37 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2016-05-09 05:48:27 +02:00
|
|
|
// add params.dht_nodes to the DHT, if enabled
|
2016-11-15 18:03:11 +01:00
|
|
|
for (auto const& n : params.dht_nodes)
|
|
|
|
add_dht_node_name(n);
|
2012-03-08 10:54:44 +01:00
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
INVARIANT_CHECK;
|
2007-08-21 20:33:28 +02:00
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
if (is_aborted())
|
2008-04-07 03:22:26 +02:00
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::session_is_closing;
|
2016-06-23 19:19:35 +02:00
|
|
|
return std::make_pair(ptr_t(), false);
|
2008-04-07 03:22:26 +02:00
|
|
|
}
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2016-05-09 05:48:27 +02:00
|
|
|
// figure out the info hash of the torrent and make sure params.info_hash
|
|
|
|
// is set correctly
|
|
|
|
if (params.ti) params.info_hash = params.ti->info_hash();
|
2016-05-09 06:30:30 +02:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
//deprecated in 1.2
|
2010-12-30 02:47:30 +01:00
|
|
|
else if (!params.url.empty())
|
2016-05-09 06:30:30 +02:00
|
|
|
{
|
|
|
|
// in order to avoid info-hash collisions, for
|
|
|
|
// torrents where we don't have an info-hash, but
|
|
|
|
// just a URL, set the temporary info-hash to the
|
|
|
|
// hash of the URL. This will be changed once we
|
|
|
|
// have the actual .torrent file
|
|
|
|
params.info_hash = hasher(¶ms.url[0], int(params.url.size())).final();
|
2012-11-08 03:07:10 +01:00
|
|
|
}
|
2016-05-09 06:30:30 +02:00
|
|
|
#endif
|
2012-11-08 03:07:10 +01:00
|
|
|
|
2016-11-15 18:03:11 +01:00
|
|
|
if (params.info_hash.is_all_zeros())
|
2016-05-17 22:49:11 +02:00
|
|
|
{
|
|
|
|
ec = errors::missing_info_hash_in_uri;
|
2016-06-25 23:48:13 +02:00
|
|
|
return std::make_pair(ptr_t(), false);
|
2016-05-17 22:49:11 +02:00
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
// is the torrent already active?
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> torrent_ptr = find_torrent(params.info_hash).lock();
|
2016-05-09 06:30:30 +02:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
//deprecated in 1.2
|
2011-01-18 04:41:54 +01:00
|
|
|
if (!torrent_ptr && !params.uuid.empty()) torrent_ptr = find_torrent(params.uuid).lock();
|
2013-09-15 14:29:09 +02:00
|
|
|
// if we still can't find the torrent, look for it by url
|
|
|
|
if (!torrent_ptr && !params.url.empty())
|
|
|
|
{
|
2016-05-25 06:31:52 +02:00
|
|
|
torrent_map::iterator i = std::find_if(m_torrents.begin(), m_torrents.end()
|
|
|
|
, [¶ms](torrent_map::value_type const& te)
|
|
|
|
{ return te.second->url() == params.url; });
|
2013-09-15 14:29:09 +02:00
|
|
|
if (i != m_torrents.end())
|
|
|
|
torrent_ptr = i->second;
|
|
|
|
}
|
2016-05-09 06:30:30 +02:00
|
|
|
#endif
|
2011-01-18 04:41:54 +01:00
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
if (torrent_ptr)
|
2008-04-07 03:22:26 +02:00
|
|
|
{
|
2011-11-08 06:36:22 +01:00
|
|
|
if ((params.flags & add_torrent_params::flag_duplicate_is_error) == 0)
|
2011-03-23 03:46:22 +01:00
|
|
|
{
|
2016-05-09 06:30:30 +02:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
//deprecated in 1.2
|
2011-03-23 03:46:22 +01:00
|
|
|
if (!params.uuid.empty() && torrent_ptr->uuid().empty())
|
|
|
|
torrent_ptr->set_uuid(params.uuid);
|
|
|
|
if (!params.url.empty() && torrent_ptr->url().empty())
|
|
|
|
torrent_ptr->set_url(params.url);
|
2016-05-09 06:30:30 +02:00
|
|
|
#endif
|
2016-06-23 19:19:35 +02:00
|
|
|
return std::make_pair(torrent_ptr, false);
|
2011-03-23 03:46:22 +01:00
|
|
|
}
|
2008-04-24 05:28:48 +02:00
|
|
|
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::duplicate_torrent;
|
2016-06-23 19:19:35 +02:00
|
|
|
return std::make_pair(ptr_t(), false);
|
2008-04-07 03:22:26 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int queue_pos = ++m_max_queue_pos;
|
2008-05-29 05:37:19 +02:00
|
|
|
|
2016-09-01 03:42:18 +02:00
|
|
|
torrent_ptr = std::make_shared<torrent>(*this
|
2016-06-03 13:32:48 +02:00
|
|
|
, 16 * 1024, queue_pos, m_paused
|
2016-09-01 03:42:18 +02:00
|
|
|
, params, params.info_hash);
|
2011-03-04 07:03:45 +01:00
|
|
|
|
2016-06-23 19:19:35 +02:00
|
|
|
return std::make_pair(torrent_ptr, true);
|
2008-03-08 07:06:31 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_outgoing_interfaces()
|
2008-03-08 07:06:31 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
std::string net_interfaces = m_settings.get_str(settings_pack::outgoing_interfaces);
|
|
|
|
|
|
|
|
// declared in string_util.hpp
|
2016-02-09 00:15:47 +01:00
|
|
|
parse_comma_separated_string(net_interfaces, m_outgoing_interfaces);
|
2008-03-08 07:06:31 +01:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
tcp::endpoint session_impl::bind_outgoing_socket(socket_type& s, address
|
|
|
|
const& remote_address, error_code& ec) const
|
2008-03-08 07:06:31 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
tcp::endpoint bind_ep(address_v4(), 0);
|
|
|
|
if (m_settings.get_int(settings_pack::outgoing_port) > 0)
|
|
|
|
{
|
2016-01-31 09:06:24 +01:00
|
|
|
#ifdef TORRENT_WINDOWS
|
|
|
|
s.set_option(exclusive_address_use(true), ec);
|
|
|
|
#endif
|
2015-06-06 19:49:18 +02:00
|
|
|
s.set_option(tcp::acceptor::reuse_address(true), ec);
|
2014-07-06 21:18:00 +02:00
|
|
|
// ignore errors because the underlying socket may not
|
|
|
|
// be opened yet. This happens when we're routing through
|
|
|
|
// a proxy. In that case, we don't yet know the address of
|
|
|
|
// the proxy server, and more importantly, we don't know
|
|
|
|
// the address family of its address. This means we can't
|
|
|
|
// open the socket yet. The socks abstraction layer defers
|
|
|
|
// opening it.
|
|
|
|
ec.clear();
|
2016-11-25 17:17:25 +01:00
|
|
|
bind_ep.port(std::uint16_t(next_port()));
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2008-11-19 01:46:48 +01:00
|
|
|
|
2016-02-09 00:15:47 +01:00
|
|
|
if (!m_outgoing_interfaces.empty())
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-02-09 00:15:47 +01:00
|
|
|
if (m_interface_index >= m_outgoing_interfaces.size()) m_interface_index = 0;
|
|
|
|
std::string const& ifname = m_outgoing_interfaces[m_interface_index++];
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
if (ec) return bind_ep;
|
|
|
|
|
2016-02-09 00:11:00 +01:00
|
|
|
bind_ep.address(bind_socket_to_device(m_io_service, s
|
2016-02-01 01:40:31 +01:00
|
|
|
, remote_address.is_v4()
|
|
|
|
? boost::asio::ip::tcp::v4()
|
|
|
|
: boost::asio::ip::tcp::v6()
|
2014-07-06 21:18:00 +02:00
|
|
|
, ifname.c_str(), bind_ep.port(), ec));
|
|
|
|
return bind_ep;
|
|
|
|
}
|
2010-01-17 22:42:14 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// if we're not binding to a specific interface, bind
|
|
|
|
// to the same protocol family as the target endpoint
|
|
|
|
if (is_any(bind_ep.address()))
|
2008-06-12 23:22:24 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
if (remote_address.is_v6())
|
|
|
|
bind_ep.address(address_v6::any());
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
bind_ep.address(address_v4::any());
|
2008-06-12 23:22:24 +02:00
|
|
|
}
|
2009-02-03 18:35:41 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
s.bind(bind_ep, ec);
|
|
|
|
return bind_ep;
|
|
|
|
}
|
|
|
|
|
|
|
|
// verify that the given local address satisfies the requirements of
|
|
|
|
// the outgoing interfaces. i.e. that one of the allowed outgoing
|
|
|
|
// interfaces has this address. For uTP sockets, which are all backed
|
|
|
|
// by an unconnected udp socket, we won't be able to tell what local
|
|
|
|
// address is used for this peer's packets, in that case, just make
|
|
|
|
// sure one of the allowed interfaces exists and maybe that it's the
|
|
|
|
// default route. For systems that have SO_BINDTODEVICE, it should be
|
|
|
|
// enough to just know that one of the devices exist
|
|
|
|
bool session_impl::verify_bound_address(address const& addr, bool utp
|
|
|
|
, error_code& ec)
|
|
|
|
{
|
2015-05-19 06:59:31 +02:00
|
|
|
TORRENT_UNUSED(utp);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// we have specific outgoing interfaces specified. Make sure the
|
|
|
|
// local endpoint for this socket is bound to one of the allowed
|
|
|
|
// interfaces. the list can be a mixture of interfaces and IP
|
2016-02-09 00:15:47 +01:00
|
|
|
// addresses.
|
2017-02-08 16:54:55 +01:00
|
|
|
for (auto const& s : m_outgoing_interfaces)
|
2011-04-28 09:54:57 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
error_code err;
|
2017-02-08 16:54:55 +01:00
|
|
|
address ip = address::from_string(s.c_str(), err);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (err) continue;
|
|
|
|
if (ip == addr) return true;
|
2011-04-28 09:54:57 +02:00
|
|
|
}
|
2010-01-17 22:42:14 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// we didn't find the address as an IP in the interface list. Now,
|
|
|
|
// resolve which device (if any) has this IP address.
|
|
|
|
std::string device = device_for_address(addr, m_io_service, ec);
|
|
|
|
if (ec) return false;
|
|
|
|
|
|
|
|
// if no device was found to have this address, we fail
|
|
|
|
if (device.empty()) return false;
|
|
|
|
|
2017-02-08 16:54:55 +01:00
|
|
|
for (auto const& s : m_outgoing_interfaces)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2017-02-08 16:54:55 +01:00
|
|
|
if (s == device) return true;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2007-10-13 05:33:33 +02:00
|
|
|
void session_impl::remove_torrent(const torrent_handle& h, int options)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2012-06-21 05:51:39 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> tptr = h.m_torrent.lock();
|
2011-06-21 04:02:58 +02:00
|
|
|
if (!tptr) return;
|
|
|
|
|
2016-03-13 08:50:37 +01:00
|
|
|
m_alerts.emplace_alert<torrent_removed_alert>(tptr->get_handle()
|
|
|
|
, tptr->info_hash());
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
remove_torrent_impl(tptr, options);
|
2011-03-23 03:46:22 +01:00
|
|
|
|
|
|
|
tptr->abort();
|
2011-04-02 22:05:44 +02:00
|
|
|
tptr->set_queue_position(-1);
|
2011-03-23 03:46:22 +01:00
|
|
|
}
|
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
void session_impl::remove_torrent_impl(std::shared_ptr<torrent> tptr
|
2016-03-13 08:50:37 +01:00
|
|
|
, int options)
|
2011-03-23 03:46:22 +01:00
|
|
|
{
|
2016-02-20 21:49:49 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
// deprecated in 1.2
|
2011-01-18 04:41:54 +01:00
|
|
|
// remove from uuid list
|
|
|
|
if (!tptr->uuid().empty())
|
|
|
|
{
|
2016-10-25 23:27:48 +02:00
|
|
|
auto const j = m_uuids.find(tptr->uuid());
|
2011-01-18 04:41:54 +01:00
|
|
|
if (j != m_uuids.end()) m_uuids.erase(j);
|
|
|
|
}
|
2016-02-20 21:49:49 +01:00
|
|
|
#endif
|
2011-01-18 04:41:54 +01:00
|
|
|
|
2016-10-25 23:27:48 +02:00
|
|
|
auto i = m_torrents.find(tptr->torrent_file().info_hash());
|
2008-04-09 22:09:36 +02:00
|
|
|
|
2016-02-20 21:49:49 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
// deprecated in 1.2
|
2010-12-30 07:46:28 +01:00
|
|
|
// this torrent might be filed under the URL-hash
|
|
|
|
if (i == m_torrents.end() && !tptr->url().empty())
|
|
|
|
{
|
|
|
|
std::string const& url = tptr->url();
|
2016-07-24 00:57:04 +02:00
|
|
|
i = m_torrents.find(hasher(url).final());
|
2010-12-30 07:46:28 +01:00
|
|
|
}
|
2016-02-20 21:49:49 +01:00
|
|
|
#endif
|
2010-12-30 07:46:28 +01:00
|
|
|
|
2011-02-01 04:25:40 +01:00
|
|
|
if (i == m_torrents.end()) return;
|
|
|
|
|
|
|
|
torrent& t = *i->second;
|
2016-03-13 08:50:37 +01:00
|
|
|
if (options)
|
2013-03-17 01:50:33 +01:00
|
|
|
{
|
2016-03-13 08:50:37 +01:00
|
|
|
if (!t.delete_files(options))
|
2013-03-17 01:50:33 +01:00
|
|
|
{
|
2013-03-17 23:16:57 +01:00
|
|
|
if (m_alerts.should_post<torrent_delete_failed_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<torrent_delete_failed_alert>(t.get_handle()
|
|
|
|
, error_code(), t.torrent_file().info_hash());
|
2013-03-17 01:50:33 +01:00
|
|
|
}
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
tptr->update_gauge();
|
2012-06-21 05:51:39 +02:00
|
|
|
|
2014-01-19 20:45:50 +01:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2011-02-01 04:25:40 +01:00
|
|
|
sha1_hash i_hash = t.torrent_file().info_hash();
|
2010-02-14 02:39:55 +01:00
|
|
|
#endif
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2011-02-01 04:25:40 +01:00
|
|
|
if (i == m_next_dht_torrent)
|
|
|
|
++m_next_dht_torrent;
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2011-02-01 04:25:40 +01:00
|
|
|
if (i == m_next_lsd_torrent)
|
|
|
|
++m_next_lsd_torrent;
|
2010-02-05 09:23:17 +01:00
|
|
|
|
2011-02-01 04:25:40 +01:00
|
|
|
m_torrents.erase(i);
|
2016-10-19 07:18:05 +02:00
|
|
|
tptr->removed();
|
2010-02-05 09:23:17 +01:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2016-07-24 00:57:04 +02:00
|
|
|
static char const req2[4] = {'r', 'e', 'q', '2'};
|
|
|
|
hasher h(req2);
|
|
|
|
h.update(tptr->info_hash());
|
2014-07-06 21:18:00 +02:00
|
|
|
m_obfuscated_torrents.erase(h.final());
|
|
|
|
#endif
|
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2011-02-01 04:25:40 +01:00
|
|
|
if (m_next_dht_torrent == m_torrents.end())
|
|
|
|
m_next_dht_torrent = m_torrents.begin();
|
2010-02-14 02:39:55 +01:00
|
|
|
#endif
|
2011-02-01 04:25:40 +01:00
|
|
|
if (m_next_lsd_torrent == m_torrents.end())
|
|
|
|
m_next_lsd_torrent = m_torrents.begin();
|
2010-02-05 09:23:17 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// this torrent may open up a slot for a queued torrent
|
|
|
|
trigger_auto_manage();
|
|
|
|
|
2011-02-01 04:25:40 +01:00
|
|
|
TORRENT_ASSERT(m_torrents.find(i_hash) == m_torrents.end());
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2016-02-08 08:01:25 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
listen_interface_t set_ssl_flag(listen_interface_t in)
|
|
|
|
{
|
|
|
|
in.ssl = true;
|
|
|
|
return in;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_ssl_listen()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
// this function maps the previous functionality of just setting the ssl
|
|
|
|
// listen port in order to enable the ssl listen sockets, to the new
|
|
|
|
// mechanism where SSL sockets are specified in listen_interfaces.
|
2016-09-20 17:24:24 +02:00
|
|
|
auto current_ifaces = parse_listen_interfaces(
|
|
|
|
m_settings.get_str(settings_pack::listen_interfaces));
|
2016-02-08 08:01:25 +01:00
|
|
|
// these are the current interfaces we have, first remove all the SSL
|
|
|
|
// interfaces
|
|
|
|
current_ifaces.erase(std::remove_if(current_ifaces.begin(), current_ifaces.end()
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&listen_interface_t::ssl, _1)), current_ifaces.end());
|
2016-02-08 08:01:25 +01:00
|
|
|
|
|
|
|
int const ssl_listen_port = m_settings.get_int(settings_pack::ssl_listen);
|
|
|
|
|
|
|
|
// setting a port of 0 means to disable listening on SSL, so just update
|
|
|
|
// the interface list with the new list, and we're done
|
|
|
|
if (ssl_listen_port == 0)
|
|
|
|
{
|
|
|
|
m_settings.set_str(settings_pack::listen_interfaces
|
|
|
|
, print_listen_interfaces(current_ifaces));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<listen_interface_t> new_ifaces;
|
|
|
|
std::transform(current_ifaces.begin(), current_ifaces.end()
|
|
|
|
, std::back_inserter(new_ifaces), &set_ssl_flag);
|
|
|
|
|
|
|
|
current_ifaces.insert(current_ifaces.end(), new_ifaces.begin(), new_ifaces.end());
|
|
|
|
|
|
|
|
m_settings.set_str(settings_pack::listen_interfaces
|
|
|
|
, print_listen_interfaces(current_ifaces));
|
|
|
|
}
|
|
|
|
#endif // TORRENT_NO_DEPRECATE
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_listen_interfaces()
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2016-09-20 17:24:24 +02:00
|
|
|
std::string const net_interfaces = m_settings.get_str(settings_pack::listen_interfaces);
|
|
|
|
m_listen_interfaces = parse_listen_interfaces(net_interfaces);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-20 17:24:24 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log("update listen interfaces: %s", net_interfaces.c_str());
|
|
|
|
session_log("parsed listen interfaces count: %d, ifaces: %s"
|
|
|
|
, int(m_listen_interfaces.size())
|
|
|
|
, print_listen_interfaces(m_listen_interfaces).c_str());
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_privileged_ports()
|
|
|
|
{
|
|
|
|
if (m_settings.get_bool(settings_pack::no_connect_privileged_ports))
|
|
|
|
{
|
|
|
|
m_port_filter.add_rule(0, 1024, port_filter::blocked);
|
|
|
|
|
|
|
|
// Close connections whose endpoint is filtered
|
|
|
|
// by the new ip-filter
|
2016-09-20 17:24:24 +02:00
|
|
|
for (auto const& t : m_torrents)
|
|
|
|
t.second->port_filter_updated();
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
else
|
2011-02-16 07:35:53 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
m_port_filter.add_rule(0, 1024, 0);
|
2011-02-16 07:35:53 +01:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2014-09-24 02:02:00 +02:00
|
|
|
void session_impl::update_auto_sequential()
|
|
|
|
{
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
i->second->update_auto_sequential();
|
|
|
|
}
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2015-01-20 07:26:22 +01:00
|
|
|
void session_impl::update_max_failcount()
|
|
|
|
{
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
i->second->update_max_failcount();
|
|
|
|
}
|
|
|
|
}
|
2014-09-24 02:02:00 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_proxy()
|
|
|
|
{
|
|
|
|
// in case we just set a socks proxy, we might have to
|
|
|
|
// open the socks incoming connection
|
|
|
|
if (!m_socks_listen_socket) open_new_incoming_socks_connection();
|
2016-04-24 21:26:28 +02:00
|
|
|
for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
i->udp_sock->set_proxy_settings(proxy());
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_upnp()
|
|
|
|
{
|
|
|
|
if (m_settings.get_bool(settings_pack::enable_upnp))
|
|
|
|
start_upnp();
|
|
|
|
else
|
|
|
|
stop_upnp();
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_natpmp()
|
|
|
|
{
|
|
|
|
if (m_settings.get_bool(settings_pack::enable_natpmp))
|
|
|
|
start_natpmp();
|
|
|
|
else
|
|
|
|
stop_natpmp();
|
|
|
|
}
|
2007-03-16 22:45:29 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_lsd()
|
|
|
|
{
|
|
|
|
if (m_settings.get_bool(settings_pack::enable_lsd))
|
|
|
|
start_lsd();
|
|
|
|
else
|
|
|
|
stop_lsd();
|
|
|
|
}
|
2007-03-16 22:45:29 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_dht()
|
|
|
|
{
|
2015-05-17 04:00:43 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::enable_dht))
|
|
|
|
start_dht();
|
|
|
|
else
|
|
|
|
stop_dht();
|
2006-11-15 22:39:58 +01:00
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2014-12-31 16:51:45 +01:00
|
|
|
void session_impl::update_peer_fingerprint()
|
|
|
|
{
|
|
|
|
// ---- generate a peer id ----
|
|
|
|
std::string print = m_settings.get_str(settings_pack::peer_fingerprint);
|
|
|
|
if (print.size() > 20) print.resize(20);
|
|
|
|
|
|
|
|
// the client's fingerprint
|
2017-02-08 16:54:55 +01:00
|
|
|
std::copy(print.begin(), print.begin() + int(print.length()), m_peer_id.begin());
|
2014-12-31 16:51:45 +01:00
|
|
|
if (print.length() < 20)
|
|
|
|
{
|
2015-08-09 04:53:11 +02:00
|
|
|
url_random(m_peer_id.data() + print.length(), m_peer_id.data() + 20);
|
2014-12-31 16:51:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-21 18:15:19 +02:00
|
|
|
void session_impl::update_dht_bootstrap_nodes()
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
std::string const& node_list = m_settings.get_str(settings_pack::dht_bootstrap_nodes);
|
2016-09-02 22:42:55 +02:00
|
|
|
std::vector<std::pair<std::string, int>> nodes;
|
2016-08-21 18:15:19 +02:00
|
|
|
parse_comma_separated_string_port(node_list, nodes);
|
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
for (auto const& n : nodes)
|
|
|
|
add_dht_router(n);
|
2016-08-21 18:15:19 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-10-06 00:30:09 +02:00
|
|
|
void session_impl::update_count_slow()
|
|
|
|
{
|
|
|
|
error_code ec;
|
2016-11-02 06:03:12 +01:00
|
|
|
for (auto const& tp : m_torrents)
|
2014-10-06 00:30:09 +02:00
|
|
|
{
|
2016-11-02 06:03:12 +01:00
|
|
|
tp.second->on_inactivity_tick(ec);
|
2014-10-06 00:30:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-18 20:01:38 +02:00
|
|
|
std::uint16_t session_impl::listen_port() const
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2010-04-13 06:30:34 +02:00
|
|
|
// if peer connections are set up to be received over a socks
|
|
|
|
// proxy, and it's the same one as we're using for the tracker
|
|
|
|
// just tell the tracker the socks5 port we're listening on
|
2012-03-17 18:48:22 +01:00
|
|
|
if (m_socks_listen_socket && m_socks_listen_socket->is_open())
|
2016-05-05 23:09:11 +02:00
|
|
|
return m_socks_listen_socket->local_endpoint().port();
|
2010-04-13 06:30:34 +02:00
|
|
|
|
2013-02-19 07:48:53 +01:00
|
|
|
// if not, don't tell the tracker anything if we're in force_proxy
|
2010-04-13 06:30:34 +02:00
|
|
|
// mode. We don't want to leak our listen port since it can
|
2016-11-02 06:03:12 +01:00
|
|
|
// potentially identify us if it is leaked elsewhere
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::force_proxy)) return 0;
|
2007-09-22 18:27:29 +02:00
|
|
|
if (m_listen_sockets.empty()) return 0;
|
2016-11-25 17:17:25 +01:00
|
|
|
return std::uint16_t(m_listen_sockets.front().tcp_external_port);
|
2007-03-15 23:03:56 +01:00
|
|
|
}
|
|
|
|
|
2016-02-08 08:01:25 +01:00
|
|
|
// TODO: 2 this function should be removed and users need to deal with the
|
|
|
|
// more generic case of having multiple ssl ports
|
2016-06-18 20:01:38 +02:00
|
|
|
std::uint16_t session_impl::ssl_listen_port() const
|
2012-01-14 17:04:25 +01:00
|
|
|
{
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
// if peer connections are set up to be received over a socks
|
|
|
|
// proxy, and it's the same one as we're using for the tracker
|
|
|
|
// just tell the tracker the socks5 port we're listening on
|
2014-07-01 09:48:34 +02:00
|
|
|
if (m_socks_listen_socket && m_socks_listen_socket->is_open())
|
2012-01-14 17:04:25 +01:00
|
|
|
return m_socks_listen_port;
|
|
|
|
|
2013-02-19 07:48:53 +01:00
|
|
|
// if not, don't tell the tracker anything if we're in force_proxy
|
2012-01-14 17:04:25 +01:00
|
|
|
// mode. We don't want to leak our listen port since it can
|
2016-11-02 06:03:12 +01:00
|
|
|
// potentially identify us if it is leaked elsewhere
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::force_proxy)) return 0;
|
2016-11-02 06:03:12 +01:00
|
|
|
for (auto const& s : m_listen_sockets)
|
2012-01-14 17:04:25 +01:00
|
|
|
{
|
2016-11-25 17:17:25 +01:00
|
|
|
if (s.ssl) return std::uint16_t(s.tcp_external_port);
|
2012-01-14 17:04:25 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-12 05:51:49 +02:00
|
|
|
void session_impl::announce_lsd(sha1_hash const& ih, int port, bool broadcast)
|
2007-04-04 04:06:07 +02:00
|
|
|
{
|
2007-04-14 17:51:36 +02:00
|
|
|
// use internal listen port for local peers
|
2015-01-06 09:08:49 +01:00
|
|
|
if (m_lsd)
|
2011-09-12 05:51:49 +02:00
|
|
|
m_lsd->announce(ih, port, broadcast);
|
2007-04-04 04:06:07 +02:00
|
|
|
}
|
|
|
|
|
2016-09-16 18:21:41 +02:00
|
|
|
void session_impl::on_lsd_peer(tcp::endpoint const& peer, sha1_hash const& ih)
|
2007-04-04 04:06:07 +02:00
|
|
|
{
|
2014-07-13 06:56:53 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::on_lsd_peer_counter);
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2007-04-04 04:06:07 +02:00
|
|
|
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> t = find_torrent(ih).lock();
|
2007-04-04 04:06:07 +02:00
|
|
|
if (!t) return;
|
2007-07-23 02:38:31 +02:00
|
|
|
// don't add peers from lsd to private torrents
|
2009-08-20 05:19:12 +02:00
|
|
|
if (t->torrent_file().priv() || (t->torrent_file().is_i2p()
|
2014-07-06 21:18:00 +02:00
|
|
|
&& !m_settings.get_bool(settings_pack::allow_i2p_mixed))) return;
|
2007-04-04 04:06:07 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
session_log("added peer from local discovery: %s", print_endpoint(peer).c_str());
|
2007-04-04 04:06:07 +02:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
t->add_peer(peer, peer_info::lsd);
|
|
|
|
t->do_connect_boost();
|
|
|
|
|
2010-07-15 07:56:29 +02:00
|
|
|
if (m_alerts.should_post<lsd_peer_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<lsd_peer_alert>(t->get_handle(), peer);
|
2007-04-04 04:06:07 +02:00
|
|
|
}
|
|
|
|
|
2016-02-07 08:09:19 +01:00
|
|
|
namespace {
|
|
|
|
bool find_tcp_port_mapping(int transport, int mapping, listen_socket_t const& ls)
|
|
|
|
{
|
|
|
|
return ls.tcp_port_mapping[transport] == mapping;
|
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
bool find_udp_port_mapping(int transport, int mapping, listen_socket_t const& ls)
|
|
|
|
{
|
|
|
|
return ls.udp_port_mapping[transport] == mapping;
|
|
|
|
}
|
2016-02-07 08:09:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// transport is 0 for NAT-PMP and 1 for UPnP
|
2010-12-05 21:40:28 +01:00
|
|
|
void session_impl::on_port_mapping(int mapping, address const& ip, int port
|
2016-09-18 16:11:56 +02:00
|
|
|
, portmap_protocol const proto, error_code const& ec
|
2016-09-16 15:53:17 +02:00
|
|
|
, aux::portmap_transport transport)
|
2009-06-12 18:40:38 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2010-07-14 06:16:38 +02:00
|
|
|
|
2016-09-16 15:53:17 +02:00
|
|
|
int map_transport =
|
|
|
|
static_cast<std::underlying_type<aux::portmap_transport>::type>(transport);
|
2009-06-12 18:40:38 +02:00
|
|
|
TORRENT_ASSERT(map_transport >= 0 && map_transport <= 1);
|
2008-10-22 03:12:14 +02:00
|
|
|
|
2016-02-07 08:09:19 +01:00
|
|
|
if (ec && m_alerts.should_post<portmap_error_alert>())
|
|
|
|
{
|
|
|
|
m_alerts.emplace_alert<portmap_error_alert>(mapping
|
|
|
|
, map_transport, ec);
|
|
|
|
}
|
|
|
|
|
|
|
|
// look through our listen sockets to see if this mapping is for one of
|
|
|
|
// them (it could also be a user mapping)
|
|
|
|
|
|
|
|
std::list<listen_socket_t>::iterator ls
|
|
|
|
= std::find_if(m_listen_sockets.begin(), m_listen_sockets.end()
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(find_tcp_port_mapping, map_transport, mapping, _1));
|
2016-02-07 08:09:19 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
bool tcp = true;
|
|
|
|
if (ls == m_listen_sockets.end())
|
|
|
|
{
|
|
|
|
ls = std::find_if(m_listen_sockets.begin(), m_listen_sockets.end()
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(find_udp_port_mapping, map_transport, mapping, _1));
|
2016-04-24 21:26:28 +02:00
|
|
|
tcp = false;
|
|
|
|
}
|
|
|
|
|
2016-02-07 08:09:19 +01:00
|
|
|
if (ls != m_listen_sockets.end())
|
2007-03-15 23:03:56 +01:00
|
|
|
{
|
2013-01-21 02:40:59 +01:00
|
|
|
if (ip != address())
|
|
|
|
{
|
|
|
|
// TODO: 1 report the proper address of the router as the source IP of
|
2016-02-07 08:09:19 +01:00
|
|
|
// this vote of our external address, instead of the empty address
|
2016-12-04 21:58:51 +01:00
|
|
|
ls->external_address.cast_vote(ip, source_router, address());
|
2013-01-21 02:40:59 +01:00
|
|
|
}
|
2010-12-05 21:40:28 +01:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
if (tcp) ls->tcp_external_port = port;
|
|
|
|
else ls->udp_external_port = port;
|
2007-03-15 23:03:56 +01:00
|
|
|
}
|
|
|
|
|
2016-02-07 08:09:19 +01:00
|
|
|
if (!ec && m_alerts.should_post<portmap_alert>())
|
2007-03-15 23:03:56 +01:00
|
|
|
{
|
2016-02-07 08:09:19 +01:00
|
|
|
m_alerts.emplace_alert<portmap_alert>(mapping, port
|
2016-09-18 16:11:56 +02:00
|
|
|
, map_transport, proto == portmap_protocol::udp
|
2016-02-24 05:48:29 +01:00
|
|
|
? portmap_alert::udp : portmap_alert::tcp);
|
2007-03-15 23:03:56 +01:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2015-01-04 22:31:02 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2006-10-11 22:57:54 +02:00
|
|
|
session_status session_impl::status() const
|
|
|
|
{
|
2007-09-22 18:27:29 +02:00
|
|
|
// INVARIANT_CHECK;
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2007-08-21 20:33:28 +02:00
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
session_status s;
|
2008-01-13 12:18:18 +01:00
|
|
|
|
2008-10-19 00:35:10 +02:00
|
|
|
s.optimistic_unchoke_counter = m_optimistic_unchoke_time_scaler;
|
|
|
|
s.unchoke_counter = m_unchoke_time_scaler;
|
2014-07-06 21:18:00 +02:00
|
|
|
s.num_dead_peers = int(m_undead_peers.size());
|
2008-01-13 12:18:18 +01:00
|
|
|
|
2016-12-06 14:24:01 +01:00
|
|
|
s.num_peers = int(m_stats_counters[counters::num_peers_connected]);
|
|
|
|
s.num_unchoked = int(m_stats_counters[counters::num_peers_up_unchoked_all]);
|
|
|
|
s.allowed_upload_slots = int(m_stats_counters[counters::num_unchoke_slots]);
|
2015-01-04 22:31:02 +01:00
|
|
|
|
|
|
|
s.num_torrents
|
2016-12-06 14:24:01 +01:00
|
|
|
= int(m_stats_counters[counters::num_checking_torrents]
|
2015-01-04 22:31:02 +01:00
|
|
|
+ m_stats_counters[counters::num_stopped_torrents]
|
|
|
|
+ m_stats_counters[counters::num_queued_seeding_torrents]
|
|
|
|
+ m_stats_counters[counters::num_queued_download_torrents]
|
|
|
|
+ m_stats_counters[counters::num_upload_only_torrents]
|
|
|
|
+ m_stats_counters[counters::num_downloading_torrents]
|
|
|
|
+ m_stats_counters[counters::num_seeding_torrents]
|
2016-12-06 14:24:01 +01:00
|
|
|
+ m_stats_counters[counters::num_error_torrents]);
|
2015-01-04 22:31:02 +01:00
|
|
|
|
|
|
|
s.num_paused_torrents
|
2016-12-06 14:24:01 +01:00
|
|
|
= int(m_stats_counters[counters::num_stopped_torrents]
|
2015-01-04 22:31:02 +01:00
|
|
|
+ m_stats_counters[counters::num_error_torrents]
|
|
|
|
+ m_stats_counters[counters::num_queued_seeding_torrents]
|
2016-12-06 14:24:01 +01:00
|
|
|
+ m_stats_counters[counters::num_queued_download_torrents]);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
s.total_redundant_bytes = m_stats_counters[counters::recv_redundant_bytes];
|
|
|
|
s.total_failed_bytes = m_stats_counters[counters::recv_failed_bytes];
|
2008-07-11 09:30:04 +02:00
|
|
|
|
2016-12-06 14:24:01 +01:00
|
|
|
s.up_bandwidth_queue = int(m_stats_counters[counters::limiter_up_queue]);
|
|
|
|
s.down_bandwidth_queue = int(m_stats_counters[counters::limiter_down_queue]);
|
2008-01-17 18:40:46 +01:00
|
|
|
|
2016-12-06 14:24:01 +01:00
|
|
|
s.up_bandwidth_bytes_queue = int(m_stats_counters[counters::limiter_up_bytes]);
|
|
|
|
s.down_bandwidth_bytes_queue = int(m_stats_counters[counters::limiter_down_bytes]);
|
2008-12-13 06:12:12 +01:00
|
|
|
|
2016-12-06 14:24:01 +01:00
|
|
|
s.disk_write_queue = int(m_stats_counters[counters::num_peers_down_disk]);
|
|
|
|
s.disk_read_queue = int(m_stats_counters[counters::num_peers_up_disk]);
|
2011-01-30 11:04:15 +01:00
|
|
|
|
2016-04-25 23:22:09 +02:00
|
|
|
s.has_incoming_connections = m_stats_counters[counters::has_incoming_connections] != 0;
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2008-09-20 19:42:25 +02:00
|
|
|
// total
|
2006-10-11 22:57:54 +02:00
|
|
|
s.download_rate = m_stat.download_rate();
|
2008-09-20 19:42:25 +02:00
|
|
|
s.total_upload = m_stat.total_upload();
|
2006-10-11 22:57:54 +02:00
|
|
|
s.upload_rate = m_stat.upload_rate();
|
2008-09-20 19:42:25 +02:00
|
|
|
s.total_download = m_stat.total_download();
|
|
|
|
|
|
|
|
// payload
|
|
|
|
s.payload_download_rate = m_stat.transfer_rate(stat::download_payload);
|
|
|
|
s.total_payload_download = m_stat.total_transfer(stat::download_payload);
|
|
|
|
s.payload_upload_rate = m_stat.transfer_rate(stat::upload_payload);
|
|
|
|
s.total_payload_upload = m_stat.total_transfer(stat::upload_payload);
|
|
|
|
|
|
|
|
// IP-overhead
|
|
|
|
s.ip_overhead_download_rate = m_stat.transfer_rate(stat::download_ip_protocol);
|
2017-01-11 01:53:56 +01:00
|
|
|
s.total_ip_overhead_download = m_stats_counters[counters::recv_ip_overhead_bytes];
|
2008-09-20 19:42:25 +02:00
|
|
|
s.ip_overhead_upload_rate = m_stat.transfer_rate(stat::upload_ip_protocol);
|
2017-01-11 01:53:56 +01:00
|
|
|
s.total_ip_overhead_upload = m_stats_counters[counters::sent_ip_overhead_bytes];
|
2010-02-08 06:43:54 +01:00
|
|
|
|
|
|
|
// tracker
|
2014-10-21 23:24:15 +02:00
|
|
|
s.total_tracker_download = m_stats_counters[counters::recv_tracker_bytes];
|
|
|
|
s.total_tracker_upload = m_stats_counters[counters::sent_tracker_bytes];
|
|
|
|
|
2014-10-21 23:36:45 +02:00
|
|
|
// dht
|
2015-01-17 23:06:30 +01:00
|
|
|
s.total_dht_download = m_stats_counters[counters::dht_bytes_in];
|
|
|
|
s.total_dht_upload = m_stats_counters[counters::dht_bytes_out];
|
2014-10-21 23:36:45 +02:00
|
|
|
|
2014-10-21 23:24:15 +02:00
|
|
|
// deprecated
|
2010-02-08 06:43:54 +01:00
|
|
|
s.tracker_download_rate = 0;
|
|
|
|
s.tracker_upload_rate = 0;
|
2014-10-21 23:36:45 +02:00
|
|
|
s.dht_download_rate = 0;
|
|
|
|
s.dht_upload_rate = 0;
|
2008-09-22 02:15:05 +02:00
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (m_dht)
|
|
|
|
{
|
|
|
|
m_dht->dht_status(s);
|
|
|
|
}
|
|
|
|
else
|
2013-04-09 03:04:43 +02:00
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2006-11-28 19:18:37 +01:00
|
|
|
s.dht_nodes = 0;
|
|
|
|
s.dht_node_cache = 0;
|
|
|
|
s.dht_torrents = 0;
|
2007-05-12 03:52:25 +02:00
|
|
|
s.dht_global_nodes = 0;
|
2010-11-06 08:12:57 +01:00
|
|
|
s.dht_total_allocations = 0;
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2015-01-04 22:31:02 +01:00
|
|
|
s.utp_stats.packet_loss = m_stats_counters[counters::utp_packet_loss];
|
|
|
|
s.utp_stats.timeout = m_stats_counters[counters::utp_timeout];
|
|
|
|
s.utp_stats.packets_in = m_stats_counters[counters::utp_packets_in];
|
|
|
|
s.utp_stats.packets_out = m_stats_counters[counters::utp_packets_out];
|
|
|
|
s.utp_stats.fast_retransmit = m_stats_counters[counters::utp_fast_retransmit];
|
|
|
|
s.utp_stats.packet_resend = m_stats_counters[counters::utp_packet_resend];
|
|
|
|
s.utp_stats.samples_above_target = m_stats_counters[counters::utp_samples_above_target];
|
|
|
|
s.utp_stats.samples_below_target = m_stats_counters[counters::utp_samples_below_target];
|
|
|
|
s.utp_stats.payload_pkts_in = m_stats_counters[counters::utp_payload_pkts_in];
|
|
|
|
s.utp_stats.payload_pkts_out = m_stats_counters[counters::utp_payload_pkts_out];
|
|
|
|
s.utp_stats.invalid_pkts_in = m_stats_counters[counters::utp_invalid_pkts_in];
|
|
|
|
s.utp_stats.redundant_pkts_in = m_stats_counters[counters::utp_redundant_pkts_in];
|
|
|
|
|
2016-12-06 14:24:01 +01:00
|
|
|
s.utp_stats.num_idle = int(m_stats_counters[counters::num_utp_idle]);
|
|
|
|
s.utp_stats.num_syn_sent = int(m_stats_counters[counters::num_utp_syn_sent]);
|
|
|
|
s.utp_stats.num_connected = int(m_stats_counters[counters::num_utp_connected]);
|
|
|
|
s.utp_stats.num_fin_sent = int(m_stats_counters[counters::num_utp_fin_sent]);
|
|
|
|
s.utp_stats.num_close_wait = int(m_stats_counters[counters::num_utp_close_wait]);
|
2010-11-29 02:33:05 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// this loop is potentially expensive. It could be optimized by
|
|
|
|
// simply keeping a global counter
|
2010-10-01 06:07:38 +02:00
|
|
|
int peerlist_size = 0;
|
|
|
|
for (torrent_map::const_iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
peerlist_size += i->second->num_known_peers();
|
2010-10-01 06:07:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
s.peerlist_size = peerlist_size;
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
return s;
|
|
|
|
}
|
2015-01-04 22:31:02 +01:00
|
|
|
#endif // TORRENT_NO_DEPRECATE
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2016-12-31 18:35:10 +01:00
|
|
|
void session_impl::get_cache_info(torrent_handle h, cache_status* ret, int flags) const
|
|
|
|
{
|
|
|
|
storage_index_t st{0};
|
|
|
|
bool whole_session = true;
|
|
|
|
std::shared_ptr<torrent> t = h.m_torrent.lock();
|
|
|
|
if (t)
|
|
|
|
{
|
|
|
|
if (t->has_storage())
|
|
|
|
{
|
|
|
|
st = t->storage();
|
|
|
|
whole_session = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
flags = session::disk_cache_no_pieces;
|
|
|
|
}
|
|
|
|
m_disk_thread.get_cache_info(ret, st
|
|
|
|
, flags & session::disk_cache_no_pieces, whole_session);
|
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
|
2010-03-04 17:42:39 +01:00
|
|
|
void session_impl::start_dht()
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2012-06-25 05:31:11 +02:00
|
|
|
stop_dht();
|
2015-08-18 18:56:05 +02:00
|
|
|
|
|
|
|
// postpone starting the DHT if we're still resolving the DHT router
|
|
|
|
if (m_outstanding_router_lookups > 0) return;
|
|
|
|
|
2016-10-11 04:54:19 +02:00
|
|
|
if (m_abort) return;
|
|
|
|
|
2016-10-04 16:43:34 +02:00
|
|
|
// TODO: refactor, move the storage to dht_tracker
|
2016-06-05 20:07:24 +02:00
|
|
|
m_dht_storage = m_dht_storage_constructor(m_dht_settings);
|
2016-08-29 14:31:23 +02:00
|
|
|
m_dht = std::make_shared<dht::dht_tracker>(
|
2016-09-17 15:42:04 +02:00
|
|
|
static_cast<dht::dht_observer*>(this)
|
2016-08-31 14:27:36 +02:00
|
|
|
, m_io_service
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&session_impl::send_udp_packet, this, false, _1, _2, _3, _4)
|
2016-08-31 14:27:36 +02:00
|
|
|
, m_dht_settings
|
|
|
|
, m_stats_counters
|
2016-06-04 01:44:16 +02:00
|
|
|
, *m_dht_storage
|
2016-09-29 14:25:51 +02:00
|
|
|
, std::move(m_dht_state));
|
2008-09-02 08:37:40 +02:00
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
for (auto const& n : m_dht_router_nodes)
|
2008-09-02 08:37:40 +02:00
|
|
|
{
|
2016-08-31 14:27:36 +02:00
|
|
|
m_dht->add_router_node(n);
|
2008-09-02 08:37:40 +02:00
|
|
|
}
|
|
|
|
|
2016-08-31 14:27:36 +02:00
|
|
|
for (auto const& n : m_dht_nodes)
|
2015-08-18 23:35:27 +02:00
|
|
|
{
|
2016-08-31 14:27:36 +02:00
|
|
|
m_dht->add_node(n);
|
2015-08-18 23:35:27 +02:00
|
|
|
}
|
|
|
|
m_dht_nodes.clear();
|
2016-09-29 14:25:51 +02:00
|
|
|
m_dht_nodes.shrink_to_fit();
|
2015-08-18 23:35:27 +02:00
|
|
|
|
2016-09-29 14:25:51 +02:00
|
|
|
auto cb = [this](
|
|
|
|
std::vector<std::pair<dht::node_entry, std::string>> const&)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<dht_bootstrap_alert>())
|
|
|
|
m_alerts.emplace_alert<dht_bootstrap_alert>();
|
|
|
|
};
|
|
|
|
m_dht->start(cb);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::stop_dht()
|
|
|
|
{
|
2016-06-04 01:44:16 +02:00
|
|
|
if (m_dht)
|
|
|
|
{
|
|
|
|
m_dht->stop();
|
|
|
|
m_dht.reset();
|
|
|
|
}
|
|
|
|
|
2016-06-04 20:04:29 +02:00
|
|
|
m_dht_storage.reset();
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_dht_settings(dht_settings const& settings)
|
|
|
|
{
|
|
|
|
m_dht_settings = settings;
|
|
|
|
}
|
|
|
|
|
2016-09-29 14:25:51 +02:00
|
|
|
void session_impl::set_dht_state(dht::dht_state state)
|
2016-09-17 15:42:04 +02:00
|
|
|
{
|
2016-09-29 14:25:51 +02:00
|
|
|
m_dht_state = std::move(state);
|
2016-09-17 15:42:04 +02:00
|
|
|
}
|
|
|
|
|
2015-09-27 01:00:36 +02:00
|
|
|
void session_impl::set_dht_storage(dht::dht_storage_constructor_type sc)
|
|
|
|
{
|
|
|
|
m_dht_storage_constructor = sc;
|
|
|
|
}
|
|
|
|
|
2010-03-04 17:42:39 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2010-07-14 06:16:38 +02:00
|
|
|
entry session_impl::dht_state() const
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2016-09-17 15:42:04 +02:00
|
|
|
return m_dht ? dht::save_dht_state(m_dht->state()) : entry();
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2016-02-27 04:16:17 +01:00
|
|
|
|
|
|
|
void session_impl::start_dht_deprecated(entry const& startup_state)
|
|
|
|
{
|
|
|
|
m_settings.set_bool(settings_pack::enable_dht, true);
|
2016-09-17 15:42:04 +02:00
|
|
|
std::vector<char> tmp;
|
|
|
|
bencode(std::back_inserter(tmp), startup_state);
|
|
|
|
|
|
|
|
bdecode_node e;
|
|
|
|
error_code ec;
|
|
|
|
if (tmp.empty() || bdecode(&tmp[0], &tmp[0] + tmp.size(), e, ec) != 0)
|
|
|
|
return;
|
2016-09-29 14:25:51 +02:00
|
|
|
m_dht_state = dht::read_dht_state(e);
|
|
|
|
start_dht();
|
2016-02-27 04:16:17 +01:00
|
|
|
}
|
2010-03-04 17:42:39 +01:00
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
void session_impl::add_dht_node_name(std::pair<std::string, int> const& node)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_dht_name_lookup");
|
2015-08-18 23:35:27 +02:00
|
|
|
m_host_resolver.async_resolve(node.first, resolver_interface::abort_on_shutdown
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&session_impl::on_dht_name_lookup
|
2015-08-18 23:35:27 +02:00
|
|
|
, this, _1, _2, node.second));
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::on_dht_name_lookup(error_code const& e
|
|
|
|
, std::vector<address> const& addresses, int port)
|
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
COMPLETE_ASYNC("session_impl::on_dht_name_lookup");
|
2015-08-18 23:35:27 +02:00
|
|
|
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<dht_error_alert>())
|
|
|
|
m_alerts.emplace_alert<dht_error_alert>(
|
|
|
|
dht_error_alert::hostname_lookup, e);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-09 21:02:20 +02:00
|
|
|
for (auto const& addr : addresses)
|
2015-08-18 23:35:27 +02:00
|
|
|
{
|
2016-11-25 17:17:25 +01:00
|
|
|
udp::endpoint ep(addr, std::uint16_t(port));
|
2015-08-18 23:35:27 +02:00
|
|
|
add_dht_node(ep);
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::add_dht_router(std::pair<std::string, int> const& node)
|
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_dht_router_name_lookup");
|
2015-08-18 18:56:05 +02:00
|
|
|
++m_outstanding_router_lookups;
|
2014-12-17 03:44:27 +01:00
|
|
|
m_host_resolver.async_resolve(node.first, resolver_interface::abort_on_shutdown
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&session_impl::on_dht_router_name_lookup
|
2014-07-06 21:18:00 +02:00
|
|
|
, this, _1, _2, node.second));
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2010-02-14 08:46:57 +01:00
|
|
|
void session_impl::on_dht_router_name_lookup(error_code const& e
|
2014-07-06 21:18:00 +02:00
|
|
|
, std::vector<address> const& addresses, int port)
|
2010-02-14 08:46:57 +01:00
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
COMPLETE_ASYNC("session_impl::on_dht_router_name_lookup");
|
2015-08-18 18:56:05 +02:00
|
|
|
--m_outstanding_router_lookups;
|
|
|
|
|
2014-01-20 10:20:47 +01:00
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<dht_error_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<dht_error_alert>(
|
|
|
|
dht_error_alert::hostname_lookup, e);
|
2015-08-18 18:56:05 +02:00
|
|
|
|
|
|
|
if (m_outstanding_router_lookups == 0) update_dht();
|
2014-01-20 10:20:47 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-09-09 21:02:20 +02:00
|
|
|
for (auto const& addr : addresses)
|
2010-11-07 20:18:16 +01:00
|
|
|
{
|
|
|
|
// router nodes should be added before the DHT is started (and bootstrapped)
|
2016-11-25 17:17:25 +01:00
|
|
|
udp::endpoint ep(addr, std::uint16_t(port));
|
2010-11-07 20:18:16 +01:00
|
|
|
if (m_dht) m_dht->add_router_node(ep);
|
|
|
|
m_dht_router_nodes.push_back(ep);
|
|
|
|
}
|
2015-08-18 18:56:05 +02:00
|
|
|
|
|
|
|
if (m_outstanding_router_lookups == 0) update_dht();
|
2010-02-14 08:46:57 +01:00
|
|
|
}
|
2014-02-24 01:31:13 +01:00
|
|
|
|
|
|
|
// callback for dht_immutable_get
|
|
|
|
void session_impl::get_immutable_callback(sha1_hash target
|
|
|
|
, dht::item const& i)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(!i.is_mutable());
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<dht_immutable_item_alert>(target, i.value());
|
2014-02-24 01:31:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::dht_get_immutable_item(sha1_hash const& target)
|
|
|
|
{
|
|
|
|
if (!m_dht) return;
|
2016-05-25 06:31:52 +02:00
|
|
|
m_dht->get_item(target, std::bind(&session_impl::get_immutable_callback
|
2014-02-24 01:31:13 +01:00
|
|
|
, this, target, _1));
|
|
|
|
}
|
|
|
|
|
|
|
|
// callback for dht_mutable_get
|
2016-07-24 00:57:04 +02:00
|
|
|
void session_impl::get_mutable_callback(dht::item const& i
|
|
|
|
, bool const authoritative)
|
2014-02-24 01:31:13 +01:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(i.is_mutable());
|
2016-07-24 00:57:04 +02:00
|
|
|
m_alerts.emplace_alert<dht_mutable_item_alert>(i.pk().bytes
|
|
|
|
, i.sig().bytes, i.seq().value
|
2015-08-08 05:37:36 +02:00
|
|
|
, i.salt(), i.value(), authoritative);
|
2014-02-24 01:31:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// key is a 32-byte binary string, the public key to look up.
|
|
|
|
// the salt is optional
|
2016-07-24 00:57:04 +02:00
|
|
|
// TODO: 3 use public_key here instead of std::array
|
2016-05-01 05:10:47 +02:00
|
|
|
void session_impl::dht_get_mutable_item(std::array<char, 32> key
|
2014-02-24 01:31:13 +01:00
|
|
|
, std::string salt)
|
|
|
|
{
|
|
|
|
if (!m_dht) return;
|
2016-07-24 00:57:04 +02:00
|
|
|
m_dht->get_item(dht::public_key(key.data()), std::bind(&session_impl::get_mutable_callback
|
2015-08-08 05:37:36 +02:00
|
|
|
, this, _1, _2), salt);
|
2014-02-24 01:31:13 +01:00
|
|
|
}
|
|
|
|
|
2015-04-20 02:01:27 +02:00
|
|
|
namespace {
|
|
|
|
|
2015-09-22 20:10:57 +02:00
|
|
|
void on_dht_put_immutable_item(alert_manager& alerts, sha1_hash target, int num)
|
2015-04-20 02:01:27 +02:00
|
|
|
{
|
|
|
|
if (alerts.should_post<dht_put_alert>())
|
2015-09-22 20:10:57 +02:00
|
|
|
alerts.emplace_alert<dht_put_alert>(target, num);
|
2015-04-20 02:01:27 +02:00
|
|
|
}
|
|
|
|
|
2015-11-22 19:00:29 +01:00
|
|
|
void on_dht_put_mutable_item(alert_manager& alerts, dht::item const& i, int num)
|
2015-09-22 20:10:57 +02:00
|
|
|
{
|
2016-07-24 00:57:04 +02:00
|
|
|
dht::signature sig = i.sig();
|
|
|
|
dht::public_key pk = i.pk();
|
|
|
|
dht::sequence_number seq = i.seq();
|
2015-09-22 20:10:57 +02:00
|
|
|
std::string salt = i.salt();
|
|
|
|
|
|
|
|
if (alerts.should_post<dht_put_alert>())
|
2016-07-24 00:57:04 +02:00
|
|
|
{
|
|
|
|
alerts.emplace_alert<dht_put_alert>(pk.bytes, sig.bytes, salt
|
|
|
|
, seq.value, num);
|
|
|
|
}
|
2015-09-22 20:10:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void put_mutable_callback(dht::item& i
|
2016-08-13 03:31:55 +02:00
|
|
|
, std::function<void(entry&, std::array<char, 64>&
|
2016-11-27 14:46:53 +01:00
|
|
|
, std::int64_t&, std::string const&)> cb)
|
2015-04-20 02:01:27 +02:00
|
|
|
{
|
|
|
|
entry value = i.value();
|
2016-07-24 00:57:04 +02:00
|
|
|
dht::signature sig = i.sig();
|
|
|
|
dht::public_key pk = i.pk();
|
|
|
|
dht::sequence_number seq = i.seq();
|
2015-04-20 02:01:27 +02:00
|
|
|
std::string salt = i.salt();
|
2016-07-24 00:57:04 +02:00
|
|
|
cb(value, sig.bytes, seq.value, salt);
|
|
|
|
i.assign(std::move(value), salt, seq, pk, sig);
|
2015-04-20 02:01:27 +02:00
|
|
|
}
|
|
|
|
|
2015-06-25 17:01:36 +02:00
|
|
|
void on_dht_get_peers(alert_manager& alerts, sha1_hash info_hash, std::vector<tcp::endpoint> const& peers)
|
|
|
|
{
|
|
|
|
if (alerts.should_post<dht_get_peers_reply_alert>())
|
|
|
|
alerts.emplace_alert<dht_get_peers_reply_alert>(info_hash, peers);
|
|
|
|
}
|
|
|
|
|
2014-02-17 06:56:49 +01:00
|
|
|
void on_direct_response(alert_manager& alerts, void* userdata, dht::msg const& msg)
|
|
|
|
{
|
2015-08-09 05:29:29 +02:00
|
|
|
if (msg.message.type() == bdecode_node::none_t)
|
|
|
|
alerts.emplace_alert<dht_direct_response_alert>(userdata, msg.addr);
|
|
|
|
else
|
|
|
|
alerts.emplace_alert<dht_direct_response_alert>(userdata, msg.addr, msg.message);
|
2014-02-17 06:56:49 +01:00
|
|
|
}
|
|
|
|
|
2015-04-20 02:01:27 +02:00
|
|
|
} // anonymous namespace
|
2014-02-24 01:31:13 +01:00
|
|
|
|
2015-11-22 19:00:29 +01:00
|
|
|
void session_impl::dht_put_immutable_item(entry const& data, sha1_hash target)
|
2014-02-24 01:31:13 +01:00
|
|
|
{
|
|
|
|
if (!m_dht) return;
|
2016-08-13 03:31:55 +02:00
|
|
|
m_dht->put_item(data, std::bind(&on_dht_put_immutable_item, std::ref(m_alerts)
|
2015-09-22 20:10:57 +02:00
|
|
|
, target, _1));
|
2014-02-24 01:31:13 +01:00
|
|
|
}
|
|
|
|
|
2016-05-01 05:10:47 +02:00
|
|
|
void session_impl::dht_put_mutable_item(std::array<char, 32> key
|
2016-08-13 03:31:55 +02:00
|
|
|
, std::function<void(entry&, std::array<char,64>&
|
2016-11-27 14:46:53 +01:00
|
|
|
, std::int64_t&, std::string const&)> cb
|
2014-02-24 01:31:13 +01:00
|
|
|
, std::string salt)
|
|
|
|
{
|
|
|
|
if (!m_dht) return;
|
2016-07-24 00:57:04 +02:00
|
|
|
m_dht->put_item(dht::public_key(key.data())
|
2016-08-13 03:31:55 +02:00
|
|
|
, std::bind(&on_dht_put_mutable_item, std::ref(m_alerts), _1, _2)
|
2016-07-24 00:57:04 +02:00
|
|
|
, std::bind(&put_mutable_callback, _1, cb), salt);
|
2014-02-24 01:31:13 +01:00
|
|
|
}
|
|
|
|
|
2015-06-25 17:01:36 +02:00
|
|
|
void session_impl::dht_get_peers(sha1_hash const& info_hash)
|
|
|
|
{
|
|
|
|
if (!m_dht) return;
|
2016-08-13 03:31:55 +02:00
|
|
|
m_dht->get_peers(info_hash, std::bind(&on_dht_get_peers, std::ref(m_alerts), info_hash, _1));
|
2015-06-25 17:01:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::dht_announce(sha1_hash const& info_hash, int port, int flags)
|
|
|
|
{
|
|
|
|
if (!m_dht) return;
|
2016-08-13 03:31:55 +02:00
|
|
|
m_dht->announce(info_hash, port, flags, std::bind(&on_dht_get_peers, std::ref(m_alerts), info_hash, _1));
|
2015-06-25 17:01:36 +02:00
|
|
|
}
|
|
|
|
|
2015-08-12 06:49:09 +02:00
|
|
|
void session_impl::dht_direct_request(udp::endpoint ep, entry& e, void* userdata)
|
2014-02-17 06:56:49 +01:00
|
|
|
{
|
|
|
|
if (!m_dht) return;
|
2016-08-13 03:31:55 +02:00
|
|
|
m_dht->direct_request(ep, e, std::bind(&on_direct_response, std::ref(m_alerts), userdata, _1));
|
2014-02-17 06:56:49 +01:00
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::add_obfuscated_hash(sha1_hash const& obfuscated
|
2016-08-31 14:27:36 +02:00
|
|
|
, std::weak_ptr<torrent> const& t)
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
m_obfuscated_torrents.insert(std::make_pair(obfuscated, t.lock()));
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
#endif // !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
bool session_impl::is_listening() const
|
|
|
|
{
|
2007-09-22 18:27:29 +02:00
|
|
|
return !m_listen_sockets.empty();
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
session_impl::~session_impl()
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
// this is not allowed to be the network thread!
|
2015-08-08 03:28:51 +02:00
|
|
|
// TORRENT_ASSERT(is_not_thread());
|
2013-09-29 21:37:57 +02:00
|
|
|
|
2016-10-19 07:18:05 +02:00
|
|
|
// TODO: asserts that no outstanding async operations are still in flight
|
2011-02-11 18:39:22 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
FILE* f = fopen("wakeups.log", "w+");
|
2016-06-20 17:32:06 +02:00
|
|
|
if (f != nullptr)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2015-03-12 05:34:54 +01:00
|
|
|
time_point m = min_time();
|
2016-04-27 00:09:11 +02:00
|
|
|
if (!_wakeups.empty()) m = _wakeups[0].timestamp;
|
2015-03-12 05:34:54 +01:00
|
|
|
time_point prev = m;
|
2016-06-18 20:01:38 +02:00
|
|
|
std::uint64_t prev_csw = 0;
|
2016-04-27 00:09:11 +02:00
|
|
|
if (!_wakeups.empty()) prev_csw = _wakeups[0].context_switches;
|
2016-05-17 15:24:06 +02:00
|
|
|
std::fprintf(f, "abs. time\trel. time\tctx switch\tidle-wakeup\toperation\n");
|
2014-07-06 21:18:00 +02:00
|
|
|
for (int i = 0; i < _wakeups.size(); ++i)
|
|
|
|
{
|
|
|
|
wakeup_t const& w = _wakeups[i];
|
|
|
|
bool idle_wakeup = w.context_switches > prev_csw;
|
2016-05-17 15:24:06 +02:00
|
|
|
std::fprintf(f, "%" PRId64 "\t%" PRId64 "\t%" PRId64 "\t%c\t%s\n"
|
2014-07-06 21:18:00 +02:00
|
|
|
, total_microseconds(w.timestamp - m)
|
|
|
|
, total_microseconds(w.timestamp - prev)
|
|
|
|
, w.context_switches
|
|
|
|
, idle_wakeup ? '*' : '.'
|
|
|
|
, w.operation);
|
|
|
|
prev = w.timestamp;
|
|
|
|
prev_csw = w.context_switches;
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2010-10-09 21:09:38 +02:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
int session_impl::max_connections() const
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
return m_settings.get_int(settings_pack::connections_limit);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int session_impl::max_uploads() const
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
return m_settings.get_int(settings_pack::unchoke_slots_limit);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_local_download_rate_limit(int bytes_per_second)
|
|
|
|
{
|
2016-12-26 17:09:52 +01:00
|
|
|
INVARIANT_CHECK;
|
2015-05-29 07:27:53 +02:00
|
|
|
settings_pack p;
|
|
|
|
p.set_int(settings_pack::local_download_rate_limit, bytes_per_second);
|
|
|
|
apply_settings_pack_impl(p);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_local_upload_rate_limit(int bytes_per_second)
|
|
|
|
{
|
2016-12-26 17:09:52 +01:00
|
|
|
INVARIANT_CHECK;
|
2015-05-29 07:27:53 +02:00
|
|
|
settings_pack p;
|
|
|
|
p.set_int(settings_pack::local_upload_rate_limit, bytes_per_second);
|
|
|
|
apply_settings_pack_impl(p);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
2016-05-22 01:05:42 +02:00
|
|
|
void session_impl::set_download_rate_limit_depr(int bytes_per_second)
|
2010-10-09 21:09:38 +02:00
|
|
|
{
|
2016-12-26 17:09:52 +01:00
|
|
|
INVARIANT_CHECK;
|
2015-05-29 07:27:53 +02:00
|
|
|
settings_pack p;
|
|
|
|
p.set_int(settings_pack::download_rate_limit, bytes_per_second);
|
|
|
|
apply_settings_pack_impl(p);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
2016-05-22 01:05:42 +02:00
|
|
|
void session_impl::set_upload_rate_limit_depr(int bytes_per_second)
|
2010-10-09 21:09:38 +02:00
|
|
|
{
|
2016-12-26 17:09:52 +01:00
|
|
|
INVARIANT_CHECK;
|
2015-05-29 07:27:53 +02:00
|
|
|
settings_pack p;
|
|
|
|
p.set_int(settings_pack::upload_rate_limit, bytes_per_second);
|
|
|
|
apply_settings_pack_impl(p);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_max_connections(int limit)
|
|
|
|
{
|
2016-12-26 17:09:52 +01:00
|
|
|
INVARIANT_CHECK;
|
2015-05-29 07:27:53 +02:00
|
|
|
settings_pack p;
|
|
|
|
p.set_int(settings_pack::connections_limit, limit);
|
|
|
|
apply_settings_pack_impl(p);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
void session_impl::set_max_uploads(int limit)
|
|
|
|
{
|
2016-12-26 17:09:52 +01:00
|
|
|
INVARIANT_CHECK;
|
2015-05-29 07:27:53 +02:00
|
|
|
settings_pack p;
|
|
|
|
p.set_int(settings_pack::unchoke_slots_limit, limit);
|
|
|
|
apply_settings_pack_impl(p);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
2007-08-21 20:33:28 +02:00
|
|
|
|
2010-10-09 21:09:38 +02:00
|
|
|
int session_impl::local_upload_rate_limit() const
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
return upload_rate_limit(m_local_peer_class);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int session_impl::local_download_rate_limit() const
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
return download_rate_limit(m_local_peer_class);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
2016-05-22 01:05:42 +02:00
|
|
|
int session_impl::upload_rate_limit_depr() const
|
2010-10-09 21:09:38 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
return upload_rate_limit(m_global_class);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
2007-08-21 20:33:28 +02:00
|
|
|
|
2016-05-22 01:05:42 +02:00
|
|
|
int session_impl::download_rate_limit_depr() const
|
2010-10-09 21:09:38 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
return download_rate_limit(m_global_class);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
template <typename Socket>
|
|
|
|
void set_tos(Socket& s, int v, error_code& ec)
|
|
|
|
{
|
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
if (s.local_endpoint(ec).address().is_v6())
|
2016-11-25 17:17:25 +01:00
|
|
|
s.set_option(traffic_class(char(v)), ec);
|
2016-04-24 21:26:28 +02:00
|
|
|
else if (!ec)
|
|
|
|
#endif
|
2016-11-25 17:17:25 +01:00
|
|
|
s.set_option(type_of_service(char(v)), ec);
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-08 08:05:00 +01:00
|
|
|
// TODO: 2 this should be factored into the udp socket, so we only have the
|
|
|
|
// code once
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_peer_tos()
|
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
int const tos = m_settings.get_int(settings_pack::peer_tos);
|
2016-09-16 14:21:07 +02:00
|
|
|
for (auto const& l : m_listen_sockets)
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
2017-01-13 06:55:54 +01:00
|
|
|
if (l.sock)
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
set_tos(*l.sock, tos, ec);
|
2014-08-22 09:56:10 +02:00
|
|
|
|
2016-04-24 21:26:28 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2017-01-13 06:55:54 +01:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log(">>> SET_TOS [ tcp (%s %d) tos: %x e: %s ]"
|
|
|
|
, l.sock->local_endpoint().address().to_string().c_str()
|
|
|
|
, l.sock->local_endpoint().port(), tos, ec.message().c_str());
|
|
|
|
}
|
2014-10-06 05:03:01 +02:00
|
|
|
#endif
|
2017-01-13 06:55:54 +01:00
|
|
|
}
|
|
|
|
if (l.udp_sock)
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
set_tos(*l.udp_sock, tos, ec);
|
2014-10-06 05:03:01 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2017-01-13 06:55:54 +01:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log(">>> SET_TOS [ udp (%s %d) tos: %x e: %s ]"
|
|
|
|
, l.udp_sock->local_endpoint().address().to_string().c_str()
|
|
|
|
, l.udp_sock->local_port()
|
|
|
|
, tos, ec.message().c_str());
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
2017-01-13 06:55:54 +01:00
|
|
|
}
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_user_agent()
|
|
|
|
{
|
2016-06-13 23:16:09 +02:00
|
|
|
// replace all occurrences of '\n' with ' '.
|
2014-07-06 21:18:00 +02:00
|
|
|
std::string agent = m_settings.get_str(settings_pack::user_agent);
|
|
|
|
std::string::iterator i = agent.begin();
|
|
|
|
while ((i = std::find(i, agent.end(), '\n'))
|
|
|
|
!= agent.end())
|
|
|
|
*i = ' ';
|
|
|
|
m_settings.set_str(settings_pack::user_agent, agent);
|
|
|
|
}
|
|
|
|
|
2014-10-23 00:06:56 +02:00
|
|
|
void session_impl::update_unchoke_limit()
|
2010-10-09 21:09:38 +02:00
|
|
|
{
|
2016-03-27 18:09:53 +02:00
|
|
|
int const allowed_upload_slots = get_int_setting(settings_pack::unchoke_slots_limit);
|
2011-12-19 06:53:11 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stats_counters.set_value(counters::num_unchoke_slots
|
2015-01-04 23:26:26 +01:00
|
|
|
, allowed_upload_slots);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-10-23 00:06:56 +02:00
|
|
|
if (m_settings.get_int(settings_pack::num_optimistic_unchoke_slots)
|
2015-01-04 23:26:26 +01:00
|
|
|
>= allowed_upload_slots / 2)
|
2010-02-06 08:39:45 +01:00
|
|
|
{
|
|
|
|
if (m_alerts.should_post<performance_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<performance_alert>(torrent_handle()
|
|
|
|
, performance_alert::too_many_optimistic_unchoke_slots);
|
2010-02-06 08:39:45 +01:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_connection_speed()
|
|
|
|
{
|
|
|
|
if (m_settings.get_int(settings_pack::connection_speed) < 0)
|
|
|
|
m_settings.set_int(settings_pack::connection_speed, 200);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_queued_disk_bytes()
|
|
|
|
{
|
2016-11-27 14:46:53 +01:00
|
|
|
int const cache_size = m_settings.get_int(settings_pack::cache_size);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::max_queued_disk_bytes) / 16 / 1024
|
|
|
|
> cache_size / 2
|
|
|
|
&& cache_size > 5
|
|
|
|
&& m_alerts.should_post<performance_alert>())
|
|
|
|
{
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<performance_alert>(torrent_handle()
|
|
|
|
, performance_alert::too_high_disk_queue_limit);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_alert_queue_size()
|
|
|
|
{
|
|
|
|
m_alerts.set_alert_queue_size_limit(m_settings.get_int(settings_pack::alert_queue_size));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool session_impl::preemptive_unchoke() const
|
|
|
|
{
|
2015-01-04 23:26:26 +01:00
|
|
|
return m_stats_counters[counters::num_peers_up_unchoked]
|
|
|
|
< m_stats_counters[counters::num_unchoke_slots]
|
2014-09-22 05:47:43 +02:00
|
|
|
|| m_settings.get_int(settings_pack::unchoke_slots_limit) < 0;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
2016-01-17 21:09:27 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_dht_upload_rate_limit()
|
|
|
|
{
|
2016-01-17 21:09:27 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
m_dht_settings.upload_rate_limit
|
|
|
|
= m_settings.get_int(settings_pack::dht_upload_rate_limit);
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2016-01-17 21:09:27 +01:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
void session_impl::update_disk_threads()
|
|
|
|
{
|
2015-06-14 22:00:04 +02:00
|
|
|
if (m_settings.get_int(settings_pack::aio_threads) < 0)
|
|
|
|
m_settings.set_int(settings_pack::aio_threads, 0);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#if !TORRENT_USE_PREAD && !TORRENT_USE_PREADV
|
|
|
|
// if we don't have pread() nor preadv() there's no way
|
|
|
|
// to perform concurrent file operations on the same file
|
|
|
|
// handle, so we must limit the disk thread to a single one
|
|
|
|
|
|
|
|
if (m_settings.get_int(settings_pack::aio_threads) > 1)
|
|
|
|
m_settings.set_int(settings_pack::aio_threads, 1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_cache_buffer_chunk_size()
|
|
|
|
{
|
|
|
|
if (m_settings.get_int(settings_pack::cache_buffer_chunk_size) <= 0)
|
|
|
|
m_settings.set_int(settings_pack::cache_buffer_chunk_size, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_report_web_seed_downloads()
|
|
|
|
{
|
|
|
|
// if this flag changed, update all web seed connections
|
|
|
|
bool report = m_settings.get_bool(settings_pack::report_web_seed_downloads);
|
|
|
|
for (connection_map::iterator i = m_connections.begin()
|
|
|
|
, end(m_connections.end()); i != end; ++i)
|
|
|
|
{
|
2016-09-24 19:47:17 +02:00
|
|
|
connection_type const type = (*i)->type();
|
|
|
|
if (type == connection_type::url_seed
|
|
|
|
|| type == connection_type::http_seed)
|
2014-07-06 21:18:00 +02:00
|
|
|
(*i)->ignore_stats(!report);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::trigger_auto_manage()
|
|
|
|
{
|
|
|
|
if (m_pending_auto_manage || m_abort) return;
|
|
|
|
|
2015-05-26 22:09:19 +02:00
|
|
|
// we recalculated auto-managed torrents less than a second ago,
|
2015-04-05 21:35:58 +02:00
|
|
|
// put it off one second.
|
2015-04-06 02:06:26 +02:00
|
|
|
if (time_now() - m_last_auto_manage < seconds(1))
|
2015-04-05 21:35:58 +02:00
|
|
|
{
|
|
|
|
m_auto_manage_time_scaler = 0;
|
|
|
|
return;
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
m_pending_auto_manage = true;
|
|
|
|
m_need_auto_manage = true;
|
|
|
|
|
2016-10-06 06:08:14 +02:00
|
|
|
m_io_service.post([this]{ this->wrap(&session_impl::on_trigger_auto_manage); });
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::on_trigger_auto_manage()
|
|
|
|
{
|
2016-06-13 13:47:16 +02:00
|
|
|
TORRENT_ASSERT(m_pending_auto_manage);
|
2015-05-17 04:00:43 +02:00
|
|
|
if (!m_need_auto_manage || m_abort)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
m_pending_auto_manage = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// don't clear m_pending_auto_manage until after we've
|
|
|
|
// recalculated the auto managed torrents. The auto-managed
|
|
|
|
// logic may trigger another auto-managed event otherwise
|
|
|
|
recalculate_auto_managed_torrents();
|
|
|
|
m_pending_auto_manage = false;
|
|
|
|
}
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_socket_buffer_size()
|
|
|
|
{
|
2016-09-16 14:21:07 +02:00
|
|
|
for (auto const& l : m_listen_sockets)
|
2014-10-06 05:03:01 +02:00
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
error_code ec;
|
2016-09-16 14:21:07 +02:00
|
|
|
set_socket_buffer_size(*l.udp_sock, m_settings, ec);
|
2016-04-24 21:26:28 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (ec && should_log())
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
|
|
|
error_code err;
|
|
|
|
session_log("socket buffer size [ udp %s %d]: (%d) %s"
|
2016-09-16 14:21:07 +02:00
|
|
|
, l.udp_sock->local_endpoint().address().to_string(err).c_str()
|
|
|
|
, l.udp_sock->local_port(), ec.value(), ec.message().c_str());
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
ec.clear();
|
2016-09-16 14:21:07 +02:00
|
|
|
set_socket_buffer_size(*l.sock, m_settings, ec);
|
2016-04-24 21:26:28 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (ec && should_log())
|
2016-04-24 21:26:28 +02:00
|
|
|
{
|
|
|
|
error_code err;
|
|
|
|
session_log("socket buffer size [ udp %s %d]: (%d) %s"
|
2016-09-16 14:21:07 +02:00
|
|
|
, l.sock->local_endpoint().address().to_string(err).c_str()
|
|
|
|
, l.sock->local_endpoint().port(), ec.value(), ec.message().c_str());
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
2014-10-06 05:03:01 +02:00
|
|
|
#endif
|
2016-04-24 21:26:28 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_dht_announce_interval()
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (!m_dht)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-06-20 17:32:06 +02:00
|
|
|
session_log("not starting DHT announce timer: m_dht == nullptr");
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-25 23:22:09 +02:00
|
|
|
m_dht_interval_update_torrents = int(m_torrents.size());
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
if (m_abort)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2014-07-06 21:18:00 +02:00
|
|
|
session_log("not starting DHT announce timer: m_abort set");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("session_impl::on_dht_announce");
|
2014-07-06 21:18:00 +02:00
|
|
|
error_code ec;
|
|
|
|
int delay = (std::max)(m_settings.get_int(settings_pack::dht_announce_interval)
|
|
|
|
/ (std::max)(int(m_torrents.size()), 1), 1);
|
|
|
|
m_dht_announce_timer.expires_from_now(seconds(delay), ec);
|
2016-10-06 06:08:14 +02:00
|
|
|
m_dht_announce_timer.async_wait([this](error_code const& e) {
|
|
|
|
this->wrap(&session_impl::on_dht_announce, e); });
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_anonymous_mode()
|
|
|
|
{
|
2016-09-19 00:56:12 +02:00
|
|
|
if (!m_settings.get_bool(settings_pack::anonymous_mode))
|
|
|
|
{
|
|
|
|
if (m_upnp)
|
|
|
|
m_upnp->set_user_agent(m_settings.get_str(settings_pack::user_agent));
|
|
|
|
return;
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-09-19 00:56:12 +02:00
|
|
|
if (m_upnp)
|
|
|
|
m_upnp->set_user_agent("");
|
2014-07-06 21:18:00 +02:00
|
|
|
m_settings.set_str(settings_pack::user_agent, "");
|
2015-08-09 04:53:11 +02:00
|
|
|
url_random(m_peer_id.data(), m_peer_id.data() + 20);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_force_proxy()
|
|
|
|
{
|
2016-04-24 21:26:28 +02:00
|
|
|
for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
i->udp_sock->set_force_proxy(m_settings.get_bool(settings_pack::force_proxy));
|
|
|
|
|
|
|
|
// close the TCP listen sockets
|
|
|
|
if (i->sock)
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
i->sock->close(ec);
|
|
|
|
i->sock.reset();
|
|
|
|
}
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
if (!m_settings.get_bool(settings_pack::force_proxy)) return;
|
|
|
|
|
|
|
|
// enable force_proxy mode. We don't want to accept any incoming
|
|
|
|
// connections, except through a proxy.
|
|
|
|
stop_lsd();
|
|
|
|
stop_upnp();
|
|
|
|
stop_natpmp();
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
stop_dht();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
void session_impl::update_local_download_rate()
|
|
|
|
{
|
|
|
|
if (m_settings.get_int(settings_pack::local_download_rate_limit) < 0)
|
|
|
|
m_settings.set_int(settings_pack::local_download_rate_limit, 0);
|
|
|
|
set_download_rate_limit(m_local_peer_class
|
|
|
|
, m_settings.get_int(settings_pack::local_download_rate_limit));
|
|
|
|
}
|
2010-10-09 21:09:38 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_local_upload_rate()
|
|
|
|
{
|
|
|
|
if (m_settings.get_int(settings_pack::local_upload_rate_limit) < 0)
|
|
|
|
m_settings.set_int(settings_pack::local_upload_rate_limit, 0);
|
|
|
|
set_upload_rate_limit(m_local_peer_class
|
|
|
|
, m_settings.get_int(settings_pack::local_upload_rate_limit));
|
|
|
|
}
|
|
|
|
#endif
|
2010-10-09 21:09:38 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_download_rate()
|
|
|
|
{
|
|
|
|
if (m_settings.get_int(settings_pack::download_rate_limit) < 0)
|
|
|
|
m_settings.set_int(settings_pack::download_rate_limit, 0);
|
|
|
|
set_download_rate_limit(m_global_class
|
|
|
|
, m_settings.get_int(settings_pack::download_rate_limit));
|
|
|
|
}
|
2010-10-09 21:09:38 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_upload_rate()
|
|
|
|
{
|
|
|
|
if (m_settings.get_int(settings_pack::upload_rate_limit) < 0)
|
|
|
|
m_settings.set_int(settings_pack::upload_rate_limit, 0);
|
|
|
|
set_upload_rate_limit(m_global_class
|
|
|
|
, m_settings.get_int(settings_pack::upload_rate_limit));
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_connections_limit()
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2015-12-02 06:45:34 +01:00
|
|
|
int limit = m_settings.get_int(settings_pack::connections_limit);
|
|
|
|
|
2017-02-01 04:59:51 +01:00
|
|
|
if (limit <= 0) limit = max_open_files();
|
2015-12-02 06:45:34 +01:00
|
|
|
|
|
|
|
m_settings.set_int(settings_pack::connections_limit, limit);
|
2010-10-03 12:07:38 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (num_connections() > m_settings.get_int(settings_pack::connections_limit)
|
|
|
|
&& !m_torrents.empty())
|
2010-10-03 12:07:38 +02:00
|
|
|
{
|
|
|
|
// if we have more connections that we're allowed, disconnect
|
|
|
|
// peers from the torrents so that they are all as even as possible
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int to_disconnect = num_connections() - m_settings.get_int(settings_pack::connections_limit);
|
2010-10-03 12:07:38 +02:00
|
|
|
|
|
|
|
int last_average = 0;
|
2017-02-08 16:54:55 +01:00
|
|
|
int average = m_settings.get_int(settings_pack::connections_limit) / int(m_torrents.size());
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2010-10-03 12:07:38 +02:00
|
|
|
// the number of slots that are unused by torrents
|
2017-02-08 16:54:55 +01:00
|
|
|
int extra = m_settings.get_int(settings_pack::connections_limit) % int(m_torrents.size());
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2010-10-03 12:07:38 +02:00
|
|
|
// run 3 iterations of this, then we're probably close enough
|
|
|
|
for (int iter = 0; iter < 4; ++iter)
|
|
|
|
{
|
|
|
|
// the number of torrents that are above average
|
|
|
|
int num_above = 0;
|
2016-09-09 21:02:20 +02:00
|
|
|
for (auto const& t : m_torrents)
|
2010-10-03 12:07:38 +02:00
|
|
|
{
|
2016-09-09 21:02:20 +02:00
|
|
|
int const num = t.second->num_peers();
|
2010-10-03 12:07:38 +02:00
|
|
|
if (num <= last_average) continue;
|
|
|
|
if (num > average) ++num_above;
|
|
|
|
if (num < average) extra += average - num;
|
|
|
|
}
|
|
|
|
|
|
|
|
// distribute extra among the torrents that are above average
|
|
|
|
if (num_above == 0) num_above = 1;
|
|
|
|
last_average = average;
|
|
|
|
average += extra / num_above;
|
|
|
|
if (extra == 0) break;
|
|
|
|
// save the remainder for the next iteration
|
|
|
|
extra = extra % num_above;
|
|
|
|
}
|
|
|
|
|
2016-09-20 17:24:24 +02:00
|
|
|
for (auto const& t : m_torrents)
|
2010-10-03 12:07:38 +02:00
|
|
|
{
|
2016-09-20 17:24:24 +02:00
|
|
|
int const num = t.second->num_peers();
|
2010-10-03 12:07:38 +02:00
|
|
|
if (num <= average) continue;
|
|
|
|
|
|
|
|
// distribute the remainder
|
|
|
|
int my_average = average;
|
|
|
|
if (extra > 0)
|
|
|
|
{
|
|
|
|
++my_average;
|
|
|
|
--extra;
|
|
|
|
}
|
|
|
|
|
2016-09-20 17:24:24 +02:00
|
|
|
int const disconnect = std::min(to_disconnect, num - my_average);
|
2010-10-03 12:07:38 +02:00
|
|
|
to_disconnect -= disconnect;
|
2016-10-08 20:17:51 +02:00
|
|
|
t.second->disconnect_peers(disconnect, errors::too_many_connections);
|
2010-10-03 12:07:38 +02:00
|
|
|
}
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2015-04-03 22:15:48 +02:00
|
|
|
void session_impl::update_alert_mask()
|
|
|
|
{
|
|
|
|
m_alerts.set_alert_mask(m_settings.get_int(settings_pack::alert_mask));
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::pop_alerts(std::vector<alert*>* alerts)
|
|
|
|
{
|
2015-12-06 18:45:20 +01:00
|
|
|
m_alerts.get_all(*alerts);
|
2015-04-03 22:15:48 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
void session_impl::update_rate_limit_utp()
|
|
|
|
{
|
|
|
|
if (m_settings.get_bool(settings_pack::rate_limit_utp))
|
|
|
|
{
|
|
|
|
// allow the global or local peer class to limit uTP peers
|
|
|
|
m_peer_class_type_filter.add(peer_class_type_filter::utp_socket
|
|
|
|
, m_local_peer_class);
|
|
|
|
m_peer_class_type_filter.add(peer_class_type_filter::utp_socket
|
|
|
|
, m_global_class);
|
|
|
|
m_peer_class_type_filter.add(peer_class_type_filter::ssl_utp_socket
|
|
|
|
, m_local_peer_class);
|
|
|
|
m_peer_class_type_filter.add(peer_class_type_filter::ssl_utp_socket
|
|
|
|
, m_global_class);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// don't add the global or local peer class to limit uTP peers
|
|
|
|
m_peer_class_type_filter.remove(peer_class_type_filter::utp_socket
|
|
|
|
, m_local_peer_class);
|
|
|
|
m_peer_class_type_filter.remove(peer_class_type_filter::utp_socket
|
|
|
|
, m_global_class);
|
|
|
|
m_peer_class_type_filter.remove(peer_class_type_filter::ssl_utp_socket
|
|
|
|
, m_local_peer_class);
|
|
|
|
m_peer_class_type_filter.remove(peer_class_type_filter::ssl_utp_socket
|
|
|
|
, m_global_class);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_ignore_rate_limits_on_local_network()
|
|
|
|
{
|
2015-04-03 22:15:48 +02:00
|
|
|
init_peer_class_filter(
|
|
|
|
m_settings.get_bool(settings_pack::ignore_limits_on_local_network));
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
2015-04-03 22:15:48 +02:00
|
|
|
// this function is called on the user's thread
|
|
|
|
// not the network thread
|
|
|
|
void session_impl::pop_alerts()
|
2008-12-15 08:12:08 +01:00
|
|
|
{
|
2015-04-03 22:15:48 +02:00
|
|
|
// if we don't have any alerts in our local cache, we have to ask
|
|
|
|
// the alert_manager for more. It will swap our vector with its and
|
|
|
|
// destruct eny left-over alerts in there.
|
2016-11-21 07:49:56 +01:00
|
|
|
if (m_alert_pointer_pos >= int(m_alert_pointers.size()))
|
2015-04-03 22:15:48 +02:00
|
|
|
{
|
|
|
|
pop_alerts(&m_alert_pointers);
|
|
|
|
m_alert_pointer_pos = 0;
|
|
|
|
}
|
2008-12-15 08:12:08 +01:00
|
|
|
}
|
|
|
|
|
2015-04-03 22:15:48 +02:00
|
|
|
alert const* session_impl::pop_alert()
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2016-11-21 07:49:56 +01:00
|
|
|
if (m_alert_pointer_pos >= int(m_alert_pointers.size()))
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2015-04-03 22:15:48 +02:00
|
|
|
pop_alerts();
|
|
|
|
if (m_alert_pointers.empty())
|
2016-06-20 17:32:06 +02:00
|
|
|
return nullptr;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2015-04-03 22:15:48 +02:00
|
|
|
|
2016-06-20 17:32:06 +02:00
|
|
|
if (m_alert_pointers.empty()) return nullptr;
|
2015-04-03 22:15:48 +02:00
|
|
|
|
|
|
|
// clone here to be backwards compatible, to make the client delete the
|
|
|
|
// alert object
|
|
|
|
return m_alert_pointers[m_alert_pointer_pos++];
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2015-04-03 22:15:48 +02:00
|
|
|
|
|
|
|
#endif
|
2011-03-14 03:59:46 +01:00
|
|
|
|
2015-04-03 22:15:48 +02:00
|
|
|
alert* session_impl::wait_for_alert(time_duration max_wait)
|
2007-11-25 09:18:57 +01:00
|
|
|
{
|
|
|
|
return m_alerts.wait_for_alert(max_wait);
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2011-01-23 19:00:52 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2017-02-08 16:54:55 +01:00
|
|
|
std::size_t session_impl::set_alert_queue_size_limit(std::size_t queue_size_limit_)
|
2008-10-07 07:46:42 +02:00
|
|
|
{
|
2016-04-25 23:22:09 +02:00
|
|
|
m_settings.set_int(settings_pack::alert_queue_size, int(queue_size_limit_));
|
|
|
|
return m_alerts.set_alert_queue_size_limit(int(queue_size_limit_));
|
2008-10-07 07:46:42 +02:00
|
|
|
}
|
2011-01-23 19:00:52 +01:00
|
|
|
#endif
|
2008-10-07 07:46:42 +02:00
|
|
|
|
2007-05-31 02:21:54 +02:00
|
|
|
void session_impl::start_lsd()
|
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-11-23 22:11:31 +01:00
|
|
|
if (m_lsd) return;
|
|
|
|
|
2016-09-16 18:21:41 +02:00
|
|
|
m_lsd = std::make_shared<lsd>(m_io_service, *this);
|
2015-01-17 00:01:14 +01:00
|
|
|
error_code ec;
|
|
|
|
m_lsd->start(ec);
|
|
|
|
if (ec && m_alerts.should_post<lsd_error_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<lsd_error_alert>(ec);
|
2007-05-31 02:21:54 +02:00
|
|
|
}
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
natpmp* session_impl::start_natpmp()
|
2007-05-31 02:21:54 +02:00
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
if (m_natpmp) return m_natpmp.get();
|
|
|
|
|
|
|
|
// the natpmp constructor may fail and call the callbacks
|
|
|
|
// into the session_impl.
|
2016-09-16 18:21:41 +02:00
|
|
|
m_natpmp = std::make_shared<natpmp>(m_io_service, *this);
|
2015-01-06 09:08:49 +01:00
|
|
|
m_natpmp->start();
|
2007-05-31 02:21:54 +02:00
|
|
|
|
2016-09-16 03:13:43 +02:00
|
|
|
for (auto& s : m_listen_sockets)
|
2008-04-13 21:19:22 +02:00
|
|
|
{
|
2016-09-16 03:13:43 +02:00
|
|
|
remap_ports(remap_natpmp, s);
|
2008-04-13 21:19:22 +02:00
|
|
|
}
|
2015-01-06 09:08:49 +01:00
|
|
|
return m_natpmp.get();
|
2007-05-31 02:21:54 +02:00
|
|
|
}
|
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
upnp* session_impl::start_upnp()
|
2007-05-31 02:21:54 +02:00
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
if (m_upnp) return m_upnp.get();
|
|
|
|
|
|
|
|
// the upnp constructor may fail and call the callbacks
|
2016-09-16 18:21:41 +02:00
|
|
|
m_upnp = std::make_shared<upnp>(m_io_service
|
2016-09-19 00:56:12 +02:00
|
|
|
, m_settings.get_bool(settings_pack::anonymous_mode)
|
|
|
|
? "" : m_settings.get_str(settings_pack::user_agent)
|
2016-09-16 15:53:17 +02:00
|
|
|
, *this
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_settings.get_bool(settings_pack::upnp_ignore_nonrouters));
|
2015-01-06 09:08:49 +01:00
|
|
|
m_upnp->start();
|
2007-05-31 02:21:54 +02:00
|
|
|
|
2007-12-24 09:18:53 +01:00
|
|
|
m_upnp->discover_device();
|
2016-02-07 08:09:19 +01:00
|
|
|
|
2016-09-16 03:13:43 +02:00
|
|
|
for (auto& s : m_listen_sockets)
|
2008-04-13 21:19:22 +02:00
|
|
|
{
|
2016-09-16 03:13:43 +02:00
|
|
|
remap_ports(remap_upnp, s);
|
2008-04-13 21:19:22 +02:00
|
|
|
}
|
2015-01-06 09:08:49 +01:00
|
|
|
return m_upnp.get();
|
2007-05-31 02:21:54 +02:00
|
|
|
}
|
|
|
|
|
2013-12-31 23:24:56 +01:00
|
|
|
int session_impl::add_port_mapping(int t, int external_port
|
2013-12-31 21:42:37 +01:00
|
|
|
, int local_port)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
2016-09-18 16:11:56 +02:00
|
|
|
if (m_upnp) ret = m_upnp->add_mapping(static_cast<portmap_protocol>(t), external_port
|
2013-12-31 23:24:56 +01:00
|
|
|
, local_port);
|
2016-09-18 16:11:56 +02:00
|
|
|
if (m_natpmp) ret = m_natpmp->add_mapping(static_cast<portmap_protocol>(t), external_port
|
2013-12-31 23:24:56 +01:00
|
|
|
, local_port);
|
2013-12-31 21:42:37 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::delete_port_mapping(int handle)
|
|
|
|
{
|
2013-12-31 23:24:56 +01:00
|
|
|
if (m_upnp) m_upnp->delete_mapping(handle);
|
|
|
|
if (m_natpmp) m_natpmp->delete_mapping(handle);
|
2013-12-31 21:42:37 +01:00
|
|
|
}
|
|
|
|
|
2007-05-31 02:21:54 +02:00
|
|
|
void session_impl::stop_lsd()
|
|
|
|
{
|
2015-01-06 09:08:49 +01:00
|
|
|
if (m_lsd)
|
2007-11-19 03:24:07 +01:00
|
|
|
m_lsd->close();
|
2015-01-06 09:08:49 +01:00
|
|
|
m_lsd.reset();
|
2007-05-31 02:21:54 +02:00
|
|
|
}
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2007-05-31 02:21:54 +02:00
|
|
|
void session_impl::stop_natpmp()
|
|
|
|
{
|
2016-02-07 08:09:19 +01:00
|
|
|
if (!m_natpmp) return;
|
|
|
|
|
|
|
|
m_natpmp->close();
|
2016-09-09 21:02:20 +02:00
|
|
|
for (auto& s : m_listen_sockets)
|
2014-10-06 05:03:01 +02:00
|
|
|
{
|
2016-09-09 21:02:20 +02:00
|
|
|
s.tcp_port_mapping[0] = -1;
|
|
|
|
s.udp_port_mapping[0] = -1;
|
2016-02-07 08:09:19 +01:00
|
|
|
}
|
|
|
|
|
2015-01-06 09:08:49 +01:00
|
|
|
m_natpmp.reset();
|
2007-05-31 02:21:54 +02:00
|
|
|
}
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2007-05-31 02:21:54 +02:00
|
|
|
void session_impl::stop_upnp()
|
|
|
|
{
|
2016-02-07 08:09:19 +01:00
|
|
|
if (!m_upnp) return;
|
|
|
|
|
|
|
|
m_upnp->close();
|
2016-09-09 21:02:20 +02:00
|
|
|
for (auto& s : m_listen_sockets)
|
2008-04-06 21:17:58 +02:00
|
|
|
{
|
2016-09-09 21:02:20 +02:00
|
|
|
s.tcp_port_mapping[1] = -1;
|
|
|
|
s.udp_port_mapping[1] = -1;
|
2016-02-07 08:09:19 +01:00
|
|
|
}
|
2015-01-06 09:08:49 +01:00
|
|
|
m_upnp.reset();
|
2007-05-31 02:21:54 +02:00
|
|
|
}
|
2013-01-02 00:12:16 +01:00
|
|
|
|
2016-12-04 21:58:51 +01:00
|
|
|
external_ip session_impl::external_address() const
|
2015-05-09 20:06:02 +02:00
|
|
|
{
|
2016-12-04 21:58:51 +01:00
|
|
|
address ips[2][2];
|
|
|
|
|
|
|
|
// take the first IP we find which matches each category
|
|
|
|
for (auto const& i : m_listen_sockets)
|
|
|
|
{
|
|
|
|
address external_addr = i.external_address.external_address();
|
|
|
|
if (ips[0][external_addr.is_v6()] == address())
|
|
|
|
ips[0][external_addr.is_v6()] = external_addr;
|
|
|
|
address local_addr = i.local_endpoint.address();
|
|
|
|
if (ips[is_local(local_addr)][local_addr.is_v6()] == address())
|
|
|
|
ips[is_local(local_addr)][local_addr.is_v6()] = local_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return external_ip(ips[1][0], ips[0][0], ips[1][1], ips[0][1]);
|
2015-05-09 20:06:02 +02:00
|
|
|
}
|
2010-12-24 02:31:41 +01:00
|
|
|
|
2013-02-05 05:18:44 +01:00
|
|
|
// this is the DHT observer version. DHT is the implied source
|
|
|
|
void session_impl::set_external_address(address const& ip
|
2015-05-10 06:54:02 +02:00
|
|
|
, address const& source)
|
2013-02-05 05:18:44 +01:00
|
|
|
{
|
|
|
|
set_external_address(ip, source_dht, source);
|
|
|
|
}
|
|
|
|
|
2016-12-04 21:58:51 +01:00
|
|
|
// TODO 3 pass in a specific listen socket rather than an address family
|
2016-02-12 04:56:52 +01:00
|
|
|
address session_impl::external_address(udp proto)
|
2015-05-09 20:06:02 +02:00
|
|
|
{
|
2015-11-14 06:08:57 +01:00
|
|
|
#if !TORRENT_USE_IPV6
|
2016-02-12 04:56:52 +01:00
|
|
|
TORRENT_UNUSED(proto);
|
2015-11-14 06:08:57 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
address addr;
|
|
|
|
#if TORRENT_USE_IPV6
|
2016-02-12 04:56:52 +01:00
|
|
|
if (proto == udp::v6())
|
2015-11-14 06:08:57 +01:00
|
|
|
addr = address_v6();
|
2015-08-30 04:49:47 +02:00
|
|
|
else
|
2015-11-14 06:08:57 +01:00
|
|
|
#endif
|
|
|
|
addr = address_v4();
|
2016-12-04 21:58:51 +01:00
|
|
|
addr = external_address().external_address(addr);
|
|
|
|
return addr;
|
2015-05-09 20:06:02 +02:00
|
|
|
}
|
|
|
|
|
2015-05-10 06:54:02 +02:00
|
|
|
void session_impl::get_peers(sha1_hash const& ih)
|
2015-04-03 22:15:48 +02:00
|
|
|
{
|
|
|
|
if (!m_alerts.should_post<dht_get_peers_alert>()) return;
|
|
|
|
m_alerts.emplace_alert<dht_get_peers_alert>(ih);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::announce(sha1_hash const& ih, address const& addr
|
2015-05-10 06:54:02 +02:00
|
|
|
, int port)
|
2015-04-03 22:15:48 +02:00
|
|
|
{
|
|
|
|
if (!m_alerts.should_post<dht_announce_alert>()) return;
|
|
|
|
m_alerts.emplace_alert<dht_announce_alert>(addr, port, ih);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::outgoing_get_peers(sha1_hash const& target
|
2015-05-10 06:54:02 +02:00
|
|
|
, sha1_hash const& sent_target, udp::endpoint const& ep)
|
2015-04-03 22:15:48 +02:00
|
|
|
{
|
|
|
|
if (!m_alerts.should_post<dht_outgoing_get_peers_alert>()) return;
|
|
|
|
m_alerts.emplace_alert<dht_outgoing_get_peers_alert>(target, sent_target, ep);
|
|
|
|
}
|
|
|
|
|
2016-05-18 07:54:37 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-09 01:13:47 +02:00
|
|
|
bool session_impl::should_log(module_t) const
|
|
|
|
{
|
|
|
|
return m_alerts.should_post<dht_log_alert>();
|
|
|
|
}
|
|
|
|
|
2015-05-10 20:38:10 +02:00
|
|
|
TORRENT_FORMAT(3,4)
|
2016-09-09 01:13:47 +02:00
|
|
|
void session_impl::log(module_t m, char const* fmt, ...)
|
2015-05-10 06:54:02 +02:00
|
|
|
{
|
|
|
|
if (!m_alerts.should_post<dht_log_alert>()) return;
|
|
|
|
|
|
|
|
va_list v;
|
|
|
|
va_start(v, fmt);
|
2016-06-29 00:52:51 +02:00
|
|
|
m_alerts.emplace_alert<dht_log_alert>(
|
|
|
|
static_cast<dht_log_alert::dht_module_t>(m), fmt, v);
|
2015-05-10 06:54:02 +02:00
|
|
|
va_end(v);
|
|
|
|
}
|
|
|
|
|
2016-09-28 05:21:18 +02:00
|
|
|
void session_impl::log_packet(message_direction_t dir, span<char const> pkt
|
2016-09-16 03:13:43 +02:00
|
|
|
, udp::endpoint const& node)
|
2015-05-16 21:29:49 +02:00
|
|
|
{
|
2015-05-28 22:36:22 +02:00
|
|
|
if (!m_alerts.should_post<dht_pkt_alert>()) return;
|
2015-05-16 21:29:49 +02:00
|
|
|
|
2016-09-14 04:46:07 +02:00
|
|
|
dht_pkt_alert::direction_t d = dir == dht::dht_logger::incoming_message
|
2015-05-28 22:36:22 +02:00
|
|
|
? dht_pkt_alert::incoming : dht_pkt_alert::outgoing;
|
2015-05-16 21:29:49 +02:00
|
|
|
|
2016-09-28 05:21:18 +02:00
|
|
|
m_alerts.emplace_alert<dht_pkt_alert>(pkt, d, node);
|
2015-05-16 21:29:49 +02:00
|
|
|
}
|
2016-09-16 15:53:17 +02:00
|
|
|
|
|
|
|
bool session_impl::should_log_portmap(aux::portmap_transport) const
|
|
|
|
{
|
|
|
|
return m_alerts.should_post<portmap_log_alert>();
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::log_portmap(aux::portmap_transport transport, char const* msg) const
|
|
|
|
{
|
|
|
|
int map_transport =
|
|
|
|
static_cast<std::underlying_type<aux::portmap_transport>::type>(transport);
|
|
|
|
TORRENT_ASSERT(map_transport >= 0 && map_transport <= 1);
|
|
|
|
|
|
|
|
if (m_alerts.should_post<portmap_log_alert>())
|
|
|
|
m_alerts.emplace_alert<portmap_log_alert>(map_transport, msg);
|
|
|
|
}
|
2016-09-16 18:21:41 +02:00
|
|
|
|
|
|
|
bool session_impl::should_log_lsd() const
|
|
|
|
{
|
|
|
|
return m_alerts.should_post<log_alert>();
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::log_lsd(char const* msg) const
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<log_alert>())
|
|
|
|
m_alerts.emplace_alert<log_alert>(msg);
|
|
|
|
}
|
2016-05-18 07:54:37 +02:00
|
|
|
#endif
|
2015-05-16 21:29:49 +02:00
|
|
|
|
2016-08-15 22:17:13 +02:00
|
|
|
bool session_impl::on_dht_request(string_view query
|
2014-02-17 06:56:49 +01:00
|
|
|
, dht::msg const& request, entry& response)
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2016-08-30 19:28:46 +02:00
|
|
|
for (auto const& ext : m_ses_extensions[plugins_dht_request_idx])
|
2014-02-17 06:56:49 +01:00
|
|
|
{
|
2016-08-15 22:17:13 +02:00
|
|
|
if (ext->on_dht_request(query
|
2016-06-18 04:02:21 +02:00
|
|
|
, request.addr, request.message, response))
|
2014-02-17 06:56:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
2015-08-22 00:28:12 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(query);
|
|
|
|
TORRENT_UNUSED(request);
|
|
|
|
TORRENT_UNUSED(response);
|
2014-02-17 06:56:49 +01:00
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-12-24 02:31:41 +01:00
|
|
|
void session_impl::set_external_address(address const& ip
|
2016-09-16 03:13:43 +02:00
|
|
|
, int const source_type, address const& source)
|
2008-03-29 23:45:55 +01:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2016-09-14 04:46:07 +02:00
|
|
|
if (should_log())
|
|
|
|
{
|
|
|
|
session_log(": set_external_address(%s, %d, %s)", print_address(ip).c_str()
|
|
|
|
, source_type, print_address(source).c_str());
|
|
|
|
}
|
2010-12-24 02:31:41 +01:00
|
|
|
#endif
|
|
|
|
|
2016-12-04 21:58:51 +01:00
|
|
|
// for now, just pick the first socket with a matching address family
|
|
|
|
// TODO: 3 allow the caller to select which listen socket to update
|
|
|
|
for (auto& i : m_listen_sockets)
|
|
|
|
{
|
|
|
|
if (i.local_endpoint.address().is_v4() != ip.is_v4())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!i.external_address.cast_vote(ip, source_type, source)) return;
|
|
|
|
break;
|
|
|
|
}
|
2010-12-24 02:31:41 +01:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" external IP updated");
|
2010-12-24 02:31:41 +01:00
|
|
|
#endif
|
2010-12-12 10:15:54 +01:00
|
|
|
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<external_ip_alert>())
|
2015-04-03 22:15:48 +02:00
|
|
|
m_alerts.emplace_alert<external_ip_alert>(ip);
|
2010-12-11 10:38:07 +01:00
|
|
|
|
2016-09-09 21:02:20 +02:00
|
|
|
for (auto const& t : m_torrents)
|
2014-01-23 04:31:36 +01:00
|
|
|
{
|
2016-09-09 21:02:20 +02:00
|
|
|
t.second->new_external_ip();
|
2014-01-23 04:31:36 +01:00
|
|
|
}
|
|
|
|
|
2010-12-11 10:38:07 +01:00
|
|
|
// since we have a new external IP now, we need to
|
|
|
|
// restart the DHT with a new node ID
|
2016-01-01 15:21:07 +01:00
|
|
|
|
2010-12-11 10:38:07 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2016-01-09 19:28:15 +01:00
|
|
|
if (m_dht) m_dht->update_node_id();
|
2010-12-11 10:38:07 +01:00
|
|
|
#endif
|
2008-03-29 23:45:55 +01:00
|
|
|
}
|
|
|
|
|
2016-12-29 02:47:18 +01:00
|
|
|
ses_buffer_holder session_impl::allocate_buffer()
|
2007-09-29 18:14:03 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2007-12-27 22:43:11 +01:00
|
|
|
|
2008-04-09 07:19:11 +02:00
|
|
|
#ifdef TORRENT_DISABLE_POOL_ALLOCATOR
|
2017-02-08 16:54:55 +01:00
|
|
|
std::size_t num_bytes = aux::numeric_cast<std::size_t>(send_buffer_size());
|
|
|
|
return ses_buffer_holder(*this, static_cast<char*>(std::malloc(num_bytes)));
|
2008-04-09 07:19:11 +02:00
|
|
|
#else
|
2016-12-29 02:47:18 +01:00
|
|
|
return ses_buffer_holder(*this, static_cast<char*>(m_send_buffers.malloc()));
|
2008-04-09 07:19:11 +02:00
|
|
|
#endif
|
2007-09-29 18:14:03 +02:00
|
|
|
}
|
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
void session_impl::free_buffer(char* buf)
|
2007-09-29 18:14:03 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2007-12-27 22:43:11 +01:00
|
|
|
|
2008-04-09 07:19:11 +02:00
|
|
|
#ifdef TORRENT_DISABLE_POOL_ALLOCATOR
|
|
|
|
free(buf);
|
|
|
|
#else
|
2011-05-19 04:41:28 +02:00
|
|
|
m_send_buffers.free(buf);
|
2008-04-09 07:19:11 +02:00
|
|
|
#endif
|
2015-05-17 04:00:43 +02:00
|
|
|
}
|
2007-01-02 00:51:24 +01:00
|
|
|
|
2014-01-21 20:26:09 +01:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2007-08-21 20:33:28 +02:00
|
|
|
void session_impl::check_invariant() const
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
|
|
|
|
|
|
|
if (m_settings.get_int(settings_pack::unchoke_slots_limit) < 0
|
|
|
|
&& m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::fixed_slots_choker)
|
2015-01-04 23:26:26 +01:00
|
|
|
TORRENT_ASSERT(m_stats_counters[counters::num_unchoke_slots] == (std::numeric_limits<int>::max)());
|
2012-08-29 03:58:06 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
for (int l = 0; l < num_torrent_lists; ++l)
|
2009-08-30 09:38:52 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
std::vector<torrent*> const& list = m_torrent_lists[l];
|
|
|
|
for (std::vector<torrent*>::const_iterator i = list.begin()
|
|
|
|
, end(list.end()); i != end; ++i)
|
2011-08-06 19:54:33 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT((*i)->m_links[l].in_list());
|
2011-08-06 19:54:33 +02:00
|
|
|
}
|
2009-08-30 09:38:52 +02:00
|
|
|
}
|
2008-11-19 01:46:48 +01:00
|
|
|
|
2016-10-19 07:18:05 +02:00
|
|
|
int const num_gauges = counters::num_error_torrents - counters::num_checking_torrents + 1;
|
2017-02-08 16:54:55 +01:00
|
|
|
aux::array<int, num_gauges> torrent_state_gauges;
|
2016-10-19 07:18:05 +02:00
|
|
|
torrent_state_gauges.fill(0);
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
|
|
|
|
2016-04-30 22:53:20 +02:00
|
|
|
std::unordered_set<int> unique;
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
|
2012-06-21 05:51:39 +02:00
|
|
|
int num_active_downloading = 0;
|
|
|
|
int num_active_finished = 0;
|
2008-05-29 05:37:19 +02:00
|
|
|
int total_downloaders = 0;
|
2016-10-19 07:18:05 +02:00
|
|
|
for (auto const& tor : m_torrents)
|
2008-05-29 05:37:19 +02:00
|
|
|
{
|
2016-10-19 07:18:05 +02:00
|
|
|
std::shared_ptr<torrent> const& t = tor.second;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (t->want_peers_download()) ++num_active_downloading;
|
|
|
|
if (t->want_peers_finished()) ++num_active_finished;
|
|
|
|
TORRENT_ASSERT(!(t->want_peers_download() && t->want_peers_finished()));
|
|
|
|
|
2016-10-19 07:18:05 +02:00
|
|
|
int const state = t->current_stats_state() - counters::num_checking_torrents;
|
|
|
|
if (state != torrent::no_gauge_state)
|
|
|
|
{
|
|
|
|
++torrent_state_gauges[state];
|
|
|
|
}
|
2012-06-21 05:51:39 +02:00
|
|
|
|
2017-02-08 16:54:55 +01:00
|
|
|
int const pos = t->queue_position();
|
2008-05-29 05:37:19 +02:00
|
|
|
if (pos < 0)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(pos == -1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
++total_downloaders;
|
2012-06-21 05:51:39 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2012-06-21 05:51:39 +02:00
|
|
|
unique.insert(t->queue_position());
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
2008-05-29 05:37:19 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
for (int i = 0, j = counters::num_checking_torrents;
|
|
|
|
j < counters::num_error_torrents + 1; ++i, ++j)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(torrent_state_gauges[i] == m_stats_counters[j]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2008-09-25 22:12:53 +02:00
|
|
|
TORRENT_ASSERT(int(unique.size()) == total_downloaders);
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
2016-11-21 07:49:56 +01:00
|
|
|
TORRENT_ASSERT(num_active_downloading == int(m_torrent_lists[torrent_want_peers_download].size()));
|
|
|
|
TORRENT_ASSERT(num_active_finished == int(m_torrent_lists[torrent_want_peers_finished].size()));
|
2008-05-29 05:37:19 +02:00
|
|
|
|
2016-04-30 22:53:20 +02:00
|
|
|
std::unordered_set<peer_connection*> unique_peers;
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(m_settings.get_int(settings_pack::connections_limit) > 0);
|
2014-10-23 00:06:56 +02:00
|
|
|
|
2007-08-16 14:41:46 +02:00
|
|
|
int unchokes = 0;
|
2014-09-22 05:47:43 +02:00
|
|
|
int unchokes_all = 0;
|
2007-08-16 14:41:46 +02:00
|
|
|
int num_optimistic = 0;
|
2011-01-30 11:04:15 +01:00
|
|
|
int disk_queue[2] = {0, 0};
|
2007-08-21 20:33:28 +02:00
|
|
|
for (connection_map::const_iterator i = m_connections.begin();
|
2006-10-11 22:57:54 +02:00
|
|
|
i != m_connections.end(); ++i)
|
|
|
|
{
|
2007-10-31 10:48:20 +01:00
|
|
|
TORRENT_ASSERT(*i);
|
2016-08-31 14:27:36 +02:00
|
|
|
std::shared_ptr<torrent> t = (*i)->associated_torrent().lock();
|
2008-10-19 00:35:10 +02:00
|
|
|
TORRENT_ASSERT(unique_peers.find(i->get()) == unique_peers.end());
|
|
|
|
unique_peers.insert(i->get());
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2011-10-29 01:08:52 +02:00
|
|
|
if ((*i)->m_channel_state[0] & peer_info::bw_disk) ++disk_queue[0];
|
|
|
|
if ((*i)->m_channel_state[1] & peer_info::bw_disk) ++disk_queue[1];
|
2011-01-30 11:04:15 +01:00
|
|
|
|
2007-10-31 10:48:20 +01:00
|
|
|
peer_connection* p = i->get();
|
2008-01-19 20:00:54 +01:00
|
|
|
TORRENT_ASSERT(!p->is_disconnecting());
|
2014-09-22 05:47:43 +02:00
|
|
|
if (p->ignore_unchoke_slots())
|
|
|
|
{
|
|
|
|
if (!p->is_choked()) ++unchokes_all;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!p->is_choked())
|
|
|
|
{
|
|
|
|
++unchokes;
|
|
|
|
++unchokes_all;
|
|
|
|
}
|
|
|
|
|
2007-10-31 10:48:20 +01:00
|
|
|
if (p->peer_info_struct()
|
|
|
|
&& p->peer_info_struct()->optimistically_unchoked)
|
2007-08-19 10:23:44 +02:00
|
|
|
{
|
2007-08-16 14:41:46 +02:00
|
|
|
++num_optimistic;
|
2007-10-31 10:48:20 +01:00
|
|
|
TORRENT_ASSERT(!p->is_choked());
|
2007-08-19 10:23:44 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2010-02-02 19:39:32 +01:00
|
|
|
|
2016-10-25 23:27:48 +02:00
|
|
|
for (auto const& p : m_undead_peers)
|
2010-08-27 16:52:42 +02:00
|
|
|
{
|
2014-09-22 05:47:43 +02:00
|
|
|
if (p->ignore_unchoke_slots())
|
|
|
|
{
|
|
|
|
if (!p->is_choked()) ++unchokes_all;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!p->is_choked())
|
|
|
|
{
|
|
|
|
++unchokes_all;
|
|
|
|
++unchokes;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->peer_info_struct()
|
|
|
|
&& p->peer_info_struct()->optimistically_unchoked)
|
|
|
|
{
|
|
|
|
++num_optimistic;
|
|
|
|
TORRENT_ASSERT(!p->is_choked());
|
|
|
|
}
|
2010-08-27 16:52:42 +02:00
|
|
|
}
|
2010-02-02 19:39:32 +01:00
|
|
|
|
2014-09-22 05:47:43 +02:00
|
|
|
TORRENT_ASSERT(disk_queue[peer_connection::download_channel]
|
|
|
|
== m_stats_counters[counters::num_peers_down_disk]);
|
|
|
|
TORRENT_ASSERT(disk_queue[peer_connection::upload_channel]
|
|
|
|
== m_stats_counters[counters::num_peers_up_disk]);
|
|
|
|
|
|
|
|
if (m_settings.get_int(settings_pack::num_optimistic_unchoke_slots))
|
2007-08-21 23:51:29 +02:00
|
|
|
{
|
2014-09-22 05:47:43 +02:00
|
|
|
TORRENT_ASSERT(num_optimistic <= m_settings.get_int(
|
|
|
|
settings_pack::num_optimistic_unchoke_slots));
|
2007-08-21 23:51:29 +02:00
|
|
|
}
|
2014-09-22 05:47:43 +02:00
|
|
|
|
2016-12-06 14:24:01 +01:00
|
|
|
int const unchoked_counter_all = int(m_stats_counters[counters::num_peers_up_unchoked_all]);
|
|
|
|
int const unchoked_counter = int(m_stats_counters[counters::num_peers_up_unchoked]);
|
2016-03-27 18:09:53 +02:00
|
|
|
int const unchoked_counter_optimistic
|
2016-12-06 14:24:01 +01:00
|
|
|
= int(m_stats_counters[counters::num_peers_up_unchoked_optimistic]);
|
2014-09-22 05:47:43 +02:00
|
|
|
|
|
|
|
TORRENT_ASSERT_VAL(unchoked_counter_all == unchokes_all, unchokes_all);
|
|
|
|
TORRENT_ASSERT_VAL(unchoked_counter == unchokes, unchokes);
|
|
|
|
TORRENT_ASSERT_VAL(unchoked_counter_optimistic == num_optimistic, num_optimistic);
|
|
|
|
|
2016-09-01 21:04:58 +02:00
|
|
|
for (auto const& te : m_torrents)
|
2007-11-27 03:46:19 +01:00
|
|
|
{
|
2016-09-01 21:04:58 +02:00
|
|
|
TORRENT_ASSERT(te.second);
|
2007-11-27 03:46:19 +01:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2015-05-19 06:59:31 +02:00
|
|
|
#endif // TORRENT_USE_INVARIANT_CHECKS
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2014-07-06 21:18:00 +02:00
|
|
|
tracker_logger::tracker_logger(session_interface& ses): m_ses(ses) {}
|
2015-05-19 06:59:31 +02:00
|
|
|
void tracker_logger::tracker_warning(tracker_request const&
|
2013-07-19 21:06:27 +02:00
|
|
|
, std::string const& str)
|
|
|
|
{
|
|
|
|
debug_log("*** tracker warning: %s", str.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
void tracker_logger::tracker_response(tracker_request const&
|
|
|
|
, libtorrent::address const& tracker_ip
|
2015-05-19 06:59:31 +02:00
|
|
|
, std::list<address> const& tracker_ips
|
2014-09-28 08:36:03 +02:00
|
|
|
, struct tracker_response const& resp)
|
|
|
|
{
|
2015-05-19 06:59:31 +02:00
|
|
|
TORRENT_UNUSED(tracker_ips);
|
2014-09-28 08:36:03 +02:00
|
|
|
debug_log("TRACKER RESPONSE\n"
|
|
|
|
"interval: %d\n"
|
|
|
|
"external ip: %s\n"
|
|
|
|
"we connected to: %s\n"
|
|
|
|
"peers:"
|
2017-02-06 01:18:06 +01:00
|
|
|
, resp.interval.count()
|
2014-09-28 08:36:03 +02:00
|
|
|
, print_address(resp.external_ip).c_str()
|
2014-10-04 21:54:12 +02:00
|
|
|
, print_address(tracker_ip).c_str());
|
2014-09-28 08:36:03 +02:00
|
|
|
|
2016-09-14 04:46:07 +02:00
|
|
|
for (auto const& p : resp.peers)
|
2013-07-19 21:06:27 +02:00
|
|
|
{
|
2016-12-17 08:05:34 +01:00
|
|
|
debug_log(" %16s %5d %s", p.hostname.c_str(), p.port
|
|
|
|
, p.pid.is_all_zeros() ? "" : to_hex(p.pid).c_str());
|
2013-07-19 21:06:27 +02:00
|
|
|
}
|
2016-09-14 04:46:07 +02:00
|
|
|
for (auto const& p : resp.peers4)
|
2015-05-17 04:00:43 +02:00
|
|
|
{
|
2016-09-14 04:46:07 +02:00
|
|
|
debug_log(" %s:%d", print_address(address_v4(p.ip)).c_str(), p.port);
|
2014-09-28 08:36:03 +02:00
|
|
|
}
|
|
|
|
#if TORRENT_USE_IPV6
|
2016-09-14 04:46:07 +02:00
|
|
|
for (auto const& p : resp.peers6)
|
2014-09-28 08:36:03 +02:00
|
|
|
{
|
2016-09-14 04:46:07 +02:00
|
|
|
debug_log(" [%s]:%d", print_address(address_v6(p.ip)).c_str(), p.port);
|
2014-09-28 08:36:03 +02:00
|
|
|
}
|
|
|
|
#endif
|
2013-07-19 21:06:27 +02:00
|
|
|
}
|
|
|
|
|
2015-05-19 06:59:31 +02:00
|
|
|
void tracker_logger::tracker_request_error(tracker_request const&
|
2013-07-19 21:06:27 +02:00
|
|
|
, int response_code, error_code const& ec, const std::string& str
|
2017-02-06 01:18:06 +01:00
|
|
|
, seconds32 const retry_interval)
|
2013-07-19 21:06:27 +02:00
|
|
|
{
|
2015-05-19 06:59:31 +02:00
|
|
|
TORRENT_UNUSED(retry_interval);
|
2013-07-19 21:06:27 +02:00
|
|
|
debug_log("*** tracker error: %d: %s %s"
|
|
|
|
, response_code, ec.message().c_str(), str.c_str());
|
|
|
|
}
|
2015-05-17 04:00:43 +02:00
|
|
|
|
2016-09-14 04:46:07 +02:00
|
|
|
bool tracker_logger::should_log() const
|
|
|
|
{
|
|
|
|
return m_ses.alerts().should_post<log_alert>();
|
|
|
|
}
|
|
|
|
|
2013-07-19 21:06:27 +02:00
|
|
|
void tracker_logger::debug_log(const char* fmt, ...) const
|
|
|
|
{
|
2016-09-14 04:46:07 +02:00
|
|
|
if (!m_ses.alerts().should_post<log_alert>()) return;
|
|
|
|
|
2015-05-17 04:00:43 +02:00
|
|
|
va_list v;
|
2013-07-19 21:06:27 +02:00
|
|
|
va_start(v, fmt);
|
2016-09-14 04:46:07 +02:00
|
|
|
m_ses.alerts().emplace_alert<log_alert>(fmt, v);
|
2013-07-19 21:06:27 +02:00
|
|
|
va_end(v);
|
|
|
|
}
|
2015-05-19 06:59:31 +02:00
|
|
|
#endif // TORRENT_DISABLE_LOGGING
|
2006-10-11 22:57:54 +02:00
|
|
|
}}
|