2003-10-23 01:00:57 +02:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2003, Arvid Norberg
|
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions
|
|
|
|
are met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in
|
|
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
* Neither the name of the author nor the names of its
|
|
|
|
contributors may be used to endorse or promote products derived
|
|
|
|
from this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
2007-03-17 18:15:16 +01:00
|
|
|
|
|
|
|
#include "libtorrent/pch.hpp"
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
#include <ctime>
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <iterator>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <set>
|
|
|
|
#include <cctype>
|
2003-10-30 00:28:09 +01:00
|
|
|
#include <numeric>
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(push, 1)
|
|
|
|
#endif
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
#include <boost/filesystem/convenience.hpp>
|
2004-08-05 15:56:26 +02:00
|
|
|
#include <boost/bind.hpp>
|
2006-04-25 23:04:48 +02:00
|
|
|
#include <boost/thread/mutex.hpp>
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(pop)
|
|
|
|
#endif
|
|
|
|
|
2003-10-26 18:35:23 +01:00
|
|
|
#include "libtorrent/torrent_handle.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
#include "libtorrent/session.hpp"
|
|
|
|
#include "libtorrent/torrent_info.hpp"
|
2004-01-31 11:46:15 +01:00
|
|
|
#include "libtorrent/tracker_manager.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
#include "libtorrent/bencode.hpp"
|
|
|
|
#include "libtorrent/hasher.hpp"
|
|
|
|
#include "libtorrent/entry.hpp"
|
|
|
|
#include "libtorrent/peer.hpp"
|
2006-04-25 23:04:48 +02:00
|
|
|
#include "libtorrent/bt_peer_connection.hpp"
|
|
|
|
#include "libtorrent/web_peer_connection.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
#include "libtorrent/peer_id.hpp"
|
2003-12-22 08:14:35 +01:00
|
|
|
#include "libtorrent/alert.hpp"
|
|
|
|
#include "libtorrent/identify_client.hpp"
|
2004-01-18 20:12:18 +01:00
|
|
|
#include "libtorrent/alert_types.hpp"
|
2006-11-14 01:08:16 +01:00
|
|
|
#include "libtorrent/extensions.hpp"
|
2006-10-11 16:02:21 +02:00
|
|
|
#include "libtorrent/aux_/session_impl.hpp"
|
2007-04-25 20:26:35 +02:00
|
|
|
#include "libtorrent/instantiate_connection.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
using namespace libtorrent;
|
2006-01-07 14:48:14 +01:00
|
|
|
using boost::tuples::tuple;
|
|
|
|
using boost::tuples::get;
|
|
|
|
using boost::tuples::make_tuple;
|
2006-01-07 16:41:20 +01:00
|
|
|
using boost::filesystem::complete;
|
2006-01-09 01:07:00 +01:00
|
|
|
using boost::bind;
|
2006-04-25 23:04:48 +02:00
|
|
|
using boost::mutex;
|
2006-10-11 16:02:21 +02:00
|
|
|
using libtorrent::aux::session_impl;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
// wait 60 seconds before retrying a failed tracker
|
2004-04-02 00:29:51 +02:00
|
|
|
tracker_retry_delay_min = 60
|
|
|
|
// when tracker_failed_max trackers
|
|
|
|
// has failed, wait 10 minutes instead
|
|
|
|
, tracker_retry_delay_max = 10 * 60
|
|
|
|
, tracker_failed_max = 5
|
2003-10-23 01:00:57 +02:00
|
|
|
};
|
|
|
|
|
2005-07-10 12:42:00 +02:00
|
|
|
int calculate_block_size(const torrent_info& i, int default_block_size)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2005-07-10 12:42:00 +02:00
|
|
|
if (default_block_size < 1024) default_block_size = 1024;
|
2003-12-21 18:28:27 +01:00
|
|
|
|
|
|
|
// if pieces are too small, adjust the block size
|
|
|
|
if (i.piece_length() < default_block_size)
|
|
|
|
{
|
2004-03-07 21:50:56 +01:00
|
|
|
return static_cast<int>(i.piece_length());
|
2003-12-21 18:28:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, go with the default
|
|
|
|
return default_block_size;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2004-01-12 04:05:10 +01:00
|
|
|
struct find_peer_by_ip
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
find_peer_by_ip(tcp::endpoint const& a, const torrent* t)
|
2004-01-25 13:37:15 +01:00
|
|
|
: ip(a)
|
|
|
|
, tor(t)
|
|
|
|
{ assert(t != 0); }
|
2004-01-12 04:05:10 +01:00
|
|
|
|
2006-10-11 16:02:21 +02:00
|
|
|
bool operator()(const session_impl::connection_map::value_type& c) const
|
2004-01-12 04:05:10 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
tcp::endpoint sender = c.first->remote_endpoint();
|
|
|
|
if (sender.address() != ip.address()) return false;
|
|
|
|
if (tor != c.second->associated_torrent().lock().get()) return false;
|
2004-01-12 04:05:10 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
tcp::endpoint const& ip;
|
|
|
|
torrent const* tor;
|
2004-01-12 04:05:10 +01:00
|
|
|
};
|
|
|
|
|
2004-01-13 04:08:59 +01:00
|
|
|
struct peer_by_id
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
peer_by_id(const peer_id& i): pid(i) {}
|
2004-01-13 04:08:59 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
bool operator()(const std::pair<tcp::endpoint, peer_connection*>& p) const
|
2004-01-13 04:08:59 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
if (p.second->pid() != pid) return false;
|
2004-01-13 04:08:59 +01:00
|
|
|
// have a special case for all zeros. We can have any number
|
2006-04-25 23:04:48 +02:00
|
|
|
// of peers with that pid, since it's used to indicate no pid.
|
|
|
|
if (std::count(pid.begin(), pid.end(), 0) == 20) return false;
|
2004-01-13 04:08:59 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
peer_id const& pid;
|
2004-01-13 04:08:59 +01:00
|
|
|
};
|
2006-11-20 22:03:58 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_LOGGING
|
|
|
|
void print_legend(boost::shared_ptr<logger> l)
|
|
|
|
{
|
2006-11-21 16:51:28 +01:00
|
|
|
(*l) << "1. time, seconds\n"
|
|
|
|
<< "2. hard send quota, bytes\n"
|
|
|
|
<< "3. soft send quota, bytes\n"
|
|
|
|
<< "4. excess bytes sent\n"
|
|
|
|
<< "5. excess bytes sent last time slice\n"
|
|
|
|
<< "6. hard receive quota, bytes\n"
|
|
|
|
<< "7. soft receive quota, bytes\n"
|
|
|
|
<< "8. excess bytes received\n"
|
|
|
|
<< "9. excess bytes received last time slice\n"
|
|
|
|
<< "10. num peers\n"
|
|
|
|
<< "11. max ul quota limit\n"
|
|
|
|
<< "12. max dl quota limit\n"
|
|
|
|
<< "13. bytes sent\n"
|
|
|
|
<< "14. bytes sent 10 seconds mean\n"
|
|
|
|
<< "15. bytes received\n"
|
|
|
|
<< "16. bytes received 10 seconds mean\n"
|
2006-11-24 15:22:52 +01:00
|
|
|
<< "17. total payload download\n"
|
|
|
|
<< "18. total web seed payload download\n"
|
2006-12-15 11:42:56 +01:00
|
|
|
<< "19. total redundant bytes downloaded\n"
|
2006-11-20 22:03:58 +01:00
|
|
|
<< "\n";
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace libtorrent
|
|
|
|
{
|
2003-12-07 06:53:04 +01:00
|
|
|
torrent::torrent(
|
2006-10-11 16:02:21 +02:00
|
|
|
session_impl& ses
|
|
|
|
, aux::checker_impl& checker
|
2005-10-16 01:07:39 +02:00
|
|
|
, torrent_info const& tf
|
2004-06-14 01:30:42 +02:00
|
|
|
, boost::filesystem::path const& save_path
|
2006-04-25 23:04:48 +02:00
|
|
|
, tcp::endpoint const& net_interface
|
2005-07-10 12:42:00 +02:00
|
|
|
, bool compact_mode
|
2006-04-25 23:04:48 +02:00
|
|
|
, int block_size
|
2007-03-16 06:29:23 +01:00
|
|
|
, session_settings const& s
|
|
|
|
, storage_constructor_type sc)
|
2005-10-16 01:07:39 +02:00
|
|
|
: m_torrent_file(tf)
|
2003-10-23 01:00:57 +02:00
|
|
|
, m_abort(false)
|
2004-03-21 03:03:37 +01:00
|
|
|
, m_paused(false)
|
2004-07-24 13:54:17 +02:00
|
|
|
, m_just_paused(false)
|
2004-01-21 14:16:11 +01:00
|
|
|
, m_event(tracker_request::started)
|
2004-06-14 01:30:42 +02:00
|
|
|
, m_block_size(0)
|
|
|
|
, m_storage(0)
|
2007-04-05 00:27:36 +02:00
|
|
|
, m_next_request(time_now())
|
2003-10-23 01:00:57 +02:00
|
|
|
, m_duration(1800)
|
2005-02-21 14:59:24 +01:00
|
|
|
, m_complete(-1)
|
|
|
|
, m_incomplete(-1)
|
2006-12-15 18:47:21 +01:00
|
|
|
, m_host_resolver(ses.m_io_service)
|
2007-05-02 21:47:38 +02:00
|
|
|
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
2007-01-29 08:39:33 +01:00
|
|
|
, m_resolving_country(false)
|
|
|
|
, m_resolve_countries(false)
|
2007-05-02 21:47:38 +02:00
|
|
|
#endif
|
2007-04-04 04:06:07 +02:00
|
|
|
, m_announce_timer(ses.m_io_service)
|
2007-05-17 02:01:51 +02:00
|
|
|
, m_last_dht_announce(time_now() - minutes(15))
|
2004-07-24 13:54:17 +02:00
|
|
|
, m_policy()
|
2003-10-23 01:00:57 +02:00
|
|
|
, m_ses(ses)
|
2005-10-13 09:59:05 +02:00
|
|
|
, m_checker(checker)
|
2004-06-14 01:30:42 +02:00
|
|
|
, m_picker(0)
|
2004-09-12 12:12:16 +02:00
|
|
|
, m_trackers(m_torrent_file.trackers())
|
2004-01-31 11:20:19 +01:00
|
|
|
, m_last_working_tracker(-1)
|
2003-10-23 01:00:57 +02:00
|
|
|
, m_currently_trying_tracker(0)
|
2004-04-02 00:29:51 +02:00
|
|
|
, m_failed_trackers(0)
|
2003-12-01 06:01:40 +01:00
|
|
|
, m_time_scaler(0)
|
2003-12-07 06:53:04 +01:00
|
|
|
, m_num_pieces(0)
|
2007-03-17 00:28:26 +01:00
|
|
|
, m_sequenced_download_threshold(0)
|
2003-12-22 08:14:35 +01:00
|
|
|
, m_got_tracker_response(false)
|
2004-01-12 04:05:10 +01:00
|
|
|
, m_ratio(0.f)
|
2004-04-18 14:28:02 +02:00
|
|
|
, m_total_failed_bytes(0)
|
2006-04-25 23:04:48 +02:00
|
|
|
, m_total_redundant_bytes(0)
|
2006-05-20 17:30:40 +02:00
|
|
|
, m_net_interface(net_interface.address(), 0)
|
2004-10-18 12:36:47 +02:00
|
|
|
, m_save_path(complete(save_path))
|
2005-05-13 02:39:39 +02:00
|
|
|
, m_compact_mode(compact_mode)
|
2005-07-10 12:42:00 +02:00
|
|
|
, m_default_block_size(block_size)
|
2005-10-16 11:15:46 +02:00
|
|
|
, m_connections_initialized(true)
|
2006-04-25 23:04:48 +02:00
|
|
|
, m_settings(s)
|
2007-03-16 06:29:23 +01:00
|
|
|
, m_storage_constructor(sc)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
m_initial_done = 0;
|
2006-11-20 22:03:58 +01:00
|
|
|
#endif
|
|
|
|
#ifdef TORRENT_LOGGING
|
|
|
|
m_log = ses.create_log("torrent_"
|
|
|
|
+ boost::lexical_cast<std::string>(tf.info_hash())
|
2006-11-21 16:51:28 +01:00
|
|
|
, m_ses.listen_port(), false);
|
2006-11-20 22:03:58 +01:00
|
|
|
print_legend(m_log);
|
|
|
|
m_second_count = 0;
|
|
|
|
std::fill_n(m_ul_history, 10, 0);
|
|
|
|
std::fill_n(m_dl_history, 10, 0);
|
2006-11-24 15:22:52 +01:00
|
|
|
|
|
|
|
m_peer_log = ses.create_log("torrent_peers_"
|
|
|
|
+ boost::lexical_cast<std::string>(tf.info_hash())
|
|
|
|
, m_ses.listen_port(), false);
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-10-29 15:21:09 +02:00
|
|
|
m_uploads_quota.min = 2;
|
|
|
|
m_connections_quota.min = 2;
|
2005-03-07 16:39:06 +01:00
|
|
|
// this will be corrected the next time the main session
|
|
|
|
// distributes resources, i.e. on average in 0.5 seconds
|
|
|
|
m_connections_quota.given = 100;
|
2007-01-11 03:59:38 +01:00
|
|
|
m_uploads_quota.max = std::numeric_limits<int>::max();
|
|
|
|
m_connections_quota.max = std::numeric_limits<int>::max();
|
2004-07-24 13:54:17 +02:00
|
|
|
m_policy.reset(new policy(this));
|
2004-06-14 01:30:42 +02:00
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
2007-04-11 19:44:15 +02:00
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
torrent::torrent(
|
2006-10-11 16:02:21 +02:00
|
|
|
session_impl& ses
|
|
|
|
, aux::checker_impl& checker
|
2004-06-14 01:30:42 +02:00
|
|
|
, char const* tracker_url
|
|
|
|
, sha1_hash const& info_hash
|
2006-11-14 01:08:16 +01:00
|
|
|
, char const* name
|
2004-06-14 01:30:42 +02:00
|
|
|
, boost::filesystem::path const& save_path
|
2006-04-25 23:04:48 +02:00
|
|
|
, tcp::endpoint const& net_interface
|
2005-07-10 12:42:00 +02:00
|
|
|
, bool compact_mode
|
2006-04-25 23:04:48 +02:00
|
|
|
, int block_size
|
2007-03-16 06:29:23 +01:00
|
|
|
, session_settings const& s
|
|
|
|
, storage_constructor_type sc)
|
2004-10-10 02:42:48 +02:00
|
|
|
: m_torrent_file(info_hash)
|
2004-06-14 01:30:42 +02:00
|
|
|
, m_abort(false)
|
|
|
|
, m_paused(false)
|
2004-07-24 13:54:17 +02:00
|
|
|
, m_just_paused(false)
|
2004-06-14 01:30:42 +02:00
|
|
|
, m_event(tracker_request::started)
|
|
|
|
, m_block_size(0)
|
|
|
|
, m_storage(0)
|
2007-04-05 00:27:36 +02:00
|
|
|
, m_next_request(time_now())
|
2004-06-14 01:30:42 +02:00
|
|
|
, m_duration(1800)
|
2005-02-21 14:59:24 +01:00
|
|
|
, m_complete(-1)
|
|
|
|
, m_incomplete(-1)
|
2006-12-15 18:47:21 +01:00
|
|
|
, m_host_resolver(ses.m_io_service)
|
2007-05-02 21:47:38 +02:00
|
|
|
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
2007-01-29 08:39:33 +01:00
|
|
|
, m_resolving_country(false)
|
|
|
|
, m_resolve_countries(false)
|
2007-05-02 21:47:38 +02:00
|
|
|
#endif
|
2007-04-04 04:06:07 +02:00
|
|
|
, m_announce_timer(ses.m_io_service)
|
2007-05-17 02:01:51 +02:00
|
|
|
, m_last_dht_announce(time_now() - minutes(15))
|
2004-07-24 13:54:17 +02:00
|
|
|
, m_policy()
|
2004-06-14 01:30:42 +02:00
|
|
|
, m_ses(ses)
|
2005-10-13 09:59:05 +02:00
|
|
|
, m_checker(checker)
|
2004-06-14 01:30:42 +02:00
|
|
|
, m_picker(0)
|
|
|
|
, m_last_working_tracker(-1)
|
|
|
|
, m_currently_trying_tracker(0)
|
|
|
|
, m_failed_trackers(0)
|
|
|
|
, m_time_scaler(0)
|
|
|
|
, m_num_pieces(0)
|
2007-03-17 00:28:26 +01:00
|
|
|
, m_sequenced_download_threshold(0)
|
2004-06-14 01:30:42 +02:00
|
|
|
, m_got_tracker_response(false)
|
|
|
|
, m_ratio(0.f)
|
|
|
|
, m_total_failed_bytes(0)
|
2006-04-25 23:04:48 +02:00
|
|
|
, m_total_redundant_bytes(0)
|
2006-05-20 17:30:40 +02:00
|
|
|
, m_net_interface(net_interface.address(), 0)
|
2004-10-18 12:36:47 +02:00
|
|
|
, m_save_path(complete(save_path))
|
2005-05-13 02:39:39 +02:00
|
|
|
, m_compact_mode(compact_mode)
|
2005-07-10 12:42:00 +02:00
|
|
|
, m_default_block_size(block_size)
|
2005-10-16 11:15:46 +02:00
|
|
|
, m_connections_initialized(false)
|
2006-04-25 23:04:48 +02:00
|
|
|
, m_settings(s)
|
2007-03-16 06:29:23 +01:00
|
|
|
, m_storage_constructor(sc)
|
2004-06-14 01:30:42 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
m_initial_done = 0;
|
|
|
|
#endif
|
2006-11-20 22:03:58 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_LOGGING
|
|
|
|
m_log = ses.create_log("torrent_"
|
|
|
|
+ boost::lexical_cast<std::string>(info_hash)
|
|
|
|
, m_ses.listen_port(), true);
|
|
|
|
print_legend(m_log);
|
|
|
|
m_second_count = 0;
|
|
|
|
std::fill_n(m_ul_history, 10, 0);
|
|
|
|
std::fill_n(m_dl_history, 10, 0);
|
|
|
|
#endif
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
if (name) m_name.reset(new std::string(name));
|
|
|
|
|
2004-10-29 15:21:09 +02:00
|
|
|
m_uploads_quota.min = 2;
|
|
|
|
m_connections_quota.min = 2;
|
2005-03-07 16:39:06 +01:00
|
|
|
// this will be corrected the next time the main session
|
|
|
|
// distributes resources, i.e. on average in 0.5 seconds
|
|
|
|
m_connections_quota.given = 100;
|
2004-10-29 15:21:09 +02:00
|
|
|
m_uploads_quota.max = std::numeric_limits<int>::max();
|
|
|
|
m_connections_quota.max = std::numeric_limits<int>::max();
|
2007-02-21 18:15:47 +01:00
|
|
|
if (tracker_url)
|
|
|
|
{
|
|
|
|
m_trackers.push_back(announce_entry(tracker_url));
|
|
|
|
m_torrent_file.add_tracker(tracker_url);
|
|
|
|
}
|
2005-10-16 01:07:39 +02:00
|
|
|
|
2004-07-24 13:54:17 +02:00
|
|
|
m_policy.reset(new policy(this));
|
2007-04-11 19:44:15 +02:00
|
|
|
}
|
2007-04-11 19:22:19 +02:00
|
|
|
|
2007-04-11 19:44:15 +02:00
|
|
|
void torrent::start()
|
|
|
|
{
|
2007-04-11 19:22:19 +02:00
|
|
|
boost::weak_ptr<torrent> self(shared_from_this());
|
2007-04-04 04:06:07 +02:00
|
|
|
m_announce_timer.expires_from_now(seconds(1));
|
|
|
|
m_announce_timer.async_wait(m_ses.m_strand.wrap(
|
2007-04-11 19:22:19 +02:00
|
|
|
bind(&torrent::on_announce_disp, self, _1)));
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2007-02-12 10:20:49 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
bool torrent::should_announce_dht() const
|
|
|
|
{
|
|
|
|
// don't announce private torrents
|
|
|
|
if (m_torrent_file.is_valid() && m_torrent_file.priv()) return false;
|
|
|
|
|
|
|
|
if (m_trackers.empty()) return true;
|
|
|
|
|
|
|
|
return m_failed_trackers > 0 || !m_ses.settings().use_dht_as_fallback;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-12-14 06:56:12 +01:00
|
|
|
torrent::~torrent()
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
// The invariant can't be maintained here, since the torrent
|
|
|
|
// is being destructed, all weak references to it have been
|
|
|
|
// reset, which means that all its peers already have an
|
|
|
|
// invalidated torrent pointer (so it cannot be verified to be correct)
|
|
|
|
|
|
|
|
// i.e. the invariant can only be maintained if all connections have
|
|
|
|
// been closed by the time the torrent is destructed. And they are
|
|
|
|
// supposed to be closed. So we can still do the invariant check.
|
|
|
|
|
|
|
|
assert(m_connections.empty());
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2006-10-11 16:02:21 +02:00
|
|
|
if (m_ses.is_aborted())
|
2006-04-25 23:04:48 +02:00
|
|
|
m_abort = true;
|
2005-11-08 01:56:26 +01:00
|
|
|
if (!m_connections.empty())
|
|
|
|
disconnect_all();
|
2003-12-14 06:56:12 +01:00
|
|
|
}
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
std::string torrent::name() const
|
|
|
|
{
|
|
|
|
if (valid_metadata()) return m_torrent_file.name();
|
|
|
|
if (m_name) return *m_name;
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
void torrent::add_extension(boost::shared_ptr<torrent_plugin> ext)
|
|
|
|
{
|
|
|
|
m_extensions.push_back(ext);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
void torrent::init()
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
assert(m_torrent_file.is_valid());
|
2004-11-18 23:33:50 +01:00
|
|
|
assert(m_torrent_file.num_files() > 0);
|
2005-08-15 00:04:58 +02:00
|
|
|
assert(m_torrent_file.total_size() >= 0);
|
2004-06-14 01:30:42 +02:00
|
|
|
|
|
|
|
m_have_pieces.resize(m_torrent_file.num_pieces(), false);
|
2007-03-16 06:29:23 +01:00
|
|
|
m_storage.reset(new piece_manager(m_torrent_file, m_save_path
|
|
|
|
, m_ses.m_files, m_storage_constructor));
|
2005-07-10 12:42:00 +02:00
|
|
|
m_block_size = calculate_block_size(m_torrent_file, m_default_block_size);
|
2007-03-17 18:28:59 +01:00
|
|
|
m_picker.reset(new piece_picker(
|
|
|
|
static_cast<int>(m_torrent_file.piece_length() / m_block_size)
|
|
|
|
, static_cast<int>((m_torrent_file.total_size()+m_block_size-1)/m_block_size)));
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
std::vector<std::string> const& url_seeds = m_torrent_file.url_seeds();
|
|
|
|
std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
|
|
|
|
, m_web_seeds.begin()));
|
2004-06-14 01:30:42 +02:00
|
|
|
}
|
|
|
|
|
2004-02-26 01:27:06 +01:00
|
|
|
void torrent::use_interface(const char* net_interface)
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2006-05-20 17:30:40 +02:00
|
|
|
m_net_interface = tcp::endpoint(address::from_string(net_interface), 0);
|
2004-02-26 01:27:06 +01:00
|
|
|
}
|
|
|
|
|
2007-04-11 19:22:19 +02:00
|
|
|
void torrent::on_announce_disp(boost::weak_ptr<torrent> p
|
|
|
|
, asio::error_code const& e)
|
2007-04-04 04:06:07 +02:00
|
|
|
{
|
|
|
|
if (e) return;
|
2007-04-11 19:22:19 +02:00
|
|
|
boost::shared_ptr<torrent> t = p.lock();
|
|
|
|
if (!t) return;
|
|
|
|
t->on_announce();
|
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::on_announce()
|
2007-04-29 22:49:30 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
try
|
|
|
|
#endif
|
2007-04-11 19:22:19 +02:00
|
|
|
{
|
|
|
|
boost::weak_ptr<torrent> self(shared_from_this());
|
2007-04-04 04:06:07 +02:00
|
|
|
|
2007-05-17 02:01:51 +02:00
|
|
|
// announce on local network every 5 minutes
|
|
|
|
m_announce_timer.expires_from_now(minutes(5));
|
2007-04-04 04:06:07 +02:00
|
|
|
m_announce_timer.async_wait(m_ses.m_strand.wrap(
|
2007-04-11 19:22:19 +02:00
|
|
|
bind(&torrent::on_announce_disp, self, _1)));
|
2007-04-04 04:06:07 +02:00
|
|
|
|
|
|
|
// announce with the local discovery service
|
|
|
|
m_ses.announce_lsd(m_torrent_file.info_hash());
|
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (!m_ses.m_dht) return;
|
2007-05-17 02:01:51 +02:00
|
|
|
ptime now = time_now();
|
|
|
|
if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
|
2007-04-04 04:06:07 +02:00
|
|
|
{
|
2007-05-17 02:01:51 +02:00
|
|
|
m_last_dht_announce = now;
|
2007-04-04 04:06:07 +02:00
|
|
|
// TODO: There should be a way to abort an announce operation on the dht.
|
|
|
|
// when the torrent is destructed
|
|
|
|
assert(m_ses.m_external_listen_port > 0);
|
|
|
|
m_ses.m_dht->announce(m_torrent_file.info_hash()
|
|
|
|
, m_ses.m_external_listen_port
|
|
|
|
, m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1)));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2007-04-29 22:49:30 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
std::cerr << e.what() << std::endl;
|
|
|
|
assert(false);
|
2007-05-16 03:17:14 +02:00
|
|
|
};
|
2007-04-29 22:49:30 +02:00
|
|
|
#endif
|
2007-04-04 04:06:07 +02:00
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
|
2006-08-29 03:15:24 +02:00
|
|
|
void torrent::on_dht_announce_response_disp(boost::weak_ptr<libtorrent::torrent> t
|
|
|
|
, std::vector<tcp::endpoint> const& peers)
|
|
|
|
{
|
|
|
|
boost::shared_ptr<libtorrent::torrent> tor = t.lock();
|
|
|
|
if (!tor) return;
|
|
|
|
tor->on_dht_announce_response(peers);
|
|
|
|
}
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
void torrent::on_dht_announce_response(std::vector<tcp::endpoint> const& peers)
|
|
|
|
{
|
2007-02-01 08:33:04 +01:00
|
|
|
if (peers.empty()) return;
|
|
|
|
|
|
|
|
if (m_ses.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(tracker_reply_alert(
|
|
|
|
get_handle(), peers.size(), "Got peers from DHT"));
|
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
std::for_each(peers.begin(), peers.end(), bind(
|
2007-04-10 23:23:13 +02:00
|
|
|
&policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0)
|
|
|
|
, peer_info::dht, 0));
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2004-07-24 13:54:17 +02:00
|
|
|
// returns true if it is time for this torrent to make another
|
|
|
|
// tracker request
|
|
|
|
bool torrent::should_request()
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
if (m_torrent_file.trackers().empty()) return false;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2004-07-24 13:54:17 +02:00
|
|
|
if (m_just_paused)
|
|
|
|
{
|
|
|
|
m_just_paused = false;
|
|
|
|
return true;
|
|
|
|
}
|
2007-04-05 00:27:36 +02:00
|
|
|
return !m_paused && m_next_request < time_now();
|
2004-07-24 13:54:17 +02:00
|
|
|
}
|
|
|
|
|
2005-08-11 01:32:39 +02:00
|
|
|
void torrent::tracker_warning(std::string const& msg)
|
|
|
|
{
|
2007-03-31 00:00:26 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2005-08-11 01:32:39 +02:00
|
|
|
if (m_ses.m_alerts.should_post(alert::warning))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(tracker_warning_alert(get_handle(), msg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-21 14:16:11 +01:00
|
|
|
void torrent::tracker_response(
|
2005-04-24 02:50:52 +02:00
|
|
|
tracker_request const&
|
2005-03-24 13:13:47 +01:00
|
|
|
, std::vector<peer_entry>& peer_list
|
2005-02-21 14:59:24 +01:00
|
|
|
, int interval
|
|
|
|
, int complete
|
2005-02-23 09:57:54 +01:00
|
|
|
, int incomplete)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
|
2007-03-31 00:00:26 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-04-02 00:29:51 +02:00
|
|
|
m_failed_trackers = 0;
|
2006-11-19 16:29:58 +01:00
|
|
|
// announce intervals less than 5 minutes
|
2004-01-25 13:37:15 +01:00
|
|
|
// are insane.
|
2004-09-16 19:18:10 +02:00
|
|
|
if (interval < 60 * 5) interval = 60 * 5;
|
2004-01-25 13:37:15 +01:00
|
|
|
|
2004-01-21 14:16:11 +01:00
|
|
|
m_last_working_tracker
|
2004-09-12 12:12:16 +02:00
|
|
|
= prioritize_tracker(m_currently_trying_tracker);
|
2004-01-21 14:16:11 +01:00
|
|
|
m_currently_trying_tracker = 0;
|
2003-10-23 18:55:52 +02:00
|
|
|
|
2004-01-21 14:16:11 +01:00
|
|
|
m_duration = interval;
|
2007-04-05 00:27:36 +02:00
|
|
|
m_next_request = time_now() + seconds(m_duration);
|
2003-10-23 18:55:52 +02:00
|
|
|
|
2005-02-21 14:59:24 +01:00
|
|
|
if (complete >= 0) m_complete = complete;
|
|
|
|
if (incomplete >= 0) m_incomplete = incomplete;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2004-01-21 14:16:11 +01:00
|
|
|
// connect to random peers from the list
|
|
|
|
std::random_shuffle(peer_list.begin(), peer_list.end());
|
2003-10-23 18:55:52 +02:00
|
|
|
|
2005-07-06 15:18:10 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2004-01-21 14:16:11 +01:00
|
|
|
std::stringstream s;
|
2004-01-22 23:45:52 +01:00
|
|
|
s << "TRACKER RESPONSE:\n"
|
|
|
|
"interval: " << m_duration << "\n"
|
|
|
|
"peers:\n";
|
2004-01-21 14:16:11 +01:00
|
|
|
for (std::vector<peer_entry>::const_iterator i = peer_list.begin();
|
2005-07-06 02:58:23 +02:00
|
|
|
i != peer_list.end(); ++i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2004-01-21 14:16:11 +01:00
|
|
|
s << " " << std::setfill(' ') << std::setw(16) << i->ip
|
2004-01-22 23:45:52 +01:00
|
|
|
<< " " << std::setw(5) << std::dec << i->port << " ";
|
2006-04-25 23:04:48 +02:00
|
|
|
if (!i->pid.is_all_zeros()) s << " " << i->pid << " " << identify_client(i->pid);
|
2004-01-22 23:45:52 +01:00
|
|
|
s << "\n";
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2004-01-21 14:16:11 +01:00
|
|
|
debug_log(s.str());
|
|
|
|
#endif
|
|
|
|
// for each of the peers we got from the tracker
|
|
|
|
for (std::vector<peer_entry>::iterator i = peer_list.begin();
|
2005-07-06 02:58:23 +02:00
|
|
|
i != peer_list.end(); ++i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2004-01-21 14:16:11 +01:00
|
|
|
// don't make connections to ourself
|
2006-04-25 23:04:48 +02:00
|
|
|
if (i->pid == m_ses.get_peer_id())
|
2004-01-21 14:16:11 +01:00
|
|
|
continue;
|
|
|
|
|
2007-03-07 19:50:38 +01:00
|
|
|
try
|
2005-07-06 02:58:23 +02:00
|
|
|
{
|
2007-03-07 19:50:38 +01:00
|
|
|
tcp::endpoint a(address::from_string(i->ip), i->port);
|
|
|
|
|
|
|
|
if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
|
|
|
|
{
|
2005-07-06 15:18:10 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2007-03-07 19:50:38 +01:00
|
|
|
debug_log("blocked ip from tracker: " + i->ip);
|
2005-07-06 02:58:23 +02:00
|
|
|
#endif
|
2007-04-17 07:56:43 +02:00
|
|
|
if (m_ses.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()
|
|
|
|
, "peer from tracker blocked by IP filter"));
|
|
|
|
}
|
|
|
|
|
2007-03-07 19:50:38 +01:00
|
|
|
continue;
|
|
|
|
}
|
2005-07-06 02:58:23 +02:00
|
|
|
|
2007-04-10 23:23:13 +02:00
|
|
|
m_policy->peer_from_tracker(a, i->pid, peer_info::tracker, 0);
|
2007-03-07 19:50:38 +01:00
|
|
|
}
|
|
|
|
catch (std::exception&)
|
|
|
|
{
|
|
|
|
// assume this is because we got a hostname instead of
|
|
|
|
// an ip address from the tracker
|
|
|
|
|
|
|
|
tcp::resolver::query q(i->ip, boost::lexical_cast<std::string>(i->port));
|
|
|
|
m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
|
|
|
|
bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid)));
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2007-05-03 03:49:14 +02:00
|
|
|
m_policy->pulse();
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-03-10 10:59:12 +01:00
|
|
|
if (m_ses.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
std::stringstream s;
|
|
|
|
s << "Got response from tracker: "
|
|
|
|
<< m_trackers[m_last_working_tracker].url;
|
|
|
|
m_ses.m_alerts.post_alert(tracker_reply_alert(
|
2007-02-01 08:33:04 +01:00
|
|
|
get_handle(), peer_list.size(), s.str()));
|
2005-03-10 10:59:12 +01:00
|
|
|
}
|
2003-12-22 08:14:35 +01:00
|
|
|
m_got_tracker_response = true;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2007-03-07 19:50:38 +01:00
|
|
|
void torrent::on_peer_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
|
|
|
|
, peer_id pid) try
|
|
|
|
{
|
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
if (e || host == tcp::resolver::iterator() ||
|
|
|
|
m_ses.is_aborted()) return;
|
|
|
|
|
|
|
|
if (m_ses.m_ip_filter.access(host->endpoint().address()) & ip_filter::blocked)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
debug_log("blocked ip from tracker: " + host->endpoint().address().to_string());
|
|
|
|
#endif
|
2007-04-17 07:56:43 +02:00
|
|
|
if (m_ses.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(peer_blocked_alert(host->endpoint().address()
|
|
|
|
, "peer from tracker blocked by IP filter"));
|
|
|
|
}
|
|
|
|
|
2007-03-07 19:50:38 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-04-10 23:23:13 +02:00
|
|
|
m_policy->peer_from_tracker(*host, pid, peer_info::tracker, 0);
|
2007-03-07 19:50:38 +01:00
|
|
|
}
|
|
|
|
catch (std::exception&)
|
2007-03-12 00:17:40 +01:00
|
|
|
{};
|
2007-03-07 19:50:38 +01:00
|
|
|
|
2004-01-18 02:58:33 +01:00
|
|
|
size_type torrent::bytes_left() const
|
2003-12-07 06:53:04 +01:00
|
|
|
{
|
2004-06-14 01:30:42 +02:00
|
|
|
// if we don't have the metadata yet, we
|
|
|
|
// cannot tell how big the torrent is.
|
|
|
|
if (!valid_metadata()) return -1;
|
2006-01-10 01:38:52 +01:00
|
|
|
return m_torrent_file.total_size()
|
2006-09-24 02:48:31 +02:00
|
|
|
- quantized_bytes_done();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_type torrent::quantized_bytes_done() const
|
|
|
|
{
|
2006-12-11 13:48:33 +01:00
|
|
|
// INVARIANT_CHECK;
|
2006-09-24 02:48:31 +02:00
|
|
|
|
|
|
|
if (!valid_metadata()) return 0;
|
|
|
|
|
|
|
|
if (m_torrent_file.num_pieces() == 0)
|
|
|
|
return 0;
|
2006-12-04 13:20:34 +01:00
|
|
|
|
|
|
|
if (is_seed()) return m_torrent_file.total_size();
|
|
|
|
|
2006-09-24 02:48:31 +02:00
|
|
|
const int last_piece = m_torrent_file.num_pieces() - 1;
|
|
|
|
|
|
|
|
size_type total_done
|
|
|
|
= m_num_pieces * m_torrent_file.piece_length();
|
|
|
|
|
|
|
|
// if we have the last piece, we have to correct
|
|
|
|
// the amount we have, since the first calculation
|
|
|
|
// assumed all pieces were of equal size
|
|
|
|
if (m_have_pieces[last_piece])
|
|
|
|
{
|
|
|
|
int corr = m_torrent_file.piece_size(last_piece)
|
|
|
|
- m_torrent_file.piece_length();
|
|
|
|
total_done += corr;
|
|
|
|
}
|
|
|
|
return total_done;
|
2004-01-15 17:45:34 +01:00
|
|
|
}
|
|
|
|
|
2005-05-30 19:43:03 +02:00
|
|
|
// the first value is the total number of bytes downloaded
|
|
|
|
// the second value is the number of bytes of those that haven't
|
|
|
|
// been filtered as not wanted we have downloaded
|
2006-01-07 14:48:14 +01:00
|
|
|
tuple<size_type, size_type> torrent::bytes_done() const
|
2004-01-15 17:45:34 +01:00
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-03-17 18:28:59 +01:00
|
|
|
if (!valid_metadata() || m_torrent_file.num_pieces() == 0)
|
2006-01-07 14:48:14 +01:00
|
|
|
return tuple<size_type, size_type>(0,0);
|
2007-03-17 00:28:26 +01:00
|
|
|
|
2005-05-30 19:43:03 +02:00
|
|
|
const int last_piece = m_torrent_file.num_pieces() - 1;
|
2004-01-15 17:45:34 +01:00
|
|
|
|
2006-12-04 13:20:34 +01:00
|
|
|
if (is_seed())
|
|
|
|
return make_tuple(m_torrent_file.total_size()
|
|
|
|
, m_torrent_file.total_size());
|
|
|
|
|
2005-05-30 19:43:03 +02:00
|
|
|
size_type wanted_done = (m_num_pieces - m_picker->num_have_filtered())
|
|
|
|
* m_torrent_file.piece_length();
|
|
|
|
|
2004-01-18 02:58:33 +01:00
|
|
|
size_type total_done
|
2004-01-15 17:45:34 +01:00
|
|
|
= m_num_pieces * m_torrent_file.piece_length();
|
2006-12-11 13:48:33 +01:00
|
|
|
assert(m_num_pieces < m_torrent_file.num_pieces());
|
2004-01-15 17:45:34 +01:00
|
|
|
|
|
|
|
// if we have the last piece, we have to correct
|
|
|
|
// the amount we have, since the first calculation
|
|
|
|
// assumed all pieces were of equal size
|
2003-12-07 06:53:04 +01:00
|
|
|
if (m_have_pieces[last_piece])
|
|
|
|
{
|
2005-05-30 19:43:03 +02:00
|
|
|
int corr = m_torrent_file.piece_size(last_piece)
|
|
|
|
- m_torrent_file.piece_length();
|
|
|
|
total_done += corr;
|
2007-03-15 23:03:56 +01:00
|
|
|
if (m_picker->piece_priority(last_piece) != 0)
|
2005-05-30 19:43:03 +02:00
|
|
|
wanted_done += corr;
|
2003-12-07 06:53:04 +01:00
|
|
|
}
|
|
|
|
|
2006-12-16 00:22:40 +01:00
|
|
|
assert(total_done <= m_torrent_file.total_size());
|
|
|
|
assert(wanted_done <= m_torrent_file.total_size());
|
2006-12-11 13:48:33 +01:00
|
|
|
|
2004-01-15 17:45:34 +01:00
|
|
|
const std::vector<piece_picker::downloading_piece>& dl_queue
|
2004-06-14 01:30:42 +02:00
|
|
|
= m_picker->get_download_queue();
|
2004-01-15 17:45:34 +01:00
|
|
|
|
2005-05-30 19:43:03 +02:00
|
|
|
const int blocks_per_piece = static_cast<int>(
|
|
|
|
m_torrent_file.piece_length() / m_block_size);
|
2004-01-15 17:45:34 +01:00
|
|
|
|
|
|
|
for (std::vector<piece_picker::downloading_piece>::const_iterator i =
|
2005-05-30 19:43:03 +02:00
|
|
|
dl_queue.begin(); i != dl_queue.end(); ++i)
|
2004-01-15 17:45:34 +01:00
|
|
|
{
|
2005-05-30 19:43:03 +02:00
|
|
|
int corr = 0;
|
2006-12-31 15:48:18 +01:00
|
|
|
int index = i->index;
|
|
|
|
assert(!m_have_pieces[index]);
|
2007-05-08 13:13:13 +02:00
|
|
|
assert(i->finished < m_picker->blocks_in_piece(index));
|
2006-12-14 17:12:31 +01:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
for (std::vector<piece_picker::downloading_piece>::const_iterator j = boost::next(i);
|
|
|
|
j != dl_queue.end(); ++j)
|
|
|
|
{
|
2006-12-31 15:48:18 +01:00
|
|
|
assert(j->index != index);
|
2006-12-14 17:12:31 +01:00
|
|
|
}
|
|
|
|
#endif
|
2004-01-15 17:45:34 +01:00
|
|
|
|
|
|
|
for (int j = 0; j < blocks_per_piece; ++j)
|
|
|
|
{
|
2007-05-08 13:13:13 +02:00
|
|
|
assert(i->info[j].finished == 0 || i->info[j].finished == 1);
|
|
|
|
assert(m_picker->is_finished(piece_block(index, j)) == i->info[j].finished);
|
|
|
|
corr += i->info[j].finished * m_block_size;
|
2006-12-31 15:48:18 +01:00
|
|
|
assert(index != last_piece || j < m_picker->blocks_in_last_piece()
|
2007-05-08 13:13:13 +02:00
|
|
|
|| i->info[j].finished == 0);
|
2004-01-15 17:45:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// correction if this was the last piece
|
|
|
|
// and if we have the last block
|
|
|
|
if (i->index == last_piece
|
2007-05-08 13:13:13 +02:00
|
|
|
&& i->info[m_picker->blocks_in_last_piece()-1].finished)
|
2004-01-15 17:45:34 +01:00
|
|
|
{
|
2005-05-30 19:43:03 +02:00
|
|
|
corr -= m_block_size;
|
|
|
|
corr += m_torrent_file.piece_size(last_piece) % m_block_size;
|
2004-01-15 17:45:34 +01:00
|
|
|
}
|
2005-05-30 19:43:03 +02:00
|
|
|
total_done += corr;
|
2007-03-15 23:03:56 +01:00
|
|
|
if (m_picker->piece_priority(index) != 0)
|
2005-05-30 19:43:03 +02:00
|
|
|
wanted_done += corr;
|
2004-01-15 17:45:34 +01:00
|
|
|
}
|
|
|
|
|
2006-12-18 02:23:30 +01:00
|
|
|
assert(total_done < m_torrent_file.total_size());
|
|
|
|
assert(wanted_done < m_torrent_file.total_size());
|
2006-12-15 13:29:47 +01:00
|
|
|
|
2004-09-16 03:14:16 +02:00
|
|
|
std::map<piece_block, int> downloading_piece;
|
|
|
|
for (const_peer_iterator i = begin(); i != end(); ++i)
|
2004-01-15 17:45:34 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
peer_connection* pc = i->second;
|
2004-01-15 17:45:34 +01:00
|
|
|
boost::optional<piece_block_progress> p
|
2006-04-25 23:04:48 +02:00
|
|
|
= pc->downloading_piece_progress();
|
2004-01-15 17:45:34 +01:00
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
if (m_have_pieces[p->piece_index])
|
|
|
|
continue;
|
2004-09-16 03:14:16 +02:00
|
|
|
|
|
|
|
piece_block block(p->piece_index, p->block_index);
|
|
|
|
if (m_picker->is_finished(block))
|
2004-01-15 17:45:34 +01:00
|
|
|
continue;
|
2003-12-07 06:53:04 +01:00
|
|
|
|
2004-09-16 03:14:16 +02:00
|
|
|
std::map<piece_block, int>::iterator dp
|
|
|
|
= downloading_piece.find(block);
|
|
|
|
if (dp != downloading_piece.end())
|
|
|
|
{
|
|
|
|
if (dp->second < p->bytes_downloaded)
|
|
|
|
dp->second = p->bytes_downloaded;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
downloading_piece[block] = p->bytes_downloaded;
|
|
|
|
}
|
2006-12-18 02:23:30 +01:00
|
|
|
#ifndef NDEBUG
|
2004-01-15 17:45:34 +01:00
|
|
|
assert(p->bytes_downloaded <= p->full_block_bytes);
|
2006-12-18 02:23:30 +01:00
|
|
|
int last_piece = m_torrent_file.num_pieces() - 1;
|
|
|
|
if (p->piece_index == last_piece
|
|
|
|
&& p->block_index == m_torrent_file.piece_size(last_piece) / block_size())
|
|
|
|
assert(p->full_block_bytes == m_torrent_file.piece_size(last_piece) % block_size());
|
|
|
|
else
|
|
|
|
assert(p->full_block_bytes == block_size());
|
|
|
|
#endif
|
2004-01-15 17:45:34 +01:00
|
|
|
}
|
|
|
|
}
|
2004-09-16 03:14:16 +02:00
|
|
|
for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
|
|
|
|
i != downloading_piece.end(); ++i)
|
2005-05-30 19:43:03 +02:00
|
|
|
{
|
2004-09-16 03:14:16 +02:00
|
|
|
total_done += i->second;
|
2007-03-15 23:03:56 +01:00
|
|
|
if (m_picker->piece_priority(i->first.piece_index) != 0)
|
2005-05-30 19:43:03 +02:00
|
|
|
wanted_done += i->second;
|
|
|
|
}
|
2006-12-15 13:29:47 +01:00
|
|
|
|
2006-12-18 02:23:30 +01:00
|
|
|
#ifndef NDEBUG
|
|
|
|
|
|
|
|
if (total_done >= m_torrent_file.total_size())
|
|
|
|
{
|
|
|
|
std::copy(m_have_pieces.begin(), m_have_pieces.end()
|
|
|
|
, std::ostream_iterator<bool>(std::cerr, " "));
|
|
|
|
std::cerr << std::endl;
|
|
|
|
std::cerr << "num_pieces: " << m_num_pieces << std::endl;
|
|
|
|
|
|
|
|
std::cerr << "unfinished:" << std::endl;
|
|
|
|
|
|
|
|
for (std::vector<piece_picker::downloading_piece>::const_iterator i =
|
|
|
|
dl_queue.begin(); i != dl_queue.end(); ++i)
|
|
|
|
{
|
|
|
|
std::cerr << " " << i->index << " ";
|
|
|
|
for (int j = 0; j < blocks_per_piece; ++j)
|
|
|
|
{
|
2007-05-08 13:13:13 +02:00
|
|
|
std::cerr << i->info[j].finished;
|
2006-12-18 02:23:30 +01:00
|
|
|
}
|
|
|
|
std::cerr << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cerr << "downloading pieces:" << std::endl;
|
|
|
|
|
|
|
|
for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
|
|
|
|
i != downloading_piece.end(); ++i)
|
|
|
|
{
|
|
|
|
std::cerr << " " << i->first.piece_index << ":" << i->first.block_index
|
|
|
|
<< " " << i->second << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(total_done < m_torrent_file.total_size());
|
|
|
|
assert(wanted_done < m_torrent_file.total_size());
|
|
|
|
|
|
|
|
#endif
|
2006-12-15 13:29:47 +01:00
|
|
|
|
2006-12-14 17:12:31 +01:00
|
|
|
assert(total_done >= wanted_done);
|
2006-01-07 14:48:14 +01:00
|
|
|
return make_tuple(total_done, wanted_done);
|
2004-01-15 17:45:34 +01:00
|
|
|
}
|
2003-12-07 06:53:04 +01:00
|
|
|
|
2003-12-01 22:27:27 +01:00
|
|
|
void torrent::piece_failed(int index)
|
|
|
|
{
|
2006-12-14 17:12:31 +01:00
|
|
|
// if the last piece fails the peer connection will still
|
|
|
|
// think that it has received all of it until this function
|
|
|
|
// resets the download queue. So, we cannot do the
|
|
|
|
// invariant check here since it assumes:
|
|
|
|
// (total_done == m_torrent_file.total_size()) => is_seed()
|
|
|
|
// INVARIANT_CHECK;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
assert(m_storage.get());
|
|
|
|
assert(m_picker.get());
|
2004-01-25 13:37:15 +01:00
|
|
|
assert(index >= 0);
|
|
|
|
assert(index < m_torrent_file.num_pieces());
|
|
|
|
|
2003-12-22 08:14:35 +01:00
|
|
|
if (m_ses.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
std::stringstream s;
|
|
|
|
s << "hash for piece " << index << " failed";
|
2004-01-07 01:48:02 +01:00
|
|
|
m_ses.m_alerts.post_alert(hash_failed_alert(get_handle(), index, s.str()));
|
2003-12-22 08:14:35 +01:00
|
|
|
}
|
2004-04-18 14:28:02 +02:00
|
|
|
// increase the total amount of failed bytes
|
|
|
|
m_total_failed_bytes += m_torrent_file.piece_size(index);
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
std::vector<tcp::endpoint> downloaders;
|
2004-06-14 01:30:42 +02:00
|
|
|
m_picker->get_downloaders(downloaders, index);
|
2003-12-01 22:27:27 +01:00
|
|
|
|
|
|
|
// decrease the trust point of all peers that sent
|
|
|
|
// parts of this piece.
|
2004-09-12 12:12:16 +02:00
|
|
|
// first, build a set of all peers that participated
|
2006-04-25 23:04:48 +02:00
|
|
|
std::set<tcp::endpoint> peers;
|
2004-09-12 12:12:16 +02:00
|
|
|
std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
try { (*i)->on_piece_failed(index); } catch (std::exception&) {}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
for (std::set<tcp::endpoint>::iterator i = peers.begin()
|
2004-09-12 12:12:16 +02:00
|
|
|
, end(peers.end()); i != end; ++i)
|
2003-12-01 22:27:27 +01:00
|
|
|
{
|
2004-01-13 04:08:59 +01:00
|
|
|
peer_iterator p = m_connections.find(*i);
|
|
|
|
if (p == m_connections.end()) continue;
|
2006-11-14 01:08:16 +01:00
|
|
|
p->second->received_invalid_data(index);
|
2003-12-14 06:56:12 +01:00
|
|
|
|
2004-09-12 12:12:16 +02:00
|
|
|
// either, we have received too many failed hashes
|
|
|
|
// or this was the only peer that sent us this piece.
|
2006-04-25 23:04:48 +02:00
|
|
|
// TODO: make this a changable setting
|
2004-09-12 12:12:16 +02:00
|
|
|
if (p->second->trust_points() <= -7 || peers.size() == 1)
|
2003-12-01 22:27:27 +01:00
|
|
|
{
|
2003-12-14 06:56:12 +01:00
|
|
|
// we don't trust this peer anymore
|
|
|
|
// ban it.
|
2004-03-21 03:03:37 +01:00
|
|
|
if (m_ses.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(peer_ban_alert(
|
|
|
|
p->first
|
|
|
|
, get_handle()
|
|
|
|
, "banning peer because of too many corrupt pieces"));
|
|
|
|
}
|
2007-04-13 03:53:25 +02:00
|
|
|
|
|
|
|
// mark the peer as banned
|
|
|
|
policy::peer* peerinfo = p->second->peer_info_struct();
|
|
|
|
if (peerinfo)
|
|
|
|
{
|
|
|
|
peerinfo->banned = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// it might be a web seed
|
|
|
|
if (web_peer_connection const* wpc
|
|
|
|
= dynamic_cast<web_peer_connection const*>(p->second))
|
|
|
|
{
|
|
|
|
remove_url_seed(wpc->url());
|
|
|
|
}
|
|
|
|
}
|
2005-09-01 23:04:21 +02:00
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
|
|
|
(*p->second->m_logger) << "*** BANNING PEER 'too many corrupt pieces'\n";
|
|
|
|
#endif
|
2004-03-30 21:11:07 +02:00
|
|
|
p->second->disconnect();
|
2003-12-01 22:27:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// we have to let the piece_picker know that
|
|
|
|
// this piece failed the check as it can restore it
|
|
|
|
// and mark it as being interesting for download
|
|
|
|
// TODO: do this more intelligently! and keep track
|
|
|
|
// of how much crap (data that failed hash-check) and
|
|
|
|
// how much redundant data we have downloaded
|
|
|
|
// if some clients has sent more than one piece
|
|
|
|
// start with redownloading the pieces that the client
|
|
|
|
// that has sent the least number of pieces
|
2004-06-14 01:30:42 +02:00
|
|
|
m_picker->restore_piece(index);
|
|
|
|
m_storage->mark_failed(index);
|
2004-01-09 11:50:22 +01:00
|
|
|
|
|
|
|
assert(m_have_pieces[index] == false);
|
2003-12-01 22:27:27 +01:00
|
|
|
}
|
|
|
|
|
2005-03-05 15:17:17 +01:00
|
|
|
void torrent::abort()
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2005-03-05 15:17:17 +01:00
|
|
|
m_abort = true;
|
2006-04-25 23:04:48 +02:00
|
|
|
// if the torrent is paused, it doesn't need
|
|
|
|
// to announce with even=stopped again.
|
|
|
|
if (!m_paused)
|
|
|
|
m_event = tracker_request::stopped;
|
2005-03-05 15:17:17 +01:00
|
|
|
// disconnect all peers and close all
|
2005-08-15 00:04:58 +02:00
|
|
|
// files belonging to the torrents
|
2005-03-05 15:17:17 +01:00
|
|
|
disconnect_all();
|
2005-03-10 12:41:22 +01:00
|
|
|
if (m_storage.get()) m_storage->release_files();
|
2005-03-05 15:17:17 +01:00
|
|
|
}
|
2003-12-01 22:27:27 +01:00
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
void torrent::announce_piece(int index)
|
|
|
|
{
|
2006-12-31 15:48:18 +01:00
|
|
|
// INVARIANT_CHECK;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2004-01-25 13:37:15 +01:00
|
|
|
assert(index >= 0);
|
|
|
|
assert(index < m_torrent_file.num_pieces());
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
std::vector<tcp::endpoint> downloaders;
|
2004-06-14 01:30:42 +02:00
|
|
|
m_picker->get_downloaders(downloaders, index);
|
2003-12-01 22:27:27 +01:00
|
|
|
|
|
|
|
// increase the trust point of all peers that sent
|
|
|
|
// parts of this piece.
|
2006-04-25 23:04:48 +02:00
|
|
|
std::set<tcp::endpoint> peers;
|
2004-09-12 12:12:16 +02:00
|
|
|
std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
|
|
|
|
|
2006-12-21 03:44:00 +01:00
|
|
|
if (!m_have_pieces[index])
|
|
|
|
m_num_pieces++;
|
|
|
|
m_have_pieces[index] = true;
|
|
|
|
|
|
|
|
assert(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0)
|
|
|
|
== m_num_pieces);
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
m_picker->we_have(index);
|
2004-01-13 04:08:59 +01:00
|
|
|
for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
|
2007-03-26 08:48:34 +02:00
|
|
|
try { i->second->announce_piece(index); } catch (std::exception&) {}
|
2006-11-14 01:08:16 +01:00
|
|
|
|
2006-12-31 15:48:18 +01:00
|
|
|
for (std::set<tcp::endpoint>::iterator i = peers.begin()
|
|
|
|
, end(peers.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
peer_iterator p = m_connections.find(*i);
|
|
|
|
if (p == m_connections.end()) continue;
|
|
|
|
p->second->received_valid_data(index);
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
try { (*i)->on_piece_pass(index); } catch (std::exception&) {}
|
|
|
|
}
|
|
|
|
#endif
|
2007-05-10 00:54:26 +02:00
|
|
|
if (is_seed())
|
|
|
|
{
|
|
|
|
m_picker.reset();
|
|
|
|
m_torrent_file.seed_free();
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2004-03-28 19:45:37 +02:00
|
|
|
std::string torrent::tracker_login() const
|
2004-02-22 23:40:45 +01:00
|
|
|
{
|
|
|
|
if (m_username.empty() && m_password.empty()) return "";
|
|
|
|
return m_username + ":" + m_password;
|
|
|
|
}
|
|
|
|
|
2007-03-20 02:59:00 +01:00
|
|
|
|
|
|
|
|
|
|
|
void torrent::set_piece_priority(int index, int priority)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
assert(valid_metadata());
|
|
|
|
if (is_seed()) return;
|
|
|
|
|
|
|
|
// this call is only valid on torrents with metadata
|
|
|
|
assert(m_picker.get());
|
|
|
|
assert(index >= 0);
|
|
|
|
assert(index < m_torrent_file.num_pieces());
|
|
|
|
|
|
|
|
m_picker->set_piece_priority(index, priority);
|
2007-03-21 03:09:50 +01:00
|
|
|
update_peer_interest();
|
2007-03-20 02:59:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int torrent::piece_priority(int index) const
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
assert(valid_metadata());
|
|
|
|
if (is_seed()) return 1;
|
|
|
|
|
|
|
|
// this call is only valid on torrents with metadata
|
|
|
|
assert(m_picker.get());
|
|
|
|
assert(index >= 0);
|
|
|
|
assert(index < m_torrent_file.num_pieces());
|
|
|
|
|
|
|
|
return m_picker->piece_priority(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::prioritize_pieces(std::vector<int> const& pieces)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
// this call is only valid on torrents with metadata
|
|
|
|
assert(valid_metadata());
|
|
|
|
if (is_seed()) return;
|
|
|
|
|
|
|
|
assert(m_picker.get());
|
|
|
|
|
|
|
|
int index = 0;
|
|
|
|
for (std::vector<int>::const_iterator i = pieces.begin()
|
|
|
|
, end(pieces.end()); i != end; ++i, ++index)
|
|
|
|
{
|
|
|
|
assert(*i >= 0);
|
|
|
|
assert(*i <= 7);
|
|
|
|
m_picker->set_piece_priority(index, *i);
|
|
|
|
}
|
2007-03-21 03:09:50 +01:00
|
|
|
update_peer_interest();
|
2007-03-20 02:59:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::piece_priorities(std::vector<int>& pieces) const
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
// this call is only valid on torrents with metadata
|
|
|
|
assert(valid_metadata());
|
|
|
|
if (is_seed())
|
|
|
|
{
|
|
|
|
pieces.clear();
|
|
|
|
pieces.resize(m_torrent_file.num_pieces(), 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(m_picker.get());
|
|
|
|
m_picker->piece_priorities(pieces);
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
void set_if_greater(int& piece_prio, int file_prio)
|
|
|
|
{
|
|
|
|
if (file_prio > piece_prio) piece_prio = file_prio;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::prioritize_files(std::vector<int> const& files)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
// this call is only valid on torrents with metadata
|
|
|
|
if (!valid_metadata() || is_seed()) return;
|
|
|
|
|
|
|
|
// the bitmask need to have exactly one bit for every file
|
|
|
|
// in the torrent
|
|
|
|
assert(int(files.size()) == m_torrent_file.num_files());
|
|
|
|
|
|
|
|
size_type position = 0;
|
|
|
|
|
2007-03-21 03:09:50 +01:00
|
|
|
if (m_torrent_file.num_pieces() == 0) return;
|
|
|
|
|
|
|
|
int piece_length = m_torrent_file.piece_length();
|
|
|
|
// initialize the piece priorities to 0, then only allow
|
|
|
|
// setting higher priorities
|
|
|
|
std::vector<int> pieces(m_torrent_file.num_pieces(), 0);
|
|
|
|
for (int i = 0; i < int(files.size()); ++i)
|
2007-03-20 02:59:00 +01:00
|
|
|
{
|
2007-03-21 03:09:50 +01:00
|
|
|
size_type start = position;
|
2007-04-18 00:56:14 +02:00
|
|
|
size_type size = m_torrent_file.file_at(i).size;
|
|
|
|
if (size == 0) continue;
|
|
|
|
position += size;
|
2007-03-21 03:09:50 +01:00
|
|
|
// mark all pieces of the file with this file's priority
|
|
|
|
// but only if the priority is higher than the pieces
|
|
|
|
// already set (to avoid problems with overlapping pieces)
|
|
|
|
int start_piece = int(start / piece_length);
|
2007-04-18 00:56:14 +02:00
|
|
|
int last_piece = int((position - 1) / piece_length);
|
|
|
|
assert(last_piece <= int(pieces.size()));
|
2007-03-21 03:09:50 +01:00
|
|
|
// if one piece spans several files, we might
|
|
|
|
// come here several times with the same start_piece, end_piece
|
|
|
|
std::for_each(pieces.begin() + start_piece
|
|
|
|
, pieces.begin() + last_piece + 1
|
|
|
|
, bind(&set_if_greater, _1, files[i]));
|
2007-03-20 02:59:00 +01:00
|
|
|
}
|
2007-03-21 03:09:50 +01:00
|
|
|
prioritize_pieces(pieces);
|
|
|
|
update_peer_interest();
|
2007-03-20 02:59:00 +01:00
|
|
|
}
|
|
|
|
|
2007-03-21 03:09:50 +01:00
|
|
|
// updates the interested flag in peers
|
|
|
|
void torrent::update_peer_interest()
|
|
|
|
{
|
|
|
|
for (peer_iterator i = begin(); i != end(); ++i)
|
|
|
|
i->second->update_interest();
|
|
|
|
}
|
2007-03-20 02:59:00 +01:00
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
void torrent::filter_piece(int index, bool filter)
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2006-12-11 13:48:33 +01:00
|
|
|
assert(valid_metadata());
|
|
|
|
if (is_seed()) return;
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
// this call is only valid on torrents with metadata
|
|
|
|
assert(m_picker.get());
|
|
|
|
assert(index >= 0);
|
|
|
|
assert(index < m_torrent_file.num_pieces());
|
|
|
|
|
2007-03-15 23:03:56 +01:00
|
|
|
m_picker->set_piece_priority(index, filter ? 1 : 0);
|
2007-03-29 00:22:24 +02:00
|
|
|
update_peer_interest();
|
2005-05-25 12:01:01 +02:00
|
|
|
}
|
|
|
|
|
2005-06-23 01:04:37 +02:00
|
|
|
void torrent::filter_pieces(std::vector<bool> const& bitmask)
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2005-06-23 01:04:37 +02:00
|
|
|
// this call is only valid on torrents with metadata
|
2006-12-11 13:48:33 +01:00
|
|
|
assert(valid_metadata());
|
|
|
|
if (is_seed()) return;
|
|
|
|
|
2005-06-23 01:04:37 +02:00
|
|
|
assert(m_picker.get());
|
|
|
|
|
|
|
|
int index = 0;
|
|
|
|
for (std::vector<bool>::const_iterator i = bitmask.begin()
|
|
|
|
, end(bitmask.end()); i != end; ++i, ++index)
|
|
|
|
{
|
2007-03-15 23:03:56 +01:00
|
|
|
if ((m_picker->piece_priority(index) == 0) == *i) continue;
|
2005-09-01 23:04:21 +02:00
|
|
|
if (*i)
|
2007-03-15 23:03:56 +01:00
|
|
|
m_picker->set_piece_priority(index, 0);
|
2005-09-01 23:04:21 +02:00
|
|
|
else
|
2007-03-15 23:03:56 +01:00
|
|
|
m_picker->set_piece_priority(index, 1);
|
2005-06-23 01:04:37 +02:00
|
|
|
}
|
2007-03-29 00:22:24 +02:00
|
|
|
update_peer_interest();
|
2005-06-23 01:04:37 +02:00
|
|
|
}
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
bool torrent::is_piece_filtered(int index) const
|
|
|
|
{
|
|
|
|
// this call is only valid on torrents with metadata
|
2006-12-11 13:48:33 +01:00
|
|
|
assert(valid_metadata());
|
|
|
|
if (is_seed()) return false;
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
assert(m_picker.get());
|
|
|
|
assert(index >= 0);
|
|
|
|
assert(index < m_torrent_file.num_pieces());
|
|
|
|
|
2007-03-15 23:03:56 +01:00
|
|
|
return m_picker->piece_priority(index) == 0;
|
2005-05-25 12:01:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::filtered_pieces(std::vector<bool>& bitmask) const
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
// this call is only valid on torrents with metadata
|
2006-12-11 13:48:33 +01:00
|
|
|
assert(valid_metadata());
|
|
|
|
if (is_seed())
|
|
|
|
{
|
|
|
|
bitmask.clear();
|
|
|
|
bitmask.resize(m_torrent_file.num_pieces(), false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
assert(m_picker.get());
|
|
|
|
m_picker->filtered_pieces(bitmask);
|
|
|
|
}
|
|
|
|
|
2005-07-04 01:33:47 +02:00
|
|
|
void torrent::filter_files(std::vector<bool> const& bitmask)
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2005-07-04 01:33:47 +02:00
|
|
|
// this call is only valid on torrents with metadata
|
2006-12-11 13:48:33 +01:00
|
|
|
if (!valid_metadata() || is_seed()) return;
|
2005-07-04 18:27:14 +02:00
|
|
|
|
2005-07-04 18:33:54 +02:00
|
|
|
// the bitmask need to have exactly one bit for every file
|
|
|
|
// in the torrent
|
2005-07-16 02:56:50 +02:00
|
|
|
assert((int)bitmask.size() == m_torrent_file.num_files());
|
2005-07-04 18:33:54 +02:00
|
|
|
|
2005-07-08 16:04:14 +02:00
|
|
|
size_type position = 0;
|
2005-07-04 18:27:14 +02:00
|
|
|
|
2005-07-04 18:33:54 +02:00
|
|
|
if (m_torrent_file.num_pieces())
|
|
|
|
{
|
|
|
|
int piece_length = m_torrent_file.piece_length();
|
|
|
|
// mark all pieces as filtered, then clear the bits for files
|
|
|
|
// that should be downloaded
|
|
|
|
std::vector<bool> piece_filter(m_torrent_file.num_pieces(), true);
|
2005-07-06 02:58:23 +02:00
|
|
|
for (int i = 0; i < (int)bitmask.size(); ++i)
|
2005-07-04 18:27:14 +02:00
|
|
|
{
|
2005-07-08 16:04:14 +02:00
|
|
|
size_type start = position;
|
2005-07-04 18:33:54 +02:00
|
|
|
position += m_torrent_file.file_at(i).size;
|
|
|
|
// is the file selected for download?
|
|
|
|
if (!bitmask[i])
|
|
|
|
{
|
|
|
|
// mark all pieces of the file as downloadable
|
|
|
|
int start_piece = int(start / piece_length);
|
|
|
|
int last_piece = int(position / piece_length);
|
|
|
|
// if one piece spans several files, we might
|
|
|
|
// come here several times with the same start_piece, end_piece
|
|
|
|
std::fill(piece_filter.begin() + start_piece, piece_filter.begin()
|
|
|
|
+ last_piece + 1, false);
|
2005-07-04 18:27:14 +02:00
|
|
|
}
|
|
|
|
}
|
2005-07-04 18:33:54 +02:00
|
|
|
filter_pieces(piece_filter);
|
2005-07-04 18:27:14 +02:00
|
|
|
}
|
2005-07-04 01:33:47 +02:00
|
|
|
}
|
|
|
|
|
2004-09-12 12:12:16 +02:00
|
|
|
void torrent::replace_trackers(std::vector<announce_entry> const& urls)
|
|
|
|
{
|
|
|
|
assert(!urls.empty());
|
|
|
|
m_trackers = urls;
|
|
|
|
if (m_currently_trying_tracker >= (int)m_trackers.size())
|
2004-09-12 15:53:00 +02:00
|
|
|
m_currently_trying_tracker = (int)m_trackers.size()-1;
|
2004-09-12 12:12:16 +02:00
|
|
|
m_last_working_tracker = -1;
|
|
|
|
}
|
|
|
|
|
2004-03-21 03:03:37 +01:00
|
|
|
tracker_request torrent::generate_tracker_request()
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-02-20 02:42:12 +01:00
|
|
|
assert(!m_trackers.empty());
|
|
|
|
|
2007-04-05 00:27:36 +02:00
|
|
|
m_next_request = time_now() + seconds(tracker_retry_delay_max);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-01-20 23:59:21 +01:00
|
|
|
tracker_request req;
|
|
|
|
req.info_hash = m_torrent_file.info_hash();
|
2006-04-25 23:04:48 +02:00
|
|
|
req.pid = m_ses.get_peer_id();
|
2004-01-20 23:59:21 +01:00
|
|
|
req.downloaded = m_stat.total_payload_download();
|
|
|
|
req.uploaded = m_stat.total_payload_upload();
|
|
|
|
req.left = bytes_left();
|
2006-09-24 13:22:25 +02:00
|
|
|
if (req.left == -1) req.left = 16*1024;
|
2004-01-21 14:16:11 +01:00
|
|
|
req.event = m_event;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
if (m_event != tracker_request::stopped)
|
|
|
|
m_event = tracker_request::none;
|
2004-09-12 12:12:16 +02:00
|
|
|
req.url = m_trackers[m_currently_trying_tracker].url;
|
2007-02-12 23:45:23 +01:00
|
|
|
req.num_want = 50;
|
2005-03-08 15:16:14 +01:00
|
|
|
// if we are aborting. we don't want any new peers
|
|
|
|
if (req.event == tracker_request::stopped)
|
|
|
|
req.num_want = 0;
|
2004-03-21 03:03:37 +01:00
|
|
|
|
|
|
|
// default initialize, these should be set by caller
|
|
|
|
// before passing the request to the tracker_manager
|
|
|
|
req.listen_port = 0;
|
|
|
|
req.key = 0;
|
|
|
|
|
2004-01-20 23:59:21 +01:00
|
|
|
return req;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
void torrent::remove_peer(peer_connection* p) try
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-01-25 13:37:15 +01:00
|
|
|
assert(p != 0);
|
|
|
|
|
2005-11-02 17:28:39 +01:00
|
|
|
peer_iterator i = m_connections.find(p->remote());
|
2007-04-12 12:21:55 +02:00
|
|
|
if (i == m_connections.end())
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
return;
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-10-16 23:14:08 +02:00
|
|
|
if (ready_for_connections())
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
assert(p->associated_torrent().lock().get() == this);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2007-04-15 04:14:02 +02:00
|
|
|
if (p->is_seed())
|
|
|
|
{
|
|
|
|
if (m_picker.get())
|
|
|
|
{
|
|
|
|
assert(!is_seed());
|
|
|
|
m_picker->dec_refcount_all();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2004-06-14 01:30:42 +02:00
|
|
|
{
|
2007-04-15 04:14:02 +02:00
|
|
|
// if we're a seed, we don't keep track of piece availability
|
|
|
|
if (!is_seed())
|
|
|
|
{
|
|
|
|
const std::vector<bool>& pieces = p->get_bitfield();
|
|
|
|
|
|
|
|
for (std::vector<bool>::const_iterator i = pieces.begin();
|
|
|
|
i != pieces.end(); ++i)
|
|
|
|
{
|
|
|
|
if (*i) peer_lost(static_cast<int>(i - pieces.begin()));
|
|
|
|
}
|
|
|
|
}
|
2004-06-14 01:30:42 +02:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
m_policy->connection_closed(*p);
|
2007-04-12 12:21:55 +02:00
|
|
|
p->set_peer_info(0);
|
2003-10-23 01:00:57 +02:00
|
|
|
m_connections.erase(i);
|
2005-10-01 13:20:47 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
m_policy->check_invariant();
|
|
|
|
#endif
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
|
|
|
std::string err = e.what();
|
|
|
|
#endif
|
|
|
|
assert(false);
|
|
|
|
};
|
|
|
|
|
|
|
|
void torrent::connect_to_url_seed(std::string const& url)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2006-06-29 01:27:44 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2007-04-10 09:52:58 +02:00
|
|
|
(*m_ses.m_logger) << time_now_string() << " resolving: " << url << "\n";
|
2006-06-29 01:27:44 +02:00
|
|
|
#endif
|
|
|
|
|
2006-05-20 17:30:40 +02:00
|
|
|
m_resolving_web_seeds.insert(url);
|
2007-04-25 20:26:35 +02:00
|
|
|
proxy_settings const& ps = m_ses.web_seed_proxy();
|
|
|
|
if (ps.type == proxy_settings::http
|
|
|
|
|| ps.type == proxy_settings::http_pw)
|
|
|
|
{
|
|
|
|
// use proxy
|
|
|
|
tcp::resolver::query q(ps.hostname
|
|
|
|
, boost::lexical_cast<std::string>(ps.port));
|
|
|
|
m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
|
|
|
|
bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, url)));
|
|
|
|
}
|
|
|
|
else
|
2006-07-27 20:07:51 +02:00
|
|
|
{
|
2007-02-12 06:46:29 +01:00
|
|
|
std::string protocol;
|
2007-05-22 22:44:18 +02:00
|
|
|
std::string auth;
|
2007-02-12 06:46:29 +01:00
|
|
|
std::string hostname;
|
|
|
|
int port;
|
|
|
|
std::string path;
|
2007-05-22 22:44:18 +02:00
|
|
|
boost::tie(protocol, auth, hostname, port, path)
|
2007-02-12 06:46:29 +01:00
|
|
|
= parse_url_components(url);
|
|
|
|
|
2007-05-22 22:44:18 +02:00
|
|
|
// TODO: should auth be used here?
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
|
2006-12-15 18:47:21 +01:00
|
|
|
m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
|
2007-02-12 06:46:29 +01:00
|
|
|
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url
|
|
|
|
, tcp::endpoint())));
|
2006-07-27 20:07:51 +02:00
|
|
|
}
|
2007-02-12 06:46:29 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::on_proxy_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
|
|
|
|
, std::string url) try
|
|
|
|
{
|
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2007-04-10 09:52:58 +02:00
|
|
|
(*m_ses.m_logger) << time_now_string() << " completed resolve proxy hostname for: " << url << "\n";
|
2007-02-12 06:46:29 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (e || host == tcp::resolver::iterator())
|
|
|
|
{
|
|
|
|
if (m_ses.m_alerts.should_post(alert::warning))
|
|
|
|
{
|
|
|
|
std::stringstream msg;
|
|
|
|
msg << "HTTP seed proxy hostname lookup failed: " << e.message();
|
|
|
|
m_ses.m_alerts.post_alert(
|
|
|
|
url_seed_alert(get_handle(), url, msg.str()));
|
|
|
|
}
|
|
|
|
|
|
|
|
// the name lookup failed for the http host. Don't try
|
|
|
|
// this host again
|
|
|
|
remove_url_seed(url);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_ses.is_aborted()) return;
|
|
|
|
|
|
|
|
tcp::endpoint a(host->endpoint());
|
2007-05-22 22:44:18 +02:00
|
|
|
|
|
|
|
using boost::tuples::ignore;
|
2007-02-12 06:46:29 +01:00
|
|
|
std::string hostname;
|
|
|
|
int port;
|
2007-05-22 22:44:18 +02:00
|
|
|
boost::tie(ignore, ignore, hostname, port, ignore)
|
2007-02-12 06:46:29 +01:00
|
|
|
= parse_url_components(url);
|
|
|
|
|
2007-04-17 07:56:43 +02:00
|
|
|
if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
|
|
|
|
{
|
|
|
|
if (m_ses.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()
|
|
|
|
, "proxy (" + hostname + ") blocked by IP filter"));
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-02-12 06:46:29 +01:00
|
|
|
tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
|
|
|
|
m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
|
|
|
|
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url, a)));
|
|
|
|
}
|
|
|
|
catch (std::exception& exc)
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
};
|
|
|
|
|
|
|
|
void torrent::on_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
|
|
|
|
, std::string url, tcp::endpoint proxy) try
|
|
|
|
{
|
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2007-04-10 09:52:58 +02:00
|
|
|
(*m_ses.m_logger) << time_now_string() << " completed resolve: " << url << "\n";
|
2007-02-12 06:46:29 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
std::set<std::string>::iterator i = m_resolving_web_seeds.find(url);
|
|
|
|
if (i != m_resolving_web_seeds.end()) m_resolving_web_seeds.erase(i);
|
|
|
|
|
|
|
|
if (e || host == tcp::resolver::iterator())
|
|
|
|
{
|
|
|
|
if (m_ses.m_alerts.should_post(alert::warning))
|
|
|
|
{
|
|
|
|
std::stringstream msg;
|
|
|
|
msg << "HTTP seed hostname lookup failed: " << e.message();
|
|
|
|
m_ses.m_alerts.post_alert(
|
|
|
|
url_seed_alert(get_handle(), url, msg.str()));
|
|
|
|
}
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << url << "\n";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// the name lookup failed for the http host. Don't try
|
|
|
|
// this host again
|
|
|
|
remove_url_seed(url);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_ses.is_aborted()) return;
|
|
|
|
|
|
|
|
tcp::endpoint a(host->endpoint());
|
|
|
|
|
|
|
|
if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
|
|
|
|
{
|
2007-04-17 07:56:43 +02:00
|
|
|
if (m_ses.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()
|
|
|
|
, "web seed (" + url + ") blocked by IP filter"));
|
|
|
|
}
|
2007-02-12 06:46:29 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
peer_iterator conn = m_connections.find(a);
|
|
|
|
if (conn != m_connections.end())
|
|
|
|
{
|
|
|
|
if (dynamic_cast<web_peer_connection*>(conn->second) == 0
|
|
|
|
|| conn->second->is_disconnecting()) conn->second->disconnect();
|
|
|
|
else return;
|
|
|
|
}
|
|
|
|
|
2007-04-25 20:26:35 +02:00
|
|
|
boost::shared_ptr<socket_type> s
|
|
|
|
= instantiate_connection(m_ses.m_io_service, m_ses.web_seed_proxy());
|
|
|
|
if (m_ses.web_seed_proxy().type == proxy_settings::http
|
|
|
|
|| m_ses.web_seed_proxy().type == proxy_settings::http_pw)
|
|
|
|
{
|
|
|
|
// the web seed connection will talk immediately to
|
|
|
|
// the proxy, without requiring CONNECT support
|
|
|
|
s->get<http_stream>().set_no_connect(true);
|
|
|
|
}
|
2007-02-12 06:46:29 +01:00
|
|
|
boost::intrusive_ptr<peer_connection> c(new web_peer_connection(
|
2007-04-25 20:26:35 +02:00
|
|
|
m_ses, shared_from_this(), s, a, url, 0));
|
2007-02-12 06:46:29 +01:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
c->m_in_constructor = false;
|
|
|
|
#endif
|
|
|
|
|
2007-04-02 22:00:24 +02:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
for (extension_list_t::iterator i = m_extensions.begin()
|
|
|
|
, end(m_extensions.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
|
|
|
|
if (pp) c->add_extension(pp);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-02-12 06:46:29 +01:00
|
|
|
try
|
|
|
|
{
|
|
|
|
assert(m_connections.find(a) == m_connections.end());
|
|
|
|
|
|
|
|
// add the newly connected peer to this torrent's peer list
|
|
|
|
m_connections.insert(
|
|
|
|
std::make_pair(a, boost::get_pointer(c)));
|
2007-05-05 02:29:33 +02:00
|
|
|
m_ses.m_connections.insert(std::make_pair(s, c));
|
2007-02-12 06:46:29 +01:00
|
|
|
|
2007-05-05 02:29:33 +02:00
|
|
|
m_ses.m_half_open.enqueue(
|
|
|
|
bind(&peer_connection::connect, c, _1)
|
|
|
|
, bind(&peer_connection::timed_out, c)
|
|
|
|
, seconds(settings().peer_connect_timeout));
|
2006-07-27 20:07:51 +02:00
|
|
|
}
|
2007-02-12 06:46:29 +01:00
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n";
|
|
|
|
#endif
|
2006-07-27 20:07:51 +02:00
|
|
|
|
2007-02-12 06:46:29 +01:00
|
|
|
// TODO: post an error alert!
|
|
|
|
std::map<tcp::endpoint, peer_connection*>::iterator i = m_connections.find(a);
|
|
|
|
if (i != m_connections.end()) m_connections.erase(i);
|
|
|
|
m_ses.connection_failed(s, a, e.what());
|
|
|
|
c->disconnect();
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2007-02-12 06:46:29 +01:00
|
|
|
catch (std::exception& exc)
|
|
|
|
{
|
2007-05-10 03:50:11 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
std::cerr << exc.what() << std::endl;
|
|
|
|
#endif
|
2007-02-12 06:46:29 +01:00
|
|
|
assert(false);
|
|
|
|
};
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2007-05-02 21:47:38 +02:00
|
|
|
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
2007-01-29 08:39:33 +01:00
|
|
|
void torrent::resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const
|
|
|
|
{
|
|
|
|
if (m_resolving_country
|
|
|
|
|| p->has_country()
|
|
|
|
|| p->is_connecting()
|
|
|
|
|| p->is_queued()
|
|
|
|
|| p->in_handshake()) return;
|
|
|
|
|
|
|
|
m_resolving_country = true;
|
|
|
|
tcp::resolver::query q(boost::lexical_cast<std::string>(p->remote().address())
|
|
|
|
+ ".zz.countries.nerd.dk", "0");
|
|
|
|
m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
|
|
|
|
bind(&torrent::on_country_lookup, shared_from_this(), _1, _2, p)));
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2007-05-06 00:55:34 +02:00
|
|
|
struct country_entry
|
2007-01-29 08:39:33 +01:00
|
|
|
{
|
2007-05-06 00:55:34 +02:00
|
|
|
int code;
|
|
|
|
char const* name;
|
|
|
|
};
|
2007-01-29 08:39:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::on_country_lookup(asio::error_code const& error, tcp::resolver::iterator i
|
|
|
|
, intrusive_ptr<peer_connection> p) const
|
|
|
|
{
|
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
m_resolving_country = false;
|
|
|
|
|
|
|
|
// must be ordered in increasing order
|
|
|
|
country_entry country_map[] =
|
|
|
|
{
|
2007-05-06 00:55:34 +02:00
|
|
|
{ 4, "AF"}, { 8, "AL"}, { 10, "AQ"}, { 12, "DZ"}, { 16, "AS"}
|
|
|
|
, { 20, "AD"}, { 24, "AO"}, { 28, "AG"}, { 31, "AZ"}, { 32, "AR"}
|
|
|
|
, { 36, "AU"}, { 40, "AT"}, { 44, "BS"}, { 48, "BH"}, { 50, "BD"}
|
|
|
|
, { 51, "AM"}, { 52, "BB"}, { 56, "BE"}, { 60, "BM"}, { 64, "BT"}
|
|
|
|
, { 68, "BO"}, { 70, "BA"}, { 72, "BW"}, { 74, "BV"}, { 76, "BR"}
|
|
|
|
, { 84, "BZ"}, { 86, "IO"}, { 90, "SB"}, { 92, "VG"}, { 96, "BN"}
|
|
|
|
, {100, "BG"}, {104, "MM"}, {108, "BI"}, {112, "BY"}, {116, "KH"}
|
|
|
|
, {120, "CM"}, {124, "CA"}, {132, "CV"}, {136, "KY"}, {140, "CF"}
|
|
|
|
, {144, "LK"}, {148, "TD"}, {152, "CL"}, {156, "CN"}, {158, "TW"}
|
|
|
|
, {162, "CX"}, {166, "CC"}, {170, "CO"}, {174, "KM"}, {175, "YT"}
|
|
|
|
, {178, "CG"}, {180, "CD"}, {184, "CK"}, {188, "CR"}, {191, "HR"}
|
|
|
|
, {192, "CU"}, {203, "CZ"}, {204, "BJ"}, {208, "DK"}, {212, "DM"}
|
|
|
|
, {214, "DO"}, {218, "EC"}, {222, "SV"}, {226, "GQ"}, {231, "ET"}
|
|
|
|
, {232, "ER"}, {233, "EE"}, {234, "FO"}, {238, "FK"}, {239, "GS"}
|
|
|
|
, {242, "FJ"}, {246, "FI"}, {248, "AX"}, {250, "FR"}, {254, "GF"}
|
|
|
|
, {258, "PF"}, {260, "TF"}, {262, "DJ"}, {266, "GA"}, {268, "GE"}
|
|
|
|
, {270, "GM"}, {275, "PS"}, {276, "DE"}, {288, "GH"}, {292, "GI"}
|
|
|
|
, {296, "KI"}, {300, "GR"}, {304, "GL"}, {308, "GD"}, {312, "GP"}
|
|
|
|
, {316, "GU"}, {320, "GT"}, {324, "GN"}, {328, "GY"}, {332, "HT"}
|
|
|
|
, {334, "HM"}, {336, "VA"}, {340, "HN"}, {344, "HK"}, {348, "HU"}
|
|
|
|
, {352, "IS"}, {356, "IN"}, {360, "ID"}, {364, "IR"}, {368, "IQ"}
|
|
|
|
, {372, "IE"}, {376, "IL"}, {380, "IT"}, {384, "CI"}, {388, "JM"}
|
|
|
|
, {392, "JP"}, {398, "KZ"}, {400, "JO"}, {404, "KE"}, {408, "KP"}
|
|
|
|
, {410, "KR"}, {414, "KW"}, {417, "KG"}, {418, "LA"}, {422, "LB"}
|
|
|
|
, {426, "LS"}, {428, "LV"}, {430, "LR"}, {434, "LY"}, {438, "LI"}
|
|
|
|
, {440, "LT"}, {442, "LU"}, {446, "MO"}, {450, "MG"}, {454, "MW"}
|
|
|
|
, {458, "MY"}, {462, "MV"}, {466, "ML"}, {470, "MT"}, {474, "MQ"}
|
|
|
|
, {478, "MR"}, {480, "MU"}, {484, "MX"}, {492, "MC"}, {496, "MN"}
|
|
|
|
, {498, "MD"}, {500, "MS"}, {504, "MA"}, {508, "MZ"}, {512, "OM"}
|
|
|
|
, {516, "NA"}, {520, "NR"}, {524, "NP"}, {528, "NL"}, {530, "AN"}
|
|
|
|
, {533, "AW"}, {540, "NC"}, {548, "VU"}, {554, "NZ"}, {558, "NI"}
|
|
|
|
, {562, "NE"}, {566, "NG"}, {570, "NU"}, {574, "NF"}, {578, "NO"}
|
|
|
|
, {580, "MP"}, {581, "UM"}, {583, "FM"}, {584, "MH"}, {585, "PW"}
|
|
|
|
, {586, "PK"}, {591, "PA"}, {598, "PG"}, {600, "PY"}, {604, "PE"}
|
|
|
|
, {608, "PH"}, {612, "PN"}, {616, "PL"}, {620, "PT"}, {624, "GW"}
|
|
|
|
, {626, "TL"}, {630, "PR"}, {634, "QA"}, {634, "QA"}, {638, "RE"}
|
|
|
|
, {642, "RO"}, {643, "RU"}, {646, "RW"}, {654, "SH"}, {659, "KN"}
|
|
|
|
, {660, "AI"}, {662, "LC"}, {666, "PM"}, {670, "VC"}, {674, "SM"}
|
|
|
|
, {678, "ST"}, {682, "SA"}, {686, "SN"}, {690, "SC"}, {694, "SL"}
|
|
|
|
, {702, "SG"}, {703, "SK"}, {704, "VN"}, {705, "SI"}, {706, "SO"}
|
|
|
|
, {710, "ZA"}, {716, "ZW"}, {724, "ES"}, {732, "EH"}, {736, "SD"}
|
|
|
|
, {740, "SR"}, {744, "SJ"}, {748, "SZ"}, {752, "SE"}, {756, "CH"}
|
|
|
|
, {760, "SY"}, {762, "TJ"}, {764, "TH"}, {768, "TG"}, {772, "TK"}
|
|
|
|
, {776, "TO"}, {780, "TT"}, {784, "AE"}, {788, "TN"}, {792, "TR"}
|
|
|
|
, {795, "TM"}, {796, "TC"}, {798, "TV"}, {800, "UG"}, {804, "UA"}
|
|
|
|
, {807, "MK"}, {818, "EG"}, {826, "GB"}, {834, "TZ"}, {840, "US"}
|
|
|
|
, {850, "VI"}, {854, "BF"}, {858, "UY"}, {860, "UZ"}, {862, "VE"}
|
|
|
|
, {876, "WF"}, {882, "WS"}, {887, "YE"}, {891, "CS"}, {894, "ZM"}
|
2007-01-29 08:39:33 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
if (error || i == tcp::resolver::iterator())
|
|
|
|
{
|
|
|
|
// this is used to indicate that we shouldn't
|
|
|
|
// try to resolve it again
|
|
|
|
p->set_country("--");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (i != tcp::resolver::iterator()
|
|
|
|
&& !i->endpoint().address().is_v4()) ++i;
|
|
|
|
if (i != tcp::resolver::iterator())
|
|
|
|
{
|
|
|
|
// country is an ISO 3166 country code
|
|
|
|
int country = i->endpoint().address().to_v4().to_ulong() & 0xffff;
|
|
|
|
|
|
|
|
// look up the country code in the map
|
|
|
|
const int size = sizeof(country_map)/sizeof(country_map[0]);
|
2007-05-06 00:55:34 +02:00
|
|
|
country_entry tmp = {country, ""};
|
2007-01-29 08:39:33 +01:00
|
|
|
country_entry* i =
|
2007-05-06 00:55:34 +02:00
|
|
|
std::lower_bound(country_map, country_map + size, tmp
|
|
|
|
, bind(&country_entry::code, _1) < bind(&country_entry::code, _2));
|
2007-01-29 08:39:33 +01:00
|
|
|
if (i == country_map + size
|
2007-05-06 00:55:34 +02:00
|
|
|
|| i->code != country)
|
2007-01-29 08:39:33 +01:00
|
|
|
{
|
|
|
|
// unknown country!
|
|
|
|
p->set_country("!!");
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
|
|
(*m_ses.m_logger) << "IP " << p->remote().address() << " was mapped to unknown country: " << country << "\n";
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-05-06 00:55:34 +02:00
|
|
|
p->set_country(i->name);
|
2007-01-29 08:39:33 +01:00
|
|
|
}
|
|
|
|
}
|
2007-05-02 21:47:38 +02:00
|
|
|
#endif
|
2007-01-29 08:39:33 +01:00
|
|
|
|
2007-05-02 19:38:37 +02:00
|
|
|
peer_connection* torrent::connect_to_peer(policy::peer* peerinfo)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
2007-05-02 19:38:37 +02:00
|
|
|
|
2007-05-04 18:35:29 +02:00
|
|
|
assert(peerinfo);
|
|
|
|
assert(peerinfo->connection == 0);
|
2007-05-12 22:25:44 +02:00
|
|
|
#ifndef NDEBUG
|
2007-05-24 20:53:55 +02:00
|
|
|
// this asserts that we don't have duplicates in the policy's peer list
|
2007-05-12 22:25:44 +02:00
|
|
|
peer_iterator i_ = m_connections.find(peerinfo->ip);
|
|
|
|
assert(i_ == m_connections.end()
|
2007-05-24 20:53:55 +02:00
|
|
|
|| i_->second->is_disconnecting()
|
2007-05-25 19:06:30 +02:00
|
|
|
|| dynamic_cast<bt_peer_connection*>(i_->second) == 0
|
|
|
|
|| m_ses.settings().allow_multiple_connections_per_ip);
|
2007-05-12 22:25:44 +02:00
|
|
|
#endif
|
2007-05-04 18:35:29 +02:00
|
|
|
|
2007-05-06 00:55:34 +02:00
|
|
|
assert(want_more_peers());
|
2007-05-02 19:38:37 +02:00
|
|
|
|
2007-04-10 23:23:13 +02:00
|
|
|
tcp::endpoint const& a(peerinfo->ip);
|
2007-05-07 20:19:53 +02:00
|
|
|
assert((m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked) == 0);
|
2006-11-24 15:22:52 +01:00
|
|
|
|
2007-04-25 20:26:35 +02:00
|
|
|
boost::shared_ptr<socket_type> s
|
|
|
|
= instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy());
|
2006-04-25 23:04:48 +02:00
|
|
|
boost::intrusive_ptr<peer_connection> c(new bt_peer_connection(
|
2007-04-10 23:23:13 +02:00
|
|
|
m_ses, shared_from_this(), s, a, peerinfo));
|
2006-11-19 16:29:58 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
c->m_in_constructor = false;
|
|
|
|
#endif
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
|
|
|
|
if (pp) c->add_extension(pp);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
// add the newly connected peer to this torrent's peer list
|
|
|
|
m_connections.insert(
|
|
|
|
std::make_pair(a, boost::get_pointer(c)));
|
2007-05-05 02:29:33 +02:00
|
|
|
m_ses.m_connections.insert(std::make_pair(s, c));
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2007-05-05 02:29:33 +02:00
|
|
|
m_ses.m_half_open.enqueue(
|
|
|
|
bind(&peer_connection::connect, c, _1)
|
|
|
|
, bind(&peer_connection::timed_out, c)
|
|
|
|
, seconds(settings().peer_connect_timeout));
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
// TODO: post an error alert!
|
|
|
|
std::map<tcp::endpoint, peer_connection*>::iterator i = m_connections.find(a);
|
|
|
|
if (i != m_connections.end()) m_connections.erase(i);
|
|
|
|
m_ses.connection_failed(s, a, e.what());
|
|
|
|
c->disconnect();
|
2006-01-06 21:20:20 +01:00
|
|
|
throw;
|
|
|
|
}
|
2006-06-25 00:30:59 +02:00
|
|
|
if (c->is_disconnecting()) throw protocol_error("failed to connect");
|
2007-05-02 19:38:37 +02:00
|
|
|
return c.get();
|
2003-12-01 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
void torrent::set_metadata(entry const& metadata)
|
|
|
|
{
|
|
|
|
m_torrent_file.parse_info_section(metadata);
|
|
|
|
|
|
|
|
boost::mutex::scoped_lock(m_checker.m_mutex);
|
|
|
|
|
|
|
|
boost::shared_ptr<aux::piece_checker_data> d(
|
|
|
|
new aux::piece_checker_data);
|
|
|
|
d->torrent_ptr = shared_from_this();
|
|
|
|
d->save_path = m_save_path;
|
|
|
|
d->info_hash = m_torrent_file.info_hash();
|
|
|
|
// add the torrent to the queue to be checked
|
|
|
|
m_checker.m_torrents.push_back(d);
|
|
|
|
typedef session_impl::torrent_map torrent_map;
|
|
|
|
torrent_map::iterator i = m_ses.m_torrents.find(
|
|
|
|
m_torrent_file.info_hash());
|
|
|
|
assert(i != m_ses.m_torrents.end());
|
|
|
|
m_ses.m_torrents.erase(i);
|
|
|
|
// and notify the thread that it got another
|
|
|
|
// job in its queue
|
|
|
|
m_checker.m_cond.notify_one();
|
|
|
|
|
|
|
|
if (m_ses.m_alerts.should_post(alert::info))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(metadata_received_alert(
|
|
|
|
get_handle(), "metadata successfully received from swarm"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-01 06:01:40 +01:00
|
|
|
void torrent::attach_peer(peer_connection* p)
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-01-25 13:37:15 +01:00
|
|
|
assert(p != 0);
|
2004-01-15 01:46:44 +01:00
|
|
|
assert(!p->is_local());
|
2004-01-13 04:08:59 +01:00
|
|
|
|
2006-09-27 19:17:41 +02:00
|
|
|
std::map<tcp::endpoint, peer_connection*>::iterator c
|
|
|
|
= m_connections.find(p->remote());
|
|
|
|
if (c != m_connections.end())
|
|
|
|
{
|
|
|
|
// we already have a peer_connection to this ip.
|
|
|
|
// It may currently be waiting for completing a
|
|
|
|
// connection attempt that might fail. So,
|
|
|
|
// prioritize this current connection since
|
|
|
|
// it has already succeeded.
|
|
|
|
if (!c->second->is_connecting())
|
|
|
|
{
|
|
|
|
throw protocol_error("already connected to peer");
|
|
|
|
}
|
|
|
|
c->second->disconnect();
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
if (m_ses.m_connections.find(p->get_socket())
|
|
|
|
== m_ses.m_connections.end())
|
|
|
|
{
|
|
|
|
throw protocol_error("peer is not properly constructed");
|
|
|
|
}
|
|
|
|
|
2006-10-11 16:02:21 +02:00
|
|
|
if (m_ses.is_aborted())
|
2006-05-28 21:03:54 +02:00
|
|
|
{
|
|
|
|
throw protocol_error("session is closing");
|
|
|
|
}
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
peer_iterator ci = m_connections.insert(
|
2006-04-25 23:04:48 +02:00
|
|
|
std::make_pair(p->remote(), p)).first;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// if new_connection throws, we have to remove the
|
|
|
|
// it from the list.
|
2005-10-01 17:12:10 +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)
|
|
|
|
{
|
|
|
|
boost::shared_ptr<peer_plugin> pp((*i)->new_connection(p));
|
|
|
|
if (pp) p->add_extension(pp);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
m_policy->new_connection(*ci->second);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
2006-11-14 01:08:16 +01:00
|
|
|
m_connections.erase(ci);
|
2006-04-25 23:04:48 +02:00
|
|
|
throw;
|
|
|
|
}
|
2007-04-25 20:26:35 +02:00
|
|
|
assert(p->remote() == p->get_socket()->remote_endpoint());
|
2005-10-01 17:12:10 +02:00
|
|
|
|
2005-10-01 13:20:47 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
m_policy->check_invariant();
|
|
|
|
#endif
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2007-05-02 19:38:37 +02:00
|
|
|
bool torrent::want_more_peers() const
|
|
|
|
{
|
2007-05-02 20:45:29 +02:00
|
|
|
return int(m_connections.size()) < m_connections_quota.given
|
2007-05-05 02:29:33 +02:00
|
|
|
&& m_ses.m_half_open.free_slots();
|
2007-05-02 19:38:37 +02:00
|
|
|
}
|
|
|
|
|
2004-01-20 23:59:21 +01:00
|
|
|
void torrent::disconnect_all()
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
while (!m_connections.empty())
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
peer_connection& p = *m_connections.begin()->second;
|
|
|
|
assert(p.associated_torrent().lock().get() == this);
|
2005-09-01 23:04:21 +02:00
|
|
|
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
2006-04-25 23:04:48 +02:00
|
|
|
if (m_abort)
|
|
|
|
(*p.m_logger) << "*** CLOSING CONNECTION 'aborting'\n";
|
|
|
|
else
|
|
|
|
(*p.m_logger) << "*** CLOSING CONNECTION 'pausing'\n";
|
2005-09-01 23:04:21 +02:00
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
std::size_t size = m_connections.size();
|
|
|
|
#endif
|
|
|
|
p.disconnect();
|
|
|
|
assert(m_connections.size() <= size);
|
2004-01-20 12:01:50 +01:00
|
|
|
}
|
|
|
|
}
|
2004-01-13 04:08:59 +01:00
|
|
|
|
2007-02-19 01:01:39 +01:00
|
|
|
bool torrent::request_bandwidth_from_session(int channel) const
|
|
|
|
{
|
|
|
|
int max_assignable = m_bandwidth_limit[channel].max_assignable();
|
|
|
|
return max_assignable > max_bandwidth_block_size
|
2007-02-19 22:24:48 +01:00
|
|
|
|| (m_bandwidth_limit[channel].throttle() < max_bandwidth_block_size
|
2007-02-20 00:06:20 +01:00
|
|
|
&& max_assignable == m_bandwidth_limit[channel].throttle());
|
|
|
|
}
|
|
|
|
|
|
|
|
int torrent::bandwidth_throttle(int channel) const
|
|
|
|
{
|
|
|
|
return m_bandwidth_limit[channel].throttle();
|
2007-02-19 01:01:39 +01:00
|
|
|
}
|
|
|
|
|
2007-01-10 16:02:25 +01:00
|
|
|
void torrent::request_bandwidth(int channel
|
2007-02-01 08:33:04 +01:00
|
|
|
, boost::intrusive_ptr<peer_connection> p
|
|
|
|
, bool non_prioritized)
|
2007-01-10 16:02:25 +01:00
|
|
|
{
|
2007-02-19 01:01:39 +01:00
|
|
|
if (request_bandwidth_from_session(channel))
|
2007-01-10 16:02:25 +01:00
|
|
|
{
|
|
|
|
if (channel == peer_connection::upload_channel)
|
2007-02-01 08:33:04 +01:00
|
|
|
m_ses.m_ul_bandwidth_manager.request_bandwidth(p, non_prioritized);
|
2007-01-10 16:02:25 +01:00
|
|
|
else if (channel == peer_connection::download_channel)
|
2007-02-01 08:33:04 +01:00
|
|
|
m_ses.m_dl_bandwidth_manager.request_bandwidth(p, non_prioritized);
|
2007-02-19 01:01:39 +01:00
|
|
|
|
2007-01-16 06:05:52 +01:00
|
|
|
m_bandwidth_limit[channel].assign(max_bandwidth_block_size);
|
2007-01-10 16:02:25 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-02-01 08:33:04 +01:00
|
|
|
m_bandwidth_queue[channel].push_back(bw_queue_entry(p, non_prioritized));
|
2007-01-10 16:02:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::expire_bandwidth(int channel, int amount)
|
|
|
|
{
|
2007-01-30 18:56:42 +01:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
|
2007-01-10 16:02:25 +01:00
|
|
|
assert(amount >= -1);
|
2007-01-16 06:05:52 +01:00
|
|
|
if (amount == -1) amount = max_bandwidth_block_size;
|
2007-01-10 16:02:25 +01:00
|
|
|
m_bandwidth_limit[channel].expire(amount);
|
|
|
|
|
2007-01-16 06:05:52 +01:00
|
|
|
while (!m_bandwidth_queue[channel].empty()
|
2007-02-19 01:01:39 +01:00
|
|
|
&& request_bandwidth_from_session(channel))
|
2007-01-10 16:02:25 +01:00
|
|
|
{
|
2007-02-01 08:33:04 +01:00
|
|
|
bw_queue_entry qe = m_bandwidth_queue[channel].front();
|
2007-01-10 16:02:25 +01:00
|
|
|
m_bandwidth_queue[channel].pop_front();
|
|
|
|
if (channel == peer_connection::upload_channel)
|
2007-02-01 08:33:04 +01:00
|
|
|
m_ses.m_ul_bandwidth_manager.request_bandwidth(qe.peer, qe.non_prioritized);
|
2007-01-10 16:02:25 +01:00
|
|
|
else if (channel == peer_connection::download_channel)
|
2007-02-01 08:33:04 +01:00
|
|
|
m_ses.m_dl_bandwidth_manager.request_bandwidth(qe.peer, qe.non_prioritized);
|
2007-01-16 06:05:52 +01:00
|
|
|
m_bandwidth_limit[channel].assign(max_bandwidth_block_size);
|
2007-01-10 16:02:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::assign_bandwidth(int channel, int amount)
|
|
|
|
{
|
2007-01-30 18:56:42 +01:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
|
2007-01-10 16:02:25 +01:00
|
|
|
assert(amount >= 0);
|
2007-01-16 06:05:52 +01:00
|
|
|
if (amount < max_bandwidth_block_size)
|
|
|
|
expire_bandwidth(channel, max_bandwidth_block_size - amount);
|
2007-01-10 16:02:25 +01:00
|
|
|
}
|
|
|
|
|
2005-06-11 01:12:50 +02:00
|
|
|
// called when torrent is finished (all interested pieces downloaded)
|
|
|
|
void torrent::finished()
|
2004-01-20 12:01:50 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-01-21 14:16:11 +01:00
|
|
|
if (alerts().should_post(alert::info))
|
|
|
|
{
|
|
|
|
alerts().post_alert(torrent_finished_alert(
|
|
|
|
get_handle()
|
2004-04-02 00:29:51 +02:00
|
|
|
, "torrent has finished downloading"));
|
2004-01-21 14:16:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// disconnect all seeds
|
2006-12-14 17:12:31 +01:00
|
|
|
// TODO: should disconnect all peers that have the pieces we have
|
|
|
|
// not just seeds
|
2006-04-25 23:04:48 +02:00
|
|
|
std::vector<peer_connection*> seeds;
|
2004-01-20 12:01:50 +01:00
|
|
|
for (peer_iterator i = m_connections.begin();
|
2005-06-11 01:12:50 +02:00
|
|
|
i != m_connections.end(); ++i)
|
2004-01-20 12:01:50 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
assert(i->second->associated_torrent().lock().get() == this);
|
2004-01-20 12:01:50 +01:00
|
|
|
if (i->second->is_seed())
|
2005-09-01 23:04:21 +02:00
|
|
|
{
|
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING)
|
|
|
|
(*i->second->m_logger) << "*** SEED, CLOSING CONNECTION\n";
|
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
seeds.push_back(i->second);
|
2005-09-01 23:04:21 +02:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
std::for_each(seeds.begin(), seeds.end()
|
|
|
|
, bind(&peer_connection::disconnect, _1));
|
2004-01-21 14:16:11 +01:00
|
|
|
|
2005-03-10 12:26:55 +01:00
|
|
|
m_storage->release_files();
|
2005-06-11 01:12:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// called when torrent is complete (all pieces downloaded)
|
|
|
|
void torrent::completed()
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-01-21 14:16:11 +01:00
|
|
|
// make the next tracker request
|
|
|
|
// be a completed-event
|
|
|
|
m_event = tracker_request::completed;
|
|
|
|
force_tracker_request();
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2004-09-12 12:12:16 +02:00
|
|
|
// this will move the tracker with the given index
|
|
|
|
// to a prioritized position in the list (move it towards
|
|
|
|
// the begining) and return the new index to the tracker.
|
|
|
|
int torrent::prioritize_tracker(int index)
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-09-12 12:12:16 +02:00
|
|
|
assert(index >= 0);
|
|
|
|
if (index >= (int)m_trackers.size()) return (int)m_trackers.size()-1;
|
|
|
|
|
|
|
|
while (index > 0 && m_trackers[index].tier == m_trackers[index-1].tier)
|
|
|
|
{
|
|
|
|
std::swap(m_trackers[index].url, m_trackers[index-1].url);
|
|
|
|
--index;
|
|
|
|
}
|
|
|
|
return index;
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
void torrent::try_next_tracker()
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-04-02 00:29:51 +02:00
|
|
|
++m_currently_trying_tracker;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-09-12 12:12:16 +02:00
|
|
|
if ((unsigned)m_currently_trying_tracker >= m_trackers.size())
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2004-04-02 00:29:51 +02:00
|
|
|
int delay = tracker_retry_delay_min
|
|
|
|
+ std::min(m_failed_trackers, (int)tracker_failed_max)
|
|
|
|
* (tracker_retry_delay_max - tracker_retry_delay_min)
|
|
|
|
/ tracker_failed_max;
|
|
|
|
|
|
|
|
++m_failed_trackers;
|
2003-10-23 01:00:57 +02:00
|
|
|
// if we've looped the tracker list, wait a bit before retrying
|
|
|
|
m_currently_trying_tracker = 0;
|
2007-04-05 00:27:36 +02:00
|
|
|
m_next_request = time_now() + seconds(delay);
|
2007-02-12 10:20:49 +01:00
|
|
|
|
2007-02-19 01:01:39 +01:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2007-04-04 04:06:07 +02:00
|
|
|
// only start the announce if we want to announce with the dht
|
|
|
|
if (should_announce_dht())
|
2007-02-12 10:20:49 +01:00
|
|
|
{
|
2007-05-17 02:01:51 +02:00
|
|
|
// force the DHT to reannounce
|
|
|
|
m_last_dht_announce = time_now() - minutes(15);
|
2007-04-11 19:22:19 +02:00
|
|
|
boost::weak_ptr<torrent> self(shared_from_this());
|
2007-04-05 00:27:36 +02:00
|
|
|
m_announce_timer.expires_from_now(seconds(1));
|
2007-04-04 04:06:07 +02:00
|
|
|
m_announce_timer.async_wait(m_ses.m_strand.wrap(
|
2007-04-11 19:22:19 +02:00
|
|
|
bind(&torrent::on_announce_disp, self, _1)));
|
2007-02-12 10:20:49 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// don't delay before trying the next tracker
|
2007-04-05 00:27:36 +02:00
|
|
|
m_next_request = time_now();
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2004-09-12 12:12:16 +02:00
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2006-10-11 16:02:21 +02:00
|
|
|
bool torrent::check_fastresume(aux::piece_checker_data& data)
|
2005-10-16 11:15:46 +02:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2005-10-16 11:15:46 +02:00
|
|
|
if (!m_storage.get())
|
|
|
|
{
|
|
|
|
// this means we have received the metadata through the
|
|
|
|
// metadata extension, and we have to initialize
|
|
|
|
init();
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2005-10-13 09:59:05 +02:00
|
|
|
assert(m_storage.get());
|
2006-12-31 00:02:21 +01:00
|
|
|
bool done = true;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces
|
|
|
|
, m_compact_mode);
|
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
// probably means file permission failure or invalid filename
|
|
|
|
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
|
|
|
|
m_num_pieces = 0;
|
|
|
|
|
|
|
|
if (m_ses.m_alerts.should_post(alert::fatal))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(
|
|
|
|
file_error_alert(
|
|
|
|
get_handle()
|
|
|
|
, e.what()));
|
|
|
|
}
|
|
|
|
pause();
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
m_initial_done = boost::get<0>(bytes_done());
|
|
|
|
#endif
|
|
|
|
return done;
|
2005-10-13 09:59:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<bool, float> torrent::check_files()
|
2003-11-07 02:44:30 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
assert(m_storage.get());
|
2006-12-31 00:02:21 +01:00
|
|
|
|
|
|
|
std::pair<bool, float> progress(true, 1.f);
|
|
|
|
try
|
|
|
|
{
|
2007-03-17 18:15:16 +01:00
|
|
|
progress = m_storage->check_files(m_have_pieces, m_num_pieces
|
|
|
|
, m_ses.m_mutex);
|
2006-12-31 00:02:21 +01:00
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
// probably means file permission failure or invalid filename
|
|
|
|
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
|
|
|
|
m_num_pieces = 0;
|
|
|
|
|
|
|
|
if (m_ses.m_alerts.should_post(alert::fatal))
|
|
|
|
{
|
|
|
|
m_ses.m_alerts.post_alert(
|
|
|
|
file_error_alert(
|
|
|
|
get_handle()
|
|
|
|
, e.what()));
|
|
|
|
}
|
|
|
|
pause();
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
m_initial_done = boost::get<0>(bytes_done());
|
|
|
|
#endif
|
|
|
|
return progress;
|
2005-10-13 09:59:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::files_checked(std::vector<piece_picker::downloading_piece> const&
|
|
|
|
unfinished_pieces)
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
|
|
|
|
INVARIANT_CHECK;
|
2003-12-07 16:03:06 +01:00
|
|
|
|
2006-12-04 13:20:34 +01:00
|
|
|
if (!is_seed())
|
|
|
|
{
|
2007-03-17 18:28:59 +01:00
|
|
|
m_picker->files_checked(m_have_pieces, unfinished_pieces);
|
2007-03-17 00:28:26 +01:00
|
|
|
if (m_sequenced_download_threshold > 0)
|
|
|
|
picker().set_sequenced_download_threshold(m_sequenced_download_threshold);
|
2006-12-04 13:20:34 +01:00
|
|
|
}
|
2007-05-10 00:54:26 +02:00
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
for (extension_list_t::iterator i = m_extensions.begin()
|
|
|
|
, end(m_extensions.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
try { (*i)->on_files_checked(); } catch (std::exception&) {}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (is_seed())
|
2006-12-04 13:20:34 +01:00
|
|
|
{
|
2007-03-17 18:28:59 +01:00
|
|
|
m_picker.reset();
|
2007-05-10 00:54:26 +02:00
|
|
|
m_torrent_file.seed_free();
|
2006-12-04 13:20:34 +01:00
|
|
|
}
|
2007-03-17 18:28:59 +01:00
|
|
|
|
2005-10-16 11:15:46 +02:00
|
|
|
if (!m_connections_initialized)
|
|
|
|
{
|
|
|
|
m_connections_initialized = true;
|
|
|
|
// all peer connections have to initialize themselves now that the metadata
|
|
|
|
// is available
|
2006-04-25 23:04:48 +02:00
|
|
|
typedef std::map<tcp::endpoint, peer_connection*> conn_map;
|
2005-10-16 11:15:46 +02:00
|
|
|
for (conn_map::iterator i = m_connections.begin()
|
2006-04-25 23:04:48 +02:00
|
|
|
, end(m_connections.end()); i != end;)
|
2005-10-16 11:15:46 +02:00
|
|
|
{
|
2006-11-14 01:08:16 +01:00
|
|
|
try
|
|
|
|
{
|
|
|
|
i->second->init();
|
|
|
|
i->second->on_metadata();
|
|
|
|
++i;
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
// the connection failed, close it
|
|
|
|
conn_map::iterator j = i;
|
|
|
|
++j;
|
|
|
|
m_ses.connection_failed(i->second->get_socket()
|
|
|
|
, i->first, e.what());
|
|
|
|
i = j;
|
|
|
|
}
|
2005-10-16 11:15:46 +02:00
|
|
|
}
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
m_initial_done = boost::get<0>(bytes_done());
|
|
|
|
#endif
|
2003-11-07 02:44:30 +01:00
|
|
|
}
|
|
|
|
|
2004-01-07 01:48:02 +01:00
|
|
|
alert_manager& torrent::alerts() const
|
|
|
|
{
|
|
|
|
return m_ses.m_alerts;
|
|
|
|
}
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
boost::filesystem::path torrent::save_path() const
|
|
|
|
{
|
2004-10-10 02:42:48 +02:00
|
|
|
return m_save_path;
|
2004-06-14 01:30:42 +02:00
|
|
|
}
|
|
|
|
|
2004-07-18 02:39:58 +02:00
|
|
|
bool torrent::move_storage(boost::filesystem::path const& save_path)
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2005-01-10 12:14:22 +01:00
|
|
|
bool ret = true;
|
|
|
|
if (m_storage.get())
|
|
|
|
{
|
|
|
|
ret = m_storage->move_storage(save_path);
|
|
|
|
m_save_path = m_storage->save_path();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_save_path = save_path;
|
|
|
|
}
|
2004-11-18 23:33:50 +01:00
|
|
|
return ret;
|
2004-07-18 02:39:58 +02:00
|
|
|
}
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
piece_manager& torrent::filesystem()
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
assert(m_storage.get());
|
|
|
|
return *m_storage;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-07 01:48:02 +01:00
|
|
|
torrent_handle torrent::get_handle() const
|
|
|
|
{
|
2006-05-28 21:03:54 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
return torrent_handle(&m_ses, &m_checker, m_torrent_file.info_hash());
|
2004-01-07 01:48:02 +01:00
|
|
|
}
|
|
|
|
|
2006-05-15 00:30:05 +02:00
|
|
|
session_settings const& torrent::settings() const
|
|
|
|
{
|
2006-12-11 13:48:33 +01:00
|
|
|
// INVARIANT_CHECK;
|
2006-05-28 21:03:54 +02:00
|
|
|
|
2006-10-11 16:02:21 +02:00
|
|
|
return m_ses.settings();
|
2006-05-15 00:30:05 +02:00
|
|
|
}
|
2004-01-07 01:48:02 +01:00
|
|
|
|
2003-12-14 06:56:12 +01:00
|
|
|
#ifndef NDEBUG
|
2004-06-14 01:30:42 +02:00
|
|
|
void torrent::check_invariant() const
|
2003-12-14 06:56:12 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
// size_type download = m_stat.total_payload_download();
|
|
|
|
// size_type done = boost::get<0>(bytes_done());
|
|
|
|
// assert(download >= done - m_initial_done);
|
|
|
|
for (const_peer_iterator i = begin(); i != end(); ++i)
|
2006-05-28 21:03:54 +02:00
|
|
|
{
|
|
|
|
peer_connection const& p = *i->second;
|
|
|
|
torrent* associated_torrent = p.associated_torrent().lock().get();
|
|
|
|
if (associated_torrent != this)
|
|
|
|
assert(false);
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2006-12-11 13:48:33 +01:00
|
|
|
if (valid_metadata())
|
|
|
|
{
|
2006-12-14 17:12:31 +01:00
|
|
|
assert(int(m_have_pieces.size()) == m_torrent_file.num_pieces());
|
2006-12-11 13:48:33 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(m_have_pieces.empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
size_type total_done = quantized_bytes_done();
|
2007-02-15 04:03:50 +01:00
|
|
|
if (m_torrent_file.is_valid())
|
|
|
|
{
|
|
|
|
if (is_seed())
|
|
|
|
assert(total_done == m_torrent_file.total_size());
|
|
|
|
else
|
|
|
|
assert(total_done != m_torrent_file.total_size());
|
|
|
|
}
|
2006-12-11 13:48:33 +01:00
|
|
|
else
|
2007-02-15 04:03:50 +01:00
|
|
|
{
|
|
|
|
assert(total_done == 0);
|
|
|
|
}
|
2006-12-11 13:48:33 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// This check is very expensive.
|
2006-12-18 02:23:30 +01:00
|
|
|
assert(m_num_pieces
|
|
|
|
== std::count(m_have_pieces.begin(), m_have_pieces.end(), true));
|
2004-06-14 01:30:42 +02:00
|
|
|
assert(!valid_metadata() || m_block_size > 0);
|
|
|
|
assert(!valid_metadata() || (m_torrent_file.piece_length() % m_block_size) == 0);
|
2006-12-04 13:20:34 +01:00
|
|
|
// if (is_seed()) assert(m_picker.get() == 0);
|
2003-12-14 06:56:12 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-09-04 19:17:45 +02:00
|
|
|
void torrent::set_sequenced_download_threshold(int threshold)
|
|
|
|
{
|
2007-03-17 00:28:26 +01:00
|
|
|
if (has_picker())
|
|
|
|
{
|
2006-09-04 19:17:45 +02:00
|
|
|
picker().set_sequenced_download_threshold(threshold);
|
2007-03-17 00:28:26 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_sequenced_download_threshold = threshold;
|
|
|
|
}
|
2006-09-04 19:17:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-29 15:21:09 +02:00
|
|
|
void torrent::set_max_uploads(int limit)
|
|
|
|
{
|
|
|
|
assert(limit >= -1);
|
|
|
|
if (limit == -1) limit = std::numeric_limits<int>::max();
|
|
|
|
m_uploads_quota.max = std::max(m_uploads_quota.min, limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::set_max_connections(int limit)
|
|
|
|
{
|
|
|
|
assert(limit >= -1);
|
|
|
|
if (limit == -1) limit = std::numeric_limits<int>::max();
|
|
|
|
m_connections_quota.max = std::max(m_connections_quota.min, limit);
|
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit)
|
|
|
|
{
|
2006-05-02 01:34:37 +02:00
|
|
|
assert(limit >= -1);
|
2006-04-25 23:04:48 +02:00
|
|
|
peer_connection* p = connection_for(ip);
|
|
|
|
if (p == 0) return;
|
|
|
|
p->set_upload_limit(limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::set_peer_download_limit(tcp::endpoint ip, int limit)
|
|
|
|
{
|
2006-05-02 01:34:37 +02:00
|
|
|
assert(limit >= -1);
|
2006-04-25 23:04:48 +02:00
|
|
|
peer_connection* p = connection_for(ip);
|
|
|
|
if (p == 0) return;
|
|
|
|
p->set_download_limit(limit);
|
|
|
|
}
|
|
|
|
|
2004-07-24 13:54:17 +02:00
|
|
|
void torrent::set_upload_limit(int limit)
|
|
|
|
{
|
|
|
|
assert(limit >= -1);
|
|
|
|
if (limit == -1) limit = std::numeric_limits<int>::max();
|
|
|
|
if (limit < num_peers() * 10) limit = num_peers() * 10;
|
2007-01-10 16:02:25 +01:00
|
|
|
m_bandwidth_limit[peer_connection::upload_channel].throttle(limit);
|
2004-07-24 13:54:17 +02:00
|
|
|
}
|
|
|
|
|
2007-04-10 11:25:17 +02:00
|
|
|
int torrent::upload_limit() const
|
|
|
|
{
|
|
|
|
int limit = m_bandwidth_limit[peer_connection::upload_channel].throttle();
|
|
|
|
if (limit == std::numeric_limits<int>::max()) limit = -1;
|
|
|
|
return limit;
|
|
|
|
}
|
|
|
|
|
2004-07-24 13:54:17 +02:00
|
|
|
void torrent::set_download_limit(int limit)
|
|
|
|
{
|
|
|
|
assert(limit >= -1);
|
|
|
|
if (limit == -1) limit = std::numeric_limits<int>::max();
|
|
|
|
if (limit < num_peers() * 10) limit = num_peers() * 10;
|
2007-01-10 16:02:25 +01:00
|
|
|
m_bandwidth_limit[peer_connection::download_channel].throttle(limit);
|
2004-07-24 13:54:17 +02:00
|
|
|
}
|
|
|
|
|
2007-04-10 11:25:17 +02:00
|
|
|
int torrent::download_limit() const
|
|
|
|
{
|
|
|
|
int limit = m_bandwidth_limit[peer_connection::download_channel].throttle();
|
|
|
|
if (limit == std::numeric_limits<int>::max()) limit = -1;
|
|
|
|
return limit;
|
|
|
|
}
|
|
|
|
|
2004-03-21 03:03:37 +01:00
|
|
|
void torrent::pause()
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-12-21 13:30:09 +01:00
|
|
|
if (m_paused) return;
|
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)
|
|
|
|
{
|
|
|
|
try { if ((*i)->on_pause()) return; } catch (std::exception&) {}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-03-21 03:03:37 +01:00
|
|
|
disconnect_all();
|
|
|
|
m_paused = true;
|
2004-07-24 13:54:17 +02:00
|
|
|
// tell the tracker that we stopped
|
|
|
|
m_event = tracker_request::stopped;
|
|
|
|
m_just_paused = true;
|
2005-03-05 15:17:17 +01:00
|
|
|
// this will make the storage close all
|
|
|
|
// files and flush all cached data
|
2005-03-10 12:26:55 +01:00
|
|
|
if (m_storage.get()) m_storage->release_files();
|
2004-03-21 03:03:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void torrent::resume()
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-12-21 13:30:09 +01:00
|
|
|
if (!m_paused) return;
|
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)
|
|
|
|
{
|
|
|
|
try { if ((*i)->on_resume()) return; } catch (std::exception&) {}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-03-21 03:03:37 +01:00
|
|
|
m_paused = false;
|
2007-02-12 19:21:14 +01:00
|
|
|
m_uploads_quota.min = 2;
|
|
|
|
m_connections_quota.min = 2;
|
|
|
|
m_uploads_quota.max = std::numeric_limits<int>::max();
|
|
|
|
m_connections_quota.max = std::numeric_limits<int>::max();
|
2004-07-24 13:54:17 +02:00
|
|
|
|
|
|
|
// tell the tracker that we're back
|
|
|
|
m_event = tracker_request::started;
|
|
|
|
force_tracker_request();
|
|
|
|
|
2004-03-21 03:03:37 +01:00
|
|
|
// make pulse be called as soon as possible
|
|
|
|
m_time_scaler = 0;
|
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
void torrent::second_tick(stat& accumulator, float tick_interval)
|
2003-12-01 06:01:40 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-10-29 15:21:09 +02:00
|
|
|
m_connections_quota.used = (int)m_connections.size();
|
|
|
|
m_uploads_quota.used = m_policy->num_uploads();
|
2003-12-07 06:53:04 +01: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)
|
|
|
|
{
|
|
|
|
try { (*i)->tick(); } catch (std::exception&) {}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-03-30 01:47:13 +02:00
|
|
|
if (m_paused)
|
|
|
|
{
|
|
|
|
// let the stats fade out to 0
|
2006-04-25 23:04:48 +02:00
|
|
|
m_stat.second_tick(tick_interval);
|
2007-02-12 06:46:29 +01:00
|
|
|
m_connections_quota.min = 0;
|
|
|
|
m_connections_quota.max = 0;
|
|
|
|
m_uploads_quota.min = 0;
|
|
|
|
m_uploads_quota.max = 0;
|
2005-03-30 01:47:13 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// ---- WEB SEEDS ----
|
|
|
|
|
2007-04-12 00:27:58 +02:00
|
|
|
// if we have everything we want we don't need to connect to any web-seed
|
|
|
|
if (!is_finished() && !m_web_seeds.empty())
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
|
|
|
// keep trying web-seeds if there are any
|
|
|
|
// first find out which web seeds we are connected to
|
|
|
|
std::set<std::string> web_seeds;
|
|
|
|
for (peer_iterator i = m_connections.begin();
|
|
|
|
i != m_connections.end(); ++i)
|
|
|
|
{
|
|
|
|
web_peer_connection* p
|
|
|
|
= dynamic_cast<web_peer_connection*>(i->second);
|
|
|
|
if (!p) continue;
|
|
|
|
web_seeds.insert(p->url());
|
|
|
|
}
|
|
|
|
|
2006-05-20 17:30:40 +02:00
|
|
|
for (std::set<std::string>::iterator i = m_resolving_web_seeds.begin()
|
|
|
|
, end(m_resolving_web_seeds.end()); i != end; ++i)
|
|
|
|
web_seeds.insert(web_seeds.begin(), *i);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
// from the list of available web seeds, subtract the ones we are
|
|
|
|
// already connected to.
|
|
|
|
std::vector<std::string> not_connected_web_seeds;
|
|
|
|
std::set_difference(m_web_seeds.begin(), m_web_seeds.end(), web_seeds.begin()
|
|
|
|
, web_seeds.end(), std::back_inserter(not_connected_web_seeds));
|
|
|
|
|
|
|
|
// connect to all of those that we aren't connected to
|
|
|
|
std::for_each(not_connected_web_seeds.begin(), not_connected_web_seeds.end()
|
|
|
|
, bind(&torrent::connect_to_url_seed, this, _1));
|
|
|
|
}
|
|
|
|
|
2004-01-13 04:08:59 +01:00
|
|
|
for (peer_iterator i = m_connections.begin();
|
2007-05-24 19:07:43 +02:00
|
|
|
i != m_connections.end();)
|
2003-12-07 06:53:04 +01:00
|
|
|
{
|
2004-01-13 04:08:59 +01:00
|
|
|
peer_connection* p = i->second;
|
2007-05-24 19:07:43 +02:00
|
|
|
++i;
|
2004-03-23 23:58:18 +01:00
|
|
|
m_stat += p->statistics();
|
2004-03-28 19:45:37 +02:00
|
|
|
// updates the peer connection's ul/dl bandwidth
|
|
|
|
// resource requests
|
2007-05-24 19:07:43 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
p->second_tick(tick_interval);
|
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
#ifdef TORRENT_VERBOSE_LOGGING
|
|
|
|
(*p->m_logger) << "**ERROR**: " << e.what() << "\n";
|
|
|
|
#endif
|
|
|
|
p->set_failed();
|
|
|
|
p->disconnect();
|
|
|
|
}
|
2003-12-07 06:53:04 +01:00
|
|
|
}
|
2004-04-18 15:41:08 +02:00
|
|
|
accumulator += m_stat;
|
2006-07-26 12:21:25 +02:00
|
|
|
m_stat.second_tick(tick_interval);
|
2003-12-07 06:53:04 +01:00
|
|
|
}
|
|
|
|
|
2007-05-05 02:29:33 +02:00
|
|
|
void torrent::try_connect_peer()
|
|
|
|
{
|
|
|
|
assert(want_more_peers());
|
|
|
|
m_policy->connect_one_peer();
|
|
|
|
}
|
|
|
|
|
2006-11-20 22:03:58 +01:00
|
|
|
void torrent::distribute_resources(float tick_interval)
|
2004-03-23 23:58:18 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-10-29 15:21:09 +02:00
|
|
|
m_time_scaler--;
|
|
|
|
if (m_time_scaler <= 0)
|
|
|
|
{
|
|
|
|
m_time_scaler = 10;
|
|
|
|
m_policy->pulse();
|
|
|
|
}
|
2004-03-23 23:58:18 +01:00
|
|
|
}
|
|
|
|
|
2003-12-07 06:53:04 +01:00
|
|
|
bool torrent::verify_piece(int piece_index)
|
|
|
|
{
|
2006-12-31 15:48:18 +01:00
|
|
|
// INVARIANT_CHECK;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
assert(m_storage.get());
|
2004-01-25 13:37:15 +01:00
|
|
|
assert(piece_index >= 0);
|
|
|
|
assert(piece_index < m_torrent_file.num_pieces());
|
2005-02-23 09:57:54 +01:00
|
|
|
assert(piece_index < (int)m_have_pieces.size());
|
2004-01-25 13:37:15 +01:00
|
|
|
|
2004-03-07 21:50:56 +01:00
|
|
|
int size = static_cast<int>(m_torrent_file.piece_size(piece_index));
|
2003-12-07 06:53:04 +01:00
|
|
|
std::vector<char> buffer(size);
|
2003-12-17 17:37:20 +01:00
|
|
|
assert(size > 0);
|
2004-06-14 01:30:42 +02:00
|
|
|
m_storage->read(&buffer[0], piece_index, 0, size);
|
2003-12-07 06:53:04 +01:00
|
|
|
|
|
|
|
hasher h;
|
|
|
|
h.update(&buffer[0], size);
|
|
|
|
sha1_hash digest = h.final();
|
|
|
|
|
|
|
|
if (m_torrent_file.hash_for_piece(piece_index) != digest)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
2003-12-01 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
const tcp::endpoint& torrent::current_tracker() const
|
2004-03-01 01:50:00 +01:00
|
|
|
{
|
|
|
|
return m_tracker_address;
|
|
|
|
}
|
|
|
|
|
2005-10-17 15:45:53 +02:00
|
|
|
bool torrent::is_allocating() const
|
|
|
|
{ return m_storage.get() && m_storage->is_allocating(); }
|
|
|
|
|
2006-06-12 01:24:36 +02:00
|
|
|
void torrent::file_progress(std::vector<float>& fp) const
|
|
|
|
{
|
|
|
|
assert(valid_metadata());
|
|
|
|
|
|
|
|
fp.clear();
|
|
|
|
fp.resize(m_torrent_file.num_files(), 0.f);
|
|
|
|
|
|
|
|
for (int i = 0; i < m_torrent_file.num_files(); ++i)
|
|
|
|
{
|
2006-08-27 20:38:30 +02:00
|
|
|
peer_request ret = m_torrent_file.map_file(i, 0, 0);
|
|
|
|
size_type size = m_torrent_file.file_at(i).size;
|
2006-10-08 22:36:05 +02:00
|
|
|
|
|
|
|
// zero sized files are considered
|
|
|
|
// 100% done all the time
|
|
|
|
if (size == 0)
|
|
|
|
{
|
|
|
|
fp[i] = 1.f;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2006-06-12 01:24:36 +02:00
|
|
|
size_type done = 0;
|
2006-08-27 20:38:30 +02:00
|
|
|
while (size > 0)
|
2006-06-12 01:24:36 +02:00
|
|
|
{
|
|
|
|
size_type bytes_step = std::min(m_torrent_file.piece_size(ret.piece)
|
2006-08-27 20:38:30 +02:00
|
|
|
- ret.start, size);
|
2006-06-12 01:24:36 +02:00
|
|
|
if (m_have_pieces[ret.piece]) done += bytes_step;
|
|
|
|
++ret.piece;
|
|
|
|
ret.start = 0;
|
2006-08-27 20:38:30 +02:00
|
|
|
size -= bytes_step;
|
2006-06-12 01:24:36 +02:00
|
|
|
}
|
2006-08-27 20:38:30 +02:00
|
|
|
assert(size == 0);
|
2006-10-08 22:36:05 +02:00
|
|
|
|
2006-06-12 01:24:36 +02:00
|
|
|
fp[i] = static_cast<float>(done) / m_torrent_file.file_at(i).size;
|
|
|
|
}
|
|
|
|
}
|
2005-10-16 18:58:41 +02:00
|
|
|
|
2003-10-31 05:02:51 +01:00
|
|
|
torrent_status torrent::status() const
|
2003-10-26 18:35:23 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-01-15 17:45:34 +01:00
|
|
|
assert(std::accumulate(
|
|
|
|
m_have_pieces.begin()
|
|
|
|
, m_have_pieces.end()
|
|
|
|
, 0) == m_num_pieces);
|
2003-10-30 00:28:09 +01:00
|
|
|
|
2004-01-15 17:45:34 +01:00
|
|
|
torrent_status st;
|
2003-10-30 00:28:09 +01:00
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end(),
|
2006-04-25 23:04:48 +02:00
|
|
|
boost::bind<bool>(std::logical_not<bool>(), boost::bind(&peer_connection::is_connecting,
|
|
|
|
boost::bind(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1))));
|
2005-11-05 11:56:47 +01:00
|
|
|
|
2005-02-23 21:38:29 +01:00
|
|
|
st.num_complete = m_complete;
|
|
|
|
st.num_incomplete = m_incomplete;
|
2004-03-21 03:03:37 +01:00
|
|
|
st.paused = m_paused;
|
2005-05-30 19:43:03 +02:00
|
|
|
boost::tie(st.total_done, st.total_wanted_done) = bytes_done();
|
2003-10-31 13:07:07 +01:00
|
|
|
|
2003-12-22 08:14:35 +01:00
|
|
|
// payload transfer
|
|
|
|
st.total_payload_download = m_stat.total_payload_download();
|
|
|
|
st.total_payload_upload = m_stat.total_payload_upload();
|
|
|
|
|
|
|
|
// total transfer
|
|
|
|
st.total_download = m_stat.total_payload_download()
|
|
|
|
+ m_stat.total_protocol_download();
|
|
|
|
st.total_upload = m_stat.total_payload_upload()
|
|
|
|
+ m_stat.total_protocol_upload();
|
|
|
|
|
2004-04-18 14:28:02 +02:00
|
|
|
// failed bytes
|
|
|
|
st.total_failed_bytes = m_total_failed_bytes;
|
2006-04-25 23:04:48 +02:00
|
|
|
st.total_redundant_bytes = m_total_redundant_bytes;
|
2004-04-18 14:28:02 +02:00
|
|
|
|
2003-12-22 08:14:35 +01:00
|
|
|
// transfer rate
|
2003-12-07 06:53:04 +01:00
|
|
|
st.download_rate = m_stat.download_rate();
|
|
|
|
st.upload_rate = m_stat.upload_rate();
|
2004-04-18 14:28:02 +02:00
|
|
|
st.download_payload_rate = m_stat.download_payload_rate();
|
|
|
|
st.upload_payload_rate = m_stat.upload_payload_rate();
|
2003-12-22 08:14:35 +01:00
|
|
|
|
2007-04-05 00:27:36 +02:00
|
|
|
st.next_announce = boost::posix_time::seconds(
|
|
|
|
total_seconds(next_announce() - time_now()));
|
|
|
|
if (st.next_announce.is_negative())
|
|
|
|
st.next_announce = boost::posix_time::seconds(0);
|
|
|
|
|
2004-01-17 21:04:19 +01:00
|
|
|
st.announce_interval = boost::posix_time::seconds(m_duration);
|
|
|
|
|
2005-03-11 18:21:56 +01:00
|
|
|
if (m_last_working_tracker >= 0)
|
|
|
|
{
|
|
|
|
st.current_tracker
|
|
|
|
= m_trackers[m_last_working_tracker].url;
|
|
|
|
}
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
// if we don't have any metadata, stop here
|
|
|
|
|
|
|
|
if (!valid_metadata())
|
|
|
|
{
|
|
|
|
if (m_got_tracker_response == false)
|
|
|
|
st.state = torrent_status::connecting_to_tracker;
|
|
|
|
else
|
|
|
|
st.state = torrent_status::downloading_metadata;
|
2004-09-16 03:14:16 +02:00
|
|
|
|
2006-12-14 17:12:31 +01:00
|
|
|
// TODO: add a progress member to the torrent that will be used in this case
|
2006-11-14 01:08:16 +01:00
|
|
|
// and that may be set by a plugin
|
|
|
|
// if (m_metadata_size == 0) st.progress = 0.f;
|
|
|
|
// else st.progress = std::min(1.f, m_metadata_progress / (float)m_metadata_size);
|
|
|
|
st.progress = 0.f;
|
2004-09-16 03:14:16 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
st.block_size = 0;
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
return st;
|
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
st.block_size = block_size();
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
// fill in status that depends on metadata
|
|
|
|
|
2005-05-30 19:43:03 +02:00
|
|
|
st.total_wanted = m_torrent_file.total_size();
|
|
|
|
|
|
|
|
if (m_picker.get() && (m_picker->num_filtered() > 0
|
|
|
|
|| m_picker->num_have_filtered() > 0))
|
|
|
|
{
|
|
|
|
int filtered_pieces = m_picker->num_filtered()
|
|
|
|
+ m_picker->num_have_filtered();
|
|
|
|
int last_piece_index = m_torrent_file.num_pieces() - 1;
|
2007-03-15 23:03:56 +01:00
|
|
|
if (m_picker->piece_priority(last_piece_index) == 0)
|
2005-05-30 19:43:03 +02:00
|
|
|
{
|
|
|
|
st.total_wanted -= m_torrent_file.piece_size(last_piece_index);
|
|
|
|
--filtered_pieces;
|
|
|
|
}
|
|
|
|
|
|
|
|
st.total_wanted -= filtered_pieces * m_torrent_file.piece_length();
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(st.total_wanted >= st.total_wanted_done);
|
2005-08-15 00:04:58 +02:00
|
|
|
|
|
|
|
if (st.total_wanted == 0) st.progress = 1.f;
|
|
|
|
else st.progress = st.total_wanted_done
|
2006-04-25 23:04:48 +02:00
|
|
|
/ static_cast<double>(st.total_wanted);
|
2004-01-15 02:01:09 +01:00
|
|
|
|
2004-01-15 17:45:34 +01:00
|
|
|
st.pieces = &m_have_pieces;
|
2006-04-25 23:04:48 +02:00
|
|
|
st.num_pieces = m_num_pieces;
|
2003-11-20 20:58:29 +01:00
|
|
|
|
2003-12-22 08:14:35 +01:00
|
|
|
if (m_got_tracker_response == false)
|
2006-12-11 13:48:33 +01:00
|
|
|
{
|
2003-12-22 08:14:35 +01:00
|
|
|
st.state = torrent_status::connecting_to_tracker;
|
2006-12-11 13:48:33 +01:00
|
|
|
}
|
|
|
|
else if (is_seed())
|
|
|
|
{
|
|
|
|
assert(st.total_done == m_torrent_file.total_size());
|
2003-10-31 05:02:51 +01:00
|
|
|
st.state = torrent_status::seeding;
|
2006-12-11 13:48:33 +01:00
|
|
|
}
|
2005-05-30 19:43:03 +02:00
|
|
|
else if (st.total_wanted_done == st.total_wanted)
|
2006-12-11 13:48:33 +01:00
|
|
|
{
|
|
|
|
assert(st.total_done != m_torrent_file.total_size());
|
2005-05-30 19:43:03 +02:00
|
|
|
st.state = torrent_status::finished;
|
2006-12-11 13:48:33 +01:00
|
|
|
}
|
2003-10-31 05:02:51 +01:00
|
|
|
else
|
2006-12-11 13:48:33 +01:00
|
|
|
{
|
2003-10-31 05:02:51 +01:00
|
|
|
st.state = torrent_status::downloading;
|
2006-12-11 13:48:33 +01:00
|
|
|
}
|
2003-10-31 05:02:51 +01:00
|
|
|
|
2004-08-05 15:56:26 +02:00
|
|
|
st.num_seeds = num_seeds();
|
2006-12-04 13:20:34 +01:00
|
|
|
if (m_picker.get())
|
|
|
|
st.distributed_copies = m_picker->distributed_copies();
|
|
|
|
else
|
|
|
|
st.distributed_copies = -1;
|
2003-10-31 05:02:51 +01:00
|
|
|
return st;
|
2003-10-26 18:35:23 +01:00
|
|
|
}
|
|
|
|
|
2004-08-05 15:56:26 +02:00
|
|
|
int torrent::num_seeds() const
|
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2004-10-18 00:23:08 +02:00
|
|
|
return (int)std::count_if(m_connections.begin(), m_connections.end(),
|
2004-08-05 15:56:26 +02:00
|
|
|
boost::bind(&peer_connection::is_seed,
|
2006-11-14 01:08:16 +01:00
|
|
|
boost::bind(&std::map<tcp::endpoint
|
|
|
|
,peer_connection*>::value_type::second, _1)));
|
2004-09-12 15:53:00 +02:00
|
|
|
}
|
|
|
|
|
2005-03-24 13:13:47 +01:00
|
|
|
void torrent::tracker_request_timed_out(
|
|
|
|
tracker_request const&)
|
2003-12-22 08:14:35 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
2007-03-31 00:00:26 +02:00
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2005-07-06 15:18:10 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2003-12-22 08:14:35 +01:00
|
|
|
debug_log("*** tracker timed out");
|
|
|
|
#endif
|
2006-05-28 21:03:54 +02:00
|
|
|
|
2003-12-22 08:14:35 +01:00
|
|
|
if (m_ses.m_alerts.should_post(alert::warning))
|
|
|
|
{
|
|
|
|
std::stringstream s;
|
|
|
|
s << "tracker: \""
|
2004-09-12 12:12:16 +02:00
|
|
|
<< m_trackers[m_currently_trying_tracker].url
|
2003-12-22 08:14:35 +01:00
|
|
|
<< "\" timed out";
|
2004-09-12 12:12:16 +02:00
|
|
|
m_ses.m_alerts.post_alert(tracker_alert(get_handle()
|
2005-04-21 01:00:27 +02:00
|
|
|
, m_failed_trackers + 1, 0, s.str()));
|
2003-12-22 08:14:35 +01:00
|
|
|
}
|
|
|
|
try_next_tracker();
|
|
|
|
}
|
|
|
|
|
2004-01-26 11:29:00 +01:00
|
|
|
// TODO: with some response codes, we should just consider
|
2003-12-22 08:14:35 +01:00
|
|
|
// the tracker as a failure and not retry
|
|
|
|
// it anymore
|
2005-04-24 02:50:52 +02:00
|
|
|
void torrent::tracker_request_error(tracker_request const&
|
2005-03-24 13:13:47 +01:00
|
|
|
, int response_code, const std::string& str)
|
2003-12-22 08:14:35 +01:00
|
|
|
{
|
2007-03-31 00:00:26 +02:00
|
|
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
|
|
|
2006-05-28 21:03:54 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2005-07-06 15:18:10 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2003-12-22 08:14:35 +01:00
|
|
|
debug_log(std::string("*** tracker error: ") + str);
|
|
|
|
#endif
|
|
|
|
if (m_ses.m_alerts.should_post(alert::warning))
|
|
|
|
{
|
|
|
|
std::stringstream s;
|
|
|
|
s << "tracker: \""
|
2004-09-12 12:12:16 +02:00
|
|
|
<< m_trackers[m_currently_trying_tracker].url
|
2003-12-22 08:14:35 +01:00
|
|
|
<< "\" " << str;
|
2004-09-12 12:12:16 +02:00
|
|
|
m_ses.m_alerts.post_alert(tracker_alert(get_handle()
|
2005-04-21 01:00:27 +02:00
|
|
|
, m_failed_trackers + 1, response_code, s.str()));
|
2003-12-22 08:14:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
try_next_tracker();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-06 15:18:10 +02:00
|
|
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
2003-11-20 20:58:29 +01:00
|
|
|
void torrent::debug_log(const std::string& line)
|
|
|
|
{
|
2003-12-07 06:53:04 +01:00
|
|
|
(*m_ses.m_logger) << line << "\n";
|
2003-11-20 20:58:29 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-06-15 14:54:35 +02:00
|
|
|
}
|
|
|
|
|