00001
00002
00003
00004
00005
00006 #include <ctime>
00007 #include <iostream>
00008 #include <fstream>
00009 #include <iomanip>
00010 #include <iterator>
00011 #include <algorithm>
00012 #include <set>
00013 #include <cctype>
00014 #include <numeric>
00015
00016 #ifdef _MSC_VER
00017 #pragma warning(push, 1)
00018 #endif
00019
00020 #include <boost/lexical_cast.hpp>
00021 #include <boost/filesystem/convenience.hpp>
00022 #include <boost/bind.hpp>
00023 #include <boost/thread/mutex.hpp>
00024
00025 #ifdef _MSC_VER
00026 #pragma warning(pop)
00027 #endif
00028
00029 #include "libtorrent/torrent_handle.hpp"
00030 #include "libtorrent/session.hpp"
00031 #include "libtorrent/torrent_info.hpp"
00032 #include "libtorrent/tracker_manager.hpp"
00033 #include "libtorrent/bencode.hpp"
00034 #include "libtorrent/hasher.hpp"
00035 #include "libtorrent/entry.hpp"
00036 #include "libtorrent/peer.hpp"
00037 #include "libtorrent/bt_peer_connection.hpp"
00038 #include "libtorrent/web_peer_connection.hpp"
00039 #include "libtorrent/peer_id.hpp"
00040 #include "libtorrent/alert.hpp"
00041 #include "libtorrent/identify_client.hpp"
00042 #include "libtorrent/alert_types.hpp"
00043 #include "libtorrent/extensions.hpp"
00044 #include "libtorrent/aux_/session_impl.hpp"
00045
00046 using namespace libtorrent;
00047 using namespace boost::posix_time;
00048 using boost::tuples::tuple;
00049 using boost::tuples::get;
00050 using boost::tuples::make_tuple;
00051 using boost::filesystem::complete;
00052 using boost::bind;
00053 using boost::mutex;
00054 using libtorrent::aux::session_impl;
00055
00056 #ifdef TORRENT_PROFILE
00057 #include <boost/date_time/posix_time/ptime.hpp>
00058
00059 namespace libtorrent
00060 {
00061 namespace
00062 {
00063 using boost::posix_time::ptime;
00064 using boost::posix_time::time_duration;
00065 using boost::posix_time::microsec_clock;
00066 std::vector<std::pair<ptime, std::string> > checkpoints;
00067 }
00068
00069 void add_checkpoint(std::string const& str)
00070 {
00071 checkpoints.push_back(std::make_pair(microsec_clock::universal_time(), str));
00072 }
00073
00074 void print_checkpoints()
00075 {
00076 for (std::vector<std::pair<ptime, std::string> >::iterator i
00077 = checkpoints.begin(); i != checkpoints.end(); ++i)
00078 {
00079 ptime cur = i->first;
00080 if (i + 1 != checkpoints.end())
00081 {
00082 time_duration diff = (i + 1)->first - cur;
00083 std::cout << diff.total_microseconds() << " " << i->second << "\n";
00084 }
00085 else
00086 {
00087 std::cout << " " << i->second << "\n";
00088 }
00089 }
00090 }
00091 }
00092
00093 #endif
00094
00095 namespace
00096 {
00097
00098 enum
00099 {
00100
00101 tracker_retry_delay_min = 60
00102
00103
00104 , tracker_retry_delay_max = 10 * 60
00105 , tracker_failed_max = 5
00106 };
00107
00108 int calculate_block_size(const torrent_info& i, int default_block_size)
00109 {
00110 if (default_block_size < 1024) default_block_size = 1024;
00111
00112
00113 if (i.piece_length() < default_block_size)
00114 {
00115 return static_cast<int>(i.piece_length());
00116 }
00117
00118
00119 if (i.piece_length() / default_block_size > piece_picker::max_blocks_per_piece)
00120 {
00121 return static_cast<int>(i.piece_length() / piece_picker::max_blocks_per_piece);
00122 }
00123
00124
00125 return default_block_size;
00126 }
00127
00128 struct find_peer_by_ip
00129 {
00130 find_peer_by_ip(tcp::endpoint const& a, const torrent* t)
00131 : ip(a)
00132 , tor(t)
00133 { assert(t != 0); }
00134
00135 bool operator()(const session_impl::connection_map::value_type& c) const
00136 {
00137 tcp::endpoint sender = c.first->remote_endpoint();
00138 if (sender.address() != ip.address()) return false;
00139 if (tor != c.second->associated_torrent().lock().get()) return false;
00140 return true;
00141 }
00142
00143 tcp::endpoint const& ip;
00144 torrent const* tor;
00145 };
00146
00147 struct peer_by_id
00148 {
00149 peer_by_id(const peer_id& i): pid(i) {}
00150
00151 bool operator()(const std::pair<tcp::endpoint, peer_connection*>& p) const
00152 {
00153 if (p.second->pid() != pid) return false;
00154
00155
00156 if (std::count(pid.begin(), pid.end(), 0) == 20) return false;
00157 return true;
00158 }
00159
00160 peer_id const& pid;
00161 };
00162
00163 #ifdef TORRENT_LOGGING
00164 void print_legend(boost::shared_ptr<logger> l)
00165 {
00166 (*l) << "1. time, seconds\n"
00167 << "2. hard send quota, bytes\n"
00168 << "3. soft send quota, bytes\n"
00169 << "4. excess bytes sent\n"
00170 << "5. excess bytes sent last time slice\n"
00171 << "6. hard receive quota, bytes\n"
00172 << "7. soft receive quota, bytes\n"
00173 << "8. excess bytes received\n"
00174 << "9. excess bytes received last time slice\n"
00175 << "10. num peers\n"
00176 << "11. max ul quota limit\n"
00177 << "12. max dl quota limit\n"
00178 << "13. bytes sent\n"
00179 << "14. bytes sent 10 seconds mean\n"
00180 << "15. bytes received\n"
00181 << "16. bytes received 10 seconds mean\n"
00182 << "17. total payload download\n"
00183 << "18. total web seed payload download\n"
00184 << "19. total redundant bytes downloaded\n"
00185 << "\n";
00186 }
00187 #endif
00188
00189 }
00190
00191 namespace libtorrent
00192 {
00193 torrent::torrent(
00194 session_impl& ses
00195 , aux::checker_impl& checker
00196 , torrent_info const& tf
00197 , boost::filesystem::path const& save_path
00198 , tcp::endpoint const& net_interface
00199 , bool compact_mode
00200 , int block_size
00201 , session_settings const& s)
00202 : m_torrent_file(tf)
00203 , m_abort(false)
00204 , m_paused(false)
00205 , m_just_paused(false)
00206 , m_event(tracker_request::started)
00207 , m_block_size(0)
00208 , m_storage(0)
00209 , m_next_request(second_clock::universal_time())
00210 , m_duration(1800)
00211 , m_complete(-1)
00212 , m_incomplete(-1)
00213 , m_host_resolver(ses.m_io_service)
00214 , m_resolving_country(false)
00215 , m_resolve_countries(false)
00216 #ifndef TORRENT_DISABLE_DHT
00217 , m_dht_announce_timer(ses.m_io_service)
00218 #endif
00219 , m_policy()
00220 , m_ses(ses)
00221 , m_checker(checker)
00222 , m_picker(0)
00223 , m_trackers(m_torrent_file.trackers())
00224 , m_last_working_tracker(-1)
00225 , m_currently_trying_tracker(0)
00226 , m_failed_trackers(0)
00227 , m_time_scaler(0)
00228 , m_num_pieces(0)
00229 , m_got_tracker_response(false)
00230 , m_ratio(0.f)
00231 , m_total_failed_bytes(0)
00232 , m_total_redundant_bytes(0)
00233 , m_net_interface(net_interface.address(), 0)
00234 , m_save_path(complete(save_path))
00235 , m_compact_mode(compact_mode)
00236 , m_default_block_size(block_size)
00237 , m_connections_initialized(true)
00238 , m_settings(s)
00239 {
00240 #ifndef NDEBUG
00241 m_initial_done = 0;
00242 #endif
00243 #ifdef TORRENT_LOGGING
00244 m_log = ses.create_log("torrent_"
00245 + boost::lexical_cast<std::string>(tf.info_hash())
00246 , m_ses.listen_port(), false);
00247 print_legend(m_log);
00248 m_second_count = 0;
00249 std::fill_n(m_ul_history, 10, 0);
00250 std::fill_n(m_dl_history, 10, 0);
00251
00252 m_peer_log = ses.create_log("torrent_peers_"
00253 + boost::lexical_cast<std::string>(tf.info_hash())
00254 , m_ses.listen_port(), false);
00255
00256 #endif
00257 INVARIANT_CHECK;
00258
00259 m_uploads_quota.min = 2;
00260 m_connections_quota.min = 2;
00261
00262
00263 m_connections_quota.given = 100;
00264 m_uploads_quota.max = std::numeric_limits<int>::max();
00265 m_connections_quota.max = std::numeric_limits<int>::max();
00266 m_policy.reset(new policy(this));
00267 init();
00268
00269 #ifndef TORRENT_DISABLE_DHT
00270 if (should_announce_dht())
00271 {
00272 m_dht_announce_timer.expires_from_now(seconds(10));
00273 m_dht_announce_timer.async_wait(m_ses.m_strand.wrap(
00274 bind(&torrent::on_dht_announce, this, _1)));
00275 }
00276 #endif
00277 }
00278
00279 torrent::torrent(
00280 session_impl& ses
00281 , aux::checker_impl& checker
00282 , char const* tracker_url
00283 , sha1_hash const& info_hash
00284 , char const* name
00285 , boost::filesystem::path const& save_path
00286 , tcp::endpoint const& net_interface
00287 , bool compact_mode
00288 , int block_size
00289 , session_settings const& s)
00290 : m_torrent_file(info_hash)
00291 , m_abort(false)
00292 , m_paused(false)
00293 , m_just_paused(false)
00294 , m_event(tracker_request::started)
00295 , m_block_size(0)
00296 , m_storage(0)
00297 , m_next_request(second_clock::universal_time())
00298 , m_duration(1800)
00299 , m_complete(-1)
00300 , m_incomplete(-1)
00301 , m_host_resolver(ses.m_io_service)
00302 , m_resolving_country(false)
00303 , m_resolve_countries(false)
00304 #ifndef TORRENT_DISABLE_DHT
00305 , m_dht_announce_timer(ses.m_io_service)
00306 #endif
00307 , m_policy()
00308 , m_ses(ses)
00309 , m_checker(checker)
00310 , m_picker(0)
00311 , m_last_working_tracker(-1)
00312 , m_currently_trying_tracker(0)
00313 , m_failed_trackers(0)
00314 , m_time_scaler(0)
00315 , m_num_pieces(0)
00316 , m_got_tracker_response(false)
00317 , m_ratio(0.f)
00318 , m_total_failed_bytes(0)
00319 , m_total_redundant_bytes(0)
00320 , m_net_interface(net_interface.address(), 0)
00321 , m_save_path(complete(save_path))
00322 , m_compact_mode(compact_mode)
00323 , m_default_block_size(block_size)
00324 , m_connections_initialized(false)
00325 , m_settings(s)
00326 {
00327 #ifndef NDEBUG
00328 m_initial_done = 0;
00329 #endif
00330
00331 #ifdef TORRENT_LOGGING
00332 m_log = ses.create_log("torrent_"
00333 + boost::lexical_cast<std::string>(info_hash)
00334 , m_ses.listen_port(), true);
00335 print_legend(m_log);
00336 m_second_count = 0;
00337 std::fill_n(m_ul_history, 10, 0);
00338 std::fill_n(m_dl_history, 10, 0);
00339 #endif
00340
00341 INVARIANT_CHECK;
00342
00343 if (name) m_name.reset(new std::string(name));
00344
00345 m_uploads_quota.min = 2;
00346 m_connections_quota.min = 2;
00347
00348
00349 m_connections_quota.given = 100;
00350 m_uploads_quota.max = std::numeric_limits<int>::max();
00351 m_connections_quota.max = std::numeric_limits<int>::max();
00352 if (tracker_url)
00353 {
00354 m_trackers.push_back(announce_entry(tracker_url));
00355 m_torrent_file.add_tracker(tracker_url);
00356 }
00357
00358 m_policy.reset(new policy(this));
00359 #ifndef TORRENT_DISABLE_DHT
00360 if (should_announce_dht())
00361 {
00362 m_dht_announce_timer.expires_from_now(seconds(10));
00363 m_dht_announce_timer.async_wait(m_ses.m_strand.wrap(
00364 bind(&torrent::on_dht_announce, this, _1)));
00365 }
00366 #endif
00367 }
00368
00369 #ifndef TORRENT_DISABLE_DHT
00370 bool torrent::should_announce_dht() const
00371 {
00372
00373 if (m_torrent_file.is_valid() && m_torrent_file.priv()) return false;
00374
00375 if (m_trackers.empty()) return true;
00376
00377 return m_failed_trackers > 0 || !m_ses.settings().use_dht_as_fallback;
00378 }
00379 #endif
00380
00381 torrent::~torrent()
00382 {
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 assert(m_connections.empty());
00393
00394 INVARIANT_CHECK;
00395
00396 if (m_ses.is_aborted())
00397 m_abort = true;
00398 if (!m_connections.empty())
00399 disconnect_all();
00400 }
00401
00402 std::string torrent::name() const
00403 {
00404 if (valid_metadata()) return m_torrent_file.name();
00405 if (m_name) return *m_name;
00406 return "";
00407 }
00408
00409 #ifndef TORRENT_DISABLE_EXTENSIONS
00410 void torrent::add_extension(boost::shared_ptr<torrent_plugin> ext)
00411 {
00412 m_extensions.push_back(ext);
00413 }
00414 #endif
00415
00416 void torrent::init()
00417 {
00418 INVARIANT_CHECK;
00419
00420 assert(m_torrent_file.is_valid());
00421 assert(m_torrent_file.num_files() > 0);
00422 assert(m_torrent_file.total_size() >= 0);
00423
00424 m_have_pieces.resize(m_torrent_file.num_pieces(), false);
00425 m_storage.reset(new piece_manager(m_torrent_file, m_save_path, m_ses.m_files));
00426 m_block_size = calculate_block_size(m_torrent_file, m_default_block_size);
00427 m_picker.reset(new piece_picker(
00428 static_cast<int>(m_torrent_file.piece_length() / m_block_size)
00429 , static_cast<int>((m_torrent_file.total_size()+m_block_size-1)/m_block_size)));
00430
00431 std::vector<std::string> const& url_seeds = m_torrent_file.url_seeds();
00432 std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
00433 , m_web_seeds.begin()));
00434 }
00435
00436 void torrent::use_interface(const char* net_interface)
00437 {
00438 INVARIANT_CHECK;
00439
00440 m_net_interface = tcp::endpoint(address::from_string(net_interface), 0);
00441 }
00442
00443 #ifndef TORRENT_DISABLE_DHT
00444
00445 void torrent::on_dht_announce_response_disp(boost::weak_ptr<libtorrent::torrent> t
00446 , std::vector<tcp::endpoint> const& peers)
00447 {
00448 boost::shared_ptr<libtorrent::torrent> tor = t.lock();
00449 if (!tor) return;
00450 tor->on_dht_announce_response(peers);
00451 }
00452
00453 void torrent::on_dht_announce(asio::error_code const& e)
00454 {
00455 if (e) return;
00456 if (should_announce_dht())
00457 {
00458 m_dht_announce_timer.expires_from_now(boost::posix_time::minutes(30));
00459 m_dht_announce_timer.async_wait(m_ses.m_strand.wrap(
00460 bind(&torrent::on_dht_announce, this, _1)));
00461 }
00462 if (!m_ses.m_dht) return;
00463
00464
00465 boost::weak_ptr<torrent> self(shared_from_this());
00466 m_ses.m_dht->announce(m_torrent_file.info_hash()
00467 , m_ses.m_listen_interface.port()
00468 , m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1)));
00469 }
00470
00471 void torrent::on_dht_announce_response(std::vector<tcp::endpoint> const& peers)
00472 {
00473 if (peers.empty()) return;
00474
00475 if (m_ses.m_alerts.should_post(alert::info))
00476 {
00477 m_ses.m_alerts.post_alert(tracker_reply_alert(
00478 get_handle(), peers.size(), "Got peers from DHT"));
00479 }
00480 std::for_each(peers.begin(), peers.end(), bind(
00481 &policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0)));
00482 }
00483
00484 #endif
00485
00486
00487
00488 bool torrent::should_request()
00489 {
00490 INVARIANT_CHECK;
00491
00492 if (m_torrent_file.trackers().empty()) return false;
00493
00494 if (m_just_paused)
00495 {
00496 m_just_paused = false;
00497 return true;
00498 }
00499 return !m_paused &&
00500 m_next_request < second_clock::universal_time();
00501 }
00502
00503 void torrent::tracker_warning(std::string const& msg)
00504 {
00505 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
00506
00507 INVARIANT_CHECK;
00508
00509 if (m_ses.m_alerts.should_post(alert::warning))
00510 {
00511 m_ses.m_alerts.post_alert(tracker_warning_alert(get_handle(), msg));
00512 }
00513 }
00514
00515 void torrent::tracker_response(
00516 tracker_request const&
00517 , std::vector<peer_entry>& peer_list
00518 , int interval
00519 , int complete
00520 , int incomplete)
00521 {
00522 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
00523
00524 INVARIANT_CHECK;
00525
00526 m_failed_trackers = 0;
00527
00528
00529 if (interval < 60 * 5) interval = 60 * 5;
00530
00531 m_last_working_tracker
00532 = prioritize_tracker(m_currently_trying_tracker);
00533 m_currently_trying_tracker = 0;
00534
00535 m_duration = interval;
00536 m_next_request = second_clock::universal_time() + boost::posix_time::seconds(m_duration);
00537
00538 if (complete >= 0) m_complete = complete;
00539 if (incomplete >= 0) m_incomplete = incomplete;
00540
00541
00542 std::random_shuffle(peer_list.begin(), peer_list.end());
00543
00544 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
00545 std::stringstream s;
00546 s << "TRACKER RESPONSE:\n"
00547 "interval: " << m_duration << "\n"
00548 "peers:\n";
00549 for (std::vector<peer_entry>::const_iterator i = peer_list.begin();
00550 i != peer_list.end(); ++i)
00551 {
00552 s << " " << std::setfill(' ') << std::setw(16) << i->ip
00553 << " " << std::setw(5) << std::dec << i->port << " ";
00554 if (!i->pid.is_all_zeros()) s << " " << i->pid << " " << identify_client(i->pid);
00555 s << "\n";
00556 }
00557 debug_log(s.str());
00558 #endif
00559
00560 for (std::vector<peer_entry>::iterator i = peer_list.begin();
00561 i != peer_list.end(); ++i)
00562 {
00563
00564 if (i->pid == m_ses.get_peer_id())
00565 continue;
00566
00567 try
00568 {
00569 tcp::endpoint a(address::from_string(i->ip), i->port);
00570
00571 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
00572 {
00573 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
00574 debug_log("blocked ip from tracker: " + i->ip);
00575 #endif
00576 continue;
00577 }
00578
00579 m_policy->peer_from_tracker(a, i->pid);
00580 }
00581 catch (std::exception&)
00582 {
00583
00584
00585
00586 tcp::resolver::query q(i->ip, boost::lexical_cast<std::string>(i->port));
00587 m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
00588 bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid)));
00589 }
00590 }
00591
00592 if (m_ses.m_alerts.should_post(alert::info))
00593 {
00594 std::stringstream s;
00595 s << "Got response from tracker: "
00596 << m_trackers[m_last_working_tracker].url;
00597 m_ses.m_alerts.post_alert(tracker_reply_alert(
00598 get_handle(), peer_list.size(), s.str()));
00599 }
00600 m_got_tracker_response = true;
00601 }
00602
00603 void torrent::on_peer_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
00604 , peer_id pid) try
00605 {
00606 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
00607
00608 INVARIANT_CHECK;
00609
00610 if (e || host == tcp::resolver::iterator() ||
00611 m_ses.is_aborted()) return;
00612
00613 if (m_ses.m_ip_filter.access(host->endpoint().address()) & ip_filter::blocked)
00614 {
00615 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
00616 debug_log("blocked ip from tracker: " + host->endpoint().address().to_string());
00617 #endif
00618 return;
00619 }
00620
00621 m_policy->peer_from_tracker(*host, pid);
00622 }
00623 catch (std::exception&)
00624 {};
00625
00626 size_type torrent::bytes_left() const
00627 {
00628
00629
00630 if (!valid_metadata()) return -1;
00631 return m_torrent_file.total_size()
00632 - quantized_bytes_done();
00633 }
00634
00635 size_type torrent::quantized_bytes_done() const
00636 {
00637
00638 if (!valid_metadata()) return 0;
00639
00640 if (m_torrent_file.num_pieces() == 0)
00641 return 0;
00642
00643 if (is_seed()) return m_torrent_file.total_size();
00644
00645 const int last_piece = m_torrent_file.num_pieces() - 1;
00646
00647 size_type total_done
00648 = m_num_pieces * m_torrent_file.piece_length();
00649
00650
00651
00652
00653 if (m_have_pieces[last_piece])
00654 {
00655 int corr = m_torrent_file.piece_size(last_piece)
00656 - m_torrent_file.piece_length();
00657 total_done += corr;
00658 }
00659 return total_done;
00660 }
00661
00662
00663
00664
00665 tuple<size_type, size_type> torrent::bytes_done() const
00666 {
00667 INVARIANT_CHECK;
00668
00669 if (!valid_metadata()) return tuple<size_type, size_type>(0,0);
00670
00671 if (m_torrent_file.num_pieces() == 0)
00672 return tuple<size_type, size_type>(0,0);
00673 const int last_piece = m_torrent_file.num_pieces() - 1;
00674
00675 if (is_seed())
00676 return make_tuple(m_torrent_file.total_size()
00677 , m_torrent_file.total_size());
00678
00679 size_type wanted_done = (m_num_pieces - m_picker->num_have_filtered())
00680 * m_torrent_file.piece_length();
00681
00682 size_type total_done
00683 = m_num_pieces * m_torrent_file.piece_length();
00684 assert(m_num_pieces < m_torrent_file.num_pieces());
00685
00686
00687
00688
00689 if (m_have_pieces[last_piece])
00690 {
00691 int corr = m_torrent_file.piece_size(last_piece)
00692 - m_torrent_file.piece_length();
00693 total_done += corr;
00694 if (!m_picker->is_filtered(last_piece))
00695 wanted_done += corr;
00696 }
00697
00698 assert(total_done <= m_torrent_file.total_size());
00699 assert(wanted_done <= m_torrent_file.total_size());
00700
00701 const std::vector<piece_picker::downloading_piece>& dl_queue
00702 = m_picker->get_download_queue();
00703
00704 const int blocks_per_piece = static_cast<int>(
00705 m_torrent_file.piece_length() / m_block_size);
00706
00707 for (std::vector<piece_picker::downloading_piece>::const_iterator i =
00708 dl_queue.begin(); i != dl_queue.end(); ++i)
00709 {
00710 int corr = 0;
00711 int index = i->index;
00712 assert(!m_have_pieces[index]);
00713 assert(int(i->finished_blocks.count())
00714 < m_picker->blocks_in_piece(index));
00715
00716 #ifndef NDEBUG
00717 for (std::vector<piece_picker::downloading_piece>::const_iterator j = boost::next(i);
00718 j != dl_queue.end(); ++j)
00719 {
00720 assert(j->index != index);
00721 }
00722 #endif
00723
00724 for (int j = 0; j < blocks_per_piece; ++j)
00725 {
00726 assert(i->finished_blocks[j] == 0 || i->finished_blocks[j] == 1);
00727 assert(m_picker->is_finished(piece_block(index, j)) == i->finished_blocks[j]);
00728 corr += i->finished_blocks[j] * m_block_size;
00729 assert(index != last_piece || j < m_picker->blocks_in_last_piece()
00730 || i->finished_blocks[j] == 0);
00731 }
00732
00733
00734
00735 if (i->index == last_piece
00736 && i->finished_blocks[m_picker->blocks_in_last_piece()-1])
00737 {
00738 corr -= m_block_size;
00739 corr += m_torrent_file.piece_size(last_piece) % m_block_size;
00740 }
00741 total_done += corr;
00742 if (!m_picker->is_filtered(index))
00743 wanted_done += corr;
00744 }
00745
00746 assert(total_done < m_torrent_file.total_size());
00747 assert(wanted_done < m_torrent_file.total_size());
00748
00749 std::map<piece_block, int> downloading_piece;
00750 for (const_peer_iterator i = begin(); i != end(); ++i)
00751 {
00752 peer_connection* pc = i->second;
00753 boost::optional<piece_block_progress> p
00754 = pc->downloading_piece_progress();
00755 if (p)
00756 {
00757 if (m_have_pieces[p->piece_index])
00758 continue;
00759
00760 piece_block block(p->piece_index, p->block_index);
00761 if (m_picker->is_finished(block))
00762 continue;
00763
00764 std::map<piece_block, int>::iterator dp
00765 = downloading_piece.find(block);
00766 if (dp != downloading_piece.end())
00767 {
00768 if (dp->second < p->bytes_downloaded)
00769 dp->second = p->bytes_downloaded;
00770 }
00771 else
00772 {
00773 downloading_piece[block] = p->bytes_downloaded;
00774 }
00775 #ifndef NDEBUG
00776 assert(p->bytes_downloaded <= p->full_block_bytes);
00777 int last_piece = m_torrent_file.num_pieces() - 1;
00778 if (p->piece_index == last_piece
00779 && p->block_index == m_torrent_file.piece_size(last_piece) / block_size())
00780 assert(p->full_block_bytes == m_torrent_file.piece_size(last_piece) % block_size());
00781 else
00782 assert(p->full_block_bytes == block_size());
00783 #endif
00784 }
00785 }
00786 for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
00787 i != downloading_piece.end(); ++i)
00788 {
00789 total_done += i->second;
00790 if (!m_picker->is_filtered(i->first.piece_index))
00791 wanted_done += i->second;
00792 }
00793
00794 #ifndef NDEBUG
00795
00796 if (total_done >= m_torrent_file.total_size())
00797 {
00798 std::copy(m_have_pieces.begin(), m_have_pieces.end()
00799 , std::ostream_iterator<bool>(std::cerr, " "));
00800 std::cerr << std::endl;
00801 std::cerr << "num_pieces: " << m_num_pieces << std::endl;
00802
00803 std::cerr << "unfinished:" << std::endl;
00804
00805 for (std::vector<piece_picker::downloading_piece>::const_iterator i =
00806 dl_queue.begin(); i != dl_queue.end(); ++i)
00807 {
00808 std::cerr << " " << i->index << " ";
00809 for (int j = 0; j < blocks_per_piece; ++j)
00810 {
00811 std::cerr << i->finished_blocks[j];
00812 }
00813 std::cerr << std::endl;
00814 }
00815
00816 std::cerr << "downloading pieces:" << std::endl;
00817
00818 for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
00819 i != downloading_piece.end(); ++i)
00820 {
00821 std::cerr << " " << i->first.piece_index << ":" << i->first.block_index
00822 << " " << i->second << std::endl;
00823 }
00824
00825 }
00826
00827 assert(total_done < m_torrent_file.total_size());
00828 assert(wanted_done < m_torrent_file.total_size());
00829
00830 #endif
00831
00832 assert(total_done >= wanted_done);
00833 return make_tuple(total_done, wanted_done);
00834 }
00835
00836 void torrent::piece_failed(int index)
00837 {
00838
00839
00840
00841
00842
00843
00844 assert(m_storage.get());
00845 assert(m_picker.get());
00846 assert(index >= 0);
00847 assert(index < m_torrent_file.num_pieces());
00848
00849 if (m_ses.m_alerts.should_post(alert::info))
00850 {
00851 std::stringstream s;
00852 s << "hash for piece " << index << " failed";
00853 m_ses.m_alerts.post_alert(hash_failed_alert(get_handle(), index, s.str()));
00854 }
00855
00856 m_total_failed_bytes += m_torrent_file.piece_size(index);
00857
00858 std::vector<tcp::endpoint> downloaders;
00859 m_picker->get_downloaders(downloaders, index);
00860
00861
00862
00863
00864 std::set<tcp::endpoint> peers;
00865 std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
00866
00867 #ifndef TORRENT_DISABLE_EXTENSIONS
00868 for (extension_list_t::iterator i = m_extensions.begin()
00869 , end(m_extensions.end()); i != end; ++i)
00870 {
00871 try { (*i)->on_piece_failed(index); } catch (std::exception&) {}
00872 }
00873 #endif
00874
00875 for (std::set<tcp::endpoint>::iterator i = peers.begin()
00876 , end(peers.end()); i != end; ++i)
00877 {
00878 peer_iterator p = m_connections.find(*i);
00879 if (p == m_connections.end()) continue;
00880 p->second->received_invalid_data(index);
00881
00882
00883
00884
00885 if (p->second->trust_points() <= -7 || peers.size() == 1)
00886 {
00887
00888
00889 if (m_ses.m_alerts.should_post(alert::info))
00890 {
00891 m_ses.m_alerts.post_alert(peer_ban_alert(
00892 p->first
00893 , get_handle()
00894 , "banning peer because of too many corrupt pieces"));
00895 }
00896 m_policy->ban_peer(*p->second);
00897
00898 #if defined(TORRENT_VERBOSE_LOGGING)
00899 (*p->second->m_logger) << "*** BANNING PEER 'too many corrupt pieces'\n";
00900 #endif
00901 p->second->disconnect();
00902 }
00903 }
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914 m_picker->restore_piece(index);
00915 m_storage->mark_failed(index);
00916
00917 assert(m_have_pieces[index] == false);
00918 }
00919
00920 void torrent::abort()
00921 {
00922 INVARIANT_CHECK;
00923
00924 m_abort = true;
00925
00926
00927 if (!m_paused)
00928 m_event = tracker_request::stopped;
00929
00930
00931 disconnect_all();
00932 if (m_storage.get()) m_storage->release_files();
00933 }
00934
00935 void torrent::announce_piece(int index)
00936 {
00937
00938 assert(index >= 0);
00939 assert(index < m_torrent_file.num_pieces());
00940
00941 std::vector<tcp::endpoint> downloaders;
00942 m_picker->get_downloaders(downloaders, index);
00943
00944
00945
00946 std::set<tcp::endpoint> peers;
00947 std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
00948
00949 if (!m_have_pieces[index])
00950 m_num_pieces++;
00951 m_have_pieces[index] = true;
00952
00953 assert(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0)
00954 == m_num_pieces);
00955
00956 m_picker->we_have(index);
00957 for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
00958 try { i->second->announce_piece(index); } catch (std::exception&) {}
00959
00960 for (std::set<tcp::endpoint>::iterator i = peers.begin()
00961 , end(peers.end()); i != end; ++i)
00962 {
00963 peer_iterator p = m_connections.find(*i);
00964 if (p == m_connections.end()) continue;
00965 p->second->received_valid_data(index);
00966 }
00967
00968 #ifndef TORRENT_DISABLE_EXTENSIONS
00969 for (extension_list_t::iterator i = m_extensions.begin()
00970 , end(m_extensions.end()); i != end; ++i)
00971 {
00972 try { (*i)->on_piece_pass(index); } catch (std::exception&) {}
00973 }
00974 #endif
00975 if (is_seed()) m_picker.reset();
00976 }
00977
00978 std::string torrent::tracker_login() const
00979 {
00980 if (m_username.empty() && m_password.empty()) return "";
00981 return m_username + ":" + m_password;
00982 }
00983
00984 void torrent::filter_piece(int index, bool filter)
00985 {
00986 INVARIANT_CHECK;
00987
00988 assert(valid_metadata());
00989 if (is_seed()) return;
00990
00991
00992 assert(m_picker.get());
00993 assert(index >= 0);
00994 assert(index < m_torrent_file.num_pieces());
00995
00996
00997
00998 if (filter) m_picker->mark_as_filtered(index);
00999 else m_picker->mark_as_unfiltered(index);
01000 }
01001
01002 void torrent::filter_pieces(std::vector<bool> const& bitmask)
01003 {
01004 INVARIANT_CHECK;
01005
01006
01007 assert(valid_metadata());
01008 if (is_seed()) return;
01009
01010 assert(m_picker.get());
01011
01012
01013
01014 std::vector<int> state;
01015 state.reserve(100);
01016 int index = 0;
01017 for (std::vector<bool>::const_iterator i = bitmask.begin()
01018 , end(bitmask.end()); i != end; ++i, ++index)
01019 {
01020 if (m_picker->is_filtered(index) == *i) continue;
01021 if (*i)
01022 m_picker->mark_as_filtered(index);
01023 else
01024 state.push_back(index);
01025 }
01026
01027 for (std::vector<int>::reverse_iterator i = state.rbegin();
01028 i != state.rend(); ++i)
01029 {
01030 m_picker->mark_as_unfiltered(*i);
01031 }
01032 }
01033
01034 bool torrent::is_piece_filtered(int index) const
01035 {
01036
01037 assert(valid_metadata());
01038 if (is_seed()) return false;
01039
01040 assert(m_picker.get());
01041 assert(index >= 0);
01042 assert(index < m_torrent_file.num_pieces());
01043
01044 return m_picker->is_filtered(index);
01045 }
01046
01047 void torrent::filtered_pieces(std::vector<bool>& bitmask) const
01048 {
01049 INVARIANT_CHECK;
01050
01051
01052 assert(valid_metadata());
01053 if (is_seed())
01054 {
01055 bitmask.clear();
01056 bitmask.resize(m_torrent_file.num_pieces(), false);
01057 return;
01058 }
01059
01060 assert(m_picker.get());
01061 m_picker->filtered_pieces(bitmask);
01062 }
01063
01064 void torrent::filter_files(std::vector<bool> const& bitmask)
01065 {
01066 INVARIANT_CHECK;
01067
01068
01069 if (!valid_metadata() || is_seed()) return;
01070
01071
01072
01073 assert((int)bitmask.size() == m_torrent_file.num_files());
01074
01075 size_type position = 0;
01076
01077 if (m_torrent_file.num_pieces())
01078 {
01079 int piece_length = m_torrent_file.piece_length();
01080
01081
01082 std::vector<bool> piece_filter(m_torrent_file.num_pieces(), true);
01083 for (int i = 0; i < (int)bitmask.size(); ++i)
01084 {
01085 size_type start = position;
01086 position += m_torrent_file.file_at(i).size;
01087
01088 if (!bitmask[i])
01089 {
01090
01091 int start_piece = int(start / piece_length);
01092 int last_piece = int(position / piece_length);
01093
01094
01095 std::fill(piece_filter.begin() + start_piece, piece_filter.begin()
01096 + last_piece + 1, false);
01097 }
01098 }
01099 filter_pieces(piece_filter);
01100 }
01101 }
01102
01103 void torrent::replace_trackers(std::vector<announce_entry> const& urls)
01104 {
01105 assert(!urls.empty());
01106 m_trackers = urls;
01107 if (m_currently_trying_tracker >= (int)m_trackers.size())
01108 m_currently_trying_tracker = (int)m_trackers.size()-1;
01109 m_last_working_tracker = -1;
01110 }
01111
01112 tracker_request torrent::generate_tracker_request()
01113 {
01114 INVARIANT_CHECK;
01115
01116 assert(!m_trackers.empty());
01117
01118 m_next_request
01119 = second_clock::universal_time()
01120 + boost::posix_time::seconds(tracker_retry_delay_max);
01121
01122 tracker_request req;
01123 req.info_hash = m_torrent_file.info_hash();
01124 req.pid = m_ses.get_peer_id();
01125 req.downloaded = m_stat.total_payload_download();
01126 req.web_downloaded = m_web_stat.total_payload_download();
01127 req.uploaded = m_stat.total_payload_upload();
01128 req.left = bytes_left();
01129 if (req.left == -1) req.left = 16*1024;
01130 req.event = m_event;
01131
01132 if (m_event != tracker_request::stopped)
01133 m_event = tracker_request::none;
01134 req.url = m_trackers[m_currently_trying_tracker].url;
01135 req.num_want = 50;
01136
01137 if (req.event == tracker_request::stopped)
01138 req.num_want = 0;
01139
01140
01141
01142 req.listen_port = 0;
01143 req.key = 0;
01144
01145 return req;
01146 }
01147
01148 void torrent::remove_peer(peer_connection* p) try
01149 {
01150 INVARIANT_CHECK;
01151
01152 assert(p != 0);
01153
01154 peer_iterator i = m_connections.find(p->remote());
01155 if (i == m_connections.end()) return;
01156
01157 if (ready_for_connections())
01158 {
01159 assert(p->associated_torrent().lock().get() == this);
01160
01161 std::vector<int> piece_list;
01162 const std::vector<bool>& pieces = p->get_bitfield();
01163
01164 for (std::vector<bool>::const_iterator i = pieces.begin();
01165 i != pieces.end(); ++i)
01166 {
01167 if (*i) piece_list.push_back(static_cast<int>(i - pieces.begin()));
01168 }
01169
01170 for (std::vector<int>::reverse_iterator i = piece_list.rbegin();
01171 i != piece_list.rend(); ++i)
01172 {
01173 peer_lost(*i);
01174 }
01175 }
01176
01177 m_policy->connection_closed(*p);
01178 m_connections.erase(i);
01179 #ifndef NDEBUG
01180 m_policy->check_invariant();
01181 #endif
01182 }
01183 catch (std::exception& e)
01184 {
01185 #ifndef NDEBUG
01186 std::string err = e.what();
01187 #endif
01188 assert(false);
01189 };
01190
01191 void torrent::connect_to_url_seed(std::string const& url)
01192 {
01193 INVARIANT_CHECK;
01194
01195 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
01196 std::string now(to_simple_string(second_clock::universal_time()));
01197 (*m_ses.m_logger) << now << " resolving: " << url << "\n";
01198 #endif
01199
01200 m_resolving_web_seeds.insert(url);
01201 if (m_ses.settings().proxy_ip.empty())
01202 {
01203 std::string protocol;
01204 std::string hostname;
01205 int port;
01206 std::string path;
01207 boost::tie(protocol, hostname, port, path)
01208 = parse_url_components(url);
01209
01210 tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
01211 m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
01212 bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url
01213 , tcp::endpoint())));
01214 }
01215 else
01216 {
01217
01218 tcp::resolver::query q(m_ses.settings().proxy_ip
01219 , boost::lexical_cast<std::string>(m_ses.settings().proxy_port));
01220 m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
01221 bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, url)));
01222 }
01223
01224 }
01225
01226 void torrent::on_proxy_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
01227 , std::string url) try
01228 {
01229 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
01230
01231 INVARIANT_CHECK;
01232
01233 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
01234 std::string now(to_simple_string(second_clock::universal_time()));
01235 (*m_ses.m_logger) << now << " completed resolve proxy hostname for: " << url << "\n";
01236 #endif
01237
01238 if (e || host == tcp::resolver::iterator())
01239 {
01240 if (m_ses.m_alerts.should_post(alert::warning))
01241 {
01242 std::stringstream msg;
01243 msg << "HTTP seed proxy hostname lookup failed: " << e.message();
01244 m_ses.m_alerts.post_alert(
01245 url_seed_alert(get_handle(), url, msg.str()));
01246 }
01247
01248
01249
01250 remove_url_seed(url);
01251 return;
01252 }
01253
01254 if (m_ses.is_aborted()) return;
01255
01256 tcp::endpoint a(host->endpoint());
01257
01258 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
01259 {
01260
01261 return;
01262 }
01263
01264 std::string protocol;
01265 std::string hostname;
01266 int port;
01267 std::string path;
01268 boost::tie(protocol, hostname, port, path)
01269 = parse_url_components(url);
01270
01271 tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
01272 m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
01273 bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url, a)));
01274 }
01275 catch (std::exception& exc)
01276 {
01277 assert(false);
01278 };
01279
01280 void torrent::on_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
01281 , std::string url, tcp::endpoint proxy) try
01282 {
01283 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
01284
01285 INVARIANT_CHECK;
01286
01287 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
01288 std::string now(to_simple_string(second_clock::universal_time()));
01289 (*m_ses.m_logger) << now << " completed resolve: " << url << "\n";
01290 #endif
01291
01292 std::set<std::string>::iterator i = m_resolving_web_seeds.find(url);
01293 if (i != m_resolving_web_seeds.end()) m_resolving_web_seeds.erase(i);
01294
01295 if (e || host == tcp::resolver::iterator())
01296 {
01297 if (m_ses.m_alerts.should_post(alert::warning))
01298 {
01299 std::stringstream msg;
01300 msg << "HTTP seed hostname lookup failed: " << e.message();
01301 m_ses.m_alerts.post_alert(
01302 url_seed_alert(get_handle(), url, msg.str()));
01303 }
01304 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
01305 (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << url << "\n";
01306 #endif
01307
01308
01309
01310 remove_url_seed(url);
01311 return;
01312 }
01313
01314 if (m_ses.is_aborted()) return;
01315
01316 tcp::endpoint a(host->endpoint());
01317
01318 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
01319 {
01320
01321 return;
01322 }
01323
01324 peer_iterator conn = m_connections.find(a);
01325 if (conn != m_connections.end())
01326 {
01327 if (dynamic_cast<web_peer_connection*>(conn->second) == 0
01328 || conn->second->is_disconnecting()) conn->second->disconnect();
01329 else return;
01330 }
01331
01332 boost::shared_ptr<stream_socket> s(new stream_socket(m_ses.m_io_service));
01333 boost::intrusive_ptr<peer_connection> c(new web_peer_connection(
01334 m_ses, shared_from_this(), s, a, proxy, url));
01335
01336 #ifndef NDEBUG
01337 c->m_in_constructor = false;
01338 #endif
01339
01340 try
01341 {
01342 m_ses.m_connection_queue.push_back(c);
01343
01344 assert(m_connections.find(a) == m_connections.end());
01345
01346 #ifndef NDEBUG
01347 m_policy->check_invariant();
01348 #endif
01349
01350 m_connections.insert(
01351 std::make_pair(a, boost::get_pointer(c)));
01352
01353 #ifndef NDEBUG
01354 m_policy->check_invariant();
01355 #endif
01356
01357 m_ses.process_connection_queue();
01358 }
01359 catch (std::exception& e)
01360 {
01361 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
01362 (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n";
01363 #endif
01364
01365
01366 std::map<tcp::endpoint, peer_connection*>::iterator i = m_connections.find(a);
01367 if (i != m_connections.end()) m_connections.erase(i);
01368 m_ses.connection_failed(s, a, e.what());
01369 c->disconnect();
01370 }
01371 }
01372 catch (std::exception& exc)
01373 {
01374 assert(false);
01375 };
01376
01377 void torrent::resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const
01378 {
01379 if (m_resolving_country
01380 || p->has_country()
01381 || p->is_connecting()
01382 || p->is_queued()
01383 || p->in_handshake()) return;
01384
01385 m_resolving_country = true;
01386 tcp::resolver::query q(boost::lexical_cast<std::string>(p->remote().address())
01387 + ".zz.countries.nerd.dk", "0");
01388 m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
01389 bind(&torrent::on_country_lookup, shared_from_this(), _1, _2, p)));
01390 }
01391
01392 namespace
01393 {
01394 typedef std::pair<int, char const*> country_entry;
01395
01396 bool compare_first(country_entry const& lhs, country_entry const& rhs)
01397 {
01398 return lhs.first < rhs.first;
01399 }
01400 }
01401
01402 void torrent::on_country_lookup(asio::error_code const& error, tcp::resolver::iterator i
01403 , intrusive_ptr<peer_connection> p) const
01404 {
01405 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
01406
01407 INVARIANT_CHECK;
01408
01409 m_resolving_country = false;
01410
01411
01412 country_entry country_map[] =
01413 {
01414 country_entry( 4, "AF")
01415 , country_entry( 8, "AL")
01416 , country_entry( 10, "AQ")
01417 , country_entry( 12, "DZ")
01418 , country_entry( 16, "AS")
01419 , country_entry( 20, "AD")
01420 , country_entry( 24, "AO")
01421 , country_entry( 28, "AG")
01422 , country_entry( 31, "AZ")
01423 , country_entry( 32, "AR")
01424 , country_entry( 36, "AU")
01425 , country_entry( 40, "AT")
01426 , country_entry( 44, "BS")
01427 , country_entry( 48, "BH")
01428 , country_entry( 50, "BD")
01429 , country_entry( 51, "AM")
01430 , country_entry( 52, "BB")
01431 , country_entry( 56, "BE")
01432 , country_entry( 60, "BM")
01433 , country_entry( 64, "BT")
01434 , country_entry( 68, "BO")
01435 , country_entry( 70, "BA")
01436 , country_entry( 72, "BW")
01437 , country_entry( 74, "BV")
01438 , country_entry( 76, "BR")
01439 , country_entry( 84, "BZ")
01440 , country_entry( 86, "IO")
01441 , country_entry( 90, "SB")
01442 , country_entry( 92, "VG")
01443 , country_entry( 96, "BN")
01444 , country_entry(100, "BG")
01445 , country_entry(104, "MM")
01446 , country_entry(108, "BI")
01447 , country_entry(112, "BY")
01448 , country_entry(116, "KH")
01449 , country_entry(120, "CM")
01450 , country_entry(124, "CA")
01451 , country_entry(132, "CV")
01452 , country_entry(136, "KY")
01453 , country_entry(140, "CF")
01454 , country_entry(144, "LK")
01455 , country_entry(148, "TD")
01456 , country_entry(152, "CL")
01457 , country_entry(156, "CN")
01458 , country_entry(158, "TW")
01459 , country_entry(162, "CX")
01460 , country_entry(166, "CC")
01461 , country_entry(170, "CO")
01462 , country_entry(174, "KM")
01463 , country_entry(175, "YT")
01464 , country_entry(178, "CG")
01465 , country_entry(180, "CD")
01466 , country_entry(184, "CK")
01467 , country_entry(188, "CR")
01468 , country_entry(191, "HR")
01469 , country_entry(192, "CU")
01470 , country_entry(203, "CZ")
01471 , country_entry(204, "BJ")
01472 , country_entry(208, "DK")
01473 , country_entry(212, "DM")
01474 , country_entry(214, "DO")
01475 , country_entry(218, "EC")
01476 , country_entry(222, "SV")
01477 , country_entry(226, "GQ")
01478 , country_entry(231, "ET")
01479 , country_entry(232, "ER")
01480 , country_entry(233, "EE")
01481 , country_entry(234, "FO")
01482 , country_entry(238, "FK")
01483 , country_entry(239, "GS")
01484 , country_entry(242, "FJ")
01485 , country_entry(246, "FI")
01486 , country_entry(248, "AX")
01487 , country_entry(250, "FR")
01488 , country_entry(254, "GF")
01489 , country_entry(258, "PF")
01490 , country_entry(260, "TF")
01491 , country_entry(262, "DJ")
01492 , country_entry(266, "GA")
01493 , country_entry(268, "GE")
01494 , country_entry(270, "GM")
01495 , country_entry(275, "PS")
01496 , country_entry(276, "DE")
01497 , country_entry(288, "GH")
01498 , country_entry(292, "GI")
01499 , country_entry(296, "KI")
01500 , country_entry(300, "GR")
01501 , country_entry(304, "GL")
01502 , country_entry(308, "GD")
01503 , country_entry(312, "GP")
01504 , country_entry(316, "GU")
01505 , country_entry(320, "GT")
01506 , country_entry(324, "GN")
01507 , country_entry(328, "GY")
01508 , country_entry(332, "HT")
01509 , country_entry(334, "HM")
01510 , country_entry(336, "VA")
01511 , country_entry(340, "HN")
01512 , country_entry(344, "HK")
01513 , country_entry(348, "HU")
01514 , country_entry(352, "IS")
01515 , country_entry(356, "IN")
01516 , country_entry(360, "ID")
01517 , country_entry(364, "IR")
01518 , country_entry(368, "IQ")
01519 , country_entry(372, "IE")
01520 , country_entry(376, "IL")
01521 , country_entry(380, "IT")
01522 , country_entry(384, "CI")
01523 , country_entry(388, "JM")
01524 , country_entry(392, "JP")
01525 , country_entry(398, "KZ")
01526 , country_entry(400, "JO")
01527 , country_entry(404, "KE")
01528 , country_entry(408, "KP")
01529 , country_entry(410, "KR")
01530 , country_entry(414, "KW")
01531 , country_entry(417, "KG")
01532 , country_entry(418, "LA")
01533 , country_entry(422, "LB")
01534 , country_entry(426, "LS")
01535 , country_entry(428, "LV")
01536 , country_entry(430, "LR")
01537 , country_entry(434, "LY")
01538 , country_entry(438, "LI")
01539 , country_entry(440, "LT")
01540 , country_entry(442, "LU")
01541 , country_entry(446, "MO")
01542 , country_entry(450, "MG")
01543 , country_entry(454, "MW")
01544 , country_entry(458, "MY")
01545 , country_entry(462, "MV")
01546 , country_entry(466, "ML")
01547 , country_entry(470, "MT")
01548 , country_entry(474, "MQ")
01549 , country_entry(478, "MR")
01550 , country_entry(480, "MU")
01551 , country_entry(484, "MX")
01552 , country_entry(492, "MC")
01553 , country_entry(496, "MN")
01554 , country_entry(498, "MD")
01555 , country_entry(500, "MS")
01556 , country_entry(504, "MA")
01557 , country_entry(508, "MZ")
01558 , country_entry(512, "OM")
01559 , country_entry(516, "NA")
01560 , country_entry(520, "NR")
01561 , country_entry(524, "NP")
01562 , country_entry(528, "NL")
01563 , country_entry(530, "AN")
01564 , country_entry(533, "AW")
01565 , country_entry(540, "NC")
01566 , country_entry(548, "VU")
01567 , country_entry(554, "NZ")
01568 , country_entry(558, "NI")
01569 , country_entry(562, "NE")
01570 , country_entry(566, "NG")
01571 , country_entry(570, "NU")
01572 , country_entry(574, "NF")
01573 , country_entry(578, "NO")
01574 , country_entry(580, "MP")
01575 , country_entry(581, "UM")
01576 , country_entry(583, "FM")
01577 , country_entry(584, "MH")
01578 , country_entry(585, "PW")
01579 , country_entry(586, "PK")
01580 , country_entry(591, "PA")
01581 , country_entry(598, "PG")
01582 , country_entry(600, "PY")
01583 , country_entry(604, "PE")
01584 , country_entry(608, "PH")
01585 , country_entry(612, "PN")
01586 , country_entry(616, "PL")
01587 , country_entry(620, "PT")
01588 , country_entry(624, "GW")
01589 , country_entry(626, "TL")
01590 , country_entry(630, "PR")
01591 , country_entry(634, "QA")
01592 , country_entry(634, "QA")
01593 , country_entry(638, "RE")
01594 , country_entry(642, "RO")
01595 , country_entry(643, "RU")
01596 , country_entry(646, "RW")
01597 , country_entry(654, "SH")
01598 , country_entry(659, "KN")
01599 , country_entry(660, "AI")
01600 , country_entry(662, "LC")
01601 , country_entry(666, "PM")
01602 , country_entry(670, "VC")
01603 , country_entry(674, "SM")
01604 , country_entry(678, "ST")
01605 , country_entry(682, "SA")
01606 , country_entry(686, "SN")
01607 , country_entry(690, "SC")
01608 , country_entry(694, "SL")
01609 , country_entry(702, "SG")
01610 , country_entry(703, "SK")
01611 , country_entry(704, "VN")
01612 , country_entry(705, "SI")
01613 , country_entry(706, "SO")
01614 , country_entry(710, "ZA")
01615 , country_entry(716, "ZW")
01616 , country_entry(724, "ES")
01617 , country_entry(732, "EH")
01618 , country_entry(736, "SD")
01619 , country_entry(740, "SR")
01620 , country_entry(744, "SJ")
01621 , country_entry(748, "SZ")
01622 , country_entry(752, "SE")
01623 , country_entry(756, "CH")
01624 , country_entry(760, "SY")
01625 , country_entry(762, "TJ")
01626 , country_entry(764, "TH")
01627 , country_entry(768, "TG")
01628 , country_entry(772, "TK")
01629 , country_entry(776, "TO")
01630 , country_entry(780, "TT")
01631 , country_entry(784, "AE")
01632 , country_entry(788, "TN")
01633 , country_entry(792, "TR")
01634 , country_entry(795, "TM")
01635 , country_entry(796, "TC")
01636 , country_entry(798, "TV")
01637 , country_entry(800, "UG")
01638 , country_entry(804, "UA")
01639 , country_entry(807, "MK")
01640 , country_entry(818, "EG")
01641 , country_entry(826, "GB")
01642 , country_entry(834, "TZ")
01643 , country_entry(840, "US")
01644 , country_entry(850, "VI")
01645 , country_entry(854, "BF")
01646 , country_entry(858, "UY")
01647 , country_entry(860, "UZ")
01648 , country_entry(862, "VE")
01649 , country_entry(876, "WF")
01650 , country_entry(882, "WS")
01651 , country_entry(887, "YE")
01652 , country_entry(891, "CS")
01653 , country_entry(894, "ZM")
01654 };
01655
01656 if (error || i == tcp::resolver::iterator())
01657 {
01658
01659
01660 p->set_country("--");
01661 return;
01662 }
01663
01664 while (i != tcp::resolver::iterator()
01665 && !i->endpoint().address().is_v4()) ++i;
01666 if (i != tcp::resolver::iterator())
01667 {
01668
01669 int country = i->endpoint().address().to_v4().to_ulong() & 0xffff;
01670
01671
01672 const int size = sizeof(country_map)/sizeof(country_map[0]);
01673 country_entry* i =
01674 std::lower_bound(country_map, country_map + size
01675 , country_entry(country, ""), &compare_first);
01676 if (i == country_map + size
01677 || i->first != country)
01678 {
01679
01680 p->set_country("!!");
01681 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
01682 (*m_ses.m_logger) << "IP " << p->remote().address() << " was mapped to unknown country: " << country << "\n";
01683 #endif
01684 return;
01685 }
01686
01687 p->set_country(i->second);
01688 }
01689 }
01690
01691 peer_connection& torrent::connect_to_peer(const tcp::endpoint& a)
01692 {
01693 INVARIANT_CHECK;
01694
01695 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
01696 throw protocol_error(a.address().to_string() + " blocked by ip filter");
01697
01698 if (m_connections.find(a) != m_connections.end())
01699 throw protocol_error("already connected to peer");
01700
01701 boost::shared_ptr<stream_socket> s(new stream_socket(m_ses.m_io_service));
01702 boost::intrusive_ptr<peer_connection> c(new bt_peer_connection(
01703 m_ses, shared_from_this(), s, a));
01704
01705 #ifndef NDEBUG
01706 c->m_in_constructor = false;
01707 #endif
01708
01709 #ifndef TORRENT_DISABLE_EXTENSIONS
01710 for (extension_list_t::iterator i = m_extensions.begin()
01711 , end(m_extensions.end()); i != end; ++i)
01712 {
01713 boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
01714 if (pp) c->add_extension(pp);
01715 }
01716 #endif
01717
01718 try
01719 {
01720 m_ses.m_connection_queue.push_back(c);
01721
01722 assert(m_connections.find(a) == m_connections.end());
01723
01724 #ifndef NDEBUG
01725 m_policy->check_invariant();
01726 #endif
01727
01728 m_connections.insert(
01729 std::make_pair(a, boost::get_pointer(c)));
01730
01731 #ifndef NDEBUG
01732 m_policy->check_invariant();
01733 #endif
01734
01735 m_ses.process_connection_queue();
01736 }
01737 catch (std::exception& e)
01738 {
01739
01740 std::map<tcp::endpoint, peer_connection*>::iterator i = m_connections.find(a);
01741 if (i != m_connections.end()) m_connections.erase(i);
01742 m_ses.connection_failed(s, a, e.what());
01743 c->disconnect();
01744 throw;
01745 }
01746 if (c->is_disconnecting()) throw protocol_error("failed to connect");
01747 return *c;
01748 }
01749
01750 void torrent::set_metadata(entry const& metadata)
01751 {
01752 m_torrent_file.parse_info_section(metadata);
01753
01754 boost::mutex::scoped_lock(m_checker.m_mutex);
01755
01756 boost::shared_ptr<aux::piece_checker_data> d(
01757 new aux::piece_checker_data);
01758 d->torrent_ptr = shared_from_this();
01759 d->save_path = m_save_path;
01760 d->info_hash = m_torrent_file.info_hash();
01761
01762 m_checker.m_torrents.push_back(d);
01763 typedef session_impl::torrent_map torrent_map;
01764 torrent_map::iterator i = m_ses.m_torrents.find(
01765 m_torrent_file.info_hash());
01766 assert(i != m_ses.m_torrents.end());
01767 m_ses.m_torrents.erase(i);
01768
01769
01770 m_checker.m_cond.notify_one();
01771
01772 if (m_ses.m_alerts.should_post(alert::info))
01773 {
01774 m_ses.m_alerts.post_alert(metadata_received_alert(
01775 get_handle(), "metadata successfully received from swarm"));
01776 }
01777 }
01778
01779 void torrent::attach_peer(peer_connection* p)
01780 {
01781 INVARIANT_CHECK;
01782
01783 assert(p != 0);
01784 assert(!p->is_local());
01785
01786 std::map<tcp::endpoint, peer_connection*>::iterator c
01787 = m_connections.find(p->remote());
01788 if (c != m_connections.end())
01789 {
01790
01791
01792
01793
01794
01795 if (!c->second->is_connecting())
01796 {
01797 throw protocol_error("already connected to peer");
01798 }
01799 c->second->disconnect();
01800 }
01801
01802 if (m_ses.m_connections.find(p->get_socket())
01803 == m_ses.m_connections.end())
01804 {
01805 throw protocol_error("peer is not properly constructed");
01806 }
01807
01808 if (m_ses.is_aborted())
01809 {
01810 throw protocol_error("session is closing");
01811 }
01812
01813 peer_iterator ci = m_connections.insert(
01814 std::make_pair(p->remote(), p)).first;
01815 try
01816 {
01817
01818
01819
01820 #ifndef TORRENT_DISABLE_EXTENSIONS
01821 for (extension_list_t::iterator i = m_extensions.begin()
01822 , end(m_extensions.end()); i != end; ++i)
01823 {
01824 boost::shared_ptr<peer_plugin> pp((*i)->new_connection(p));
01825 if (pp) p->add_extension(pp);
01826 }
01827 #endif
01828 m_policy->new_connection(*ci->second);
01829 }
01830 catch (std::exception& e)
01831 {
01832 m_connections.erase(ci);
01833 throw;
01834 }
01835 assert((p->proxy() == tcp::endpoint() && p->remote() == p->get_socket()->remote_endpoint())
01836 || p->proxy() == p->get_socket()->remote_endpoint());
01837
01838 #ifndef NDEBUG
01839 m_policy->check_invariant();
01840 #endif
01841 }
01842
01843 void torrent::disconnect_all()
01844 {
01845 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
01846
01847 INVARIANT_CHECK;
01848
01849 while (!m_connections.empty())
01850 {
01851 peer_connection& p = *m_connections.begin()->second;
01852 assert(p.associated_torrent().lock().get() == this);
01853
01854 #if defined(TORRENT_VERBOSE_LOGGING)
01855 if (m_abort)
01856 (*p.m_logger) << "*** CLOSING CONNECTION 'aborting'\n";
01857 else
01858 (*p.m_logger) << "*** CLOSING CONNECTION 'pausing'\n";
01859 #endif
01860 #ifndef NDEBUG
01861 std::size_t size = m_connections.size();
01862 #endif
01863 p.disconnect();
01864 assert(m_connections.size() <= size);
01865 }
01866 }
01867
01868 bool torrent::request_bandwidth_from_session(int channel) const
01869 {
01870 int max_assignable = m_bandwidth_limit[channel].max_assignable();
01871 return max_assignable > max_bandwidth_block_size
01872 || (m_bandwidth_limit[channel].throttle() < max_bandwidth_block_size
01873 && max_assignable == m_bandwidth_limit[channel].throttle());
01874 }
01875
01876 int torrent::bandwidth_throttle(int channel) const
01877 {
01878 return m_bandwidth_limit[channel].throttle();
01879 }
01880
01881 void torrent::request_bandwidth(int channel
01882 , boost::intrusive_ptr<peer_connection> p
01883 , bool non_prioritized)
01884 {
01885 if (request_bandwidth_from_session(channel))
01886 {
01887 if (channel == peer_connection::upload_channel)
01888 m_ses.m_ul_bandwidth_manager.request_bandwidth(p, non_prioritized);
01889 else if (channel == peer_connection::download_channel)
01890 m_ses.m_dl_bandwidth_manager.request_bandwidth(p, non_prioritized);
01891
01892 m_bandwidth_limit[channel].assign(max_bandwidth_block_size);
01893 }
01894 else
01895 {
01896 m_bandwidth_queue[channel].push_back(bw_queue_entry(p, non_prioritized));
01897 }
01898 }
01899
01900 void torrent::expire_bandwidth(int channel, int amount)
01901 {
01902 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
01903
01904 assert(amount >= -1);
01905 if (amount == -1) amount = max_bandwidth_block_size;
01906 m_bandwidth_limit[channel].expire(amount);
01907
01908 while (!m_bandwidth_queue[channel].empty()
01909 && request_bandwidth_from_session(channel))
01910 {
01911 bw_queue_entry qe = m_bandwidth_queue[channel].front();
01912 m_bandwidth_queue[channel].pop_front();
01913 if (channel == peer_connection::upload_channel)
01914 m_ses.m_ul_bandwidth_manager.request_bandwidth(qe.peer, qe.non_prioritized);
01915 else if (channel == peer_connection::download_channel)
01916 m_ses.m_dl_bandwidth_manager.request_bandwidth(qe.peer, qe.non_prioritized);
01917 m_bandwidth_limit[channel].assign(max_bandwidth_block_size);
01918 }
01919 }
01920
01921 void torrent::assign_bandwidth(int channel, int amount)
01922 {
01923 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
01924
01925 assert(amount >= 0);
01926 if (amount < max_bandwidth_block_size)
01927 expire_bandwidth(channel, max_bandwidth_block_size - amount);
01928 }
01929
01930
01931 void torrent::finished()
01932 {
01933 INVARIANT_CHECK;
01934
01935 if (alerts().should_post(alert::info))
01936 {
01937 alerts().post_alert(torrent_finished_alert(
01938 get_handle()
01939 , "torrent has finished downloading"));
01940 }
01941
01942
01943
01944
01945 std::vector<peer_connection*> seeds;
01946 for (peer_iterator i = m_connections.begin();
01947 i != m_connections.end(); ++i)
01948 {
01949 assert(i->second->associated_torrent().lock().get() == this);
01950 if (i->second->is_seed())
01951 {
01952 #if defined(TORRENT_VERBOSE_LOGGING)
01953 (*i->second->m_logger) << "*** SEED, CLOSING CONNECTION\n";
01954 #endif
01955 seeds.push_back(i->second);
01956 }
01957 }
01958 std::for_each(seeds.begin(), seeds.end()
01959 , bind(&peer_connection::disconnect, _1));
01960
01961 m_storage->release_files();
01962 }
01963
01964
01965 void torrent::completed()
01966 {
01967 INVARIANT_CHECK;
01968
01969
01970
01971 m_event = tracker_request::completed;
01972 force_tracker_request();
01973 }
01974
01975
01976
01977
01978 int torrent::prioritize_tracker(int index)
01979 {
01980 INVARIANT_CHECK;
01981
01982 assert(index >= 0);
01983 if (index >= (int)m_trackers.size()) return (int)m_trackers.size()-1;
01984
01985 while (index > 0 && m_trackers[index].tier == m_trackers[index-1].tier)
01986 {
01987 std::swap(m_trackers[index].url, m_trackers[index-1].url);
01988 --index;
01989 }
01990 return index;
01991 }
01992
01993 void torrent::try_next_tracker()
01994 {
01995 INVARIANT_CHECK;
01996
01997 using namespace boost::posix_time;
01998 ++m_currently_trying_tracker;
01999
02000 if ((unsigned)m_currently_trying_tracker >= m_trackers.size())
02001 {
02002 int delay = tracker_retry_delay_min
02003 + std::min(m_failed_trackers, (int)tracker_failed_max)
02004 * (tracker_retry_delay_max - tracker_retry_delay_min)
02005 / tracker_failed_max;
02006
02007 ++m_failed_trackers;
02008
02009 m_currently_trying_tracker = 0;
02010 m_next_request = second_clock::universal_time() + seconds(delay);
02011
02012 #ifndef TORRENT_DISABLE_DHT
02013
02014
02015
02016 if (m_dht_announce_timer.expires_from_now().is_negative() && should_announce_dht())
02017 {
02018 m_dht_announce_timer.expires_from_now(boost::posix_time::seconds(1));
02019 m_dht_announce_timer.async_wait(m_ses.m_strand.wrap(
02020 bind(&torrent::on_dht_announce, this, _1)));
02021 }
02022 #endif
02023
02024 }
02025 else
02026 {
02027
02028 m_next_request = second_clock::universal_time();
02029 }
02030
02031 }
02032
02033 bool torrent::check_fastresume(aux::piece_checker_data& data)
02034 {
02035 INVARIANT_CHECK;
02036
02037 if (!m_storage.get())
02038 {
02039
02040
02041 init();
02042 }
02043
02044 assert(m_storage.get());
02045 bool done = true;
02046 try
02047 {
02048 done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces
02049 , m_compact_mode);
02050 }
02051 catch (std::exception& e)
02052 {
02053
02054 std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
02055 m_num_pieces = 0;
02056
02057 if (m_ses.m_alerts.should_post(alert::fatal))
02058 {
02059 m_ses.m_alerts.post_alert(
02060 file_error_alert(
02061 get_handle()
02062 , e.what()));
02063 }
02064 pause();
02065 }
02066 #ifndef NDEBUG
02067 m_initial_done = boost::get<0>(bytes_done());
02068 #endif
02069 return done;
02070 }
02071
02072 std::pair<bool, float> torrent::check_files()
02073 {
02074 INVARIANT_CHECK;
02075
02076 assert(m_storage.get());
02077
02078 std::pair<bool, float> progress(true, 1.f);
02079 try
02080 {
02081 progress = m_storage->check_files(m_have_pieces, m_num_pieces
02082 , m_ses.m_mutex);
02083 }
02084 catch (std::exception& e)
02085 {
02086
02087 std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
02088 m_num_pieces = 0;
02089
02090 if (m_ses.m_alerts.should_post(alert::fatal))
02091 {
02092 m_ses.m_alerts.post_alert(
02093 file_error_alert(
02094 get_handle()
02095 , e.what()));
02096 }
02097 pause();
02098 }
02099
02100 #ifndef NDEBUG
02101 m_initial_done = boost::get<0>(bytes_done());
02102 #endif
02103 return progress;
02104 }
02105
02106 void torrent::files_checked(std::vector<piece_picker::downloading_piece> const&
02107 unfinished_pieces)
02108 {
02109 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
02110
02111 INVARIANT_CHECK;
02112
02113 if (!is_seed())
02114 {
02115 m_picker->files_checked(m_have_pieces, unfinished_pieces);
02116 }
02117 else
02118 {
02119 m_picker.reset();
02120 }
02121 if (!m_connections_initialized)
02122 {
02123 m_connections_initialized = true;
02124
02125
02126 typedef std::map<tcp::endpoint, peer_connection*> conn_map;
02127 for (conn_map::iterator i = m_connections.begin()
02128 , end(m_connections.end()); i != end;)
02129 {
02130 try
02131 {
02132 i->second->init();
02133 i->second->on_metadata();
02134 ++i;
02135 }
02136 catch (std::exception& e)
02137 {
02138
02139 conn_map::iterator j = i;
02140 ++j;
02141 m_ses.connection_failed(i->second->get_socket()
02142 , i->first, e.what());
02143 i = j;
02144 }
02145 }
02146 }
02147 #ifndef NDEBUG
02148 m_initial_done = boost::get<0>(bytes_done());
02149 #endif
02150 }
02151
02152 alert_manager& torrent::alerts() const
02153 {
02154 return m_ses.m_alerts;
02155 }
02156
02157 boost::filesystem::path torrent::save_path() const
02158 {
02159 return m_save_path;
02160 }
02161
02162 bool torrent::move_storage(boost::filesystem::path const& save_path)
02163 {
02164 INVARIANT_CHECK;
02165
02166 bool ret = true;
02167 if (m_storage.get())
02168 {
02169 ret = m_storage->move_storage(save_path);
02170 m_save_path = m_storage->save_path();
02171 }
02172 else
02173 {
02174 m_save_path = save_path;
02175 }
02176 return ret;
02177 }
02178
02179 piece_manager& torrent::filesystem()
02180 {
02181 INVARIANT_CHECK;
02182
02183 assert(m_storage.get());
02184 return *m_storage;
02185 }
02186
02187 torrent_handle torrent::get_handle() const
02188 {
02189 INVARIANT_CHECK;
02190
02191 return torrent_handle(&m_ses, &m_checker, m_torrent_file.info_hash());
02192 }
02193
02194 session_settings const& torrent::settings() const
02195 {
02196
02197 return m_ses.settings();
02198 }
02199
02200 #ifndef NDEBUG
02201 void torrent::check_invariant() const
02202 {
02203
02204 for (const_peer_iterator i = begin(); i != end(); ++i)
02205 {
02206 peer_connection const& p = *i->second;
02207 torrent* associated_torrent = p.associated_torrent().lock().get();
02208 if (associated_torrent != this)
02209 assert(false);
02210 }
02211
02212 if (valid_metadata())
02213 {
02214 assert(int(m_have_pieces.size()) == m_torrent_file.num_pieces());
02215 }
02216 else
02217 {
02218 assert(m_have_pieces.empty());
02219 }
02220
02221 size_type total_done = quantized_bytes_done();
02222 if (m_torrent_file.is_valid())
02223 {
02224 if (is_seed())
02225 assert(total_done == m_torrent_file.total_size());
02226 else
02227 assert(total_done != m_torrent_file.total_size());
02228 }
02229 else
02230 {
02231 assert(total_done == 0);
02232 }
02233
02234 assert(m_num_pieces
02235 == std::count(m_have_pieces.begin(), m_have_pieces.end(), true));
02236 assert(!valid_metadata() || m_block_size > 0);
02237 assert(!valid_metadata() || (m_torrent_file.piece_length() % m_block_size) == 0);
02238
02239 }
02240 #endif
02241
02242 void torrent::set_sequenced_download_threshold(int threshold)
02243 {
02244
02245
02246 if (valid_metadata() && !is_seed())
02247 picker().set_sequenced_download_threshold(threshold);
02248 }
02249
02250 void torrent::set_max_uploads(int limit)
02251 {
02252 assert(limit >= -1);
02253 if (limit == -1) limit = std::numeric_limits<int>::max();
02254 m_uploads_quota.max = std::max(m_uploads_quota.min, limit);
02255 }
02256
02257 void torrent::set_max_connections(int limit)
02258 {
02259 assert(limit >= -1);
02260 if (limit == -1) limit = std::numeric_limits<int>::max();
02261 m_connections_quota.max = std::max(m_connections_quota.min, limit);
02262 }
02263
02264 void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit)
02265 {
02266 assert(limit >= -1);
02267 peer_connection* p = connection_for(ip);
02268 if (p == 0) return;
02269 p->set_upload_limit(limit);
02270 }
02271
02272 void torrent::set_peer_download_limit(tcp::endpoint ip, int limit)
02273 {
02274 assert(limit >= -1);
02275 peer_connection* p = connection_for(ip);
02276 if (p == 0) return;
02277 p->set_download_limit(limit);
02278 }
02279
02280 void torrent::set_upload_limit(int limit)
02281 {
02282 assert(limit >= -1);
02283 if (limit == -1) limit = std::numeric_limits<int>::max();
02284 if (limit < num_peers() * 10) limit = num_peers() * 10;
02285 m_bandwidth_limit[peer_connection::upload_channel].throttle(limit);
02286 }
02287
02288 void torrent::set_download_limit(int limit)
02289 {
02290 assert(limit >= -1);
02291 if (limit == -1) limit = std::numeric_limits<int>::max();
02292 if (limit < num_peers() * 10) limit = num_peers() * 10;
02293 m_bandwidth_limit[peer_connection::download_channel].throttle(limit);
02294 }
02295
02296 void torrent::pause()
02297 {
02298 INVARIANT_CHECK;
02299
02300 if (m_paused) return;
02301
02302 #ifndef TORRENT_DISABLE_EXTENSIONS
02303 for (extension_list_t::iterator i = m_extensions.begin()
02304 , end(m_extensions.end()); i != end; ++i)
02305 {
02306 try { if ((*i)->on_pause()) return; } catch (std::exception&) {}
02307 }
02308 #endif
02309
02310 disconnect_all();
02311 m_paused = true;
02312
02313 m_event = tracker_request::stopped;
02314 m_just_paused = true;
02315
02316
02317 if (m_storage.get()) m_storage->release_files();
02318 }
02319
02320 void torrent::resume()
02321 {
02322 INVARIANT_CHECK;
02323
02324 if (!m_paused) return;
02325
02326 #ifndef TORRENT_DISABLE_EXTENSIONS
02327 for (extension_list_t::iterator i = m_extensions.begin()
02328 , end(m_extensions.end()); i != end; ++i)
02329 {
02330 try { if ((*i)->on_resume()) return; } catch (std::exception&) {}
02331 }
02332 #endif
02333
02334 m_paused = false;
02335 m_uploads_quota.min = 2;
02336 m_connections_quota.min = 2;
02337 m_uploads_quota.max = std::numeric_limits<int>::max();
02338 m_connections_quota.max = std::numeric_limits<int>::max();
02339
02340
02341 m_event = tracker_request::started;
02342 force_tracker_request();
02343
02344
02345 m_time_scaler = 0;
02346 }
02347
02348 void torrent::second_tick(stat& accumulator, float tick_interval)
02349 {
02350 INVARIANT_CHECK;
02351
02352 m_connections_quota.used = (int)m_connections.size();
02353 m_uploads_quota.used = m_policy->num_uploads();
02354
02355 #ifndef TORRENT_DISABLE_EXTENSIONS
02356 for (extension_list_t::iterator i = m_extensions.begin()
02357 , end(m_extensions.end()); i != end; ++i)
02358 {
02359 try { (*i)->tick(); } catch (std::exception&) {}
02360 }
02361 #endif
02362
02363 if (m_paused)
02364 {
02365
02366 m_stat.second_tick(tick_interval);
02367 m_web_stat.second_tick(tick_interval);
02368 m_connections_quota.min = 0;
02369 m_connections_quota.max = 0;
02370 m_uploads_quota.min = 0;
02371 m_uploads_quota.max = 0;
02372 return;
02373 }
02374
02375
02376
02377
02378 if (!is_seed() && !m_web_seeds.empty())
02379 {
02380
02381
02382 std::set<std::string> web_seeds;
02383 for (peer_iterator i = m_connections.begin();
02384 i != m_connections.end(); ++i)
02385 {
02386 web_peer_connection* p
02387 = dynamic_cast<web_peer_connection*>(i->second);
02388 if (!p) continue;
02389 web_seeds.insert(p->url());
02390 }
02391
02392 for (std::set<std::string>::iterator i = m_resolving_web_seeds.begin()
02393 , end(m_resolving_web_seeds.end()); i != end; ++i)
02394 web_seeds.insert(web_seeds.begin(), *i);
02395
02396
02397
02398 std::vector<std::string> not_connected_web_seeds;
02399 std::set_difference(m_web_seeds.begin(), m_web_seeds.end(), web_seeds.begin()
02400 , web_seeds.end(), std::back_inserter(not_connected_web_seeds));
02401
02402
02403 std::for_each(not_connected_web_seeds.begin(), not_connected_web_seeds.end()
02404 , bind(&torrent::connect_to_url_seed, this, _1));
02405 }
02406
02407 for (peer_iterator i = m_connections.begin();
02408 i != m_connections.end(); ++i)
02409 {
02410 peer_connection* p = i->second;
02411 m_stat += p->statistics();
02412 if (dynamic_cast<web_peer_connection*>(p))
02413 {
02414 m_web_stat += p->statistics();
02415 }
02416
02417
02418 p->second_tick(tick_interval);
02419 }
02420 accumulator += m_stat;
02421 m_stat.second_tick(tick_interval);
02422 m_web_stat.second_tick(tick_interval);
02423 }
02424
02425 void torrent::distribute_resources(float tick_interval)
02426 {
02427 INVARIANT_CHECK;
02428
02429 m_time_scaler--;
02430 if (m_time_scaler <= 0)
02431 {
02432 m_time_scaler = 10;
02433 m_policy->pulse();
02434 }
02435 }
02436
02437 bool torrent::verify_piece(int piece_index)
02438 {
02439
02440 assert(m_storage.get());
02441 assert(piece_index >= 0);
02442 assert(piece_index < m_torrent_file.num_pieces());
02443 assert(piece_index < (int)m_have_pieces.size());
02444
02445 int size = static_cast<int>(m_torrent_file.piece_size(piece_index));
02446 std::vector<char> buffer(size);
02447 assert(size > 0);
02448 m_storage->read(&buffer[0], piece_index, 0, size);
02449
02450 hasher h;
02451 h.update(&buffer[0], size);
02452 sha1_hash digest = h.final();
02453
02454 if (m_torrent_file.hash_for_piece(piece_index) != digest)
02455 return false;
02456
02457 return true;
02458 }
02459
02460 const tcp::endpoint& torrent::current_tracker() const
02461 {
02462 return m_tracker_address;
02463 }
02464
02465 bool torrent::is_allocating() const
02466 { return m_storage.get() && m_storage->is_allocating(); }
02467
02468 void torrent::file_progress(std::vector<float>& fp) const
02469 {
02470 assert(valid_metadata());
02471
02472 fp.clear();
02473 fp.resize(m_torrent_file.num_files(), 0.f);
02474
02475 for (int i = 0; i < m_torrent_file.num_files(); ++i)
02476 {
02477 peer_request ret = m_torrent_file.map_file(i, 0, 0);
02478 size_type size = m_torrent_file.file_at(i).size;
02479
02480 if (size == 0)
02481 {
02482 fp[i] = 1.f;
02483 continue;
02484 }
02485
02486 size_type done = 0;
02487 while (size > 0)
02488 {
02489 size_type bytes_step = std::min(m_torrent_file.piece_size(ret.piece)
02490 - ret.start, size);
02491 if (m_have_pieces[ret.piece]) done += bytes_step;
02492 ++ret.piece;
02493 ret.start = 0;
02494 size -= bytes_step;
02495 }
02496 assert(size == 0);
02497
02498 fp[i] = static_cast<float>(done) / m_torrent_file.file_at(i).size;
02499 }
02500 }
02501
02502 torrent_status torrent::status() const
02503 {
02504 INVARIANT_CHECK;
02505
02506 assert(std::accumulate(
02507 m_have_pieces.begin()
02508 , m_have_pieces.end()
02509 , 0) == m_num_pieces);
02510
02511 torrent_status st;
02512
02513 st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end(),
02514 boost::bind<bool>(std::logical_not<bool>(), boost::bind(&peer_connection::is_connecting,
02515 boost::bind(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1))));
02516
02517 st.num_complete = m_complete;
02518 st.num_incomplete = m_incomplete;
02519 st.paused = m_paused;
02520 boost::tie(st.total_done, st.total_wanted_done) = bytes_done();
02521
02522
02523 st.total_payload_download = m_stat.total_payload_download();
02524 st.total_payload_upload = m_stat.total_payload_upload();
02525
02526
02527 st.total_download = m_stat.total_payload_download()
02528 + m_stat.total_protocol_download();
02529 st.total_upload = m_stat.total_payload_upload()
02530 + m_stat.total_protocol_upload();
02531
02532
02533 st.total_failed_bytes = m_total_failed_bytes;
02534 st.total_redundant_bytes = m_total_redundant_bytes;
02535
02536
02537 st.download_rate = m_stat.download_rate();
02538 st.upload_rate = m_stat.upload_rate();
02539 st.download_payload_rate = m_stat.download_payload_rate();
02540 st.upload_payload_rate = m_stat.upload_payload_rate();
02541
02542 st.next_announce = next_announce()
02543 - second_clock::universal_time();
02544 if (st.next_announce.is_negative()) st.next_announce
02545 = boost::posix_time::seconds(0);
02546 st.announce_interval = boost::posix_time::seconds(m_duration);
02547
02548 if (m_last_working_tracker >= 0)
02549 {
02550 st.current_tracker
02551 = m_trackers[m_last_working_tracker].url;
02552 }
02553
02554
02555
02556 if (!valid_metadata())
02557 {
02558 if (m_got_tracker_response == false)
02559 st.state = torrent_status::connecting_to_tracker;
02560 else
02561 st.state = torrent_status::downloading_metadata;
02562
02563 st.progress = 0.f;
02564
02565 st.block_size = 0;
02566
02567 return st;
02568 }
02569
02570 st.block_size = block_size();
02571
02572
02573
02574 st.total_wanted = m_torrent_file.total_size();
02575
02576 if (m_picker.get() && (m_picker->num_filtered() > 0
02577 || m_picker->num_have_filtered() > 0))
02578 {
02579 int filtered_pieces = m_picker->num_filtered()
02580 + m_picker->num_have_filtered();
02581 int last_piece_index = m_torrent_file.num_pieces() - 1;
02582 if (m_picker->is_filtered(last_piece_index))
02583 {
02584 st.total_wanted -= m_torrent_file.piece_size(last_piece_index);
02585 --filtered_pieces;
02586 }
02587
02588 st.total_wanted -= filtered_pieces * m_torrent_file.piece_length();
02589 }
02590
02591 assert(st.total_wanted >= st.total_wanted_done);
02592
02593 if (st.total_wanted == 0) st.progress = 1.f;
02594 else st.progress = st.total_wanted_done
02595 / static_cast<double>(st.total_wanted);
02596
02597 st.pieces = &m_have_pieces;
02598 st.num_pieces = m_num_pieces;
02599
02600 if (m_got_tracker_response == false)
02601 {
02602 st.state = torrent_status::connecting_to_tracker;
02603 }
02604 else if (is_seed())
02605 {
02606 assert(st.total_done == m_torrent_file.total_size());
02607 st.state = torrent_status::seeding;
02608 }
02609 else if (st.total_wanted_done == st.total_wanted)
02610 {
02611 assert(st.total_done != m_torrent_file.total_size());
02612 st.state = torrent_status::finished;
02613 }
02614 else
02615 {
02616 st.state = torrent_status::downloading;
02617 }
02618
02619 st.num_seeds = num_seeds();
02620 if (m_picker.get())
02621 st.distributed_copies = m_picker->distributed_copies();
02622 else
02623 st.distributed_copies = -1;
02624 return st;
02625 }
02626
02627 int torrent::num_seeds() const
02628 {
02629 INVARIANT_CHECK;
02630
02631 return (int)std::count_if(m_connections.begin(), m_connections.end(),
02632 boost::bind(&peer_connection::is_seed,
02633 boost::bind(&std::map<tcp::endpoint
02634 ,peer_connection*>::value_type::second, _1)));
02635 }
02636
02637 void torrent::tracker_request_timed_out(
02638 tracker_request const&)
02639 {
02640 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
02641
02642 INVARIANT_CHECK;
02643
02644 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
02645 debug_log("*** tracker timed out");
02646 #endif
02647
02648 if (m_ses.m_alerts.should_post(alert::warning))
02649 {
02650 std::stringstream s;
02651 s << "tracker: \""
02652 << m_trackers[m_currently_trying_tracker].url
02653 << "\" timed out";
02654 m_ses.m_alerts.post_alert(tracker_alert(get_handle()
02655 , m_failed_trackers + 1, 0, s.str()));
02656 }
02657 try_next_tracker();
02658 }
02659
02660
02661
02662
02663 void torrent::tracker_request_error(tracker_request const&
02664 , int response_code, const std::string& str)
02665 {
02666 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
02667
02668 INVARIANT_CHECK;
02669
02670 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
02671 debug_log(std::string("*** tracker error: ") + str);
02672 #endif
02673 if (m_ses.m_alerts.should_post(alert::warning))
02674 {
02675 std::stringstream s;
02676 s << "tracker: \""
02677 << m_trackers[m_currently_trying_tracker].url
02678 << "\" " << str;
02679 m_ses.m_alerts.post_alert(tracker_alert(get_handle()
02680 , m_failed_trackers + 1, response_code, s.str()));
02681 }
02682
02683 try_next_tracker();
02684 }
02685
02686 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
02687 void torrent::debug_log(const std::string& line)
02688 {
02689 (*m_ses.m_logger) << line << "\n";
02690 }
02691 #endif
02692
02693 }
02694