2006-10-11 22:57:54 +02:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2006, Arvid Norberg, Magnus Jonsson
|
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2007-03-17 18:15:16 +01:00
|
|
|
#include "libtorrent/pch.hpp"
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
#include <ctime>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <set>
|
|
|
|
#include <cctype>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#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>
|
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"
|
|
|
|
#include "libtorrent/kademlia/dht_tracker.hpp"
|
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"
|
2006-10-11 22:57:54 +02:00
|
|
|
|
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
|
|
|
|
|
|
|
|
// 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>
|
|
|
|
#endif // TORRENT_DISABLE_DHT
|
|
|
|
|
|
|
|
#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 {
|
|
|
|
|
|
|
|
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
|
|
|
|
2006-11-15 22:39:58 +01:00
|
|
|
struct seed_random_generator
|
|
|
|
{
|
|
|
|
seed_random_generator()
|
2006-11-30 12:56:19 +01:00
|
|
|
{
|
2009-05-25 04:45:51 +02:00
|
|
|
std::srand(total_microseconds(time_now_hires() - min_time()));
|
2006-11-30 12:56:19 +01:00
|
|
|
}
|
2006-11-15 22:39:58 +01:00
|
|
|
};
|
|
|
|
|
2009-12-03 06:11:57 +01:00
|
|
|
enum { std_string = 0, character = 1, short_integer = 2
|
|
|
|
, integer = 3, floating_point = 4, boolean = 5};
|
|
|
|
|
|
|
|
// this is used to map struct entries
|
|
|
|
// to names in a bencoded dictionary to
|
|
|
|
// save and load the struct
|
|
|
|
struct bencode_map_entry
|
|
|
|
{
|
|
|
|
char const* name;
|
|
|
|
int offset; // struct offset
|
|
|
|
int type;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define TORRENT_SETTING(t, x) {#x, offsetof(session_settings,x), t},
|
|
|
|
|
|
|
|
bencode_map_entry session_settings_map[] =
|
|
|
|
{
|
|
|
|
TORRENT_SETTING(std_string, user_agent)
|
|
|
|
TORRENT_SETTING(integer, tracker_completion_timeout)
|
|
|
|
TORRENT_SETTING(integer, tracker_receive_timeout)
|
|
|
|
TORRENT_SETTING(integer, stop_tracker_timeout)
|
|
|
|
TORRENT_SETTING(integer, tracker_maximum_response_length)
|
|
|
|
TORRENT_SETTING(integer, piece_timeout)
|
|
|
|
TORRENT_SETTING(integer, request_timeout)
|
|
|
|
TORRENT_SETTING(integer, request_queue_time)
|
|
|
|
TORRENT_SETTING(integer, max_allowed_in_request_queue)
|
|
|
|
TORRENT_SETTING(integer, max_out_request_queue)
|
|
|
|
TORRENT_SETTING(integer, whole_pieces_threshold)
|
|
|
|
TORRENT_SETTING(integer, peer_timeout)
|
|
|
|
TORRENT_SETTING(integer, urlseed_timeout)
|
|
|
|
TORRENT_SETTING(integer, urlseed_pipeline_size)
|
|
|
|
TORRENT_SETTING(integer, urlseed_wait_retry)
|
|
|
|
TORRENT_SETTING(integer, file_pool_size)
|
|
|
|
TORRENT_SETTING(boolean, allow_multiple_connections_per_ip)
|
|
|
|
TORRENT_SETTING(integer, max_failcount)
|
|
|
|
TORRENT_SETTING(integer, min_reconnect_time)
|
|
|
|
TORRENT_SETTING(integer, peer_connect_timeout)
|
|
|
|
TORRENT_SETTING(boolean, ignore_limits_on_local_network)
|
|
|
|
TORRENT_SETTING(integer, connection_speed)
|
|
|
|
TORRENT_SETTING(boolean, send_redundant_have)
|
|
|
|
TORRENT_SETTING(boolean, lazy_bitfields)
|
|
|
|
TORRENT_SETTING(integer, inactivity_timeout)
|
|
|
|
TORRENT_SETTING(integer, unchoke_interval)
|
|
|
|
TORRENT_SETTING(integer, optimistic_unchoke_interval)
|
|
|
|
TORRENT_SETTING(std_string, announce_ip)
|
|
|
|
TORRENT_SETTING(integer, num_want)
|
|
|
|
TORRENT_SETTING(integer, initial_picker_threshold)
|
|
|
|
TORRENT_SETTING(integer, allowed_fast_set_size)
|
2010-01-15 17:45:42 +01:00
|
|
|
TORRENT_SETTING(integer, suggest_mode)
|
2009-12-03 06:11:57 +01:00
|
|
|
TORRENT_SETTING(integer, max_queued_disk_bytes)
|
|
|
|
TORRENT_SETTING(integer, handshake_timeout)
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
TORRENT_SETTING(boolean, use_dht_as_fallback)
|
|
|
|
#endif
|
|
|
|
TORRENT_SETTING(boolean, free_torrent_hashes)
|
|
|
|
TORRENT_SETTING(boolean, upnp_ignore_nonrouters)
|
|
|
|
TORRENT_SETTING(integer, send_buffer_watermark)
|
2010-02-09 04:04:41 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2009-12-03 06:11:57 +01:00
|
|
|
TORRENT_SETTING(boolean, auto_upload_slots)
|
|
|
|
TORRENT_SETTING(boolean, auto_upload_slots_rate_based)
|
2010-02-09 04:04:41 +01:00
|
|
|
#endif
|
|
|
|
TORRENT_SETTING(integer, choking_algorithm)
|
2009-12-03 06:11:57 +01:00
|
|
|
TORRENT_SETTING(boolean, use_parole_mode)
|
|
|
|
TORRENT_SETTING(integer, cache_size)
|
|
|
|
TORRENT_SETTING(integer, cache_buffer_chunk_size)
|
|
|
|
TORRENT_SETTING(integer, cache_expiry)
|
|
|
|
TORRENT_SETTING(boolean, use_read_cache)
|
2010-01-15 17:45:42 +01:00
|
|
|
TORRENT_SETTING(boolean, explicit_read_cache)
|
2009-12-03 06:11:57 +01:00
|
|
|
TORRENT_SETTING(integer, disk_io_write_mode)
|
|
|
|
TORRENT_SETTING(integer, disk_io_read_mode)
|
|
|
|
TORRENT_SETTING(boolean, coalesce_reads)
|
|
|
|
TORRENT_SETTING(boolean, coalesce_writes)
|
|
|
|
TORRENT_SETTING(character, peer_tos)
|
|
|
|
TORRENT_SETTING(integer, active_downloads)
|
|
|
|
TORRENT_SETTING(integer, active_seeds)
|
2010-03-29 02:34:04 +02:00
|
|
|
TORRENT_SETTING(integer, active_dht_limit)
|
|
|
|
TORRENT_SETTING(integer, active_tracker_limit)
|
|
|
|
TORRENT_SETTING(integer, active_lsd_limit)
|
2009-12-03 06:11:57 +01:00
|
|
|
TORRENT_SETTING(integer, active_limit)
|
|
|
|
TORRENT_SETTING(boolean, auto_manage_prefer_seeds)
|
|
|
|
TORRENT_SETTING(boolean, dont_count_slow_torrents)
|
|
|
|
TORRENT_SETTING(integer, auto_manage_interval)
|
|
|
|
TORRENT_SETTING(floating_point, share_ratio_limit)
|
|
|
|
TORRENT_SETTING(floating_point, seed_time_ratio_limit)
|
|
|
|
TORRENT_SETTING(integer, seed_time_limit)
|
|
|
|
TORRENT_SETTING(floating_point, peer_turnover)
|
|
|
|
TORRENT_SETTING(floating_point, peer_turnover_cutoff)
|
|
|
|
TORRENT_SETTING(boolean, close_redundant_connections)
|
|
|
|
TORRENT_SETTING(integer, auto_scrape_interval)
|
|
|
|
TORRENT_SETTING(integer, auto_scrape_min_interval)
|
|
|
|
TORRENT_SETTING(integer, max_peerlist_size)
|
|
|
|
TORRENT_SETTING(integer, max_paused_peerlist_size)
|
|
|
|
TORRENT_SETTING(integer, min_announce_interval)
|
|
|
|
TORRENT_SETTING(boolean, prioritize_partial_pieces)
|
|
|
|
TORRENT_SETTING(integer, auto_manage_startup)
|
|
|
|
TORRENT_SETTING(boolean, rate_limit_ip_overhead)
|
|
|
|
TORRENT_SETTING(boolean, announce_to_all_trackers)
|
|
|
|
TORRENT_SETTING(boolean, announce_to_all_tiers)
|
|
|
|
TORRENT_SETTING(boolean, prefer_udp_trackers)
|
|
|
|
TORRENT_SETTING(boolean, strict_super_seeding)
|
|
|
|
TORRENT_SETTING(integer, seeding_piece_quota)
|
|
|
|
TORRENT_SETTING(integer, max_sparse_regions)
|
|
|
|
#ifndef TORRENT_DISABLE_MLOCK
|
|
|
|
TORRENT_SETTING(boolean, lock_disk_cache)
|
|
|
|
#endif
|
|
|
|
TORRENT_SETTING(integer, max_rejects)
|
|
|
|
TORRENT_SETTING(integer, recv_socket_buffer_size)
|
|
|
|
TORRENT_SETTING(integer, send_socket_buffer_size)
|
|
|
|
TORRENT_SETTING(boolean, optimize_hashing_for_speed)
|
|
|
|
TORRENT_SETTING(integer, file_checks_delay_per_block)
|
|
|
|
TORRENT_SETTING(integer, disk_cache_algorithm)
|
|
|
|
TORRENT_SETTING(integer, read_cache_line_size)
|
|
|
|
TORRENT_SETTING(integer, write_cache_line_size)
|
|
|
|
TORRENT_SETTING(integer, optimistic_disk_retry)
|
|
|
|
TORRENT_SETTING(boolean, disable_hash_checks)
|
|
|
|
TORRENT_SETTING(boolean, allow_reordered_disk_operations)
|
|
|
|
TORRENT_SETTING(boolean, allow_i2p_mixed)
|
|
|
|
TORRENT_SETTING(integer, max_suggest_pieces)
|
2010-01-24 23:00:36 +01:00
|
|
|
TORRENT_SETTING(boolean, drop_skipped_requests)
|
|
|
|
TORRENT_SETTING(boolean, low_prio_disk)
|
2010-02-06 09:14:18 +01:00
|
|
|
TORRENT_SETTING(integer, local_service_announce_interval)
|
|
|
|
TORRENT_SETTING(integer, udp_tracker_token_expiry)
|
|
|
|
TORRENT_SETTING(boolean, volatile_read_cache)
|
|
|
|
TORRENT_SETTING(boolean, guided_read_cache)
|
|
|
|
TORRENT_SETTING(integer, default_cache_min_age)
|
|
|
|
TORRENT_SETTING(integer, num_optimistic_unchoke_slots)
|
|
|
|
TORRENT_SETTING(boolean, no_atime_storage)
|
2010-02-21 02:34:23 +01:00
|
|
|
TORRENT_SETTING(integer, default_est_reciprocation_rate)
|
|
|
|
TORRENT_SETTING(integer, increase_est_reciprocation_rate)
|
|
|
|
TORRENT_SETTING(integer, decrease_est_reciprocation_rate)
|
|
|
|
TORRENT_SETTING(boolean, incoming_starts_queued_torrents)
|
|
|
|
TORRENT_SETTING(boolean, report_true_downloaded)
|
|
|
|
TORRENT_SETTING(boolean, strict_end_game_mode)
|
2010-03-03 02:31:31 +01:00
|
|
|
TORRENT_SETTING(integer, default_peer_upload_rate)
|
|
|
|
TORRENT_SETTING(integer, default_peer_download_rate)
|
2010-04-13 06:30:34 +02:00
|
|
|
TORRENT_SETTING(boolean, broadcast_lsd)
|
2010-04-11 23:02:43 +02:00
|
|
|
TORRENT_SETTING(boolean, ignore_resume_timestamps)
|
2010-04-13 06:30:34 +02:00
|
|
|
TORRENT_SETTING(boolean, anonymous_mode)
|
2010-05-03 10:54:03 +02:00
|
|
|
TORRENT_SETTING(integer, tick_interval)
|
2009-12-03 06:11:57 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#undef TORRENT_SETTING
|
|
|
|
#define TORRENT_SETTING(t, x) {#x, offsetof(proxy_settings,x), t},
|
|
|
|
|
|
|
|
bencode_map_entry proxy_settings_map[] =
|
|
|
|
{
|
|
|
|
TORRENT_SETTING(std_string, hostname)
|
|
|
|
TORRENT_SETTING(integer, port)
|
|
|
|
TORRENT_SETTING(std_string, username)
|
|
|
|
TORRENT_SETTING(std_string, password)
|
|
|
|
TORRENT_SETTING(integer, type)
|
|
|
|
};
|
|
|
|
#undef TORRENT_SETTING
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
#define TORRENT_SETTING(t, x) {#x, offsetof(dht_settings,x), t},
|
|
|
|
bencode_map_entry dht_settings_map[] =
|
|
|
|
{
|
|
|
|
TORRENT_SETTING(integer, max_peers_reply)
|
|
|
|
TORRENT_SETTING(integer, search_branching)
|
2010-05-30 03:33:03 +02:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2009-12-03 06:11:57 +01:00
|
|
|
TORRENT_SETTING(integer, service_port)
|
2010-05-30 03:33:03 +02:00
|
|
|
#endif
|
2009-12-03 06:11:57 +01:00
|
|
|
TORRENT_SETTING(integer, max_fail_count)
|
|
|
|
TORRENT_SETTING(integer, max_torrent_search_reply)
|
|
|
|
};
|
|
|
|
#undef TORRENT_SETTING
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
|
|
|
#define TORRENT_SETTING(t, x) {#x, offsetof(pe_settings,x), t},
|
|
|
|
bencode_map_entry pe_settings_map[] =
|
|
|
|
{
|
|
|
|
TORRENT_SETTING(integer, out_enc_policy)
|
|
|
|
TORRENT_SETTING(integer, in_enc_policy)
|
|
|
|
TORRENT_SETTING(integer, allowed_enc_level)
|
|
|
|
TORRENT_SETTING(boolean, prefer_rc4)
|
|
|
|
};
|
|
|
|
#undef TORRENT_SETTING
|
|
|
|
#endif
|
|
|
|
|
2010-03-10 03:28:40 +01:00
|
|
|
struct session_category
|
|
|
|
{
|
|
|
|
char const* name;
|
|
|
|
bencode_map_entry const* map;
|
|
|
|
int num_entries;
|
|
|
|
int flag;
|
|
|
|
int offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define lenof(x) sizeof(x)/sizeof(x[0])
|
|
|
|
#define TORRENT_CATEGORY(name, flag, member, map) \
|
|
|
|
{ name, map, lenof(map), session:: flag , offsetof(session_impl, member) },
|
|
|
|
|
|
|
|
session_category all_settings[] =
|
|
|
|
{
|
|
|
|
TORRENT_CATEGORY("settings", save_settings, m_settings, session_settings_map)
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
// TORRENT_CATEGORY("dht", save_dht_settings, m_dht_settings, dht_settings_map)
|
|
|
|
TORRENT_CATEGORY("dht proxy", save_dht_proxy, m_dht_proxy, proxy_settings_map)
|
|
|
|
#endif
|
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
// TORRENT_CATEGORY("i2p", save_i2p_proxy, m_i2p_proxy, proxy_settings_map)
|
|
|
|
#endif
|
|
|
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
|
|
|
TORRENT_CATEGORY("encryption", save_encryption_settings, m_pe_settings, pe_settings_map)
|
|
|
|
#endif
|
|
|
|
TORRENT_CATEGORY("peer proxy", save_peer_proxy, m_peer_proxy, proxy_settings_map)
|
|
|
|
TORRENT_CATEGORY("web proxy", save_web_proxy, m_web_seed_proxy, proxy_settings_map)
|
|
|
|
TORRENT_CATEGORY("tracker proxy", save_tracker_proxy, m_tracker_proxy, proxy_settings_map)
|
|
|
|
};
|
|
|
|
|
|
|
|
#undef lenof
|
|
|
|
|
2009-12-03 06:11:57 +01:00
|
|
|
void load_struct(lazy_entry const& e, void* s, bencode_map_entry const* m, int num)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < num; ++i)
|
|
|
|
{
|
|
|
|
lazy_entry const* key = e.dict_find(m[i].name);
|
|
|
|
if (key == 0) continue;
|
|
|
|
void* dest = ((char*)s) + m[i].offset;
|
|
|
|
switch (m[i].type)
|
|
|
|
{
|
|
|
|
case std_string:
|
|
|
|
{
|
|
|
|
if (key->type() != lazy_entry::string_t) continue;
|
|
|
|
*((std::string*)dest) = key->string_value();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case character:
|
|
|
|
case boolean:
|
|
|
|
case integer:
|
|
|
|
case floating_point:
|
|
|
|
{
|
|
|
|
if (key->type() != lazy_entry::int_t) continue;
|
|
|
|
size_type val = key->int_value();
|
|
|
|
switch (m[i].type)
|
|
|
|
{
|
|
|
|
case character: *((char*)dest) = val; break;
|
|
|
|
case integer: *((int*)dest) = val; break;
|
|
|
|
case floating_point: *((float*)dest) = float(val) / 1000.f; break;
|
|
|
|
case boolean: *((bool*)dest) = val; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void save_struct(entry& e, void const* s, bencode_map_entry const* m, int num)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < num; ++i)
|
|
|
|
{
|
|
|
|
char const* key = m[i].name;
|
|
|
|
void const* src = ((char*)s) + m[i].offset;
|
|
|
|
entry& val = e[key];
|
|
|
|
TORRENT_ASSERT(val.type() == entry::undefined_t);
|
|
|
|
switch (m[i].type)
|
|
|
|
{
|
|
|
|
case std_string:
|
|
|
|
{
|
|
|
|
val = *((std::string*)src);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case character: val = *((char*)src); break;
|
|
|
|
case integer: val = *((int*)src); break;
|
|
|
|
case floating_point: val = size_type(*((float*)src) * 1000.f); break;
|
|
|
|
case boolean: val = *((bool*)src); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-07 22:30:20 +02:00
|
|
|
#ifdef TORRENT_STATS
|
|
|
|
int session_impl::logging_allocator::allocations = 0;
|
|
|
|
int session_impl::logging_allocator::allocated_bytes = 0;
|
|
|
|
#endif
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
session_impl::session_impl(
|
|
|
|
std::pair<int, int> listen_port_range
|
|
|
|
, fingerprint const& cl_fprint
|
2007-11-16 22:21:28 +01:00
|
|
|
, char const* listen_interface
|
2008-02-17 23:51:03 +01:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2009-10-26 02:29:39 +01:00
|
|
|
, std::string const& logpath
|
2007-11-16 22:21:28 +01:00
|
|
|
#endif
|
|
|
|
)
|
2009-05-24 23:49:19 +02:00
|
|
|
: m_ipv4_peer_pool(500)
|
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
, m_ipv6_peer_pool(500)
|
|
|
|
#endif
|
2008-04-09 07:19:11 +02:00
|
|
|
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
2009-05-07 00:36:24 +02:00
|
|
|
, m_send_buffers(send_buffer_size)
|
2008-04-09 07:19:11 +02:00
|
|
|
#endif
|
2009-05-07 00:36:24 +02:00
|
|
|
, m_files(40)
|
2008-02-08 11:22:05 +01:00
|
|
|
, m_io_service()
|
2009-05-23 23:36:09 +02:00
|
|
|
, m_alerts(m_io_service)
|
2010-01-23 04:02:32 +01:00
|
|
|
, m_disk_thread(m_io_service, boost::bind(&session_impl::on_disk_queue, this), m_files)
|
2007-05-24 20:53:55 +02:00
|
|
|
, m_half_open(m_io_service)
|
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
|
2008-09-22 02:15:05 +02:00
|
|
|
, m_tracker_manager(*this, m_tracker_proxy)
|
2007-09-22 18:27:29 +02:00
|
|
|
, m_listen_port_retries(listen_port_range.second - listen_port_range.first)
|
2009-08-20 05:19:12 +02:00
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
, m_i2p_conn(m_io_service)
|
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
, m_abort(false)
|
2008-06-29 21:08:30 +02:00
|
|
|
, m_paused(false)
|
2007-08-16 14:41:46 +02:00
|
|
|
, m_max_uploads(8)
|
2008-01-13 12:18:18 +01:00
|
|
|
, m_allowed_upload_slots(8)
|
2007-08-16 14:41:46 +02:00
|
|
|
, m_max_connections(200)
|
|
|
|
, m_num_unchoked(0)
|
|
|
|
, 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)
|
2010-02-09 04:04:41 +01:00
|
|
|
, m_peak_up_rate(0)
|
|
|
|
, m_peak_down_rate(0)
|
2006-10-11 22:57:54 +02:00
|
|
|
, m_incoming_connection(false)
|
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)
|
|
|
|
, m_last_second_tick(m_created)
|
|
|
|
, m_last_choke(m_created)
|
2007-03-15 23:03:56 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2010-02-14 02:39:55 +01:00
|
|
|
, m_dht_announce_timer(m_io_service)
|
2007-03-15 23:03:56 +01:00
|
|
|
#endif
|
2010-05-30 03:33:03 +02:00
|
|
|
, m_external_udp_port(0)
|
|
|
|
, m_udp_socket(m_io_service, boost::bind(&session_impl::on_receive_udp, this, _1, _2, _3, _4)
|
|
|
|
, m_half_open)
|
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)
|
|
|
|
, m_tick_residual(0)
|
2008-02-17 23:51:03 +01:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2007-11-16 22:21:28 +01:00
|
|
|
, m_logpath(logpath)
|
2008-04-05 06:53:22 +02:00
|
|
|
#endif
|
|
|
|
#ifndef TORRENT_DISABLE_GEO_IP
|
2008-04-11 10:46:43 +02:00
|
|
|
, m_asnum_db(0)
|
|
|
|
, m_country_db(0)
|
2007-11-16 22:21:28 +01:00
|
|
|
#endif
|
2008-07-11 09:30:04 +02:00
|
|
|
, m_total_failed_bytes(0)
|
|
|
|
, m_total_redundant_bytes(0)
|
2006-10-11 22:57:54 +02: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);
|
|
|
|
(*m_logger) << time_now_string() << "\n";
|
|
|
|
#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();
|
|
|
|
m_next_connect_torrent = m_torrents.begin();
|
|
|
|
|
2008-12-21 00:06:06 +01:00
|
|
|
TORRENT_ASSERT(listen_interface);
|
2008-11-05 06:39:18 +01:00
|
|
|
error_code ec;
|
|
|
|
m_listen_interface = tcp::endpoint(address::from_string(listen_interface, ec), listen_port_range.first);
|
|
|
|
TORRENT_ASSERT(!ec);
|
|
|
|
|
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;
|
2007-09-10 03:57:40 +02:00
|
|
|
#ifdef WIN32
|
2007-10-15 03:15:58 +02:00
|
|
|
// windows XP has a limit on the number of
|
|
|
|
// simultaneous half-open TCP connections
|
2010-03-31 04:50:09 +02:00
|
|
|
// here's a table:
|
|
|
|
|
|
|
|
// windows version half-open connections limit
|
|
|
|
// --------------------- ---------------------------
|
|
|
|
// XP sp1 and earlier infinite
|
|
|
|
// earlier than vista 8
|
|
|
|
// vista sp1 and earlier 5
|
|
|
|
// vista sp2 and later infinite
|
|
|
|
|
|
|
|
// windows release version number
|
|
|
|
// ----------------------------------- --------------
|
|
|
|
// Windows 7 6.1
|
|
|
|
// Windows Server 2008 R2 6.1
|
|
|
|
// Windows Server 2008 6.0
|
|
|
|
// Windows Vista 6.0
|
|
|
|
// Windows Server 2003 R2 5.2
|
|
|
|
// Windows Home Server 5.2
|
|
|
|
// Windows Server 2003 5.2
|
|
|
|
// Windows XP Professional x64 Edition 5.2
|
|
|
|
// Windows XP 5.1
|
|
|
|
// Windows 2000 5.0
|
|
|
|
|
|
|
|
OSVERSIONINFOEX osv;
|
|
|
|
memset(&osv, 0, sizeof(osv));
|
|
|
|
osv.dwOSVersionInfoSize = sizeof(osv);
|
|
|
|
GetVersionEx((OSVERSIONINFO*)&osv);
|
|
|
|
|
|
|
|
// the low two bytes of windows_version is the actual
|
|
|
|
// version.
|
|
|
|
boost::uint32_t windows_version
|
|
|
|
= ((osv.dwMajorVersion & 0xff) << 16)
|
2010-03-31 06:22:48 +02:00
|
|
|
| ((osv.dwMinorVersion & 0xff) << 8)
|
2010-03-31 04:50:09 +02:00
|
|
|
| (osv.wServicePackMajor & 0xff);
|
|
|
|
|
|
|
|
// this is the format of windows_version
|
|
|
|
// xx xx xx
|
|
|
|
// | | |
|
|
|
|
// | | + service pack version
|
|
|
|
// | + minor version
|
|
|
|
// + major version
|
|
|
|
|
|
|
|
// the least significant byte is the major version
|
|
|
|
// and the most significant one is the minor version
|
|
|
|
if (windows_version >= 0x060100)
|
|
|
|
{
|
|
|
|
// windows 7 and up doesn't have a half-open limit
|
|
|
|
m_half_open.limit(0);
|
|
|
|
}
|
|
|
|
else if (windows_version >= 0x060002)
|
|
|
|
{
|
|
|
|
// on vista SP 2 and up, there's no limit
|
|
|
|
m_half_open.limit(0);
|
|
|
|
}
|
|
|
|
else if (windows_version >= 0x060000)
|
2007-10-15 03:15:58 +02:00
|
|
|
{
|
|
|
|
// on vista the limit is 5 (in home edition)
|
|
|
|
m_half_open.limit(4);
|
|
|
|
}
|
2010-03-31 04:50:09 +02:00
|
|
|
else if (windows_version >= 0x050102)
|
|
|
|
{
|
|
|
|
// on XP SP2 the limit is 10
|
|
|
|
m_half_open.limit(9);
|
|
|
|
}
|
2007-10-15 03:15:58 +02:00
|
|
|
else
|
|
|
|
{
|
2010-03-31 04:50:09 +02:00
|
|
|
// before XP SP2, there was no limit
|
|
|
|
m_half_open.limit(0);
|
2007-10-15 03:15:58 +02:00
|
|
|
}
|
2007-09-10 03:57:40 +02:00
|
|
|
#endif
|
|
|
|
|
2009-04-26 02:21:59 +02:00
|
|
|
m_bandwidth_channel[peer_connection::download_channel] = &m_download_channel;
|
|
|
|
m_bandwidth_channel[peer_connection::upload_channel] = &m_upload_channel;
|
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
|
2009-04-30 07:49:46 +02:00
|
|
|
#define PRINT_SIZEOF(x) (*m_logger) << "sizeof(" #x "): " << sizeof(x) << "\n";
|
|
|
|
#define PRINT_OFFSETOF(x, y) (*m_logger) << " offsetof(" #x "," #y "): " << offsetof(x, y) << "\n";
|
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
PRINT_SIZEOF(union_endpoint)
|
2010-02-08 05:51:34 +01:00
|
|
|
PRINT_SIZEOF(request_callback)
|
|
|
|
PRINT_SIZEOF(stat)
|
|
|
|
PRINT_SIZEOF(bandwidth_channel)
|
|
|
|
PRINT_SIZEOF(policy)
|
|
|
|
stat_channel::print_size(*m_logger);
|
|
|
|
torrent::print_size(*m_logger);
|
|
|
|
|
2009-04-30 07:49:46 +02:00
|
|
|
PRINT_SIZEOF(peer_connection)
|
|
|
|
PRINT_SIZEOF(bt_peer_connection)
|
|
|
|
PRINT_SIZEOF(address)
|
|
|
|
PRINT_SIZEOF(address_v4)
|
|
|
|
PRINT_SIZEOF(address_v4::bytes_type)
|
2009-11-27 22:04:26 +01:00
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
PRINT_SIZEOF(address_v6)
|
2009-04-30 07:49:46 +02:00
|
|
|
PRINT_SIZEOF(address_v6::bytes_type)
|
2009-11-27 22:04:26 +01:00
|
|
|
#endif
|
2009-04-30 07:49:46 +02:00
|
|
|
PRINT_SIZEOF(void*)
|
2010-02-05 09:40:08 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2009-04-30 07:49:46 +02:00
|
|
|
PRINT_SIZEOF(dht::node_entry)
|
2010-02-05 09:40:08 +01:00
|
|
|
#endif
|
2009-04-30 07:49:46 +02:00
|
|
|
|
|
|
|
PRINT_SIZEOF(policy::peer)
|
|
|
|
PRINT_OFFSETOF(policy::peer, connection)
|
|
|
|
PRINT_OFFSETOF(policy::peer, last_optimistically_unchoked)
|
|
|
|
PRINT_OFFSETOF(policy::peer, last_connected)
|
|
|
|
PRINT_OFFSETOF(policy::peer, port)
|
|
|
|
PRINT_OFFSETOF(policy::peer, hashfails)
|
|
|
|
|
2009-05-24 23:49:19 +02:00
|
|
|
PRINT_SIZEOF(policy::ipv4_peer)
|
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
PRINT_SIZEOF(policy::ipv6_peer)
|
|
|
|
#endif
|
|
|
|
|
2010-02-05 09:40:08 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2009-05-14 00:18:41 +02:00
|
|
|
PRINT_SIZEOF(dht::find_data_observer)
|
|
|
|
PRINT_SIZEOF(dht::announce_observer)
|
|
|
|
PRINT_SIZEOF(dht::null_observer)
|
2010-02-05 09:40:08 +01:00
|
|
|
#endif
|
2009-04-30 07:49:46 +02:00
|
|
|
#undef PRINT_OFFSETOF
|
|
|
|
#undef PRINT_SIZEOF
|
|
|
|
|
2007-05-14 00:01:21 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef TORRENT_STATS
|
2007-09-29 18:14:03 +02:00
|
|
|
m_stats_logger.open("session_stats.log", std::ios::trunc);
|
2007-05-14 00:01:21 +02:00
|
|
|
m_stats_logger <<
|
2008-12-25 23:26:02 +01:00
|
|
|
"second:upload rate:download rate:downloading torrents:seeding torrents"
|
2009-05-07 22:30:20 +02:00
|
|
|
":peers:connecting peers:disk block buffers:unchoked peers:num list peers"
|
|
|
|
":peer allocations:peer storage bytes\n\n";
|
2007-09-29 18:14:03 +02:00
|
|
|
m_buffer_usage_logger.open("buffer_stats.log", std::ios::trunc);
|
2006-11-21 16:51:28 +01:00
|
|
|
m_second_counter = 0;
|
2008-02-12 09:34:57 +01:00
|
|
|
m_buffer_allocations = 0;
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
|
|
|
|
2009-10-03 21:02:31 +02:00
|
|
|
#if defined TORRENT_BSD || defined TORRENT_LINUX
|
|
|
|
// ---- auto-cap open files ----
|
|
|
|
|
|
|
|
struct rlimit rl;
|
|
|
|
if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
|
|
|
|
{
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2009-12-28 21:59:34 +01:00
|
|
|
(*m_logger) << time_now_string() << " max number of open files: " << rl.rlim_cur << "\n";
|
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;
|
|
|
|
|
|
|
|
// 80% of the available file descriptors should go
|
|
|
|
m_max_connections = (std::min)(m_max_connections, int(rl.rlim_cur * 8 / 10));
|
|
|
|
// 20% goes towards regular files
|
|
|
|
m_files.resize((std::min)(m_files.size_limit(), int(rl.rlim_cur * 2 / 10)));
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
(*m_logger) << time_now_string() << " max connections: " << m_max_connections << "\n";
|
|
|
|
(*m_logger) << time_now_string() << " max files: " << m_files.size_limit() << "\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif // TORRENT_BSD || TORRENT_LINUX
|
|
|
|
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
// ---- generate a peer id ----
|
2006-11-15 22:39:58 +01:00
|
|
|
static seed_random_generator seeder;
|
2006-10-11 22:57:54 +02:00
|
|
|
|
|
|
|
m_key = rand() + (rand() << 15) + (rand() << 30);
|
|
|
|
std::string print = cl_fprint.to_string();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(print.length() <= 20);
|
2006-10-11 22:57:54 +02:00
|
|
|
|
|
|
|
// the client's fingerprint
|
|
|
|
std::copy(
|
|
|
|
print.begin()
|
|
|
|
, print.begin() + print.length()
|
|
|
|
, m_peer_id.begin());
|
|
|
|
|
2010-04-13 06:30:34 +02:00
|
|
|
url_random((char*)&m_peer_id[print.length()], (char*)&m_peer_id[0] + 20);
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2010-05-03 10:54:03 +02:00
|
|
|
m_timer.expires_from_now(milliseconds(m_settings.tick_interval), ec);
|
2010-04-30 21:08:16 +02:00
|
|
|
m_timer.async_wait(boost::bind(&session_impl::on_tick, this, _1));
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2010-02-05 09:23:17 +01:00
|
|
|
int delay = (std::max)(m_settings.local_service_announce_interval
|
|
|
|
/ (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-02-05 09:23:17 +01:00
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
delay = (std::max)(m_settings.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(
|
2010-04-30 21:08:16 +02:00
|
|
|
boost::bind(&session_impl::on_dht_announce, this, _1));
|
2010-02-14 02:39:55 +01:00
|
|
|
#endif
|
|
|
|
|
2010-06-17 19:14:56 +02:00
|
|
|
// no reuse_address
|
|
|
|
open_listen_port(false);
|
2010-06-01 04:04:00 +02:00
|
|
|
|
2009-10-20 04:49:56 +02:00
|
|
|
m_thread.reset(new thread(boost::bind(&session_impl::main_thread, this)));
|
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
|
|
|
{
|
2010-07-14 06:16:38 +02:00
|
|
|
entry& e = *eptr;
|
|
|
|
|
2010-03-08 04:51:07 +01:00
|
|
|
if (flags & session::save_settings)
|
|
|
|
{
|
|
|
|
// TODO: move these to session_settings
|
|
|
|
e["upload_rate_limit"] = upload_rate_limit();
|
2010-03-13 18:37:47 +01:00
|
|
|
e["download_rate_limit"] = download_rate_limit();
|
2010-03-08 04:51:07 +01:00
|
|
|
e["local_upload_rate_limit"] = local_upload_rate_limit();
|
2010-03-13 18:37:47 +01:00
|
|
|
e["local_download_rate_limit"] = local_download_rate_limit();
|
2010-03-08 04:51:07 +01:00
|
|
|
e["max_uploads"] = max_uploads();
|
|
|
|
e["max_half_open_connections"] = max_half_open_connections();
|
|
|
|
e["max_connections"] = max_connections();
|
|
|
|
}
|
|
|
|
|
2010-03-10 03:28:40 +01:00
|
|
|
for (int i = 0; i < sizeof(all_settings)/sizeof(all_settings[0]); ++i)
|
2010-03-06 08:49:40 +01:00
|
|
|
{
|
2010-03-10 03:28:40 +01:00
|
|
|
session_category const& c = all_settings[i];
|
|
|
|
if ((flags & c.flag) == 0) continue;
|
|
|
|
save_struct(e[c.name], reinterpret_cast<char const*>(this) + c.offset, c.map, c.num_entries);
|
2010-03-06 08:49:40 +01:00
|
|
|
}
|
2009-12-03 06:11:57 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2010-03-06 08:49:40 +01:00
|
|
|
if (flags & session::save_dht_settings)
|
|
|
|
{
|
|
|
|
save_struct(e["dht"], &m_dht_settings, dht_settings_map
|
|
|
|
, sizeof(dht_settings_map)/sizeof(dht_settings_map[0]));
|
|
|
|
}
|
2010-03-10 03:28:40 +01:00
|
|
|
#endif
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
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
|
|
|
|
2009-12-03 06:11:57 +01:00
|
|
|
#if TORRENT_USE_I2P
|
2010-03-06 08:49:40 +01:00
|
|
|
if (flags & session::save_i2p_proxy)
|
|
|
|
{
|
|
|
|
save_struct(e["i2p"], &i2p_proxy(), proxy_settings_map
|
|
|
|
, sizeof(proxy_settings_map)/sizeof(proxy_settings_map[0]));
|
|
|
|
}
|
2009-12-03 06:11:57 +01:00
|
|
|
#endif
|
2010-03-04 17:42:39 +01:00
|
|
|
#ifndef TORRENT_DISABLE_GEO_IP
|
2010-03-06 08:49:40 +01:00
|
|
|
if (flags & session::save_as_map)
|
2010-03-04 17:42:39 +01:00
|
|
|
{
|
2010-03-06 08:49:40 +01:00
|
|
|
entry::dictionary_type& as_map = e["AS map"].dict();
|
|
|
|
char buf[10];
|
|
|
|
for (std::map<int, int>::const_iterator i = m_as_peak.begin()
|
|
|
|
, end(m_as_peak.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if (i->second == 0) continue;
|
|
|
|
sprintf(buf, "%05d", i->first);
|
|
|
|
as_map[buf] = i->second;
|
|
|
|
}
|
2010-03-04 17:42:39 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-12-03 06:11:57 +01: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
|
|
|
{
|
|
|
|
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
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
set_upload_rate_limit(e->dict_find_int_value("upload_rate_limit", 0));
|
|
|
|
set_download_rate_limit(e->dict_find_int_value("download_rate_limit", 0));
|
|
|
|
set_local_upload_rate_limit(e->dict_find_int_value("local_upload_rate_limit", 0));
|
|
|
|
set_local_download_rate_limit(e->dict_find_int_value("local_download_rate_limit", 0));
|
|
|
|
set_max_uploads(e->dict_find_int_value("max_uploads", 0));
|
|
|
|
set_max_half_open_connections(e->dict_find_int_value("max_half_open_connections", 0));
|
|
|
|
set_max_connections(e->dict_find_int_value("max_connections", 0));
|
2010-03-08 04:51:07 +01:00
|
|
|
|
2010-03-10 03:28:40 +01:00
|
|
|
for (int i = 0; i < sizeof(all_settings)/sizeof(all_settings[0]); ++i)
|
2009-12-03 06:11:57 +01:00
|
|
|
{
|
2010-03-10 03:28:40 +01:00
|
|
|
session_category const& c = all_settings[i];
|
2010-07-14 06:16:38 +02:00
|
|
|
settings = e->dict_find_dict(c.name);
|
2010-03-10 08:14:10 +01:00
|
|
|
if (!settings) continue;
|
|
|
|
load_struct(*settings, reinterpret_cast<char*>(this) + c.offset, c.map, c.num_entries);
|
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");
|
2009-12-03 06:11:57 +01:00
|
|
|
if (settings)
|
|
|
|
{
|
|
|
|
dht_settings s;
|
|
|
|
load_struct(*settings, &s, dht_settings_map
|
|
|
|
, sizeof(dht_settings_map)/sizeof(dht_settings_map[0]));
|
|
|
|
set_dht_settings(s);
|
|
|
|
}
|
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
|
|
|
|
|
|
|
|
#if TORRENT_USE_I2P
|
2010-07-14 06:16:38 +02:00
|
|
|
settings = e->dict_find_dict("i2p");
|
2009-12-03 06:11:57 +01:00
|
|
|
if (settings)
|
|
|
|
{
|
|
|
|
proxy_settings s;
|
|
|
|
load_struct(*settings, &s, proxy_settings_map
|
|
|
|
, sizeof(proxy_settings_map)/sizeof(proxy_settings_map[0]));
|
|
|
|
set_i2p_proxy(s);
|
|
|
|
}
|
|
|
|
#endif
|
2010-03-04 17:42:39 +01:00
|
|
|
#ifndef TORRENT_DISABLE_GEO_IP
|
2010-07-14 06:16:38 +02:00
|
|
|
settings = e->dict_find_dict("AS map");
|
2010-03-04 17:42:39 +01:00
|
|
|
if (settings)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < settings->dict_size(); ++i)
|
|
|
|
{
|
|
|
|
std::pair<std::string, lazy_entry const*> item = settings->dict_at(i);
|
2010-03-04 23:34:49 +01:00
|
|
|
int as_num = atoi(item.first.c_str());
|
|
|
|
if (item.second->type() != lazy_entry::int_t || item.second->int_value() == 0) continue;
|
2010-03-04 17:42:39 +01:00
|
|
|
int& peak = m_as_peak[as_num];
|
2010-03-04 23:34:49 +01:00
|
|
|
if (peak < item.second->int_value()) peak = item.second->int_value();
|
2010-03-04 17:42:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2010-03-26 18:45:16 +01:00
|
|
|
|
|
|
|
if (m_settings.connection_speed < 0) m_settings.connection_speed = 200;
|
|
|
|
|
|
|
|
if (m_settings.broadcast_lsd && m_lsd)
|
|
|
|
m_lsd->use_broadcast(true);
|
|
|
|
|
2010-03-10 08:14:10 +01:00
|
|
|
update_disk_thread_settings();
|
2009-12-03 06:11:57 +01:00
|
|
|
}
|
|
|
|
|
2008-04-05 06:53:22 +02:00
|
|
|
#ifndef TORRENT_DISABLE_GEO_IP
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
struct free_ptr
|
|
|
|
{
|
|
|
|
void* ptr_;
|
|
|
|
free_ptr(void* p): ptr_(p) {}
|
|
|
|
~free_ptr() { free(ptr_); }
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2008-04-11 10:46:43 +02:00
|
|
|
char const* session_impl::country_for_ip(address const& a)
|
|
|
|
{
|
|
|
|
if (!a.is_v4() || m_country_db == 0) return 0;
|
|
|
|
return GeoIP_country_code_by_ipnum(m_country_db, a.to_v4().to_ulong());
|
|
|
|
}
|
|
|
|
|
2008-04-05 06:53:22 +02:00
|
|
|
int session_impl::as_for_ip(address const& a)
|
|
|
|
{
|
2008-04-11 10:46:43 +02:00
|
|
|
if (!a.is_v4() || m_asnum_db == 0) return 0;
|
|
|
|
char* name = GeoIP_name_by_ipnum(m_asnum_db, a.to_v4().to_ulong());
|
2008-04-05 06:53:22 +02:00
|
|
|
if (name == 0) return 0;
|
|
|
|
free_ptr p(name);
|
|
|
|
// GeoIP returns the name as AS??? where ? is the AS-number
|
|
|
|
return atoi(name + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string session_impl::as_name_for_ip(address const& a)
|
|
|
|
{
|
2008-04-11 10:46:43 +02:00
|
|
|
if (!a.is_v4() || m_asnum_db == 0) return std::string();
|
|
|
|
char* name = GeoIP_name_by_ipnum(m_asnum_db, a.to_v4().to_ulong());
|
2008-04-05 06:53:22 +02:00
|
|
|
if (name == 0) return std::string();
|
|
|
|
free_ptr p(name);
|
|
|
|
char* tmp = std::strchr(name, ' ');
|
|
|
|
if (tmp == 0) return std::string();
|
|
|
|
return tmp + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<const int, int>* session_impl::lookup_as(int as)
|
|
|
|
{
|
|
|
|
std::map<int, int>::iterator i = m_as_peak.lower_bound(as);
|
|
|
|
|
|
|
|
if (i == m_as_peak.end() || i->first != as)
|
|
|
|
{
|
|
|
|
// we don't have any data for this AS, insert a new entry
|
|
|
|
i = m_as_peak.insert(i, std::pair<int, int>(as, 0));
|
|
|
|
}
|
|
|
|
return &(*i);
|
|
|
|
}
|
|
|
|
|
2010-07-14 09:38:35 +02:00
|
|
|
void session_impl::load_asnum_db(std::string file)
|
2008-04-05 06:53:22 +02:00
|
|
|
{
|
2008-04-11 10:46:43 +02:00
|
|
|
if (m_asnum_db) GeoIP_delete(m_asnum_db);
|
2010-07-14 09:38:35 +02:00
|
|
|
m_asnum_db = GeoIP_open(file.c_str(), GEOIP_STANDARD);
|
|
|
|
// return m_asnum_db;
|
2008-04-11 10:46:43 +02:00
|
|
|
}
|
|
|
|
|
2009-10-29 19:12:43 +01:00
|
|
|
#if TORRENT_USE_WSTRING
|
2010-07-14 09:38:35 +02:00
|
|
|
void session_impl::load_asnum_dbw(std::wstring file)
|
2008-12-21 09:48:06 +01:00
|
|
|
{
|
|
|
|
if (m_asnum_db) GeoIP_delete(m_asnum_db);
|
|
|
|
std::string utf8;
|
|
|
|
wchar_utf8(file, utf8);
|
2008-12-21 20:15:53 +01:00
|
|
|
m_asnum_db = GeoIP_open(utf8.c_str(), GEOIP_STANDARD);
|
2010-07-14 09:38:35 +02:00
|
|
|
// return m_asnum_db;
|
2008-12-21 09:48:06 +01:00
|
|
|
}
|
|
|
|
|
2010-07-14 09:38:35 +02:00
|
|
|
void session_impl::load_country_dbw(std::wstring file)
|
2008-04-11 10:46:43 +02:00
|
|
|
{
|
|
|
|
if (m_country_db) GeoIP_delete(m_country_db);
|
2009-04-04 10:32:23 +02:00
|
|
|
std::string utf8;
|
|
|
|
wchar_utf8(file, utf8);
|
|
|
|
m_country_db = GeoIP_open(utf8.c_str(), GEOIP_STANDARD);
|
2010-07-14 09:38:35 +02:00
|
|
|
// return m_country_db;
|
2008-04-05 06:53:22 +02:00
|
|
|
}
|
2009-10-29 19:12:43 +01:00
|
|
|
#endif // TORRENT_USE_WSTRING
|
2008-04-05 06:53:22 +02:00
|
|
|
|
2010-07-14 09:38:35 +02:00
|
|
|
void session_impl::load_country_db(std::string file)
|
2008-12-21 09:48:06 +01:00
|
|
|
{
|
|
|
|
if (m_country_db) GeoIP_delete(m_country_db);
|
2010-07-14 09:38:35 +02:00
|
|
|
m_country_db = GeoIP_open(file.c_str(), GEOIP_STANDARD);
|
|
|
|
// return m_country_db;
|
2008-12-21 09:48:06 +01:00
|
|
|
}
|
|
|
|
|
2009-10-29 19:12:43 +01:00
|
|
|
#endif // TORRENT_DISABLE_GEO_IP
|
2008-04-05 06:53:22 +02:00
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
void session_impl::add_extension(
|
2007-09-14 02:11:33 +02:00
|
|
|
boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> ext)
|
2006-11-14 01:08:16 +01:00
|
|
|
{
|
2008-09-22 01:19:58 +02:00
|
|
|
TORRENT_ASSERT(ext);
|
|
|
|
|
|
|
|
typedef boost::shared_ptr<torrent_plugin>(*function_t)(torrent*, void*);
|
|
|
|
function_t const* f = ext.target<function_t>();
|
|
|
|
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
for (extension_list_t::iterator i = m_extensions.begin(); i != m_extensions.end(); ++i)
|
|
|
|
if (function_equal(*i, *f)) return;
|
|
|
|
}
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
m_extensions.push_back(ext);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-04-18 01:06:00 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2006-10-11 22:57:54 +02:00
|
|
|
void session_impl::add_dht_node(udp::endpoint n)
|
|
|
|
{
|
|
|
|
if (m_dht) m_dht->add_node(n);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-06-29 21:08:30 +02:00
|
|
|
void session_impl::pause()
|
|
|
|
{
|
|
|
|
if (m_paused) return;
|
2008-12-30 09:20:25 +01:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
|
|
|
|
(*m_logger) << time_now_string() << " *** session paused ***\n";
|
|
|
|
#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;
|
|
|
|
if (!t.is_torrent_paused()) t.do_pause();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::resume()
|
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
void session_impl::abort()
|
|
|
|
{
|
2007-10-07 20:06:56 +02:00
|
|
|
if (m_abort) return;
|
2008-12-30 09:20:25 +01:00
|
|
|
#if defined TORRENT_LOGGING
|
2007-10-07 20:06:56 +02:00
|
|
|
(*m_logger) << time_now_string() << " *** ABORT CALLED ***\n";
|
|
|
|
#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
|
2008-06-24 14:17:42 +02:00
|
|
|
m_queued_for_checking.clear();
|
2007-10-07 20:06:56 +02:00
|
|
|
if (m_lsd) m_lsd->close();
|
|
|
|
if (m_upnp) m_upnp->close();
|
|
|
|
if (m_natpmp) m_natpmp->close();
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (m_dht) m_dht->stop();
|
2010-02-14 02:39:55 +01:00
|
|
|
m_dht_announce_timer.cancel(ec);
|
2007-10-07 20:06:56 +02:00
|
|
|
#endif
|
2008-04-07 03:22:26 +02:00
|
|
|
m_timer.cancel(ec);
|
2010-02-05 09:23:17 +01:00
|
|
|
m_lsd_announce_timer.cancel(ec);
|
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);
|
2007-10-26 09:14:19 +02:00
|
|
|
}
|
|
|
|
|
2007-10-29 01:29:43 +01:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2008-01-27 23:39:50 +01:00
|
|
|
(*m_logger) << time_now_string() << " aborting all torrents (" << m_torrents.size() << ")\n";
|
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();
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2007-10-29 01:29:43 +01:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2007-11-02 01:27:53 +01:00
|
|
|
(*m_logger) << time_now_string() << " aborting all tracker requests\n";
|
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)
|
|
|
|
(*m_logger) << time_now_string() << " sending event=stopped to trackers\n";
|
|
|
|
#endif
|
|
|
|
for (torrent_map::iterator i = m_torrents.begin();
|
|
|
|
i != m_torrents.end(); ++i)
|
2007-10-29 01:29:43 +01:00
|
|
|
{
|
2007-11-02 01:27:53 +01:00
|
|
|
torrent& t = *i->second;
|
2008-07-12 10:25:19 +02:00
|
|
|
t.abort();
|
2007-10-29 01:29:43 +01:00
|
|
|
}
|
2008-07-12 10:25:19 +02:00
|
|
|
|
2007-11-02 01:27:53 +01:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_logger) << time_now_string() << " aborting all connections (" << m_connections.size() << ")\n";
|
|
|
|
#endif
|
2009-05-23 23:36:09 +02:00
|
|
|
// closing all the connections needs to be done from a callback,
|
|
|
|
// when the session mutex is not held
|
|
|
|
m_io_service.post(boost::bind(&connection_queue::close, &m_half_open));
|
2008-10-30 18:13:10 +01:00
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2008-11-01 06:35:41 +01:00
|
|
|
(*m_logger) << time_now_string() << " connection queue: " << m_half_open.size() << "\n";
|
2008-10-30 18:13:10 +01:00
|
|
|
#endif
|
|
|
|
|
2007-11-02 01:27:53 +01:00
|
|
|
// abort all connections
|
|
|
|
while (!m_connections.empty())
|
|
|
|
{
|
2008-11-29 22:33:21 +01:00
|
|
|
#ifdef TORRENT_DEBUG
|
2007-11-02 01:27:53 +01:00
|
|
|
int conn = m_connections.size();
|
|
|
|
#endif
|
2009-11-29 08:06:38 +01:00
|
|
|
(*m_connections.begin())->disconnect(errors::stopping_torrent);
|
2007-11-07 02:38:17 +01:00
|
|
|
TORRENT_ASSERT(conn == int(m_connections.size()) + 1);
|
2007-11-02 01:27:53 +01:00
|
|
|
}
|
2007-10-26 09:14:19 +02:00
|
|
|
|
2008-10-30 18:13:10 +01:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2008-11-01 06:35:41 +01:00
|
|
|
(*m_logger) << time_now_string() << " connection queue: " << m_half_open.size() << "\n";
|
2008-10-30 18:13:10 +01:00
|
|
|
#endif
|
|
|
|
|
2007-10-26 09:14:19 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_logger) << time_now_string() << " shutting down connection queue\n";
|
|
|
|
#endif
|
2007-10-08 01:20:38 +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
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_GEO_IP
|
|
|
|
if (m_asnum_db) GeoIP_delete(m_asnum_db);
|
|
|
|
if (m_country_db) GeoIP_delete(m_country_db);
|
|
|
|
m_asnum_db = 0;
|
|
|
|
m_country_db = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
m_disk_thread.abort();
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2007-06-01 03:05:57 +02:00
|
|
|
void session_impl::set_port_filter(port_filter const& f)
|
|
|
|
{
|
|
|
|
m_port_filter = f;
|
2009-06-18 18:16:41 +02:00
|
|
|
// TODO: recalculate all connect candidates for all torrents
|
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)
|
|
|
|
i->second->ip_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
|
|
|
}
|
|
|
|
|
2010-03-10 08:14:10 +01:00
|
|
|
void session_impl::update_disk_thread_settings()
|
|
|
|
{
|
|
|
|
disk_io_job j;
|
|
|
|
j.buffer = (char*)&m_settings;
|
|
|
|
j.action = disk_io_job::update_settings;
|
|
|
|
m_disk_thread.add_job(j);
|
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
void session_impl::set_settings(session_settings const& s)
|
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(s.file_pool_size > 0);
|
2007-06-08 00:37:58 +02:00
|
|
|
|
|
|
|
// less than 5 seconds unchoke interval is insane
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(s.unchoke_interval >= 5);
|
2009-01-10 06:46:02 +01:00
|
|
|
|
|
|
|
// if disk io thread settings were changed
|
|
|
|
// post a notification to that thread
|
|
|
|
bool update_disk_io_thread = false;
|
|
|
|
if (m_settings.cache_size != s.cache_size
|
|
|
|
|| m_settings.cache_expiry != s.cache_expiry
|
2009-05-19 08:51:30 +02:00
|
|
|
|| m_settings.optimize_hashing_for_speed != s.optimize_hashing_for_speed
|
2009-05-22 08:32:39 +02:00
|
|
|
|| m_settings.file_checks_delay_per_block != s.file_checks_delay_per_block
|
2009-05-23 09:35:45 +02:00
|
|
|
|| m_settings.disk_cache_algorithm != s.disk_cache_algorithm
|
2009-05-23 21:27:27 +02:00
|
|
|
|| m_settings.read_cache_line_size != s.read_cache_line_size
|
2009-05-24 02:12:53 +02:00
|
|
|
|| m_settings.write_cache_line_size != s.write_cache_line_size
|
2009-05-25 09:46:31 +02:00
|
|
|
|| m_settings.coalesce_writes != s.coalesce_writes
|
|
|
|
|| m_settings.coalesce_reads != s.coalesce_reads
|
2009-06-10 10:30:55 +02:00
|
|
|
|| m_settings.max_queued_disk_bytes != s.max_queued_disk_bytes
|
2009-08-02 08:40:45 +02:00
|
|
|
|| m_settings.disable_hash_checks != s.disable_hash_checks
|
2010-01-15 17:45:42 +01:00
|
|
|
|| m_settings.explicit_read_cache != s.explicit_read_cache
|
2009-02-06 10:46:13 +01:00
|
|
|
#ifndef TORRENT_DISABLE_MLOCK
|
|
|
|
|| m_settings.lock_disk_cache != s.lock_disk_cache
|
|
|
|
#endif
|
2010-01-23 04:02:32 +01:00
|
|
|
|| m_settings.use_read_cache != s.use_read_cache
|
|
|
|
|| m_settings.allow_reordered_disk_operations != s.allow_reordered_disk_operations
|
|
|
|
|| m_settings.file_pool_size != s.file_pool_size
|
2010-01-30 04:50:17 +01:00
|
|
|
|| m_settings.volatile_read_cache != s.volatile_read_cache
|
2010-02-02 20:44:52 +01:00
|
|
|
|| m_settings.no_atime_storage!= s.no_atime_storage
|
2010-06-25 16:06:28 +02:00
|
|
|
|| m_settings.ignore_resume_timestamps != s.ignore_resume_timestamps
|
2010-01-23 04:02:32 +01:00
|
|
|
|| m_settings.low_prio_disk != s.low_prio_disk)
|
2009-01-10 06:46:02 +01:00
|
|
|
update_disk_io_thread = true;
|
|
|
|
|
2010-02-09 04:04:41 +01:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
|
|
|
// support deprecated choker settings
|
|
|
|
if (s.choking_algorithm == session_settings::rate_based_choker)
|
|
|
|
{
|
|
|
|
if (s.auto_upload_slots && !s.auto_upload_slots_rate_based)
|
|
|
|
m_settings.choking_algorithm = session_settings::auto_expand_choker;
|
|
|
|
else if (!s.auto_upload_slots)
|
|
|
|
m_settings.choking_algorithm = session_settings::fixed_slots_choker;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-01-31 20:16:22 +01:00
|
|
|
// safety check
|
2010-01-31 17:35:38 +01:00
|
|
|
if (m_settings.volatile_read_cache
|
2010-01-31 20:16:22 +01:00
|
|
|
&& (m_settings.suggest_mode == session_settings::suggest_read_cache
|
|
|
|
|| m_settings.explicit_read_cache))
|
2010-01-31 17:35:38 +01:00
|
|
|
{
|
|
|
|
// If you hit this assert, you're trying to set your cache to be
|
2010-01-31 20:16:22 +01:00
|
|
|
// volatile and to suggest pieces out of it (or to make the cache
|
|
|
|
// explicit) at the same time this is a bad configuration, don't do it
|
2010-01-31 17:35:38 +01:00
|
|
|
TORRENT_ASSERT(false);
|
|
|
|
m_settings.volatile_read_cache = false;
|
|
|
|
}
|
|
|
|
|
2010-02-09 04:04:41 +01:00
|
|
|
if (m_settings.choking_algorithm != s.choking_algorithm)
|
|
|
|
{
|
|
|
|
// trigger recalculation of the unchoked peers
|
|
|
|
m_unchoke_time_scaler = 0;
|
|
|
|
}
|
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (m_settings.dht_announce_interval != s.dht_announce_interval)
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
int delay = (std::max)(s.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(
|
2010-04-30 21:08:16 +02:00
|
|
|
boost::bind(&session_impl::on_dht_announce, this, _1));
|
2010-02-14 02:39:55 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-02-13 17:29:17 +01:00
|
|
|
if (m_settings.local_service_announce_interval != s.local_service_announce_interval)
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
int delay = (std::max)(s.local_service_announce_interval
|
|
|
|
/ (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-02-13 17:29:17 +01:00
|
|
|
}
|
|
|
|
|
2008-06-12 08:58:42 +02:00
|
|
|
// if queuing settings were changed, recalculate
|
|
|
|
// queued torrents sooner
|
|
|
|
if ((m_settings.active_downloads != s.active_downloads
|
2008-06-23 00:49:18 +02:00
|
|
|
|| m_settings.active_seeds != s.active_seeds
|
|
|
|
|| m_settings.active_limit != s.active_limit)
|
2008-06-12 08:58:42 +02:00
|
|
|
&& m_auto_manage_time_scaler > 2)
|
|
|
|
m_auto_manage_time_scaler = 2;
|
2010-04-13 06:30:34 +02:00
|
|
|
|
|
|
|
// if anonymous mode was enabled, clear out the peer ID
|
|
|
|
bool anonymous = (m_settings.anonymous_mode != s.anonymous_mode && s.anonymous_mode);
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
m_settings = s;
|
2010-04-13 06:30:34 +02:00
|
|
|
|
|
|
|
// enable anonymous mode. We don't want to accept any incoming
|
|
|
|
// connections, except through a proxy.
|
|
|
|
if (anonymous)
|
|
|
|
{
|
|
|
|
m_settings.user_agent.clear();
|
|
|
|
url_random((char*)&m_peer_id[0], (char*)&m_peer_id[0] + 20);
|
|
|
|
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();
|
|
|
|
}
|
2010-02-06 22:40:55 +01:00
|
|
|
if (m_settings.connection_speed < 0) m_settings.connection_speed = 200;
|
2010-03-26 18:45:16 +01:00
|
|
|
if (m_settings.broadcast_lsd && m_lsd)
|
|
|
|
m_lsd->use_broadcast(true);
|
2008-02-11 04:55:53 +01:00
|
|
|
|
2009-01-10 06:46:02 +01:00
|
|
|
if (update_disk_io_thread)
|
2010-03-10 08:14:10 +01:00
|
|
|
update_disk_thread_settings();
|
2009-01-10 06:46:02 +01:00
|
|
|
|
2010-02-06 08:39:45 +01:00
|
|
|
if (m_allowed_upload_slots <= m_settings.num_optimistic_unchoke_slots / 2)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<performance_alert>())
|
|
|
|
m_alerts.post_alert(performance_alert(torrent_handle()
|
|
|
|
, performance_alert::too_many_optimistic_unchoke_slots));
|
|
|
|
}
|
|
|
|
|
2010-02-09 04:04:41 +01:00
|
|
|
if (s.choking_algorithm == session_settings::fixed_slots_choker)
|
|
|
|
m_allowed_upload_slots = m_max_uploads;
|
|
|
|
else if (s.choking_algorithm == session_settings::auto_expand_choker
|
|
|
|
&& m_allowed_upload_slots < m_max_uploads)
|
|
|
|
m_allowed_upload_slots = m_max_uploads;
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
// replace all occurances of '\n' with ' '.
|
|
|
|
std::string::iterator i = m_settings.user_agent.begin();
|
|
|
|
while ((i = std::find(i, m_settings.user_agent.end(), '\n'))
|
|
|
|
!= m_settings.user_agent.end())
|
|
|
|
*i = ' ';
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-11-23 23:14:33 +01:00
|
|
|
session_impl::listen_socket_t session_impl::setup_listener(tcp::endpoint ep
|
2010-06-17 19:14:56 +02:00
|
|
|
, int retries, bool v6_only, bool reuse_address)
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
2008-05-03 18:05:42 +02:00
|
|
|
error_code ec;
|
2007-09-22 18:27:29 +02:00
|
|
|
listen_socket_t s;
|
|
|
|
s.sock.reset(new socket_acceptor(m_io_service));
|
|
|
|
s.sock->open(ep.protocol(), ec);
|
2010-06-17 19:14:56 +02:00
|
|
|
if (reuse_address)
|
|
|
|
s.sock->set_option(socket_acceptor::reuse_address(true), ec);
|
2009-04-04 18:59:53 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
2009-01-21 02:39:13 +01:00
|
|
|
if (ep.protocol() == tcp::v6())
|
|
|
|
{
|
|
|
|
s.sock->set_option(v6only(v6_only), ec);
|
|
|
|
#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
|
|
|
|
s.sock->set_option(v6_protection_level(PROTECTION_LEVEL_UNRESTRICTED), ec);
|
|
|
|
#endif
|
|
|
|
}
|
2009-04-04 18:59:53 +02:00
|
|
|
#endif
|
2007-09-22 18:27:29 +02:00
|
|
|
s.sock->bind(ep, ec);
|
|
|
|
while (ec && retries > 0)
|
|
|
|
{
|
2008-05-03 18:05:42 +02:00
|
|
|
ec = error_code();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!ec);
|
2007-09-22 18:27:29 +02:00
|
|
|
--retries;
|
|
|
|
ep.port(ep.port() + 1);
|
|
|
|
s.sock->bind(ep, ec);
|
|
|
|
}
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
// instead of giving up, try
|
|
|
|
// let the OS pick a port
|
|
|
|
ep.port(0);
|
2008-05-03 18:05:42 +02:00
|
|
|
ec = error_code();
|
2007-09-22 18:27:29 +02:00
|
|
|
s.sock->bind(ep, ec);
|
|
|
|
}
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
// not even that worked, give up
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
m_alerts.post_alert(listen_failed_alert(ep, ec));
|
2010-05-30 03:33:03 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2009-04-04 11:52:25 +02:00
|
|
|
char msg[200];
|
|
|
|
snprintf(msg, 200, "cannot bind to interface \"%s\": %s"
|
|
|
|
, print_endpoint(ep).c_str(), ec.message().c_str());
|
|
|
|
(*m_logger) << msg << "\n";
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2007-09-22 18:27:29 +02:00
|
|
|
return listen_socket_t();
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2007-09-22 18:27:29 +02:00
|
|
|
s.external_port = s.sock->local_endpoint(ec).port();
|
2008-08-25 23:17:24 +02:00
|
|
|
s.sock->listen(5, ec);
|
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>())
|
|
|
|
m_alerts.post_alert(listen_failed_alert(ep, ec));
|
2010-05-30 03:33:03 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
2009-04-04 11:52:25 +02:00
|
|
|
char msg[200];
|
|
|
|
snprintf(msg, 200, "cannot listen on interface \"%s\": %s"
|
|
|
|
, print_endpoint(ep).c_str(), ec.message().c_str());
|
|
|
|
(*m_logger) << msg << "\n";
|
2007-09-22 18:27:29 +02:00
|
|
|
#endif
|
|
|
|
return listen_socket_t();
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<listen_succeeded_alert>())
|
|
|
|
m_alerts.post_alert(listen_succeeded_alert(ep));
|
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
|
2007-09-24 00:50:25 +02:00
|
|
|
(*m_logger) << "listening on: " << ep
|
2007-09-22 18:27:29 +02:00
|
|
|
<< " external port: " << s.external_port << "\n";
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2007-09-22 18:27:29 +02:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2010-06-17 19:14:56 +02:00
|
|
|
void session_impl::open_listen_port(bool reuse_address)
|
2007-09-22 18:27:29 +02:00
|
|
|
{
|
|
|
|
// close the open listen sockets
|
|
|
|
m_listen_sockets.clear();
|
|
|
|
m_incoming_connection = false;
|
|
|
|
|
2009-04-12 02:37:06 +02:00
|
|
|
m_ipv6_interface = tcp::endpoint();
|
|
|
|
m_ipv4_interface = tcp::endpoint();
|
|
|
|
|
2007-09-22 18:27:29 +02:00
|
|
|
if (is_any(m_listen_interface.address()))
|
|
|
|
{
|
|
|
|
// this means we should open two listen sockets
|
|
|
|
// one for IPv4 and one for IPv6
|
|
|
|
|
|
|
|
listen_socket_t s = setup_listener(
|
|
|
|
tcp::endpoint(address_v4::any(), m_listen_interface.port())
|
2010-06-17 19:14:56 +02:00
|
|
|
, m_listen_port_retries, false, reuse_address);
|
2007-09-22 18:27:29 +02:00
|
|
|
|
|
|
|
if (s.sock)
|
|
|
|
{
|
2010-05-30 03:33:03 +02:00
|
|
|
// if we're configured to listen on port 0 (i.e. let the
|
|
|
|
// OS decide), update the listen_interface member with the
|
|
|
|
// actual port we ended up listening on, so that the other
|
|
|
|
// sockets can be bound to the same one
|
|
|
|
if (m_listen_interface.port() == 0)
|
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
m_listen_interface.port(s.sock->local_endpoint(ec).port());
|
|
|
|
}
|
|
|
|
|
2007-09-22 18:27:29 +02:00
|
|
|
m_listen_sockets.push_back(s);
|
|
|
|
async_accept(s.sock);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2009-04-13 07:11:44 +02:00
|
|
|
s = setup_listener(
|
|
|
|
tcp::endpoint(address_v6::any(), m_listen_interface.port())
|
2010-06-17 19:14:56 +02:00
|
|
|
, m_listen_port_retries, true, reuse_address);
|
2009-04-13 07:11:44 +02:00
|
|
|
|
|
|
|
if (s.sock)
|
|
|
|
{
|
|
|
|
m_listen_sockets.push_back(s);
|
|
|
|
async_accept(s.sock);
|
|
|
|
}
|
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
|
|
|
|
error_code ec;
|
|
|
|
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
|
|
|
|
{
|
|
|
|
// we should only open a single listen socket, that
|
|
|
|
// binds to the given interface
|
|
|
|
|
|
|
|
listen_socket_t s = setup_listener(
|
2010-06-17 19:14:56 +02:00
|
|
|
m_listen_interface, m_listen_port_retries, false, reuse_address);
|
2007-09-22 18:27:29 +02:00
|
|
|
|
|
|
|
if (s.sock)
|
|
|
|
{
|
|
|
|
m_listen_sockets.push_back(s);
|
|
|
|
async_accept(s.sock);
|
2009-04-12 02:37:06 +02:00
|
|
|
|
|
|
|
if (m_listen_interface.address().is_v6())
|
|
|
|
m_ipv6_interface = m_listen_interface;
|
|
|
|
else
|
|
|
|
m_ipv4_interface = m_listen_interface;
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
2010-05-30 03:33:03 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
error_code ec;
|
|
|
|
m_udp_socket.bind(udp::endpoint(m_listen_interface.address(), m_listen_interface.port()), ec);
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
m_alerts.post_alert(listen_failed_alert(m_listen_interface, ec));
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
char msg[200];
|
|
|
|
snprintf(msg, sizeof(msg), "cannot bind to UDP interface \"%s\": %s"
|
|
|
|
, print_endpoint(m_listen_interface).c_str(), ec.message().c_str());
|
|
|
|
(*m_logger) << msg << "\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
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());
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
open_new_incoming_socks_connection();
|
2009-08-20 05:19:12 +02:00
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
open_new_incoming_i2p_connection();
|
|
|
|
#endif
|
2009-04-09 03:04:49 +02:00
|
|
|
|
2007-09-22 18:27:29 +02:00
|
|
|
if (!m_listen_sockets.empty())
|
|
|
|
{
|
2008-05-03 18:05:42 +02:00
|
|
|
error_code ec;
|
2007-09-22 18:27:29 +02:00
|
|
|
tcp::endpoint local = m_listen_sockets.front().sock->local_endpoint(ec);
|
|
|
|
if (!ec)
|
|
|
|
{
|
2008-04-06 21:17:58 +02:00
|
|
|
if (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
|
|
|
|
, local.port(), local.port());
|
|
|
|
}
|
|
|
|
if (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
|
|
|
|
, local.port(), local.port());
|
|
|
|
}
|
2007-09-22 18:27:29 +02:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
void session_impl::open_new_incoming_socks_connection()
|
|
|
|
{
|
|
|
|
if (m_peer_proxy.type != proxy_settings::socks5
|
|
|
|
&& m_peer_proxy.type != proxy_settings::socks5_pw
|
|
|
|
&& m_peer_proxy.type != proxy_settings::socks4)
|
|
|
|
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));
|
2009-04-09 03:04:49 +02:00
|
|
|
bool ret = instantiate_connection(m_io_service, m_peer_proxy
|
|
|
|
, *m_socks_listen_socket);
|
|
|
|
TORRENT_ASSERT(ret);
|
|
|
|
|
|
|
|
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();
|
|
|
|
if (m_socks_listen_port == 0) m_socks_listen_port = 2000 + rand() % 60000;
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2009-08-20 05:19:12 +02:00
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
void session_impl::on_i2p_open(error_code const& ec)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
TORRENT_ASSERT(ret);
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
m_i2p_listen_socket.reset();
|
|
|
|
if (e == asio::error::operation_aborted) return;
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
m_alerts.post_alert(listen_failed_alert(tcp::endpoint(
|
|
|
|
address_v4::any(), m_listen_interface.port()), e));
|
2010-05-30 03:33:03 +02:00
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
char msg[200];
|
|
|
|
snprintf(msg, sizeof(msg), "cannot bind to port %d: %s"
|
|
|
|
, m_listen_interface.port(), e.message().c_str());
|
|
|
|
(*m_logger) << msg << "\n";
|
|
|
|
#endif
|
2009-08-20 05:19:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
open_new_incoming_i2p_connection();
|
|
|
|
incoming_connection(s);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-01-18 03:02:18 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
void session_impl::on_receive_udp(error_code const& e
|
2008-03-25 05:38:59 +01:00
|
|
|
, udp::endpoint const& ep, char const* buf, int len)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
2008-03-25 05:38:59 +01:00
|
|
|
if (e)
|
|
|
|
{
|
2008-05-08 02:22:17 +02:00
|
|
|
if (e == asio::error::connection_refused
|
|
|
|
|| e == asio::error::connection_reset
|
|
|
|
|| e == asio::error::connection_aborted)
|
2010-05-30 03:33:03 +02:00
|
|
|
{
|
2010-06-26 19:09:37 +02:00
|
|
|
if (m_dht) m_dht->on_unreachable(ep);
|
2010-05-30 03:33:03 +02:00
|
|
|
if (m_tracker_manager.incoming_udp(e, ep, buf, len))
|
|
|
|
m_stat.received_tracker_bytes(len + 28);
|
|
|
|
}
|
2008-05-08 02:22:17 +02:00
|
|
|
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<udp_error_alert>())
|
|
|
|
m_alerts.post_alert(udp_error_alert(ep, e));
|
2008-03-25 05:38:59 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-30 03:33:03 +02:00
|
|
|
if (len > 20 && *buf == 'd' && buf[len-1] == 'e' && m_dht)
|
2007-12-09 05:15:24 +01:00
|
|
|
{
|
|
|
|
// this is probably a dht message
|
|
|
|
m_dht->on_receive(ep, buf, len);
|
|
|
|
}
|
2010-05-30 03:33:03 +02:00
|
|
|
// maybe it's a udp tracker response
|
|
|
|
else if (m_tracker_manager.incoming_udp(e, ep, buf, len))
|
|
|
|
{
|
|
|
|
m_stat.received_tracker_bytes(len + 28);
|
|
|
|
}
|
2007-12-09 05:15:24 +01:00
|
|
|
}
|
2008-01-18 03:02:18 +01:00
|
|
|
|
|
|
|
#endif
|
2007-12-09 05:15:24 +01:00
|
|
|
|
2007-09-22 18:27:29 +02:00
|
|
|
void session_impl::async_accept(boost::shared_ptr<socket_acceptor> const& listener)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2008-01-27 23:39:50 +01:00
|
|
|
shared_ptr<socket_type> c(new socket_type(m_io_service));
|
2007-10-22 06:17:26 +02:00
|
|
|
c->instantiate<stream_socket>(m_io_service);
|
2008-10-18 09:12:04 +02:00
|
|
|
listener->async_accept(*c->get<stream_socket>()
|
2009-04-09 03:04:49 +02:00
|
|
|
, bind(&session_impl::on_accept_connection, this, c
|
2007-09-22 18:27:29 +02:00
|
|
|
, boost::weak_ptr<socket_acceptor>(listener), _1));
|
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
|
2008-05-03 18:05:42 +02:00
|
|
|
, weak_ptr<socket_acceptor> listen_socket, error_code const& e)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2010-07-14 06:16:38 +02:00
|
|
|
TORRENT_ASSERT(is_network_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)
|
|
|
|
std::string msg = "error accepting connection on '"
|
2009-08-25 20:13:46 +02:00
|
|
|
+ print_endpoint(ep) + "' " + e.message();
|
2006-10-11 22:57:54 +02:00
|
|
|
(*m_logger) << msg << "\n";
|
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)
|
|
|
|
{
|
|
|
|
async_accept(listener);
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
async_accept(listener);
|
|
|
|
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.
|
|
|
|
if (m_max_connections > 10)
|
|
|
|
--m_max_connections;
|
|
|
|
// try again, but still alert the user of the problem
|
|
|
|
async_accept(listener);
|
|
|
|
}
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
m_alerts.post_alert(listen_failed_alert(ep, e));
|
2006-10-11 22:57:54 +02:00
|
|
|
return;
|
|
|
|
}
|
2007-09-22 18:27:29 +02:00
|
|
|
async_accept(listener);
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2009-04-09 03:04:49 +02:00
|
|
|
incoming_connection(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::incoming_connection(boost::shared_ptr<socket_type> const& s)
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
(*m_logger) << endp << " <== INCOMING CONNECTION FAILED, could "
|
|
|
|
"not retrieve remote endpoint " << ec.message() << "\n";
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2007-12-19 22:36:54 +01:00
|
|
|
(*m_logger) << time_now_string() << " <== INCOMING CONNECTION " << endp << "\n";
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
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()))
|
|
|
|
m_incoming_connection = true;
|
|
|
|
|
2006-11-19 16:29:58 +01:00
|
|
|
if (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)
|
|
|
|
(*m_logger) << "filtered blocked ip\n";
|
|
|
|
#endif
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<peer_blocked_alert>())
|
2009-09-07 03:47:30 +02:00
|
|
|
m_alerts.post_alert(peer_blocked_alert(torrent_handle(), endp.address()));
|
2006-10-11 22:57:54 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-10-27 23:21:44 +02:00
|
|
|
// don't allow more connections than the max setting
|
2010-01-31 19:35:46 +01:00
|
|
|
bool reject = false;
|
|
|
|
if (m_settings.ignore_limits_on_local_network && is_local(endp.address()))
|
|
|
|
reject = max_connections() < INT_MAX / 12
|
|
|
|
&& num_connections() >= max_connections() * 12 / 10;
|
|
|
|
else
|
|
|
|
reject = num_connections() >= max_connections();
|
|
|
|
|
|
|
|
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()
|
|
|
|
, 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)
|
|
|
|
(*m_logger) << "number of connections limit exceeded (conns: "
|
|
|
|
<< num_connections() << ", limit: " << max_connections()
|
|
|
|
<< "), connection rejected\n";
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-09-04 00:27:52 +02:00
|
|
|
// check if we have any active torrents
|
|
|
|
// if we don't reject the connection
|
2008-05-12 12:10:39 +02:00
|
|
|
if (m_torrents.empty())
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_logger) << " There are no torrents, disconnect\n";
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2007-09-22 18:27:29 +02:00
|
|
|
|
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.
|
|
|
|
if (!m_settings.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)
|
2010-02-11 05:39:04 +01:00
|
|
|
(*m_logger) << " There are no _active_ torrents, disconnect\n";
|
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
|
|
|
|
2009-05-01 06:59:15 +02:00
|
|
|
setup_socket_buffers(*s);
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
boost::intrusive_ptr<peer_connection> c(
|
2008-05-12 12:10:39 +02:00
|
|
|
new bt_peer_connection(*this, s, endp, 0));
|
2008-11-29 22:33:21 +01:00
|
|
|
#ifdef TORRENT_DEBUG
|
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())
|
|
|
|
{
|
|
|
|
m_connections.insert(c);
|
|
|
|
c->start();
|
2010-03-03 02:31:31 +01:00
|
|
|
if (m_settings.default_peer_upload_rate)
|
|
|
|
c->set_upload_limit(m_settings.default_peer_upload_rate);
|
|
|
|
if (m_settings.default_peer_download_rate)
|
|
|
|
c->set_download_limit(m_settings.default_peer_download_rate);
|
2008-03-31 06:46:24 +02:00
|
|
|
}
|
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;
|
|
|
|
if (m_settings.send_socket_buffer_size)
|
|
|
|
{
|
2009-06-03 09:22:43 +02:00
|
|
|
stream_socket::send_buffer_size option(
|
2009-05-01 06:59:15 +02:00
|
|
|
m_settings.send_socket_buffer_size);
|
|
|
|
s.set_option(option, ec);
|
|
|
|
}
|
|
|
|
if (m_settings.recv_socket_buffer_size)
|
|
|
|
{
|
2009-06-03 09:22:43 +02:00
|
|
|
stream_socket::receive_buffer_size option(
|
2009-05-01 06:59:15 +02:00
|
|
|
m_settings.recv_socket_buffer_size);
|
|
|
|
s.set_option(option, ec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
m_socks_listen_socket.reset();
|
|
|
|
if (e == asio::error::operation_aborted) return;
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
if (m_alerts.should_post<listen_failed_alert>())
|
|
|
|
m_alerts.post_alert(listen_failed_alert(tcp::endpoint(
|
|
|
|
address_v4::any(), m_listen_interface.port()), e));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
open_new_incoming_socks_connection();
|
|
|
|
incoming_connection(s);
|
|
|
|
}
|
|
|
|
|
2008-01-07 02:10:46 +01:00
|
|
|
void session_impl::close_connection(peer_connection const* p
|
2009-06-12 18:40:38 +02:00
|
|
|
, error_code const& ec)
|
2006-10-11 22:57:54 +02: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)
|
2008-01-07 02:10:46 +01:00
|
|
|
(*m_logger) << time_now_string() << " CLOSING CONNECTION "
|
2009-06-12 18:40:38 +02:00
|
|
|
<< p->remote() << " : " << ec.message() << "\n";
|
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
|
|
|
|
2009-01-28 07:14:21 +01:00
|
|
|
if (!p->is_choked() && !p->ignore_unchoke_slots()) --m_num_unchoked;
|
2008-01-07 02:10:46 +01:00
|
|
|
// connection_map::iterator i = std::lower_bound(m_connections.begin(), m_connections.end()
|
|
|
|
// , p, bind(&boost::intrusive_ptr<peer_connection>::get, _1) < p);
|
|
|
|
// if (i->get() != p) i == m_connections.end();
|
|
|
|
connection_map::iterator i = std::find_if(m_connections.begin(), m_connections.end()
|
|
|
|
, bind(&boost::intrusive_ptr<peer_connection>::get, _1) == p);
|
|
|
|
if (i != m_connections.end()) m_connections.erase(i);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_peer_id(peer_id const& id)
|
|
|
|
{
|
|
|
|
m_peer_id = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_key(int key)
|
|
|
|
{
|
|
|
|
m_key = key;
|
|
|
|
}
|
|
|
|
|
2008-12-26 08:00:21 +01:00
|
|
|
void session_impl::unchoke_peer(peer_connection& c)
|
|
|
|
{
|
2009-01-28 07:14:21 +01:00
|
|
|
TORRENT_ASSERT(!c.ignore_unchoke_slots());
|
2008-12-26 08:00:21 +01:00
|
|
|
torrent* t = c.associated_torrent().lock().get();
|
|
|
|
TORRENT_ASSERT(t);
|
|
|
|
if (t->unchoke_peer(c))
|
|
|
|
++m_num_unchoked;
|
|
|
|
}
|
|
|
|
|
2009-07-23 06:38:52 +02:00
|
|
|
void session_impl::choke_peer(peer_connection& c)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(!c.ignore_unchoke_slots());
|
|
|
|
torrent* t = c.associated_torrent().lock().get();
|
|
|
|
TORRENT_ASSERT(t);
|
|
|
|
if (t->choke_peer(c))
|
|
|
|
--m_num_unchoked;
|
|
|
|
}
|
|
|
|
|
2008-02-28 08:34:07 +01:00
|
|
|
int session_impl::next_port()
|
|
|
|
{
|
|
|
|
std::pair<int, int> const& out_ports = m_settings.outgoing_ports;
|
|
|
|
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
|
|
|
|
(*m_logger) << time_now_string() << " *** BINDING OUTGOING CONNECTION [ "
|
|
|
|
"port: " << port << " ]\n";
|
|
|
|
#endif
|
|
|
|
return port;
|
|
|
|
}
|
|
|
|
|
2009-06-10 10:30:55 +02:00
|
|
|
// this function is called from the disk-io thread
|
|
|
|
// when the disk queue is low enough to post new
|
|
|
|
// write jobs to it. It will go through all peer
|
|
|
|
// connections that are blocked on the disk and
|
|
|
|
// wake them up
|
|
|
|
void session_impl::on_disk_queue()
|
|
|
|
{
|
2010-07-14 06:16:38 +02:00
|
|
|
TORRENT_ASSERT(is_network_thread());
|
|
|
|
|
2010-06-26 19:09:37 +02:00
|
|
|
for (connection_map::iterator i = m_connections.begin();
|
|
|
|
i != m_connections.end();)
|
2009-06-10 10:30:55 +02:00
|
|
|
{
|
2010-06-26 19:58:04 +02:00
|
|
|
boost::intrusive_ptr<peer_connection> p = *i;
|
2010-06-26 19:09:37 +02:00
|
|
|
++i;
|
|
|
|
if (p->m_channel_state[peer_connection::download_channel]
|
2009-06-10 10:30:55 +02:00
|
|
|
!= peer_info::bw_disk) continue;
|
|
|
|
|
2010-06-26 19:09:37 +02:00
|
|
|
// setup_receive() may disconnect the connection
|
|
|
|
// and clear it out from the m_connections list
|
|
|
|
p->setup_receive();
|
2009-06-10 10:30:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2009-04-26 02:21:59 +02:00
|
|
|
void session_impl::on_tick(error_code const& e)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2010-07-14 06:16:38 +02:00
|
|
|
TORRENT_ASSERT(is_network_thread());
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2009-05-25 04:45:51 +02:00
|
|
|
ptime now = time_now_hires();
|
|
|
|
aux::g_current_time = now;
|
2007-09-29 18:14:03 +02:00
|
|
|
// too expensive
|
|
|
|
// INVARIANT_CHECK;
|
2007-08-21 20:33:28 +02:00
|
|
|
|
2007-10-07 20:06:56 +02:00
|
|
|
if (m_abort) return;
|
|
|
|
|
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)
|
|
|
|
{
|
2008-02-28 08:34:07 +01:00
|
|
|
#if defined TORRENT_LOGGING
|
2009-04-30 07:49:46 +02:00
|
|
|
(*m_logger) << "*** TICK TIMER FAILED " << e.message() << "\n";
|
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;
|
|
|
|
}
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
error_code ec;
|
2010-05-03 10:54:03 +02:00
|
|
|
m_timer.expires_at(now + milliseconds(m_settings.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;
|
|
|
|
|
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;
|
|
|
|
|
2009-07-19 06:59:27 +02:00
|
|
|
int tick_interval_ms = 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
|
|
|
|
2009-04-30 07:49:46 +02:00
|
|
|
int session_time = total_seconds(now - m_created);
|
|
|
|
if (session_time > 65000)
|
|
|
|
{
|
|
|
|
// we're getting close to the point where our timestamps
|
|
|
|
// in policy::peer are wrapping. We need to step all counters back
|
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
policy& p = i->second->get_policy();
|
|
|
|
for (policy::iterator j = p.begin_peer()
|
|
|
|
, end(p.end_peer()); j != end; ++j)
|
|
|
|
{
|
2009-05-13 18:14:20 +02:00
|
|
|
policy::peer* pe = *j;
|
2009-04-30 07:49:46 +02:00
|
|
|
|
|
|
|
if (pe->last_optimistically_unchoked < four_hours)
|
|
|
|
pe->last_optimistically_unchoked = 0;
|
|
|
|
else
|
|
|
|
pe->last_optimistically_unchoked -= four_hours;
|
|
|
|
|
|
|
|
if (pe->last_connected < four_hours)
|
|
|
|
pe->last_connected = 0;
|
|
|
|
else
|
|
|
|
pe->last_connected -= four_hours;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-14 00:01:21 +02:00
|
|
|
#ifdef TORRENT_STATS
|
|
|
|
++m_second_counter;
|
|
|
|
int downloading_torrents = 0;
|
|
|
|
int seeding_torrents = 0;
|
2008-12-27 03:22:20 +01:00
|
|
|
static size_type downloaded = 0;
|
|
|
|
static size_type uploaded = 0;
|
2009-07-19 06:59:27 +02:00
|
|
|
size_type download_rate = (m_stat.total_download() - downloaded) * 1000 / tick_interval_ms;
|
|
|
|
size_type upload_rate = (m_stat.total_upload() - uploaded) * 1000 / tick_interval_ms;
|
2008-12-27 03:22:20 +01:00
|
|
|
downloaded = m_stat.total_download();
|
|
|
|
uploaded = m_stat.total_upload();
|
2009-05-04 08:56:29 +02:00
|
|
|
size_type num_peers = 0;
|
2007-05-14 00:01:21 +02:00
|
|
|
for (torrent_map::iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
2009-05-04 08:56:29 +02:00
|
|
|
num_peers += i->second->get_policy().num_peers();
|
2007-05-14 00:01:21 +02:00
|
|
|
if (i->second->is_seed())
|
|
|
|
++seeding_torrents;
|
|
|
|
else
|
|
|
|
++downloading_torrents;
|
|
|
|
}
|
2007-09-29 18:14:03 +02:00
|
|
|
int num_complete_connections = 0;
|
2007-05-14 06:01:30 +02:00
|
|
|
int num_half_open = 0;
|
2008-12-27 03:22:20 +01:00
|
|
|
int unchoked_peers = 0;
|
2007-05-14 06:01:30 +02:00
|
|
|
for (connection_map::iterator i = m_connections.begin()
|
|
|
|
, end(m_connections.end()); i != end; ++i)
|
|
|
|
{
|
2007-10-31 10:48:20 +01:00
|
|
|
if ((*i)->is_connecting())
|
2007-05-14 06:01:30 +02:00
|
|
|
++num_half_open;
|
|
|
|
else
|
2008-12-27 03:22:20 +01:00
|
|
|
{
|
2007-09-29 18:14:03 +02:00
|
|
|
++num_complete_connections;
|
2008-12-27 03:22:20 +01:00
|
|
|
if (!(*i)->is_choked()) ++unchoked_peers;
|
|
|
|
}
|
2007-05-14 06:01:30 +02:00
|
|
|
}
|
|
|
|
|
2007-05-14 00:01:21 +02:00
|
|
|
m_stats_logger
|
|
|
|
<< m_second_counter << "\t"
|
2008-12-27 03:22:20 +01:00
|
|
|
<< upload_rate << "\t"
|
|
|
|
<< download_rate << "\t"
|
2007-05-14 00:01:21 +02:00
|
|
|
<< downloading_torrents << "\t"
|
|
|
|
<< seeding_torrents << "\t"
|
2007-09-29 18:14:03 +02:00
|
|
|
<< num_complete_connections << "\t"
|
2007-05-14 06:01:30 +02:00
|
|
|
<< num_half_open << "\t"
|
2007-09-29 18:14:03 +02:00
|
|
|
<< m_disk_thread.disk_allocations() << "\t"
|
2008-12-27 03:22:20 +01:00
|
|
|
<< unchoked_peers << "\t"
|
2009-05-04 08:56:29 +02:00
|
|
|
<< num_peers << "\t"
|
2009-05-07 22:30:20 +02:00
|
|
|
<< logging_allocator::allocations << "\t"
|
|
|
|
<< logging_allocator::allocated_bytes << "\t"
|
2007-05-14 06:01:30 +02:00
|
|
|
<< std::endl;
|
2007-05-14 00:01:21 +02:00
|
|
|
#endif
|
2008-07-10 12:35:11 +02:00
|
|
|
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
// 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
|
2008-12-25 23:19:14 +01:00
|
|
|
// are ticked through the torrents' second_tick
|
2008-07-10 12:35:11 +02:00
|
|
|
if (!p->associated_torrent().expired()) continue;
|
2008-07-12 10:25:19 +02:00
|
|
|
if (m_last_tick - p->connected_time() > seconds(m_settings.handshake_timeout))
|
2009-11-29 08:06:38 +01:00
|
|
|
p->disconnect(errors::timed_out);
|
2008-07-10 12:35:11 +02:00
|
|
|
}
|
|
|
|
|
2008-03-29 20:39:24 +01:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// second_tick every torrent
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
|
|
|
|
int congested_torrents = 0;
|
|
|
|
int uncongested_torrents = 0;
|
|
|
|
|
|
|
|
// count the number of seeding torrents vs. downloading
|
|
|
|
// torrents we are running
|
|
|
|
int num_seeds = 0;
|
|
|
|
int num_downloads = 0;
|
|
|
|
|
|
|
|
// count the number of peers of downloading torrents
|
|
|
|
int num_downloads_peers = 0;
|
|
|
|
|
2009-07-24 10:25:07 +02:00
|
|
|
torrent_map::iterator least_recently_scraped = m_torrents.end();
|
2008-05-19 06:06:25 +02:00
|
|
|
int num_paused_auto_managed = 0;
|
|
|
|
|
2009-05-30 04:38:34 +02:00
|
|
|
int num_checking = 0;
|
|
|
|
int num_queued = 0;
|
2008-03-29 20:39:24 +01:00
|
|
|
for (torrent_map::iterator i = m_torrents.begin();
|
|
|
|
i != m_torrents.end();)
|
|
|
|
{
|
|
|
|
torrent& t = *i->second;
|
|
|
|
TORRENT_ASSERT(!t.is_aborted());
|
2009-12-29 20:06:27 +01:00
|
|
|
if (t.statistics().upload_rate() > t.upload_limit() * 9 / 10)
|
2008-03-29 20:39:24 +01:00
|
|
|
++congested_torrents;
|
|
|
|
else
|
|
|
|
++uncongested_torrents;
|
|
|
|
|
2009-05-30 04:38:34 +02:00
|
|
|
if (t.state() == torrent_status::checking_files) ++num_checking;
|
2009-11-28 23:47:45 +01:00
|
|
|
else if (t.state() == torrent_status::queued_for_checking && !t.is_paused()) ++num_queued;
|
2009-11-26 16:14:39 +01:00
|
|
|
|
2008-05-20 09:57:44 +02:00
|
|
|
if (t.is_auto_managed() && t.is_paused() && !t.has_error())
|
2008-05-19 06:06:25 +02:00
|
|
|
{
|
|
|
|
++num_paused_auto_managed;
|
2009-07-24 10:25:07 +02:00
|
|
|
if (least_recently_scraped == m_torrents.end()
|
2010-02-14 02:39:55 +01:00
|
|
|
|| least_recently_scraped->second->seconds_since_last_scrape()
|
|
|
|
< t.seconds_since_last_scrape())
|
2008-05-19 06:06:25 +02:00
|
|
|
{
|
|
|
|
least_recently_scraped = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-29 20:39:24 +01:00
|
|
|
if (t.is_finished())
|
|
|
|
{
|
|
|
|
++num_seeds;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++num_downloads;
|
|
|
|
num_downloads_peers += t.num_peers();
|
|
|
|
}
|
|
|
|
|
2009-07-19 06:59:27 +02:00
|
|
|
t.second_tick(m_stat, tick_interval_ms);
|
2008-03-29 20:39:24 +01:00
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
2009-05-30 04:38:34 +02:00
|
|
|
// some people claim that there sometimes can be cases where
|
|
|
|
// there is no torrent being checked, but there are torrents
|
|
|
|
// waiting to be checked. I have never seen this, and I can't
|
|
|
|
// see a way for it to happen. But, if it does, start one of
|
|
|
|
// the queued torrents
|
|
|
|
if (num_checking == 0 && num_queued > 0)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(false);
|
|
|
|
check_queue_t::iterator i = std::min_element(m_queued_for_checking.begin()
|
|
|
|
, m_queued_for_checking.end(), boost::bind(&torrent::queue_position, _1)
|
|
|
|
< boost::bind(&torrent::queue_position, _2));
|
|
|
|
if (i != m_queued_for_checking.end())
|
|
|
|
{
|
|
|
|
(*i)->start_checking();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-30 08:25:17 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2008-11-02 11:01:04 +01:00
|
|
|
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);
|
|
|
|
}
|
2009-08-30 08:25:17 +02:00
|
|
|
#endif
|
2008-11-02 11:01:04 +01:00
|
|
|
|
2008-11-18 12:14:44 +01:00
|
|
|
if (m_settings.rate_limit_ip_overhead)
|
|
|
|
{
|
2009-04-26 02:21:59 +02:00
|
|
|
m_download_channel.use_quota(m_stat.download_dht()
|
2008-11-18 12:14:44 +01:00
|
|
|
+ m_stat.download_tracker());
|
2008-09-22 02:15:05 +02:00
|
|
|
|
2009-04-26 02:21:59 +02:00
|
|
|
m_upload_channel.use_quota(m_stat.upload_dht()
|
|
|
|
+ m_stat.upload_tracker());
|
|
|
|
|
|
|
|
int up_limit = m_upload_channel.throttle();
|
|
|
|
int down_limit = m_download_channel.throttle();
|
|
|
|
|
|
|
|
if (down_limit > 0
|
|
|
|
&& m_stat.download_ip_overhead() >= down_limit
|
|
|
|
&& m_alerts.should_post<performance_alert>())
|
2008-12-25 23:26:02 +01:00
|
|
|
{
|
|
|
|
m_alerts.post_alert(performance_alert(torrent_handle()
|
2009-04-26 02:21:59 +02:00
|
|
|
, performance_alert::download_limit_too_low));
|
2008-12-25 23:26:02 +01:00
|
|
|
}
|
2008-10-28 07:45:42 +01:00
|
|
|
|
2009-04-26 02:21:59 +02:00
|
|
|
if (up_limit > 0
|
|
|
|
&& m_stat.upload_ip_overhead() >= up_limit
|
|
|
|
&& m_alerts.should_post<performance_alert>())
|
2008-12-25 23:26:02 +01:00
|
|
|
{
|
|
|
|
m_alerts.post_alert(performance_alert(torrent_handle()
|
2009-04-26 02:21:59 +02:00
|
|
|
, performance_alert::upload_limit_too_low));
|
2008-12-25 23:26:02 +01:00
|
|
|
}
|
2008-10-28 07:45:42 +01:00
|
|
|
}
|
|
|
|
|
2010-02-09 04:04:41 +01:00
|
|
|
m_peak_up_rate = (std::max)(m_stat.upload_rate(), m_peak_up_rate);
|
|
|
|
m_peak_down_rate = (std::max)(m_stat.download_rate(), m_peak_down_rate);
|
|
|
|
|
2009-07-19 06:59:27 +02:00
|
|
|
m_stat.second_tick(tick_interval_ms);
|
2008-03-29 20:39:24 +01:00
|
|
|
|
2009-07-24 10:25:07 +02:00
|
|
|
TORRENT_ASSERT(least_recently_scraped == m_torrents.end()
|
2009-10-20 04:49:56 +02:00
|
|
|
|| (least_recently_scraped->second->is_paused()
|
|
|
|
&& least_recently_scraped->second->is_auto_managed()));
|
2009-07-24 10:25:07 +02:00
|
|
|
|
2008-05-19 06:06:25 +02:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// scrape paused torrents that are auto managed
|
2009-07-24 10:25:07 +02:00
|
|
|
// (unless the session is paused)
|
2008-05-19 06:06:25 +02:00
|
|
|
// --------------------------------------------------------------
|
2008-07-19 09:45:15 +02:00
|
|
|
if (!is_paused())
|
2008-05-19 06:06:25 +02:00
|
|
|
{
|
2008-07-19 09:45:15 +02:00
|
|
|
--m_auto_scrape_time_scaler;
|
|
|
|
if (m_auto_scrape_time_scaler <= 0)
|
2008-05-19 06:06:25 +02:00
|
|
|
{
|
2008-07-19 09:45:15 +02:00
|
|
|
m_auto_scrape_time_scaler = m_settings.auto_scrape_interval
|
|
|
|
/ (std::max)(1, num_paused_auto_managed);
|
|
|
|
if (m_auto_scrape_time_scaler < m_settings.auto_scrape_min_interval)
|
|
|
|
m_auto_scrape_time_scaler = m_settings.auto_scrape_min_interval;
|
|
|
|
|
|
|
|
if (least_recently_scraped != m_torrents.end())
|
|
|
|
{
|
|
|
|
least_recently_scraped->second->scrape_tracker();
|
|
|
|
}
|
2008-05-19 06:06:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-15 17:45:42 +01:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// refresh explicit disk read cache
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
--m_cache_rotation_timer;
|
|
|
|
if (m_settings.explicit_read_cache
|
|
|
|
&& m_cache_rotation_timer <= 0)
|
|
|
|
{
|
|
|
|
m_cache_rotation_timer = m_settings.explicit_cache_interval;
|
|
|
|
|
|
|
|
torrent_map::iterator least_recently_refreshed = m_torrents.begin();
|
|
|
|
if (m_next_explicit_cache_torrent >= 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?
|
|
|
|
int cache_size = (std::max)(0, m_settings.cache_size * 9 / 10);
|
|
|
|
|
|
|
|
if (m_connections.empty())
|
|
|
|
{
|
|
|
|
// if we don't have any connections at all, split the
|
|
|
|
// cache evenly across all torrents
|
2010-01-17 22:57:24 +01:00
|
|
|
cache_size = cache_size / (std::max)(int(m_torrents.size()), 1);
|
2010-01-15 17:45:42 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cache_size = cache_size * least_recently_refreshed->second->num_peers()
|
|
|
|
/ m_connections.size();
|
|
|
|
}
|
|
|
|
|
2010-01-17 22:57:24 +01:00
|
|
|
if (least_recently_refreshed != m_torrents.end())
|
|
|
|
least_recently_refreshed->second->refresh_explicit_cache(cache_size);
|
2010-01-15 17:45:42 +01:00
|
|
|
++m_next_explicit_cache_torrent;
|
|
|
|
}
|
|
|
|
|
2008-03-29 20:39:24 +01:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// connect new peers
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
|
2007-05-05 02:29:33 +02:00
|
|
|
// let torrents connect to peers if they want to
|
|
|
|
// if there are any torrents and any free slots
|
2007-05-25 23:00:35 +02:00
|
|
|
|
|
|
|
// this loop will "hand out" max(connection_speed
|
|
|
|
// , half_open.free_slots()) to the torrents, in a
|
|
|
|
// round robin fashion, so that every torrent is
|
2010-02-06 22:40:55 +01:00
|
|
|
// equally likely to connect to a peer
|
2007-05-25 23:00:35 +02:00
|
|
|
|
2008-03-16 11:49:47 +01:00
|
|
|
int free_slots = m_half_open.free_slots();
|
2007-08-16 14:41:46 +02:00
|
|
|
if (!m_torrents.empty()
|
2008-03-16 11:49:47 +01:00
|
|
|
&& free_slots > -m_half_open.limit()
|
2008-09-30 03:14:27 +02:00
|
|
|
&& num_connections() < m_max_connections
|
2010-02-06 22:40:55 +01:00
|
|
|
&& !m_abort
|
|
|
|
&& m_settings.connection_speed > 0)
|
2007-05-05 02:29:33 +02:00
|
|
|
{
|
2007-05-25 23:00:35 +02:00
|
|
|
// this is the maximum number of connections we will
|
|
|
|
// attempt this tick
|
|
|
|
int max_connections = m_settings.connection_speed;
|
2008-03-29 20:39:24 +01:00
|
|
|
int average_peers = 0;
|
|
|
|
if (num_downloads > 0)
|
|
|
|
average_peers = num_downloads_peers / num_downloads;
|
2007-05-25 23:00:35 +02:00
|
|
|
|
2010-02-05 09:23:17 +01:00
|
|
|
if (m_next_connect_torrent == m_torrents.end())
|
|
|
|
m_next_connect_torrent = m_torrents.begin();
|
|
|
|
|
2007-05-25 23:00:35 +02:00
|
|
|
int steps_since_last_connect = 0;
|
|
|
|
int num_torrents = int(m_torrents.size());
|
|
|
|
for (;;)
|
2007-05-05 02:29:33 +02:00
|
|
|
{
|
2010-02-05 09:23:17 +01:00
|
|
|
torrent& t = *m_next_connect_torrent->second;
|
2007-05-05 02:29:33 +02:00
|
|
|
if (t.want_more_peers())
|
2007-08-16 14:41:46 +02:00
|
|
|
{
|
2008-03-29 20:39:24 +01:00
|
|
|
int connect_points = 100;
|
|
|
|
// have a bias against torrents with more peers
|
|
|
|
// than average
|
|
|
|
if (!t.is_seed() && t.num_peers() > average_peers)
|
|
|
|
connect_points /= 2;
|
|
|
|
// if this is a seed and there is a torrent that
|
|
|
|
// is downloading, lower the rate at which this
|
|
|
|
// torrent gets connections.
|
|
|
|
// dividing by num_seeds will have the effect
|
|
|
|
// that all seed will get as many connections
|
|
|
|
// together, as a single downloading torrent.
|
|
|
|
if (t.is_seed() && num_downloads > 0)
|
|
|
|
connect_points /= num_seeds + 1;
|
|
|
|
if (connect_points <= 0) connect_points = 1;
|
|
|
|
t.give_connect_points(connect_points);
|
2008-12-26 00:51:16 +01:00
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
2008-02-05 06:51:05 +01:00
|
|
|
try
|
2007-05-25 23:00:35 +02:00
|
|
|
{
|
2008-12-26 00:51:16 +01:00
|
|
|
#endif
|
2008-02-05 06:51:05 +01:00
|
|
|
if (t.try_connect_peer())
|
|
|
|
{
|
|
|
|
--max_connections;
|
2008-03-16 11:49:47 +01:00
|
|
|
--free_slots;
|
2008-02-05 06:51:05 +01:00
|
|
|
steps_since_last_connect = 0;
|
|
|
|
}
|
2008-12-26 00:51:16 +01:00
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
2008-02-05 06:51:05 +01:00
|
|
|
}
|
|
|
|
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_max_connections = num_connections();
|
|
|
|
if (m_max_connections < 2) m_max_connections = 2;
|
2007-05-25 23:00:35 +02:00
|
|
|
}
|
2008-12-26 00:51:16 +01:00
|
|
|
#endif
|
2007-08-16 14:41:46 +02:00
|
|
|
}
|
2010-02-05 09:23:17 +01:00
|
|
|
|
2007-05-05 02:29:33 +02:00
|
|
|
++m_next_connect_torrent;
|
2007-05-25 23:00:35 +02:00
|
|
|
++steps_since_last_connect;
|
2010-02-05 09:23:17 +01:00
|
|
|
if (m_next_connect_torrent == m_torrents.end())
|
|
|
|
m_next_connect_torrent = m_torrents.begin();
|
|
|
|
|
2008-03-29 20:39:24 +01:00
|
|
|
// if we have gone two whole loops without
|
2007-05-25 23:00:35 +02:00
|
|
|
// handing out a single connection, break
|
2008-03-29 20:39:24 +01:00
|
|
|
if (steps_since_last_connect > num_torrents * 2) break;
|
2007-05-25 23:00:35 +02:00
|
|
|
// if there are no more free connection slots, abort
|
2008-03-16 11:49:47 +01:00
|
|
|
if (free_slots <= -m_half_open.limit()) break;
|
2007-05-25 23:00:35 +02:00
|
|
|
// if we should not make any more connections
|
|
|
|
// attempts this tick, abort
|
|
|
|
if (max_connections == 0) break;
|
2007-08-27 18:45:45 +02:00
|
|
|
// maintain the global limit on number of connections
|
|
|
|
if (num_connections() >= m_max_connections) break;
|
2007-05-25 23:00:35 +02:00
|
|
|
}
|
2007-05-05 02:29:33 +02:00
|
|
|
}
|
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
// --------------------------------------------------------------
|
|
|
|
// auto managed torrent
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
m_auto_manage_time_scaler--;
|
|
|
|
if (m_auto_manage_time_scaler <= 0)
|
|
|
|
{
|
|
|
|
m_auto_manage_time_scaler = settings().auto_manage_interval;
|
|
|
|
recalculate_auto_managed_torrents();
|
|
|
|
}
|
|
|
|
|
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())
|
|
|
|
{
|
|
|
|
m_unchoke_time_scaler = settings().unchoke_interval;
|
2008-04-24 05:28:48 +02:00
|
|
|
recalculate_unchoke_slots(congested_torrents
|
|
|
|
, uncongested_torrents);
|
|
|
|
}
|
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
|
|
|
|
= settings().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)
|
|
|
|
{
|
|
|
|
m_disconnect_time_scaler = 90;
|
|
|
|
|
2008-05-12 07:17:11 +02:00
|
|
|
// every 90 seconds, disconnect the worst peers
|
2008-04-24 05:28:48 +02:00
|
|
|
// if we have reached the connection limit
|
2008-05-12 07:17:11 +02:00
|
|
|
if (num_connections() >= max_connections() * m_settings.peer_turnover_cutoff
|
|
|
|
&& !m_torrents.empty())
|
2007-08-16 14:41:46 +02:00
|
|
|
{
|
2008-04-24 05:28:48 +02:00
|
|
|
torrent_map::iterator i = std::max_element(m_torrents.begin(), m_torrents.end()
|
2009-11-23 00:55:54 +01:00
|
|
|
, 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)));
|
2008-04-24 05:28:48 +02:00
|
|
|
|
|
|
|
TORRENT_ASSERT(i != m_torrents.end());
|
2008-05-12 07:17:11 +02:00
|
|
|
int peers_to_disconnect = (std::min)((std::max)(int(i->second->num_peers()
|
|
|
|
* m_settings.peer_turnover), 1)
|
|
|
|
, i->second->get_policy().num_connect_candidates());
|
|
|
|
i->second->disconnect_peers(peers_to_disconnect);
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
if (t->num_peers() < t->max_connections() * m_settings.peer_turnover_cutoff)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int peers_to_disconnect = (std::min)((std::max)(int(i->second->num_peers()
|
|
|
|
* m_settings.peer_turnover), 1)
|
|
|
|
, i->second->get_policy().num_connect_candidates());
|
|
|
|
t->disconnect_peers(peers_to_disconnect);
|
|
|
|
}
|
2007-08-16 14:41:46 +02:00
|
|
|
}
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
2009-05-11 22:23:47 +02:00
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
while (m_tick_residual >= 1000) 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
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
|
|
|
|
void session_impl::on_dht_announce(error_code const& e)
|
|
|
|
{
|
2010-07-14 06:16:38 +02:00
|
|
|
TORRENT_ASSERT(is_network_thread());
|
2010-02-14 02:39:55 +01:00
|
|
|
if (e) return;
|
|
|
|
|
|
|
|
if (m_abort) return;
|
|
|
|
|
|
|
|
// announce to DHT every 15 minutes
|
|
|
|
int delay = (std::max)(m_settings.dht_announce_interval
|
|
|
|
/ (std::max)(int(m_torrents.size()), 1), 1);
|
|
|
|
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));
|
|
|
|
|
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();
|
|
|
|
++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-07-14 06:16:38 +02:00
|
|
|
TORRENT_ASSERT(is_network_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
|
|
|
|
|
|
|
// announce on local network every 5 minutes
|
|
|
|
int delay = (std::max)(m_settings.local_service_announce_interval
|
|
|
|
/ (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();
|
|
|
|
}
|
|
|
|
|
2008-06-21 14:31:28 +02:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
bool is_active(torrent* t, session_settings const& s)
|
|
|
|
{
|
2008-10-19 06:31:33 +02:00
|
|
|
// if we count slow torrents, every torrent
|
|
|
|
// is considered active
|
|
|
|
if (!s.dont_count_slow_torrents) return true;
|
|
|
|
|
|
|
|
// if the torrent started less than 2 minutes
|
|
|
|
// ago (default), let it count as active since
|
|
|
|
// the rates are probably not accurate yet
|
|
|
|
if (time_now() - t->started() < seconds(s.auto_manage_startup)) return true;
|
|
|
|
|
|
|
|
return t->statistics().upload_payload_rate() != 0.f
|
|
|
|
|| t->statistics().download_payload_rate() != 0.f;
|
2008-06-21 14:31:28 +02:00
|
|
|
}
|
|
|
|
}
|
2009-05-27 21:27:12 +02:00
|
|
|
|
2010-03-29 02:34:04 +02:00
|
|
|
void session_impl::auto_manage_torrents(std::vector<torrent*>& list
|
|
|
|
, int& dht_limit, int& tracker_limit, int& lsd_limit
|
|
|
|
, int& hard_limit, int type_limit)
|
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;
|
|
|
|
if (!t->is_paused() && !is_active(t, settings())
|
|
|
|
&& hard_limit > 0)
|
|
|
|
{
|
|
|
|
--hard_limit;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type_limit > 0 && hard_limit > 0)
|
|
|
|
{
|
|
|
|
--hard_limit;
|
|
|
|
--type_limit;
|
2010-03-29 02:34:04 +02:00
|
|
|
--dht_limit;
|
|
|
|
--tracker_limit;
|
|
|
|
t->set_announce_to_dht(dht_limit >= 0);
|
|
|
|
t->set_announce_to_trackers(tracker_limit >= 0);
|
2010-03-31 04:40:00 +02:00
|
|
|
t->set_allow_peers(true);
|
2009-05-27 21:27:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-31 04:40:00 +02:00
|
|
|
t->set_allow_peers(false);
|
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()
|
|
|
|
{
|
|
|
|
// these vectors are filled with auto managed torrents
|
|
|
|
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
|
|
|
|
int num_downloaders = settings().active_downloads;
|
|
|
|
int num_seeds = settings().active_seeds;
|
2010-03-29 02:34:04 +02:00
|
|
|
int dht_limit = settings().active_dht_limit;
|
|
|
|
int tracker_limit = settings().active_tracker_limit;
|
|
|
|
int lsd_limit = settings().active_lsd_limit;
|
2008-06-21 14:31:28 +02:00
|
|
|
int hard_limit = settings().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)();
|
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);
|
2008-05-20 09:57:44 +02:00
|
|
|
if (t->is_auto_managed() && !t->has_error())
|
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
|
|
|
{
|
2008-06-21 14:31:28 +02:00
|
|
|
--hard_limit;
|
|
|
|
if (is_active(t, settings()))
|
|
|
|
{
|
|
|
|
// this is not an auto managed torrent,
|
|
|
|
// if it's running and active, decrease the
|
|
|
|
// counters.
|
2009-11-29 04:28:11 +01:00
|
|
|
if (t->is_finished())
|
|
|
|
--num_seeds;
|
|
|
|
else
|
|
|
|
--num_downloaders;
|
2008-06-21 14:31:28 +02:00
|
|
|
}
|
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
|
|
|
|
// TODO: allow extensions to sort torrents for queuing
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!handled_by_extension)
|
|
|
|
{
|
|
|
|
std::sort(downloaders.begin(), downloaders.end()
|
|
|
|
, bind(&torrent::sequence_number, _1) < bind(&torrent::sequence_number, _2));
|
|
|
|
|
|
|
|
std::sort(seeds.begin(), seeds.end()
|
2008-05-06 20:03:41 +02:00
|
|
|
, bind(&torrent::seed_rank, _1, boost::ref(m_settings))
|
2008-05-07 10:24:16 +02:00
|
|
|
> bind(&torrent::seed_rank, _2, boost::ref(m_settings)));
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
|
|
|
|
2009-05-27 21:27:12 +02:00
|
|
|
if (settings().auto_manage_prefer_seeds)
|
2008-04-24 05:28:48 +02:00
|
|
|
{
|
2010-03-29 02:34:04 +02:00
|
|
|
auto_manage_torrents(seeds, dht_limit, tracker_limit, lsd_limit
|
|
|
|
, hard_limit, num_seeds);
|
|
|
|
auto_manage_torrents(downloaders, dht_limit, tracker_limit, lsd_limit
|
|
|
|
, 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
|
|
|
{
|
2010-03-29 02:34:04 +02:00
|
|
|
auto_manage_torrents(downloaders, dht_limit, tracker_limit, lsd_limit
|
|
|
|
, hard_limit, num_downloaders);
|
|
|
|
auto_manage_torrents(seeds, dht_limit, tracker_limit, lsd_limit
|
|
|
|
, hard_limit, num_seeds);
|
2008-04-24 05:28:48 +02:00
|
|
|
}
|
2009-05-27 21:27:12 +02:00
|
|
|
|
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
|
|
|
{
|
2008-10-19 00:35:10 +02:00
|
|
|
if (m_allowed_upload_slots == 0) return;
|
|
|
|
|
2010-02-02 19:39:32 +01:00
|
|
|
std::vector<policy::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);
|
2008-10-19 00:35:10 +02:00
|
|
|
policy::peer* pi = p->peer_info_struct();
|
|
|
|
if (!pi) continue;
|
|
|
|
torrent* t = p->associated_torrent().lock().get();
|
|
|
|
if (!t) continue;
|
|
|
|
|
|
|
|
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()
|
|
|
|
, boost::bind(&policy::peer::last_optimistically_unchoked, _1)
|
|
|
|
< boost::bind(&policy::peer::last_optimistically_unchoked, _2));
|
|
|
|
|
|
|
|
int num_opt_unchoke = m_settings.num_optimistic_unchoke_slots;
|
|
|
|
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
|
|
|
|
for (std::vector<policy::peer*>::iterator i = opt_unchoke.begin()
|
|
|
|
, end(opt_unchoke.end()); i != end; ++i)
|
2008-10-19 00:35:10 +02:00
|
|
|
{
|
2010-02-02 19:39:32 +01:00
|
|
|
policy::peer* pi = *i;
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
torrent* t = pi->connection->associated_torrent().lock().get();
|
|
|
|
bool ret = t->unchoke_peer(*pi->connection);
|
|
|
|
TORRENT_ASSERT(ret);
|
|
|
|
pi->optimistically_unchoked = true;
|
|
|
|
++m_num_unchoked;
|
|
|
|
pi->last_optimistically_unchoked = session_time();
|
|
|
|
}
|
2008-10-19 00:35:10 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-02-02 19:39:32 +01:00
|
|
|
if (pi->optimistically_unchoked)
|
|
|
|
{
|
|
|
|
torrent* t = pi->connection->associated_torrent().lock().get();
|
|
|
|
pi->optimistically_unchoked = false;
|
|
|
|
t->choke_peer(*pi->connection);
|
|
|
|
--m_num_unchoked;
|
|
|
|
}
|
2008-10-19 00:35:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::recalculate_unchoke_slots(int congested_torrents
|
|
|
|
, int uncongested_torrents)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
// unchoke:able.
|
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();)
|
|
|
|
{
|
|
|
|
boost::intrusive_ptr<peer_connection> p = *i;
|
|
|
|
TORRENT_ASSERT(p);
|
|
|
|
++i;
|
2008-04-24 05:28:48 +02:00
|
|
|
torrent* t = p->associated_torrent().lock().get();
|
2009-04-04 09:55:34 +02:00
|
|
|
policy::peer* pi = p->peer_info_struct();
|
2010-02-09 04:04:41 +01:00
|
|
|
|
2009-04-04 09:55:34 +02:00
|
|
|
if (p->ignore_unchoke_slots() || t == 0 || pi == 0) continue;
|
|
|
|
|
2010-02-09 04:04:41 +01:00
|
|
|
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
|
|
|
|
{
|
|
|
|
if (!p->is_choked())
|
|
|
|
{
|
|
|
|
policy::peer* pi = p->peer_info_struct();
|
|
|
|
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()
|
|
|
|
|| p->is_connecting()
|
|
|
|
|| (p->share_diff() < -free_upload_amount
|
|
|
|
&& !t->is_seed()))
|
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
|
|
|
{
|
2009-04-04 09:55:34 +02:00
|
|
|
pi->optimistically_unchoked = false;
|
|
|
|
// force a new optimistic unchoke
|
|
|
|
m_optimistic_unchoke_time_scaler = 0;
|
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
|
|
|
|
2010-02-09 04:04:41 +01:00
|
|
|
if (m_settings.choking_algorithm == session_settings::rate_based_choker)
|
2009-04-04 09:55:34 +02:00
|
|
|
{
|
|
|
|
m_allowed_upload_slots = 0;
|
|
|
|
std::sort(peers.begin(), peers.end()
|
|
|
|
, bind(&peer_connection::upload_rate_compare, _1, _2));
|
|
|
|
|
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);
|
2009-05-02 05:15:52 +02:00
|
|
|
TORRENT_ASSERT((*prev)->uploaded_since_unchoke() * 1000
|
2010-07-15 03:46:50 +02:00
|
|
|
* (1 + t1->priority()) / total_milliseconds(unchoke_interval)
|
2009-05-02 05:15:52 +02:00
|
|
|
>= (*i)->uploaded_since_unchoke() * 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;
|
|
|
|
int rate = p.uploaded_since_unchoke()
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2010-02-09 04:04:41 +01:00
|
|
|
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
|
|
|
|
{
|
|
|
|
// 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()
|
|
|
|
, bind(&peer_connection::bittyrant_unchoke_compare, _1, _2));
|
|
|
|
}
|
|
|
|
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()
|
|
|
|
, bind(&peer_connection::unchoke_compare, _1, _2));
|
|
|
|
}
|
2007-08-16 14:41:46 +02:00
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
// auto unchoke
|
2009-04-26 02:21:59 +02:00
|
|
|
int upload_limit = m_bandwidth_channel[peer_connection::upload_channel]->throttle();
|
2010-02-09 04:04:41 +01:00
|
|
|
if (m_settings.choking_algorithm == session_settings::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 AND most torrents are not "congested", i.e.
|
|
|
|
// they are not holding back because of a per-torrent
|
|
|
|
// limit
|
|
|
|
if (m_stat.upload_rate() < upload_limit * 0.9f
|
|
|
|
&& m_allowed_upload_slots <= m_num_unchoked + 1
|
2008-10-14 02:56:44 +02:00
|
|
|
&& congested_torrents < uncongested_torrents
|
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
|
2008-04-24 05:28:48 +02:00
|
|
|
&& m_allowed_upload_slots > m_max_uploads)
|
|
|
|
{
|
|
|
|
--m_allowed_upload_slots;
|
|
|
|
}
|
|
|
|
}
|
2007-08-17 09:37:08 +02:00
|
|
|
|
2010-02-02 19:39:32 +01:00
|
|
|
int num_opt_unchoke = m_settings.num_optimistic_unchoke_slots;
|
|
|
|
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;
|
|
|
|
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
|
|
|
|
{
|
|
|
|
upload_capacity_left = m_upload_channel.throttle();
|
|
|
|
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
|
|
|
m_num_unchoked = 0;
|
|
|
|
// 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
|
2010-02-09 04:04:41 +01:00
|
|
|
// #error 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;
|
|
|
|
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
++m_num_unchoked;
|
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;
|
2007-08-16 14:41:46 +02:00
|
|
|
}
|
|
|
|
}
|
2008-04-24 05:28:48 +02:00
|
|
|
else
|
|
|
|
{
|
2009-04-04 09:55:34 +02:00
|
|
|
// no, this peer should be shoked
|
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);
|
|
|
|
if (!p->is_choked())
|
|
|
|
++m_num_unchoked;
|
|
|
|
}
|
2007-08-16 14:41:46 +02:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
2006-12-21 23:20:28 +01:00
|
|
|
|
2009-10-20 04:49:56 +02:00
|
|
|
void session_impl::main_thread()
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2010-07-14 06:16:38 +02:00
|
|
|
#ifdef TORRENT_DEBUG
|
|
|
|
#if defined BOOST_HAS_PTHREADS
|
|
|
|
m_network_thread = pthread_self();
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
TORRENT_ASSERT(is_network_thread());
|
2006-10-11 22:57:54 +02:00
|
|
|
eh_initializer();
|
|
|
|
|
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)
|
|
|
|
(*m_logger) << time_now_string() << " locking mutex\n";
|
|
|
|
#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)
|
|
|
|
(*m_logger) << time_now_string() << " cleaning up torrents\n";
|
|
|
|
#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());
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// the return value from this function is valid only as long as the
|
|
|
|
// session is locked!
|
|
|
|
boost::weak_ptr<torrent> session_impl::find_torrent(sha1_hash const& info_hash)
|
|
|
|
{
|
2010-07-14 06:16:38 +02:00
|
|
|
TORRENT_ASSERT(is_network_thread());
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator i
|
|
|
|
= m_torrents.find(info_hash);
|
2008-11-29 22:33:21 +01:00
|
|
|
#ifdef TORRENT_DEBUG
|
2006-10-11 22:57:54 +02:00
|
|
|
for (std::map<sha1_hash, boost::shared_ptr<torrent> >::iterator j
|
|
|
|
= 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>();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
// current options are file_logger, cout_logger and null_logger
|
2007-11-16 22:21:28 +01:00
|
|
|
return boost::shared_ptr<logger>(new logger(m_logpath, name + ".log", instance, append));
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
std::vector<torrent_handle> session_impl::get_torrents()
|
|
|
|
{
|
|
|
|
std::vector<torrent_handle> ret;
|
2006-11-14 01:08:16 +01:00
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
for (session_impl::torrent_map::iterator i
|
|
|
|
= 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
|
|
|
}
|
|
|
|
|
2009-02-23 02:21:19 +01:00
|
|
|
torrent_handle session_impl::add_torrent(add_torrent_params const& params
|
|
|
|
, error_code& ec)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2008-04-24 05:28:48 +02:00
|
|
|
TORRENT_ASSERT(!params.save_path.empty());
|
2007-09-22 18:27:29 +02:00
|
|
|
|
2009-02-13 08:13:03 +01:00
|
|
|
if (params.ti && 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
|
|
|
|
2007-09-22 18:27:29 +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;
|
|
|
|
if (params.ti) ih = ¶ms.ti->info_hash();
|
|
|
|
else ih = ¶ms.info_hash;
|
|
|
|
|
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();
|
|
|
|
if (torrent_ptr)
|
2008-04-07 03:22:26 +02:00
|
|
|
{
|
2008-04-24 05:28:48 +02:00
|
|
|
if (!params.duplicate_is_error)
|
|
|
|
return torrent_handle(torrent_ptr);
|
|
|
|
|
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
|
|
|
|
2008-05-29 05:37:19 +02:00
|
|
|
int queue_pos = 0;
|
|
|
|
for (torrent_map::const_iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
int pos = i->second->queue_position();
|
|
|
|
if (pos >= queue_pos) queue_pos = pos + 1;
|
|
|
|
}
|
|
|
|
|
2009-02-03 08:46:24 +01:00
|
|
|
torrent_ptr.reset(new torrent(*this, m_listen_interface
|
|
|
|
, 16 * 1024, queue_pos, params));
|
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
|
|
|
|
for (extension_list_t::iterator i = m_extensions.begin()
|
|
|
|
, end(m_extensions.end()); i != end; ++i)
|
|
|
|
{
|
2008-04-24 05:28:48 +02:00
|
|
|
boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get(), params.userdata));
|
2006-11-23 17:21:45 +01:00
|
|
|
if (tp) torrent_ptr->add_extension(tp);
|
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
|
|
|
|
|
2008-04-24 05:28:48 +02:00
|
|
|
m_torrents.insert(std::make_pair(*ih, torrent_ptr));
|
2008-03-08 07:06:31 +01:00
|
|
|
|
2008-05-29 05:37:19 +02:00
|
|
|
// if this is an auto managed torrent, force a recalculation
|
|
|
|
// of which torrents to have active
|
|
|
|
if (params.auto_managed && m_auto_manage_time_scaler > 2)
|
|
|
|
m_auto_manage_time_scaler = 2;
|
|
|
|
|
2008-04-09 22:09:36 +02:00
|
|
|
return torrent_handle(torrent_ptr);
|
2008-03-08 07:06:31 +01:00
|
|
|
}
|
|
|
|
|
2010-01-17 22:42:14 +01:00
|
|
|
void session_impl::queue_check_torrent(boost::shared_ptr<torrent> const& t)
|
2008-03-08 07:06:31 +01:00
|
|
|
{
|
2008-06-24 14:17:42 +02:00
|
|
|
if (m_abort) return;
|
2008-11-19 01:46:48 +01:00
|
|
|
TORRENT_ASSERT(t->should_check_files());
|
|
|
|
TORRENT_ASSERT(t->state() != torrent_status::checking_files);
|
2008-03-08 07:06:31 +01:00
|
|
|
if (m_queued_for_checking.empty()) t->start_checking();
|
2008-11-19 01:46:48 +01:00
|
|
|
else t->set_state(torrent_status::queued_for_checking);
|
2008-09-20 19:42:25 +02:00
|
|
|
TORRENT_ASSERT(std::find(m_queued_for_checking.begin()
|
|
|
|
, m_queued_for_checking.end(), t) == m_queued_for_checking.end());
|
2008-03-08 07:06:31 +01:00
|
|
|
m_queued_for_checking.push_back(t);
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2010-01-17 22:42:14 +01:00
|
|
|
void session_impl::dequeue_check_torrent(boost::shared_ptr<torrent> const& t)
|
2008-03-08 07:06:31 +01:00
|
|
|
{
|
2008-11-19 01:46:48 +01:00
|
|
|
INVARIANT_CHECK;
|
2010-01-17 22:42:14 +01:00
|
|
|
TORRENT_ASSERT(t->state() == torrent_status::checking_files
|
|
|
|
|| t->state() == torrent_status::queued_for_checking);
|
2008-11-19 01:46:48 +01:00
|
|
|
|
2008-06-24 14:17:42 +02:00
|
|
|
if (m_queued_for_checking.empty()) return;
|
2010-01-17 22:42:14 +01:00
|
|
|
|
2009-02-03 18:35:41 +01:00
|
|
|
boost::shared_ptr<torrent> next_check = *m_queued_for_checking.begin();
|
2008-06-12 23:22:24 +02:00
|
|
|
check_queue_t::iterator done = m_queued_for_checking.end();
|
|
|
|
for (check_queue_t::iterator i = m_queued_for_checking.begin()
|
|
|
|
, end(m_queued_for_checking.end()); i != end; ++i)
|
|
|
|
{
|
2008-11-19 01:46:48 +01:00
|
|
|
TORRENT_ASSERT(*i == t || (*i)->should_check_files());
|
2008-06-12 23:22:24 +02:00
|
|
|
if (*i == t) done = i;
|
2009-02-03 18:35:41 +01:00
|
|
|
if (next_check == t || next_check->queue_position() > (*i)->queue_position())
|
|
|
|
next_check = *i;
|
2008-06-12 23:22:24 +02:00
|
|
|
}
|
2008-11-19 01:46:48 +01:00
|
|
|
// only start a new one if we removed the one that is checking
|
2010-01-17 22:42:14 +01:00
|
|
|
TORRENT_ASSERT(done != m_queued_for_checking.end());
|
2009-02-03 18:35:41 +01:00
|
|
|
if (done == m_queued_for_checking.end()) return;
|
|
|
|
|
|
|
|
if (next_check != t && t->state() == torrent_status::checking_files)
|
|
|
|
next_check->start_checking();
|
2010-01-17 22:42:14 +01:00
|
|
|
|
2008-06-12 23:22:24 +02:00
|
|
|
m_queued_for_checking.erase(done);
|
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
|
|
|
{
|
2008-04-09 22:09:36 +02:00
|
|
|
boost::shared_ptr<torrent> tptr = h.m_torrent.lock();
|
|
|
|
if (!tptr)
|
|
|
|
#ifdef BOOST_NO_EXCEPTIONS
|
|
|
|
return;
|
|
|
|
#else
|
2009-02-23 02:21:19 +01:00
|
|
|
throw_invalid_handle();
|
2008-04-09 22:09:36 +02:00
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
session_impl::torrent_map::iterator i =
|
2008-04-09 22:09:36 +02:00
|
|
|
m_torrents.find(tptr->torrent_file().info_hash());
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
if (i != m_torrents.end())
|
|
|
|
{
|
|
|
|
torrent& t = *i->second;
|
2007-10-13 05:33:33 +02:00
|
|
|
if (options & session::delete_files)
|
|
|
|
t.delete_files();
|
2006-10-11 22:57:54 +02:00
|
|
|
t.abort();
|
|
|
|
|
2008-11-29 22:33:21 +01:00
|
|
|
#ifdef TORRENT_DEBUG
|
2006-10-11 22:57:54 +02:00
|
|
|
sha1_hash i_hash = t.torrent_file().info_hash();
|
2010-02-14 02:39:55 +01:00
|
|
|
#endif
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (i == m_next_dht_torrent)
|
|
|
|
++m_next_dht_torrent;
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
2010-02-05 09:23:17 +01:00
|
|
|
if (i == m_next_lsd_torrent)
|
|
|
|
++m_next_lsd_torrent;
|
|
|
|
if (i == m_next_connect_torrent)
|
|
|
|
++m_next_connect_torrent;
|
|
|
|
|
2008-10-26 10:23:00 +01:00
|
|
|
t.set_queue_position(-1);
|
2006-10-11 22:57:54 +02:00
|
|
|
m_torrents.erase(i);
|
2010-02-05 09:23:17 +01:00
|
|
|
|
2010-02-14 02:39:55 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (m_next_dht_torrent == m_torrents.end())
|
|
|
|
m_next_dht_torrent = m_torrents.begin();
|
|
|
|
#endif
|
2010-02-05 09:23:17 +01:00
|
|
|
if (m_next_lsd_torrent == m_torrents.end())
|
|
|
|
m_next_lsd_torrent = m_torrents.begin();
|
|
|
|
if (m_next_connect_torrent == m_torrents.end())
|
|
|
|
m_next_connect_torrent = m_torrents.begin();
|
|
|
|
|
2008-10-26 05:10:27 +01:00
|
|
|
std::list<boost::shared_ptr<torrent> >::iterator k
|
|
|
|
= std::find(m_queued_for_checking.begin(), m_queued_for_checking.end(), tptr);
|
|
|
|
if (k != m_queued_for_checking.end()) m_queued_for_checking.erase(k);
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_torrents.find(i_hash) == m_torrents.end());
|
2006-10-11 22:57:54 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool session_impl::listen_on(
|
|
|
|
std::pair<int, int> const& port_range
|
2010-06-17 19:14:56 +02:00
|
|
|
, const char* net_interface, int flags)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
tcp::endpoint new_interface;
|
|
|
|
if (net_interface && std::strlen(net_interface) > 0)
|
2008-11-05 06:39:18 +01:00
|
|
|
{
|
|
|
|
error_code ec;
|
|
|
|
new_interface = tcp::endpoint(address::from_string(net_interface, ec), port_range.first);
|
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
|
|
(*m_logger) << time_now_string() << "listen_on: " << net_interface
|
|
|
|
<< " failed: " << ec.message() << "\n";
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
else
|
2007-09-22 18:27:29 +02:00
|
|
|
new_interface = tcp::endpoint(address_v4::any(), port_range.first);
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2007-09-22 18:27:29 +02:00
|
|
|
m_listen_port_retries = port_range.second - port_range.first;
|
2006-10-11 22:57:54 +02:00
|
|
|
|
|
|
|
// if the interface is the same and the socket is open
|
|
|
|
// don't do anything
|
|
|
|
if (new_interface == m_listen_interface
|
2007-09-22 18:27:29 +02:00
|
|
|
&& !m_listen_sockets.empty()) return true;
|
2006-10-11 22:57:54 +02:00
|
|
|
|
2007-03-16 22:45:29 +01:00
|
|
|
m_listen_interface = new_interface;
|
|
|
|
|
2010-06-17 19:14:56 +02:00
|
|
|
open_listen_port(flags & session::listen_reuse_address);
|
2007-03-16 22:45:29 +01:00
|
|
|
|
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
|
|
|
m_logger = create_log("main_session", listen_port(), false);
|
2007-04-10 09:52:58 +02:00
|
|
|
(*m_logger) << time_now_string() << "\n";
|
2006-11-15 22:39:58 +01:00
|
|
|
#endif
|
|
|
|
|
2007-09-22 18:27:29 +02:00
|
|
|
return !m_listen_sockets.empty();
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned short session_impl::listen_port() const
|
|
|
|
{
|
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
|
2010-04-13 07:59:59 +02:00
|
|
|
if (m_socks_listen_socket && m_socks_listen_socket->is_open()
|
2010-04-13 06:30:34 +02:00
|
|
|
&& m_peer_proxy.hostname == m_tracker_proxy.hostname)
|
|
|
|
return m_socks_listen_port;
|
|
|
|
|
|
|
|
// if not, don't tell the tracker anything if we're in anonymous
|
|
|
|
// mode. We don't want to leak our listen port since it can
|
|
|
|
// potentially identify us if it is leaked elsewere
|
|
|
|
if (m_settings.anonymous_mode) 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
|
|
|
}
|
|
|
|
|
2007-04-04 04:06:07 +02:00
|
|
|
void session_impl::announce_lsd(sha1_hash const& ih)
|
|
|
|
{
|
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())
|
|
|
|
m_lsd->announce(ih, m_listen_interface.port());
|
2007-04-04 04:06:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih)
|
|
|
|
{
|
2010-07-14 06:16:38 +02:00
|
|
|
TORRENT_ASSERT(is_network_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()
|
|
|
|
&& !m_settings.allow_i2p_mixed)) return;
|
2007-04-04 04:06:07 +02:00
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2007-04-10 09:52:58 +02:00
|
|
|
(*m_logger) << time_now_string()
|
2007-04-04 04:06:07 +02:00
|
|
|
<< ": added peer from local discovery: " << peer << "\n";
|
|
|
|
#endif
|
2009-05-16 00:07:19 +02:00
|
|
|
t->get_policy().add_peer(peer, peer_id(0), peer_info::lsd, 0);
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::on_port_mapping(int mapping, int port
|
|
|
|
, error_code const& ec, int map_transport)
|
|
|
|
{
|
2010-07-14 06:16:38 +02:00
|
|
|
TORRENT_ASSERT(is_network_thread());
|
|
|
|
|
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
|
|
|
{
|
2007-09-22 18:27:29 +02:00
|
|
|
if (!m_listen_sockets.empty())
|
2008-04-06 21:17:58 +02:00
|
|
|
m_listen_sockets.front().external_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
|
|
|
}
|
|
|
|
|
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;
|
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;
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
s.num_peers = (int)m_connections.size();
|
2008-01-13 12:18:18 +01:00
|
|
|
s.num_unchoked = m_num_unchoked;
|
|
|
|
s.allowed_upload_slots = m_allowed_upload_slots;
|
|
|
|
|
2008-07-11 09:30:04 +02:00
|
|
|
s.total_redundant_bytes = m_total_redundant_bytes;
|
|
|
|
s.total_failed_bytes = m_total_failed_bytes;
|
|
|
|
|
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
|
|
|
|
2009-04-26 02:21:59 +02:00
|
|
|
s.up_bandwidth_bytes_queue = m_upload_rate.queued_bytes();
|
|
|
|
s.down_bandwidth_bytes_queue = m_download_rate.queued_bytes();
|
2008-12-13 06:12:12 +01:00
|
|
|
|
2008-01-13 12:18:18 +01:00
|
|
|
s.has_incoming_connections = m_incoming_connection;
|
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);
|
|
|
|
|
|
|
|
// 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);
|
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
|
|
|
|
{
|
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;
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
|
2010-03-04 17:42:39 +01:00
|
|
|
void session_impl::start_dht()
|
|
|
|
{ start_dht(m_dht_state); }
|
|
|
|
|
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;
|
|
|
|
|
2010-05-09 08:03:52 +02:00
|
|
|
if (m_listen_interface.port() != 0)
|
2010-06-17 19:14:56 +02:00
|
|
|
open_listen_port(false);
|
2010-05-09 08:03:52 +02:00
|
|
|
|
2007-02-25 10:42:43 +01:00
|
|
|
if (m_dht)
|
|
|
|
{
|
|
|
|
m_dht->stop();
|
2007-03-02 02:16:59 +01:00
|
|
|
m_dht = 0;
|
2007-02-25 10:42:43 +01:00
|
|
|
}
|
2010-05-30 03:33:03 +02:00
|
|
|
m_dht = new dht::dht_tracker(*this, m_udp_socket, m_dht_settings, &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);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_dht->start(startup_state);
|
2009-10-25 03:37:45 +01:00
|
|
|
|
|
|
|
// announce all torrents we have to the DHT
|
|
|
|
for (torrent_map::const_iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
2010-02-14 02:39:55 +01:00
|
|
|
i->second->dht_announce();
|
2009-10-25 03:37:45 +01:00
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2008-11-16 03:11:04 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
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;
|
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
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_dht);
|
2006-10-11 22:57:54 +02:00
|
|
|
m_dht->add_node(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::add_dht_router(std::pair<std::string, int> const& node)
|
|
|
|
{
|
2010-02-14 08:46:57 +01:00
|
|
|
char port[7];
|
|
|
|
snprintf(port, sizeof(port), "%d", node.second);
|
|
|
|
tcp::resolver::query q(node.first, port);
|
|
|
|
m_host_resolver.async_resolve(q,
|
|
|
|
bind(&session_impl::on_dht_router_name_lookup, this, _1, _2));
|
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
|
|
|
|
, tcp::resolver::iterator host)
|
|
|
|
{
|
|
|
|
if (e || host == tcp::resolver::iterator()) return;
|
|
|
|
// router nodes should be added before the DHT is started (and bootstrapped)
|
|
|
|
udp::endpoint ep(host->endpoint().address(), host->endpoint().port());
|
|
|
|
if (m_dht) m_dht->add_router_node(ep);
|
|
|
|
m_dht_router_nodes.push_back(ep);
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
#endif
|
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
|
|
|
void session_impl::set_pe_settings(pe_settings const& settings)
|
|
|
|
{
|
|
|
|
m_pe_settings = settings;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
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()
|
|
|
|
{
|
2010-07-14 06:16:38 +02:00
|
|
|
#if defined BOOST_HAS_PTHREADS
|
|
|
|
TORRENT_ASSERT(!is_network_thread());
|
|
|
|
#endif
|
2009-05-23 23:36:09 +02:00
|
|
|
|
2007-05-24 21:51:14 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_logger) << time_now_string() << "\n\n *** shutting down session *** \n\n";
|
|
|
|
#endif
|
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
|
|
|
|
2009-04-25 10:45:13 +02:00
|
|
|
// we need to wait for the disk-io thread to
|
|
|
|
// die first, to make sure it won't post any
|
|
|
|
// more messages to the io_service containing references
|
|
|
|
// to disk_io_pool inside the disk_io_thread. Once
|
|
|
|
// the main thread has handled all the outstanding requests
|
|
|
|
// we know it's safe to destruct the disk thread.
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_logger) << time_now_string() << " waiting for disk io thread\n";
|
|
|
|
#endif
|
|
|
|
m_disk_thread.join();
|
|
|
|
|
2007-05-24 21:51:14 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_logger) << time_now_string() << " waiting for main thread\n";
|
|
|
|
#endif
|
2006-10-11 22:57:54 +02:00
|
|
|
m_thread->join();
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_torrents.empty());
|
|
|
|
TORRENT_ASSERT(m_connections.empty());
|
2007-05-24 21:51:14 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_logger) << time_now_string() << " shutdown complete!\n";
|
|
|
|
#endif
|
2008-10-30 18:13:10 +01:00
|
|
|
TORRENT_ASSERT(m_connections.empty());
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_max_uploads(int limit)
|
|
|
|
{
|
2008-09-06 23:16:04 +02:00
|
|
|
TORRENT_ASSERT(limit >= 0 || limit == -1);
|
2007-08-21 20:33:28 +02:00
|
|
|
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2009-06-21 01:23:41 +02:00
|
|
|
if (limit < 0) limit = (std::numeric_limits<int>::max)();
|
2008-01-15 09:37:48 +01:00
|
|
|
if (m_max_uploads == limit) return;
|
2006-10-11 22:57:54 +02:00
|
|
|
m_max_uploads = limit;
|
2008-01-15 09:37:48 +01:00
|
|
|
m_allowed_upload_slots = limit;
|
2010-02-06 08:39:45 +01:00
|
|
|
if (m_allowed_upload_slots <= m_settings.num_optimistic_unchoke_slots / 2)
|
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_max_connections(int limit)
|
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2008-05-16 17:19:38 +02:00
|
|
|
if (limit <= 0)
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
limit = l.rlim_cur - m_settings.file_pool_size;
|
|
|
|
if (limit < 5) limit = 5;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
m_max_connections = limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_max_half_open_connections(int limit)
|
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-08-21 06:46:17 +02:00
|
|
|
if (limit <= 0) limit = (std::numeric_limits<int>::max)();
|
2007-05-05 02:29:33 +02:00
|
|
|
m_half_open.limit(limit);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2009-05-14 19:21:19 +02:00
|
|
|
void session_impl::set_local_download_rate_limit(int bytes_per_second)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
if (bytes_per_second <= 0) bytes_per_second = 0;
|
|
|
|
m_local_download_channel.throttle(bytes_per_second);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_impl::set_local_upload_rate_limit(int bytes_per_second)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
if (bytes_per_second <= 0) bytes_per_second = 0;
|
|
|
|
m_local_upload_channel.throttle(bytes_per_second);
|
|
|
|
}
|
|
|
|
|
2007-07-03 01:48:06 +02:00
|
|
|
void session_impl::set_download_rate_limit(int bytes_per_second)
|
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2009-05-14 19:21:19 +02:00
|
|
|
if (bytes_per_second <= 0) bytes_per_second = 0;
|
|
|
|
m_download_channel.throttle(bytes_per_second);
|
2007-07-03 01:48:06 +02:00
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
void session_impl::set_upload_rate_limit(int bytes_per_second)
|
|
|
|
{
|
2007-08-21 20:33:28 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2009-05-14 19:21:19 +02:00
|
|
|
if (bytes_per_second <= 0) bytes_per_second = 0;
|
|
|
|
m_upload_channel.throttle(bytes_per_second);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-10-11 22:57:54 +02:00
|
|
|
std::auto_ptr<alert> session_impl::pop_alert()
|
|
|
|
{
|
2007-08-21 21:18:06 +02:00
|
|
|
// too expensive
|
|
|
|
// INVARIANT_CHECK;
|
2007-08-21 20:33:28 +02:00
|
|
|
|
2010-07-14 06:16:38 +02:00
|
|
|
return m_alerts.get();
|
2006-10-11 22:57:54 +02: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
|
|
|
|
2008-07-06 14:22:56 +02:00
|
|
|
void session_impl::set_alert_mask(int m)
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2008-07-06 14:22:56 +02:00
|
|
|
m_alerts.set_alert_mask(m);
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
|
2008-10-07 07:46:42 +02:00
|
|
|
size_t session_impl::set_alert_queue_size_limit(size_t queue_size_limit_)
|
|
|
|
{
|
|
|
|
return m_alerts.set_alert_queue_size_limit(queue_size_limit_);
|
|
|
|
}
|
|
|
|
|
2009-05-14 19:21:19 +02:00
|
|
|
int session_impl::local_upload_rate_limit() const
|
2007-01-02 00:51:24 +01:00
|
|
|
{
|
2009-05-14 19:21:19 +02:00
|
|
|
return m_local_upload_channel.throttle();
|
|
|
|
}
|
2007-08-21 20:33:28 +02:00
|
|
|
|
2009-05-14 19:21:19 +02:00
|
|
|
int session_impl::local_download_rate_limit() const
|
|
|
|
{
|
|
|
|
return m_local_download_channel.throttle();
|
|
|
|
}
|
2007-08-21 20:33:28 +02:00
|
|
|
|
2009-05-14 19:21:19 +02:00
|
|
|
int session_impl::upload_rate_limit() const
|
|
|
|
{
|
|
|
|
return m_upload_channel.throttle();
|
2007-01-02 00:51:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int session_impl::download_rate_limit() const
|
|
|
|
{
|
2009-05-14 19:21:19 +02:00
|
|
|
return m_download_channel.throttle();
|
2007-01-02 00:51:24 +01: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
|
2007-05-31 02:21:54 +02:00
|
|
|
, m_listen_interface.address()
|
2007-09-29 23:31:51 +02:00
|
|
|
, bind(&session_impl::on_lsd_peer, this, _1, _2));
|
2010-03-26 18:45:16 +01:00
|
|
|
if (m_settings.broadcast_lsd)
|
|
|
|
m_lsd->use_broadcast(true);
|
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
|
|
|
|
, this, _1, _2, _3, 0)
|
|
|
|
, 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)
|
|
|
|
{
|
|
|
|
m_tcp_mapping[0] = m_natpmp->add_mapping(natpmp::tcp
|
|
|
|
, m_listen_interface.port(), m_listen_interface.port());
|
|
|
|
}
|
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());
|
|
|
|
}
|
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_half_open
|
|
|
|
, m_listen_interface.address()
|
|
|
|
, m_settings.user_agent
|
|
|
|
, boost::bind(&session_impl::on_port_mapping
|
|
|
|
, this, _1, _2, _3, 1)
|
|
|
|
, boost::bind(&session_impl::on_port_map_log
|
|
|
|
, this, _1, 1)
|
|
|
|
, m_settings.upnp_ignore_nonrouters);
|
|
|
|
|
|
|
|
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();
|
2008-04-13 21:19:22 +02:00
|
|
|
if (m_listen_interface.port() > 0)
|
|
|
|
{
|
|
|
|
m_tcp_mapping[1] = m_upnp->add_mapping(upnp::tcp
|
|
|
|
, m_listen_interface.port(), m_listen_interface.port());
|
|
|
|
}
|
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());
|
|
|
|
}
|
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;
|
|
|
|
}
|
2007-09-29 23:31:51 +02:00
|
|
|
m_upnp = 0;
|
2007-05-31 02:21:54 +02:00
|
|
|
}
|
|
|
|
|
2008-03-29 23:45:55 +01:00
|
|
|
void session_impl::set_external_address(address const& ip)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(ip != address());
|
|
|
|
|
2008-08-25 23:17:24 +02:00
|
|
|
if (is_local(ip)) return;
|
|
|
|
if (is_loopback(ip)) return;
|
2008-03-29 23:45:55 +01:00
|
|
|
if (m_external_address == ip) return;
|
|
|
|
|
|
|
|
m_external_address = ip;
|
2008-07-06 14:22:56 +02:00
|
|
|
if (m_alerts.should_post<external_ip_alert>())
|
|
|
|
m_alerts.post_alert(external_ip_alert(ip));
|
2008-03-29 23:45:55 +01:00
|
|
|
}
|
|
|
|
|
2007-09-29 18:14:03 +02:00
|
|
|
void session_impl::free_disk_buffer(char* buf)
|
|
|
|
{
|
|
|
|
m_disk_thread.free_buffer(buf);
|
|
|
|
}
|
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
|
|
|
{
|
2009-01-23 10:13:31 +01:00
|
|
|
return m_disk_thread.allocate_buffer(category);
|
2008-04-10 12:03:23 +02:00
|
|
|
}
|
2007-09-29 18:14:03 +02:00
|
|
|
|
|
|
|
std::pair<char*, int> session_impl::allocate_buffer(int size)
|
|
|
|
{
|
2007-12-27 22:43:11 +01:00
|
|
|
TORRENT_ASSERT(size > 0);
|
2007-09-29 18:14:03 +02:00
|
|
|
int num_buffers = (size + send_buffer_size - 1) / send_buffer_size;
|
2007-12-27 22:43:11 +01:00
|
|
|
TORRENT_ASSERT(num_buffers > 0);
|
|
|
|
|
2009-10-20 04:49:56 +02:00
|
|
|
mutex::scoped_lock l(m_send_buffer_mutex);
|
2007-09-29 18:14:03 +02:00
|
|
|
#ifdef TORRENT_STATS
|
2008-02-14 04:48:20 +01:00
|
|
|
TORRENT_ASSERT(m_buffer_allocations >= 0);
|
2007-09-29 18:14:03 +02:00
|
|
|
m_buffer_allocations += num_buffers;
|
|
|
|
m_buffer_usage_logger << log_time() << " protocol_buffer: "
|
|
|
|
<< (m_buffer_allocations * send_buffer_size) << std::endl;
|
|
|
|
#endif
|
2008-04-09 07:19:11 +02:00
|
|
|
#ifdef TORRENT_DISABLE_POOL_ALLOCATOR
|
|
|
|
int num_bytes = num_buffers * send_buffer_size;
|
|
|
|
return std::make_pair((char*)malloc(num_bytes), num_bytes);
|
|
|
|
#else
|
2007-09-29 18:14:03 +02:00
|
|
|
return std::make_pair((char*)m_send_buffers.ordered_malloc(num_buffers)
|
|
|
|
, num_buffers * send_buffer_size);
|
2008-04-09 07:19:11 +02:00
|
|
|
#endif
|
2007-09-29 18:14:03 +02:00
|
|
|
}
|
|
|
|
|
2010-01-31 21:32:12 +01:00
|
|
|
#if defined TORRENT_STATS && defined TORRENT_DISK_STATS
|
2008-12-26 08:00:21 +01:00
|
|
|
void session_impl::log_buffer_usage()
|
|
|
|
{
|
|
|
|
int send_buffer_capacity = 0;
|
|
|
|
int used_send_buffer = 0;
|
|
|
|
for (connection_map::const_iterator i = m_connections.begin()
|
|
|
|
, end(m_connections.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
send_buffer_capacity += (*i)->send_buffer_capacity();
|
|
|
|
used_send_buffer += (*i)->send_buffer_size();
|
|
|
|
}
|
|
|
|
TORRENT_ASSERT(send_buffer_capacity >= used_send_buffer);
|
|
|
|
m_buffer_usage_logger << log_time() << " send_buffer_size: " << send_buffer_capacity << std::endl;
|
|
|
|
m_buffer_usage_logger << log_time() << " used_send_buffer: " << used_send_buffer << std::endl;
|
|
|
|
m_buffer_usage_logger << log_time() << " send_buffer_utilization: "
|
|
|
|
<< (used_send_buffer * 100.f / send_buffer_capacity) << std::endl;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-09-29 18:14:03 +02:00
|
|
|
void session_impl::free_buffer(char* buf, int size)
|
|
|
|
{
|
2007-12-27 22:43:11 +01:00
|
|
|
TORRENT_ASSERT(size > 0);
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(size % send_buffer_size == 0);
|
2007-09-29 18:14:03 +02:00
|
|
|
int num_buffers = size / send_buffer_size;
|
2007-12-27 22:43:11 +01:00
|
|
|
TORRENT_ASSERT(num_buffers > 0);
|
|
|
|
|
2009-10-20 04:49:56 +02:00
|
|
|
mutex::scoped_lock l(m_send_buffer_mutex);
|
2007-09-29 18:14:03 +02:00
|
|
|
#ifdef TORRENT_STATS
|
|
|
|
m_buffer_allocations -= num_buffers;
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_buffer_allocations >= 0);
|
2007-09-29 18:14:03 +02:00
|
|
|
m_buffer_usage_logger << log_time() << " protocol_buffer: "
|
|
|
|
<< (m_buffer_allocations * send_buffer_size) << std::endl;
|
|
|
|
#endif
|
2008-04-09 07:19:11 +02:00
|
|
|
#ifdef TORRENT_DISABLE_POOL_ALLOCATOR
|
|
|
|
free(buf);
|
|
|
|
#else
|
2007-09-29 18:14:03 +02:00
|
|
|
m_send_buffers.ordered_free(buf, num_buffers);
|
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
|
|
|
|
2008-11-29 22:33:21 +01:00
|
|
|
#ifdef TORRENT_DEBUG
|
2007-08-21 20:33:28 +02:00
|
|
|
void session_impl::check_invariant() const
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2009-08-30 09:38:52 +02:00
|
|
|
int num_checking = 0;
|
|
|
|
for (check_queue_t::const_iterator i = m_queued_for_checking.begin()
|
|
|
|
, end(m_queued_for_checking.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if ((*i)->state() == torrent_status::checking_files) ++num_checking;
|
|
|
|
}
|
2008-11-19 01:46:48 +01:00
|
|
|
|
|
|
|
// the queue is either empty, or it has exactly one checking torrent in it
|
|
|
|
TORRENT_ASSERT(m_queued_for_checking.empty() || num_checking == 1);
|
|
|
|
|
2008-05-29 05:37:19 +02:00
|
|
|
std::set<int> unique;
|
|
|
|
int total_downloaders = 0;
|
|
|
|
for (torrent_map::const_iterator i = m_torrents.begin()
|
|
|
|
, end(m_torrents.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
int pos = i->second->queue_position();
|
|
|
|
if (pos < 0)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(pos == -1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
++total_downloaders;
|
|
|
|
unique.insert(i->second->queue_position());
|
|
|
|
}
|
2008-09-25 22:12:53 +02:00
|
|
|
TORRENT_ASSERT(int(unique.size()) == total_downloaders);
|
2008-05-29 05:37:19 +02:00
|
|
|
|
2008-10-19 00:35:10 +02:00
|
|
|
std::set<peer_connection*> unique_peers;
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_max_connections > 0);
|
2009-06-21 01:23:41 +02:00
|
|
|
TORRENT_ASSERT(m_max_uploads >= 0);
|
2010-02-09 04:04:41 +01:00
|
|
|
if (m_settings.choking_algorithm == session_settings::auto_expand_choker)
|
2009-04-04 09:55:34 +02:00
|
|
|
TORRENT_ASSERT(m_allowed_upload_slots >= m_max_uploads);
|
2007-08-16 14:41:46 +02:00
|
|
|
int unchokes = 0;
|
|
|
|
int num_optimistic = 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
|
|
|
|
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());
|
2009-01-28 07:14:21 +01:00
|
|
|
if (p->ignore_unchoke_slots()) continue;
|
2007-10-31 10:48:20 +01:00
|
|
|
if (!p->is_choked()) ++unchokes;
|
|
|
|
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
|
|
|
}
|
2007-10-31 10:48:20 +01:00
|
|
|
if (t && p->peer_info_struct())
|
2006-10-11 22:57:54 +02:00
|
|
|
{
|
2007-10-31 10:48:20 +01:00
|
|
|
TORRENT_ASSERT(t->get_policy().has_connection(p));
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
}
|
2010-02-02 19:39:32 +01:00
|
|
|
|
|
|
|
if (m_settings.num_optimistic_unchoke_slots)
|
|
|
|
TORRENT_ASSERT(num_optimistic <= m_settings.num_optimistic_unchoke_slots);
|
|
|
|
|
2007-08-21 23:51:29 +02:00
|
|
|
if (m_num_unchoked != unchokes)
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(false);
|
2007-08-21 23:51:29 +02:00
|
|
|
}
|
2007-11-27 03:46:19 +01:00
|
|
|
for (std::map<sha1_hash, boost::shared_ptr<torrent> >::const_iterator j
|
|
|
|
= m_torrents.begin(); j != m_torrents.end(); ++j)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(boost::get_pointer(j->second));
|
|
|
|
}
|
2006-10-11 22:57:54 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}}
|
|
|
|
|