2006-10-11 22:57:54 +02:00
|
|
|
/*
|
|
|
|
|
2014-02-23 20:12:25 +01:00
|
|
|
Copyright (c) 2006-2014, 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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <ctime>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cctype>
|
|
|
|
#include <algorithm>
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if defined TORRENT_DEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
|
|
|
|
#if TORRENT_HAS_BOOST_UNORDERED
|
|
|
|
#include <boost/unordered_set.hpp>
|
|
|
|
#else
|
|
|
|
#include <set>
|
|
|
|
#endif
|
|
|
|
#endif // TORRENT_DEBUG && !TORRENT_DISABLE_INVARIANT_CHECKS
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(push, 1)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <boost/limits.hpp>
|
|
|
|
#include <boost/bind.hpp>
|
2008-09-22 01:19:58 +02:00
|
|
|
#include <boost/function_equal.hpp>
|
2014-07-06 21:18:00 +02:00
|
|
|
#include <boost/make_shared.hpp>
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2013-10-02 23:51:30 +02:00
|
|
|
#ifdef TORRENT_USE_VALGRIND
|
|
|
|
#include <valgrind/memcheck.h>
|
|
|
|
#endif
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(pop)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#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/entry.hpp"
|
|
|
|
#include "libtorrent/alert_types.hpp"
|
|
|
|
#include "libtorrent/invariant_check.hpp"
|
|
|
|
#include "libtorrent/file.hpp"
|
|
|
|
#include "libtorrent/bt_peer_connection.hpp"
|
|
|
|
#include "libtorrent/ip_filter.hpp"
|
|
|
|
#include "libtorrent/socket.hpp"
|
|
|
|
#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"
|
2010-12-29 03:17:44 +01:00
|
|
|
#endif
|
2007-09-22 18:27:29 +02:00
|
|
|
#include "libtorrent/enum_net.hpp"
|
2008-04-24 05:28:48 +02:00
|
|
|
#include "libtorrent/config.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-01-29 11:37:21 +01:00
|
|
|
#include "libtorrent/extensions.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"
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2014-10-04 21:54:12 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING
|
|
|
|
#include "libtorrent/socket_io.hpp"
|
|
|
|
#endif
|
|
|
|
|
2011-10-22 19:44:40 +02:00
|
|
|
#if defined TORRENT_STATS && defined __MACH__
|
2011-10-17 19:12:08 +02:00
|
|
|
#include <mach/task.h>
|
|
|
|
#endif
|
|
|
|
|
2008-05-16 17:19:38 +02:00
|
|
|
#ifndef TORRENT_WINDOWS
|
|
|
|
#include <sys/resource.h>
|
|
|
|
#endif
|
|
|
|
|
2010-04-14 20:52:13 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
|
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"
|
|
|
|
|
2010-04-14 20:52:13 +02:00
|
|
|
#include "libtorrent/debug.hpp"
|
|
|
|
|
|
|
|
#if TORRENT_USE_IOSTREAM
|
|
|
|
namespace libtorrent {
|
|
|
|
std::ofstream logger::log_file;
|
|
|
|
std::string logger::open_filename;
|
|
|
|
mutex logger::file_mutex;
|
|
|
|
}
|
|
|
|
#endif // TORRENT_USE_IOSTREAM
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2009-11-08 04:09:19 +01:00
|
|
|
#ifdef TORRENT_USE_GCRYPT
|
|
|
|
|
|
|
|
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);
|
|
|
|
if (e != 0) fprintf(stderr, "libcrypt ERROR: %s\n", gcry_strerror(e));
|
|
|
|
e = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
|
|
|
if (e != 0) fprintf(stderr, "initialization finished error: %s\n", gcry_strerror(e));
|
|
|
|
}
|
|
|
|
} gcrypt_global_constructor;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // TORRENT_USE_GCRYPT
|
|
|
|
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2007-07-07 01:06:58 +02:00
|
|
|
|
|
|
|
#include <openssl/crypto.h>
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
// openssl requires this to clean up internal
|
|
|
|
// structures it allocates
|
|
|
|
struct openssl_cleanup
|
|
|
|
{
|
|
|
|
~openssl_cleanup() { CRYPTO_cleanup_all_ex_data(); }
|
|
|
|
} 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
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
using boost::shared_ptr;
|
|
|
|
using boost::weak_ptr;
|
|
|
|
using libtorrent::aux::session_impl;
|
|
|
|
|
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;
|
|
|
|
mutex _async_ops_mutex;
|
2010-11-28 02:47:30 +01:00
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
socket_job::~socket_job() {}
|
|
|
|
|
|
|
|
void network_thread_pool::process_job(socket_job const& j, bool post)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if (j.type == socket_job::write_job)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(j.peer->m_socket_is_writing);
|
|
|
|
j.peer->get_socket()->async_write_some(
|
|
|
|
*j.vec, j.peer->make_write_handler(boost::bind(
|
|
|
|
&peer_connection::on_send_data, j.peer, _1, _2)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (j.recv_buf)
|
|
|
|
{
|
|
|
|
j.peer->get_socket()->async_read_some(asio::buffer(j.recv_buf, j.buf_size)
|
|
|
|
, j.peer->make_read_handler(boost::bind(
|
|
|
|
&peer_connection::on_receive_data, j.peer, _1, _2)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
j.peer->get_socket()->async_read_some(j.read_vec
|
|
|
|
, j.peer->make_read_handler(boost::bind(
|
|
|
|
&peer_connection::on_receive_data, j.peer, _1, _2)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
namespace detail
|
|
|
|
{
|
2006-10-11 22:57:54 +02:00
|
|
|
std::string generate_auth_string(std::string const& user
|
|
|
|
, std::string const& passwd)
|
|
|
|
{
|
|
|
|
if (user.empty()) return std::string();
|
|
|
|
return user + ":" + passwd;
|
|
|
|
}
|
2008-03-08 07:06:31 +01:00
|
|
|
}
|
2009-05-25 04:45:51 +02:00
|
|
|
|
2008-03-08 07:06:31 +01:00
|
|
|
namespace aux {
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2011-10-22 19:44:40 +02:00
|
|
|
#ifdef TORRENT_STATS
|
2014-07-06 21:18:00 +02:00
|
|
|
void get_vm_stats(vm_statistics_data_t* vm_stat, error_code& ec)
|
2011-10-22 19:44:40 +02:00
|
|
|
{
|
|
|
|
memset(vm_stat, 0, sizeof(*vm_stat));
|
|
|
|
#if defined __MACH__
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.clear();
|
2011-10-22 19:44:40 +02:00
|
|
|
mach_port_t host_port = mach_host_self();
|
|
|
|
mach_msg_type_number_t host_count = HOST_VM_INFO_COUNT;
|
|
|
|
kern_return_t error = host_statistics(host_port, HOST_VM_INFO,
|
|
|
|
(host_info_t)vm_stat, &host_count);
|
2014-03-23 20:13:21 +01:00
|
|
|
TORRENT_ASSERT_VAL(error == KERN_SUCCESS, error);
|
2011-10-22 19:44:40 +02:00
|
|
|
#elif defined TORRENT_LINUX
|
2014-07-06 21:18:00 +02:00
|
|
|
ec.clear();
|
|
|
|
char string[4096];
|
2011-10-22 19:44:40 +02:00
|
|
|
boost::uint32_t value;
|
|
|
|
FILE* f = fopen("/proc/vmstat", "r");
|
|
|
|
int ret = 0;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (f == 0)
|
|
|
|
{
|
|
|
|
ec.assign(errno, boost::system::system_category());
|
|
|
|
return;
|
|
|
|
}
|
2011-10-22 19:44:40 +02:00
|
|
|
while ((ret = fscanf(f, "%s %u\n", string, &value)) != EOF)
|
|
|
|
{
|
|
|
|
if (ret != 2) continue;
|
|
|
|
if (strcmp(string, "nr_active_anon") == 0) vm_stat->active_count += value;
|
|
|
|
else if (strcmp(string, "nr_active_file") == 0) vm_stat->active_count += value;
|
|
|
|
else if (strcmp(string, "nr_inactive_anon") == 0) vm_stat->inactive_count += value;
|
|
|
|
else if (strcmp(string, "nr_inactive_file") == 0) vm_stat->inactive_count += value;
|
|
|
|
else if (strcmp(string, "nr_free_pages") == 0) vm_stat->free_count = value;
|
|
|
|
else if (strcmp(string, "nr_unevictable") == 0) vm_stat->wire_count = value;
|
|
|
|
else if (strcmp(string, "pswpin") == 0) vm_stat->pageins = value;
|
|
|
|
else if (strcmp(string, "pswpout") == 0) vm_stat->pageouts = value;
|
|
|
|
else if (strcmp(string, "pgfault") == 0) vm_stat->faults = value;
|
|
|
|
}
|
|
|
|
fclose(f);
|
2014-07-06 21:18:00 +02:00
|
|
|
#else
|
|
|
|
ec = asio::error::operation_not_supported;
|
2011-10-22 19:44:40 +02:00
|
|
|
#endif
|
|
|
|
// TOOD: windows?
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_thread_cpu_usage(thread_cpu_usage* tu)
|
|
|
|
{
|
|
|
|
#if defined __MACH__
|
|
|
|
task_thread_times_info t_info;
|
|
|
|
mach_msg_type_number_t t_info_count = TASK_THREAD_TIMES_INFO_COUNT;
|
|
|
|
task_info(mach_task_self(), TASK_THREAD_TIMES_INFO, (task_info_t)&t_info, &t_info_count);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
tu->user_time = seconds(t_info.user_time.seconds)
|
|
|
|
+ microseconds(t_info.user_time.microseconds);
|
|
|
|
tu->system_time = seconds(t_info.system_time.seconds)
|
|
|
|
+ microseconds(t_info.system_time.microseconds);
|
2011-10-22 19:44:40 +02:00
|
|
|
#elif defined TORRENT_LINUX
|
|
|
|
struct rusage ru;
|
|
|
|
getrusage(RUSAGE_THREAD, &ru);
|
2014-07-06 21:18:00 +02:00
|
|
|
tu->user_time = seconds(ru.ru_utime.tv_sec)
|
|
|
|
+ microseconds(ru.ru_utime.tv_usec);
|
|
|
|
tu->system_time = seconds(ru.ru_stime.tv_sec)
|
|
|
|
+ microseconds(ru.ru_stime.tv_usec);
|
2011-10-22 19:44:40 +02:00
|
|
|
#elif defined TORRENT_WINDOWS
|
|
|
|
FILETIME system_time;
|
|
|
|
FILETIME user_time;
|
|
|
|
FILETIME creation_time;
|
|
|
|
FILETIME exit_time;
|
|
|
|
GetThreadTimes(GetCurrentThread(), &creation_time, &exit_time, &user_time, &system_time);
|
|
|
|
|
|
|
|
boost::uint64_t utime = (boost::uint64_t(user_time.dwHighDateTime) << 32)
|
|
|
|
+ user_time.dwLowDateTime;
|
|
|
|
boost::uint64_t stime = (boost::uint64_t(system_time.dwHighDateTime) << 32)
|
|
|
|
+ system_time.dwLowDateTime;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
tu->user_time = microseconds(utime / 10);
|
|
|
|
tu->system_time = microseconds(stime / 10);
|
2011-10-22 19:44:40 +02:00
|
|
|
#endif
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif // TORRENT_STATS
|
2011-10-22 19:44:40 +02:00
|
|
|
|
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
|
|
|
|
boost::uint32_t lfilter = 1 << m_local_peer_class;
|
|
|
|
boost::uint32_t gfilter = 1 << 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;
|
|
|
|
boost::uint32_t filter;
|
|
|
|
};
|
2009-12-03 06:11:57 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
const static class_mapping v4_classes[] =
|
|
|
|
{
|
|
|
|
// 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
|
|
|
|
const static class_mapping v6_classes[] =
|
|
|
|
{
|
|
|
|
// 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
|
|
|
|
2012-04-06 06:11:04 +02:00
|
|
|
#if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700 && OPENSSL_VERSION_NUMBER >= 0x90812f
|
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
|
|
|
|
int servername_callback(SSL *s, int *ad, void *arg)
|
|
|
|
{
|
|
|
|
session_impl* ses = (session_impl*)arg;
|
|
|
|
const char* servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
|
|
|
|
|
|
|
|
if (!servername || strlen(servername) < 40)
|
|
|
|
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
|
|
|
|
|
|
sha1_hash info_hash;
|
|
|
|
bool valid = from_hex(servername, 40, (char*)&info_hash[0]);
|
|
|
|
|
|
|
|
// 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
|
|
|
|
boost::shared_ptr<torrent> t = ses->find_torrent(info_hash).lock();
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
session_impl::session_impl(fingerprint const& cl_fprint)
|
|
|
|
:
|
2008-04-09 07:19:11 +02:00
|
|
|
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
2014-07-06 21:18:00 +02:00
|
|
|
m_send_buffers(send_buffer_size())
|
|
|
|
,
|
2008-04-09 07:19:11 +02:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
m_io_service()
|
2010-10-12 10:57:43 +02:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2012-01-14 17:04:25 +01:00
|
|
|
, m_ssl_ctx(m_io_service, 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)
|
2014-08-01 08:07:48 +02:00
|
|
|
, m_disk_thread(m_io_service, this, m_stats_counters
|
|
|
|
, (uncork_interface*)this)
|
2009-04-26 02:21:59 +02:00
|
|
|
, m_download_rate(peer_connection::download_channel)
|
2008-01-12 19:47:26 +01:00
|
|
|
#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT
|
2009-04-26 02:21:59 +02:00
|
|
|
, m_upload_rate(peer_connection::upload_channel, true)
|
2008-01-12 19:47:26 +01:00
|
|
|
#else
|
2009-04-26 02:21:59 +02:00
|
|
|
, m_upload_rate(peer_connection::upload_channel)
|
2008-01-12 19:47:26 +01:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_tracker_manager(*this)
|
|
|
|
, m_num_save_resume(0)
|
|
|
|
, m_work(io_service::work(m_io_service))
|
|
|
|
, m_max_queue_pos(-1)
|
2013-08-31 23:06:43 +02:00
|
|
|
, m_key(0)
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_listen_port_retries(10)
|
2009-08-20 05:19:12 +02:00
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
, m_i2p_conn(m_io_service)
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_socks_listen_port(0)
|
|
|
|
, m_interface_index(0)
|
2008-01-13 12:18:18 +01:00
|
|
|
, m_allowed_upload_slots(8)
|
2007-08-16 14:41:46 +02:00
|
|
|
, m_unchoke_time_scaler(0)
|
2008-04-24 05:28:48 +02:00
|
|
|
, m_auto_manage_time_scaler(0)
|
2007-08-16 14:41:46 +02:00
|
|
|
, m_optimistic_unchoke_time_scaler(0)
|
2008-04-22 02:05:23 +02:00
|
|
|
, m_disconnect_time_scaler(90)
|
2008-05-19 06:06:25 +02:00
|
|
|
, m_auto_scrape_time_scaler(180)
|
2010-01-15 17:45:42 +01:00
|
|
|
, m_next_explicit_cache_torrent(0)
|
|
|
|
, m_cache_rotation_timer(0)
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_next_suggest_torrent(0)
|
|
|
|
, m_suggest_timer(0)
|
2010-02-09 04:04:41 +01:00
|
|
|
, m_peak_up_rate(0)
|
|
|
|
, m_peak_down_rate(0)
|
2009-05-25 04:45:51 +02:00
|
|
|
, m_created(time_now_hires())
|
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)
|
2011-01-18 04:41:54 +01:00
|
|
|
, m_next_rss_update(min_time())
|
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)
|
2012-08-03 07:13:40 +02:00
|
|
|
, m_dht_interval_update_torrents(0)
|
2007-03-15 23:03:56 +01:00
|
|
|
#endif
|
2010-05-30 03:33:03 +02:00
|
|
|
, m_external_udp_port(0)
|
2014-10-03 22:56:57 +02:00
|
|
|
, m_udp_socket(m_io_service)
|
2013-08-31 22:19:03 +02:00
|
|
|
// TODO: 4 in order to support SSL over uTP, the utp_socket manager either
|
|
|
|
// needs to be able to receive packets on multiple ports, or we need to
|
|
|
|
// peek into the first few bytes the payload stream of a socket to determine
|
|
|
|
// whether or not it's an SSL connection. (The former is simpler but won't
|
|
|
|
// do as well with NATs)
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_utp_socket_manager(m_settings, m_udp_socket, m_stats_counters
|
2010-11-29 02:33:05 +01:00
|
|
|
, boost::bind(&session_impl::incoming_connection, this, _1))
|
2010-12-17 04:10:56 +01:00
|
|
|
, m_boost_connections(0)
|
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)
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_download_connect_attempts(0)
|
2010-02-14 02:39:55 +01:00
|
|
|
, m_tick_residual(0)
|
2008-02-17 23:51:03 +01:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2013-03-10 10:19:58 +01:00
|
|
|
, m_logpath(".")
|
2007-11-16 22:21:28 +01:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_deferred_submit_disk_jobs(false)
|
2012-11-03 04:50:12 +01:00
|
|
|
, m_pending_auto_manage(false)
|
|
|
|
, m_need_auto_manage(false)
|
2013-11-26 03:00:02 +01:00
|
|
|
, m_abort(false)
|
|
|
|
, m_paused(false)
|
2014-01-19 20:45:50 +01:00
|
|
|
#if TORRENT_USE_ASSERTS && defined BOOST_HAS_PTHREADS
|
2010-12-04 23:20:31 +01:00
|
|
|
, m_network_thread(0)
|
|
|
|
#endif
|
2006-10-11 22:57:54 +02: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
|
2014-07-06 21:18:00 +02:00
|
|
|
m_udp_socket.set_rate_limit(m_settings.get_int(settings_pack::dht_upload_rate_limit));
|
2011-03-14 08:47:24 +01:00
|
|
|
|
2012-06-22 06:21:20 +02:00
|
|
|
m_udp_socket.subscribe(&m_tracker_manager);
|
|
|
|
m_udp_socket.subscribe(&m_utp_socket_manager);
|
|
|
|
m_udp_socket.subscribe(this);
|
|
|
|
|
2011-12-29 13:15:29 +01:00
|
|
|
#ifdef TORRENT_REQUEST_LOGGING
|
|
|
|
char log_filename[200];
|
2013-06-18 05:18:47 +02:00
|
|
|
#ifdef TORRENT_WINDOWS
|
|
|
|
const int pid = GetCurrentProcessId();
|
|
|
|
#else
|
|
|
|
const int pid = getpid();
|
|
|
|
#endif
|
|
|
|
snprintf(log_filename, sizeof(log_filename), "requests-%d.log", pid);
|
2011-12-29 13:15:29 +01:00
|
|
|
m_request_log = fopen(log_filename, "w+");
|
|
|
|
if (m_request_log == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "failed to open request log file: (%d) %s\n", errno, strerror(errno));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-03-10 10:19:58 +01:00
|
|
|
error_code ec;
|
2014-07-06 21:18:00 +02:00
|
|
|
m_listen_interface = tcp::endpoint(address_v4::any(), 0);
|
2013-03-10 10:19:58 +01:00
|
|
|
TORRENT_ASSERT_VAL(!ec, ec);
|
|
|
|
|
|
|
|
// ---- generate a peer id ----
|
|
|
|
std::string print = cl_fprint.to_string();
|
|
|
|
TORRENT_ASSERT_VAL(print.length() <= 20, print.length());
|
|
|
|
|
|
|
|
// the client's fingerprint
|
|
|
|
std::copy(
|
|
|
|
print.begin()
|
|
|
|
, print.begin() + print.length()
|
|
|
|
, m_peer_id.begin());
|
|
|
|
|
|
|
|
url_random((char*)&m_peer_id[print.length()], (char*)&m_peer_id[0] + 20);
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::start_session(settings_pack const& pack)
|
2013-03-10 10:19:58 +01:00
|
|
|
{
|
2010-05-09 08:03:52 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
m_logger = create_log("main_session", listen_port(), false);
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log("log created");
|
2010-05-09 08:03:52 +02:00
|
|
|
#endif
|
|
|
|
|
2010-10-12 10:57:43 +02:00
|
|
|
error_code ec;
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
m_ssl_ctx.set_verify_mode(asio::ssl::context::verify_none, ec);
|
2012-02-26 01:01:53 +01:00
|
|
|
#if BOOST_VERSION >= 104700
|
2012-04-06 06:11:04 +02:00
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x90812f
|
2012-01-14 17:04:25 +01:00
|
|
|
SSL_CTX_set_tlsext_servername_callback(m_ssl_ctx.native_handle(), servername_callback);
|
|
|
|
SSL_CTX_set_tlsext_servername_arg(m_ssl_ctx.native_handle(), this);
|
2012-04-06 06:11:04 +02:00
|
|
|
#endif // OPENSSL_VERSION_NUMBER
|
2012-02-25 09:31:25 +01:00
|
|
|
#endif // BOOST_VERSION
|
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();
|
2014-07-06 21:18:00 +02:00
|
|
|
m_next_downloading_connect_torrent = 0;
|
|
|
|
m_next_finished_connect_torrent = 0;
|
|
|
|
m_next_scrape_torrent = 0;
|
2010-02-05 09:23:17 +01:00
|
|
|
|
2008-04-06 21:17:58 +02:00
|
|
|
m_tcp_mapping[0] = -1;
|
|
|
|
m_tcp_mapping[1] = -1;
|
|
|
|
m_udp_mapping[0] = -1;
|
|
|
|
m_udp_mapping[1] = -1;
|
2012-01-14 17:04:25 +01:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
m_ssl_mapping[0] = -1;
|
|
|
|
m_ssl_mapping[1] = -1;
|
|
|
|
#endif
|
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);
|
|
|
|
|
|
|
|
// TODO: there's no rule here to make uTP connections not have the global or
|
|
|
|
// local rate limits apply to it. This used to be the default.
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2008-10-22 03:12:14 +02:00
|
|
|
#ifdef TORRENT_UPNP_LOGGING
|
|
|
|
m_upnp_log.open("upnp.log", std::ios::in | std::ios::out | std::ios::trunc);
|
|
|
|
#endif
|
2008-05-19 04:52:32 +02:00
|
|
|
|
2010-05-09 08:03:52 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2010-10-24 02:44:07 +02:00
|
|
|
|
2010-11-15 05:43:53 +01:00
|
|
|
char tmp[300];
|
|
|
|
snprintf(tmp, sizeof(tmp), "libtorrent configuration: %s\n"
|
2011-02-15 11:05:25 +01:00
|
|
|
"libtorrent version: %s\n"
|
|
|
|
"libtorrent revision: %s\n\n"
|
2010-11-15 05:43:53 +01:00
|
|
|
, TORRENT_CFG_STRING
|
|
|
|
, LIBTORRENT_VERSION
|
|
|
|
, LIBTORRENT_REVISION);
|
|
|
|
(*m_logger) << tmp;
|
2010-10-24 02:44:07 +02:00
|
|
|
|
2013-12-02 11:00:03 +01:00
|
|
|
#endif // TORRENT_VERBOSE_LOGGING
|
2007-05-14 00:01:21 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_STATS
|
2011-04-06 08:27:42 +02:00
|
|
|
|
2011-04-26 09:05:26 +02:00
|
|
|
m_stats_logger = 0;
|
2011-06-01 09:06:20 +02:00
|
|
|
m_log_seq = 0;
|
2011-04-06 08:27:42 +02:00
|
|
|
m_stats_logging_enabled = true;
|
2011-06-29 00:20:34 +02:00
|
|
|
|
|
|
|
memset(&m_last_cache_status, 0, sizeof(m_last_cache_status));
|
2014-07-06 21:18:00 +02:00
|
|
|
vm_statistics_data_t vst;
|
|
|
|
get_vm_stats(&vst, ec);
|
|
|
|
if (!ec) m_last_vm_stat = vst;
|
2011-06-29 00:20:34 +02:00
|
|
|
|
2011-11-28 02:27:55 +01:00
|
|
|
get_thread_cpu_usage(&m_network_thread_cpu_usage);
|
2011-08-27 11:47:36 +02:00
|
|
|
|
2011-02-11 18:39:22 +01:00
|
|
|
rotate_stats_log();
|
2011-02-03 05:09:50 +01:00
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_RLIMIT
|
|
|
|
// ---- auto-cap max connections ----
|
2009-10-03 21:02:31 +02:00
|
|
|
|
|
|
|
struct rlimit rl;
|
|
|
|
if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
|
|
|
|
{
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" max number of open files: %d", rl.rlim_cur);
|
2009-10-03 21:02:31 +02:00
|
|
|
#endif
|
|
|
|
// deduct some margin for epoll/kqueue, log files,
|
|
|
|
// futexes, shared objects etc.
|
|
|
|
rl.rlim_cur -= 20;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// 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)
|
|
|
|
, int(rl.rlim_cur * 8 / 10)));
|
|
|
|
// 20% goes towards regular files (see disk_io_thread)
|
2009-10-03 21:02:31 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2014-07-06 21:18:00 +02:00
|
|
|
session_log(" max connections: %d", m_settings.get_int(settings_pack::connections_limit));
|
|
|
|
session_log(" max files: %d", int(rl.rlim_cur * 2 / 10));
|
2009-10-03 21:02:31 +02:00
|
|
|
#endif
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif // TORRENT_USE_RLIMIT
|
2009-10-03 21:02:31 +02:00
|
|
|
|
|
|
|
|
2010-12-24 01:37:01 +01:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" generated peer ID: %s", m_peer_id.to_string().c_str());
|
2010-12-24 01:37:01 +01:00
|
|
|
#endif
|
|
|
|
|
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();
|
|
|
|
update_choking_algorithm();
|
|
|
|
update_disk_threads();
|
|
|
|
update_network_threads();
|
|
|
|
update_upnp();
|
|
|
|
update_natpmp();
|
|
|
|
update_lsd();
|
|
|
|
update_dht();
|
|
|
|
|
|
|
|
settings_pack* copy = new settings_pack(pack);
|
|
|
|
m_io_service.post(boost::bind(&session_impl::apply_settings_pack, this, copy));
|
|
|
|
m_io_service.post(boost::bind(&session_impl::maybe_open_listen_port, this));
|
|
|
|
|
2013-03-10 10:19:58 +01:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
session_log(" spawning network thread");
|
|
|
|
#endif
|
|
|
|
m_thread.reset(new thread(boost::bind(&session_impl::main_thread, this)));
|
2010-12-04 23:20:31 +01:00
|
|
|
}
|
2010-10-09 21:09:38 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::maybe_open_listen_port()
|
|
|
|
{
|
|
|
|
if (m_listen_sockets.empty())
|
|
|
|
{
|
|
|
|
update_listen_interfaces();
|
|
|
|
open_listen_port();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-02-11 18:39:22 +01:00
|
|
|
#ifdef TORRENT_STATS
|
|
|
|
void session_impl::rotate_stats_log()
|
|
|
|
{
|
|
|
|
if (m_stats_logger)
|
|
|
|
{
|
|
|
|
++m_log_seq;
|
|
|
|
fclose(m_stats_logger);
|
|
|
|
}
|
2011-11-13 09:12:11 +01:00
|
|
|
|
2011-02-11 18:39:22 +01:00
|
|
|
error_code ec;
|
|
|
|
char filename[100];
|
2011-11-13 09:12:11 +01:00
|
|
|
create_directory("session_stats", ec);
|
2013-06-18 10:48:19 +02:00
|
|
|
#ifdef TORRENT_WINDOWS
|
|
|
|
const int pid = GetCurrentProcessId();
|
|
|
|
#else
|
|
|
|
const int pid = getpid();
|
|
|
|
#endif
|
|
|
|
snprintf(filename, sizeof(filename), "session_stats/%d.%04d.log", pid, m_log_seq);
|
2011-02-11 18:39:22 +01:00
|
|
|
m_stats_logger = fopen(filename, "w+");
|
2014-07-06 21:18:00 +02:00
|
|
|
m_last_log_rotation = time_now();
|
2011-02-11 18:39:22 +01:00
|
|
|
if (m_stats_logger == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Failed to create session stats log file \"%s\": (%d) %s\n"
|
|
|
|
, filename, errno, strerror(errno));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
fputs("second"
|
|
|
|
":uploaded bytes"
|
|
|
|
":downloaded bytes"
|
|
|
|
":downloading torrents"
|
|
|
|
":seeding torrents"
|
|
|
|
":peers"
|
|
|
|
":connecting peers"
|
|
|
|
":disk block buffers"
|
|
|
|
":num list peers"
|
|
|
|
":peer allocations"
|
|
|
|
":peer storage bytes"
|
2012-03-11 06:35:29 +01:00
|
|
|
":checking torrents"
|
|
|
|
":stopped torrents"
|
|
|
|
":upload-only torrents"
|
|
|
|
":queued seed torrents"
|
|
|
|
":queued download torrents"
|
2014-07-06 21:18:00 +02:00
|
|
|
":peers bw-up"
|
|
|
|
":peers bw-down"
|
|
|
|
":peers disk-up"
|
|
|
|
":peers disk-down"
|
|
|
|
":upload rate"
|
|
|
|
":download rate"
|
|
|
|
":disk write queued bytes"
|
|
|
|
":peers down 0"
|
|
|
|
":peers down 0-2"
|
|
|
|
":peers down 2-5"
|
|
|
|
":peers down 5-10"
|
|
|
|
":peers down 10-50"
|
|
|
|
":peers down 50-100"
|
|
|
|
":peers down 100-"
|
|
|
|
":peers up 0"
|
|
|
|
":peers up 0-2"
|
|
|
|
":peers up 2-5"
|
|
|
|
":peers up 5-10"
|
|
|
|
":peers up 10-50"
|
|
|
|
":peers up 50-100"
|
|
|
|
":peers up 100-"
|
|
|
|
":error peers"
|
|
|
|
":peers down interesting"
|
|
|
|
":peers down unchoked"
|
|
|
|
":peers down requests"
|
|
|
|
":peers up interested"
|
|
|
|
":peers up unchoked"
|
|
|
|
":peers up requests"
|
|
|
|
":peer disconnects"
|
|
|
|
":peers eof"
|
|
|
|
":peers connection reset"
|
|
|
|
":outstanding requests"
|
|
|
|
":outstanding end-game requests"
|
2011-02-11 18:39:22 +01:00
|
|
|
":outstanding writing blocks"
|
|
|
|
":reject piece picks"
|
|
|
|
":unchoke piece picks"
|
|
|
|
":incoming redundant piece picks"
|
|
|
|
":incoming piece picks"
|
|
|
|
":end game piece picks"
|
|
|
|
":snubbed piece picks"
|
2014-07-06 21:18:00 +02:00
|
|
|
":interesting piece picks"
|
|
|
|
":hash fail piece picks"
|
2011-02-14 05:48:02 +01:00
|
|
|
":connect timeouts"
|
|
|
|
":uninteresting peers disconnect"
|
2011-02-14 06:38:59 +01:00
|
|
|
":timeout peers"
|
2011-02-11 18:39:22 +01:00
|
|
|
":% failed payload bytes"
|
|
|
|
":% wasted payload bytes"
|
|
|
|
":% protocol bytes"
|
2011-03-11 08:37:12 +01:00
|
|
|
":disk read time"
|
|
|
|
":disk write time"
|
|
|
|
":disk queue size"
|
2014-07-06 21:18:00 +02:00
|
|
|
":queued disk bytes"
|
2011-03-11 08:37:12 +01:00
|
|
|
":read cache hits"
|
|
|
|
":disk block read"
|
2011-03-12 22:41:05 +01:00
|
|
|
":disk block written"
|
2011-03-13 05:34:57 +01:00
|
|
|
":failed bytes"
|
|
|
|
":redundant bytes"
|
2011-03-13 20:06:19 +01:00
|
|
|
":error torrents"
|
2011-03-14 04:35:18 +01:00
|
|
|
":read disk cache size"
|
|
|
|
":disk cache size"
|
|
|
|
":disk buffer allocations"
|
2011-03-14 06:21:46 +01:00
|
|
|
":disk hash time"
|
2011-03-17 06:31:06 +01:00
|
|
|
":connection attempts"
|
|
|
|
":banned peers"
|
|
|
|
":banned for hash failure"
|
|
|
|
":cache size"
|
|
|
|
":max connections"
|
|
|
|
":connect candidates"
|
2014-07-06 21:18:00 +02:00
|
|
|
":cache trim low watermark"
|
2011-03-20 06:47:27 +01:00
|
|
|
":% read time"
|
|
|
|
":% write time"
|
|
|
|
":% hash time"
|
|
|
|
":disk read back"
|
|
|
|
":% read back"
|
2011-03-20 10:04:03 +01:00
|
|
|
":disk read queue size"
|
2011-03-25 08:49:32 +01:00
|
|
|
":tick interval"
|
|
|
|
":tick residual"
|
2011-03-27 10:21:26 +02:00
|
|
|
":max unchoked"
|
2011-03-27 22:58:43 +02:00
|
|
|
":smooth upload rate"
|
|
|
|
":smooth download rate"
|
2011-06-13 18:20:21 +02:00
|
|
|
":num end-game peers"
|
2011-06-20 06:33:46 +02:00
|
|
|
":TCP up rate"
|
|
|
|
":TCP down rate"
|
|
|
|
":TCP up limit"
|
2011-06-21 09:44:13 +02:00
|
|
|
":TCP down limit"
|
2011-06-20 06:33:46 +02:00
|
|
|
":uTP up rate"
|
|
|
|
":uTP down rate"
|
2011-06-21 09:44:13 +02:00
|
|
|
":uTP peak send delay"
|
|
|
|
":uTP avg send delay"
|
2011-09-28 02:03:12 +02:00
|
|
|
":uTP peak recv delay"
|
|
|
|
":uTP avg recv delay"
|
2011-06-26 21:00:40 +02:00
|
|
|
":read ops/s"
|
|
|
|
":write ops/s"
|
2011-06-29 00:20:34 +02:00
|
|
|
":active resident pages"
|
|
|
|
":inactive resident pages"
|
|
|
|
":pinned resident pages"
|
|
|
|
":free pages"
|
|
|
|
":pageins"
|
|
|
|
":pageouts"
|
|
|
|
":page faults"
|
2011-07-03 19:21:45 +02:00
|
|
|
":smooth read ops/s"
|
|
|
|
":smooth write ops/s"
|
2014-07-06 21:18:00 +02:00
|
|
|
":pinned blocks"
|
|
|
|
":num partial pieces"
|
|
|
|
":num downloading partial pieces"
|
|
|
|
":num full partial pieces"
|
|
|
|
":num finished partial pieces"
|
|
|
|
":num 0-priority partial pieces"
|
|
|
|
":allocated jobs"
|
|
|
|
":allocated read jobs"
|
|
|
|
":allocated write jobs"
|
2011-09-23 22:57:42 +02:00
|
|
|
":pending reading bytes"
|
2011-10-17 07:17:21 +02:00
|
|
|
":read_counter"
|
|
|
|
":write_counter"
|
|
|
|
":tick_counter"
|
|
|
|
":lsd_counter"
|
|
|
|
":lsd_peer_counter"
|
|
|
|
":udp_counter"
|
|
|
|
":accept_counter"
|
|
|
|
":disk_queue_counter"
|
2014-07-06 21:18:00 +02:00
|
|
|
":disk_counter"
|
2011-10-17 08:54:02 +02:00
|
|
|
":up 8:up 16:up 32:up 64:up 128:up 256:up 512:up 1024:up 2048:up 4096:up 8192:up 16384:up 32768:up 65536:up 131072:up 262144:up 524288:up 1048576"
|
|
|
|
":down 8:down 16:down 32:down 64:down 128:down 256:down 512:down 1024:down 2048:down 4096:down 8192:down 16384:down 32768:down 65536:down 131072:down 262144:down 524288:down 1048576"
|
2011-10-17 19:12:08 +02:00
|
|
|
":network thread system time"
|
|
|
|
":network thread user+system time"
|
2011-11-16 03:29:59 +01:00
|
|
|
|
|
|
|
":redundant timed-out"
|
|
|
|
":redundant cancelled"
|
|
|
|
":redundant unknown"
|
|
|
|
":redundant seed"
|
|
|
|
":redundant end-game"
|
|
|
|
":redundant closing"
|
2011-11-24 18:50:57 +01:00
|
|
|
":no memory peer errors"
|
|
|
|
":too many peers"
|
|
|
|
":transport timeout peers"
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
":arc LRU write pieces"
|
|
|
|
":arc LRU volatile pieces"
|
|
|
|
":arc LRU pieces"
|
|
|
|
":arc LRU ghost pieces"
|
|
|
|
":arc LFU pieces"
|
|
|
|
":arc LFU ghost pieces"
|
|
|
|
|
2012-01-17 04:11:16 +01:00
|
|
|
":uTP idle"
|
|
|
|
":uTP syn-sent"
|
|
|
|
":uTP connected"
|
|
|
|
":uTP fin-sent"
|
|
|
|
":uTP close-wait"
|
2012-03-02 09:52:54 +01:00
|
|
|
|
|
|
|
":tcp peers"
|
|
|
|
":utp peers"
|
|
|
|
|
|
|
|
":connection refused peers"
|
|
|
|
":connection aborted peers"
|
|
|
|
":permission denied peers"
|
|
|
|
":no buffer peers"
|
|
|
|
":host unreachable peers"
|
|
|
|
":broken pipe peers"
|
|
|
|
":address in use peers"
|
|
|
|
":access denied peers"
|
|
|
|
":invalid argument peers"
|
|
|
|
":operation aborted peers"
|
|
|
|
|
|
|
|
":error incoming peers"
|
|
|
|
":error outgoing peers"
|
|
|
|
":error rc4 peers"
|
|
|
|
":error encrypted peers"
|
|
|
|
":error tcp peers"
|
|
|
|
":error utp peers"
|
2012-03-04 12:18:27 +01:00
|
|
|
|
|
|
|
":total peers"
|
2012-03-05 11:05:20 +01:00
|
|
|
":pending incoming block requests"
|
|
|
|
":average pending incoming block requests"
|
2012-03-06 11:34:18 +01:00
|
|
|
|
|
|
|
":torrents want more peers"
|
|
|
|
":average peers per limit"
|
2012-03-09 07:24:01 +01:00
|
|
|
|
|
|
|
":piece requests"
|
|
|
|
":max piece requests"
|
|
|
|
":invalid piece requests"
|
|
|
|
":choked piece requests"
|
|
|
|
":cancelled piece requests"
|
|
|
|
":piece rejects"
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
":total pieces"
|
|
|
|
":pieces flushed"
|
|
|
|
":pieces passed"
|
|
|
|
":pieces failed"
|
|
|
|
|
2012-03-09 18:03:10 +01:00
|
|
|
":peers up send buffer"
|
|
|
|
|
2013-09-14 12:06:48 +02:00
|
|
|
":packet_loss"
|
|
|
|
":timeout"
|
|
|
|
":packets_in"
|
|
|
|
":packets_out"
|
|
|
|
":fast_retransmit"
|
|
|
|
":packet_resend"
|
|
|
|
":samples_above_target"
|
|
|
|
":samples_below_target"
|
|
|
|
":payload_pkts_in"
|
|
|
|
":payload_pkts_out"
|
|
|
|
":invalid_pkts_in"
|
|
|
|
":redundant_pkts_in"
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
":loaded torrents"
|
|
|
|
":pinned torrents"
|
|
|
|
":loaded torrent churn"
|
|
|
|
|
|
|
|
":num_incoming_choke"
|
|
|
|
":num_incoming_unchoke"
|
|
|
|
":num_incoming_interested"
|
|
|
|
":num_incoming_not_interested"
|
|
|
|
":num_incoming_have"
|
|
|
|
":num_incoming_bitfield"
|
|
|
|
":num_incoming_request"
|
|
|
|
":num_incoming_piece"
|
|
|
|
":num_incoming_cancel"
|
|
|
|
":num_incoming_dht_port"
|
|
|
|
":num_incoming_suggest"
|
|
|
|
":num_incoming_have_all"
|
|
|
|
":num_incoming_have_none"
|
|
|
|
":num_incoming_reject"
|
|
|
|
":num_incoming_allowed_fast"
|
|
|
|
":num_incoming_ext_handshake"
|
|
|
|
":num_incoming_pex"
|
|
|
|
":num_incoming_metadata"
|
|
|
|
":num_incoming_extended"
|
|
|
|
|
|
|
|
":num_outgoing_choke"
|
|
|
|
":num_outgoing_unchoke"
|
|
|
|
":num_outgoing_interested"
|
|
|
|
":num_outgoing_not_interested"
|
|
|
|
":num_outgoing_have"
|
|
|
|
":num_outgoing_bitfield"
|
|
|
|
":num_outgoing_request"
|
|
|
|
":num_outgoing_piece"
|
|
|
|
":num_outgoing_cancel"
|
|
|
|
":num_outgoing_dht_port"
|
|
|
|
":num_outgoing_suggest"
|
|
|
|
":num_outgoing_have_all"
|
|
|
|
":num_outgoing_have_none"
|
|
|
|
":num_outgoing_reject"
|
|
|
|
":num_outgoing_allowed_fast"
|
|
|
|
":num_outgoing_ext_handshake"
|
|
|
|
":num_outgoing_pex"
|
|
|
|
":num_outgoing_metadata"
|
|
|
|
":num_outgoing_extended"
|
|
|
|
|
|
|
|
":blocked jobs"
|
|
|
|
":num writing threads"
|
|
|
|
":num running threads"
|
|
|
|
":incoming connections"
|
|
|
|
|
|
|
|
":move_storage"
|
|
|
|
":release_files"
|
|
|
|
":delete_files"
|
|
|
|
":check_fastresume"
|
|
|
|
":save_resume_data"
|
|
|
|
":rename_file"
|
|
|
|
":stop_torrent"
|
|
|
|
":file_priority"
|
|
|
|
":clear_piece"
|
|
|
|
|
|
|
|
":piece_picker_partial_loops"
|
|
|
|
":piece_picker_suggest_loops"
|
|
|
|
":piece_picker_sequential_loops"
|
|
|
|
":piece_picker_reverse_rare_loops"
|
|
|
|
":piece_picker_rare_loops"
|
|
|
|
":piece_picker_rand_start_loops"
|
|
|
|
":piece_picker_rand_loops"
|
|
|
|
":piece_picker_busy_loops"
|
|
|
|
|
|
|
|
":connection attempt loops"
|
|
|
|
|
2014-07-29 00:18:06 +02:00
|
|
|
":request latency"
|
|
|
|
|
2011-02-11 18:39:22 +01:00
|
|
|
"\n\n", m_stats_logger);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::queue_async_resume_data(boost::shared_ptr<torrent> const& t)
|
2012-11-03 04:50:12 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
INVARIANT_CHECK;
|
2012-11-03 04:50:12 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int loaded_limit = m_settings.get_int(settings_pack::active_loaded_limit);
|
|
|
|
|
2014-07-21 05:03:59 +02:00
|
|
|
if (m_num_save_resume + m_alerts.num_queued_resume() >= loaded_limit
|
2014-07-06 21:18:00 +02:00
|
|
|
&& m_user_load_torrent
|
|
|
|
&& loaded_limit > 0)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(t);
|
|
|
|
// do loaded torrents first, otherwise they'll just be
|
|
|
|
// evicted and have to be loaded again
|
|
|
|
if (t->is_loaded())
|
|
|
|
m_save_resume_queue.push_front(t);
|
|
|
|
else
|
|
|
|
m_save_resume_queue.push_back(t);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t->do_async_save_resume_data())
|
|
|
|
++m_num_save_resume;
|
2012-11-03 04:50:12 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// this is called whenever a save_resume_data comes back
|
|
|
|
// from the disk thread
|
|
|
|
void session_impl::done_async_resume()
|
2012-11-03 04:50:12 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(m_num_save_resume > 0);
|
|
|
|
--m_num_save_resume;
|
2012-11-03 04:50:12 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// this is called when one or all save resume alerts are
|
|
|
|
// popped off the alert queue
|
2014-07-21 05:03:59 +02:00
|
|
|
void session_impl::async_resume_dispatched(int num_popped_resume)
|
2012-08-03 07:13:40 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
INVARIANT_CHECK;
|
2012-08-03 07:13:40 +02:00
|
|
|
|
2014-07-21 05:03:59 +02:00
|
|
|
int num_queued_resume = m_alerts.num_queued_resume();
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
int loaded_limit = m_settings.get_int(settings_pack::active_loaded_limit);
|
|
|
|
while (!m_save_resume_queue.empty()
|
2014-07-21 05:03:59 +02:00
|
|
|
&& (m_num_save_resume + num_queued_resume < loaded_limit
|
2014-07-06 21:18:00 +02:00
|
|
|
|| loaded_limit == 0))
|
|
|
|
{
|
|
|
|
boost::shared_ptr<torrent> t = m_save_resume_queue.front();
|
|
|
|
m_save_resume_queue.erase(m_save_resume_queue.begin());
|
|
|
|
if (t->do_async_save_resume_data())
|
|
|
|
++m_num_save_resume;
|
|
|
|
}
|
2012-08-03 07:13:40 +02:00
|
|
|
}
|
|
|
|
|
2010-12-04 23:20:31 +01:00
|
|
|
void session_impl::init()
|
2010-09-25 22:07:27 +02:00
|
|
|
{
|
2010-10-17 18:15:32 +02:00
|
|
|
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" *** session thread init");
|
2010-10-17 18:15:32 +02:00
|
|
|
#endif
|
|
|
|
|
2010-09-25 22:07:27 +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
|
|
|
|
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
2010-12-24 19:15:01 +01:00
|
|
|
async_inc_threads();
|
2010-11-28 02:47:30 +01:00
|
|
|
add_outstanding_async("session_impl::on_tick");
|
|
|
|
#endif
|
2010-09-25 22:07:27 +02:00
|
|
|
error_code ec;
|
2010-10-17 18:15:32 +02:00
|
|
|
m_io_service.post(boost::bind(&session_impl::on_tick, this, ec));
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::on_lsd_announce");
|
|
|
|
#endif
|
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);
|
|
|
|
m_lsd_announce_timer.expires_from_now(seconds(delay), ec);
|
|
|
|
m_lsd_announce_timer.async_wait(
|
2010-04-30 21:08:16 +02:00
|
|
|
boost::bind(&session_impl::on_lsd_announce, this, _1));
|
2010-09-25 22:07:27 +02:00
|
|
|
TORRENT_ASSERT(!ec);
|
2010-02-05 09:23:17 +01:00
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2012-08-03 07:13:40 +02:00
|
|
|
update_dht_announce_interval();
|
2010-02-14 02:39:55 +01:00
|
|
|
#endif
|
|
|
|
|
2010-10-17 18:15:32 +02:00
|
|
|
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" done starting session");
|
2010-10-17 18:15:32 +02:00
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
void session_impl::save_state(entry* eptr, boost::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;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
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
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
entry::dictionary_type& dht_sett = e["dht"].dict();
|
|
|
|
|
|
|
|
dht_sett["max_peers_reply"] = m_dht_settings.max_peers_reply;
|
|
|
|
dht_sett["search_branching"] = m_dht_settings.search_branching;
|
|
|
|
dht_sett["max_fail_count"] = m_dht_settings.max_fail_count;
|
|
|
|
dht_sett["max_torrents"] = m_dht_settings.max_torrents;
|
|
|
|
dht_sett["max_dht_items"] = m_dht_settings.max_dht_items;
|
|
|
|
dht_sett["max_torrent_search_reply"] = m_dht_settings.max_torrent_search_reply;
|
|
|
|
dht_sett["restrict_routing_ips"] = m_dht_settings.restrict_routing_ips;
|
|
|
|
dht_sett["extended_routing_table"] = m_dht_settings.extended_routing_table;
|
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
|
|
|
{
|
2010-07-14 06:16:38 +02:00
|
|
|
e["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-18 04:41:54 +01:00
|
|
|
if (flags & session::save_feeds)
|
|
|
|
{
|
|
|
|
entry::list_type& feeds = e["feeds"].list();
|
|
|
|
for (std::vector<boost::shared_ptr<feed> >::const_iterator i =
|
|
|
|
m_feeds.begin(), end(m_feeds.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
feeds.push_back(entry());
|
|
|
|
(*i)->save_state(feeds.back());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-29 11:37:21 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
for (ses_extension_list_t::const_iterator i = m_ses_extensions.begin()
|
|
|
|
, end(m_ses_extensions.end()); i != end; ++i)
|
|
|
|
{
|
2011-02-25 18:00:36 +01:00
|
|
|
TORRENT_TRY {
|
|
|
|
(*i)->save_state(*eptr);
|
|
|
|
} TORRENT_CATCH(std::exception&) {}
|
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-07-06 21:18:00 +02:00
|
|
|
proxy_settings ret;
|
2010-09-25 22:07:27 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
ret.hostname = m_settings.get_str(settings_pack::proxy_hostname);
|
|
|
|
ret.username = m_settings.get_str(settings_pack::proxy_username);
|
|
|
|
ret.password = m_settings.get_str(settings_pack::proxy_password);
|
|
|
|
ret.type = m_settings.get_int(settings_pack::proxy_type);
|
|
|
|
ret.port = m_settings.get_int(settings_pack::proxy_port);
|
|
|
|
ret.proxy_hostnames = m_settings.get_bool(settings_pack::proxy_hostnames);
|
|
|
|
ret.proxy_peer_connections = m_settings.get_bool(
|
|
|
|
settings_pack::proxy_peer_connections);
|
|
|
|
return ret;
|
2010-08-23 08:27:18 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
void session_impl::load_state(lazy_entry const* e)
|
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
|
|
|
|
2009-12-03 06:11:57 +01:00
|
|
|
lazy_entry const* settings;
|
2010-07-14 06:16:38 +02:00
|
|
|
if (e->type() != lazy_entry::dict_t) return;
|
2010-03-04 17:42:39 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
// load from the old settings names
|
|
|
|
settings = e->dict_find_dict("dht");
|
|
|
|
if (settings)
|
|
|
|
{
|
|
|
|
lazy_entry const* val;
|
|
|
|
val = settings->dict_find_int("max_peers_reply");
|
|
|
|
if (val) m_dht_settings.max_peers_reply = val->int_value();
|
|
|
|
val = settings->dict_find_int("search_branching");
|
|
|
|
if (val) m_dht_settings.search_branching = val->int_value();
|
|
|
|
val = settings->dict_find_int("max_fail_count");
|
|
|
|
if (val) m_dht_settings.max_fail_count = val->int_value();
|
|
|
|
val = settings->dict_find_int("max_torrents");
|
|
|
|
if (val) m_dht_settings.max_torrents = val->int_value();
|
|
|
|
val = settings->dict_find_int("max_dht_items");
|
|
|
|
if (val) m_dht_settings.max_dht_items = val->int_value();
|
|
|
|
val = settings->dict_find_int("max_torrent_search_reply");
|
|
|
|
if (val) m_dht_settings.max_torrent_search_reply = val->int_value();
|
|
|
|
val = settings->dict_find_int("restrict_routing_ips");
|
|
|
|
if (val) m_dht_settings.restrict_routing_ips = val->int_value();
|
|
|
|
val = settings->dict_find_int("extended_routing_table");
|
|
|
|
if (val) m_dht_settings.extended_routing_table = val->int_value();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
settings = e->dict_find_dict("proxy");
|
|
|
|
if (settings)
|
|
|
|
{
|
|
|
|
lazy_entry const* val;
|
|
|
|
val = settings->dict_find_int("port");
|
|
|
|
if (val) m_settings.set_int(settings_pack::proxy_port, val->int_value());
|
|
|
|
val = settings->dict_find_int("type");
|
|
|
|
if (val) m_settings.set_int(settings_pack::proxy_type, val->int_value());
|
|
|
|
val = settings->dict_find_int("proxy_hostnames");
|
|
|
|
if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val->int_value());
|
|
|
|
val = settings->dict_find_int("proxy_peer_connections");
|
|
|
|
if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val->int_value());
|
|
|
|
val = settings->dict_find_string("hostname");
|
|
|
|
if (val) m_settings.set_str(settings_pack::proxy_hostname, val->string_value());
|
|
|
|
val = settings->dict_find_string("password");
|
|
|
|
if (val) m_settings.set_str(settings_pack::proxy_password, val->string_value());
|
|
|
|
val = settings->dict_find_string("username");
|
|
|
|
if (val) m_settings.set_str(settings_pack::proxy_username, val->string_value());
|
|
|
|
}
|
|
|
|
|
|
|
|
settings = e->dict_find_dict("encryption");
|
|
|
|
if (settings)
|
2009-12-03 06:11:57 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
lazy_entry const* val;
|
|
|
|
val = settings->dict_find_int("prefer_rc4");
|
|
|
|
if (val) m_settings.set_bool(settings_pack::prefer_rc4, val->int_value());
|
|
|
|
val = settings->dict_find_int("out_enc_policy");
|
|
|
|
if (val) m_settings.set_int(settings_pack::out_enc_policy, val->int_value());
|
|
|
|
val = settings->dict_find_int("in_enc_policy");
|
|
|
|
if (val) m_settings.set_int(settings_pack::in_enc_policy, val->int_value());
|
|
|
|
val = settings->dict_find_int("allowed_enc_level");
|
|
|
|
if (val) m_settings.set_int(settings_pack::allowed_enc_level, val->int_value());
|
2009-12-03 06:11:57 +01:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
2010-10-09 21:09:38 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
settings = e->dict_find_dict("settings");
|
|
|
|
if (settings)
|
|
|
|
{
|
|
|
|
settings_pack* pack = load_pack_from_dict(settings);
|
|
|
|
apply_settings_pack(pack);
|
|
|
|
}
|
2010-10-09 21:09:38 +02:00
|
|
|
|
|
|
|
// 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();
|
2014-07-06 21:18:00 +02:00
|
|
|
m_udp_socket.set_proxy_settings(proxy());
|
2010-10-09 21:09:38 +02:00
|
|
|
|
2009-12-03 06:11:57 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2010-07-14 06:16:38 +02:00
|
|
|
settings = e->dict_find_dict("dht state");
|
2010-03-04 17:42:39 +01:00
|
|
|
if (settings)
|
|
|
|
{
|
|
|
|
m_dht_state = *settings;
|
|
|
|
}
|
2009-12-03 06:11:57 +01:00
|
|
|
#endif
|
|
|
|
|
2011-01-18 04:41:54 +01:00
|
|
|
settings = e->dict_find_list("feeds");
|
|
|
|
if (settings)
|
|
|
|
{
|
|
|
|
m_feeds.reserve(settings->list_size());
|
|
|
|
for (int i = 0; i < settings->list_size(); ++i)
|
|
|
|
{
|
|
|
|
if (settings->list_at(i)->type() != lazy_entry::dict_t) continue;
|
2012-02-21 00:44:34 +01:00
|
|
|
boost::shared_ptr<feed> f(new_feed(*this, feed_settings()));
|
2011-01-18 04:41:54 +01:00
|
|
|
f->load_state(*settings->list_at(i));
|
2011-03-21 05:59:45 +01:00
|
|
|
f->update_feed();
|
2011-01-18 04:41:54 +01:00
|
|
|
m_feeds.push_back(f);
|
|
|
|
}
|
2011-03-21 05:59:45 +01:00
|
|
|
update_rss_feeds();
|
2011-01-18 04:41:54 +01:00
|
|
|
}
|
2011-01-29 11:37:21 +01:00
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
for (ses_extension_list_t::iterator i = m_ses_extensions.begin()
|
|
|
|
, end(m_ses_extensions.end()); i != end; ++i)
|
|
|
|
{
|
2011-02-25 18:00:36 +01:00
|
|
|
TORRENT_TRY {
|
|
|
|
(*i)->load_state(*e);
|
|
|
|
} TORRENT_CATCH(std::exception&) {}
|
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
|
|
|
|
|
|
|
typedef boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> ext_function_t;
|
|
|
|
|
|
|
|
struct session_plugin_wrapper : plugin
|
|
|
|
{
|
|
|
|
session_plugin_wrapper(ext_function_t const& f) : m_f(f) {}
|
|
|
|
|
|
|
|
virtual boost::shared_ptr<torrent_plugin> new_torrent(torrent* t, void* user)
|
|
|
|
{ return m_f(t, user); }
|
|
|
|
ext_function_t m_f;
|
|
|
|
};
|
|
|
|
|
|
|
|
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());
|
2010-09-25 19:46:13 +02:00
|
|
|
TORRENT_ASSERT_VAL(ext, ext);
|
2008-09-22 01:19:58 +02:00
|
|
|
|
2013-01-07 05:19:19 +01:00
|
|
|
boost::shared_ptr<plugin> p(new session_plugin_wrapper(ext));
|
2008-09-22 01:19:58 +02:00
|
|
|
|
2013-01-07 05:19:19 +01:00
|
|
|
m_ses_extensions.push_back(p);
|
2006-11-14 01:08:16 +01:00
|
|
|
}
|
2011-01-29 11:37:21 +01:00
|
|
|
|
|
|
|
void session_impl::add_ses_extension(boost::shared_ptr<plugin> ext)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2011-01-29 11:37:21 +01:00
|
|
|
TORRENT_ASSERT_VAL(ext, ext);
|
|
|
|
|
|
|
|
m_ses_extensions.push_back(ext);
|
|
|
|
m_alerts.add_extension(ext);
|
2014-02-21 05:30:59 +01:00
|
|
|
ext->added(this);
|
2011-01-29 11:37:21 +01:00
|
|
|
}
|
2006-11-14 01:08:16 +01:00
|
|
|
#endif
|
|
|
|
|
2011-01-18 04:41:54 +01:00
|
|
|
feed_handle session_impl::add_feed(feed_settings const& sett)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2011-01-18 04:41:54 +01:00
|
|
|
|
|
|
|
// look for duplicates. If we already have a feed with this
|
|
|
|
// URL, return a handle to the existing one
|
|
|
|
for (std::vector<boost::shared_ptr<feed> >::const_iterator i
|
|
|
|
= m_feeds.begin(), end(m_feeds.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if (sett.url != (*i)->m_settings.url) continue;
|
|
|
|
return feed_handle(*i);
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::shared_ptr<feed> f(new_feed(*this, sett));
|
|
|
|
m_feeds.push_back(f);
|
|
|
|
update_rss_feeds();
|
|
|
|
return feed_handle(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::remove_feed(feed_handle h)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2011-01-18 04:41:54 +01:00
|
|
|
|
|
|
|
boost::shared_ptr<feed> f = h.m_feed_ptr.lock();
|
|
|
|
if (!f) return;
|
|
|
|
|
|
|
|
std::vector<boost::shared_ptr<feed> >::iterator i
|
|
|
|
= std::find(m_feeds.begin(), m_feeds.end(), f);
|
|
|
|
|
|
|
|
if (i == m_feeds.end()) return;
|
|
|
|
|
|
|
|
m_feeds.erase(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::get_feeds(std::vector<feed_handle>* ret) const
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2011-01-18 04:41:54 +01:00
|
|
|
|
|
|
|
ret->clear();
|
|
|
|
ret->reserve(m_feeds.size());
|
|
|
|
for (std::vector<boost::shared_ptr<feed> >::const_iterator i = m_feeds.begin()
|
|
|
|
, end(m_feeds.end()); i != end; ++i)
|
|
|
|
ret->push_back(feed_handle(*i));
|
|
|
|
}
|
|
|
|
|
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;
|
2008-12-30 09:20:25 +01:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_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;
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
torrent& t = *i->second;
|
2011-06-03 10:40:13 +02:00
|
|
|
t.do_pause();
|
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;
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
torrent& t = *i->second;
|
|
|
|
t.do_resume();
|
2014-07-06 21:18:00 +02:00
|
|
|
if (t.should_check_files()) t.start_checking();
|
2008-06-29 21:08:30 +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;
|
2008-12-30 09:20:25 +01:00
|
|
|
#if defined TORRENT_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" *** ABORT CALLED ***");
|
2007-10-07 20:06:56 +02:00
|
|
|
#endif
|
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;
|
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
|
|
|
|
2013-08-21 17:55:24 +02:00
|
|
|
for (std::set<boost::shared_ptr<socket_type> >::iterator i = m_incoming_sockets.begin()
|
|
|
|
, end(m_incoming_sockets.end()); i != end; ++i)
|
|
|
|
{
|
2013-09-14 12:26:55 +02:00
|
|
|
(*i)->close(ec);
|
|
|
|
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
|
|
|
|
for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
{
|
2008-04-07 03:22:26 +02:00
|
|
|
i->sock->close(ec);
|
2010-12-24 19:15:01 +01:00
|
|
|
TORRENT_ASSERT(!ec);
|
2007-10-26 09:14:19 +02:00
|
|
|
}
|
2010-12-24 19:15:01 +01:00
|
|
|
m_listen_sockets.clear();
|
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
|
|
|
|
2007-10-29 01:29:43 +01:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" aborting all torrents (%d)", m_torrents.size());
|
2007-10-29 01:29:43 +01:00
|
|
|
#endif
|
2007-10-07 20:06:56 +02:00
|
|
|
// abort all torrents
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
i->second->abort();
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
m_torrents.clear();
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2007-10-29 01:29:43 +01:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_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();
|
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" aborting all connections (%d)", 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
|
2007-11-02 01:27:53 +01:00
|
|
|
int conn = m_connections.size();
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
(*m_connections.begin())->disconnect(errors::stopping_torrent, peer_connection::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
|
|
|
|
2009-04-26 02:21:59 +02:00
|
|
|
m_download_rate.close();
|
|
|
|
m_upload_rate.close();
|
2010-05-30 03:33:03 +02:00
|
|
|
|
|
|
|
// #error closing the udp socket here means that
|
|
|
|
// the uTP connections cannot be closed gracefully
|
|
|
|
m_udp_socket.close();
|
|
|
|
m_external_udp_port = 0;
|
2010-07-14 06:16:38 +02:00
|
|
|
|
2013-12-05 08:42:32 +01:00
|
|
|
m_undead_peers.clear();
|
|
|
|
|
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).
|
|
|
|
m_disk_thread.set_num_threads(0, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::insert_peer(boost::shared_ptr<peer_connection> const& c)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(!c->m_in_constructor);
|
|
|
|
m_connections.insert(c);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
i->second->ip_filter_updated();
|
2007-06-01 03:05:57 +02:00
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
void session_impl::set_ip_filter(ip_filter const& f)
|
|
|
|
{
|
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)
|
2014-07-06 21:18:00 +02:00
|
|
|
i->second->port_filter_updated();
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2009-07-21 03:52:37 +02:00
|
|
|
ip_filter const& session_impl::get_ip_filter() const
|
|
|
|
{
|
2009-07-21 06:42:19 +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
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
return m_port_filter;
|
2010-03-10 08:14:10 +01:00
|
|
|
}
|
|
|
|
|
2013-09-03 10:39:30 +02:00
|
|
|
template <class Socket>
|
|
|
|
void static set_socket_buffer_size(Socket& s, session_settings const& sett, error_code& ec)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
int snd_size = sett.get_int(settings_pack::send_socket_buffer_size);
|
|
|
|
if (snd_size)
|
2013-09-03 10:39:30 +02:00
|
|
|
{
|
|
|
|
stream_socket::send_buffer_size prev_option;
|
|
|
|
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
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
stream_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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
int recv_size = sett.get_int(settings_pack::recv_socket_buffer_size);
|
|
|
|
if (recv_size)
|
2013-09-03 10:39:30 +02:00
|
|
|
{
|
|
|
|
stream_socket::receive_buffer_size prev_option;
|
|
|
|
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
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
stream_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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int session_impl::create_peer_class(char const* name)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
return m_classes.new_peer_class(name);
|
|
|
|
}
|
2010-10-09 21:09:38 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::delete_peer_class(int cid)
|
|
|
|
{
|
|
|
|
// if you hit this assert, you're deleting a non-existent peer class
|
|
|
|
TORRENT_ASSERT(m_classes.at(cid));
|
|
|
|
if (m_classes.at(cid) == 0) return;
|
|
|
|
m_classes.decref(cid);
|
|
|
|
}
|
2010-02-09 04:04:41 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
peer_class_info session_impl::get_peer_class(int cid)
|
|
|
|
{
|
|
|
|
peer_class_info ret;
|
|
|
|
peer_class* pc = m_classes.at(cid);
|
|
|
|
// if you hit this assert, you're passing in an invalid cid
|
|
|
|
TORRENT_ASSERT(pc);
|
|
|
|
if (pc == 0)
|
2010-01-31 17:35:38 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifdef TORRENT_DEBUG
|
|
|
|
// make it obvious that the return value is undefined
|
2014-08-16 22:26:00 +02:00
|
|
|
ret.upload_limit = random();
|
|
|
|
ret.download_limit = random();
|
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;
|
|
|
|
#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
|
|
|
|
, std::string login, boost::weak_ptr<request_callback> c, boost::uint32_t key)
|
|
|
|
{
|
|
|
|
req.listen_port = listen_port();
|
|
|
|
if (m_key)
|
|
|
|
req.key = m_key;
|
|
|
|
else
|
|
|
|
req.key = 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
|
|
|
|
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
|
2014-07-06 21:18:00 +02:00
|
|
|
if (is_any(req.bind_ip)) req.bind_ip = m_listen_interface.address();
|
2014-10-03 22:56:57 +02:00
|
|
|
m_tracker_manager.queue_request(get_io_service(), req
|
2014-07-06 21:18:00 +02:00
|
|
|
, login, c);
|
|
|
|
}
|
2010-02-13 17:29:17 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::set_peer_class(int cid, peer_class_info const& pci)
|
|
|
|
{
|
|
|
|
peer_class* pc = m_classes.at(cid);
|
|
|
|
// if you hit this assert, you're passing in an invalid cid
|
|
|
|
TORRENT_ASSERT(pc);
|
|
|
|
if (pc == 0) 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_peer_classes(peer_class_set* s, address const& a, int st)
|
|
|
|
{
|
|
|
|
boost::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
|
|
|
|
const static int mapping[] = { 0, 0, 0, 0, 1, 4, 2, 2, 2, 3};
|
|
|
|
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);
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
if (m_classes.at(i) == 0) continue;
|
|
|
|
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));
|
|
|
|
if (pc == 0) continue;
|
|
|
|
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
|
|
|
// the back argument determines whether this bump causes the torrent
|
|
|
|
// to be the most recently used or the least recently used. Putting
|
|
|
|
// the torrent at the back of the queue makes it the most recently
|
|
|
|
// used and the least likely to be evicted. This is the default.
|
|
|
|
// if back is false, the torrent is moved to the front of the queue,
|
|
|
|
// and made the most likely to be evicted. This is used for torrents
|
|
|
|
// that are paused, to give up their slot among the loaded torrents
|
|
|
|
void session_impl::bump_torrent(torrent* t, bool back)
|
|
|
|
{
|
|
|
|
if (t->is_aborted()) return;
|
2011-03-20 05:56:20 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
bool new_torrent = false;
|
2010-10-09 21:09:38 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// if t is the only torrent in the LRU list, both
|
|
|
|
// its prev and next links will be NULL, even though
|
|
|
|
// it's already in the list. Cover this case by also
|
|
|
|
// checking to see if it's the first item
|
|
|
|
if (t->next != NULL || t->prev != NULL || m_torrent_lru.front() == t)
|
|
|
|
{
|
|
|
|
#ifdef TORRENT_DEBUG
|
|
|
|
torrent* i = (torrent*)m_torrent_lru.front();
|
|
|
|
while (i != NULL && i != t) i = (torrent*)i->next;
|
|
|
|
TORRENT_ASSERT(i == t);
|
|
|
|
#endif
|
2010-10-09 21:09:38 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// this torrent is in the list already.
|
|
|
|
// first remove it
|
|
|
|
m_torrent_lru.erase(t);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
new_torrent = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// pinned torrents should not be part of the LRU, since
|
|
|
|
// the LRU is only used to evict torrents
|
|
|
|
if (t->is_pinned()) return;
|
|
|
|
|
|
|
|
if (back)
|
|
|
|
m_torrent_lru.push_back(t);
|
|
|
|
else
|
|
|
|
m_torrent_lru.push_front(t);
|
|
|
|
|
|
|
|
if (new_torrent) evict_torrents_except(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::evict_torrent(torrent* t)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(!t->is_pinned());
|
|
|
|
|
|
|
|
// if there's no user-load function set, we cannot evict
|
|
|
|
// torrents. The feature is not enabled
|
|
|
|
if (!m_user_load_torrent) return;
|
|
|
|
|
|
|
|
// if it's already evicted, there's nothing to do
|
|
|
|
if (!t->is_loaded() || !t->should_be_loaded()) return;
|
|
|
|
|
|
|
|
TORRENT_ASSERT(t->next != NULL || t->prev != NULL || m_torrent_lru.front() == t);
|
|
|
|
|
|
|
|
#if defined TORRENT_DEBUG && defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
|
|
|
torrent* i = (torrent*)m_torrent_lru.front();
|
|
|
|
while (i != NULL && i != t) i = (torrent*)i->next;
|
|
|
|
TORRENT_ASSERT(i == t);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int loaded_limit = m_settings.get_int(settings_pack::active_loaded_limit);
|
|
|
|
|
|
|
|
// 0 means unlimited, never evict enything
|
|
|
|
if (loaded_limit == 0) return;
|
|
|
|
|
|
|
|
if (m_torrent_lru.size() > loaded_limit)
|
2013-02-19 09:14:16 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
// just evict the torrent
|
2014-07-13 06:56:53 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::torrent_evicted_counter);
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(t->is_pinned() == false);
|
|
|
|
t->unload();
|
|
|
|
m_torrent_lru.erase(t);
|
|
|
|
return;
|
2013-02-19 09:14:16 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// move this torrent to be the first to be evicted whenever
|
|
|
|
// another torrent need its slot
|
|
|
|
bump_torrent(t, false);
|
|
|
|
}
|
2013-02-19 07:48:53 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::evict_torrents_except(torrent* ignore)
|
|
|
|
{
|
|
|
|
if (!m_user_load_torrent) return;
|
2013-02-19 07:48:53 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int loaded_limit = m_settings.get_int(settings_pack::active_loaded_limit);
|
|
|
|
|
|
|
|
// 0 means unlimited, never evict enything
|
|
|
|
if (loaded_limit == 0) return;
|
|
|
|
|
|
|
|
// if the torrent we're ignoring (i.e. making room for), allow
|
|
|
|
// one more torrent in the list.
|
|
|
|
if (ignore->next != NULL || ignore->prev != NULL || m_torrent_lru.front() == ignore)
|
2010-04-13 06:30:34 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifdef TORRENT_DEBUG
|
|
|
|
torrent* i = (torrent*)m_torrent_lru.front();
|
|
|
|
while (i != NULL && i != ignore) i = (torrent*)i->next;
|
|
|
|
TORRENT_ASSERT(i == ignore);
|
2010-04-13 06:30:34 +02:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
++loaded_limit;
|
2010-04-13 06:30:34 +02:00
|
|
|
}
|
2009-01-10 06:46:02 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
while (m_torrent_lru.size() >= loaded_limit)
|
2010-02-06 08:39:45 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
// we're at the limit of loaded torrents. Find the least important
|
|
|
|
// torrent and unload it. This is done with an LRU.
|
|
|
|
torrent* i = (torrent*)m_torrent_lru.front();
|
|
|
|
|
|
|
|
if (i == ignore)
|
|
|
|
{
|
|
|
|
i = (torrent*)i->next;
|
|
|
|
if (i == NULL) break;
|
|
|
|
}
|
2014-07-13 06:56:53 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::torrent_evicted_counter);
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(i->is_pinned() == false);
|
|
|
|
i->unload();
|
|
|
|
m_torrent_lru.erase(i);
|
2010-02-06 08:39:45 +01:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2010-02-06 08:39:45 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
bool session_impl::load_torrent(torrent* t)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(is_single_thread());
|
|
|
|
evict_torrents_except(t);
|
2010-02-09 04:04:41 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// we wouldn't be loading the torrent if it was already
|
|
|
|
// in the LRU (and loaded)
|
|
|
|
TORRENT_ASSERT(t->next == NULL && t->prev == NULL && m_torrent_lru.front() != t);
|
|
|
|
|
|
|
|
// now, load t into RAM
|
|
|
|
std::vector<char> buffer;
|
|
|
|
error_code ec;
|
|
|
|
m_user_load_torrent(t->info_hash(), buffer, ec);
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
t->set_error(ec, torrent::error_file_metadata);
|
|
|
|
t->pause(false);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool ret = t->load(buffer);
|
|
|
|
if (ret) bump_torrent(t);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::deferred_submit_jobs()
|
|
|
|
{
|
|
|
|
if (m_deferred_submit_disk_jobs) return;
|
|
|
|
m_deferred_submit_disk_jobs = true;
|
|
|
|
m_io_service.post(boost::bind(&session_impl::submit_disk_jobs, this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::submit_disk_jobs()
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(m_deferred_submit_disk_jobs);
|
|
|
|
m_deferred_submit_disk_jobs = false;
|
|
|
|
if (m_abort) return;
|
|
|
|
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);
|
|
|
|
if (pc == 0) continue;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool session_impl::use_quota_overhead(bandwidth_channel* ch, int channel, int amount)
|
|
|
|
{
|
|
|
|
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));
|
|
|
|
if (p == 0) continue;
|
|
|
|
bandwidth_channel* ch = &p->channel[peer_connection::download_channel];
|
|
|
|
if (use_quota_overhead(ch, peer_connection::download_channel, amount_down))
|
|
|
|
ret |= 1 << peer_connection::download_channel;
|
|
|
|
ch = &p->channel[peer_connection::upload_channel];
|
|
|
|
if (use_quota_overhead(ch, peer_connection::upload_channel, amount_up))
|
|
|
|
ret |= 1 << peer_connection::upload_channel;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// session_impl is responsible for deleting 'pack', but it
|
|
|
|
// will pass it on to the disk io thread, which will take
|
|
|
|
// over ownership of it
|
|
|
|
void session_impl::apply_settings_pack(settings_pack* pack)
|
|
|
|
{
|
|
|
|
bool reopen_listen_port =
|
|
|
|
(pack->has_val(settings_pack::ssl_listen)
|
|
|
|
&& pack->get_int(settings_pack::ssl_listen)
|
|
|
|
!= m_settings.get_int(settings_pack::ssl_listen))
|
|
|
|
|| (pack->has_val(settings_pack::listen_interfaces)
|
|
|
|
&& pack->get_str(settings_pack::listen_interfaces)
|
|
|
|
!= m_settings.get_str(settings_pack::listen_interfaces));
|
|
|
|
|
|
|
|
apply_pack(pack, m_settings, this);
|
|
|
|
m_disk_thread.set_settings(pack);
|
|
|
|
delete pack;
|
2013-08-18 00:29:34 +02:00
|
|
|
|
|
|
|
if (reopen_listen_port)
|
|
|
|
{
|
|
|
|
error_code ec;
|
2014-07-06 21:18:00 +02:00
|
|
|
open_listen_port();
|
2013-08-18 00:29:34 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
void session_impl::set_settings(libtorrent::session_settings const& s)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
TORRENT_ASSERT(is_single_thread());
|
|
|
|
settings_pack* p = load_pack_from_struct(m_settings, s);
|
|
|
|
apply_settings_pack(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
libtorrent::session_settings session_impl::deprecated_settings() const
|
|
|
|
{
|
|
|
|
libtorrent::session_settings ret;
|
|
|
|
|
|
|
|
load_struct_from_settings(m_settings, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-09-22 18:27:29 +02:00
|
|
|
tcp::endpoint session_impl::get_ipv6_interface() const
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2007-09-22 18:27:29 +02:00
|
|
|
return m_ipv6_interface;
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2009-04-12 02:37:06 +02:00
|
|
|
tcp::endpoint session_impl::get_ipv4_interface() const
|
|
|
|
{
|
|
|
|
return m_ipv4_interface;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
enum { listen_no_system_port = 0x02 };
|
|
|
|
|
|
|
|
void session_impl::setup_listener(listen_socket_t* s, std::string const& device
|
|
|
|
, bool ipv4, int port, int& retries, int flags, error_code& ec)
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
2013-06-04 02:35:42 +02:00
|
|
|
int last_op = 0;
|
2013-10-06 08:32:33 +02:00
|
|
|
listen_failed_alert::socket_type_t sock_type = s->ssl ? listen_failed_alert::tcp_ssl : listen_failed_alert::tcp;
|
2011-09-12 05:51:49 +02:00
|
|
|
s->sock.reset(new socket_acceptor(m_io_service));
|
2014-07-06 21:18:00 +02:00
|
|
|
s->sock->open(ipv4 ? tcp::v4() : tcp::v6(), ec);
|
2013-06-04 02:35:42 +02:00
|
|
|
last_op = listen_failed_alert::open;
|
2010-08-25 08:22:49 +02:00
|
|
|
if (ec)
|
|
|
|
{
|
2013-06-04 02:35:42 +02:00
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
2014-07-06 21:18:00 +02:00
|
|
|
m_alerts.post_alert(listen_failed_alert(device, last_op, ec, sock_type));
|
|
|
|
|
2011-02-16 07:35:53 +01:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log("failed to open socket: %s: %s"
|
2014-07-06 21:18:00 +02:00
|
|
|
, device.c_str(), ec.message().c_str());
|
2010-08-25 08:22:49 +02:00
|
|
|
#endif
|
2011-09-12 05:51:49 +02:00
|
|
|
return;
|
2011-02-16 07:35:53 +01:00
|
|
|
}
|
2012-06-28 08:51:18 +02:00
|
|
|
|
2013-08-02 03:25:52 +02:00
|
|
|
// SO_REUSEADDR on windows is a bit special. It actually allows
|
|
|
|
// two active sockets to bind to the same port. That means we
|
|
|
|
// may end up binding to the same socket as some other random
|
|
|
|
// application. Don't do it!
|
|
|
|
#ifndef TORRENT_WINDOWS
|
2012-06-28 08:51:18 +02:00
|
|
|
error_code err; // ignore errors here
|
|
|
|
s->sock->set_option(socket_acceptor::reuse_address(true), err);
|
2013-08-02 03:25:52 +02:00
|
|
|
#endif
|
2012-06-28 08:51:18 +02:00
|
|
|
|
2009-04-04 18:59:53 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!ipv4)
|
2009-01-21 02:39:13 +01:00
|
|
|
{
|
2011-02-16 07:35:53 +01:00
|
|
|
error_code err; // ignore errors here
|
2012-11-19 05:58:46 +01:00
|
|
|
#ifdef IPV6_V6ONLY
|
2014-07-06 21:18:00 +02:00
|
|
|
s->sock->set_option(v6only(true), err);
|
2012-11-19 05:58:46 +01:00
|
|
|
#endif
|
2009-01-21 02:39:13 +01:00
|
|
|
#ifdef TORRENT_WINDOWS
|
2010-02-14 05:05:18 +01:00
|
|
|
|
|
|
|
#ifndef PROTECTION_LEVEL_UNRESTRICTED
|
|
|
|
#define PROTECTION_LEVEL_UNRESTRICTED 10
|
|
|
|
#endif
|
2009-01-21 02:39:13 +01:00
|
|
|
// enable Teredo on windows
|
2011-09-12 05:51:49 +02:00
|
|
|
s->sock->set_option(v6_protection_level(PROTECTION_LEVEL_UNRESTRICTED), err);
|
2009-01-21 02:39:13 +01:00
|
|
|
#endif
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif // TORRENT_USE_IPV6
|
|
|
|
|
|
|
|
address bind_ip = bind_to_device(m_io_service, *s->sock, ipv4
|
|
|
|
, device.c_str(), port, ec);
|
|
|
|
|
|
|
|
if (ec == error_code(boost::system::errc::no_such_device, generic_category()))
|
|
|
|
return;
|
|
|
|
|
2007-09-22 18:27:29 +02:00
|
|
|
while (ec && retries > 0)
|
|
|
|
{
|
2010-08-25 08:22:49 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2014-07-06 21:18:00 +02:00
|
|
|
session_log("failed to bind to interface [%s] \"%s\": %s"
|
|
|
|
, device.c_str(), bind_ip.to_string(ec).c_str()
|
|
|
|
, ec.message().c_str());
|
2010-08-25 08:22:49 +02:00
|
|
|
#endif
|
2011-02-16 07:35:53 +01:00
|
|
|
ec.clear();
|
2010-09-25 19:46:13 +02:00
|
|
|
TORRENT_ASSERT_VAL(!ec, ec);
|
2007-09-22 18:27:29 +02:00
|
|
|
--retries;
|
2014-07-06 21:18:00 +02:00
|
|
|
port += 1;
|
|
|
|
bind_ip = bind_to_device(m_io_service, *s->sock, ipv4
|
|
|
|
, device.c_str(), port, ec);
|
2013-06-04 02:35:42 +02:00
|
|
|
last_op = listen_failed_alert::bind;
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
if (ec && !(flags & listen_no_system_port))
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
2011-02-16 07:35:53 +01:00
|
|
|
// instead of giving up, trying
|
2007-09-22 18:27:29 +02:00
|
|
|
// let the OS pick a port
|
2014-07-06 21:18:00 +02:00
|
|
|
port = 0;
|
|
|
|
ec.clear();
|
|
|
|
bind_ip = bind_to_device(m_io_service, *s->sock, ipv4
|
|
|
|
, device.c_str(), port, ec);
|
2013-06-04 02:35:42 +02:00
|
|
|
last_op = listen_failed_alert::bind;
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
// not even that worked, give up
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
2014-07-06 21:18:00 +02:00
|
|
|
m_alerts.post_alert(listen_failed_alert(device, last_op, ec, sock_type));
|
2010-05-30 03:33:03 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log("cannot bind to interface \"%s\": %s"
|
2014-07-06 21:18:00 +02:00
|
|
|
, device.c_str(), ec.message().c_str());
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2011-09-12 05:51:49 +02:00
|
|
|
return;
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2011-09-12 05:51:49 +02:00
|
|
|
s->external_port = s->sock->local_endpoint(ec).port();
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(s->external_port == port || port == 0);
|
2013-06-04 02:35:42 +02:00
|
|
|
last_op = listen_failed_alert::get_peer_name;
|
|
|
|
if (!ec)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
s->sock->listen(m_settings.get_int(settings_pack::listen_queue_size), ec);
|
2013-06-04 02:35:42 +02:00
|
|
|
last_op = listen_failed_alert::listen;
|
|
|
|
}
|
2007-09-22 18:27:29 +02:00
|
|
|
if (ec)
|
2006-10-11 22:57:54 +02: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
|
|
|
m_alerts.post_alert(listen_failed_alert(device, last_op, ec, sock_type));
|
2010-05-30 03:33:03 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log("cannot listen on interface \"%s\": %s"
|
2014-07-06 21:18:00 +02:00
|
|
|
, device.c_str(), ec.message().c_str());
|
2007-09-22 18:27:29 +02:00
|
|
|
#endif
|
2011-09-12 05:51:49 +02:00
|
|
|
return;
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:30 +01:00
|
|
|
// if we asked the system to listen on port 0, which
|
|
|
|
// socket did it end up choosing?
|
2014-07-06 21:18:00 +02:00
|
|
|
if (port == 0)
|
2013-06-04 02:35:42 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
port = s->sock->local_endpoint(ec).port();
|
2013-06-04 02:35:42 +02:00
|
|
|
last_op = listen_failed_alert::get_peer_name;
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
2014-07-06 21:18:00 +02:00
|
|
|
m_alerts.post_alert(listen_failed_alert(device, last_op, ec, sock_type));
|
2013-06-04 02:35:42 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
char msg[200];
|
|
|
|
snprintf(msg, 200, "failed to get peer name \"%s\": %s"
|
2014-07-06 21:18:00 +02:00
|
|
|
, device.c_str(), ec.message().c_str());
|
2013-06-04 02:35:42 +02:00
|
|
|
(*m_logger) << time_now_string() << msg << "\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2011-03-07 08:02:30 +01:00
|
|
|
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<listen_succeeded_alert>())
|
2014-07-06 21:18:00 +02:00
|
|
|
m_alerts.post_alert(listen_succeeded_alert(tcp::endpoint(bind_ip, port)
|
|
|
|
, s->ssl ? listen_succeeded_alert::tcp_ssl : listen_succeeded_alert::tcp));
|
2007-09-22 18:27:29 +02:00
|
|
|
|
2010-05-30 03:33:03 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" listening on: %s external port: %d"
|
2014-07-06 21:18:00 +02:00
|
|
|
, print_endpoint(tcp::endpoint(bind_ip, port)).c_str(), s->external_port);
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::open_listen_port()
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
m_logger = create_log("main_session", listen_port(), false);
|
|
|
|
session_log("log created");
|
|
|
|
#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);
|
2014-07-06 21:18:00 +02:00
|
|
|
int flags = m_settings.get_bool(settings_pack::listen_system_port_fallback) ? 0 : listen_no_system_port;
|
|
|
|
error_code ec;
|
|
|
|
|
|
|
|
// reset the retry counter
|
|
|
|
m_listen_port_retries = m_settings.get_int(settings_pack::max_retry_port_bind);
|
|
|
|
|
2012-10-08 01:34:44 +02:00
|
|
|
retry:
|
|
|
|
|
2007-09-22 18:27:29 +02:00
|
|
|
// close the open listen sockets
|
2012-10-15 08:20:42 +02:00
|
|
|
// close the listen sockets
|
|
|
|
for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
i->sock->close(ec);
|
2007-09-22 18:27:29 +02:00
|
|
|
m_listen_sockets.clear();
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stats_counters.set_value(counters::has_incoming_connections, 0);
|
2012-10-15 08:20:42 +02:00
|
|
|
ec.clear();
|
|
|
|
|
|
|
|
if (m_abort) return;
|
2007-09-22 18:27:29 +02:00
|
|
|
|
2009-04-12 02:37:06 +02:00
|
|
|
m_ipv6_interface = tcp::endpoint();
|
|
|
|
m_ipv4_interface = tcp::endpoint();
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// TODO: instead of having a special case for this, just make the
|
|
|
|
// default listen interfaces be "0.0.0.0:6881,[::1]:6881" and use
|
|
|
|
// the generic path. That would even allow for not listening at all.
|
|
|
|
if (m_listen_interfaces.empty())
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
|
|
|
// this means we should open two listen sockets
|
|
|
|
// one for IPv4 and one for IPv6
|
|
|
|
|
2011-09-12 05:51:49 +02:00
|
|
|
listen_socket_t s;
|
2014-07-06 21:18:00 +02:00
|
|
|
setup_listener(&s, "0.0.0.0", true, m_listen_interface.port()
|
|
|
|
, m_listen_port_retries, flags, ec);
|
2007-09-22 18:27:29 +02:00
|
|
|
|
|
|
|
if (s.sock)
|
|
|
|
{
|
2010-08-25 08:22:49 +02:00
|
|
|
// update the listen_interface member with the
|
2010-05-30 03:33:03 +02:00
|
|
|
// actual port we ended up listening on, so that the other
|
|
|
|
// sockets can be bound to the same one
|
2012-01-14 17:04:25 +01:00
|
|
|
m_listen_interface.port(s.external_port);
|
2010-05-30 03:33:03 +02:00
|
|
|
|
2012-10-15 08:20:42 +02:00
|
|
|
TORRENT_ASSERT(!m_abort);
|
2007-09-22 18:27:29 +02:00
|
|
|
m_listen_sockets.push_back(s);
|
2012-01-14 17:04:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::ssl_listen))
|
2012-01-14 17:04:25 +01:00
|
|
|
{
|
|
|
|
listen_socket_t s;
|
|
|
|
s.ssl = true;
|
2012-10-10 07:52:08 +02:00
|
|
|
int retries = 10;
|
2014-07-06 21:18:00 +02:00
|
|
|
setup_listener(&s, "0.0.0.0", true, m_settings.get_int(settings_pack::ssl_listen)
|
|
|
|
, retries, flags, ec);
|
2012-01-14 17:04:25 +01:00
|
|
|
|
|
|
|
if (s.sock)
|
|
|
|
{
|
2012-10-15 08:20:42 +02:00
|
|
|
TORRENT_ASSERT(!m_abort);
|
2012-01-14 17:04:25 +01:00
|
|
|
m_listen_sockets.push_back(s);
|
|
|
|
}
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
2012-01-14 17:04:25 +01:00
|
|
|
#endif
|
2007-09-22 18:27:29 +02:00
|
|
|
|
2009-03-31 09:45:54 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
2009-03-27 19:44:40 +01:00
|
|
|
// only try to open the IPv6 port if IPv6 is installed
|
2009-04-13 07:11:44 +02:00
|
|
|
if (supports_ipv6())
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
setup_listener(&s, "::1", false, m_listen_interface.port()
|
|
|
|
, m_listen_port_retries, flags, ec);
|
2009-04-13 07:11:44 +02:00
|
|
|
|
|
|
|
if (s.sock)
|
|
|
|
{
|
2012-10-15 08:20:42 +02:00
|
|
|
TORRENT_ASSERT(!m_abort);
|
2009-04-13 07:11:44 +02:00
|
|
|
m_listen_sockets.push_back(s);
|
|
|
|
}
|
2012-01-14 17:04:25 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::ssl_listen))
|
2012-01-14 17:04:25 +01:00
|
|
|
{
|
|
|
|
listen_socket_t s;
|
|
|
|
s.ssl = true;
|
2012-10-10 07:52:08 +02:00
|
|
|
int retries = 10;
|
2014-07-06 21:18:00 +02:00
|
|
|
setup_listener(&s, "::1", false, m_settings.get_int(settings_pack::ssl_listen)
|
|
|
|
, retries, flags, ec);
|
2012-01-14 17:04:25 +01:00
|
|
|
|
|
|
|
if (s.sock)
|
|
|
|
{
|
2012-10-15 08:20:42 +02:00
|
|
|
TORRENT_ASSERT(!m_abort);
|
2012-01-14 17:04:25 +01:00
|
|
|
m_listen_sockets.push_back(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // TORRENT_USE_OPENSSL
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
2009-03-31 09:45:54 +02:00
|
|
|
#endif // TORRENT_USE_IPV6
|
2009-04-12 02:37:06 +02:00
|
|
|
|
|
|
|
// set our main IPv4 and IPv6 interfaces
|
|
|
|
// used to send to the tracker
|
|
|
|
std::vector<ip_interface> ifs = enum_net_interfaces(m_io_service, ec);
|
|
|
|
for (std::vector<ip_interface>::const_iterator i = ifs.begin()
|
|
|
|
, end(ifs.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
address const& addr = i->interface_address;
|
|
|
|
if (addr.is_v6() && !is_local(addr) && !is_loopback(addr))
|
|
|
|
m_ipv6_interface = tcp::endpoint(addr, m_listen_interface.port());
|
|
|
|
else if (addr.is_v4() && !is_local(addr) && !is_loopback(addr))
|
|
|
|
m_ipv4_interface = tcp::endpoint(addr, m_listen_interface.port());
|
|
|
|
}
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
// we should open a one listen socket for each entry in the
|
|
|
|
// listen_interfaces list
|
|
|
|
for (int i = 0; i < m_listen_interfaces.size(); ++i)
|
|
|
|
{
|
|
|
|
std::string const& device = m_listen_interfaces[i].first;
|
|
|
|
int port = m_listen_interfaces[i].second;
|
2007-09-22 18:27:29 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int num_device_fails = 0;
|
|
|
|
|
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
const int first_family = 0;
|
|
|
|
#else
|
|
|
|
const int first_family = 1;
|
|
|
|
#endif
|
|
|
|
for (int address_family = first_family; address_family < 2; ++address_family)
|
|
|
|
{
|
|
|
|
error_code err;
|
|
|
|
address test_family = address::from_string(device.c_str(), err);
|
|
|
|
if (!err && test_family.is_v4() != address_family)
|
|
|
|
continue;
|
2007-09-22 18:27:29 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
listen_socket_t s;
|
|
|
|
setup_listener(&s, device, address_family, port
|
|
|
|
, m_listen_port_retries, flags, ec);
|
2009-04-12 02:37:06 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (ec == error_code(boost::system::errc::no_such_device, generic_category()))
|
|
|
|
{
|
|
|
|
++num_device_fails;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s.sock)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(!m_abort);
|
|
|
|
m_listen_sockets.push_back(s);
|
|
|
|
|
|
|
|
tcp::endpoint bind_ep = s.sock->local_endpoint(ec);
|
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
if (bind_ep.address().is_v6())
|
|
|
|
m_ipv6_interface = bind_ep;
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
m_ipv4_interface = bind_ep;
|
|
|
|
}
|
2012-01-14 17:04:25 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::ssl_listen))
|
|
|
|
{
|
|
|
|
listen_socket_t s;
|
|
|
|
s.ssl = true;
|
|
|
|
int retries = 10;
|
2012-01-14 17:04:25 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
setup_listener(&s, device, address_family
|
|
|
|
, m_settings.get_int(settings_pack::ssl_listen)
|
|
|
|
, m_listen_port_retries, flags, ec);
|
|
|
|
|
|
|
|
if (s.sock)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(!m_abort);
|
|
|
|
m_listen_sockets.push_back(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_device_fails == 2)
|
2012-01-14 17:04:25 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
// only report this if both IPv4 and IPv6 fails for a device
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
m_alerts.post_alert(listen_failed_alert(device
|
|
|
|
, listen_failed_alert::bind
|
|
|
|
, error_code(boost::system::errc::no_such_device, generic_category())
|
|
|
|
, listen_failed_alert::tcp));
|
2012-01-14 17:04:25 +01:00
|
|
|
}
|
|
|
|
}
|
2010-05-30 03:33:03 +02:00
|
|
|
}
|
|
|
|
|
2014-08-16 09:46:06 +02:00
|
|
|
if (m_listen_sockets.empty() && ec)
|
|
|
|
{
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
char msg[200];
|
|
|
|
snprintf(msg, sizeof(msg), "cannot bind TCP listen socket to interface \"%s\": %s"
|
|
|
|
, print_endpoint(m_listen_interface).c_str(), ec.message().c_str());
|
|
|
|
(*m_logger) << msg << "\n";
|
|
|
|
#endif
|
|
|
|
if (m_listen_port_retries > 0)
|
|
|
|
{
|
|
|
|
m_listen_interface.port(m_listen_interface.port() + 1);
|
|
|
|
--m_listen_port_retries;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
m_alerts.post_alert(listen_failed_alert(print_endpoint(m_listen_interface)
|
|
|
|
, listen_failed_alert::bind, ec, listen_failed_alert::udp));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// TODO: 2 use bind_to_device in udp_socket
|
2010-05-30 03:33:03 +02:00
|
|
|
m_udp_socket.bind(udp::endpoint(m_listen_interface.address(), m_listen_interface.port()), ec);
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log("cannot bind to UDP interface \"%s\": %s"
|
2010-05-30 03:33:03 +02:00
|
|
|
, print_endpoint(m_listen_interface).c_str(), ec.message().c_str());
|
|
|
|
#endif
|
2012-10-08 01:34:44 +02:00
|
|
|
if (m_listen_port_retries > 0)
|
|
|
|
{
|
|
|
|
m_listen_interface.port(m_listen_interface.port() + 1);
|
2012-10-18 09:42:15 +02:00
|
|
|
--m_listen_port_retries;
|
2012-10-08 01:34:44 +02:00
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
error_code err;
|
|
|
|
m_alerts.post_alert(listen_failed_alert(print_endpoint(m_listen_interface)
|
2013-10-06 08:32:33 +02:00
|
|
|
, listen_failed_alert::bind, ec, listen_failed_alert::udp));
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2014-08-16 09:46:06 +02:00
|
|
|
return;
|
2010-05-30 03:33:03 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_external_udp_port = m_udp_socket.local_port();
|
|
|
|
maybe_update_udp_mapping(0, m_listen_interface.port(), m_listen_interface.port());
|
|
|
|
maybe_update_udp_mapping(1, m_listen_interface.port(), m_listen_interface.port());
|
2013-10-06 08:32:33 +02:00
|
|
|
if (m_alerts.should_post<listen_succeeded_alert>())
|
|
|
|
m_alerts.post_alert(listen_succeeded_alert(m_listen_interface, listen_succeeded_alert::udp));
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02: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
|
|
|
|
|
|
|
set_socket_buffer_size(m_udp_socket, m_settings, ec);
|
|
|
|
if (ec)
|
2013-09-02 11:24:34 +02:00
|
|
|
{
|
2013-09-03 10:39:30 +02:00
|
|
|
if (m_alerts.should_post<udp_error_alert>())
|
|
|
|
m_alerts.post_alert(udp_error_alert(udp::endpoint(), ec));
|
2013-09-02 11:24:34 +02:00
|
|
|
}
|
2012-01-29 21:59:20 +01:00
|
|
|
|
2012-10-18 09:42:15 +02:00
|
|
|
// initiate accepting on the listen sockets
|
|
|
|
for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
async_accept(i->sock, i->ssl);
|
|
|
|
|
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
|
2009-04-09 03:04:49 +02:00
|
|
|
|
2007-09-22 18:27:29 +02:00
|
|
|
if (!m_listen_sockets.empty())
|
|
|
|
{
|
|
|
|
tcp::endpoint local = m_listen_sockets.front().sock->local_endpoint(ec);
|
2012-01-14 17:04:25 +01:00
|
|
|
if (!ec) remap_tcp_ports(3, local.port(), ssl_listen_port());
|
2007-09-10 21:10:38 +02:00
|
|
|
}
|
2008-08-25 23:17:24 +02:00
|
|
|
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
m_logger = create_log("main_session", listen_port(), false);
|
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2012-01-14 17:04:25 +01:00
|
|
|
void session_impl::remap_tcp_ports(boost::uint32_t mask, int tcp_port, int ssl_port)
|
|
|
|
{
|
|
|
|
if ((mask & 1) && m_natpmp.get())
|
|
|
|
{
|
|
|
|
if (m_tcp_mapping[0] != -1) m_natpmp->delete_mapping(m_tcp_mapping[0]);
|
|
|
|
m_tcp_mapping[0] = m_natpmp->add_mapping(natpmp::tcp, tcp_port, tcp_port);
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
if (m_ssl_mapping[0] != -1) m_natpmp->delete_mapping(m_ssl_mapping[0]);
|
2014-06-15 19:30:40 +02:00
|
|
|
if (ssl_port > 0) m_ssl_mapping[0] = m_natpmp->add_mapping(natpmp::tcp
|
|
|
|
, ssl_port, ssl_port);
|
2012-01-14 17:04:25 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
if ((mask & 2) && m_upnp.get())
|
|
|
|
{
|
|
|
|
if (m_tcp_mapping[1] != -1) m_upnp->delete_mapping(m_tcp_mapping[1]);
|
|
|
|
m_tcp_mapping[1] = m_upnp->add_mapping(upnp::tcp, tcp_port, tcp_port);
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
if (m_ssl_mapping[1] != -1) m_upnp->delete_mapping(m_ssl_mapping[1]);
|
2014-06-15 19:30:40 +02:00
|
|
|
if (ssl_port > 0) m_ssl_mapping[1] = m_upnp->add_mapping(upnp::tcp
|
|
|
|
, ssl_port, ssl_port);
|
2012-01-14 17:04:25 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
void session_impl::open_new_incoming_socks_connection()
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
int proxy_type = m_settings.get_int(settings_pack::proxy_type);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (m_socks_listen_socket) return;
|
|
|
|
|
2009-08-18 20:47:44 +02:00
|
|
|
m_socks_listen_socket = boost::shared_ptr<socket_type>(new socket_type(m_io_service));
|
2014-07-06 21:18:00 +02:00
|
|
|
bool ret = instantiate_connection(m_io_service, proxy()
|
2009-04-09 03:04:49 +02:00
|
|
|
, *m_socks_listen_socket);
|
2010-09-25 19:46:13 +02:00
|
|
|
TORRENT_ASSERT_VAL(ret, ret);
|
2009-04-09 03:04:49 +02:00
|
|
|
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::on_socks_accept");
|
|
|
|
#endif
|
2009-04-09 03:04:49 +02:00
|
|
|
socks5_stream& s = *m_socks_listen_socket->get<socks5_stream>();
|
|
|
|
s.set_command(2); // 2 means BIND (as opposed to CONNECT)
|
2010-04-13 06:30:34 +02:00
|
|
|
m_socks_listen_port = m_listen_interface.port();
|
2011-02-26 08:55:51 +01:00
|
|
|
if (m_socks_listen_port == 0) m_socks_listen_port = 2000 + random() % 60000;
|
2010-04-13 06:30:34 +02:00
|
|
|
s.async_connect(tcp::endpoint(address_v4::any(), m_socks_listen_port)
|
2009-04-09 03:04:49 +02:00
|
|
|
, boost::bind(&session_impl::on_socks_accept, this, m_socks_listen_socket, _1));
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
, boost::bind(&session_impl::on_i2p_open, this, _1));
|
|
|
|
#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;
|
|
|
|
ret.port = m_settings.get_int(settings_pack::i2p_port);
|
|
|
|
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>())
|
|
|
|
m_alerts.post_alert(i2p_alert(ec));
|
|
|
|
|
2013-10-27 20:56:37 +01:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
char msg[200];
|
|
|
|
snprintf(msg, sizeof(msg), "i2p open failed (%d) %s", ec.value(), ec.message().c_str());
|
|
|
|
(*m_logger) << msg << "\n";
|
|
|
|
#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;
|
|
|
|
|
|
|
|
m_i2p_listen_socket = boost::shared_ptr<socket_type>(new socket_type(m_io_service));
|
|
|
|
bool ret = instantiate_connection(m_io_service, m_i2p_conn.proxy()
|
|
|
|
, *m_i2p_listen_socket);
|
2010-09-25 19:46:13 +02:00
|
|
|
TORRENT_ASSERT_VAL(ret, ret);
|
2009-08-20 05:19:12 +02:00
|
|
|
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::on_i2p_accept");
|
|
|
|
#endif
|
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());
|
|
|
|
s.async_connect(tcp::endpoint(address_v4::any(), m_listen_interface.port())
|
|
|
|
, boost::bind(&session_impl::on_i2p_accept, this, m_i2p_listen_socket, _1));
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::on_i2p_accept(boost::shared_ptr<socket_type> const& s
|
|
|
|
, error_code const& e)
|
|
|
|
{
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
complete_async("session_impl::on_i2p_accept");
|
|
|
|
#endif
|
2009-08-20 05:19:12 +02:00
|
|
|
m_i2p_listen_socket.reset();
|
|
|
|
if (e == asio::error::operation_aborted) return;
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
2014-07-06 21:18:00 +02:00
|
|
|
m_alerts.post_alert(listen_failed_alert("i2p", listen_failed_alert::accept
|
2013-10-06 08:32:33 +02:00
|
|
|
, e, listen_failed_alert::i2p));
|
2010-05-30 03:33:03 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log("cannot bind to port %d: %s"
|
2010-05-30 03:33:03 +02:00
|
|
|
, m_listen_interface.port(), e.message().c_str());
|
|
|
|
#endif
|
2009-08-20 05:19:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
open_new_incoming_i2p_connection();
|
|
|
|
incoming_connection(s);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-06-22 06:21:20 +02:00
|
|
|
bool session_impl::incoming_packet(error_code const& ec
|
|
|
|
, udp::endpoint const& ep, char const* buf, int size)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2014-07-13 06:56:53 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::on_udp_counter);
|
2008-05-08 02:22:17 +02:00
|
|
|
|
2012-06-22 06:21:20 +02:00
|
|
|
if (ec)
|
|
|
|
{
|
2011-08-21 03:55:38 +02:00
|
|
|
// don't bubble up operation aborted errors to the user
|
2012-06-22 06:21:20 +02:00
|
|
|
if (ec != asio::error::operation_aborted
|
2011-08-21 03:55:38 +02:00
|
|
|
&& m_alerts.should_post<udp_error_alert>())
|
2012-06-22 06:21:20 +02:00
|
|
|
m_alerts.post_alert(udp_error_alert(ep, ec));
|
2012-09-25 04:49:40 +02:00
|
|
|
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log("UDP socket error: (%d) %s", ec.value(), ec.message().c_str());
|
2012-09-25 04:49:40 +02:00
|
|
|
#endif
|
2010-08-03 11:08:37 +02:00
|
|
|
}
|
2012-06-23 07:46:51 +02:00
|
|
|
return false;
|
2010-08-03 11:08:37 +02:00
|
|
|
}
|
|
|
|
|
2012-01-14 17:04:25 +01:00
|
|
|
void session_impl::async_accept(boost::shared_ptr<socket_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);
|
2008-01-27 23:39:50 +01:00
|
|
|
shared_ptr<socket_type> c(new socket_type(m_io_service));
|
2012-01-14 17:04:25 +01:00
|
|
|
stream_socket* str = 0;
|
|
|
|
|
|
|
|
#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
|
|
|
|
c->instantiate<ssl_stream<stream_socket> >(m_io_service, &m_ssl_ctx);
|
|
|
|
str = &c->get<ssl_stream<stream_socket> >()->next_layer();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
c->instantiate<stream_socket>(m_io_service);
|
|
|
|
str = c->get<stream_socket>();
|
|
|
|
}
|
|
|
|
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::on_accept_connection");
|
|
|
|
#endif
|
2012-01-14 17:04:25 +01:00
|
|
|
listener->async_accept(*str
|
2010-07-22 18:49:40 +02:00
|
|
|
, boost::bind(&session_impl::on_accept_connection, this, c
|
2012-01-14 17:04:25 +01:00
|
|
|
, boost::weak_ptr<socket_acceptor>(listener), _1, ssl));
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
void session_impl::on_accept_connection(shared_ptr<socket_type> const& s
|
2012-01-14 17:04:25 +01:00
|
|
|
, weak_ptr<socket_acceptor> listen_socket, error_code const& e, bool ssl)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
complete_async("session_impl::on_accept_connection");
|
2011-10-17 07:17:21 +02:00
|
|
|
#endif
|
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());
|
2007-09-22 18:27:29 +02:00
|
|
|
boost::shared_ptr<socket_acceptor> listener = listen_socket.lock();
|
|
|
|
if (!listener) return;
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2007-09-22 18:27:29 +02:00
|
|
|
if (e == 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);
|
2006-10-11 22:57:54 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2012-10-18 09:32:16 +02:00
|
|
|
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
|
|
|
|
torrent_map::iterator i = std::max_element(m_torrents.begin()
|
|
|
|
, m_torrents.end(), boost::bind(&torrent::num_peers
|
|
|
|
, boost::bind(&torrent_map::value_type::second, _1)));
|
|
|
|
|
2012-03-04 12:18:27 +01:00
|
|
|
if (m_alerts.should_post<performance_alert>())
|
|
|
|
m_alerts.post_alert(performance_alert(
|
|
|
|
torrent_handle(), performance_alert::too_few_file_descriptors));
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_settings.set_int(settings_pack::connections_limit, 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;
|
|
|
|
m_alerts.post_alert(listen_failed_alert(print_endpoint(ep), listen_failed_alert::accept, e
|
2013-10-06 08:32:33 +02:00
|
|
|
, ssl ? listen_failed_alert::tcp_ssl : listen_failed_alert::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)
|
|
|
|
{
|
|
|
|
// for SSL connections, incoming_connection() is called
|
|
|
|
// after the handshake is done
|
2013-08-21 17:41:19 +02:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::ssl_handshake");
|
|
|
|
#endif
|
2012-01-14 17:04:25 +01:00
|
|
|
s->get<ssl_stream<stream_socket> >()->async_accept_handshake(
|
|
|
|
boost::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
|
|
|
|
|
|
|
|
// to test SSL connections, one can use this openssl command template:
|
|
|
|
//
|
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>
|
|
|
|
|
|
|
|
void session_impl::ssl_handshake(error_code const& ec, boost::shared_ptr<socket_type> s)
|
|
|
|
{
|
2013-08-21 17:41:19 +02:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
complete_async("session_impl::ssl_handshake");
|
|
|
|
#endif
|
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;
|
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2012-10-18 09:32:16 +02:00
|
|
|
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>())
|
|
|
|
{
|
|
|
|
m_alerts.post_alert(peer_error_alert(torrent_handle(), endp
|
2014-07-06 21:18:00 +02:00
|
|
|
, peer_id(), peer_connection::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
|
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
void session_impl::incoming_connection(boost::shared_ptr<socket_type> const& s)
|
|
|
|
{
|
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
|
|
|
|
// add the current time to the PRNG, to add more unpredictability
|
2014-07-06 21:18:00 +02:00
|
|
|
boost::uint64_t now = time_now_hires().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);
|
|
|
|
#endif
|
|
|
|
|
2011-01-23 19:00:52 +01:00
|
|
|
if (m_paused)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_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)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log("%s <== INCOMING CONNECTION FAILED, could "
|
|
|
|
"not retrieve remote endpoint "
|
|
|
|
, print_endpoint(endp).c_str(), ec.message().c_str());
|
2007-09-22 18:27:29 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2012-10-18 09:32:16 +02:00
|
|
|
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
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_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>())
|
2014-02-07 18:35:56 +01:00
|
|
|
m_alerts.post_alert(peer_blocked_alert(torrent_handle()
|
|
|
|
, endp.address(), 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)
|
2010-11-29 02:33:05 +01:00
|
|
|
&& s->get<stream_socket>())
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_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>())
|
2014-02-07 18:35:56 +01:00
|
|
|
m_alerts.post_alert(peer_blocked_alert(torrent_handle()
|
|
|
|
, endp.address(), 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())
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
tcp::endpoint local = s->local_endpoint(ec);
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log(" rejected connection: (%d) %s", ec.value()
|
|
|
|
, ec.message().c_str());
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!verify_bound_address(local.address()
|
|
|
|
, is_utp(*s), ec))
|
|
|
|
{
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log(" rejected connection, not allowed local interface: (%d) %s"
|
|
|
|
, ec.value(), ec.message().c_str());
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log(" rejected connection, not allowed local interface: %s"
|
|
|
|
, local.address().to_string(ec).c_str());
|
|
|
|
#endif
|
|
|
|
if (m_alerts.should_post<peer_blocked_alert>())
|
|
|
|
m_alerts.post_alert(peer_blocked_alert(torrent_handle()
|
|
|
|
, endp.address(), peer_blocked_alert::invalid_local_interface));
|
|
|
|
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
|
2011-03-02 18:37:10 +01:00
|
|
|
&& (m_ip_filter.access(endp.address()) & ip_filter::blocked))
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_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>())
|
2014-02-07 18:35:56 +01:00
|
|
|
m_alerts.post_alert(peer_blocked_alert(torrent_handle()
|
|
|
|
, endp.address(), 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())
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log(" There are no torrents, disconnect");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
int pc = pcs.class_at(i);
|
|
|
|
if (m_classes.at(pc) == NULL) continue;
|
|
|
|
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;
|
|
|
|
|
|
|
|
boost::uint64_t limit = m_settings.get_int(settings_pack::connections_limit);
|
|
|
|
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>())
|
|
|
|
{
|
|
|
|
m_alerts.post_alert(
|
|
|
|
peer_disconnected_alert(torrent_handle(), endp, peer_id()
|
2014-07-06 21:18:00 +02:00
|
|
|
, peer_connection::op_bittorrent
|
2010-02-06 22:40:55 +01:00
|
|
|
, error_code(errors::too_many_connections, get_libtorrent_category())));
|
|
|
|
}
|
2007-10-27 23:21:44 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2014-07-06 21:18:00 +02:00
|
|
|
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
|
|
|
{
|
2010-03-29 02:34:04 +02:00
|
|
|
if (i->second->allows_peers())
|
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)
|
|
|
|
{
|
2008-05-12 12:10:39 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_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
|
2010-02-11 05:39:04 +01:00
|
|
|
return;
|
|
|
|
}
|
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>())
|
|
|
|
m_alerts.post_alert(incoming_connection_alert(s->type(), endp));
|
|
|
|
|
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.allocator = this;
|
|
|
|
pack.disk_thread = &m_disk_thread;
|
|
|
|
pack.ios = &m_io_service;
|
|
|
|
pack.tor = boost::weak_ptr<torrent>();
|
|
|
|
pack.s = s;
|
2014-09-28 06:05:44 +02:00
|
|
|
pack.endp = endp;
|
2014-07-14 06:32:41 +02:00
|
|
|
pack.peerinfo = 0;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
boost::shared_ptr<peer_connection> c
|
2014-07-14 06:32:41 +02:00
|
|
|
= boost::make_shared<bt_peer_connection>(boost::cref(pack)
|
2014-07-06 21:18:00 +02:00
|
|
|
, 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
|
|
|
}
|
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
void session_impl::on_socks_accept(boost::shared_ptr<socket_type> const& s
|
|
|
|
, error_code const& e)
|
|
|
|
{
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
complete_async("session_impl::on_socks_accept");
|
|
|
|
#endif
|
2009-04-09 03:04:49 +02:00
|
|
|
m_socks_listen_socket.reset();
|
|
|
|
if (e == asio::error::operation_aborted) return;
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
2014-07-06 21:18:00 +02:00
|
|
|
m_alerts.post_alert(listen_failed_alert("socks5", listen_failed_alert::accept, e
|
2013-10-06 08:32:33 +02:00
|
|
|
, listen_failed_alert::socks5));
|
2009-04-09 03:04:49 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
open_new_incoming_socks_connection();
|
|
|
|
incoming_connection(s);
|
|
|
|
}
|
|
|
|
|
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());
|
|
|
|
boost::shared_ptr<peer_connection> sp(p->self());
|
|
|
|
|
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
|
|
|
|
2007-08-21 21:18:06 +02:00
|
|
|
// too expensive
|
|
|
|
// INVARIANT_CHECK;
|
2007-08-21 20:33:28 +02:00
|
|
|
|
2008-11-29 22:33:21 +01:00
|
|
|
#ifdef TORRENT_DEBUG
|
2008-01-07 02:10:46 +01:00
|
|
|
// for (aux::session_impl::torrent_map::const_iterator i = m_torrents.begin()
|
|
|
|
// , end(m_torrents.end()); i != end; ++i)
|
|
|
|
// TORRENT_ASSERT(!i->second->has_peer((peer_connection*)p));
|
|
|
|
#endif
|
|
|
|
|
2007-12-19 22:36:54 +01:00
|
|
|
#if defined(TORRENT_LOGGING)
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" CLOSING CONNECTION %s : %s"
|
|
|
|
, print_endpoint(p->remote()).c_str(), ec.message().c_str());
|
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
|
|
|
}
|
|
|
|
|
2012-04-30 07:39:35 +02:00
|
|
|
// implements alert_dispatcher
|
|
|
|
bool session_impl::post_alert(alert* a)
|
|
|
|
{
|
|
|
|
if (!m_alerts.should_post(a)) return false;
|
|
|
|
m_alerts.post_alert_ptr(a);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
int port = m_next_port;
|
|
|
|
++m_next_port;
|
|
|
|
if (m_next_port > out_ports.second) m_next_port = out_ports.first;
|
|
|
|
#if defined TORRENT_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;
|
|
|
|
}
|
|
|
|
|
2009-11-30 08:03:34 +01:00
|
|
|
// used to cache the current time
|
|
|
|
// every 100 ms. This is cheaper
|
|
|
|
// than a system call and can be
|
|
|
|
// used where more accurate time
|
|
|
|
// is not necessary
|
|
|
|
extern ptime g_current_time;
|
|
|
|
|
2009-12-13 17:32:07 +01:00
|
|
|
initialize_timer::initialize_timer()
|
|
|
|
{
|
|
|
|
g_current_time = time_now_hires();
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
if (pc == 0) return 0;
|
|
|
|
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);
|
|
|
|
if (pc == 0) return;
|
|
|
|
if (limit <= 0) limit = 0;
|
|
|
|
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());
|
|
|
|
return std::find_if(m_connections.begin(), m_connections.end()
|
|
|
|
, boost::bind(&boost::shared_ptr<peer_connection>::get, _1) == p)
|
|
|
|
!= m_connections.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool session_impl::any_torrent_has_peer(peer_connection const* p) const
|
|
|
|
{
|
|
|
|
for (aux::session_impl::torrent_map::const_iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
if (i->second->has_peer(p)) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void session_impl::sent_bytes(int bytes_payload, int bytes_protocol)
|
|
|
|
{
|
|
|
|
m_stat.sent_bytes(bytes_payload, bytes_protocol);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::received_bytes(int bytes_payload, int bytes_protocol)
|
|
|
|
{
|
|
|
|
m_stat.received_bytes(bytes_payload, bytes_protocol);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::trancieve_ip_packet(int bytes, bool ipv6)
|
|
|
|
{
|
|
|
|
m_stat.trancieve_ip_packet(bytes, ipv6);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::sent_syn(bool ipv6)
|
|
|
|
{
|
|
|
|
m_stat.sent_syn(ipv6);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::received_synack(bool ipv6)
|
|
|
|
{
|
|
|
|
m_stat.received_synack(ipv6);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::on_tick(error_code const& e)
|
|
|
|
{
|
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
complete_async("session_impl::on_tick");
|
|
|
|
#endif
|
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();
|
|
|
|
|
|
|
|
ptime now = time_now_hires();
|
|
|
|
aux::g_current_time = now;
|
|
|
|
// 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
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_utp_socket_manager.num_sockets() == 0)
|
|
|
|
return;
|
2012-01-23 06:02:12 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
fprintf(stderr, "uTP sockets left: %d\n", m_utp_socket_manager.num_sockets());
|
|
|
|
#endif
|
|
|
|
}
|
2007-10-07 20:06:56 +02:00
|
|
|
|
2010-03-17 20:01:08 +01:00
|
|
|
if (e == asio::error::operation_aborted) return;
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
if (e)
|
|
|
|
{
|
2010-10-17 18:15:32 +02:00
|
|
|
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log("*** TICK TIMER FAILED %s", e.message().c_str());
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2008-02-28 08:34:07 +01:00
|
|
|
::abort();
|
2006-10-11 22:57:54 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::on_tick");
|
|
|
|
#endif
|
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);
|
2009-04-30 07:49:46 +02:00
|
|
|
m_timer.async_wait(bind(&session_impl::on_tick, this, _1));
|
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);
|
|
|
|
|
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
|
|
|
|
if (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
|
|
|
|
|
2013-12-05 08:42:32 +01:00
|
|
|
// remove undead peers that only have this list as their reference keeping them alive
|
2014-07-06 21:18:00 +02:00
|
|
|
std::vector<boost::shared_ptr<peer_connection> >::iterator i = std::remove_if(
|
2013-12-05 08:42:32 +01:00
|
|
|
m_undead_peers.begin(), m_undead_peers.end()
|
2014-07-06 21:18:00 +02:00
|
|
|
, boost::bind(&boost::shared_ptr<peer_connection>::unique, _1));
|
2013-12-05 08:42:32 +01:00
|
|
|
m_undead_peers.erase(i, m_undead_peers.end());
|
|
|
|
|
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
|
|
|
|
2014-05-10 05:23:05 +02:00
|
|
|
boost::int64_t session_time = total_seconds(now - m_created);
|
2009-04-30 07:49:46 +02:00
|
|
|
if (session_time > 65000)
|
|
|
|
{
|
|
|
|
// 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
|
|
|
|
for (ses_extension_list_t::const_iterator i = m_ses_extensions.begin()
|
|
|
|
, end(m_ses_extensions.end()); i != end; ++i)
|
|
|
|
{
|
2011-02-25 18:00:36 +01:00
|
|
|
TORRENT_TRY {
|
|
|
|
(*i)->on_tick();
|
|
|
|
} TORRENT_CATCH(std::exception&) {}
|
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;
|
|
|
|
|
2011-01-18 04:41:54 +01:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// RSS feeds
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
if (now > m_next_rss_update)
|
|
|
|
update_rss_feeds();
|
|
|
|
|
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
|
2013-11-02 04:26:53 +01:00
|
|
|
boost::uint64_t rate = stat_rate[i];
|
2014-07-06 21:18:00 +02:00
|
|
|
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
|
|
|
INVARIANT_CHECK;
|
|
|
|
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
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_last_tick - p->connected_time()
|
|
|
|
> seconds(m_settings.get_int(settings_pack::handshake_timeout)))
|
|
|
|
p->disconnect(errors::timed_out, peer_connection::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
|
|
|
|
printf("\033[2J\033[0;0H");
|
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
std::vector<torrent*>& want_tick = m_torrent_lists[torrent_want_tick];
|
|
|
|
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());
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
t.second_tick(tick_interval_ms, m_tick_residual / 1000);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (m_dht)
|
|
|
|
{
|
|
|
|
int dht_down;
|
|
|
|
int dht_up;
|
|
|
|
m_dht->network_stats(dht_up, dht_down);
|
|
|
|
m_stat.sent_dht_bytes(dht_up);
|
|
|
|
m_stat.received_dht_bytes(dht_down);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
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
|
|
|
peer_class* gpc = m_classes.at(m_global_class);
|
|
|
|
|
|
|
|
gpc->channel[peer_connection::download_channel].use_quota(
|
2011-03-25 08:49:32 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
m_stat.download_dht() +
|
|
|
|
#endif
|
|
|
|
m_stat.download_tracker());
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
gpc->channel[peer_connection::upload_channel].use_quota(
|
2011-03-25 08:49:32 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
m_stat.upload_dht() +
|
|
|
|
#endif
|
|
|
|
m_stat.upload_tracker());
|
|
|
|
|
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>())
|
|
|
|
{
|
|
|
|
m_alerts.post_alert(performance_alert(torrent_handle()
|
|
|
|
, performance_alert::download_limit_too_low));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (up_limit > 0
|
|
|
|
&& m_stat.upload_ip_overhead() >= up_limit
|
|
|
|
&& m_alerts.should_post<performance_alert>())
|
|
|
|
{
|
|
|
|
m_alerts.post_alert(performance_alert(torrent_handle()
|
|
|
|
, performance_alert::upload_limit_too_low));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
m_stat.second_tick(tick_interval_ms);
|
|
|
|
|
2007-05-14 00:01:21 +02:00
|
|
|
#ifdef TORRENT_STATS
|
2011-04-06 08:27:42 +02:00
|
|
|
if (m_stats_logging_enabled)
|
2007-05-14 00:01:21 +02:00
|
|
|
{
|
2011-04-06 08:27:42 +02:00
|
|
|
print_log_line(tick_interval_ms, now);
|
|
|
|
}
|
|
|
|
#endif
|
2011-02-06 04:07:00 +01:00
|
|
|
|
2011-04-06 08:27:42 +02:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// scrape paused torrents that are auto managed
|
|
|
|
// (unless the session is paused)
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
if (!is_paused())
|
|
|
|
{
|
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
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
std::vector<torrent*>& want_scrape = m_torrent_lists[torrent_want_scrape];
|
|
|
|
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());
|
|
|
|
|
|
|
|
t.scrape_tracker();
|
|
|
|
|
|
|
|
++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
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// refresh torrent suggestions
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
--m_suggest_timer;
|
|
|
|
if (m_settings.get_int(settings_pack::suggest_mode) != settings_pack::no_piece_suggestions
|
|
|
|
&& m_suggest_timer <= 0)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
m_suggest_timer = 10;
|
|
|
|
|
|
|
|
torrent_map::iterator least_recently_refreshed = m_torrents.begin();
|
|
|
|
if (m_next_suggest_torrent >= int(m_torrents.size()))
|
|
|
|
m_next_suggest_torrent = 0;
|
|
|
|
|
|
|
|
std::advance(least_recently_refreshed, m_next_suggest_torrent);
|
|
|
|
|
|
|
|
if (least_recently_refreshed != m_torrents.end())
|
|
|
|
least_recently_refreshed->second->refresh_suggest_pieces();
|
|
|
|
++m_next_suggest_torrent;
|
|
|
|
}
|
|
|
|
|
2011-04-06 08:27:42 +02:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// refresh explicit disk read cache
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
--m_cache_rotation_timer;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::explicit_read_cache)
|
2011-04-06 08:27:42 +02:00
|
|
|
&& m_cache_rotation_timer <= 0)
|
2007-05-14 06:01:30 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
m_cache_rotation_timer = m_settings.get_int(settings_pack::explicit_cache_interval);
|
2011-04-06 08:27:42 +02:00
|
|
|
|
|
|
|
torrent_map::iterator least_recently_refreshed = m_torrents.begin();
|
|
|
|
if (m_next_explicit_cache_torrent >= int(m_torrents.size()))
|
|
|
|
m_next_explicit_cache_torrent = 0;
|
|
|
|
|
|
|
|
std::advance(least_recently_refreshed, m_next_explicit_cache_torrent);
|
|
|
|
|
|
|
|
// how many blocks does this torrent get?
|
2014-07-06 21:18:00 +02:00
|
|
|
int cache_size = (std::max)(0, m_settings.get_int(settings_pack::cache_size) * 9 / 10);
|
2011-04-06 08:27:42 +02:00
|
|
|
|
|
|
|
if (m_connections.empty())
|
2008-12-27 03:22:20 +01:00
|
|
|
{
|
2011-04-06 08:27:42 +02:00
|
|
|
// if we don't have any connections at all, split the
|
|
|
|
// cache evenly across all torrents
|
|
|
|
cache_size = cache_size / (std::max)(int(m_torrents.size()), 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cache_size = cache_size * least_recently_refreshed->second->num_peers()
|
|
|
|
/ m_connections.size();
|
2008-12-27 03:22:20 +01:00
|
|
|
}
|
2011-02-03 05:09:50 +01:00
|
|
|
|
2011-04-06 08:27:42 +02:00
|
|
|
if (least_recently_refreshed != m_torrents.end())
|
|
|
|
least_recently_refreshed->second->refresh_explicit_cache(cache_size);
|
|
|
|
++m_next_explicit_cache_torrent;
|
|
|
|
}
|
2011-02-03 07:22:22 +01: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()
|
|
|
|
, boost::bind(&torrent::num_peers, boost::bind(&torrent_map::value_type::second, _1))
|
|
|
|
< boost::bind(&torrent::num_peers, boost::bind(&torrent_map::value_type::second, _2)));
|
|
|
|
|
|
|
|
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
|
2010-10-03 12:07:38 +02:00
|
|
|
, error_code(errors::optimistic_disconnect, get_libtorrent_category()));
|
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
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
boost::shared_ptr<torrent> t = i->second;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
int peers_to_disconnect = (std::min)((std::max)(int(t->num_peers()
|
|
|
|
* m_settings.get_int(settings_pack::peer_turnover) / 100), 1)
|
|
|
|
, t->num_connect_candidates());
|
|
|
|
t->disconnect_peers(peers_to_disconnect
|
|
|
|
, error_code(errors::optimistic_disconnect, get_libtorrent_category()));
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// returns the index of the first set bit.
|
|
|
|
int log2(boost::uint32_t v)
|
|
|
|
{
|
|
|
|
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
|
|
|
|
static const int MultiplyDeBruijnBitPosition[32] =
|
|
|
|
{
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
v |= v >> 1; // first round down to one less than a power of 2
|
|
|
|
v |= v >> 2;
|
|
|
|
v |= v >> 4;
|
|
|
|
v |= v >> 8;
|
|
|
|
v |= v >> 16;
|
|
|
|
|
|
|
|
return MultiplyDeBruijnBitPosition[boost::uint32_t(v * 0x07C4ACDDU) >> 27];
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::received_buffer(int s)
|
|
|
|
{
|
|
|
|
int index = (std::min)(log2(s >> 3), 17);
|
|
|
|
m_stats_counters.inc_stats_counter(counters::socket_recv_size3 + index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::sent_buffer(int s)
|
|
|
|
{
|
|
|
|
int index = (std::min)(log2(s >> 3), 17);
|
|
|
|
m_stats_counters.inc_stats_counter(counters::socket_send_size3 + index);
|
|
|
|
}
|
|
|
|
|
2011-04-06 08:27:42 +02:00
|
|
|
#ifdef TORRENT_STATS
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2011-04-06 08:27:42 +02:00
|
|
|
void session_impl::enable_stats_logging(bool s)
|
|
|
|
{
|
|
|
|
if (m_stats_logging_enabled == s) return;
|
|
|
|
|
|
|
|
m_stats_logging_enabled = s;
|
|
|
|
|
2011-04-06 09:33:10 +02:00
|
|
|
if (!s)
|
|
|
|
{
|
|
|
|
if (m_stats_logger) fclose(m_stats_logger);
|
2011-04-06 09:58:29 +02:00
|
|
|
m_stats_logger = 0;
|
2011-04-06 09:33:10 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rotate_stats_log();
|
2011-10-17 19:12:08 +02:00
|
|
|
get_thread_cpu_usage(&m_network_thread_cpu_usage);
|
2011-04-06 09:33:10 +02:00
|
|
|
}
|
2011-04-06 08:27:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::print_log_line(int tick_interval_ms, ptime now)
|
|
|
|
{
|
|
|
|
int connect_candidates = 0;
|
2012-03-11 06:35:29 +01:00
|
|
|
|
2011-04-06 08:27:42 +02:00
|
|
|
int num_peers = 0;
|
|
|
|
int peer_dl_rate_buckets[7];
|
|
|
|
int peer_ul_rate_buckets[7];
|
|
|
|
memset(peer_dl_rate_buckets, 0, sizeof(peer_dl_rate_buckets));
|
|
|
|
memset(peer_ul_rate_buckets, 0, sizeof(peer_ul_rate_buckets));
|
|
|
|
int outstanding_requests = 0;
|
|
|
|
int outstanding_end_game_requests = 0;
|
|
|
|
int outstanding_write_blocks = 0;
|
|
|
|
|
2012-03-09 18:03:10 +01:00
|
|
|
int peers_up_send_buffer = 0;
|
2011-04-06 08:27:42 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int partial_pieces = 0;
|
|
|
|
int partial_downloading_pieces = 0;
|
|
|
|
int partial_full_pieces = 0;
|
|
|
|
int partial_finished_pieces = 0;
|
|
|
|
int partial_zero_prio_pieces = 0;
|
|
|
|
|
2012-03-06 11:34:18 +01:00
|
|
|
// number of torrents that want more peers
|
2014-07-06 21:18:00 +02:00
|
|
|
int num_want_more_peers = int(m_torrent_lists[torrent_want_peers_download].size()
|
|
|
|
+ m_torrent_lists[torrent_want_peers_finished].size());
|
2012-03-06 11:34:18 +01:00
|
|
|
|
|
|
|
// number of peers among torrents with a peer limit
|
|
|
|
int num_limited_peers = 0;
|
|
|
|
// sum of limits of all torrents with a peer limit
|
2014-03-25 10:17:48 +01:00
|
|
|
boost::uint64_t total_peers_limit = 0;
|
2012-03-06 11:34:18 +01:00
|
|
|
|
2011-04-06 08:27:42 +02:00
|
|
|
std::vector<partial_piece_info> dq;
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
2012-03-11 06:35:29 +01:00
|
|
|
torrent* t = i->second.get();
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2012-03-11 06:35:29 +01:00
|
|
|
int connection_slots = (std::max)(t->max_connections() - t->num_peers(), 0);
|
2014-07-06 21:18:00 +02:00
|
|
|
int candidates = t->num_connect_candidates();
|
2011-04-06 08:27:42 +02:00
|
|
|
connect_candidates += (std::min)(candidates, connection_slots);
|
2014-07-06 21:18:00 +02:00
|
|
|
num_peers += t->num_known_peers();
|
2012-03-06 11:34:18 +01:00
|
|
|
|
2012-03-11 06:35:29 +01:00
|
|
|
if (t->max_connections() > 0)
|
2012-03-06 11:34:18 +01:00
|
|
|
{
|
2012-03-11 06:35:29 +01:00
|
|
|
num_limited_peers += t->num_peers();
|
2014-03-25 10:17:48 +01:00
|
|
|
total_peers_limit += t->max_connections();
|
2012-03-06 11:34:18 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (t->has_picker())
|
2012-03-11 06:35:29 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
piece_picker& p = t->picker();
|
|
|
|
partial_pieces += p.get_download_queue_size();
|
|
|
|
int a, b, c, d;
|
|
|
|
p.get_download_queue_sizes(&a, &b, &c, &d);
|
|
|
|
partial_downloading_pieces += a;
|
|
|
|
partial_full_pieces += b;
|
|
|
|
partial_finished_pieces += c;
|
|
|
|
partial_zero_prio_pieces += d;
|
2012-03-11 06:35:29 +01:00
|
|
|
}
|
2011-04-06 08:27:42 +02:00
|
|
|
|
|
|
|
dq.clear();
|
2014-07-06 21:18:00 +02:00
|
|
|
t->get_download_queue(&dq);
|
2011-04-06 08:27:42 +02:00
|
|
|
for (std::vector<partial_piece_info>::iterator j = dq.begin()
|
|
|
|
, end(dq.end()); j != end; ++j)
|
|
|
|
{
|
|
|
|
for (int k = 0; k < j->blocks_in_piece; ++k)
|
|
|
|
{
|
|
|
|
block_info& bi = j->blocks[k];
|
|
|
|
if (bi.state == block_info::requested)
|
|
|
|
{
|
|
|
|
++outstanding_requests;
|
|
|
|
if (bi.num_peers > 1) ++outstanding_end_game_requests;
|
|
|
|
}
|
|
|
|
else if (bi.state == block_info::writing)
|
|
|
|
++outstanding_write_blocks;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-20 06:33:46 +02:00
|
|
|
int tcp_up_rate = 0;
|
|
|
|
int tcp_down_rate = 0;
|
|
|
|
int utp_up_rate = 0;
|
|
|
|
int utp_down_rate = 0;
|
2011-06-21 09:44:13 +02:00
|
|
|
int utp_peak_send_delay = 0;
|
2011-09-28 02:03:12 +02:00
|
|
|
int utp_peak_recv_delay = 0;
|
2011-06-21 09:44:13 +02:00
|
|
|
boost::uint64_t utp_send_delay_sum = 0;
|
2011-09-28 02:03:12 +02:00
|
|
|
boost::uint64_t utp_recv_delay_sum = 0;
|
2011-06-21 09:44:13 +02:00
|
|
|
int utp_num_delay_sockets = 0;
|
2011-09-28 02:03:12 +02:00
|
|
|
int utp_num_recv_delay_sockets = 0;
|
2011-09-23 22:57:42 +02:00
|
|
|
int reading_bytes = 0;
|
2012-03-05 11:05:20 +01:00
|
|
|
int pending_incoming_reqs = 0;
|
2012-03-09 18:03:10 +01:00
|
|
|
|
2011-04-06 08:27:42 +02:00
|
|
|
for (connection_map::iterator i = m_connections.begin()
|
|
|
|
, end(m_connections.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
peer_connection* p = i->get();
|
|
|
|
if (p->is_connecting())
|
|
|
|
continue;
|
|
|
|
|
2011-09-23 22:57:42 +02:00
|
|
|
reading_bytes += p->num_reading_bytes();
|
2012-03-05 11:05:20 +01:00
|
|
|
|
|
|
|
pending_incoming_reqs += int(p->upload_queue().size());
|
2011-04-06 08:27:42 +02:00
|
|
|
|
|
|
|
int dl_bucket = 0;
|
|
|
|
int dl_rate = p->statistics().download_payload_rate();
|
|
|
|
if (dl_rate == 0) dl_bucket = 0;
|
|
|
|
else if (dl_rate < 2000) dl_bucket = 1;
|
|
|
|
else if (dl_rate < 5000) dl_bucket = 2;
|
|
|
|
else if (dl_rate < 10000) dl_bucket = 3;
|
|
|
|
else if (dl_rate < 50000) dl_bucket = 4;
|
|
|
|
else if (dl_rate < 100000) dl_bucket = 5;
|
|
|
|
else dl_bucket = 6;
|
|
|
|
|
|
|
|
int ul_rate = p->statistics().upload_payload_rate();
|
|
|
|
int ul_bucket = 0;
|
|
|
|
if (ul_rate == 0) ul_bucket = 0;
|
|
|
|
else if (ul_rate < 2000) ul_bucket = 1;
|
|
|
|
else if (ul_rate < 5000) ul_bucket = 2;
|
|
|
|
else if (ul_rate < 10000) ul_bucket = 3;
|
|
|
|
else if (ul_rate < 50000) ul_bucket = 4;
|
|
|
|
else if (ul_rate < 100000) ul_bucket = 5;
|
|
|
|
else ul_bucket = 6;
|
|
|
|
|
|
|
|
++peer_dl_rate_buckets[dl_bucket];
|
|
|
|
++peer_ul_rate_buckets[ul_bucket];
|
2011-06-20 06:33:46 +02:00
|
|
|
|
2012-03-09 18:03:10 +01:00
|
|
|
boost::uint64_t upload_rate = int(p->statistics().upload_rate());
|
|
|
|
int buffer_size_watermark = upload_rate
|
2014-07-06 21:18:00 +02:00
|
|
|
* m_settings.get_int(settings_pack::send_buffer_watermark_factor) / 100;
|
|
|
|
if (buffer_size_watermark < m_settings.get_int(settings_pack::send_buffer_low_watermark))
|
|
|
|
buffer_size_watermark = m_settings.get_int(settings_pack::send_buffer_low_watermark);
|
|
|
|
else if (buffer_size_watermark > m_settings.get_int(settings_pack::send_buffer_watermark))
|
|
|
|
buffer_size_watermark = m_settings.get_int(settings_pack::send_buffer_watermark);
|
2012-03-09 18:03:10 +01:00
|
|
|
if (p->send_buffer_size() + p->num_reading_bytes() >= buffer_size_watermark)
|
|
|
|
++peers_up_send_buffer;
|
|
|
|
|
2011-06-21 09:44:13 +02:00
|
|
|
utp_stream* utp_socket = p->get_socket()->get<utp_stream>();
|
2012-10-05 05:20:40 +02:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2012-11-11 06:07:19 +01:00
|
|
|
if (!utp_socket)
|
|
|
|
{
|
|
|
|
ssl_stream<utp_stream>* ssl_str = p->get_socket()->get<ssl_stream<utp_stream> >();
|
|
|
|
if (ssl_str) utp_socket = &ssl_str->next_layer();
|
|
|
|
}
|
2012-10-05 05:20:40 +02:00
|
|
|
#endif
|
2011-06-21 09:44:13 +02:00
|
|
|
if (utp_socket)
|
2011-06-20 06:33:46 +02:00
|
|
|
{
|
|
|
|
utp_up_rate += ul_rate;
|
2011-06-21 09:44:13 +02:00
|
|
|
utp_down_rate += dl_rate;
|
|
|
|
int send_delay = utp_socket->send_delay();
|
2011-09-28 02:03:12 +02:00
|
|
|
int recv_delay = utp_socket->recv_delay();
|
2011-06-21 09:44:13 +02:00
|
|
|
utp_peak_send_delay = (std::max)(utp_peak_send_delay, send_delay);
|
2011-09-28 02:03:12 +02:00
|
|
|
utp_peak_recv_delay = (std::max)(utp_peak_recv_delay, recv_delay);
|
2011-06-21 09:44:13 +02:00
|
|
|
if (send_delay > 0)
|
|
|
|
{
|
|
|
|
utp_send_delay_sum += send_delay;
|
|
|
|
++utp_num_delay_sockets;
|
|
|
|
}
|
2011-09-28 02:03:12 +02:00
|
|
|
if (recv_delay > 0)
|
|
|
|
{
|
|
|
|
utp_recv_delay_sum += recv_delay;
|
|
|
|
++utp_num_recv_delay_sockets;
|
|
|
|
}
|
2011-06-20 06:33:46 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tcp_up_rate += ul_rate;
|
|
|
|
tcp_down_rate += dl_rate;
|
|
|
|
}
|
2011-04-06 08:27:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (now - m_last_log_rotation > hours(1))
|
|
|
|
rotate_stats_log();
|
2011-06-29 00:20:34 +02:00
|
|
|
|
|
|
|
// system memory stats
|
2014-07-06 21:18:00 +02:00
|
|
|
error_code vm_ec;
|
2011-06-29 00:20:34 +02:00
|
|
|
vm_statistics_data_t vm_stat;
|
2014-07-06 21:18:00 +02:00
|
|
|
get_vm_stats(&vm_stat, vm_ec);
|
2011-10-17 19:12:08 +02:00
|
|
|
thread_cpu_usage cur_cpu_usage;
|
|
|
|
get_thread_cpu_usage(&cur_cpu_usage);
|
2011-06-29 00:20:34 +02:00
|
|
|
|
2011-04-06 08:27:42 +02:00
|
|
|
if (m_stats_logger)
|
|
|
|
{
|
2014-08-01 08:07:48 +02:00
|
|
|
counters cnt = m_stats_counters;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
cache_status cs;
|
|
|
|
m_disk_thread.get_cache_info(&cs);
|
2012-01-17 04:11:16 +01:00
|
|
|
session_status sst = status();
|
2011-04-06 08:27:42 +02:00
|
|
|
|
2013-10-02 23:51:30 +02:00
|
|
|
#ifdef TORRENT_USE_VALGRIND
|
2013-10-03 17:39:19 +02:00
|
|
|
#define STAT_LOGL(type, val) VALGRIND_CHECK_VALUE_IS_DEFINED(val); fprintf(m_stats_logger, "%" #type "\t", val)
|
2013-10-02 23:51:30 +02:00
|
|
|
#else
|
2013-10-03 17:39:19 +02:00
|
|
|
#define STAT_LOGL(type, val) fprintf(m_stats_logger, "%" #type "\t", val)
|
2013-10-02 23:51:30 +02:00
|
|
|
#endif
|
2014-08-01 08:07:48 +02:00
|
|
|
#define STAT_COUNTER(c) fprintf(m_stats_logger, "%" PRId64 "\t", cnt[counters:: c])
|
|
|
|
#define STAT_COUNTER_DELTA(c) fprintf(m_stats_logger, "%" PRId64 "\t", cnt[counters:: c] \
|
|
|
|
- m_last_stats_counters[counters:: c])
|
2013-10-03 17:39:19 +02:00
|
|
|
#define STAT_LOG(type, val) fprintf(m_stats_logger, "%" #type "\t", val)
|
2011-06-26 20:43:23 +02:00
|
|
|
|
2011-06-26 21:45:33 +02:00
|
|
|
STAT_LOG(f, total_milliseconds(now - m_last_log_rotation) / 1000.f);
|
2014-08-01 08:07:48 +02:00
|
|
|
STAT_COUNTER_DELTA(sent_bytes);
|
|
|
|
STAT_COUNTER_DELTA(recv_bytes);
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(num_downloading_torrents);
|
|
|
|
STAT_COUNTER(num_seeding_torrents);
|
|
|
|
STAT_COUNTER(num_peers_connected);
|
|
|
|
STAT_COUNTER(disk_blocks_in_use);
|
|
|
|
STAT_LOGL(d, num_peers); // total number of known peers
|
|
|
|
STAT_LOG(d, m_peer_allocator.live_allocations());
|
|
|
|
STAT_LOG(d, m_peer_allocator.live_bytes());
|
|
|
|
STAT_COUNTER(num_checking_torrents);
|
|
|
|
STAT_COUNTER(num_stopped_torrents);
|
|
|
|
STAT_COUNTER(num_upload_only_torrents);
|
|
|
|
STAT_COUNTER(num_queued_seeding_torrents);
|
|
|
|
STAT_COUNTER(num_queued_download_torrents);
|
2011-06-26 20:43:23 +02:00
|
|
|
STAT_LOG(d, m_upload_rate.queue_size());
|
|
|
|
STAT_LOG(d, m_download_rate.queue_size());
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(num_peers_up_disk);
|
|
|
|
STAT_COUNTER(num_peers_down_disk);
|
2011-06-26 20:43:23 +02:00
|
|
|
STAT_LOG(d, m_stat.upload_rate());
|
|
|
|
STAT_LOG(d, m_stat.download_rate());
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(queued_write_bytes);
|
2013-10-03 17:39:19 +02:00
|
|
|
STAT_LOGL(d, peer_dl_rate_buckets[0]);
|
|
|
|
STAT_LOGL(d, peer_dl_rate_buckets[1]);
|
|
|
|
STAT_LOGL(d, peer_dl_rate_buckets[2]);
|
|
|
|
STAT_LOGL(d, peer_dl_rate_buckets[3]);
|
|
|
|
STAT_LOGL(d, peer_dl_rate_buckets[4]);
|
|
|
|
STAT_LOGL(d, peer_dl_rate_buckets[5]);
|
|
|
|
STAT_LOGL(d, peer_dl_rate_buckets[6]);
|
|
|
|
STAT_LOGL(d, peer_ul_rate_buckets[0]);
|
|
|
|
STAT_LOGL(d, peer_ul_rate_buckets[1]);
|
|
|
|
STAT_LOGL(d, peer_ul_rate_buckets[2]);
|
|
|
|
STAT_LOGL(d, peer_ul_rate_buckets[3]);
|
|
|
|
STAT_LOGL(d, peer_ul_rate_buckets[4]);
|
|
|
|
STAT_LOGL(d, peer_ul_rate_buckets[5]);
|
|
|
|
STAT_LOGL(d, peer_ul_rate_buckets[6]);
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(error_peers);
|
|
|
|
STAT_COUNTER(num_peers_down_interested);
|
|
|
|
STAT_COUNTER(num_peers_down_unchoked);
|
|
|
|
STAT_COUNTER(num_peers_down_requests);
|
|
|
|
STAT_COUNTER(num_peers_up_interested);
|
|
|
|
STAT_COUNTER(num_peers_up_unchoked);
|
|
|
|
STAT_COUNTER(num_peers_up_requests);
|
|
|
|
STAT_COUNTER(disconnected_peers);
|
|
|
|
STAT_COUNTER(eof_peers);
|
|
|
|
STAT_COUNTER(connreset_peers);
|
2013-10-03 17:39:19 +02:00
|
|
|
STAT_LOGL(d, outstanding_requests);
|
|
|
|
STAT_LOGL(d, outstanding_end_game_requests);
|
|
|
|
STAT_LOGL(d, outstanding_write_blocks);
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(reject_piece_picks);
|
|
|
|
STAT_COUNTER(unchoke_piece_picks);
|
|
|
|
STAT_COUNTER(incoming_redundant_piece_picks);
|
|
|
|
STAT_COUNTER(incoming_piece_picks);
|
|
|
|
STAT_COUNTER(end_game_piece_picks);
|
|
|
|
STAT_COUNTER(snubbed_piece_picks);
|
|
|
|
STAT_COUNTER(interesting_piece_picks);
|
|
|
|
STAT_COUNTER(hash_fail_piece_picks);
|
|
|
|
STAT_COUNTER(connect_timeouts);
|
|
|
|
STAT_COUNTER(uninteresting_peers);
|
|
|
|
STAT_COUNTER(timeout_peers);
|
2014-08-01 08:07:48 +02:00
|
|
|
STAT_LOG(f, float(cnt[counters::recv_failed_bytes]) * 100.f
|
|
|
|
/ (std::max)(cnt[counters::recv_bytes], boost::int64_t(1)));
|
|
|
|
STAT_LOG(f, float(cnt[counters::recv_redundant_bytes]) * 100.f
|
|
|
|
/ (std::max)(cnt[counters::recv_bytes], boost::int64_t(1)));
|
|
|
|
STAT_LOG(f, float(cnt[counters::recv_bytes]
|
|
|
|
- cnt[counters::recv_payload_bytes]) * 100.f
|
|
|
|
/ (std::max)(cnt[counters::recv_bytes], boost::int64_t(1)));
|
|
|
|
|
|
|
|
int delta_read_jobs = cnt[counters::num_read_ops]
|
|
|
|
- m_last_stats_counters[counters::num_read_ops];
|
|
|
|
int delta_read_time = cnt[counters::disk_read_time]
|
|
|
|
- m_last_stats_counters[counters::disk_read_time];
|
|
|
|
int delta_write_jobs = cnt[counters::num_write_ops]
|
|
|
|
- m_last_stats_counters[counters::num_write_ops];
|
|
|
|
int delta_write_time = cnt[counters::disk_write_time]
|
|
|
|
- m_last_stats_counters[counters::disk_write_time];
|
|
|
|
int delta_hash_jobs = cnt[counters::num_blocks_hashed]
|
|
|
|
- m_last_stats_counters[counters::num_blocks_hashed];
|
|
|
|
int delta_hash_time = cnt[counters::disk_hash_time]
|
|
|
|
- m_last_stats_counters[counters::disk_hash_time];
|
|
|
|
|
|
|
|
STAT_LOG(f, float(delta_read_jobs == 0 ? 0.f
|
|
|
|
: delta_read_time / delta_read_jobs) / 1000000.f);
|
|
|
|
STAT_LOG(f, float(delta_write_jobs == 0 ? 0.f
|
|
|
|
: delta_write_time / delta_write_jobs) / 1000000.f);
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_LOG(d, int(cs.pending_jobs + cs.queued_jobs));
|
|
|
|
STAT_COUNTER(queued_write_bytes);
|
2014-08-01 08:07:48 +02:00
|
|
|
STAT_COUNTER_DELTA(num_blocks_cache_hits);
|
|
|
|
STAT_COUNTER_DELTA(num_blocks_read);
|
|
|
|
STAT_COUNTER_DELTA(num_blocks_written);
|
|
|
|
STAT_COUNTER_DELTA(recv_failed_bytes);
|
|
|
|
STAT_COUNTER_DELTA(recv_redundant_bytes);
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(num_error_torrents);
|
2013-10-03 17:39:19 +02:00
|
|
|
STAT_LOGL(d, cs.read_cache_size);
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_LOG(d, cs.write_cache_size + cs.read_cache_size);
|
|
|
|
STAT_COUNTER(disk_blocks_in_use);
|
2014-08-01 08:07:48 +02:00
|
|
|
STAT_LOG(f, float(delta_hash_jobs == 0 ? 0.f
|
|
|
|
: delta_hash_time / delta_hash_jobs) / 1000000.f);
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(connection_attempts);
|
|
|
|
STAT_COUNTER(num_banned_peers);
|
|
|
|
STAT_COUNTER(banned_for_hash_failure);
|
|
|
|
STAT_LOG(d, m_settings.get_int(settings_pack::cache_size));
|
|
|
|
STAT_LOG(d, m_settings.get_int(settings_pack::connections_limit));
|
2013-10-03 17:39:19 +02:00
|
|
|
STAT_LOGL(d, connect_candidates);
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_LOG(d, int(m_settings.get_int(settings_pack::cache_size)
|
|
|
|
- m_settings.get_int(settings_pack::max_queued_disk_bytes) / 0x4000));
|
2014-08-01 08:07:48 +02:00
|
|
|
STAT_LOG(f, float(cnt[counters::disk_read_time] * 100.f
|
|
|
|
/ (std::max)(cnt[counters::disk_job_time], boost::int64_t(1))));
|
|
|
|
STAT_LOG(f, float(cnt[counters::disk_write_time] * 100.f
|
|
|
|
/ (std::max)(cnt[counters::disk_job_time], boost::int64_t(1))));
|
|
|
|
STAT_LOG(f, float(cnt[counters::disk_hash_time] * 100.f
|
|
|
|
/ (std::max)(cnt[counters::disk_job_time], boost::int64_t(1))));
|
|
|
|
STAT_COUNTER_DELTA(num_read_back);
|
|
|
|
STAT_LOG(f, float(cnt[counters::num_read_back] * 100.f / (std::max)(1, int(cnt[counters::num_blocks_written]))));
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(num_read_jobs);
|
2011-06-26 20:43:23 +02:00
|
|
|
STAT_LOG(f, float(tick_interval_ms) / 1000.f);
|
|
|
|
STAT_LOG(f, float(m_tick_residual) / 1000.f);
|
2013-10-03 17:39:19 +02:00
|
|
|
STAT_LOGL(d, m_allowed_upload_slots);
|
2011-06-26 20:43:23 +02:00
|
|
|
STAT_LOG(d, m_stat.low_pass_upload_rate());
|
|
|
|
STAT_LOG(d, m_stat.low_pass_download_rate());
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(num_peers_end_game);
|
2013-10-03 17:39:19 +02:00
|
|
|
STAT_LOGL(d, tcp_up_rate);
|
|
|
|
STAT_LOGL(d, tcp_down_rate);
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_LOG(d, int(rate_limit(m_tcp_peer_class, peer_connection::upload_channel)));
|
|
|
|
STAT_LOG(d, int(rate_limit(m_tcp_peer_class, peer_connection::download_channel)));
|
2013-10-03 17:39:19 +02:00
|
|
|
STAT_LOGL(d, utp_up_rate);
|
|
|
|
STAT_LOGL(d, utp_down_rate);
|
2011-06-26 20:43:23 +02:00
|
|
|
STAT_LOG(f, float(utp_peak_send_delay) / 1000000.f);
|
|
|
|
STAT_LOG(f, float(utp_num_delay_sockets ? float(utp_send_delay_sum) / float(utp_num_delay_sockets) : 0) / 1000000.f);
|
2011-09-28 02:03:12 +02:00
|
|
|
STAT_LOG(f, float(utp_peak_recv_delay) / 1000000.f);
|
|
|
|
STAT_LOG(f, float(utp_num_recv_delay_sockets ? float(utp_recv_delay_sum) / float(utp_num_recv_delay_sockets) : 0) / 1000000.f);
|
2014-08-01 08:07:48 +02:00
|
|
|
STAT_LOG(f, float(delta_read_jobs) * 1000.0 / float(tick_interval_ms));
|
|
|
|
STAT_LOG(f, float(delta_write_jobs) * 1000.0 / float(tick_interval_ms));
|
2011-06-29 00:20:34 +02:00
|
|
|
|
|
|
|
STAT_LOG(d, int(vm_stat.active_count));
|
|
|
|
STAT_LOG(d, int(vm_stat.inactive_count));
|
|
|
|
STAT_LOG(d, int(vm_stat.wire_count));
|
|
|
|
STAT_LOG(d, int(vm_stat.free_count));
|
|
|
|
STAT_LOG(d, int(vm_stat.pageins - m_last_vm_stat.pageins));
|
|
|
|
STAT_LOG(d, int(vm_stat.pageouts - m_last_vm_stat.pageouts));
|
|
|
|
STAT_LOG(d, int(vm_stat.faults - m_last_vm_stat.faults));
|
|
|
|
|
2014-08-01 08:07:48 +02:00
|
|
|
STAT_LOG(f, float(delta_read_jobs) * 1000.f / float(tick_interval_ms));
|
|
|
|
STAT_LOG(f, float(delta_write_jobs) * 1000.f / float(tick_interval_ms));
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(pinned_blocks);
|
|
|
|
|
|
|
|
STAT_LOGL(d, partial_pieces);
|
|
|
|
STAT_LOGL(d, partial_downloading_pieces);
|
|
|
|
STAT_LOGL(d, partial_full_pieces);
|
|
|
|
STAT_LOGL(d, partial_finished_pieces);
|
|
|
|
STAT_LOGL(d, partial_zero_prio_pieces);
|
|
|
|
|
|
|
|
STAT_COUNTER(num_jobs);
|
|
|
|
STAT_COUNTER(num_read_jobs);
|
|
|
|
STAT_COUNTER(num_write_jobs);
|
2011-07-03 19:21:45 +02:00
|
|
|
|
2013-10-03 17:39:19 +02:00
|
|
|
STAT_LOGL(d, reading_bytes);
|
2011-09-23 22:57:42 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
for (int i = counters::on_read_counter; i <= counters::on_disk_counter; ++i)
|
2013-10-03 17:39:19 +02:00
|
|
|
{
|
2014-08-01 08:07:48 +02:00
|
|
|
STAT_LOG(d, int(cnt[i]));
|
2013-10-03 17:39:19 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
for (int i = counters::socket_send_size3; i <= counters::socket_send_size20; ++i)
|
2013-10-03 17:39:19 +02:00
|
|
|
{
|
2014-08-01 08:07:48 +02:00
|
|
|
STAT_LOG(d, int(cnt[i]));
|
2013-10-03 17:39:19 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
for (int i = counters::socket_recv_size3; i <= counters::socket_recv_size20; ++i)
|
2013-10-03 17:39:19 +02:00
|
|
|
{
|
2014-08-01 08:07:48 +02:00
|
|
|
STAT_LOG(d, int(cnt[i]));
|
2013-10-03 17:39:19 +02:00
|
|
|
}
|
2011-10-17 07:17:21 +02:00
|
|
|
|
2012-03-09 02:22:45 +01:00
|
|
|
STAT_LOG(f, total_microseconds(cur_cpu_usage.user_time
|
|
|
|
- m_network_thread_cpu_usage.user_time) / double(tick_interval_ms * 10));
|
|
|
|
STAT_LOG(f, (total_microseconds(cur_cpu_usage.system_time
|
2011-10-17 19:12:08 +02:00
|
|
|
- m_network_thread_cpu_usage.system_time)
|
2012-03-09 02:22:45 +01:00
|
|
|
+ total_microseconds(cur_cpu_usage.user_time
|
|
|
|
- m_network_thread_cpu_usage.user_time))
|
|
|
|
/ double(tick_interval_ms * 10));
|
2011-10-17 19:12:08 +02:00
|
|
|
|
2014-07-29 07:59:00 +02:00
|
|
|
STAT_COUNTER(waste_piece_timed_out);
|
|
|
|
STAT_COUNTER(waste_piece_cancelled);
|
|
|
|
STAT_COUNTER(waste_piece_unknown);
|
|
|
|
STAT_COUNTER(waste_piece_seed);
|
|
|
|
STAT_COUNTER(waste_piece_end_game);
|
|
|
|
STAT_COUNTER(waste_piece_closing);
|
2011-11-16 03:29:59 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(no_memory_peers);
|
|
|
|
STAT_COUNTER(too_many_peers);
|
|
|
|
STAT_COUNTER(transport_timeout_peers);
|
|
|
|
|
|
|
|
STAT_LOGL(d, cs.arc_write_size);
|
|
|
|
STAT_LOGL(d, cs.arc_volatile_size);
|
|
|
|
STAT_LOG(d, cs.arc_volatile_size + cs.arc_mru_size);
|
|
|
|
STAT_LOG(d, cs.arc_volatile_size + cs.arc_mru_size + cs.arc_mru_ghost_size);
|
|
|
|
STAT_LOG(d, -cs.arc_mfu_size);
|
|
|
|
STAT_LOG(d, -cs.arc_mfu_size - cs.arc_mfu_ghost_size);
|
2013-10-03 17:39:19 +02:00
|
|
|
|
|
|
|
STAT_LOGL(d, sst.utp_stats.num_idle);
|
|
|
|
STAT_LOGL(d, sst.utp_stats.num_syn_sent);
|
|
|
|
STAT_LOGL(d, sst.utp_stats.num_connected);
|
|
|
|
STAT_LOGL(d, sst.utp_stats.num_fin_sent);
|
|
|
|
STAT_LOGL(d, sst.utp_stats.num_close_wait);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(num_tcp_peers);
|
|
|
|
STAT_COUNTER(num_utp_peers);
|
|
|
|
|
|
|
|
STAT_COUNTER(connrefused_peers);
|
|
|
|
STAT_COUNTER(connaborted_peers);
|
|
|
|
STAT_COUNTER(perm_peers);
|
|
|
|
STAT_COUNTER(buffer_peers);
|
|
|
|
STAT_COUNTER(unreachable_peers);
|
|
|
|
STAT_COUNTER(broken_pipe_peers);
|
|
|
|
STAT_COUNTER(addrinuse_peers);
|
|
|
|
STAT_COUNTER(no_access_peers);
|
|
|
|
STAT_COUNTER(invalid_arg_peers);
|
|
|
|
STAT_COUNTER(aborted_peers);
|
|
|
|
|
|
|
|
STAT_COUNTER(error_incoming_peers);
|
|
|
|
STAT_COUNTER(error_outgoing_peers);
|
|
|
|
STAT_COUNTER(error_rc4_peers);
|
|
|
|
STAT_COUNTER(error_encrypted_peers);
|
|
|
|
STAT_COUNTER(error_tcp_peers);
|
|
|
|
STAT_COUNTER(error_utp_peers);
|
2012-03-02 09:52:54 +01:00
|
|
|
|
2012-03-04 12:18:27 +01:00
|
|
|
STAT_LOG(d, int(m_connections.size()));
|
2013-10-03 17:39:19 +02:00
|
|
|
STAT_LOGL(d, pending_incoming_reqs);
|
2014-08-01 08:07:48 +02:00
|
|
|
STAT_LOG(f, cnt[counters::num_peers_connected] == 0 ? 0.f : (float(pending_incoming_reqs) / cnt[counters::num_peers_connected]));
|
2012-03-04 12:18:27 +01:00
|
|
|
|
2013-10-03 17:39:19 +02:00
|
|
|
STAT_LOGL(d, num_want_more_peers);
|
2012-03-06 11:34:18 +01:00
|
|
|
STAT_LOG(f, total_peers_limit == 0 ? 0 : float(num_limited_peers) / total_peers_limit);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(piece_requests);
|
|
|
|
STAT_COUNTER(max_piece_requests);
|
|
|
|
STAT_COUNTER(invalid_piece_requests);
|
|
|
|
STAT_COUNTER(choked_piece_requests);
|
|
|
|
STAT_COUNTER(cancelled_piece_requests);
|
|
|
|
STAT_COUNTER(piece_rejects);
|
|
|
|
|
|
|
|
STAT_COUNTER(num_total_pieces_added);
|
|
|
|
STAT_COUNTER(num_have_pieces);
|
|
|
|
STAT_COUNTER(num_piece_passed);
|
|
|
|
STAT_COUNTER(num_piece_failed);
|
2013-10-03 17:39:19 +02:00
|
|
|
|
|
|
|
STAT_LOGL(d, peers_up_send_buffer);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
STAT_COUNTER(utp_packet_loss);
|
|
|
|
STAT_COUNTER(utp_timeout);
|
|
|
|
STAT_COUNTER(utp_packets_in);
|
|
|
|
STAT_COUNTER(utp_packets_out);
|
|
|
|
STAT_COUNTER(utp_fast_retransmit);
|
|
|
|
STAT_COUNTER(utp_packet_resend);
|
|
|
|
STAT_COUNTER(utp_samples_above_target);
|
|
|
|
STAT_COUNTER(utp_samples_below_target);
|
|
|
|
STAT_COUNTER(utp_payload_pkts_in);
|
|
|
|
STAT_COUNTER(utp_payload_pkts_out);
|
|
|
|
STAT_COUNTER(utp_invalid_pkts_in);
|
|
|
|
STAT_COUNTER(utp_redundant_pkts_in);
|
|
|
|
|
|
|
|
// loaded torrents
|
|
|
|
STAT_COUNTER(num_loaded_torrents);
|
|
|
|
STAT_COUNTER(num_pinned_torrents);
|
|
|
|
STAT_COUNTER(torrent_evicted_counter);
|
|
|
|
|
|
|
|
STAT_COUNTER(num_incoming_choke);
|
|
|
|
STAT_COUNTER(num_incoming_unchoke);
|
|
|
|
STAT_COUNTER(num_incoming_interested);
|
|
|
|
STAT_COUNTER(num_incoming_not_interested);
|
|
|
|
STAT_COUNTER(num_incoming_have);
|
|
|
|
STAT_COUNTER(num_incoming_bitfield);
|
|
|
|
STAT_COUNTER(num_incoming_request);
|
|
|
|
STAT_COUNTER(num_incoming_piece);
|
|
|
|
STAT_COUNTER(num_incoming_cancel);
|
|
|
|
STAT_COUNTER(num_incoming_dht_port);
|
|
|
|
STAT_COUNTER(num_incoming_suggest);
|
|
|
|
STAT_COUNTER(num_incoming_have_all);
|
|
|
|
STAT_COUNTER(num_incoming_have_none);
|
|
|
|
STAT_COUNTER(num_incoming_reject);
|
|
|
|
STAT_COUNTER(num_incoming_allowed_fast);
|
|
|
|
STAT_COUNTER(num_incoming_ext_handshake);
|
|
|
|
STAT_COUNTER(num_incoming_pex);
|
|
|
|
STAT_COUNTER(num_incoming_metadata);
|
|
|
|
STAT_COUNTER(num_incoming_extended);
|
|
|
|
|
|
|
|
STAT_COUNTER(num_outgoing_choke);
|
|
|
|
STAT_COUNTER(num_outgoing_unchoke);
|
|
|
|
STAT_COUNTER(num_outgoing_interested);
|
|
|
|
STAT_COUNTER(num_outgoing_not_interested);
|
|
|
|
STAT_COUNTER(num_outgoing_have);
|
|
|
|
STAT_COUNTER(num_outgoing_bitfield);
|
|
|
|
STAT_COUNTER(num_outgoing_request);
|
|
|
|
STAT_COUNTER(num_outgoing_piece);
|
|
|
|
STAT_COUNTER(num_outgoing_cancel);
|
|
|
|
STAT_COUNTER(num_outgoing_dht_port);
|
|
|
|
STAT_COUNTER(num_outgoing_suggest);
|
|
|
|
STAT_COUNTER(num_outgoing_have_all);
|
|
|
|
STAT_COUNTER(num_outgoing_have_none);
|
|
|
|
STAT_COUNTER(num_outgoing_reject);
|
|
|
|
STAT_COUNTER(num_outgoing_allowed_fast);
|
|
|
|
STAT_COUNTER(num_outgoing_ext_handshake);
|
|
|
|
STAT_COUNTER(num_outgoing_pex);
|
|
|
|
STAT_COUNTER(num_outgoing_metadata);
|
|
|
|
STAT_COUNTER(num_outgoing_extended);
|
|
|
|
|
|
|
|
STAT_LOG(d, cs.blocked_jobs);
|
|
|
|
STAT_COUNTER(num_writing_threads);
|
|
|
|
STAT_COUNTER(num_running_threads);
|
|
|
|
STAT_COUNTER(incoming_connections);
|
|
|
|
|
|
|
|
STAT_LOG(d, cs.num_fence_jobs[disk_io_job::move_storage]);
|
|
|
|
STAT_LOG(d, cs.num_fence_jobs[disk_io_job::release_files]);
|
|
|
|
STAT_LOG(d, cs.num_fence_jobs[disk_io_job::delete_files]);
|
|
|
|
STAT_LOG(d, cs.num_fence_jobs[disk_io_job::check_fastresume]);
|
|
|
|
STAT_LOG(d, cs.num_fence_jobs[disk_io_job::save_resume_data]);
|
|
|
|
STAT_LOG(d, cs.num_fence_jobs[disk_io_job::rename_file]);
|
|
|
|
STAT_LOG(d, cs.num_fence_jobs[disk_io_job::stop_torrent]);
|
|
|
|
STAT_LOG(d, cs.num_fence_jobs[disk_io_job::file_priority]);
|
|
|
|
STAT_LOG(d, cs.num_fence_jobs[disk_io_job::clear_piece]);
|
|
|
|
|
|
|
|
STAT_COUNTER(piece_picker_partial_loops);
|
|
|
|
STAT_COUNTER(piece_picker_suggest_loops);
|
|
|
|
STAT_COUNTER(piece_picker_sequential_loops);
|
|
|
|
STAT_COUNTER(piece_picker_reverse_rare_loops);
|
|
|
|
STAT_COUNTER(piece_picker_rare_loops);
|
|
|
|
STAT_COUNTER(piece_picker_rand_start_loops);
|
|
|
|
STAT_COUNTER(piece_picker_rand_loops);
|
|
|
|
STAT_COUNTER(piece_picker_busy_loops);
|
|
|
|
|
|
|
|
STAT_COUNTER(connection_attempt_loops);
|
2013-09-14 12:06:48 +02:00
|
|
|
|
2014-07-29 00:18:06 +02:00
|
|
|
STAT_COUNTER(request_latency);
|
|
|
|
|
2011-06-26 20:43:23 +02:00
|
|
|
fprintf(m_stats_logger, "\n");
|
|
|
|
|
|
|
|
#undef STAT_LOG
|
2013-10-03 17:39:19 +02:00
|
|
|
#undef STAT_LOGL
|
2011-06-26 20:43:23 +02:00
|
|
|
|
2011-04-06 08:27:42 +02:00
|
|
|
m_last_cache_status = cs;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!vm_ec) m_last_vm_stat = vm_stat;
|
2011-10-17 19:12:08 +02:00
|
|
|
m_network_thread_cpu_usage = cur_cpu_usage;
|
2014-08-01 08:07:48 +02:00
|
|
|
|
|
|
|
m_last_stats_counters = cnt;
|
2011-04-06 08:27:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // TORRENT_STATS
|
|
|
|
|
2011-01-18 04:41:54 +01:00
|
|
|
void session_impl::update_rss_feeds()
|
|
|
|
{
|
|
|
|
time_t now_posix = time(0);
|
|
|
|
ptime min_update = max_time();
|
|
|
|
ptime now = time_now();
|
|
|
|
for (std::vector<boost::shared_ptr<feed> >::iterator i
|
|
|
|
= m_feeds.begin(), end(m_feeds.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
feed& f = **i;
|
|
|
|
int delta = f.next_update(now_posix);
|
|
|
|
if (delta <= 0)
|
2012-02-22 09:26:42 +01:00
|
|
|
delta = f.update_feed();
|
|
|
|
TORRENT_ASSERT(delta >= 0);
|
2011-01-18 04:41:54 +01:00
|
|
|
ptime next_update = now + seconds(delta);
|
|
|
|
if (next_update < min_update) min_update = next_update;
|
|
|
|
}
|
|
|
|
m_next_rss_update = min_update;
|
|
|
|
}
|
|
|
|
|
2012-11-03 04:50:12 +01:00
|
|
|
void session_impl::prioritize_connections(boost::weak_ptr<torrent> t)
|
|
|
|
{
|
|
|
|
m_prio_torrents.push_back(std::make_pair(t, 10));
|
|
|
|
}
|
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
|
2012-11-03 04:50:12 +01:00
|
|
|
void session_impl::add_dht_node(udp::endpoint n)
|
|
|
|
{
|
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);
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
bool session_impl::has_dht() const
|
|
|
|
{
|
|
|
|
return m_dht.get();
|
|
|
|
}
|
|
|
|
|
2012-11-03 04:50:12 +01:00
|
|
|
void session_impl::prioritize_dht(boost::weak_ptr<torrent> t)
|
|
|
|
{
|
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);
|
2014-07-06 21:18:00 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
boost::shared_ptr<torrent> tor = t.lock();
|
|
|
|
if (tor)
|
|
|
|
session_log("prioritizing DHT announce: \"%s\"", tor->name().c_str());
|
|
|
|
#endif
|
2012-11-03 04:50:12 +01:00
|
|
|
// trigger a DHT announce right away if we just
|
|
|
|
// added a new torrent and there's no back-log
|
|
|
|
if (m_dht_torrents.size() == 1)
|
|
|
|
{
|
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::on_dht_announce");
|
|
|
|
#endif
|
|
|
|
error_code ec;
|
|
|
|
m_dht_announce_timer.expires_from_now(seconds(0), ec);
|
|
|
|
m_dht_announce_timer.async_wait(
|
|
|
|
bind(&session_impl::on_dht_announce, this, _1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
void session_impl::on_dht_announce(error_code const& e)
|
|
|
|
{
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
complete_async("session_impl::on_dht_announce");
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log("aborting DHT announce timer (%d): %s"
|
|
|
|
, e.value(), e.message().c_str());
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2010-02-14 02:39:55 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_abort)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::on_dht_announce");
|
|
|
|
#endif
|
2010-02-14 02:39:55 +01:00
|
|
|
error_code ec;
|
|
|
|
m_dht_announce_timer.expires_from_now(seconds(delay), ec);
|
|
|
|
m_dht_announce_timer.async_wait(
|
|
|
|
bind(&session_impl::on_dht_announce, this, _1));
|
|
|
|
|
2012-08-03 07:13:40 +02:00
|
|
|
if (!m_dht_torrents.empty())
|
|
|
|
{
|
|
|
|
boost::shared_ptr<torrent> t;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
t = m_dht_torrents.front().lock();
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-02-05 09:23:17 +01:00
|
|
|
void session_impl::on_lsd_announce(error_code const& e)
|
|
|
|
{
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
complete_async("session_impl::on_lsd_announce");
|
2011-10-17 07:17:21 +02:00
|
|
|
#endif
|
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
|
|
|
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::on_lsd_announce");
|
|
|
|
#endif
|
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);
|
|
|
|
m_lsd_announce_timer.async_wait(
|
|
|
|
bind(&session_impl::on_lsd_announce, this, _1));
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2010-03-29 02:34:04 +02:00
|
|
|
void session_impl::auto_manage_torrents(std::vector<torrent*>& list
|
2014-07-06 21:18:00 +02:00
|
|
|
, int& checking_limit, int& dht_limit, int& tracker_limit
|
|
|
|
, int& lsd_limit, int& hard_limit, int type_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
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (t->state() == torrent_status::checking_files)
|
|
|
|
{
|
|
|
|
if (checking_limit <= 0) t->pause();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
t->resume();
|
|
|
|
t->start_checking();
|
|
|
|
--checking_limit;
|
|
|
|
}
|
2011-02-04 07:55:05 +01:00
|
|
|
continue;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2011-02-04 07:55:05 +01:00
|
|
|
|
2014-05-23 00:07:01 +02:00
|
|
|
--dht_limit;
|
|
|
|
--lsd_limit;
|
|
|
|
--tracker_limit;
|
|
|
|
t->set_announce_to_dht(dht_limit >= 0);
|
|
|
|
t->set_announce_to_trackers(tracker_limit >= 0);
|
|
|
|
t->set_announce_to_lsd(lsd_limit >= 0);
|
|
|
|
|
|
|
|
if (!t->is_paused() && t->is_inactive()
|
|
|
|
&& hard_limit > 0)
|
|
|
|
{
|
|
|
|
// the hard limit takes inactive torrents into account, but the
|
|
|
|
// download and seed limits don't.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-05-27 21:27:12 +02:00
|
|
|
if (type_limit > 0 && hard_limit > 0)
|
|
|
|
{
|
|
|
|
--hard_limit;
|
|
|
|
--type_limit;
|
2012-09-27 19:39:41 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!t->allows_peers())
|
|
|
|
t->log_to_all_peers("AUTO MANAGER STARTING TORRENT");
|
2010-08-18 19:14:40 +02:00
|
|
|
#endif
|
2010-03-31 04:40:00 +02:00
|
|
|
t->set_allow_peers(true);
|
2009-05-27 21:27:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-09-27 19:39:41 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
2014-07-06 21:18:00 +02:00
|
|
|
if (t->allows_peers())
|
|
|
|
t->log_to_all_peers("AUTO MANAGER PAUSING TORRENT");
|
2010-08-18 19:14:40 +02:00
|
|
|
#endif
|
2010-10-30 10:36:18 +02:00
|
|
|
// use graceful pause for auto-managed torrents
|
|
|
|
t->set_allow_peers(false, true);
|
2009-05-27 21:27:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-06-21 14:31:28 +02:00
|
|
|
|
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;
|
|
|
|
|
2012-11-03 04:50:12 +01:00
|
|
|
m_need_auto_manage = false;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (is_paused()) return;
|
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
// these vectors are filled with auto managed torrents
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// TODO: these vectors could be copied from m_torrent_lists,
|
|
|
|
// if we would maintain them. That way the first pass over
|
|
|
|
// all torrents could be avoided. It would be especially
|
|
|
|
// efficient if most torrents are not auto-managed
|
|
|
|
// whenever we receive a scrape response (or anything
|
|
|
|
// that may change the rank of a torrent) that one torrent
|
|
|
|
// could re-sort itself in a list that's kept sorted at all
|
|
|
|
// times. That way, this pass over all torrents could be
|
|
|
|
// avoided alltogether.
|
|
|
|
std::vector<torrent*> checking;
|
2008-04-24 05:28:48 +02:00
|
|
|
std::vector<torrent*> downloaders;
|
|
|
|
downloaders.reserve(m_torrents.size());
|
|
|
|
std::vector<torrent*> seeds;
|
|
|
|
seeds.reserve(m_torrents.size());
|
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
|
2014-07-06 21:18:00 +02:00
|
|
|
int num_downloaders = settings().get_int(settings_pack::active_downloads);
|
|
|
|
int num_seeds = settings().get_int(settings_pack::active_seeds);
|
|
|
|
int checking_limit = 1;
|
|
|
|
int dht_limit = settings().get_int(settings_pack::active_dht_limit);
|
|
|
|
int tracker_limit = settings().get_int(settings_pack::active_tracker_limit);
|
|
|
|
int lsd_limit = settings().get_int(settings_pack::active_lsd_limit);
|
|
|
|
int hard_limit = settings().get_int(settings_pack::active_limit);
|
2007-08-16 14:41:46 +02:00
|
|
|
|
2008-08-29 02:44:55 +02:00
|
|
|
if (num_downloaders == -1)
|
|
|
|
num_downloaders = (std::numeric_limits<int>::max)();
|
|
|
|
if (num_seeds == -1)
|
|
|
|
num_seeds = (std::numeric_limits<int>::max)();
|
|
|
|
if (hard_limit == -1)
|
|
|
|
hard_limit = (std::numeric_limits<int>::max)();
|
2012-12-31 04:12:11 +01:00
|
|
|
if (dht_limit == -1)
|
|
|
|
dht_limit = (std::numeric_limits<int>::max)();
|
|
|
|
if (lsd_limit == -1)
|
|
|
|
lsd_limit = (std::numeric_limits<int>::max)();
|
|
|
|
if (tracker_limit == -1)
|
|
|
|
tracker_limit = (std::numeric_limits<int>::max)();
|
2008-06-17 17:44:04 +02:00
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
torrent* t = i->second.get();
|
|
|
|
TORRENT_ASSERT(t);
|
2011-02-04 07:55:05 +01:00
|
|
|
|
2008-05-20 09:57:44 +02:00
|
|
|
if (t->is_auto_managed() && !t->has_error())
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if (t->state() == torrent_status::checking_files)
|
|
|
|
{
|
|
|
|
checking.push_back(t);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-06-09 07:46:47 +02:00
|
|
|
TORRENT_ASSERT(t->m_resume_data_loaded || !t->valid_metadata());
|
2008-04-24 05:28:48 +02:00
|
|
|
// this torrent is auto managed, add it to
|
|
|
|
// the list (depending on if it's a seed or not)
|
|
|
|
if (t->is_finished())
|
|
|
|
seeds.push_back(t);
|
|
|
|
else
|
|
|
|
downloaders.push_back(t);
|
|
|
|
}
|
|
|
|
else if (!t->is_paused())
|
2008-01-13 12:18:18 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if (t->state() == torrent_status::checking_files)
|
|
|
|
{
|
|
|
|
if (checking_limit > 0) --checking_limit;
|
|
|
|
continue;
|
|
|
|
}
|
2011-06-09 07:46:47 +02:00
|
|
|
TORRENT_ASSERT(t->m_resume_data_loaded || !t->valid_metadata());
|
2008-06-21 14:31:28 +02:00
|
|
|
--hard_limit;
|
2008-01-13 12:18:18 +01:00
|
|
|
}
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool handled_by_extension = false;
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2013-01-21 00:21:53 +01:00
|
|
|
// TODO: 0 allow extensions to sort torrents for queuing
|
2008-04-24 05:28:48 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!handled_by_extension)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
std::sort(checking.begin(), checking.end()
|
|
|
|
, boost::bind(&torrent::sequence_number, _1) < boost::bind(&torrent::sequence_number, _2));
|
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
std::sort(downloaders.begin(), downloaders.end()
|
2010-07-22 18:49:40 +02:00
|
|
|
, boost::bind(&torrent::sequence_number, _1) < boost::bind(&torrent::sequence_number, _2));
|
2008-04-24 05:28:48 +02:00
|
|
|
|
|
|
|
std::sort(seeds.begin(), seeds.end()
|
2010-07-22 18:49:40 +02:00
|
|
|
, boost::bind(&torrent::seed_rank, _1, boost::ref(m_settings))
|
|
|
|
> boost::bind(&torrent::seed_rank, _2, boost::ref(m_settings)));
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
auto_manage_torrents(checking, checking_limit, dht_limit, tracker_limit, lsd_limit
|
|
|
|
, hard_limit, num_downloaders);
|
|
|
|
|
|
|
|
if (settings().get_bool(settings_pack::auto_manage_prefer_seeds))
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
auto_manage_torrents(seeds, checking_limit, dht_limit, tracker_limit, lsd_limit
|
2010-03-29 02:34:04 +02:00
|
|
|
, hard_limit, num_seeds);
|
2014-07-06 21:18:00 +02:00
|
|
|
auto_manage_torrents(downloaders, checking_limit, dht_limit, tracker_limit, lsd_limit
|
2010-03-29 02:34:04 +02:00
|
|
|
, hard_limit, num_downloaders);
|
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
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
auto_manage_torrents(downloaders, checking_limit, dht_limit, tracker_limit, lsd_limit
|
2010-03-29 02:34:04 +02:00
|
|
|
, hard_limit, num_downloaders);
|
2014-07-06 21:18:00 +02:00
|
|
|
auto_manage_torrents(seeds, checking_limit, dht_limit, tracker_limit, lsd_limit
|
2010-03-29 02:34:04 +02:00
|
|
|
, hard_limit, num_seeds);
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
|
|
|
}
|
2007-08-16 14:41:46 +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
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2008-10-19 00:35:10 +02:00
|
|
|
if (m_allowed_upload_slots == 0) return;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
std::vector<torrent_peer*> opt_unchoke;
|
2008-10-19 00:35:10 +02:00
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
for (connection_map::iterator i = m_connections.begin()
|
|
|
|
, end(m_connections.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
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
|
|
|
torrent* t = p->associated_torrent().lock().get();
|
|
|
|
if (!t) continue;
|
2010-10-30 10:36:18 +02:00
|
|
|
if (t->is_paused()) continue;
|
2008-10-19 00:35:10 +02:00
|
|
|
|
|
|
|
if (pi->optimistically_unchoked)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(!p->is_choked());
|
2010-02-02 19:39:32 +01:00
|
|
|
opt_unchoke.push_back(pi);
|
2008-10-19 00:35:10 +02:00
|
|
|
}
|
|
|
|
|
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()
|
|
|
|
&& p->is_choked()
|
2009-01-28 07:14:21 +01:00
|
|
|
&& !p->ignore_unchoke_slots()
|
2008-10-19 00:35:10 +02:00
|
|
|
&& t->valid_metadata())
|
|
|
|
{
|
2010-02-02 19:39:32 +01:00
|
|
|
opt_unchoke.push_back(pi);
|
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
|
|
|
|
|
|
|
|
// avoid having a bias towards peers that happen to be sorted first
|
|
|
|
std::random_shuffle(opt_unchoke.begin(), opt_unchoke.end());
|
|
|
|
|
|
|
|
// sort all candidates based on when they were last optimistically
|
|
|
|
// unchoked.
|
|
|
|
std::sort(opt_unchoke.begin(), opt_unchoke.end()
|
2014-07-06 21:18:00 +02:00
|
|
|
, boost::bind(&torrent_peer::last_optimistically_unchoked, _1)
|
|
|
|
< boost::bind(&torrent_peer::last_optimistically_unchoked, _2));
|
2010-02-02 19:39:32 +01:00
|
|
|
|
2014-05-12 09:28:34 +02:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
for (ses_extension_list_t::iterator i = m_ses_extensions.begin()
|
|
|
|
, end(m_ses_extensions.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if ((*i)->on_optimistic_unchoke(opt_unchoke))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int num_opt_unchoke = m_settings.get_int(settings_pack::num_optimistic_unchoke_slots);
|
2010-02-02 19:39:32 +01:00
|
|
|
if (num_opt_unchoke == 0) num_opt_unchoke = (std::max)(1, m_allowed_upload_slots / 5);
|
|
|
|
|
|
|
|
// unchoke the first num_opt_unchoke peers in the candidate set
|
|
|
|
// and make sure that the others are choked
|
2014-07-06 21:18:00 +02:00
|
|
|
for (std::vector<torrent_peer*>::iterator i = opt_unchoke.begin()
|
2010-02-02 19:39:32 +01:00
|
|
|
, end(opt_unchoke.end()); i != end; ++i)
|
2008-10-19 00:35:10 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent_peer* pi = *i;
|
2010-02-02 19:39:32 +01:00
|
|
|
if (num_opt_unchoke > 0)
|
2008-10-19 00:35:10 +02:00
|
|
|
{
|
2010-02-02 19:39:32 +01:00
|
|
|
--num_opt_unchoke;
|
|
|
|
if (!pi->optimistically_unchoked)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
peer_connection* p = static_cast<peer_connection*>(pi->connection);
|
|
|
|
torrent* t = p->associated_torrent().lock().get();
|
|
|
|
bool ret = t->unchoke_peer(*p, true);
|
2010-10-04 06:06:14 +02:00
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
pi->optimistically_unchoked = true;
|
2014-09-22 05:47:43 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic);
|
2014-05-10 05:23:05 +02:00
|
|
|
pi->last_optimistically_unchoked = boost::uint16_t(session_time());
|
2010-10-04 06:06:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// we failed to unchoke it, increment the count again
|
|
|
|
++num_opt_unchoke;
|
|
|
|
}
|
2010-02-02 19:39:32 +01:00
|
|
|
}
|
2008-10-19 00:35:10 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-02-02 19:39:32 +01:00
|
|
|
if (pi->optimistically_unchoked)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
peer_connection* p = static_cast<peer_connection*>(pi->connection);
|
|
|
|
torrent* t = p->associated_torrent().lock().get();
|
2010-02-02 19:39:32 +01:00
|
|
|
pi->optimistically_unchoked = false;
|
2014-09-22 05:47:43 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic, -1);
|
2014-07-06 21:18:00 +02:00
|
|
|
t->choke_peer(*p);
|
2010-02-02 19:39:32 +01:00
|
|
|
}
|
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
|
2014-10-03 22:56:57 +02:00
|
|
|
int limit = m_settings.get_int(settings_pack::connections_limit)
|
|
|
|
- num_connections();
|
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)
|
2012-07-04 22:41:22 +02:00
|
|
|
max_connections = (limit+1) / 2;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
std::vector<torrent*>& want_peers_download = m_torrent_lists[torrent_want_peers_download];
|
|
|
|
std::vector<torrent*>& want_peers_finished = m_torrent_lists[torrent_want_peers_finished];
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
torrent* t = NULL;
|
|
|
|
// 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
|
|
|
|
&& t != NULL
|
|
|
|
&& t->want_peers()) break;
|
|
|
|
m_prio_torrents.pop_front();
|
|
|
|
t = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t == NULL)
|
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());
|
|
|
|
TORRENT_ASSERT(t->allows_peers());
|
|
|
|
|
|
|
|
TORRENT_TRY
|
|
|
|
{
|
|
|
|
if (t->try_connect_peer())
|
|
|
|
{
|
|
|
|
--max_connections;
|
|
|
|
steps_since_last_connect = 0;
|
2014-07-13 06:56:53 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::connection_attempts);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2012-07-04 22:41:22 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_CATCH(std::bad_alloc&)
|
|
|
|
{
|
|
|
|
// we ran out of memory trying to connect to a peer
|
|
|
|
// lower the global limit to the number of peers
|
|
|
|
// we already have
|
|
|
|
m_settings.set_int(settings_pack::connections_limit, num_connections());
|
|
|
|
if (m_settings.get_int(settings_pack::connections_limit) < 2)
|
|
|
|
m_settings.set_int(settings_pack::connections_limit, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
++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;
|
|
|
|
|
2009-04-04 09:55:34 +02:00
|
|
|
ptime now = time_now();
|
|
|
|
time_duration unchoke_interval = now - m_last_choke;
|
|
|
|
m_last_choke = now;
|
|
|
|
|
|
|
|
// build list of all peers that are
|
2011-04-30 22:33:35 +02:00
|
|
|
// unchokable.
|
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();)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
boost::shared_ptr<peer_connection> p = *i;
|
2008-10-19 00:35:10 +02:00
|
|
|
TORRENT_ASSERT(p);
|
|
|
|
++i;
|
2008-04-24 05:28:48 +02:00
|
|
|
torrent* t = p->associated_torrent().lock().get();
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent_peer* pi = p->peer_info_struct();
|
2010-02-09 04:04:41 +01:00
|
|
|
|
2012-04-12 02:02:35 +02:00
|
|
|
if (p->ignore_unchoke_slots() || t == 0 || pi == 0 || pi->web_seed || t->is_paused())
|
|
|
|
continue;
|
2009-04-04 09:55:34 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::bittyrant_choker)
|
2010-02-09 04:04:41 +01:00
|
|
|
{
|
2010-10-09 23:11:03 +02:00
|
|
|
if (!p->is_choked() && p->is_interesting())
|
2010-02-09 04:04:41 +01:00
|
|
|
{
|
|
|
|
if (!p->has_peer_choked())
|
|
|
|
{
|
|
|
|
// we're unchoked, we may want to lower our estimated
|
|
|
|
// reciprocation rate
|
|
|
|
p->decrease_est_reciprocation_rate();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// we've unchoked this peer, and it hasn't reciprocated
|
|
|
|
// we may want to increase our estimated reciprocation rate
|
|
|
|
p->increase_est_reciprocation_rate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
if (p->is_choked()) continue;
|
|
|
|
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);
|
2009-05-02 05:15:52 +02:00
|
|
|
continue;
|
2007-08-16 14:41:46 +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-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::rate_based_choker)
|
2009-04-04 09:55:34 +02:00
|
|
|
{
|
|
|
|
m_allowed_upload_slots = 0;
|
|
|
|
std::sort(peers.begin(), peers.end()
|
2010-07-22 18:49:40 +02:00
|
|
|
, boost::bind(&peer_connection::upload_rate_compare, _1, _2));
|
2009-04-04 09:55:34 +02:00
|
|
|
|
2009-05-02 05:15:52 +02:00
|
|
|
#ifdef TORRENT_DEBUG
|
|
|
|
for (std::vector<peer_connection*>::const_iterator i = peers.begin()
|
|
|
|
, end(peers.end()), prev(peers.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if (prev != end)
|
|
|
|
{
|
2010-06-25 16:14:36 +02:00
|
|
|
boost::shared_ptr<torrent> t1 = (*prev)->associated_torrent().lock();
|
|
|
|
TORRENT_ASSERT(t1);
|
|
|
|
boost::shared_ptr<torrent> t2 = (*i)->associated_torrent().lock();
|
|
|
|
TORRENT_ASSERT(t2);
|
2013-06-02 00:33:11 +02:00
|
|
|
TORRENT_ASSERT((*prev)->uploaded_in_last_round() * 1000
|
2010-07-15 03:46:50 +02:00
|
|
|
* (1 + t1->priority()) / total_milliseconds(unchoke_interval)
|
2013-06-02 00:33:11 +02:00
|
|
|
>= (*i)->uploaded_in_last_round() * 1000
|
2010-07-15 03:46:50 +02:00
|
|
|
* (1 + t2->priority()) / total_milliseconds(unchoke_interval));
|
2009-05-02 05:15:52 +02:00
|
|
|
}
|
|
|
|
prev = i;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-04-04 09:55:34 +02:00
|
|
|
// TODO: make configurable
|
|
|
|
int rate_threshold = 1024;
|
|
|
|
|
|
|
|
for (std::vector<peer_connection*>::const_iterator i = peers.begin()
|
|
|
|
, end(peers.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
peer_connection const& p = **i;
|
2013-06-02 00:33:11 +02:00
|
|
|
int rate = int(p.uploaded_in_last_round()
|
2011-02-21 06:24:41 +01:00
|
|
|
* 1000 / total_milliseconds(unchoke_interval));
|
2009-05-02 05:15:52 +02:00
|
|
|
|
2009-07-26 04:27:52 +02:00
|
|
|
if (rate < rate_threshold) break;
|
2009-07-19 00:55:07 +02:00
|
|
|
|
2009-05-02 05:15:52 +02:00
|
|
|
++m_allowed_upload_slots;
|
2009-04-04 09:55:34 +02:00
|
|
|
|
|
|
|
// TODO: make configurable
|
|
|
|
rate_threshold += 1024;
|
|
|
|
}
|
|
|
|
// allow one optimistic unchoke
|
|
|
|
++m_allowed_upload_slots;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::bittyrant_choker)
|
2010-02-09 04:04:41 +01:00
|
|
|
{
|
|
|
|
// if we're using the bittyrant choker, sort peers by their return
|
|
|
|
// on investment. i.e. download rate / upload rate
|
|
|
|
std::sort(peers.begin(), peers.end()
|
2010-07-22 18:49:40 +02:00
|
|
|
, boost::bind(&peer_connection::bittyrant_unchoke_compare, _1, _2));
|
2010-02-09 04:04:41 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// sorts the peers that are eligible for unchoke by download rate and secondary
|
|
|
|
// by total upload. The reason for this is, if all torrents are being seeded,
|
|
|
|
// the download rate will be 0, and the peers we have sent the least to should
|
|
|
|
// be unchoked
|
|
|
|
std::sort(peers.begin(), peers.end()
|
2010-07-22 18:49:40 +02:00
|
|
|
, boost::bind(&peer_connection::unchoke_compare, _1, _2));
|
2010-02-09 04:04:41 +01:00
|
|
|
}
|
2007-08-16 14:41:46 +02:00
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
// auto unchoke
|
2014-07-06 21:18:00 +02:00
|
|
|
peer_class* gpc = m_classes.at(m_global_class);
|
|
|
|
int upload_limit = gpc->channel[peer_connection::upload_channel].throttle();
|
|
|
|
if (m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::auto_expand_choker
|
2009-04-26 02:21:59 +02:00
|
|
|
&& upload_limit > 0)
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
|
|
|
// if our current upload rate is less than 90% of our
|
|
|
|
// limit
|
|
|
|
if (m_stat.upload_rate() < upload_limit * 0.9f
|
2014-09-22 05:47:43 +02:00
|
|
|
&& m_allowed_upload_slots
|
|
|
|
<= m_stats_counters[counters::num_peers_up_unchoked] + 1
|
2009-04-26 02:21:59 +02:00
|
|
|
&& m_upload_rate.queue_size() < 2)
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
|
|
|
++m_allowed_upload_slots;
|
|
|
|
}
|
2009-04-26 02:21:59 +02:00
|
|
|
else if (m_upload_rate.queue_size() > 1
|
2014-07-06 21:18:00 +02:00
|
|
|
&& m_allowed_upload_slots > m_settings.get_int(settings_pack::unchoke_slots_limit)
|
|
|
|
&& m_settings.get_int(settings_pack::unchoke_slots_limit) >= 0)
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
|
|
|
--m_allowed_upload_slots;
|
|
|
|
}
|
|
|
|
}
|
2007-08-17 09:37:08 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int num_opt_unchoke = m_settings.get_int(settings_pack::num_optimistic_unchoke_slots);
|
2010-02-02 19:39:32 +01:00
|
|
|
if (num_opt_unchoke == 0) num_opt_unchoke = (std::max)(1, m_allowed_upload_slots / 5);
|
|
|
|
|
2010-02-09 04:04:41 +01:00
|
|
|
// reserve some upload slots for optimistic unchokes
|
2010-02-02 19:39:32 +01:00
|
|
|
int unchoke_set_size = m_allowed_upload_slots - num_opt_unchoke;
|
2007-08-17 09:37:08 +02:00
|
|
|
|
2010-02-09 04:04:41 +01:00
|
|
|
int upload_capacity_left = 0;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::bittyrant_choker)
|
2010-02-09 04:04:41 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
upload_capacity_left = upload_rate_limit(m_global_class);
|
2010-02-09 04:04:41 +01:00
|
|
|
if (upload_capacity_left == 0)
|
|
|
|
{
|
|
|
|
// 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
|
|
|
|
upload_capacity_left = (std::max)(20000, m_peak_up_rate + 10000);
|
|
|
|
if (m_alerts.should_post<performance_alert>())
|
|
|
|
m_alerts.post_alert(performance_alert(torrent_handle()
|
|
|
|
, performance_alert::bittyrant_with_no_uplimit));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
// go through all the peers and unchoke the first ones and choke
|
|
|
|
// all the other ones.
|
|
|
|
for (std::vector<peer_connection*>::iterator i = peers.begin()
|
|
|
|
, end(peers.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
peer_connection* p = *i;
|
|
|
|
TORRENT_ASSERT(p);
|
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
|
2014-07-06 21:18:00 +02:00
|
|
|
// TODO: this should be called for all peers!
|
2009-05-02 05:15:52 +02:00
|
|
|
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
|
|
|
|
|
|
|
// if this peer should be unchoked depends on different things
|
|
|
|
// in different unchoked schemes
|
|
|
|
bool unchoke = false;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::bittyrant_choker)
|
2010-02-09 04:04:41 +01:00
|
|
|
{
|
|
|
|
unchoke = p->est_reciprocation_rate() <= upload_capacity_left;
|
|
|
|
}
|
|
|
|
else
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
2010-02-09 04:04:41 +01:00
|
|
|
unchoke = unchoke_set_size > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unchoke)
|
|
|
|
{
|
|
|
|
upload_capacity_left -= p->est_reciprocation_rate();
|
|
|
|
|
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
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::cork_burst(peer_connection* p)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(is_single_thread());
|
|
|
|
if (p->is_corked()) return;
|
|
|
|
p->cork_socket();
|
|
|
|
m_delayed_uncorks.push_back(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::do_delayed_uncork()
|
|
|
|
{
|
2014-07-13 06:56:53 +02:00
|
|
|
m_stats_counters.inc_stats_counter(counters::on_disk_counter);
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
|
|
|
for (std::vector<peer_connection*>::iterator i = m_delayed_uncorks.begin()
|
|
|
|
, end(m_delayed_uncorks.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
(*i)->uncork_socket();
|
|
|
|
}
|
|
|
|
m_delayed_uncorks.clear();
|
|
|
|
}
|
|
|
|
|
2013-07-19 21:06:27 +02:00
|
|
|
#if defined _MSC_VER && defined TORRENT_DEBUG
|
|
|
|
static void straight_to_debugger(unsigned int, _EXCEPTION_POINTERS*)
|
|
|
|
{ throw; }
|
|
|
|
#endif
|
|
|
|
|
2009-10-20 04:49:56 +02:00
|
|
|
void session_impl::main_thread()
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2013-07-19 21:06:27 +02:00
|
|
|
#if defined _MSC_VER && defined TORRENT_DEBUG
|
|
|
|
// workaround for microsofts
|
|
|
|
// hardware exceptions that makes
|
|
|
|
// it hard to debug stuff
|
|
|
|
::_set_se_translator(straight_to_debugger);
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
// this is a debug facility
|
|
|
|
// see single_threaded in debug.hpp
|
|
|
|
thread_started();
|
|
|
|
|
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2010-09-25 22:07:27 +02:00
|
|
|
// initialize async operations
|
2010-12-04 23:20:31 +01:00
|
|
|
init();
|
2010-09-25 22:07:27 +02:00
|
|
|
|
2010-06-24 23:43:00 +02:00
|
|
|
bool stop_loop = false;
|
|
|
|
while (!stop_loop)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2008-11-05 06:39:18 +01:00
|
|
|
error_code ec;
|
|
|
|
m_io_service.run(ec);
|
|
|
|
if (ec)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2008-11-29 22:33:21 +01:00
|
|
|
#ifdef TORRENT_DEBUG
|
2009-10-20 04:49:56 +02:00
|
|
|
fprintf(stderr, "%s\n", ec.message().c_str());
|
2008-11-05 06:39:18 +01:00
|
|
|
std::string err = ec.message();
|
2007-02-12 19:21:14 +01:00
|
|
|
#endif
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(false);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2009-03-31 09:57:57 +02:00
|
|
|
m_io_service.reset();
|
2010-06-24 23:43:00 +02:00
|
|
|
|
|
|
|
stop_loop = m_abort;
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2007-05-23 03:02:46 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" locking mutex");
|
2007-05-23 03:02:46 +02:00
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2008-01-27 23:39:50 +01:00
|
|
|
/*
|
2008-11-29 22:33:21 +01:00
|
|
|
#ifdef TORRENT_DEBUG
|
2006-10-11 22:57:54 +02:00
|
|
|
for (torrent_map::iterator i = m_torrents.begin();
|
|
|
|
i != m_torrents.end(); ++i)
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(i->second->num_peers() == 0);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
#endif
|
2008-01-27 23:39:50 +01:00
|
|
|
*/
|
2007-05-23 03:02:46 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2012-10-18 09:32:16 +02:00
|
|
|
session_log(" cleaning up torrents");
|
2007-05-23 03:02:46 +02:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// clear the torrent LRU (probably not strictly necessary)
|
|
|
|
list_node* i = m_torrent_lru.get_all();
|
|
|
|
#if TORRENT_USE_ASSERTS
|
|
|
|
// clear the prev and next pointers in all torrents
|
|
|
|
// to avoid the assert when destructing them
|
|
|
|
while (i)
|
|
|
|
{
|
|
|
|
list_node* tmp = i;
|
|
|
|
i = i->next;
|
|
|
|
tmp->next = NULL;
|
|
|
|
tmp->prev= NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
m_torrents.clear();
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_torrents.empty());
|
|
|
|
TORRENT_ASSERT(m_connections.empty());
|
2010-12-04 23:20:31 +01:00
|
|
|
|
2014-01-19 20:45:50 +01:00
|
|
|
#if TORRENT_USE_ASSERTS && defined BOOST_HAS_PTHREADS
|
2010-12-04 23:20:31 +01:00
|
|
|
m_network_thread = 0;
|
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
boost::shared_ptr<torrent> session_impl::delay_load_torrent(sha1_hash const& info_hash
|
|
|
|
, peer_connection* pc)
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
for (ses_extension_list_t::iterator i = m_ses_extensions.begin()
|
|
|
|
, end(m_ses_extensions.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
add_torrent_params p;
|
|
|
|
if ((*i)->on_unknown_torrent(info_hash, pc, p))
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
torrent_handle handle = add_torrent(p, ec);
|
|
|
|
|
|
|
|
return handle.native_handle();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return boost::shared_ptr<torrent>();
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
|
|
|
// the return value from this function is valid only as long as the
|
|
|
|
// session is locked!
|
2013-01-02 09:09:21 +01:00
|
|
|
boost::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);
|
2014-07-06 21:18:00 +02:00
|
|
|
#if defined TORRENT_DEBUG && defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2013-01-02 09:09:21 +01:00
|
|
|
for (torrent_map::const_iterator j
|
2006-10-11 22:57:54 +02:00
|
|
|
= m_torrents.begin(); j != m_torrents.end(); ++j)
|
|
|
|
{
|
|
|
|
torrent* p = boost::get_pointer(j->second);
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(p);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (i != m_torrents.end()) return i->second;
|
|
|
|
return boost::weak_ptr<torrent>();
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::insert_torrent(sha1_hash const& ih, boost::shared_ptr<torrent> const& t
|
|
|
|
, std::string uuid)
|
|
|
|
{
|
|
|
|
m_torrents.insert(std::make_pair(ih, t));
|
|
|
|
if (!uuid.empty()) m_uuids.insert(std::make_pair(uuid, t));
|
|
|
|
|
|
|
|
TORRENT_ASSERT(m_torrents.size() >= m_torrent_lru.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_queue_position(torrent* me, int p)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
if (t->queue_position() >= p
|
|
|
|
&& 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();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
|
|
|
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);
|
|
|
|
if (i == m_obfuscated_torrents.end()) return NULL;
|
|
|
|
return i->second.get();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-02 09:09:21 +01:00
|
|
|
boost::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
|
|
|
|
2013-01-02 09:09:21 +01:00
|
|
|
std::map<std::string, boost::shared_ptr<torrent> >::const_iterator i
|
2011-01-18 04:41:54 +01:00
|
|
|
= m_uuids.find(uuid);
|
|
|
|
if (i != m_uuids.end()) return i->second;
|
|
|
|
return boost::weak_ptr<torrent>();
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2013-01-02 09:09:21 +01:00
|
|
|
boost::weak_ptr<torrent> session_impl::find_disconnect_candidate_torrent() const
|
2013-01-02 08:39:02 +01:00
|
|
|
{
|
2013-01-02 09:09:21 +01:00
|
|
|
aux::session_impl::torrent_map::const_iterator i = std::min_element(m_torrents.begin(), m_torrents.end()
|
2013-01-02 08:48:09 +01:00
|
|
|
, boost::bind(&compare_disconnect_torrent, _1, _2));
|
2013-01-02 08:39:02 +01:00
|
|
|
|
|
|
|
TORRENT_ASSERT(i != m_torrents.end());
|
|
|
|
if (i == m_torrents.end()) return boost::shared_ptr<torrent>();
|
|
|
|
|
|
|
|
return i->second;
|
|
|
|
}
|
|
|
|
|
2008-02-17 23:51:03 +01:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2006-11-15 22:39:58 +01:00
|
|
|
boost::shared_ptr<logger> session_impl::create_log(std::string const& name
|
|
|
|
, int instance, bool append)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2012-10-07 01:45:36 +02:00
|
|
|
error_code ec;
|
2006-10-11 22:57:54 +02:00
|
|
|
// current options are file_logger, cout_logger and null_logger
|
2012-10-07 01:45:36 +02:00
|
|
|
return boost::shared_ptr<logger>(new logger(m_logpath, name, instance, append));
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2012-10-18 17:14:18 +02:00
|
|
|
|
|
|
|
void session_impl::session_log(char const* fmt, ...) const
|
|
|
|
{
|
|
|
|
if (!m_logger) return;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
va_list v;
|
2012-10-18 17:14:18 +02:00
|
|
|
va_start(v, fmt);
|
2014-07-06 21:18:00 +02:00
|
|
|
session_vlog(fmt, v);
|
|
|
|
va_end(v);
|
|
|
|
}
|
2012-10-18 17:14:18 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::session_vlog(char const* fmt, va_list& v) const
|
|
|
|
{
|
2012-10-18 17:14:18 +02:00
|
|
|
char usr[400];
|
|
|
|
vsnprintf(usr, sizeof(usr), fmt, v);
|
|
|
|
va_end(v);
|
|
|
|
char buf[450];
|
|
|
|
snprintf(buf, sizeof(buf), "%s: %s\n", time_now_string(), usr);
|
|
|
|
(*m_logger) << buf;
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING
|
|
|
|
void session_impl::log_all_torrents(peer_connection* p)
|
|
|
|
{
|
|
|
|
for (session_impl::torrent_map::const_iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
p->peer_log(" %s", to_hex(i->second->torrent_file().info_hash().to_string()).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
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
|
|
|
|
, boost::function<bool(torrent_status const&)> const& pred
|
|
|
|
, boost::uint32_t flags) const
|
|
|
|
{
|
2011-12-21 22:21:19 +01:00
|
|
|
for (torrent_map::const_iterator i
|
2011-02-01 10:48:28 +01:00
|
|
|
= m_torrents.begin(), end(m_torrents.end());
|
|
|
|
i != end; ++i)
|
|
|
|
{
|
|
|
|
if (i->second->is_aborted()) continue;
|
|
|
|
torrent_status st;
|
|
|
|
i->second->status(&st, flags);
|
|
|
|
if (!pred(st)) continue;
|
|
|
|
ret->push_back(st);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::refresh_torrent_status(std::vector<torrent_status>* ret
|
|
|
|
, boost::uint32_t flags) const
|
|
|
|
{
|
|
|
|
for (std::vector<torrent_status>::iterator i
|
|
|
|
= ret->begin(), end(ret->end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
boost::shared_ptr<torrent> t = i->handle.m_torrent.lock();
|
|
|
|
if (!t) continue;
|
|
|
|
t->status(&*i, flags);
|
|
|
|
}
|
|
|
|
}
|
2011-11-15 03:34:00 +01:00
|
|
|
|
|
|
|
void session_impl::post_torrent_updates()
|
|
|
|
{
|
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
|
|
|
|
2011-11-15 03:34:00 +01:00
|
|
|
std::auto_ptr<state_update_alert> alert(new state_update_alert());
|
2014-07-06 21:18:00 +02:00
|
|
|
std::vector<torrent*>& state_updates
|
|
|
|
= m_torrent_lists[aux::session_impl::torrent_state_updates];
|
|
|
|
|
|
|
|
alert->status.reserve(state_updates.size());
|
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 = true;
|
|
|
|
#endif
|
|
|
|
|
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
|
|
|
|
// pushed back
|
|
|
|
for (std::vector<torrent*>::iterator i = state_updates.begin()
|
|
|
|
, end(state_updates.end()); i != end; ++i)
|
2011-11-15 03:34:00 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent* t = *i;
|
|
|
|
TORRENT_ASSERT(t->m_links[aux::session_impl::torrent_state_updates].in_list());
|
2011-11-15 03:34:00 +01:00
|
|
|
alert->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
|
|
|
|
t->status(&alert->status.back(), ~torrent_handle::query_accurate_download_counters);
|
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
|
|
|
|
|
2011-11-15 03:34:00 +01:00
|
|
|
m_alerts.post_alert_ptr(alert.release());
|
|
|
|
}
|
2011-02-01 10:48:28 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::post_session_stats()
|
|
|
|
{
|
|
|
|
std::auto_ptr<session_stats_alert> alert(new session_stats_alert());
|
|
|
|
std::vector<boost::uint64_t>& values = alert->values;
|
|
|
|
values.resize(counters::num_counters, 0);
|
|
|
|
|
|
|
|
m_disk_thread.update_stats_counters(m_stats_counters);
|
|
|
|
|
|
|
|
// TODO: 3 it would be really nice to update these counters
|
|
|
|
// as they are incremented. This depends on the session
|
|
|
|
// being ticked, which has a fairly coarse grained resolution
|
|
|
|
m_stats_counters.set_value(counters::sent_bytes
|
|
|
|
, m_stat.total_upload());
|
|
|
|
m_stats_counters.set_value(counters::sent_payload_bytes
|
|
|
|
, m_stat.total_transfer(stat::upload_payload));
|
|
|
|
m_stats_counters.set_value(counters::sent_ip_overhead_bytes
|
|
|
|
, m_stat.total_transfer(stat::upload_ip_protocol));
|
|
|
|
m_stats_counters.set_value(counters::sent_tracker_bytes
|
|
|
|
, m_stat.total_transfer(stat::upload_tracker_protocol));
|
|
|
|
|
|
|
|
m_stats_counters.set_value(counters::recv_bytes
|
|
|
|
, m_stat.total_download());
|
|
|
|
m_stats_counters.set_value(counters::recv_payload_bytes
|
|
|
|
, m_stat.total_transfer(stat::download_payload));
|
|
|
|
m_stats_counters.set_value(counters::recv_ip_overhead_bytes
|
|
|
|
, m_stat.total_transfer(stat::download_ip_protocol));
|
|
|
|
m_stats_counters.set_value(counters::recv_tracker_bytes
|
|
|
|
, m_stat.total_transfer(stat::download_tracker_protocol));
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
for (int i = 0; i < counters::num_counters; ++i)
|
|
|
|
values[i] = m_stats_counters[i];
|
|
|
|
|
|
|
|
alert->timestamp = total_microseconds(time_now_hires() - m_created);
|
|
|
|
|
|
|
|
m_alerts.post_alert_ptr(alert.release());
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if (string_begins_no_case("file://", params->url.c_str()) && !params->ti)
|
|
|
|
{
|
|
|
|
m_disk_thread.async_load_torrent(params
|
|
|
|
, boost::bind(&session_impl::on_async_load_torrent, this, _1));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-10-12 12:27:17 +02:00
|
|
|
error_code ec;
|
|
|
|
torrent_handle handle = add_torrent(*params, ec);
|
|
|
|
delete params;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::on_async_load_torrent(disk_io_job const* j)
|
|
|
|
{
|
|
|
|
add_torrent_params* params = (add_torrent_params*)j->requester;
|
|
|
|
error_code ec;
|
|
|
|
torrent_handle handle;
|
|
|
|
if (j->error.ec)
|
|
|
|
{
|
|
|
|
ec = j->error.ec;
|
|
|
|
m_alerts.post_alert(add_torrent_alert(handle, *params, ec));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
params->url.clear();
|
|
|
|
params->ti = boost::shared_ptr<torrent_info>((torrent_info*)j->buffer);
|
|
|
|
handle = add_torrent(*params, ec);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete params;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
void session_impl::add_extensions_to_torrent(
|
|
|
|
boost::shared_ptr<torrent> const& torrent_ptr, void* userdata)
|
|
|
|
{
|
|
|
|
for (ses_extension_list_t::iterator i = m_ses_extensions.begin()
|
|
|
|
, end(m_ses_extensions.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
boost::shared_ptr<torrent_plugin> tp((*i)->new_torrent(torrent_ptr.get(), userdata));
|
|
|
|
if (tp) torrent_ptr->add_extension(tp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#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
|
|
|
{
|
|
|
|
torrent_handle h = add_torrent_impl(p, ec);
|
|
|
|
m_alerts.post_alert(add_torrent_alert(h, p, ec));
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
torrent_handle session_impl::add_torrent_impl(add_torrent_params const& p
|
|
|
|
, error_code& ec)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2012-03-08 10:54:44 +01:00
|
|
|
TORRENT_ASSERT(!p.save_path.empty());
|
2007-09-22 18:27:29 +02:00
|
|
|
|
2011-11-15 03:34:00 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2012-03-08 10:54:44 +01:00
|
|
|
p.update_flags();
|
2011-11-15 03:34:00 +01:00
|
|
|
#endif
|
|
|
|
|
2012-03-08 10:54:44 +01:00
|
|
|
add_torrent_params params = p;
|
|
|
|
if (string_begins_no_case("magnet:", params.url.c_str()))
|
|
|
|
{
|
|
|
|
parse_magnet_uri(params.url, params, ec);
|
|
|
|
if (ec) return torrent_handle();
|
|
|
|
params.url.clear();
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (string_begins_no_case("file://", params.url.c_str()) && !params.ti)
|
|
|
|
{
|
|
|
|
std::string filename = resolve_file_url(params.url);
|
|
|
|
boost::shared_ptr<torrent_info> t = boost::make_shared<torrent_info>(filename, boost::ref(ec), 0);
|
|
|
|
if (ec) return torrent_handle();
|
|
|
|
params.url.clear();
|
|
|
|
params.ti = t;
|
|
|
|
}
|
|
|
|
|
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;
|
2008-04-07 03:22:26 +02:00
|
|
|
return torrent_handle();
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2012-03-08 10:54:44 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
// add p.dht_nodes to the DHT, if enabled
|
|
|
|
if (m_dht && !p.dht_nodes.empty())
|
|
|
|
{
|
|
|
|
for (std::vector<std::pair<std::string, int> >::const_iterator i = p.dht_nodes.begin()
|
|
|
|
, end(p.dht_nodes.end()); i != end; ++i)
|
|
|
|
m_dht->add_node(*i);
|
|
|
|
}
|
|
|
|
#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;
|
2008-04-07 03:22:26 +02:00
|
|
|
return torrent_handle();
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
// figure out the info hash of the torrent
|
|
|
|
sha1_hash const* ih = 0;
|
2010-12-30 02:47:30 +01:00
|
|
|
sha1_hash tmp;
|
2008-04-24 05:28:48 +02:00
|
|
|
if (params.ti) ih = ¶ms.ti->info_hash();
|
2010-12-30 02:47:30 +01:00
|
|
|
else if (!params.url.empty())
|
|
|
|
{
|
|
|
|
// 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
|
|
|
|
tmp = hasher(¶ms.url[0], params.url.size()).final();
|
|
|
|
ih = &tmp;
|
|
|
|
}
|
2008-04-24 05:28:48 +02:00
|
|
|
else ih = ¶ms.info_hash;
|
|
|
|
|
2012-11-08 03:07:10 +01:00
|
|
|
// we don't have a torrent file. If the user provided
|
|
|
|
// resume data, there may be some metadata in there
|
|
|
|
if ((!params.ti || !params.ti->is_valid())
|
2013-07-17 22:21:48 +02:00
|
|
|
&& !params.resume_data.empty())
|
2012-11-08 03:07:10 +01:00
|
|
|
{
|
|
|
|
int pos;
|
|
|
|
error_code ec;
|
|
|
|
lazy_entry tmp;
|
|
|
|
lazy_entry const* info = 0;
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
2012-11-09 18:11:42 +01:00
|
|
|
session_log("adding magnet link with resume data");
|
2012-11-08 03:07:10 +01:00
|
|
|
#endif
|
2013-07-17 22:21:48 +02:00
|
|
|
if (lazy_bdecode(¶ms.resume_data[0], ¶ms.resume_data[0]
|
|
|
|
+ params.resume_data.size(), tmp, ec, &pos) == 0
|
2012-11-08 03:07:10 +01:00
|
|
|
&& tmp.type() == lazy_entry::dict_t
|
|
|
|
&& (info = tmp.dict_find_dict("info")))
|
|
|
|
{
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
2012-11-09 18:11:42 +01:00
|
|
|
session_log("found metadata in resume data");
|
2012-11-08 03:07:10 +01:00
|
|
|
#endif
|
|
|
|
// verify the info-hash of the metadata stored in the resume file matches
|
|
|
|
// the torrent we're loading
|
|
|
|
|
|
|
|
std::pair<char const*, int> buf = info->data_section();
|
|
|
|
sha1_hash resume_ih = hasher(buf.first, buf.second).final();
|
|
|
|
|
|
|
|
// if url is set, the info_hash is not actually the info-hash of the
|
|
|
|
// torrent, but the hash of the URL, until we have the full torrent
|
|
|
|
// only require the info-hash to match if we actually passed in one
|
|
|
|
if (resume_ih == params.info_hash
|
|
|
|
|| !params.url.empty()
|
|
|
|
|| params.info_hash.is_all_zeros())
|
|
|
|
{
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
2012-11-09 18:11:42 +01:00
|
|
|
session_log("info-hash matched");
|
2012-11-08 03:07:10 +01:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
params.ti = boost::make_shared<torrent_info>(resume_ih);
|
2012-11-08 03:07:10 +01:00
|
|
|
|
|
|
|
if (params.ti->parse_info_section(*info, ec, 0))
|
|
|
|
{
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
2012-11-09 18:11:42 +01:00
|
|
|
session_log("successfully loaded metadata from resume file");
|
2012-11-08 03:07:10 +01:00
|
|
|
#endif
|
|
|
|
// make the info-hash be the one in the resume file
|
|
|
|
params.info_hash = resume_ih;
|
|
|
|
ih = ¶ms.info_hash;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2012-11-09 18:11:42 +01:00
|
|
|
session_log("failed to load metadata from resume file: %s"
|
2012-11-08 03:07:10 +01:00
|
|
|
, ec.message().c_str());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
else
|
|
|
|
{
|
2012-11-09 18:11:42 +01:00
|
|
|
session_log("metadata info-hash failed");
|
2012-11-08 03:07:10 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
else
|
|
|
|
{
|
2012-11-09 18:11:42 +01:00
|
|
|
session_log("no metadata found");
|
2012-11-08 03:07:10 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
// is the torrent already active?
|
2008-04-24 05:28:48 +02:00
|
|
|
boost::shared_ptr<torrent> torrent_ptr = find_torrent(*ih).lock();
|
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())
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent_map::iterator i = std::find_if(m_torrents.begin()
|
2013-09-15 14:29:09 +02:00
|
|
|
, m_torrents.end(), boost::bind(&torrent::url, boost::bind(&std::pair<const sha1_hash
|
|
|
|
, boost::shared_ptr<torrent> >::second, _1)) == params.url);
|
|
|
|
if (i != m_torrents.end())
|
|
|
|
torrent_ptr = i->second;
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
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);
|
|
|
|
if (!params.source_feed_url.empty() && torrent_ptr->source_feed_url().empty())
|
|
|
|
torrent_ptr->set_source_feed_url(params.source_feed_url);
|
2008-04-24 05:28:48 +02:00
|
|
|
return torrent_handle(torrent_ptr);
|
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;
|
2008-04-07 03:22:26 +02:00
|
|
|
return torrent_handle();
|
|
|
|
}
|
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
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent_ptr.reset(new torrent(*this
|
2010-12-30 02:47:30 +01:00
|
|
|
, 16 * 1024, queue_pos, params, *ih));
|
2009-01-02 09:58:51 +01:00
|
|
|
torrent_ptr->start();
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2013-08-02 11:42:51 +02:00
|
|
|
typedef std::vector<boost::function<
|
|
|
|
boost::shared_ptr<torrent_plugin>(torrent*, void*)> >
|
|
|
|
torrent_plugins_t;
|
|
|
|
|
|
|
|
for (torrent_plugins_t::const_iterator i = params.extensions.begin()
|
|
|
|
, end(params.extensions.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
torrent_ptr->add_extension((*i)(torrent_ptr.get(),
|
|
|
|
params.userdata));
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2008-04-24 05:28:48 +02:00
|
|
|
if (m_dht && params.ti)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2008-04-24 05:28:48 +02:00
|
|
|
torrent_info::nodes_t const& nodes = params.ti->nodes();
|
2009-11-23 00:55:54 +01:00
|
|
|
std::for_each(nodes.begin(), nodes.end(), boost::bind(
|
2006-10-11 22:57:54 +02:00
|
|
|
(void(dht::dht_tracker::*)(std::pair<std::string, int> const&))
|
|
|
|
&dht::dht_tracker::add_node
|
|
|
|
, boost::ref(m_dht), _1));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_HAS_BOOST_UNORDERED
|
|
|
|
sha1_hash next_lsd(0);
|
|
|
|
sha1_hash next_dht(0);
|
|
|
|
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
|
|
|
|
float load_factor = m_torrents.load_factor();
|
|
|
|
#endif // TORRENT_HAS_BOOST_UNORDERED
|
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
m_torrents.insert(std::make_pair(*ih, torrent_ptr));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
TORRENT_ASSERT(m_torrents.size() >= m_torrent_lru.size());
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
|
|
|
hasher h;
|
|
|
|
h.update("req2", 4);
|
|
|
|
h.update((char*)&(*ih)[0], 20);
|
|
|
|
// this is SHA1("req2" + info-hash), used for
|
|
|
|
// encrypted hand shakes
|
|
|
|
m_obfuscated_torrents.insert(std::make_pair(h.final(), torrent_ptr));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (torrent_ptr->is_pinned() == false)
|
|
|
|
{
|
|
|
|
evict_torrents_except(torrent_ptr.get());
|
|
|
|
bump_torrent(torrent_ptr.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
#if TORRENT_HAS_BOOST_UNORDERED
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
#endif // TORRENT_HAS_BOOST_UNORDERED
|
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));
|
2008-03-08 07:06:31 +01:00
|
|
|
|
2011-02-01 04:25:40 +01:00
|
|
|
if (m_alerts.should_post<torrent_added_alert>())
|
|
|
|
m_alerts.post_alert(torrent_added_alert(torrent_ptr->get_handle()));
|
|
|
|
|
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)
|
2012-11-03 04:50:12 +01:00
|
|
|
trigger_auto_manage();
|
2011-03-04 07:03:45 +01:00
|
|
|
|
2008-04-09 22:09:36 +02:00
|
|
|
return torrent_handle(torrent_ptr);
|
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
|
|
|
INVARIANT_CHECK;
|
|
|
|
std::string net_interfaces = m_settings.get_str(settings_pack::outgoing_interfaces);
|
|
|
|
|
|
|
|
// declared in string_util.hpp
|
|
|
|
parse_comma_separated_string(net_interfaces, m_net_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)
|
|
|
|
{
|
|
|
|
s.set_option(socket_acceptor::reuse_address(true), ec);
|
|
|
|
// 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();
|
|
|
|
bind_ep.port(next_port());
|
|
|
|
}
|
2008-11-19 01:46:48 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!m_net_interfaces.empty())
|
|
|
|
{
|
|
|
|
if (m_interface_index >= m_net_interfaces.size()) m_interface_index = 0;
|
|
|
|
std::string const& ifname = m_net_interfaces[m_interface_index++];
|
|
|
|
|
|
|
|
if (ec) return bind_ep;
|
|
|
|
|
|
|
|
bind_ep.address(bind_to_device(m_io_service, s, remote_address.is_v4()
|
|
|
|
, 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)
|
|
|
|
{
|
|
|
|
// 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
|
|
|
|
// addresses. first look for the address
|
|
|
|
for (int i = 0; i < int(m_net_interfaces.size()); ++i)
|
2011-04-28 09:54:57 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
error_code err;
|
|
|
|
address ip = address::from_string(m_net_interfaces[i].c_str(), err);
|
|
|
|
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;
|
|
|
|
|
|
|
|
for (int i = 0; i < int(m_net_interfaces.size()); ++i)
|
|
|
|
{
|
|
|
|
if (m_net_interfaces[i] == device) return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2008-04-09 22:09:36 +02:00
|
|
|
boost::shared_ptr<torrent> tptr = h.m_torrent.lock();
|
2011-06-21 04:02:58 +02:00
|
|
|
if (!tptr) return;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_alerts.post_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
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::remove_torrent_impl(boost::shared_ptr<torrent> tptr, int options)
|
|
|
|
{
|
2011-01-18 04:41:54 +01:00
|
|
|
// remove from uuid list
|
|
|
|
if (!tptr->uuid().empty())
|
|
|
|
{
|
|
|
|
std::map<std::string, boost::shared_ptr<torrent> >::iterator j
|
|
|
|
= m_uuids.find(tptr->uuid());
|
|
|
|
if (j != m_uuids.end()) m_uuids.erase(j);
|
|
|
|
}
|
|
|
|
|
2011-12-21 22:21:19 +01:00
|
|
|
torrent_map::iterator i =
|
2008-04-09 22:09:36 +02:00
|
|
|
m_torrents.find(tptr->torrent_file().info_hash());
|
|
|
|
|
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();
|
|
|
|
sha1_hash urlhash = hasher(&url[0], url.size()).final();
|
|
|
|
i = m_torrents.find(urlhash);
|
|
|
|
}
|
|
|
|
|
2011-02-01 04:25:40 +01:00
|
|
|
if (i == m_torrents.end()) return;
|
|
|
|
|
|
|
|
torrent& t = *i->second;
|
|
|
|
if (options & session::delete_files)
|
2013-03-17 01:50:33 +01:00
|
|
|
{
|
|
|
|
if (!t.delete_files())
|
|
|
|
{
|
2013-03-17 23:16:57 +01:00
|
|
|
if (m_alerts.should_post<torrent_delete_failed_alert>())
|
2013-10-28 00:39:24 +01:00
|
|
|
m_alerts.post_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
|
|
|
if (m_torrent_lru.size() > 0
|
|
|
|
&& (t.prev != NULL || t.next != NULL || m_torrent_lru.front() == &t))
|
|
|
|
m_torrent_lru.erase(&t);
|
|
|
|
|
|
|
|
TORRENT_ASSERT(t.prev == NULL && t.next == NULL);
|
|
|
|
|
|
|
|
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);
|
2010-02-05 09:23:17 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(m_torrents.size() >= m_torrent_lru.size());
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
|
|
|
hasher h;
|
|
|
|
h.update("req2", 4);
|
|
|
|
h.update((char*)&tptr->info_hash()[0], 20);
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
std::string net_interfaces = m_settings.get_str(settings_pack::listen_interfaces);
|
|
|
|
std::vector<std::pair<std::string, int> > new_listen_interfaces;
|
|
|
|
|
|
|
|
// declared in string_util.hpp
|
|
|
|
parse_comma_separated_string_port(net_interfaces, new_listen_interfaces);
|
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log("update listen interfaces: %s", net_interfaces.c_str());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// if the interface is the same and the socket is open
|
|
|
|
// don't do anything
|
|
|
|
if (new_listen_interfaces == m_listen_interfaces
|
|
|
|
&& !m_listen_sockets.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_listen_interfaces = new_listen_interfaces;
|
|
|
|
|
|
|
|
// for backwards compatibility. Some components still only supports
|
|
|
|
// a single listen interface
|
|
|
|
m_listen_interface.address(address_v4::any());
|
|
|
|
m_listen_interface.port(0);
|
|
|
|
if (m_listen_interfaces.size() > 0)
|
2008-11-05 06:39:18 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
error_code ec;
|
|
|
|
m_listen_interface.port(m_listen_interfaces[0].second);
|
|
|
|
char const* device_name = m_listen_interfaces[0].first.c_str();
|
|
|
|
|
|
|
|
// if the first character is [, skip it since it may be an
|
|
|
|
// IPv6 address
|
|
|
|
m_listen_interface.address(address::from_string(
|
|
|
|
device_name[0] == '[' ? device_name + 1 : device_name, ec));
|
2008-11-05 06:39:18 +01:00
|
|
|
if (ec)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log("failed to treat %s as an IP address [ %s ]"
|
|
|
|
, device_name, ec.message().c_str());
|
|
|
|
#endif
|
|
|
|
// it may have been a device name.
|
|
|
|
std::vector<ip_interface> ifs = enum_net_interfaces(m_io_service, ec);
|
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
if (ec)
|
|
|
|
session_log("failed to enumerate interfaces [ %s ]"
|
|
|
|
, ec.message().c_str());
|
|
|
|
#endif
|
2013-06-04 02:35:42 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
bool found = false;
|
|
|
|
for (int i = 0; i < int(ifs.size()); ++i)
|
|
|
|
{
|
|
|
|
// we're looking for a specific interface, and its address
|
|
|
|
// (which must be of the same family as the address we're
|
|
|
|
// connecting to)
|
|
|
|
if (strcmp(ifs[i].name, device_name) != 0) continue;
|
|
|
|
m_listen_interface.address(ifs[i].interface_address);
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log("binding to %s"
|
|
|
|
, m_listen_interface.address().to_string(ec).c_str());
|
2008-11-05 06:39:18 +01:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log("failed to find device %s", device_name);
|
|
|
|
#endif
|
|
|
|
// effectively disable whatever socket decides to bind to this
|
|
|
|
m_listen_interface.address(address_v4::loopback());
|
|
|
|
}
|
2008-11-05 06:39:18 +01:00
|
|
|
}
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
i->second->ip_filter_updated();
|
|
|
|
}
|
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();
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
m_udp_socket.set_proxy_settings(proxy());
|
|
|
|
}
|
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()
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2010-12-05 21:40:28 +01:00
|
|
|
address session_impl::listen_address() const
|
|
|
|
{
|
|
|
|
for (std::list<listen_socket_t>::const_iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if (i->external_address != address()) return i->external_address;
|
|
|
|
}
|
|
|
|
return address();
|
|
|
|
}
|
|
|
|
|
2012-01-14 17:04:25 +01:00
|
|
|
boost::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())
|
2010-04-13 06:30:34 +02: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
|
2010-04-13 06:30:34 +02:00
|
|
|
// mode. We don't want to leak our listen port since it can
|
|
|
|
// potentially identify us if it is leaked elsewere
|
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;
|
2009-01-19 09:31:31 +01:00
|
|
|
return m_listen_sockets.front().external_port;
|
2007-03-15 23:03:56 +01:00
|
|
|
}
|
|
|
|
|
2012-01-14 17:04:25 +01:00
|
|
|
boost::uint16_t session_impl::ssl_listen_port() const
|
|
|
|
{
|
|
|
|
#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
|
|
|
|
// potentially identify us if it is leaked elsewere
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::force_proxy)) return 0;
|
2012-01-14 17:04:25 +01:00
|
|
|
if (m_listen_sockets.empty()) return 0;
|
|
|
|
for (std::list<listen_socket_t>::const_iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if (i->ssl) return i->external_port;
|
|
|
|
}
|
|
|
|
#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
|
2007-05-31 02:21:54 +02:00
|
|
|
if (m_lsd.get())
|
2011-09-12 05:51:49 +02:00
|
|
|
m_lsd->announce(ih, port, broadcast);
|
2007-04-04 04:06:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih)
|
|
|
|
{
|
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;
|
|
|
|
|
2007-04-04 04:06:07 +02:00
|
|
|
boost::shared_ptr<torrent> t = find_torrent(ih).lock();
|
|
|
|
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
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2012-10-18 09:32:16 +02:00
|
|
|
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>())
|
|
|
|
m_alerts.post_alert(lsd_peer_alert(t->get_handle(), peer));
|
2007-04-04 04:06:07 +02:00
|
|
|
}
|
|
|
|
|
2009-06-12 18:40:38 +02:00
|
|
|
void session_impl::on_port_map_log(
|
|
|
|
char const* msg, int map_transport)
|
2007-03-15 23:03:56 +01:00
|
|
|
{
|
2008-10-22 03:12:14 +02:00
|
|
|
TORRENT_ASSERT(map_transport >= 0 && map_transport <= 1);
|
|
|
|
// log message
|
|
|
|
#ifdef TORRENT_UPNP_LOGGING
|
2009-06-12 18:40:38 +02:00
|
|
|
char const* transport_names[] = {"NAT-PMP", "UPnP"};
|
|
|
|
m_upnp_log << time_now_string() << " "
|
|
|
|
<< transport_names[map_transport] << ": " << msg;
|
2008-10-22 03:12:14 +02:00
|
|
|
#endif
|
2009-06-12 18:40:38 +02:00
|
|
|
if (m_alerts.should_post<portmap_log_alert>())
|
|
|
|
m_alerts.post_alert(portmap_log_alert(map_transport, msg));
|
|
|
|
}
|
|
|
|
|
2010-12-05 21:40:28 +01:00
|
|
|
void session_impl::on_port_mapping(int mapping, address const& ip, int port
|
2009-06-12 18:40:38 +02:00
|
|
|
, error_code const& ec, int map_transport)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(is_single_thread());
|
2010-07-14 06:16:38 +02:00
|
|
|
|
2009-06-12 18:40:38 +02:00
|
|
|
TORRENT_ASSERT(map_transport >= 0 && map_transport <= 1);
|
2008-10-22 03:12:14 +02:00
|
|
|
|
2008-04-06 21:17:58 +02:00
|
|
|
if (mapping == m_udp_mapping[map_transport] && port != 0)
|
2007-03-15 23:03:56 +01:00
|
|
|
{
|
2008-04-06 21:17:58 +02:00
|
|
|
m_external_udp_port = port;
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<portmap_alert>())
|
2008-04-06 21:17:58 +02:00
|
|
|
m_alerts.post_alert(portmap_alert(mapping, port
|
2008-07-06 14:22:56 +02:00
|
|
|
, map_transport));
|
2008-04-06 21:17:58 +02:00
|
|
|
return;
|
2007-03-15 23:03:56 +01:00
|
|
|
}
|
|
|
|
|
2008-04-06 21:17:58 +02:00
|
|
|
if (mapping == m_tcp_mapping[map_transport] && port != 0)
|
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
|
|
|
|
// this understanding of our external address, instead of the empty address
|
|
|
|
set_external_address(ip, source_router, address());
|
|
|
|
}
|
2010-12-05 21:40:28 +01:00
|
|
|
|
|
|
|
if (!m_listen_sockets.empty()) {
|
|
|
|
m_listen_sockets.front().external_address = ip;
|
2008-04-06 21:17:58 +02:00
|
|
|
m_listen_sockets.front().external_port = port;
|
2010-12-05 21:40:28 +01:00
|
|
|
}
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<portmap_alert>())
|
2008-04-06 21:17:58 +02:00
|
|
|
m_alerts.post_alert(portmap_alert(mapping, port
|
2008-07-06 14:22:56 +02:00
|
|
|
, map_transport));
|
2008-04-06 21:17:58 +02:00
|
|
|
return;
|
2007-03-15 23:03:56 +01:00
|
|
|
}
|
|
|
|
|
2009-06-12 18:40:38 +02:00
|
|
|
if (ec)
|
2007-03-15 23:03:56 +01:00
|
|
|
{
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<portmap_error_alert>())
|
2008-04-07 01:18:35 +02:00
|
|
|
m_alerts.post_alert(portmap_error_alert(mapping
|
2009-06-12 18:40:38 +02:00
|
|
|
, map_transport, ec));
|
2008-04-06 21:17:58 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<portmap_alert>())
|
2008-04-07 01:18:35 +02:00
|
|
|
m_alerts.post_alert(portmap_alert(mapping, port
|
2008-07-06 14:22:56 +02:00
|
|
|
, map_transport));
|
2007-03-15 23:03:56 +01:00
|
|
|
}
|
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_peers = int(m_connections.size());
|
|
|
|
s.num_dead_peers = int(m_undead_peers.size());
|
2014-09-22 05:47:43 +02:00
|
|
|
s.num_unchoked = m_stats_counters[counters::num_peers_up_unchoked_all];
|
2008-01-13 12:18:18 +01:00
|
|
|
s.allowed_upload_slots = m_allowed_upload_slots;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
s.num_torrents = m_torrents.size();
|
|
|
|
// only non-paused torrents want tick
|
|
|
|
s.num_paused_torrents = m_torrents.size() - m_torrent_lists[torrent_want_tick].size();
|
|
|
|
|
|
|
|
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
|
|
|
|
2009-04-26 02:21:59 +02:00
|
|
|
s.up_bandwidth_queue = m_upload_rate.queue_size();
|
|
|
|
s.down_bandwidth_queue = m_download_rate.queue_size();
|
2008-01-17 18:40:46 +01:00
|
|
|
|
2014-05-10 05:23:05 +02:00
|
|
|
s.up_bandwidth_bytes_queue = int(m_upload_rate.queued_bytes());
|
|
|
|
s.down_bandwidth_bytes_queue = int(m_download_rate.queued_bytes());
|
2008-12-13 06:12:12 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
s.disk_write_queue = m_stats_counters[counters::num_peers_down_disk];
|
|
|
|
s.disk_read_queue = m_stats_counters[counters::num_peers_up_disk];
|
2011-01-30 11:04:15 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
s.has_incoming_connections = m_stats_counters[counters::has_incoming_connections];
|
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);
|
|
|
|
|
2010-02-08 06:43:54 +01:00
|
|
|
#ifndef TORRENT_DISABLE_FULL_STATS
|
2008-09-20 19:42:25 +02:00
|
|
|
// IP-overhead
|
|
|
|
s.ip_overhead_download_rate = m_stat.transfer_rate(stat::download_ip_protocol);
|
|
|
|
s.total_ip_overhead_download = m_stat.total_transfer(stat::download_ip_protocol);
|
|
|
|
s.ip_overhead_upload_rate = m_stat.transfer_rate(stat::upload_ip_protocol);
|
|
|
|
s.total_ip_overhead_upload = m_stat.total_transfer(stat::upload_ip_protocol);
|
|
|
|
|
2010-12-29 03:17:44 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2008-09-20 19:42:25 +02:00
|
|
|
// DHT protocol
|
|
|
|
s.dht_download_rate = m_stat.transfer_rate(stat::download_dht_protocol);
|
|
|
|
s.total_dht_download = m_stat.total_transfer(stat::download_dht_protocol);
|
|
|
|
s.dht_upload_rate = m_stat.transfer_rate(stat::upload_dht_protocol);
|
|
|
|
s.total_dht_upload = m_stat.total_transfer(stat::upload_dht_protocol);
|
2013-04-09 03:04:43 +02:00
|
|
|
#else
|
|
|
|
s.dht_download_rate = 0;
|
|
|
|
s.total_dht_download = 0;
|
|
|
|
s.dht_upload_rate = 0;
|
|
|
|
s.total_dht_upload = 0;
|
|
|
|
#endif // TORRENT_DISABLE_DHT
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2008-09-22 02:15:05 +02:00
|
|
|
// tracker
|
|
|
|
s.tracker_download_rate = m_stat.transfer_rate(stat::download_tracker_protocol);
|
|
|
|
s.total_tracker_download = m_stat.total_transfer(stat::download_tracker_protocol);
|
|
|
|
s.tracker_upload_rate = m_stat.transfer_rate(stat::upload_tracker_protocol);
|
|
|
|
s.total_tracker_upload = m_stat.total_transfer(stat::upload_tracker_protocol);
|
2010-02-08 06:43:54 +01:00
|
|
|
#else
|
|
|
|
// IP-overhead
|
|
|
|
s.ip_overhead_download_rate = 0;
|
|
|
|
s.total_ip_overhead_download = 0;
|
|
|
|
s.ip_overhead_upload_rate = 0;
|
|
|
|
s.total_ip_overhead_upload = 0;
|
|
|
|
|
|
|
|
// DHT protocol
|
|
|
|
s.dht_download_rate = 0;
|
|
|
|
s.total_dht_download = 0;
|
|
|
|
s.dht_upload_rate = 0;
|
|
|
|
s.total_dht_upload = 0;
|
|
|
|
|
|
|
|
// tracker
|
|
|
|
s.tracker_download_rate = 0;
|
|
|
|
s.total_tracker_download = 0;
|
|
|
|
s.tracker_upload_rate = 0;
|
|
|
|
s.total_tracker_upload = 0;
|
|
|
|
#endif
|
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
|
|
|
}
|
|
|
|
|
2010-11-29 02:33:05 +01:00
|
|
|
m_utp_socket_manager.get_status(s.utp_stats);
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
|
2010-03-04 17:42:39 +01:00
|
|
|
void session_impl::start_dht()
|
|
|
|
{ start_dht(m_dht_state); }
|
|
|
|
|
2014-02-28 05:02:48 +01:00
|
|
|
void on_bootstrap(alert_manager& alerts)
|
|
|
|
{
|
|
|
|
if (alerts.should_post<dht_bootstrap_alert>())
|
|
|
|
alerts.post_alert(dht_bootstrap_alert());
|
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
void session_impl::start_dht(entry const& startup_state)
|
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2012-06-25 05:31:11 +02:00
|
|
|
stop_dht();
|
2014-07-06 21:18:00 +02:00
|
|
|
m_dht = new dht::dht_tracker(*this, m_udp_socket, m_dht_settings, m_stats_counters, &startup_state);
|
2008-09-02 08:37:40 +02:00
|
|
|
|
2010-02-14 08:46:57 +01:00
|
|
|
for (std::list<udp::endpoint>::iterator i = m_dht_router_nodes.begin()
|
2008-09-02 08:37:40 +02:00
|
|
|
, end(m_dht_router_nodes.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
m_dht->add_router_node(*i);
|
|
|
|
}
|
|
|
|
|
2014-02-28 05:02:48 +01:00
|
|
|
m_dht->start(startup_state, boost::bind(&on_bootstrap, boost::ref(m_alerts)));
|
2009-10-25 03:37:45 +01:00
|
|
|
|
2012-06-22 06:21:20 +02:00
|
|
|
m_udp_socket.subscribe(m_dht.get());
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::stop_dht()
|
|
|
|
{
|
2007-03-02 06:02:12 +01:00
|
|
|
if (!m_dht) return;
|
2012-06-22 06:21:20 +02:00
|
|
|
m_udp_socket.unsubscribe(m_dht.get());
|
2007-02-25 10:42:43 +01:00
|
|
|
m_dht->stop();
|
2007-03-02 02:16:59 +01:00
|
|
|
m_dht = 0;
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_dht_settings(dht_settings const& settings)
|
|
|
|
{
|
|
|
|
m_dht_settings = settings;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2007-10-29 17:18:37 +01:00
|
|
|
if (!m_dht) return entry();
|
2010-07-14 06:16:38 +02:00
|
|
|
return m_dht->state();
|
2006-10-11 22:57:54 +02: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
|
|
|
{
|
2010-11-07 20:18:16 +01:00
|
|
|
if (m_dht) m_dht->add_node(node);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::add_dht_router(std::pair<std::string, int> const& node)
|
|
|
|
{
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::on_dht_router_name_lookup");
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
m_host_resolver.async_resolve(node.first, 0
|
|
|
|
, boost::bind(&session_impl::on_dht_router_name_lookup
|
|
|
|
, 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
|
|
|
{
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
complete_async("session_impl::on_dht_router_name_lookup");
|
|
|
|
#endif
|
2014-01-20 10:20:47 +01:00
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<dht_error_alert>())
|
|
|
|
m_alerts.post_alert(dht_error_alert(
|
|
|
|
dht_error_alert::hostname_lookup, e));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
for (std::vector<address>::const_iterator i = addresses.begin()
|
|
|
|
, end(addresses.end()); i != end; ++i)
|
2010-11-07 20:18:16 +01:00
|
|
|
{
|
|
|
|
// router nodes should be added before the DHT is started (and bootstrapped)
|
2014-07-06 21:18:00 +02:00
|
|
|
udp::endpoint ep(*i, 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);
|
|
|
|
}
|
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());
|
|
|
|
m_alerts.post_alert(dht_immutable_item_alert(target, i.value()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::dht_get_immutable_item(sha1_hash const& target)
|
|
|
|
{
|
|
|
|
if (!m_dht) return;
|
|
|
|
m_dht->get_item(target, boost::bind(&session_impl::get_immutable_callback
|
|
|
|
, this, target, _1));
|
|
|
|
}
|
|
|
|
|
|
|
|
// callback for dht_mutable_get
|
|
|
|
void session_impl::get_mutable_callback(dht::item const& i)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(i.is_mutable());
|
|
|
|
m_alerts.post_alert(dht_mutable_item_alert(i.pk(), i.sig(), i.seq()
|
|
|
|
, i.salt(), i.value()));
|
|
|
|
}
|
|
|
|
|
|
|
|
// key is a 32-byte binary string, the public key to look up.
|
|
|
|
// the salt is optional
|
|
|
|
void session_impl::dht_get_mutable_item(boost::array<char, 32> key
|
|
|
|
, std::string salt)
|
|
|
|
{
|
|
|
|
if (!m_dht) return;
|
|
|
|
m_dht->get_item(key.data(), boost::bind(&session_impl::get_mutable_callback
|
|
|
|
, this, _1), salt);
|
|
|
|
}
|
|
|
|
|
2014-02-28 05:02:48 +01:00
|
|
|
void on_dht_put(alert_manager& alerts, sha1_hash target)
|
|
|
|
{
|
|
|
|
if (alerts.should_post<dht_put_alert>())
|
|
|
|
alerts.post_alert(dht_put_alert(target));
|
|
|
|
}
|
2014-02-24 01:31:13 +01:00
|
|
|
|
2014-02-28 05:02:48 +01:00
|
|
|
void session_impl::dht_put_item(entry data, sha1_hash target)
|
2014-02-24 01:31:13 +01:00
|
|
|
{
|
|
|
|
if (!m_dht) return;
|
2014-02-28 05:02:48 +01:00
|
|
|
m_dht->put_item(data, boost::bind(&on_dht_put, boost::ref(m_alerts)
|
|
|
|
, target));
|
2014-02-24 01:31:13 +01:00
|
|
|
}
|
|
|
|
|
2014-02-28 05:02:48 +01:00
|
|
|
void put_mutable_callback(alert_manager& alerts, dht::item& i
|
2014-02-24 01:31:13 +01:00
|
|
|
, boost::function<void(entry&, boost::array<char,64>&
|
|
|
|
, boost::uint64_t&, std::string const&)> cb)
|
|
|
|
{
|
|
|
|
entry value = i.value();
|
|
|
|
boost::array<char, 64> sig = i.sig();
|
|
|
|
boost::array<char, 32> pk = i.pk();
|
|
|
|
boost::uint64_t seq = i.seq();
|
|
|
|
std::string salt = i.salt();
|
|
|
|
cb(value, sig, seq, salt);
|
|
|
|
i.assign(value, salt, seq, pk.data(), sig.data());
|
2014-02-28 05:02:48 +01:00
|
|
|
|
|
|
|
if (alerts.should_post<dht_put_alert>())
|
|
|
|
alerts.post_alert(dht_put_alert(pk, sig, salt, seq));
|
2014-02-24 01:31:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::dht_put_mutable_item(boost::array<char, 32> key
|
|
|
|
, boost::function<void(entry&, boost::array<char,64>&
|
|
|
|
, boost::uint64_t&, std::string const&)> cb
|
|
|
|
, std::string salt)
|
|
|
|
{
|
|
|
|
if (!m_dht) return;
|
2014-02-28 05:02:48 +01:00
|
|
|
m_dht->put_item(key.data(), boost::bind(&put_mutable_callback
|
|
|
|
, boost::ref(m_alerts), _1, cb), salt);
|
2014-02-24 01:31:13 +01:00
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
|
|
|
|
2010-12-29 03:17:44 +01:00
|
|
|
void session_impl::maybe_update_udp_mapping(int nat, int local_port, int external_port)
|
|
|
|
{
|
|
|
|
int local, external, protocol;
|
|
|
|
if (nat == 0 && m_natpmp.get())
|
|
|
|
{
|
|
|
|
if (m_udp_mapping[nat] != -1)
|
|
|
|
{
|
|
|
|
if (m_natpmp->get_mapping(m_udp_mapping[nat], local, external, protocol))
|
|
|
|
{
|
|
|
|
// we already have a mapping. If it's the same, don't do anything
|
|
|
|
if (local == local_port && external == external_port && protocol == natpmp::udp)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_natpmp->delete_mapping(m_udp_mapping[nat]);
|
|
|
|
}
|
|
|
|
m_udp_mapping[nat] = m_natpmp->add_mapping(natpmp::udp
|
|
|
|
, local_port, external_port);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (nat == 1 && m_upnp.get())
|
|
|
|
{
|
|
|
|
if (m_udp_mapping[nat] != -1)
|
|
|
|
{
|
|
|
|
if (m_upnp->get_mapping(m_udp_mapping[nat], local, external, protocol))
|
|
|
|
{
|
|
|
|
// we already have a mapping. If it's the same, don't do anything
|
|
|
|
if (local == local_port && external == external_port && protocol == natpmp::udp)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_upnp->delete_mapping(m_udp_mapping[nat]);
|
|
|
|
}
|
|
|
|
m_udp_mapping[nat] = m_upnp->add_mapping(upnp::udp
|
|
|
|
, local_port, external_port);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if !defined TORRENT_DISABLE_ENCRYPTION
|
|
|
|
void session_impl::add_obfuscated_hash(sha1_hash const& obfuscated
|
|
|
|
, boost::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-07-06 21:18:00 +02:00
|
|
|
#endif // TORRENT_DISABLE_ENCRYPTION
|
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!
|
|
|
|
TORRENT_ASSERT(is_not_thread());
|
2013-09-29 21:37:57 +02:00
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
m_io_service.post(boost::bind(&session_impl::abort, this));
|
2007-03-02 06:02:12 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// now it's OK for the network thread to exit
|
|
|
|
m_work.reset();
|
2009-04-25 10:45:13 +02:00
|
|
|
|
2010-11-28 02:47:30 +01:00
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
int counter = 0;
|
|
|
|
while (log_async())
|
|
|
|
{
|
|
|
|
sleep(1000);
|
|
|
|
++counter;
|
2014-10-03 22:56:57 +02:00
|
|
|
printf("\x1b[2J\x1b[0;0H\x1b[33m==== Waiting to shut down: %d ==== \x1b[0m\n\n"
|
|
|
|
, counter);
|
2010-11-28 02:47:30 +01:00
|
|
|
}
|
2010-12-24 19:15:01 +01:00
|
|
|
async_dec_threads();
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
fprintf(stderr, "\n\nEXPECTS NO MORE ASYNC OPS\n\n\n");
|
|
|
|
|
|
|
|
// m_io_service.post(boost::bind(&io_service::stop, &m_io_service));
|
2007-05-24 21:51:14 +02:00
|
|
|
#endif
|
2010-12-24 19:15:01 +01:00
|
|
|
|
2010-12-24 02:31:41 +01:00
|
|
|
if (m_thread) m_thread->join();
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2012-06-22 06:21:20 +02:00
|
|
|
m_udp_socket.unsubscribe(this);
|
|
|
|
m_udp_socket.unsubscribe(&m_utp_socket_manager);
|
|
|
|
m_udp_socket.unsubscribe(&m_tracker_manager);
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_torrents.empty());
|
|
|
|
TORRENT_ASSERT(m_connections.empty());
|
2011-02-11 18:39:22 +01:00
|
|
|
|
2011-12-29 13:15:29 +01:00
|
|
|
#ifdef TORRENT_REQUEST_LOGGING
|
|
|
|
if (m_request_log) fclose(m_request_log);
|
|
|
|
#endif
|
|
|
|
|
2011-02-11 18:39:22 +01:00
|
|
|
#ifdef TORRENT_STATS
|
|
|
|
if (m_stats_logger) fclose(m_stats_logger);
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
FILE* f = fopen("wakeups.log", "w+");
|
|
|
|
if (f != NULL)
|
|
|
|
{
|
|
|
|
ptime m = min_time();
|
|
|
|
if (_wakeups.size() > 0) m = _wakeups[0].timestamp;
|
|
|
|
ptime prev = m;
|
|
|
|
boost::uint64_t prev_csw = 0;
|
|
|
|
if (_wakeups.size() > 0) prev_csw = _wakeups[0].context_switches;
|
|
|
|
fprintf(f, "abs. time\trel. time\tctx switch\tidle-wakeup\toperation\n");
|
|
|
|
for (int i = 0; i < _wakeups.size(); ++i)
|
|
|
|
{
|
|
|
|
wakeup_t const& w = _wakeups[i];
|
|
|
|
bool idle_wakeup = w.context_switches > prev_csw;
|
|
|
|
fprintf(f, "%" PRId64 "\t%" PRId64 "\t%" PRId64 "\t%c\t%s\n"
|
|
|
|
, 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)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
settings_pack* p = new settings_pack;
|
|
|
|
p->set_int(settings_pack::local_download_rate_limit, bytes_per_second);
|
|
|
|
apply_settings_pack(p);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_local_upload_rate_limit(int bytes_per_second)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
settings_pack* p = new settings_pack;
|
|
|
|
p->set_int(settings_pack::local_upload_rate_limit, bytes_per_second);
|
|
|
|
apply_settings_pack(p);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_download_rate_limit(int bytes_per_second)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
settings_pack* p = new settings_pack;
|
|
|
|
p->set_int(settings_pack::download_rate_limit, bytes_per_second);
|
|
|
|
apply_settings_pack(p);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_upload_rate_limit(int bytes_per_second)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
settings_pack* p = new settings_pack;
|
|
|
|
p->set_int(settings_pack::upload_rate_limit, bytes_per_second);
|
|
|
|
apply_settings_pack(p);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_max_connections(int limit)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
settings_pack* p = new settings_pack;
|
|
|
|
p->set_int(settings_pack::connections_limit, limit);
|
|
|
|
apply_settings_pack(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)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
settings_pack* p = new settings_pack;
|
|
|
|
p->set_int(settings_pack::unchoke_slots_limit, limit);
|
|
|
|
apply_settings_pack(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
|
|
|
}
|
|
|
|
|
|
|
|
int session_impl::upload_rate_limit() const
|
|
|
|
{
|
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
|
|
|
|
2010-10-09 21:09:38 +02:00
|
|
|
int session_impl::download_rate_limit() const
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
return download_rate_limit(m_global_class);
|
2010-10-09 21:09:38 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void session_impl::update_peer_tos()
|
|
|
|
{
|
|
|
|
error_code ec;
|
2014-08-22 09:56:10 +02:00
|
|
|
|
2014-09-13 21:47:51 +02:00
|
|
|
#if TORRENT_USE_IPV6 && defined IPV6_TCLASS
|
2014-08-22 09:56:10 +02:00
|
|
|
if (m_udp_socket.local_endpoint(ec).address().is_v6())
|
|
|
|
m_udp_socket.set_option(traffic_class(m_settings.get_int(settings_pack::peer_tos)), ec);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
m_udp_socket.set_option(type_of_service(m_settings.get_int(settings_pack::peer_tos)), ec);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING
|
2014-08-22 09:56:10 +02:00
|
|
|
session_log(">>> SET_TOS [ udp_socket tos: %x e: %s ]"
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_settings.get_int(settings_pack::peer_tos)
|
|
|
|
, ec.message().c_str());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_user_agent()
|
|
|
|
{
|
|
|
|
// replace all occurances of '\n' with ' '.
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_choking_algorithm()
|
2010-10-09 21:09:38 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
int algo = m_settings.get_int(settings_pack::choking_algorithm);
|
|
|
|
int unchoke_limit = m_settings.get_int(settings_pack::unchoke_slots_limit);
|
|
|
|
|
|
|
|
if (algo == settings_pack::fixed_slots_choker)
|
|
|
|
m_allowed_upload_slots = unchoke_limit;
|
|
|
|
else if (algo == settings_pack::auto_expand_choker)
|
|
|
|
m_allowed_upload_slots = unchoke_limit;
|
|
|
|
|
2011-12-19 06:53:11 +01:00
|
|
|
if (m_allowed_upload_slots < 0)
|
|
|
|
m_allowed_upload_slots = (std::numeric_limits<int>::max)();
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_stats_counters.set_value(counters::num_unchoke_slots
|
|
|
|
, m_allowed_upload_slots);
|
|
|
|
|
|
|
|
if (m_settings.get_int(settings_pack::num_optimistic_unchoke_slots) >= m_allowed_upload_slots / 2)
|
2010-02-06 08:39:45 +01:00
|
|
|
{
|
|
|
|
if (m_alerts.should_post<performance_alert>())
|
|
|
|
m_alerts.post_alert(performance_alert(torrent_handle()
|
|
|
|
, performance_alert::too_many_optimistic_unchoke_slots));
|
|
|
|
}
|
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()
|
|
|
|
{
|
|
|
|
boost::uint64_t cache_size = m_settings.get_int(settings_pack::cache_size);
|
|
|
|
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>())
|
|
|
|
{
|
|
|
|
m_alerts.post_alert(performance_alert(torrent_handle()
|
|
|
|
, performance_alert::too_high_disk_queue_limit));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2014-09-22 05:47:43 +02:00
|
|
|
return m_stats_counters[counters::num_peers_up_unchoked] < m_allowed_upload_slots
|
|
|
|
|| m_settings.get_int(settings_pack::unchoke_slots_limit) < 0;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_dht_upload_rate_limit()
|
|
|
|
{
|
|
|
|
m_udp_socket.set_rate_limit(m_settings.get_int(settings_pack::dht_upload_rate_limit));
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_disk_threads()
|
|
|
|
{
|
|
|
|
if (m_settings.get_int(settings_pack::aio_threads) < 1)
|
|
|
|
m_settings.set_int(settings_pack::aio_threads, 1);
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
|
|
|
m_disk_thread.set_num_threads(m_settings.get_int(settings_pack::aio_threads));
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_network_threads()
|
|
|
|
{
|
|
|
|
int num_threads = m_settings.get_int(settings_pack::network_threads);
|
|
|
|
int num_pools = num_threads > 0 ? num_threads : 1;
|
|
|
|
while (num_pools > m_net_thread_pool.size())
|
|
|
|
{
|
|
|
|
m_net_thread_pool.push_back(boost::make_shared<network_thread_pool>());
|
|
|
|
m_net_thread_pool.back()->set_num_threads(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (num_pools < m_net_thread_pool.size())
|
|
|
|
{
|
|
|
|
m_net_thread_pool.erase(m_net_thread_pool.end() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_threads == 0 && m_net_thread_pool.size() > 0)
|
|
|
|
{
|
|
|
|
m_net_thread_pool[0]->set_num_threads(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: 3 If socket jobs could be higher level, to include RC4 encryption and decryption,
|
|
|
|
// we would offload the main thread even more
|
|
|
|
void session_impl::post_socket_job(socket_job& j)
|
|
|
|
{
|
|
|
|
uintptr_t idx = 0;
|
|
|
|
if (m_net_thread_pool.size() > 1)
|
|
|
|
{
|
|
|
|
// each peer needs to be pinned to a specific thread
|
|
|
|
// since reading and writing simultaneously on the same
|
|
|
|
// socket from different threads is not supported by asio.
|
|
|
|
// as long as a specific socket is consistently used from
|
|
|
|
// the same thread, it's safe
|
|
|
|
idx = uintptr_t(j.peer.get());
|
|
|
|
idx ^= idx >> 8;
|
|
|
|
idx %= m_net_thread_pool.size();
|
|
|
|
}
|
|
|
|
m_net_thread_pool[idx]->post_job(j);
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
int type = (*i)->type();
|
|
|
|
if (type == peer_connection::url_seed_connection
|
|
|
|
|| type == peer_connection::http_seed_connection)
|
|
|
|
(*i)->ignore_stats(!report);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::trigger_auto_manage()
|
|
|
|
{
|
|
|
|
if (m_pending_auto_manage || m_abort) return;
|
|
|
|
|
|
|
|
m_pending_auto_manage = true;
|
|
|
|
m_need_auto_manage = true;
|
|
|
|
|
|
|
|
// if we haven't started yet, don't actually trigger this
|
|
|
|
if (!m_thread) return;
|
|
|
|
|
|
|
|
m_io_service.post(boost::bind(&session_impl::on_trigger_auto_manage, this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::on_trigger_auto_manage()
|
|
|
|
{
|
|
|
|
assert(m_pending_auto_manage);
|
|
|
|
if (!m_need_auto_manage || m_abort)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_socket_buffer_size()
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
set_socket_buffer_size(m_udp_socket, m_settings, ec);
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<udp_error_alert>())
|
|
|
|
m_alerts.post_alert(udp_error_alert(udp::endpoint(), ec));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_dht_announce_interval()
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (!m_dht)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log("not starting DHT announce timer: m_dht == NULL");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_dht_interval_update_torrents = m_torrents.size();
|
|
|
|
|
|
|
|
// if we haven't started yet, don't actually trigger this
|
|
|
|
if (!m_thread)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log("not starting DHT announce timer: thread not running yet");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_abort)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
session_log("not starting DHT announce timer: m_abort set");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined TORRENT_ASIO_DEBUGGING
|
|
|
|
add_outstanding_async("session_impl::on_dht_announce");
|
|
|
|
#endif
|
|
|
|
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);
|
|
|
|
m_dht_announce_timer.async_wait(
|
|
|
|
boost::bind(&session_impl::on_dht_announce, this, _1));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_anonymous_mode()
|
|
|
|
{
|
|
|
|
if (!m_settings.get_bool(settings_pack::anonymous_mode)) return;
|
|
|
|
|
|
|
|
m_settings.set_str(settings_pack::user_agent, "");
|
|
|
|
url_random((char*)&m_peer_id[0], (char*)&m_peer_id[0] + 20);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::update_force_proxy()
|
|
|
|
{
|
|
|
|
m_udp_socket.set_force_proxy(m_settings.get_bool(settings_pack::force_proxy));
|
|
|
|
|
|
|
|
if (!m_settings.get_bool(settings_pack::force_proxy)) return;
|
|
|
|
|
|
|
|
// if we haven't started yet, don't actually trigger this
|
|
|
|
if (!m_thread) 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
|
|
|
|
// close the listen sockets
|
|
|
|
error_code ec;
|
|
|
|
for (std::list<listen_socket_t>::iterator i = m_listen_sockets.begin()
|
|
|
|
, end(m_listen_sockets.end()); i != end; ++i)
|
|
|
|
i->sock->close(ec);
|
|
|
|
m_listen_sockets.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
#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
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::connections_limit) <= 0)
|
2008-05-16 17:19:38 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
m_settings.set_int(settings_pack::connections_limit, (std::numeric_limits<int>::max)());
|
2010-02-14 05:05:18 +01:00
|
|
|
#if TORRENT_USE_RLIMIT
|
2008-05-16 17:19:38 +02:00
|
|
|
rlimit l;
|
|
|
|
if (getrlimit(RLIMIT_NOFILE, &l) == 0
|
|
|
|
&& l.rlim_cur != RLIM_INFINITY)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
m_settings.set_int(settings_pack::connections_limit
|
|
|
|
, l.rlim_cur - m_settings.get_int(settings_pack::file_pool_size));
|
|
|
|
if (m_settings.get_int(settings_pack::connections_limit) < 5)
|
|
|
|
m_settings.set_int(settings_pack::connections_limit, 5);
|
2008-05-16 17:19:38 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
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;
|
2014-07-06 21:18:00 +02:00
|
|
|
int average = m_settings.get_int(settings_pack::connections_limit) / m_torrents.size();
|
2010-10-03 12:07:38 +02:00
|
|
|
|
|
|
|
// the number of slots that are unused by torrents
|
2014-07-06 21:18:00 +02:00
|
|
|
int extra = m_settings.get_int(settings_pack::connections_limit) % m_torrents.size();
|
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;
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
int num = i->second->num_peers();
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
int num = i->second->num_peers();
|
|
|
|
if (num <= average) continue;
|
|
|
|
|
|
|
|
// distribute the remainder
|
|
|
|
int my_average = average;
|
|
|
|
if (extra > 0)
|
|
|
|
{
|
|
|
|
++my_average;
|
|
|
|
--extra;
|
|
|
|
}
|
|
|
|
|
|
|
|
int disconnect = (std::min)(to_disconnect, num - my_average);
|
|
|
|
to_disconnect -= disconnect;
|
|
|
|
i->second->disconnect_peers(disconnect
|
|
|
|
, error_code(errors::too_many_connections, get_libtorrent_category()));
|
|
|
|
}
|
|
|
|
}
|
2006-10-11 22:57:54 +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()
|
|
|
|
{
|
|
|
|
init_peer_class_filter(m_settings.get_bool(settings_pack::ignore_limits_on_local_network));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void session_impl::update_alert_mask()
|
|
|
|
{
|
|
|
|
m_alerts.set_alert_mask(m_settings.get_int(settings_pack::alert_mask));
|
|
|
|
}
|
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
void session_impl::set_alert_dispatch(boost::function<void(std::auto_ptr<alert>)> const& fun)
|
2008-12-15 08:12:08 +01:00
|
|
|
{
|
|
|
|
m_alerts.set_dispatch_function(fun);
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// this function is called on the user's thread
|
|
|
|
// not the network thread
|
2006-10-11 22:57:54 +02:00
|
|
|
std::auto_ptr<alert> session_impl::pop_alert()
|
|
|
|
{
|
2014-07-21 05:03:59 +02:00
|
|
|
int num_resume = 0;
|
|
|
|
std::auto_ptr<alert> ret = m_alerts.get(num_resume);
|
|
|
|
if (num_resume > 0)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
// we can only issue more resume data jobs from
|
|
|
|
// the network thread
|
|
|
|
m_io_service.post(boost::bind(&session_impl::async_resume_dispatched
|
2014-07-21 05:03:59 +02:00
|
|
|
, this, num_resume));
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
return ret;
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2007-11-25 09:18:57 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// this function is called on the user's thread
|
|
|
|
// not the network thread
|
2011-03-14 03:59:46 +01:00
|
|
|
void session_impl::pop_alerts(std::deque<alert*>* alerts)
|
|
|
|
{
|
2014-07-21 05:03:59 +02:00
|
|
|
int num_resume = 0;
|
|
|
|
m_alerts.get_all(alerts, num_resume);
|
2014-07-06 21:18:00 +02:00
|
|
|
// we can only issue more resume data jobs from
|
|
|
|
// the network thread
|
|
|
|
m_io_service.post(boost::bind(&session_impl::async_resume_dispatched
|
2014-07-21 05:03:59 +02:00
|
|
|
, this, num_resume));
|
2011-03-14 03:59:46 +01:00
|
|
|
}
|
|
|
|
|
2007-11-25 09:18:57 +01:00
|
|
|
alert const* session_impl::wait_for_alert(time_duration max_wait)
|
|
|
|
{
|
|
|
|
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
|
2008-10-07 07:46:42 +02:00
|
|
|
size_t session_impl::set_alert_queue_size_limit(size_t queue_size_limit_)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
m_settings.set_int(settings_pack::alert_queue_size, queue_size_limit_);
|
2008-10-07 07:46:42 +02:00
|
|
|
return m_alerts.set_alert_queue_size_limit(queue_size_limit_);
|
|
|
|
}
|
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;
|
|
|
|
|
2007-09-29 23:31:51 +02:00
|
|
|
m_lsd = new lsd(m_io_service
|
2010-07-22 18:49:40 +02:00
|
|
|
, boost::bind(&session_impl::on_lsd_peer, this, _1, _2));
|
2007-05-31 02:21:54 +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.
|
|
|
|
natpmp* n = new (std::nothrow) natpmp(m_io_service
|
|
|
|
, m_listen_interface.address()
|
|
|
|
, boost::bind(&session_impl::on_port_mapping
|
2010-12-05 21:40:28 +01:00
|
|
|
, this, _1, _2, _3, _4, 0)
|
2010-07-14 06:16:38 +02:00
|
|
|
, boost::bind(&session_impl::on_port_map_log
|
|
|
|
, this, _1, 0));
|
|
|
|
if (n == 0) return 0;
|
|
|
|
|
2009-06-13 12:45:07 +02:00
|
|
|
m_natpmp = n;
|
2007-05-31 02:21:54 +02:00
|
|
|
|
2008-04-13 21:19:22 +02:00
|
|
|
if (m_listen_interface.port() > 0)
|
|
|
|
{
|
2012-01-14 17:04:25 +01:00
|
|
|
remap_tcp_ports(1, m_listen_interface.port(), ssl_listen_port());
|
2008-04-13 21:19:22 +02:00
|
|
|
}
|
2010-05-30 03:33:03 +02:00
|
|
|
if (m_udp_socket.is_open())
|
|
|
|
{
|
2008-04-06 21:17:58 +02:00
|
|
|
m_udp_mapping[0] = m_natpmp->add_mapping(natpmp::udp
|
2010-05-30 03:33:03 +02:00
|
|
|
, m_listen_interface.port(), m_listen_interface.port());
|
|
|
|
}
|
2010-07-15 08:02:58 +02:00
|
|
|
return n;
|
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
|
|
|
|
upnp* u = new (std::nothrow) upnp(m_io_service
|
|
|
|
, m_listen_interface.address()
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_settings.get_str(settings_pack::user_agent)
|
2010-07-14 06:16:38 +02:00
|
|
|
, boost::bind(&session_impl::on_port_mapping
|
2010-12-05 21:40:28 +01:00
|
|
|
, this, _1, _2, _3, _4, 1)
|
2010-07-14 06:16:38 +02:00
|
|
|
, boost::bind(&session_impl::on_port_map_log
|
|
|
|
, this, _1, 1)
|
2014-07-06 21:18:00 +02:00
|
|
|
, m_settings.get_bool(settings_pack::upnp_ignore_nonrouters));
|
2010-07-14 06:16:38 +02:00
|
|
|
|
|
|
|
if (u == 0) return 0;
|
|
|
|
|
2009-06-13 12:45:07 +02:00
|
|
|
m_upnp = u;
|
2007-05-31 02:21:54 +02:00
|
|
|
|
2007-12-24 09:18:53 +01:00
|
|
|
m_upnp->discover_device();
|
2012-01-14 17:04:25 +01:00
|
|
|
if (m_listen_interface.port() > 0 || ssl_listen_port() > 0)
|
2008-04-13 21:19:22 +02:00
|
|
|
{
|
2012-01-14 17:04:25 +01:00
|
|
|
remap_tcp_ports(2, m_listen_interface.port(), ssl_listen_port());
|
2008-04-13 21:19:22 +02:00
|
|
|
}
|
2010-05-30 03:33:03 +02:00
|
|
|
if (m_udp_socket.is_open())
|
|
|
|
{
|
2008-04-06 21:17:58 +02:00
|
|
|
m_udp_mapping[1] = m_upnp->add_mapping(upnp::udp
|
2010-05-30 03:33:03 +02:00
|
|
|
, m_listen_interface.port(), m_listen_interface.port());
|
|
|
|
}
|
2010-07-15 08:02:58 +02:00
|
|
|
return u;
|
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;
|
2013-12-31 23:24:56 +01:00
|
|
|
if (m_upnp) ret = m_upnp->add_mapping((upnp::protocol_type)t, external_port
|
|
|
|
, local_port);
|
|
|
|
if (m_natpmp) ret = m_natpmp->add_mapping((natpmp::protocol_type)t, external_port
|
|
|
|
, 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()
|
|
|
|
{
|
2007-11-19 03:24:07 +01:00
|
|
|
if (m_lsd.get())
|
|
|
|
m_lsd->close();
|
2007-09-29 23:31:51 +02:00
|
|
|
m_lsd = 0;
|
2007-05-31 02:21:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::stop_natpmp()
|
|
|
|
{
|
|
|
|
if (m_natpmp.get())
|
|
|
|
m_natpmp->close();
|
2007-09-29 23:31:51 +02:00
|
|
|
m_natpmp = 0;
|
2007-05-31 02:21:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::stop_upnp()
|
|
|
|
{
|
|
|
|
if (m_upnp.get())
|
2008-04-06 21:17:58 +02:00
|
|
|
{
|
2007-05-31 02:21:54 +02:00
|
|
|
m_upnp->close();
|
2008-04-06 21:17:58 +02:00
|
|
|
m_udp_mapping[1] = -1;
|
|
|
|
m_tcp_mapping[1] = -1;
|
2012-01-14 17:04:25 +01:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
m_ssl_mapping[1] = -1;
|
|
|
|
#endif
|
2008-04-06 21:17:58 +02:00
|
|
|
}
|
2007-09-29 23:31:51 +02:00
|
|
|
m_upnp = 0;
|
2007-05-31 02:21:54 +02:00
|
|
|
}
|
2013-01-02 00:12:16 +01:00
|
|
|
|
|
|
|
external_ip const& session_impl::external_address() const
|
|
|
|
{ return m_external_ip; }
|
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
|
|
|
|
, address const& source)
|
|
|
|
{
|
|
|
|
set_external_address(ip, source_dht, source);
|
|
|
|
}
|
|
|
|
|
2010-12-24 02:31:41 +01:00
|
|
|
void session_impl::set_external_address(address const& ip
|
|
|
|
, int source_type, address const& source)
|
2008-03-29 23:45:55 +01:00
|
|
|
{
|
2010-12-24 02:31:41 +01:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING
|
2012-10-18 09:32:16 +02:00
|
|
|
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
|
|
|
|
|
2013-01-02 00:43:52 +01:00
|
|
|
if (!m_external_ip.cast_vote(ip, source_type, source)) return;
|
2010-12-24 02:31:41 +01:00
|
|
|
|
|
|
|
#if defined TORRENT_VERBOSE_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>())
|
|
|
|
m_alerts.post_alert(external_ip_alert(ip));
|
2010-12-11 10:38:07 +01:00
|
|
|
|
2014-01-23 04:31:36 +01:00
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
i->second->new_external_ip();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2013-01-21 00:21:53 +01:00
|
|
|
// TODO: 1 we only need to do this if our global IPv4 address has changed
|
|
|
|
// since the DHT (currently) only supports IPv4. Since restarting the DHT
|
|
|
|
// is kind of expensive, it would be nice to not do it unnecessarily
|
2010-12-12 10:15:54 +01:00
|
|
|
if (m_dht)
|
|
|
|
{
|
|
|
|
entry s = m_dht->state();
|
|
|
|
int cur_state = 0;
|
|
|
|
int prev_state = 0;
|
|
|
|
entry* nodes1 = s.find_key("nodes");
|
|
|
|
if (nodes1 && nodes1->type() == entry::list_t) cur_state = nodes1->list().size();
|
|
|
|
entry* nodes2 = m_dht_state.find_key("nodes");
|
|
|
|
if (nodes2 && nodes2->type() == entry::list_t) prev_state = nodes2->list().size();
|
|
|
|
if (cur_state > prev_state) m_dht_state = s;
|
|
|
|
start_dht(m_dht_state);
|
|
|
|
}
|
2010-12-11 10:38:07 +01:00
|
|
|
#endif
|
2008-03-29 23:45:55 +01:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// decrement the refcount of the block in the disk cache
|
|
|
|
// since the network thread doesn't need it anymore
|
|
|
|
void session_impl::reclaim_block(block_cache_reference ref)
|
2007-09-29 18:14:03 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
m_disk_thread.reclaim_block(ref);
|
2007-09-29 18:14:03 +02:00
|
|
|
}
|
2008-04-10 12:03:23 +02:00
|
|
|
|
2009-01-23 10:13:31 +01:00
|
|
|
char* session_impl::allocate_disk_buffer(char const* category)
|
2008-04-10 12:03:23 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
return m_disk_thread.allocate_disk_buffer(category);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* session_impl::async_allocate_disk_buffer(char const* category
|
|
|
|
, boost::function<void(char*)> const& handler)
|
|
|
|
{
|
|
|
|
return m_disk_thread.async_allocate_disk_buffer(category, handler);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::free_disk_buffer(char* buf)
|
|
|
|
{
|
|
|
|
m_disk_thread.free_disk_buffer(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* session_impl::allocate_disk_buffer(bool& exceeded
|
|
|
|
, boost::shared_ptr<disk_observer> o
|
|
|
|
, char const* category)
|
|
|
|
{
|
|
|
|
return m_disk_thread.allocate_disk_buffer(exceeded, o, category);
|
2008-04-10 12:03:23 +02:00
|
|
|
}
|
2007-09-29 18:14:03 +02:00
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
char* 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
|
2014-07-06 21:18:00 +02:00
|
|
|
int num_bytes = send_buffer_size();
|
2011-05-19 04:41:28 +02:00
|
|
|
return (char*)malloc(num_bytes);
|
2008-04-09 07:19:11 +02:00
|
|
|
#else
|
2011-05-19 04:41:28 +02:00
|
|
|
return (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
|
2007-09-29 18:14:03 +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());
|
|
|
|
|
|
|
|
int loaded_limit = m_settings.get_int(settings_pack::active_loaded_limit);
|
|
|
|
TORRENT_ASSERT(m_num_save_resume <= loaded_limit);
|
2014-07-10 03:59:35 +02:00
|
|
|
// if (m_num_save_resume < loaded_limit)
|
|
|
|
// TORRENT_ASSERT(m_save_resume_queue.empty());
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
TORRENT_ASSERT(m_torrents.size() >= m_torrent_lru.size());
|
2010-12-04 23:20:31 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_int(settings_pack::unchoke_slots_limit) < 0
|
|
|
|
&& m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::fixed_slots_choker)
|
2012-08-29 03:58:06 +02:00
|
|
|
TORRENT_ASSERT(m_allowed_upload_slots == (std::numeric_limits<int>::max)());
|
|
|
|
|
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
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_HAS_BOOST_UNORDERED
|
|
|
|
boost::unordered_set<torrent*> unique_torrents;
|
|
|
|
#else
|
|
|
|
std::set<torrent*> unique_torrents;
|
|
|
|
#endif
|
|
|
|
for (list_iterator i = m_torrent_lru.iterate(); i.get(); i.next())
|
|
|
|
{
|
|
|
|
torrent* t = (torrent*)i.get();
|
|
|
|
TORRENT_ASSERT(t->is_loaded());
|
|
|
|
TORRENT_ASSERT(unique_torrents.count(t) == 0);
|
|
|
|
unique_torrents.insert(t);
|
|
|
|
}
|
|
|
|
TORRENT_ASSERT(unique_torrents.size() == m_torrent_lru.size());
|
2008-11-19 01:46:48 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
int torrent_state_gauges[counters::num_error_torrents - counters::num_checking_torrents + 1];
|
|
|
|
memset(torrent_state_gauges, 0, sizeof(torrent_state_gauges));
|
|
|
|
|
|
|
|
#if defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
|
|
|
|
|
|
|
#if TORRENT_HAS_BOOST_UNORDERED
|
|
|
|
boost::unordered_set<int> unique;
|
|
|
|
#else
|
2008-05-29 05:37:19 +02:00
|
|
|
std::set<int> unique;
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
#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;
|
|
|
|
for (torrent_map::const_iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
2012-06-21 05:51:39 +02:00
|
|
|
boost::shared_ptr<torrent> t = i->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()));
|
|
|
|
|
|
|
|
++torrent_state_gauges[t->current_stats_state() - counters::num_checking_torrents];
|
2012-06-21 05:51:39 +02:00
|
|
|
|
|
|
|
int 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
|
|
|
|
TORRENT_ASSERT(num_active_downloading == m_torrent_lists[torrent_want_peers_download].size());
|
|
|
|
TORRENT_ASSERT(num_active_finished == m_torrent_lists[torrent_want_peers_finished].size());
|
2008-05-29 05:37:19 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_HAS_BOOST_UNORDERED
|
|
|
|
boost::unordered_set<peer_connection*> unique_peers;
|
|
|
|
#else
|
2008-10-19 00:35:10 +02:00
|
|
|
std::set<peer_connection*> unique_peers;
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
TORRENT_ASSERT(m_settings.get_int(settings_pack::connections_limit) > 0);
|
|
|
|
if (m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::auto_expand_choker)
|
|
|
|
TORRENT_ASSERT(m_allowed_upload_slots >= m_settings.get_int(settings_pack::unchoke_slots_limit));
|
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);
|
|
|
|
boost::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
|
|
|
|
2014-09-22 05:47:43 +02:00
|
|
|
for (std::vector<boost::shared_ptr<peer_connection> >::const_iterator i
|
|
|
|
= m_undead_peers.begin(); i != m_undead_peers.end(); ++i)
|
2010-08-27 16:52:42 +02:00
|
|
|
{
|
2014-09-22 05:47:43 +02:00
|
|
|
peer_connection* p = i->get();
|
|
|
|
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
|
|
|
|
|
|
|
int unchoked_counter_all = m_stats_counters[counters::num_peers_up_unchoked_all];
|
|
|
|
int unchoked_counter = m_stats_counters[counters::num_peers_up_unchoked];
|
|
|
|
int unchoked_counter_optimistic
|
|
|
|
= m_stats_counters[counters::num_peers_up_unchoked_optimistic];
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2011-12-21 22:21:19 +01:00
|
|
|
for (torrent_map::const_iterator j
|
2007-11-27 03:46:19 +01:00
|
|
|
= m_torrents.begin(); j != m_torrents.end(); ++j)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(boost::get_pointer(j->second));
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-07-19 21:06:27 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2014-07-06 21:18:00 +02:00
|
|
|
tracker_logger::tracker_logger(session_interface& ses): m_ses(ses) {}
|
2013-07-19 21:06:27 +02:00
|
|
|
void tracker_logger::tracker_warning(tracker_request const& req
|
|
|
|
, 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
|
|
|
|
, std::list<address> const& ip_list
|
2014-09-28 08:36:03 +02:00
|
|
|
, struct tracker_response const& resp)
|
|
|
|
{
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
|
|
|
debug_log("TRACKER RESPONSE\n"
|
|
|
|
"interval: %d\n"
|
|
|
|
"external ip: %s\n"
|
|
|
|
"we connected to: %s\n"
|
|
|
|
"peers:"
|
2014-10-04 21:54:12 +02:00
|
|
|
, resp.interval
|
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
|
|
|
|
|
|
|
for (std::vector<peer_entry>::const_iterator i = resp.peers.begin();
|
|
|
|
i != resp.peers.end(); ++i)
|
2013-07-19 21:06:27 +02:00
|
|
|
{
|
2014-09-28 08:36:03 +02:00
|
|
|
debug_log(" %16s %5d %s %s", i->hostname.c_str(), i->port
|
|
|
|
, i->pid.is_all_zeros()?"":to_hex(i->pid.to_string()).c_str()
|
|
|
|
, identify_client(i->pid).c_str());
|
2013-07-19 21:06:27 +02:00
|
|
|
}
|
2014-09-28 08:36:03 +02:00
|
|
|
for (std::vector<ipv4_peer_entry>::const_iterator i = resp.peers4.begin();
|
|
|
|
i != resp.peers4.end(); ++i)
|
|
|
|
{
|
2014-10-04 21:54:12 +02:00
|
|
|
debug_log(" %s:%d", print_address(address_v4(i->ip)).c_str(), i->port);
|
2014-09-28 08:36:03 +02:00
|
|
|
}
|
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
for (std::vector<ipv6_peer_entry>::const_iterator i = resp.peers6.begin();
|
|
|
|
i != resp.peers6.end(); ++i)
|
|
|
|
{
|
2014-10-04 21:54:12 +02:00
|
|
|
debug_log(" [%s]:%d", print_address(address_v6(i->ip)).c_str(), i->port);
|
2014-09-28 08:36:03 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
2013-07-19 21:06:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void tracker_logger::tracker_request_timed_out(
|
|
|
|
tracker_request const&)
|
|
|
|
{
|
|
|
|
debug_log("*** tracker timed out");
|
|
|
|
}
|
|
|
|
|
|
|
|
void tracker_logger::tracker_request_error(tracker_request const& r
|
|
|
|
, int response_code, error_code const& ec, const std::string& str
|
|
|
|
, int retry_interval)
|
|
|
|
{
|
|
|
|
debug_log("*** tracker error: %d: %s %s"
|
|
|
|
, response_code, ec.message().c_str(), str.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
void tracker_logger::debug_log(const char* fmt, ...) const
|
|
|
|
{
|
|
|
|
va_list v;
|
|
|
|
va_start(v, fmt);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2013-07-19 21:06:27 +02:00
|
|
|
char usr[1024];
|
|
|
|
vsnprintf(usr, sizeof(usr), fmt, v);
|
|
|
|
va_end(v);
|
2014-07-06 21:18:00 +02:00
|
|
|
m_ses.session_log("%s", usr);
|
2013-07-19 21:06:27 +02:00
|
|
|
}
|
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
}}
|
|
|
|
|