fixes bug where priorities where lost when force-rechecking.
[libtorrent.git] / src / torrent.cpp
blobf0a16bd4f12a34461e4fb4ac7a3eef8fc6bd4f02
1 /*
3 Copyright (c) 2003, Arvid Norberg
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
33 #include "libtorrent/pch.hpp"
35 #include <ctime>
36 #include <iostream>
37 #include <fstream>
38 #include <iomanip>
39 #include <iterator>
40 #include <algorithm>
41 #include <set>
42 #include <cctype>
43 #include <numeric>
45 #ifdef _MSC_VER
46 #pragma warning(push, 1)
47 #endif
49 #include <boost/lexical_cast.hpp>
50 #include <boost/filesystem/convenience.hpp>
51 #include <boost/bind.hpp>
52 #include <boost/thread/mutex.hpp>
54 #ifdef _MSC_VER
55 #pragma warning(pop)
56 #endif
58 #include "libtorrent/torrent_handle.hpp"
59 #include "libtorrent/session.hpp"
60 #include "libtorrent/torrent_info.hpp"
61 #include "libtorrent/tracker_manager.hpp"
62 #include "libtorrent/parse_url.hpp"
63 #include "libtorrent/bencode.hpp"
64 #include "libtorrent/hasher.hpp"
65 #include "libtorrent/entry.hpp"
66 #include "libtorrent/peer.hpp"
67 #include "libtorrent/bt_peer_connection.hpp"
68 #include "libtorrent/web_peer_connection.hpp"
69 #include "libtorrent/peer_id.hpp"
70 #include "libtorrent/alert.hpp"
71 #include "libtorrent/identify_client.hpp"
72 #include "libtorrent/alert_types.hpp"
73 #include "libtorrent/extensions.hpp"
74 #include "libtorrent/aux_/session_impl.hpp"
75 #include "libtorrent/instantiate_connection.hpp"
76 #include "libtorrent/assert.hpp"
78 using namespace libtorrent;
79 using boost::tuples::tuple;
80 using boost::tuples::get;
81 using boost::tuples::make_tuple;
82 using boost::bind;
83 using boost::mutex;
84 using libtorrent::aux::session_impl;
86 namespace
89 enum
91 // wait 60 seconds before retrying a failed tracker
92 tracker_retry_delay_min = 60
93 // when tracker_failed_max trackers
94 // has failed, wait 10 minutes instead
95 , tracker_retry_delay_max = 10 * 60
96 , tracker_failed_max = 5
99 struct find_peer_by_ip
101 find_peer_by_ip(tcp::endpoint const& a, const torrent* t)
102 : ip(a)
103 , tor(t)
104 { TORRENT_ASSERT(t != 0); }
106 bool operator()(session_impl::connection_map::value_type const& c) const
108 tcp::endpoint const& sender = c->remote();
109 if (sender.address() != ip.address()) return false;
110 if (tor != c->associated_torrent().lock().get()) return false;
111 return true;
114 tcp::endpoint const& ip;
115 torrent const* tor;
118 struct peer_by_id
120 peer_by_id(const peer_id& i): pid(i) {}
122 bool operator()(session_impl::connection_map::value_type const& p) const
124 if (p->pid() != pid) return false;
125 // have a special case for all zeros. We can have any number
126 // of peers with that pid, since it's used to indicate no pid.
127 if (std::count(pid.begin(), pid.end(), 0) == 20) return false;
128 return true;
131 peer_id const& pid;
135 namespace libtorrent
138 torrent::torrent(
139 session_impl& ses
140 , boost::intrusive_ptr<torrent_info> tf
141 , fs::path const& save_path
142 , tcp::endpoint const& net_interface
143 , storage_mode_t storage_mode
144 , int block_size
145 , storage_constructor_type sc
146 , bool paused
147 , std::vector<char>* resume_data
148 , int seq
149 , bool auto_managed)
150 : m_policy(this)
151 , m_active_time(seconds(0))
152 , m_seeding_time(seconds(0))
153 , m_total_uploaded(0)
154 , m_total_downloaded(0)
155 , m_started(time_now())
156 , m_last_scrape(min_time())
157 , m_torrent_file(tf)
158 , m_storage(0)
159 , m_next_tracker_announce(time_now())
160 , m_host_resolver(ses.m_io_service)
161 , m_lsd_announce_timer(ses.m_io_service)
162 , m_tracker_timer(ses.m_io_service)
163 #ifndef TORRENT_DISABLE_DHT
164 , m_last_dht_announce(time_now() - minutes(15))
165 #endif
166 , m_ses(ses)
167 , m_picker(new piece_picker())
168 , m_trackers(m_torrent_file->trackers())
169 , m_total_failed_bytes(0)
170 , m_total_redundant_bytes(0)
171 , m_net_interface(net_interface.address(), 0)
172 , m_save_path(complete(save_path))
173 , m_storage_mode(storage_mode)
174 , m_state(torrent_status::queued_for_checking)
175 , m_settings(ses.settings())
176 , m_storage_constructor(sc)
177 , m_progress(0.f)
178 , m_ratio(0.f)
179 , m_max_uploads((std::numeric_limits<int>::max)())
180 , m_num_uploads(0)
181 , m_max_connections((std::numeric_limits<int>::max)())
182 , m_block_size((std::min)(block_size, tf->piece_length()))
183 , m_complete(-1)
184 , m_incomplete(-1)
185 , m_deficit_counter(0)
186 , m_duration(1800)
187 , m_sequence_number(seq)
188 , m_last_working_tracker(-1)
189 , m_currently_trying_tracker(0)
190 , m_failed_trackers(0)
191 , m_time_scaler(0)
192 , m_abort(false)
193 , m_paused(paused)
194 , m_auto_managed(auto_managed)
195 #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
196 , m_resolving_country(false)
197 , m_resolve_countries(false)
198 #endif
199 , m_sequential_download(false)
200 , m_got_tracker_response(false)
201 , m_connections_initialized(true)
202 , m_has_incoming(false)
203 , m_files_checked(false)
204 , m_announcing(false)
205 , m_start_sent(false)
206 , m_complete_sent(false)
208 parse_resume_data(resume_data);
210 #ifndef TORRENT_DISABLE_ENCRYPTION
211 hasher h;
212 h.update("req2", 4);
213 h.update((char*)&tf->info_hash()[0], 20);
214 m_obfuscated_hash = h.final();
215 #endif
218 torrent::torrent(
219 session_impl& ses
220 , char const* tracker_url
221 , sha1_hash const& info_hash
222 , char const* name
223 , fs::path const& save_path
224 , tcp::endpoint const& net_interface
225 , storage_mode_t storage_mode
226 , int block_size
227 , storage_constructor_type sc
228 , bool paused
229 , std::vector<char>* resume_data
230 , int seq
231 , bool auto_managed)
232 : m_policy(this)
233 , m_active_time(seconds(0))
234 , m_seeding_time(seconds(0))
235 , m_total_uploaded(0)
236 , m_total_downloaded(0)
237 , m_started(time_now())
238 , m_last_scrape(min_time())
239 , m_torrent_file(new torrent_info(info_hash))
240 , m_storage(0)
241 , m_next_tracker_announce(time_now())
242 , m_host_resolver(ses.m_io_service)
243 , m_lsd_announce_timer(ses.m_io_service)
244 , m_tracker_timer(ses.m_io_service)
245 #ifndef TORRENT_DISABLE_DHT
246 , m_last_dht_announce(time_now() - minutes(15))
247 #endif
248 , m_ses(ses)
249 , m_picker(new piece_picker())
250 , m_total_failed_bytes(0)
251 , m_total_redundant_bytes(0)
252 , m_net_interface(net_interface.address(), 0)
253 , m_save_path(complete(save_path))
254 , m_storage_mode(storage_mode)
255 , m_state(torrent_status::queued_for_checking)
256 , m_settings(ses.settings())
257 , m_storage_constructor(sc)
258 , m_progress(0.f)
259 , m_ratio(0.f)
260 , m_max_uploads((std::numeric_limits<int>::max)())
261 , m_num_uploads(0)
262 , m_max_connections((std::numeric_limits<int>::max)())
263 , m_block_size(block_size)
264 , m_complete(-1)
265 , m_incomplete(-1)
266 , m_deficit_counter(0)
267 , m_duration(1800)
268 , m_sequence_number(seq)
269 , m_last_working_tracker(-1)
270 , m_currently_trying_tracker(0)
271 , m_failed_trackers(0)
272 , m_time_scaler(0)
273 , m_abort(false)
274 , m_paused(paused)
275 , m_auto_managed(auto_managed)
276 #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
277 , m_resolving_country(false)
278 , m_resolve_countries(false)
279 #endif
280 , m_sequential_download(false)
281 , m_got_tracker_response(false)
282 , m_connections_initialized(false)
283 , m_has_incoming(false)
284 , m_files_checked(false)
285 , m_announcing(false)
286 , m_start_sent(false)
287 , m_complete_sent(false)
289 parse_resume_data(resume_data);
291 #ifndef TORRENT_DISABLE_ENCRYPTION
292 hasher h;
293 h.update("req2", 4);
294 h.update((char*)&info_hash[0], 20);
295 m_obfuscated_hash = h.final();
296 #endif
298 #ifndef NDEBUG
299 m_files_checked = false;
300 #endif
301 INVARIANT_CHECK;
303 if (name) m_name.reset(new std::string(name));
305 if (tracker_url)
307 m_trackers.push_back(announce_entry(tracker_url));
308 m_torrent_file->add_tracker(tracker_url);
312 void torrent::parse_resume_data(std::vector<char>* resume_data)
314 if (!resume_data) return;
315 m_resume_data.swap(*resume_data);
316 if (lazy_bdecode(&m_resume_data[0], &m_resume_data[0]
317 + m_resume_data.size(), m_resume_entry) != 0)
319 std::vector<char>().swap(m_resume_data);
320 if (m_ses.m_alerts.should_post<fastresume_rejected_alert>())
322 m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), "parse failed"));
323 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
324 (*m_ses.m_logger) << "fastresume data for "
325 << torrent_file().name() << " rejected: parse failed\n";
326 #endif
331 void torrent::start()
333 if (m_torrent_file->is_valid()) init();
334 if (m_abort) return;
337 #ifndef TORRENT_DISABLE_DHT
338 bool torrent::should_announce_dht() const
340 if (m_ses.m_listen_sockets.empty()) return false;
342 if (!m_ses.m_dht) return false;
343 if (!m_files_checked) return false;
345 // don't announce private torrents
346 if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false;
347 if (m_trackers.empty()) return true;
349 return m_failed_trackers > 0 || !m_ses.settings().use_dht_as_fallback;
351 #endif
353 torrent::~torrent()
355 // The invariant can't be maintained here, since the torrent
356 // is being destructed, all weak references to it have been
357 // reset, which means that all its peers already have an
358 // invalidated torrent pointer (so it cannot be verified to be correct)
360 // i.e. the invariant can only be maintained if all connections have
361 // been closed by the time the torrent is destructed. And they are
362 // supposed to be closed. So we can still do the invariant check.
364 TORRENT_ASSERT(m_connections.empty());
366 INVARIANT_CHECK;
368 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
369 for (peer_iterator i = m_connections.begin();
370 i != m_connections.end(); ++i)
372 (*(*i)->m_logger) << "*** DESTRUCTING TORRENT\n";
374 #endif
376 TORRENT_ASSERT(m_abort);
377 if (!m_connections.empty())
378 disconnect_all();
381 peer_request torrent::to_req(piece_block const& p)
383 int block_offset = p.block_index * m_block_size;
384 int block_size = (std::min)(torrent_file().piece_size(
385 p.piece_index) - block_offset, m_block_size);
386 TORRENT_ASSERT(block_size > 0);
387 TORRENT_ASSERT(block_size <= m_block_size);
389 peer_request r;
390 r.piece = p.piece_index;
391 r.start = block_offset;
392 r.length = block_size;
393 return r;
396 std::string torrent::name() const
398 if (valid_metadata()) return m_torrent_file->name();
399 if (m_name) return *m_name;
400 return "";
403 #ifndef TORRENT_DISABLE_EXTENSIONS
405 void torrent::add_extension(boost::shared_ptr<torrent_plugin> ext)
407 m_extensions.push_back(ext);
410 void torrent::add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
411 , void* userdata)
413 boost::shared_ptr<torrent_plugin> tp(ext(this, userdata));
414 if (!tp) return;
416 add_extension(tp);
418 for (peer_iterator i = m_connections.begin();
419 i != m_connections.end(); ++i)
421 peer_connection* p = *i;
422 boost::shared_ptr<peer_plugin> pp(tp->new_connection(p));
423 if (pp) p->add_extension(pp);
426 // if files are checked for this torrent, call the extension
427 // to let it initialize itself
428 if (m_connections_initialized)
429 tp->on_files_checked();
432 #endif
434 // this may not be called from a constructor because of the call to
435 // shared_from_this()
436 void torrent::init()
438 TORRENT_ASSERT(m_torrent_file->is_valid());
439 TORRENT_ASSERT(m_torrent_file->num_files() > 0);
440 TORRENT_ASSERT(m_torrent_file->total_size() >= 0);
442 m_file_priority.clear();
443 m_file_priority.resize(m_torrent_file->num_files(), 1);
445 m_block_size = (std::min)(m_block_size, m_torrent_file->piece_length());
447 if (m_torrent_file->num_pieces()
448 > piece_picker::max_pieces)
450 m_error = "too many pieces in torrent";
451 pause();
454 // the shared_from_this() will create an intentional
455 // cycle of ownership, se the hpp file for description.
456 m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
457 , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor
458 , m_storage_mode);
459 m_storage = m_owning_storage.get();
460 m_picker->init((std::max)(m_torrent_file->piece_length() / m_block_size, 1)
461 , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
463 std::vector<std::string> const& url_seeds = m_torrent_file->url_seeds();
464 std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
465 , m_web_seeds.begin()));
467 set_state(torrent_status::queued_for_checking);
469 if (m_resume_entry.type() == lazy_entry::dict_t)
471 char const* error = 0;
472 if (m_resume_entry.dict_find_string_value("file-format") != "libtorrent resume file")
473 error = "invalid file format tag";
475 std::string info_hash = m_resume_entry.dict_find_string_value("info-hash");
476 if (!error && info_hash.empty())
477 error = "missing info-hash";
479 if (!error && sha1_hash(info_hash) != m_torrent_file->info_hash())
480 error = "mismatching info-hash";
482 if (error && m_ses.m_alerts.should_post<fastresume_rejected_alert>())
484 m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), error));
485 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
486 (*m_ses.m_logger) << "fastresume data for "
487 << torrent_file().name() << " rejected: "
488 << error << "\n";
489 #endif
492 if (error)
494 std::vector<char>().swap(m_resume_data);
495 lazy_entry().swap(m_resume_entry);
497 else
499 read_resume_data(m_resume_entry);
503 m_storage->async_check_fastresume(&m_resume_entry
504 , bind(&torrent::on_resume_data_checked
505 , shared_from_this(), _1, _2));
508 void torrent::on_resume_data_checked(int ret, disk_io_job const& j)
510 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
512 if (ret == piece_manager::fatal_disk_error)
514 if (m_ses.m_alerts.should_post<file_error_alert>())
516 m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
517 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
518 (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
519 " error: " << j.str <<
520 " torrent: " << torrent_file().name() <<
521 " ]\n";
522 #endif
524 m_error = j.str;
525 pause();
527 std::vector<char>().swap(m_resume_data);
528 lazy_entry().swap(m_resume_entry);
530 return;
533 if (m_resume_entry.type() == lazy_entry::dict_t)
535 // parse out "peers" from the resume data and add them to the peer list
536 if (lazy_entry const* peers_entry = m_resume_entry.dict_find_list("peers"))
538 peer_id id(0);
540 for (int i = 0; i < peers_entry->list_size(); ++i)
542 lazy_entry const* e = peers_entry->list_at(i);
543 if (e->type() != lazy_entry::dict_t) continue;
544 std::string ip = e->dict_find_string_value("ip");
545 int port = e->dict_find_int_value("port");
546 if (ip.empty() || port == 0) continue;
547 tcp::endpoint a(address::from_string(ip), (unsigned short)port);
548 m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
552 // parse out "banned_peers" and add them as banned
553 if (lazy_entry const* banned_peers_entry = m_resume_entry.dict_find_list("banned_peers"))
555 peer_id id(0);
557 for (int i = 0; i < banned_peers_entry->list_size(); ++i)
559 lazy_entry const* e = banned_peers_entry->list_at(i);
560 if (e->type() != lazy_entry::dict_t) continue;
561 std::string ip = e->dict_find_string_value("ip");
562 int port = e->dict_find_int_value("port");
563 if (ip.empty() || port == 0) continue;
564 tcp::endpoint a(address::from_string(ip), (unsigned short)port);
565 policy::peer* p = m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
566 if (p) p->banned = true;
571 bool fastresume_rejected = !j.str.empty();
573 if (fastresume_rejected && m_ses.m_alerts.should_post<fastresume_rejected_alert>())
575 m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), j.str));
576 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
577 (*m_ses.m_logger) << "fastresume data for "
578 << torrent_file().name() << " rejected: "
579 << j.str << "\n";
580 #endif
583 if (ret == 0)
585 // there are either no files for this torrent
586 // or the resume_data was accepted
588 if (!fastresume_rejected && m_resume_entry.type() == lazy_entry::dict_t)
590 // parse have bitmask
591 lazy_entry const* pieces = m_resume_entry.dict_find("pieces");
592 if (pieces && pieces->type() == lazy_entry::string_t
593 && int(pieces->string_length()) == m_torrent_file->num_pieces())
595 char const* pieces_str = pieces->string_ptr();
596 for (int i = 0, end(pieces->string_length()); i < end; ++i)
598 if ((pieces_str[i] & 1) == 0) continue;
599 m_picker->we_have(i);
603 // parse unfinished pieces
604 int num_blocks_per_piece =
605 static_cast<int>(torrent_file().piece_length()) / block_size();
607 if (lazy_entry const* unfinished_ent = m_resume_entry.dict_find_list("unfinished"))
609 for (int i = 0; i < unfinished_ent->list_size(); ++i)
611 lazy_entry const* e = unfinished_ent->list_at(i);
612 if (e->type() != lazy_entry::dict_t) continue;
613 int piece = e->dict_find_int_value("piece", -1);
614 if (piece < 0 || piece > torrent_file().num_pieces()) continue;
616 if (m_picker->have_piece(piece))
617 m_picker->we_dont_have(piece);
619 std::string bitmask = e->dict_find_string_value("bitmask");
620 if (bitmask.empty()) continue;
622 const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1);
623 if ((int)bitmask.size() != num_bitmask_bytes) continue;
624 for (int j = 0; j < num_bitmask_bytes; ++j)
626 unsigned char bits = bitmask[j];
627 int num_bits = (std::min)(num_blocks_per_piece - j*8, 8);
628 for (int k = 0; k < num_bits; ++k)
630 const int bit = j * 8 + k;
631 if (bits & (1 << k))
633 m_picker->mark_as_finished(piece_block(piece, bit), 0);
634 if (m_picker->is_piece_finished(piece))
635 async_verify_piece(piece, bind(&torrent::piece_finished
636 , shared_from_this(), piece, _1));
644 files_checked();
646 else
648 // either the fastresume data was rejected or there are
649 // some files
650 m_ses.check_torrent(shared_from_this());
653 std::vector<char>().swap(m_resume_data);
654 lazy_entry().swap(m_resume_entry);
657 void torrent::force_recheck()
659 if (m_state == torrent_status::checking_files
660 || m_state == torrent_status::queued_for_checking)
661 return;
663 disconnect_all();
665 m_owning_storage->async_release_files();
666 m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
667 , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor
668 , m_storage_mode);
669 m_storage = m_owning_storage.get();
670 m_picker->init(m_torrent_file->piece_length() / m_block_size
671 , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
672 // assume that we don't have anything
673 m_files_checked = false;
674 set_state(torrent_status::queued_for_checking);
676 if (m_auto_managed)
677 set_queue_position((std::numeric_limits<int>::max)());
679 std::vector<char>().swap(m_resume_data);
680 lazy_entry().swap(m_resume_entry);
681 m_storage->async_check_fastresume(&m_resume_entry
682 , bind(&torrent::on_force_recheck
683 , shared_from_this(), _1, _2));
686 void torrent::on_force_recheck(int ret, disk_io_job const& j)
688 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
690 if (ret == piece_manager::fatal_disk_error)
692 if (m_ses.m_alerts.should_post<file_error_alert>())
694 m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
695 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
696 (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
697 " error: " << j.str <<
698 " torrent: " << torrent_file().name() <<
699 " ]\n";
700 #endif
702 m_error = j.str;
703 pause();
704 return;
706 m_ses.check_torrent(shared_from_this());
709 void torrent::start_checking()
711 set_state(torrent_status::checking_files);
713 m_storage->async_check_files(bind(
714 &torrent::on_piece_checked
715 , shared_from_this(), _1, _2));
718 void torrent::on_piece_checked(int ret, disk_io_job const& j)
720 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
722 if (ret == piece_manager::disk_check_aborted)
724 m_error = "aborted";
725 m_ses.done_checking(shared_from_this());
726 return;
728 if (ret == piece_manager::fatal_disk_error)
730 if (m_ses.m_alerts.should_post<file_error_alert>())
732 m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
733 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
734 (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
735 " error: " << j.str <<
736 " torrent: " << torrent_file().name() <<
737 " ]\n";
738 #endif
740 m_error = j.str;
741 pause();
742 m_ses.done_checking(shared_from_this());
743 return;
746 m_progress = j.piece / float(torrent_file().num_pieces());
748 TORRENT_ASSERT(m_picker);
749 if (j.offset >= 0 && !m_picker->have_piece(j.offset))
750 m_picker->we_have(j.offset);
752 // we're not done checking yet
753 // this handler will be called repeatedly until
754 // we're done, or encounter a failure
755 if (ret == piece_manager::need_full_check) return;
757 m_ses.done_checking(shared_from_this());
758 files_checked();
761 void torrent::use_interface(const char* net_interface)
763 INVARIANT_CHECK;
765 m_net_interface = tcp::endpoint(address::from_string(net_interface), 0);
768 void torrent::on_tracker_announce_disp(boost::weak_ptr<torrent> p
769 , error_code const& e)
771 if (e) return;
772 boost::shared_ptr<torrent> t = p.lock();
773 if (!t) return;
774 t->on_tracker_announce();
777 void torrent::on_tracker_announce()
779 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
781 if (m_abort) return;
782 announce_with_tracker();
785 void torrent::on_lsd_announce_disp(boost::weak_ptr<torrent> p
786 , error_code const& e)
788 if (e) return;
789 boost::shared_ptr<torrent> t = p.lock();
790 if (!t) return;
791 t->on_lsd_announce();
794 void torrent::on_lsd_announce()
796 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
798 if (m_abort) return;
800 TORRENT_ASSERT(!m_torrent_file->priv());
801 if (m_torrent_file->is_valid() && m_torrent_file->priv())
802 return;
804 if (is_paused()) return;
806 boost::weak_ptr<torrent> self(shared_from_this());
808 error_code ec;
810 // announce on local network every 5 minutes
811 m_lsd_announce_timer.expires_from_now(minutes(5), ec);
812 m_lsd_announce_timer.async_wait(
813 bind(&torrent::on_lsd_announce_disp, self, _1));
815 // announce with the local discovery service
816 m_ses.announce_lsd(m_torrent_file->info_hash());
818 #ifndef TORRENT_DISABLE_DHT
819 if (!m_ses.m_dht) return;
820 ptime now = time_now();
821 if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
823 m_last_dht_announce = now;
824 m_ses.m_dht->announce(m_torrent_file->info_hash()
825 , m_ses.m_listen_sockets.front().external_port
826 , bind(&torrent::on_dht_announce_response_disp, self, _1));
828 #endif
831 #ifndef TORRENT_DISABLE_DHT
833 void torrent::on_dht_announce_response_disp(boost::weak_ptr<libtorrent::torrent> t
834 , std::vector<tcp::endpoint> const& peers)
836 boost::shared_ptr<libtorrent::torrent> tor = t.lock();
837 if (!tor) return;
838 tor->on_dht_announce_response(peers);
841 void torrent::on_dht_announce_response(std::vector<tcp::endpoint> const& peers)
843 if (peers.empty()) return;
845 if (m_ses.m_alerts.should_post<dht_reply_alert>())
847 m_ses.m_alerts.post_alert(dht_reply_alert(
848 get_handle(), peers.size()));
850 std::for_each(peers.begin(), peers.end(), bind(
851 &policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0)
852 , peer_info::dht, 0));
855 #endif
857 void torrent::announce_with_tracker(tracker_request::event_t e)
859 INVARIANT_CHECK;
861 if (m_trackers.empty()) return;
863 restart_tracker_timer(time_now() + seconds(tracker_retry_delay_max));
865 if (m_abort) e = tracker_request::stopped;
867 if (e == tracker_request::none)
869 if (!m_start_sent) e = tracker_request::started;
870 if (!m_complete_sent && is_seed()) e = tracker_request::completed;
873 tracker_request req;
874 req.info_hash = m_torrent_file->info_hash();
875 req.pid = m_ses.get_peer_id();
876 req.downloaded = m_stat.total_payload_download();
877 req.uploaded = m_stat.total_payload_upload();
878 req.left = bytes_left();
879 if (req.left == -1) req.left = 16*1024;
880 req.event = e;
881 tcp::endpoint ep = m_ses.get_ipv6_interface();
882 if (ep != tcp::endpoint())
883 req.ipv6 = ep.address().to_string();
885 req.url = m_trackers[m_currently_trying_tracker].url;
886 // if we are aborting. we don't want any new peers
887 req.num_want = (req.event == tracker_request::stopped)
888 ?0:m_settings.num_want;
890 req.listen_port = m_ses.m_listen_sockets.empty()
891 ?0:m_ses.m_listen_sockets.front().external_port;
892 req.key = m_ses.m_key;
894 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
895 if (m_abort)
897 boost::shared_ptr<aux::tracker_logger> tl(new aux::tracker_logger(m_ses));
898 m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
899 , tracker_login(), m_ses.m_listen_interface.address(), tl);
901 else
902 #endif
903 m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
904 , tracker_login(), m_ses.m_listen_interface.address()
905 , m_abort?boost::shared_ptr<torrent>():shared_from_this());
907 if (m_ses.m_alerts.should_post<tracker_announce_alert>())
909 m_ses.m_alerts.post_alert(
910 tracker_announce_alert(get_handle(), req.url, req.event));
914 void torrent::scrape_tracker()
916 if (m_trackers.empty()) return;
918 TORRENT_ASSERT(m_currently_trying_tracker >= 0);
919 TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size()));
921 tracker_request req;
922 req.info_hash = m_torrent_file->info_hash();
923 req.kind = tracker_request::scrape_request;
924 req.url = m_trackers[m_currently_trying_tracker].url;
925 m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
926 , tracker_login(), m_ses.m_listen_interface.address(), shared_from_this());
928 m_last_scrape = time_now();
931 void torrent::tracker_warning(tracker_request const& req, std::string const& msg)
933 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
935 INVARIANT_CHECK;
937 if (m_ses.m_alerts.should_post<tracker_warning_alert>())
938 m_ses.m_alerts.post_alert(tracker_warning_alert(get_handle(), req.url, msg));
941 void torrent::tracker_scrape_response(tracker_request const& req
942 , int complete, int incomplete, int downloaded)
944 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
946 INVARIANT_CHECK;
947 TORRENT_ASSERT(req.kind == tracker_request::scrape_request);
949 if (complete >= 0) m_complete = complete;
950 if (incomplete >= 0) m_incomplete = incomplete;
952 if (m_ses.m_alerts.should_post<scrape_reply_alert>())
954 m_ses.m_alerts.post_alert(scrape_reply_alert(
955 get_handle(), m_incomplete, m_complete, req.url));
959 void torrent::tracker_response(
960 tracker_request const& r
961 , std::vector<peer_entry>& peer_list
962 , int interval
963 , int complete
964 , int incomplete
965 , address const& external_ip)
967 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
969 INVARIANT_CHECK;
970 TORRENT_ASSERT(r.kind == tracker_request::announce_request);
972 if (external_ip != address())
973 m_ses.set_external_address(external_ip);
975 if (!m_start_sent && r.event == tracker_request::started)
976 m_start_sent = true;
977 if (!m_complete_sent && r.event == tracker_request::completed)
978 m_complete_sent = true;
980 m_failed_trackers = 0;
982 if (interval < m_ses.settings().min_announce_interval)
983 interval = m_ses.settings().min_announce_interval;
985 m_last_working_tracker
986 = prioritize_tracker(m_currently_trying_tracker);
987 m_currently_trying_tracker = 0;
989 m_duration = interval;
990 restart_tracker_timer(time_now() + seconds(m_duration));
992 if (complete >= 0) m_complete = complete;
993 if (incomplete >= 0) m_incomplete = incomplete;
994 if (complete >= 0 && incomplete >= 0)
995 m_last_scrape = time_now();
997 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
998 std::stringstream s;
999 s << "TRACKER RESPONSE:\n"
1000 "interval: " << m_duration << "\n"
1001 "peers:\n";
1002 for (std::vector<peer_entry>::const_iterator i = peer_list.begin();
1003 i != peer_list.end(); ++i)
1005 s << " " << std::setfill(' ') << std::setw(16) << i->ip
1006 << " " << std::setw(5) << std::dec << i->port << " ";
1007 if (!i->pid.is_all_zeros()) s << " " << i->pid << " " << identify_client(i->pid);
1008 s << "\n";
1010 s << "external ip: " << external_ip << "\n";
1011 debug_log(s.str());
1012 #endif
1013 // for each of the peers we got from the tracker
1014 for (std::vector<peer_entry>::iterator i = peer_list.begin();
1015 i != peer_list.end(); ++i)
1017 // don't make connections to ourself
1018 if (i->pid == m_ses.get_peer_id())
1019 continue;
1021 error_code ec;
1022 tcp::endpoint a(address::from_string(i->ip, ec), i->port);
1024 if (ec)
1026 // assume this is because we got a hostname instead of
1027 // an ip address from the tracker
1029 tcp::resolver::query q(i->ip, boost::lexical_cast<std::string>(i->port));
1030 m_host_resolver.async_resolve(q,
1031 bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid));
1033 else
1035 m_policy.peer_from_tracker(a, i->pid, peer_info::tracker, 0);
1039 if (m_ses.m_alerts.should_post<tracker_reply_alert>())
1041 m_ses.m_alerts.post_alert(tracker_reply_alert(
1042 get_handle(), peer_list.size(), r.url));
1044 m_got_tracker_response = true;
1047 void torrent::on_peer_name_lookup(error_code const& e, tcp::resolver::iterator host
1048 , peer_id pid)
1050 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1052 INVARIANT_CHECK;
1054 if (e || host == tcp::resolver::iterator() ||
1055 m_ses.is_aborted()) return;
1057 if (m_ses.m_ip_filter.access(host->endpoint().address()) & ip_filter::blocked)
1059 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
1060 debug_log("blocked ip from tracker: " + host->endpoint().address().to_string());
1061 #endif
1062 if (m_ses.m_alerts.should_post<peer_blocked_alert>())
1064 m_ses.m_alerts.post_alert(peer_blocked_alert(host->endpoint().address()));
1067 return;
1070 m_policy.peer_from_tracker(*host, pid, peer_info::tracker, 0);
1073 size_type torrent::bytes_left() const
1075 // if we don't have the metadata yet, we
1076 // cannot tell how big the torrent is.
1077 if (!valid_metadata()) return -1;
1078 return m_torrent_file->total_size()
1079 - quantized_bytes_done();
1082 size_type torrent::quantized_bytes_done() const
1084 // INVARIANT_CHECK;
1086 if (!valid_metadata()) return 0;
1088 if (m_torrent_file->num_pieces() == 0)
1089 return 0;
1091 if (is_seed()) return m_torrent_file->total_size();
1093 const int last_piece = m_torrent_file->num_pieces() - 1;
1095 size_type total_done
1096 = size_type(num_have()) * m_torrent_file->piece_length();
1098 // if we have the last piece, we have to correct
1099 // the amount we have, since the first calculation
1100 // assumed all pieces were of equal size
1101 if (m_picker->have_piece(last_piece))
1103 int corr = m_torrent_file->piece_size(last_piece)
1104 - m_torrent_file->piece_length();
1105 total_done += corr;
1107 return total_done;
1110 // the first value is the total number of bytes downloaded
1111 // the second value is the number of bytes of those that haven't
1112 // been filtered as not wanted we have downloaded
1113 tuple<size_type, size_type> torrent::bytes_done() const
1115 INVARIANT_CHECK;
1117 if (!valid_metadata() || m_torrent_file->num_pieces() == 0)
1118 return tuple<size_type, size_type>(0,0);
1120 const int last_piece = m_torrent_file->num_pieces() - 1;
1121 const int piece_size = m_torrent_file->piece_length();
1123 if (is_seed())
1124 return make_tuple(m_torrent_file->total_size()
1125 , m_torrent_file->total_size());
1127 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1128 size_type wanted_done = size_type(num_have() - m_picker->num_have_filtered())
1129 * piece_size;
1130 TORRENT_ASSERT(wanted_done >= 0);
1132 size_type total_done
1133 = size_type(num_have()) * piece_size;
1134 TORRENT_ASSERT(num_have() < m_torrent_file->num_pieces());
1136 // if we have the last piece, we have to correct
1137 // the amount we have, since the first calculation
1138 // assumed all pieces were of equal size
1139 if (m_picker->have_piece(last_piece))
1141 TORRENT_ASSERT(total_done >= piece_size);
1142 int corr = m_torrent_file->piece_size(last_piece)
1143 - piece_size;
1144 TORRENT_ASSERT(corr <= 0);
1145 TORRENT_ASSERT(corr > -piece_size);
1146 total_done += corr;
1147 if (m_picker->piece_priority(last_piece) != 0)
1149 TORRENT_ASSERT(wanted_done >= piece_size);
1150 wanted_done += corr;
1154 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1155 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1156 TORRENT_ASSERT(total_done >= wanted_done);
1158 const std::vector<piece_picker::downloading_piece>& dl_queue
1159 = m_picker->get_download_queue();
1161 const int blocks_per_piece = piece_size / m_block_size;
1163 for (std::vector<piece_picker::downloading_piece>::const_iterator i =
1164 dl_queue.begin(); i != dl_queue.end(); ++i)
1166 int corr = 0;
1167 int index = i->index;
1168 if (m_picker->have_piece(index)) continue;
1169 TORRENT_ASSERT(i->finished <= m_picker->blocks_in_piece(index));
1171 #ifndef NDEBUG
1172 for (std::vector<piece_picker::downloading_piece>::const_iterator j = boost::next(i);
1173 j != dl_queue.end(); ++j)
1175 TORRENT_ASSERT(j->index != index);
1177 #endif
1179 for (int j = 0; j < blocks_per_piece; ++j)
1181 TORRENT_ASSERT(m_picker->is_finished(piece_block(index, j)) == (i->info[j].state == piece_picker::block_info::state_finished));
1182 corr += (i->info[j].state == piece_picker::block_info::state_finished) * m_block_size;
1183 TORRENT_ASSERT(corr >= 0);
1184 TORRENT_ASSERT(index != last_piece || j < m_picker->blocks_in_last_piece()
1185 || i->info[j].state != piece_picker::block_info::state_finished);
1188 // correction if this was the last piece
1189 // and if we have the last block
1190 if (i->index == last_piece
1191 && i->info[m_picker->blocks_in_last_piece()-1].state
1192 == piece_picker::block_info::state_finished)
1194 corr -= m_block_size;
1195 corr += m_torrent_file->piece_size(last_piece) % m_block_size;
1197 total_done += corr;
1198 if (m_picker->piece_priority(index) != 0)
1199 wanted_done += corr;
1202 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1203 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1205 std::map<piece_block, int> downloading_piece;
1206 for (const_peer_iterator i = begin(); i != end(); ++i)
1208 peer_connection* pc = *i;
1209 boost::optional<piece_block_progress> p
1210 = pc->downloading_piece_progress();
1211 if (p)
1213 if (m_picker->have_piece(p->piece_index))
1214 continue;
1216 piece_block block(p->piece_index, p->block_index);
1217 if (m_picker->is_finished(block))
1218 continue;
1220 std::map<piece_block, int>::iterator dp
1221 = downloading_piece.find(block);
1222 if (dp != downloading_piece.end())
1224 if (dp->second < p->bytes_downloaded)
1225 dp->second = p->bytes_downloaded;
1227 else
1229 downloading_piece[block] = p->bytes_downloaded;
1231 #ifndef NDEBUG
1232 TORRENT_ASSERT(p->bytes_downloaded <= p->full_block_bytes);
1233 int last_piece = m_torrent_file->num_pieces() - 1;
1234 if (p->piece_index == last_piece
1235 && p->block_index == m_torrent_file->piece_size(last_piece) / block_size())
1236 TORRENT_ASSERT(p->full_block_bytes == m_torrent_file->piece_size(last_piece) % block_size());
1237 else
1238 TORRENT_ASSERT(p->full_block_bytes == block_size());
1239 #endif
1242 for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
1243 i != downloading_piece.end(); ++i)
1245 total_done += i->second;
1246 if (m_picker->piece_priority(i->first.piece_index) != 0)
1247 wanted_done += i->second;
1250 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1251 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1253 #ifndef NDEBUG
1255 if (total_done >= m_torrent_file->total_size())
1257 // Thist happens when a piece has been downloaded completely
1258 // but not yet verified against the hash
1259 std::cerr << "num_have: " << num_have() << std::endl;
1261 std::cerr << "unfinished:" << std::endl;
1263 for (std::vector<piece_picker::downloading_piece>::const_iterator i =
1264 dl_queue.begin(); i != dl_queue.end(); ++i)
1266 std::cerr << " " << i->index << " ";
1267 for (int j = 0; j < blocks_per_piece; ++j)
1269 std::cerr << (i->info[j].state == piece_picker::block_info::state_finished ? "1" : "0");
1271 std::cerr << std::endl;
1274 std::cerr << "downloading pieces:" << std::endl;
1276 for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
1277 i != downloading_piece.end(); ++i)
1279 std::cerr << " " << i->first.piece_index << ":" << i->first.block_index
1280 << " " << i->second << std::endl;
1285 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1286 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1288 #endif
1290 TORRENT_ASSERT(total_done >= wanted_done);
1291 return make_tuple(total_done, wanted_done);
1294 // passed_hash_check
1295 // 0: success, piece passed check
1296 // -1: disk failure
1297 // -2: piece failed check
1298 void torrent::piece_finished(int index, int passed_hash_check)
1300 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1302 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
1303 (*m_ses.m_logger) << time_now_string() << " *** PIECE_FINISHED [ p: "
1304 << index << " chk: " << ((passed_hash_check == 0)
1305 ?"passed":passed_hash_check == -1
1306 ?"disk failed":"failed") << " ]\n";
1307 #endif
1309 TORRENT_ASSERT(valid_metadata());
1311 if (passed_hash_check == 0)
1313 // the following call may cause picker to become invalid
1314 // in case we just became a seed
1315 piece_passed(index);
1317 else if (passed_hash_check == -2)
1319 // piece_failed() will restore the piece
1320 piece_failed(index);
1322 else
1324 TORRENT_ASSERT(passed_hash_check == -1);
1325 m_picker->restore_piece(index);
1326 restore_piece_state(index);
1330 void torrent::piece_passed(int index)
1332 // INVARIANT_CHECK;
1334 TORRENT_ASSERT(index >= 0);
1335 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1337 if (m_ses.m_alerts.should_post<piece_finished_alert>())
1339 m_ses.m_alerts.post_alert(piece_finished_alert(get_handle()
1340 , index));
1343 bool was_finished = m_picker->num_filtered() + num_have()
1344 == torrent_file().num_pieces();
1346 std::vector<void*> downloaders;
1347 m_picker->get_downloaders(downloaders, index);
1349 // increase the trust point of all peers that sent
1350 // parts of this piece.
1351 std::set<void*> peers;
1352 std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
1354 m_picker->we_have(index);
1355 for (peer_iterator i = m_connections.begin(); i != m_connections.end();)
1357 peer_connection* p = *i;
1358 ++i;
1359 p->announce_piece(index);
1362 for (std::set<void*>::iterator i = peers.begin()
1363 , end(peers.end()); i != end; ++i)
1365 policy::peer* p = static_cast<policy::peer*>(*i);
1366 if (p == 0) continue;
1367 p->on_parole = false;
1368 ++p->trust_points;
1369 // TODO: make this limit user settable
1370 if (p->trust_points > 20) p->trust_points = 20;
1371 if (p->connection) p->connection->received_valid_data(index);
1374 #ifndef TORRENT_DISABLE_EXTENSIONS
1375 for (extension_list_t::iterator i = m_extensions.begin()
1376 , end(m_extensions.end()); i != end; ++i)
1378 #ifndef BOOST_NO_EXCEPTIONS
1379 try {
1380 #endif
1381 (*i)->on_piece_pass(index);
1382 #ifndef BOOST_NO_EXCEPTIONS
1383 } catch (std::exception&) {}
1384 #endif
1386 #endif
1388 // since this piece just passed, we might have
1389 // become uninterested in some peers where this
1390 // was the last piece we were interested in
1391 for (peer_iterator i = m_connections.begin()
1392 , end(m_connections.end()); i != end; ++i)
1394 peer_connection* p = *i;
1395 // if we're not interested already, no need to check
1396 if (!p->is_interesting()) continue;
1397 // if the peer doesn't have the piece we just got, it
1398 // wouldn't affect our interest
1399 if (!p->has_piece(index)) continue;
1400 p->update_interest();
1403 if (!was_finished && is_finished())
1405 // torrent finished
1406 // i.e. all the pieces we're interested in have
1407 // been downloaded. Release the files (they will open
1408 // in read only mode if needed)
1409 finished();
1410 // if we just became a seed, picker is now invalid, since it
1411 // is deallocated by the torrent once it starts seeding
1415 void torrent::piece_failed(int index)
1417 // if the last piece fails the peer connection will still
1418 // think that it has received all of it until this function
1419 // resets the download queue. So, we cannot do the
1420 // invariant check here since it assumes:
1421 // (total_done == m_torrent_file->total_size()) => is_seed()
1422 INVARIANT_CHECK;
1424 TORRENT_ASSERT(m_storage);
1425 TORRENT_ASSERT(m_storage->refcount() > 0);
1426 TORRENT_ASSERT(m_picker.get());
1427 TORRENT_ASSERT(index >= 0);
1428 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1430 if (m_ses.m_alerts.should_post<hash_failed_alert>())
1431 m_ses.m_alerts.post_alert(hash_failed_alert(get_handle(), index));
1433 // increase the total amount of failed bytes
1434 add_failed_bytes(m_torrent_file->piece_size(index));
1436 std::vector<void*> downloaders;
1437 m_picker->get_downloaders(downloaders, index);
1439 // decrease the trust point of all peers that sent
1440 // parts of this piece.
1441 // first, build a set of all peers that participated
1442 std::set<void*> peers;
1443 std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
1445 #ifndef NDEBUG
1446 for (std::vector<void*>::iterator i = downloaders.begin()
1447 , end(downloaders.end()); i != end; ++i)
1449 policy::peer* p = (policy::peer*)*i;
1450 if (p && p->connection)
1452 p->connection->piece_failed = true;
1455 #endif
1457 #ifndef TORRENT_DISABLE_EXTENSIONS
1458 for (extension_list_t::iterator i = m_extensions.begin()
1459 , end(m_extensions.end()); i != end; ++i)
1461 #ifndef BOOST_NO_EXCEPTIONS
1462 try {
1463 #endif
1464 (*i)->on_piece_failed(index);
1465 #ifndef BOOST_NO_EXCEPTIONS
1466 } catch (std::exception&) {}
1467 #endif
1469 #endif
1471 for (std::set<void*>::iterator i = peers.begin()
1472 , end(peers.end()); i != end; ++i)
1474 policy::peer* p = static_cast<policy::peer*>(*i);
1475 if (p == 0) continue;
1476 if (p->connection) p->connection->received_invalid_data(index);
1478 // either, we have received too many failed hashes
1479 // or this was the only peer that sent us this piece.
1480 // TODO: make this a changable setting
1481 if (p->trust_points <= -7
1482 || peers.size() == 1)
1484 // we don't trust this peer anymore
1485 // ban it.
1486 if (m_ses.m_alerts.should_post<peer_ban_alert>())
1488 peer_id pid(0);
1489 if (p->connection) pid = p->connection->pid();
1490 m_ses.m_alerts.post_alert(peer_ban_alert(
1491 get_handle(), p->ip(), pid));
1494 // mark the peer as banned
1495 p->banned = true;
1497 if (p->connection)
1499 #ifdef TORRENT_LOGGING
1500 (*m_ses.m_logger) << time_now_string() << " *** BANNING PEER [ " << p->ip()
1501 << " ] 'too many corrupt pieces'\n";
1502 #endif
1503 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
1504 (*p->connection->m_logger) << "*** BANNING PEER [ " << p->ip()
1505 << " ] 'too many corrupt pieces'\n";
1506 #endif
1507 p->connection->disconnect("too many corrupt pieces, banning peer");
1512 // we have to let the piece_picker know that
1513 // this piece failed the check as it can restore it
1514 // and mark it as being interesting for download
1515 // TODO: do this more intelligently! and keep track
1516 // of how much crap (data that failed hash-check) and
1517 // how much redundant data we have downloaded
1518 // if some clients has sent more than one piece
1519 // start with redownloading the pieces that the client
1520 // that has sent the least number of pieces
1521 m_picker->restore_piece(index);
1522 restore_piece_state(index);
1523 TORRENT_ASSERT(m_storage);
1525 TORRENT_ASSERT(m_picker->have_piece(index) == false);
1527 #ifndef NDEBUG
1528 for (std::vector<void*>::iterator i = downloaders.begin()
1529 , end(downloaders.end()); i != end; ++i)
1531 policy::peer* p = (policy::peer*)*i;
1532 if (p && p->connection)
1534 p->connection->piece_failed = false;
1537 #endif
1540 void torrent::restore_piece_state(int index)
1542 TORRENT_ASSERT(has_picker());
1543 for (peer_iterator i = m_connections.begin();
1544 i != m_connections.end(); ++i)
1546 peer_connection* p = *i;
1547 std::deque<pending_block> const& dq = p->download_queue();
1548 std::deque<piece_block> const& rq = p->request_queue();
1549 for (std::deque<pending_block>::const_iterator k = dq.begin()
1550 , end(dq.end()); k != end; ++k)
1552 if (k->block.piece_index != index) continue;
1553 m_picker->mark_as_downloading(k->block, p->peer_info_struct()
1554 , (piece_picker::piece_state_t)p->peer_speed());
1556 for (std::deque<piece_block>::const_iterator k = rq.begin()
1557 , end(rq.end()); k != end; ++k)
1559 if (k->piece_index != index) continue;
1560 m_picker->mark_as_downloading(*k, p->peer_info_struct()
1561 , (piece_picker::piece_state_t)p->peer_speed());
1566 void torrent::abort()
1568 INVARIANT_CHECK;
1570 m_abort = true;
1571 // if the torrent is paused, it doesn't need
1572 // to announce with even=stopped again.
1573 if (!is_paused())
1575 stop_announcing();
1578 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
1579 for (peer_iterator i = m_connections.begin();
1580 i != m_connections.end(); ++i)
1582 (*(*i)->m_logger) << "*** ABORTING TORRENT\n";
1584 #endif
1586 // disconnect all peers and close all
1587 // files belonging to the torrents
1588 disconnect_all();
1589 if (m_owning_storage.get())
1590 m_storage->async_release_files(
1591 bind(&torrent::on_files_released, shared_from_this(), _1, _2));
1593 m_owning_storage = 0;
1594 m_host_resolver.cancel();
1597 void torrent::on_files_deleted(int ret, disk_io_job const& j)
1599 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1601 if (ret != 0)
1603 if (alerts().should_post<torrent_delete_failed_alert>())
1604 alerts().post_alert(torrent_delete_failed_alert(get_handle(), j.str));
1606 else
1608 if (alerts().should_post<torrent_deleted_alert>())
1609 alerts().post_alert(torrent_deleted_alert(get_handle()));
1613 void torrent::on_files_released(int ret, disk_io_job const& j)
1616 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1618 if (alerts().should_post<torrent_paused_alert>())
1620 alerts().post_alert(torrent_paused_alert(get_handle()));
1625 void torrent::on_save_resume_data(int ret, disk_io_job const& j)
1627 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1629 if (!j.resume_data && alerts().should_post<save_resume_data_failed_alert>())
1631 alerts().post_alert(save_resume_data_failed_alert(get_handle(), j.str));
1632 return;
1635 if (j.resume_data && alerts().should_post<save_resume_data_alert>())
1637 write_resume_data(*j.resume_data);
1638 alerts().post_alert(save_resume_data_alert(j.resume_data
1639 , get_handle()));
1643 void torrent::on_file_renamed(int ret, disk_io_job const& j)
1645 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1648 if (ret == 0)
1650 if (alerts().should_post<file_renamed_alert>())
1651 alerts().post_alert(file_renamed_alert(get_handle(), j.str, j.piece));
1653 else
1655 if (alerts().should_post<file_rename_failed_alert>())
1656 alerts().post_alert(file_rename_failed_alert(get_handle(), j.str, j.piece));
1661 void torrent::on_torrent_paused(int ret, disk_io_job const& j)
1663 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1665 if (alerts().should_post<torrent_paused_alert>())
1666 alerts().post_alert(torrent_paused_alert(get_handle()));
1669 std::string torrent::tracker_login() const
1671 if (m_username.empty() && m_password.empty()) return "";
1672 return m_username + ":" + m_password;
1675 void torrent::piece_availability(std::vector<int>& avail) const
1677 INVARIANT_CHECK;
1679 TORRENT_ASSERT(valid_metadata());
1680 if (is_seed())
1682 avail.clear();
1683 return;
1686 m_picker->get_availability(avail);
1689 void torrent::set_piece_priority(int index, int priority)
1691 // INVARIANT_CHECK;
1693 TORRENT_ASSERT(valid_metadata());
1694 if (is_seed()) return;
1696 // this call is only valid on torrents with metadata
1697 TORRENT_ASSERT(m_picker.get());
1698 TORRENT_ASSERT(index >= 0);
1699 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1701 bool was_finished = is_finished();
1702 bool filter_updated = m_picker->set_piece_priority(index, priority);
1703 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1704 if (filter_updated) update_peer_interest(was_finished);
1707 int torrent::piece_priority(int index) const
1709 // INVARIANT_CHECK;
1711 TORRENT_ASSERT(valid_metadata());
1712 if (is_seed()) return 1;
1714 // this call is only valid on torrents with metadata
1715 TORRENT_ASSERT(m_picker.get());
1716 TORRENT_ASSERT(index >= 0);
1717 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1719 return m_picker->piece_priority(index);
1722 void torrent::prioritize_pieces(std::vector<int> const& pieces)
1724 INVARIANT_CHECK;
1726 // this call is only valid on torrents with metadata
1727 TORRENT_ASSERT(valid_metadata());
1728 if (is_seed()) return;
1730 TORRENT_ASSERT(m_picker.get());
1732 int index = 0;
1733 bool filter_updated = false;
1734 bool was_finished = is_finished();
1735 for (std::vector<int>::const_iterator i = pieces.begin()
1736 , end(pieces.end()); i != end; ++i, ++index)
1738 TORRENT_ASSERT(*i >= 0);
1739 TORRENT_ASSERT(*i <= 7);
1740 filter_updated |= m_picker->set_piece_priority(index, *i);
1741 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1743 if (filter_updated) update_peer_interest(was_finished);
1746 void torrent::piece_priorities(std::vector<int>& pieces) const
1748 INVARIANT_CHECK;
1750 // this call is only valid on torrents with metadata
1751 TORRENT_ASSERT(valid_metadata());
1752 if (is_seed())
1754 pieces.clear();
1755 pieces.resize(m_torrent_file->num_pieces(), 1);
1756 return;
1759 TORRENT_ASSERT(m_picker.get());
1760 m_picker->piece_priorities(pieces);
1763 namespace
1765 void set_if_greater(int& piece_prio, int file_prio)
1767 if (file_prio > piece_prio) piece_prio = file_prio;
1771 void torrent::prioritize_files(std::vector<int> const& files)
1773 INVARIANT_CHECK;
1775 // this call is only valid on torrents with metadata
1776 if (!valid_metadata() || is_seed()) return;
1778 // the bitmask need to have exactly one bit for every file
1779 // in the torrent
1780 TORRENT_ASSERT(int(files.size()) == m_torrent_file->num_files());
1782 if (m_torrent_file->num_pieces() == 0) return;
1784 std::copy(files.begin(), files.end(), m_file_priority.begin());
1785 update_piece_priorities();
1788 void torrent::set_file_priority(int index, int prio)
1790 INVARIANT_CHECK;
1791 TORRENT_ASSERT(index < m_torrent_file->num_files());
1792 TORRENT_ASSERT(index >= 0);
1793 if (m_file_priority[index] == prio) return;
1794 m_file_priority[index] = prio;
1795 update_piece_priorities();
1798 int torrent::file_priority(int index) const
1800 TORRENT_ASSERT(index < m_torrent_file->num_files());
1801 TORRENT_ASSERT(index >= 0);
1802 return m_file_priority[index];
1805 void torrent::file_priorities(std::vector<int>& files) const
1807 INVARIANT_CHECK;
1808 files.resize(m_file_priority.size());
1809 std::copy(m_file_priority.begin(), m_file_priority.end(), files.begin());
1812 void torrent::update_piece_priorities()
1814 INVARIANT_CHECK;
1816 if (m_torrent_file->num_pieces() == 0) return;
1818 size_type position = 0;
1819 int piece_length = m_torrent_file->piece_length();
1820 // initialize the piece priorities to 0, then only allow
1821 // setting higher priorities
1822 std::vector<int> pieces(m_torrent_file->num_pieces(), 0);
1823 for (int i = 0; i < int(m_file_priority.size()); ++i)
1825 size_type start = position;
1826 size_type size = m_torrent_file->files().at(i).size;
1827 if (size == 0) continue;
1828 position += size;
1829 // mark all pieces of the file with this file's priority
1830 // but only if the priority is higher than the pieces
1831 // already set (to avoid problems with overlapping pieces)
1832 int start_piece = int(start / piece_length);
1833 int last_piece = int((position - 1) / piece_length);
1834 TORRENT_ASSERT(last_piece < int(pieces.size()));
1835 // if one piece spans several files, we might
1836 // come here several times with the same start_piece, end_piece
1837 std::for_each(pieces.begin() + start_piece
1838 , pieces.begin() + last_piece + 1
1839 , bind(&set_if_greater, _1, m_file_priority[i]));
1841 prioritize_pieces(pieces);
1844 // this is called when piece priorities have been updated
1845 // updates the interested flag in peers
1846 void torrent::update_peer_interest(bool was_finished)
1848 for (peer_iterator i = begin(); i != end(); ++i)
1849 (*i)->update_interest();
1851 // the torrent just became finished
1852 if (is_finished() && !was_finished)
1854 finished();
1856 else if (!is_finished() && was_finished)
1858 // if we used to be finished, but we aren't anymore
1859 // we may need to connect to peers again
1860 resume_download();
1861 m_policy.recalculate_connect_candidates();
1865 void torrent::filter_piece(int index, bool filter)
1867 INVARIANT_CHECK;
1869 TORRENT_ASSERT(valid_metadata());
1870 if (is_seed()) return;
1872 // this call is only valid on torrents with metadata
1873 TORRENT_ASSERT(m_picker.get());
1874 TORRENT_ASSERT(index >= 0);
1875 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1877 bool was_finished = is_finished();
1878 m_picker->set_piece_priority(index, filter ? 1 : 0);
1879 update_peer_interest(was_finished);
1882 void torrent::filter_pieces(std::vector<bool> const& bitmask)
1884 INVARIANT_CHECK;
1886 // this call is only valid on torrents with metadata
1887 TORRENT_ASSERT(valid_metadata());
1888 if (is_seed()) return;
1890 TORRENT_ASSERT(m_picker.get());
1892 bool was_finished = is_finished();
1893 int index = 0;
1894 for (std::vector<bool>::const_iterator i = bitmask.begin()
1895 , end(bitmask.end()); i != end; ++i, ++index)
1897 if ((m_picker->piece_priority(index) == 0) == *i) continue;
1898 if (*i)
1899 m_picker->set_piece_priority(index, 0);
1900 else
1901 m_picker->set_piece_priority(index, 1);
1903 update_peer_interest(was_finished);
1906 bool torrent::is_piece_filtered(int index) const
1908 // this call is only valid on torrents with metadata
1909 TORRENT_ASSERT(valid_metadata());
1910 if (is_seed()) return false;
1912 TORRENT_ASSERT(m_picker.get());
1913 TORRENT_ASSERT(index >= 0);
1914 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1916 return m_picker->piece_priority(index) == 0;
1919 void torrent::filtered_pieces(std::vector<bool>& bitmask) const
1921 INVARIANT_CHECK;
1923 // this call is only valid on torrents with metadata
1924 TORRENT_ASSERT(valid_metadata());
1925 if (is_seed())
1927 bitmask.clear();
1928 bitmask.resize(m_torrent_file->num_pieces(), false);
1929 return;
1932 TORRENT_ASSERT(m_picker.get());
1933 m_picker->filtered_pieces(bitmask);
1936 void torrent::filter_files(std::vector<bool> const& bitmask)
1938 INVARIANT_CHECK;
1940 // this call is only valid on torrents with metadata
1941 if (!valid_metadata() || is_seed()) return;
1943 // the bitmask need to have exactly one bit for every file
1944 // in the torrent
1945 TORRENT_ASSERT((int)bitmask.size() == m_torrent_file->num_files());
1947 size_type position = 0;
1949 if (m_torrent_file->num_pieces())
1951 int piece_length = m_torrent_file->piece_length();
1952 // mark all pieces as filtered, then clear the bits for files
1953 // that should be downloaded
1954 std::vector<bool> piece_filter(m_torrent_file->num_pieces(), true);
1955 for (int i = 0; i < (int)bitmask.size(); ++i)
1957 size_type start = position;
1958 position += m_torrent_file->files().at(i).size;
1959 // is the file selected for download?
1960 if (!bitmask[i])
1962 // mark all pieces of the file as downloadable
1963 int start_piece = int(start / piece_length);
1964 int last_piece = int(position / piece_length);
1965 // if one piece spans several files, we might
1966 // come here several times with the same start_piece, end_piece
1967 std::fill(piece_filter.begin() + start_piece, piece_filter.begin()
1968 + last_piece + 1, false);
1971 filter_pieces(piece_filter);
1975 void torrent::replace_trackers(std::vector<announce_entry> const& urls)
1977 m_trackers = urls;
1978 if (m_currently_trying_tracker >= (int)m_trackers.size())
1979 m_currently_trying_tracker = (int)m_trackers.size()-1;
1980 m_last_working_tracker = -1;
1983 void torrent::choke_peer(peer_connection& c)
1985 INVARIANT_CHECK;
1987 TORRENT_ASSERT(!c.is_choked());
1988 TORRENT_ASSERT(m_num_uploads > 0);
1989 c.send_choke();
1990 --m_num_uploads;
1993 bool torrent::unchoke_peer(peer_connection& c)
1995 INVARIANT_CHECK;
1997 TORRENT_ASSERT(c.is_choked());
1998 if (m_num_uploads >= m_max_uploads) return false;
1999 c.send_unchoke();
2000 ++m_num_uploads;
2001 return true;
2004 void torrent::cancel_block(piece_block block)
2006 INVARIANT_CHECK;
2008 for (peer_iterator i = m_connections.begin()
2009 , end(m_connections.end()); i != end; ++i)
2011 (*i)->cancel_request(block);
2015 void torrent::remove_peer(peer_connection* p)
2017 // INVARIANT_CHECK;
2019 TORRENT_ASSERT(p != 0);
2021 peer_iterator i = m_connections.find(p);
2022 if (i == m_connections.end())
2024 TORRENT_ASSERT(false);
2025 return;
2028 if (ready_for_connections())
2030 TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
2032 if (p->is_seed())
2034 if (m_picker.get())
2036 m_picker->dec_refcount_all();
2039 else
2041 if (m_picker.get())
2043 bitfield const& pieces = p->get_bitfield();
2044 TORRENT_ASSERT(pieces.count() < int(pieces.size()));
2045 m_picker->dec_refcount(pieces);
2050 if (!p->is_choked())
2051 --m_num_uploads;
2053 m_policy.connection_closed(*p);
2054 p->set_peer_info(0);
2055 TORRENT_ASSERT(i != m_connections.end());
2056 m_connections.erase(i);
2058 // remove from bandwidth request-queue
2059 for (int c = 0; c < 2; ++c)
2061 for (queue_t::iterator i = m_bandwidth_queue[c].begin()
2062 , end(m_bandwidth_queue[c].end()); i != end; ++i)
2064 if (i->peer != p) continue;
2065 m_bandwidth_queue[c].erase(i);
2066 break;
2071 void torrent::connect_to_url_seed(std::string const& url)
2073 INVARIANT_CHECK;
2075 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2076 (*m_ses.m_logger) << time_now_string() << " resolving web seed: " << url << "\n";
2077 #endif
2079 std::string protocol;
2080 std::string auth;
2081 std::string hostname;
2082 int port;
2083 std::string path;
2084 char const* error;
2085 boost::tie(protocol, auth, hostname, port, path, error)
2086 = parse_url_components(url);
2088 if (error)
2090 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2091 (*m_ses.m_logger) << time_now_string() << " failed to parse web seed url: " << error << "\n";
2092 #endif
2093 // never try it again
2094 remove_url_seed(url);
2095 return;
2098 #ifdef TORRENT_USE_OPENSSL
2099 if (protocol != "http" && protocol != "https")
2100 #else
2101 if (protocol != "http")
2102 #endif
2104 if (m_ses.m_alerts.should_post<url_seed_alert>())
2106 m_ses.m_alerts.post_alert(
2107 url_seed_alert(get_handle(), url, "unknown protocol"));
2109 // never try it again
2110 remove_url_seed(url);
2111 return;
2114 if (hostname.empty())
2116 if (m_ses.m_alerts.should_post<url_seed_alert>())
2118 m_ses.m_alerts.post_alert(
2119 url_seed_alert(get_handle(), url, "invalid hostname"));
2121 // never try it again
2122 remove_url_seed(url);
2123 return;
2126 if (port == 0)
2128 if (m_ses.m_alerts.should_post<url_seed_alert>())
2130 m_ses.m_alerts.post_alert(
2131 url_seed_alert(get_handle(), url, "invalid port"));
2133 // never try it again
2134 remove_url_seed(url);
2135 return;
2138 m_resolving_web_seeds.insert(url);
2139 proxy_settings const& ps = m_ses.web_seed_proxy();
2140 if (ps.type == proxy_settings::http
2141 || ps.type == proxy_settings::http_pw)
2143 // use proxy
2144 tcp::resolver::query q(ps.hostname
2145 , boost::lexical_cast<std::string>(ps.port));
2146 m_host_resolver.async_resolve(q,
2147 bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, url));
2149 else
2151 if (m_ses.m_port_filter.access(port) & port_filter::blocked)
2153 if (m_ses.m_alerts.should_post<url_seed_alert>())
2155 m_ses.m_alerts.post_alert(
2156 url_seed_alert(get_handle(), url, "port blocked by port-filter"));
2158 // never try it again
2159 remove_url_seed(url);
2160 return;
2163 tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
2164 m_host_resolver.async_resolve(q,
2165 bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url
2166 , tcp::endpoint()));
2171 void torrent::on_proxy_name_lookup(error_code const& e, tcp::resolver::iterator host
2172 , std::string url)
2174 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2176 INVARIANT_CHECK;
2178 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2179 (*m_ses.m_logger) << time_now_string() << " completed resolve proxy hostname for: " << url << "\n";
2180 #endif
2182 if (e || host == tcp::resolver::iterator())
2184 if (m_ses.m_alerts.should_post<url_seed_alert>())
2186 m_ses.m_alerts.post_alert(
2187 url_seed_alert(get_handle(), url, e.message()));
2190 // the name lookup failed for the http host. Don't try
2191 // this host again
2192 remove_url_seed(url);
2193 return;
2196 if (m_ses.is_aborted()) return;
2198 tcp::endpoint a(host->endpoint());
2200 using boost::tuples::ignore;
2201 std::string hostname;
2202 int port;
2203 char const* error;
2204 boost::tie(ignore, ignore, hostname, port, ignore, error)
2205 = parse_url_components(url);
2207 if (error)
2209 if (m_ses.m_alerts.should_post<url_seed_alert>())
2211 m_ses.m_alerts.post_alert(
2212 url_seed_alert(get_handle(), url, error));
2214 remove_url_seed(url);
2215 return;
2218 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
2220 if (m_ses.m_alerts.should_post<peer_blocked_alert>())
2221 m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()));
2222 return;
2225 tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
2226 m_host_resolver.async_resolve(q,
2227 bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url, a));
2230 void torrent::on_name_lookup(error_code const& e, tcp::resolver::iterator host
2231 , std::string url, tcp::endpoint proxy)
2233 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2235 INVARIANT_CHECK;
2237 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2238 (*m_ses.m_logger) << time_now_string() << " completed resolve: " << url << "\n";
2239 #endif
2241 std::set<std::string>::iterator i = m_resolving_web_seeds.find(url);
2242 if (i != m_resolving_web_seeds.end()) m_resolving_web_seeds.erase(i);
2244 if (e || host == tcp::resolver::iterator())
2246 if (m_ses.m_alerts.should_post<url_seed_alert>())
2248 std::stringstream msg;
2249 msg << "HTTP seed hostname lookup failed: " << e.message();
2250 m_ses.m_alerts.post_alert(
2251 url_seed_alert(get_handle(), url, msg.str()));
2253 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2254 (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << url << "\n";
2255 #endif
2257 // the name lookup failed for the http host. Don't try
2258 // this host again
2259 remove_url_seed(url);
2260 return;
2263 if (m_ses.is_aborted()) return;
2265 tcp::endpoint a(host->endpoint());
2267 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
2269 if (m_ses.m_alerts.should_post<peer_blocked_alert>())
2270 m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()));
2271 return;
2274 boost::shared_ptr<socket_type> s(new (std::nothrow) socket_type(m_ses.m_io_service));
2275 if (!s) return;
2277 bool ret = instantiate_connection(m_ses.m_io_service, m_ses.web_seed_proxy(), *s);
2278 (void)ret;
2279 TORRENT_ASSERT(ret);
2281 if (m_ses.web_seed_proxy().type == proxy_settings::http
2282 || m_ses.web_seed_proxy().type == proxy_settings::http_pw)
2284 // the web seed connection will talk immediately to
2285 // the proxy, without requiring CONNECT support
2286 s->get<http_stream>().set_no_connect(true);
2289 std::pair<int, int> const& out_ports = m_settings.outgoing_ports;
2290 error_code ec;
2291 if (out_ports.first > 0 && out_ports.second >= out_ports.first)
2292 s->bind(tcp::endpoint(address(), m_ses.next_port()), ec);
2294 boost::intrusive_ptr<peer_connection> c(new (std::nothrow) web_peer_connection(
2295 m_ses, shared_from_this(), s, a, url, 0));
2296 if (!c) return;
2298 #ifndef NDEBUG
2299 c->m_in_constructor = false;
2300 #endif
2302 #ifndef TORRENT_DISABLE_EXTENSIONS
2303 for (extension_list_t::iterator i = m_extensions.begin()
2304 , end(m_extensions.end()); i != end; ++i)
2306 boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
2307 if (pp) c->add_extension(pp);
2309 #endif
2311 // add the newly connected peer to this torrent's peer list
2312 m_connections.insert(boost::get_pointer(c));
2313 m_ses.m_connections.insert(c);
2315 #ifndef BOOST_NO_EXCEPTIONS
2318 #endif
2319 // add the newly connected peer to this torrent's peer list
2320 m_connections.insert(boost::get_pointer(c));
2321 m_ses.m_connections.insert(c);
2322 c->start();
2324 m_ses.m_half_open.enqueue(
2325 bind(&peer_connection::connect, c, _1)
2326 , bind(&peer_connection::timed_out, c)
2327 , seconds(settings().peer_connect_timeout));
2328 #ifndef BOOST_NO_EXCEPTIONS
2330 catch (std::exception& e)
2332 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2333 (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n";
2334 #endif
2335 c->disconnect(e.what(), 1);
2337 #endif
2340 #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
2341 namespace
2343 unsigned long swap_bytes(unsigned long a)
2345 return (a >> 24) | ((a & 0xff0000) >> 8) | ((a & 0xff00) << 8) | (a << 24);
2349 void torrent::resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const
2351 if (m_resolving_country
2352 || p->has_country()
2353 || p->is_connecting()
2354 || p->is_queued()
2355 || p->in_handshake()
2356 || p->remote().address().is_v6()) return;
2358 m_resolving_country = true;
2359 asio::ip::address_v4 reversed(swap_bytes(p->remote().address().to_v4().to_ulong()));
2360 tcp::resolver::query q(reversed.to_string() + ".zz.countries.nerd.dk", "0");
2361 m_host_resolver.async_resolve(q,
2362 bind(&torrent::on_country_lookup, shared_from_this(), _1, _2, p));
2365 namespace
2367 struct country_entry
2369 int code;
2370 char const* name;
2374 void torrent::on_country_lookup(error_code const& error, tcp::resolver::iterator i
2375 , intrusive_ptr<peer_connection> p) const
2377 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2379 INVARIANT_CHECK;
2381 m_resolving_country = false;
2383 // must be ordered in increasing order
2384 static const country_entry country_map[] =
2386 { 4, "AF"}, { 8, "AL"}, { 10, "AQ"}, { 12, "DZ"}, { 16, "AS"}
2387 , { 20, "AD"}, { 24, "AO"}, { 28, "AG"}, { 31, "AZ"}, { 32, "AR"}
2388 , { 36, "AU"}, { 40, "AT"}, { 44, "BS"}, { 48, "BH"}, { 50, "BD"}
2389 , { 51, "AM"}, { 52, "BB"}, { 56, "BE"}, { 60, "BM"}, { 64, "BT"}
2390 , { 68, "BO"}, { 70, "BA"}, { 72, "BW"}, { 74, "BV"}, { 76, "BR"}
2391 , { 84, "BZ"}, { 86, "IO"}, { 90, "SB"}, { 92, "VG"}, { 96, "BN"}
2392 , {100, "BG"}, {104, "MM"}, {108, "BI"}, {112, "BY"}, {116, "KH"}
2393 , {120, "CM"}, {124, "CA"}, {132, "CV"}, {136, "KY"}, {140, "CF"}
2394 , {144, "LK"}, {148, "TD"}, {152, "CL"}, {156, "CN"}, {158, "TW"}
2395 , {162, "CX"}, {166, "CC"}, {170, "CO"}, {174, "KM"}, {175, "YT"}
2396 , {178, "CG"}, {180, "CD"}, {184, "CK"}, {188, "CR"}, {191, "HR"}
2397 , {192, "CU"}, {203, "CZ"}, {204, "BJ"}, {208, "DK"}, {212, "DM"}
2398 , {214, "DO"}, {218, "EC"}, {222, "SV"}, {226, "GQ"}, {231, "ET"}
2399 , {232, "ER"}, {233, "EE"}, {234, "FO"}, {238, "FK"}, {239, "GS"}
2400 , {242, "FJ"}, {246, "FI"}, {248, "AX"}, {250, "FR"}, {254, "GF"}
2401 , {258, "PF"}, {260, "TF"}, {262, "DJ"}, {266, "GA"}, {268, "GE"}
2402 , {270, "GM"}, {275, "PS"}, {276, "DE"}, {288, "GH"}, {292, "GI"}
2403 , {296, "KI"}, {300, "GR"}, {304, "GL"}, {308, "GD"}, {312, "GP"}
2404 , {316, "GU"}, {320, "GT"}, {324, "GN"}, {328, "GY"}, {332, "HT"}
2405 , {334, "HM"}, {336, "VA"}, {340, "HN"}, {344, "HK"}, {348, "HU"}
2406 , {352, "IS"}, {356, "IN"}, {360, "ID"}, {364, "IR"}, {368, "IQ"}
2407 , {372, "IE"}, {376, "IL"}, {380, "IT"}, {384, "CI"}, {388, "JM"}
2408 , {392, "JP"}, {398, "KZ"}, {400, "JO"}, {404, "KE"}, {408, "KP"}
2409 , {410, "KR"}, {414, "KW"}, {417, "KG"}, {418, "LA"}, {422, "LB"}
2410 , {426, "LS"}, {428, "LV"}, {430, "LR"}, {434, "LY"}, {438, "LI"}
2411 , {440, "LT"}, {442, "LU"}, {446, "MO"}, {450, "MG"}, {454, "MW"}
2412 , {458, "MY"}, {462, "MV"}, {466, "ML"}, {470, "MT"}, {474, "MQ"}
2413 , {478, "MR"}, {480, "MU"}, {484, "MX"}, {492, "MC"}, {496, "MN"}
2414 , {498, "MD"}, {500, "MS"}, {504, "MA"}, {508, "MZ"}, {512, "OM"}
2415 , {516, "NA"}, {520, "NR"}, {524, "NP"}, {528, "NL"}, {530, "AN"}
2416 , {533, "AW"}, {540, "NC"}, {548, "VU"}, {554, "NZ"}, {558, "NI"}
2417 , {562, "NE"}, {566, "NG"}, {570, "NU"}, {574, "NF"}, {578, "NO"}
2418 , {580, "MP"}, {581, "UM"}, {583, "FM"}, {584, "MH"}, {585, "PW"}
2419 , {586, "PK"}, {591, "PA"}, {598, "PG"}, {600, "PY"}, {604, "PE"}
2420 , {608, "PH"}, {612, "PN"}, {616, "PL"}, {620, "PT"}, {624, "GW"}
2421 , {626, "TL"}, {630, "PR"}, {634, "QA"}, {634, "QA"}, {638, "RE"}
2422 , {642, "RO"}, {643, "RU"}, {646, "RW"}, {654, "SH"}, {659, "KN"}
2423 , {660, "AI"}, {662, "LC"}, {666, "PM"}, {670, "VC"}, {674, "SM"}
2424 , {678, "ST"}, {682, "SA"}, {686, "SN"}, {690, "SC"}, {694, "SL"}
2425 , {702, "SG"}, {703, "SK"}, {704, "VN"}, {705, "SI"}, {706, "SO"}
2426 , {710, "ZA"}, {716, "ZW"}, {724, "ES"}, {732, "EH"}, {736, "SD"}
2427 , {740, "SR"}, {744, "SJ"}, {748, "SZ"}, {752, "SE"}, {756, "CH"}
2428 , {760, "SY"}, {762, "TJ"}, {764, "TH"}, {768, "TG"}, {772, "TK"}
2429 , {776, "TO"}, {780, "TT"}, {784, "AE"}, {788, "TN"}, {792, "TR"}
2430 , {795, "TM"}, {796, "TC"}, {798, "TV"}, {800, "UG"}, {804, "UA"}
2431 , {807, "MK"}, {818, "EG"}, {826, "GB"}, {834, "TZ"}, {840, "US"}
2432 , {850, "VI"}, {854, "BF"}, {858, "UY"}, {860, "UZ"}, {862, "VE"}
2433 , {876, "WF"}, {882, "WS"}, {887, "YE"}, {891, "CS"}, {894, "ZM"}
2436 if (error || i == tcp::resolver::iterator())
2438 // this is used to indicate that we shouldn't
2439 // try to resolve it again
2440 p->set_country("--");
2441 return;
2444 while (i != tcp::resolver::iterator()
2445 && !i->endpoint().address().is_v4()) ++i;
2446 if (i != tcp::resolver::iterator())
2448 // country is an ISO 3166 country code
2449 int country = i->endpoint().address().to_v4().to_ulong() & 0xffff;
2451 // look up the country code in the map
2452 const int size = sizeof(country_map)/sizeof(country_map[0]);
2453 country_entry tmp = {country, ""};
2454 country_entry const* i =
2455 std::lower_bound(country_map, country_map + size, tmp
2456 , bind(&country_entry::code, _1) < bind(&country_entry::code, _2));
2457 if (i == country_map + size
2458 || i->code != country)
2460 // unknown country!
2461 p->set_country("!!");
2462 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2463 (*m_ses.m_logger) << "IP " << p->remote().address() << " was mapped to unknown country: " << country << "\n";
2464 #endif
2465 return;
2468 p->set_country(i->name);
2471 #endif
2473 void torrent::read_resume_data(lazy_entry const& rd)
2475 m_total_uploaded = rd.dict_find_int_value("total_uploaded");
2476 m_total_downloaded = rd.dict_find_int_value("total_downloaded");
2477 m_active_time = seconds(rd.dict_find_int_value("active_time"));
2478 m_seeding_time = seconds(rd.dict_find_int_value("seeding_time"));
2479 m_complete = rd.dict_find_int_value("num_seeds", -1);
2480 m_incomplete = rd.dict_find_int_value("num_downloaders", -1);
2481 set_upload_limit(rd.dict_find_int_value("upload_rate_limit", -1));
2482 set_download_limit(rd.dict_find_int_value("download_rate_limit", -1));
2483 set_max_connections(rd.dict_find_int_value("max_connections", -1));
2484 set_max_uploads(rd.dict_find_int_value("max_uploads", -1));
2486 lazy_entry const* file_priority = rd.dict_find_list("file_priority");
2487 if (file_priority && file_priority->list_size()
2488 == m_torrent_file->num_files())
2490 for (int i = 0; i < file_priority->list_size(); ++i)
2491 m_file_priority[i] = file_priority->list_int_value_at(i, 1);
2492 update_piece_priorities();
2494 lazy_entry const* piece_priority = rd.dict_find_string("piece_priority");
2495 if (piece_priority && piece_priority->string_length()
2496 == m_torrent_file->num_pieces())
2498 char const* p = piece_priority->string_ptr();
2499 for (int i = 0; i < piece_priority->string_length(); ++i)
2500 m_picker->set_piece_priority(i, p[i]);
2503 if (rd.dict_find_int_value("auto_managed")) auto_managed(true);
2504 if (rd.dict_find_int_value("paused")) pause();
2507 void torrent::write_resume_data(entry& ret) const
2509 ret["file-format"] = "libtorrent resume file";
2510 ret["file-version"] = 1;
2512 ret["total_uploaded"] = m_total_uploaded;
2513 ret["total_downloaded"] = m_total_downloaded;
2515 ret["active_time"] = total_seconds(m_active_time);
2516 ret["seeding_time"] = total_seconds(m_seeding_time);
2518 int seeds = 0;
2519 int downloaders = 0;
2520 if (m_complete >= 0) seeds = m_complete;
2521 else seeds = m_policy.num_seeds();
2522 if (m_incomplete >= 0) downloaders = m_incomplete;
2523 else downloaders = m_policy.num_peers() - m_policy.num_seeds();
2525 ret["num_seeds"] = seeds;
2526 ret["num_downloaders"] = downloaders;
2528 const sha1_hash& info_hash = torrent_file().info_hash();
2529 ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
2531 // blocks per piece
2532 int num_blocks_per_piece =
2533 static_cast<int>(torrent_file().piece_length()) / block_size();
2534 ret["blocks per piece"] = num_blocks_per_piece;
2536 // if this torrent is a seed, we won't have a piece picker
2537 // and there will be no half-finished pieces.
2538 if (!is_seed())
2540 const std::vector<piece_picker::downloading_piece>& q
2541 = m_picker->get_download_queue();
2543 // unfinished pieces
2544 ret["unfinished"] = entry::list_type();
2545 entry::list_type& up = ret["unfinished"].list();
2547 // info for each unfinished piece
2548 for (std::vector<piece_picker::downloading_piece>::const_iterator i
2549 = q.begin(); i != q.end(); ++i)
2551 if (i->finished == 0) continue;
2553 entry piece_struct(entry::dictionary_t);
2555 // the unfinished piece's index
2556 piece_struct["piece"] = i->index;
2558 std::string bitmask;
2559 const int num_bitmask_bytes
2560 = (std::max)(num_blocks_per_piece / 8, 1);
2562 for (int j = 0; j < num_bitmask_bytes; ++j)
2564 unsigned char v = 0;
2565 int bits = (std::min)(num_blocks_per_piece - j*8, 8);
2566 for (int k = 0; k < bits; ++k)
2567 v |= (i->info[j*8+k].state == piece_picker::block_info::state_finished)
2568 ? (1 << k) : 0;
2569 bitmask.insert(bitmask.end(), v);
2570 TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1);
2572 piece_struct["bitmask"] = bitmask;
2573 // push the struct onto the unfinished-piece list
2574 up.push_back(piece_struct);
2578 // write have bitmask
2579 entry::string_type& pieces = ret["pieces"].string();
2580 pieces.resize(m_torrent_file->num_pieces());
2581 if (is_seed())
2583 std::memset(&pieces[0], 1, pieces.size());
2585 else
2587 for (int i = 0, end(pieces.size()); i < end; ++i)
2588 pieces[i] = m_picker->have_piece(i) ? 1 : 0;
2591 // write local peers
2593 entry::list_type& peer_list = ret["peers"].list();
2594 entry::list_type& banned_peer_list = ret["banned_peers"].list();
2596 int max_failcount = m_ses.m_settings.max_failcount;
2598 for (policy::const_iterator i = m_policy.begin_peer()
2599 , end(m_policy.end_peer()); i != end; ++i)
2601 error_code ec;
2602 if (i->second.banned)
2604 entry peer(entry::dictionary_t);
2605 peer["ip"] = i->second.addr.to_string(ec);
2606 if (ec) continue;
2607 peer["port"] = i->second.port;
2608 banned_peer_list.push_back(peer);
2609 continue;
2611 // we cannot save remote connection
2612 // since we don't know their listen port
2613 // unless they gave us their listen port
2614 // through the extension handshake
2615 // so, if the peer is not connectable (i.e. we
2616 // don't know its listen port) or if it has
2617 // been banned, don't save it.
2618 if (i->second.type == policy::peer::not_connectable) continue;
2620 // don't save peers that doesn't work
2621 if (i->second.failcount >= max_failcount) continue;
2623 entry peer(entry::dictionary_t);
2624 peer["ip"] = i->second.addr.to_string(ec);
2625 if (ec) continue;
2626 peer["port"] = i->second.port;
2627 peer_list.push_back(peer);
2630 ret["upload_rate_limit"] = upload_limit();
2631 ret["download_rate_limit"] = download_limit();
2632 ret["max_connections"] = max_connections();
2633 ret["max_uploads"] = max_uploads();
2634 ret["paused"] = m_paused;
2635 ret["auto_managed"] = m_auto_managed;
2637 // write piece priorities
2638 entry::string_type& piece_priority = ret["piece_priority"].string();
2639 piece_priority.resize(m_torrent_file->num_pieces());
2640 if (is_seed())
2642 std::memset(&piece_priority[0], 1, pieces.size());
2644 else
2646 for (int i = 0, end(piece_priority.size()); i < end; ++i)
2647 piece_priority[i] = m_picker->piece_priority(i);
2650 // write file priorities
2651 entry::list_type& file_priority = ret["file_priority"].list();
2652 file_priority.clear();
2653 for (int i = 0, end(m_file_priority.size()); i < end; ++i)
2654 file_priority.push_back(m_file_priority[i]);
2658 void torrent::get_full_peer_list(std::vector<peer_list_entry>& v) const
2660 v.clear();
2661 v.reserve(m_policy.num_peers());
2662 for (policy::const_iterator i = m_policy.begin_peer();
2663 i != m_policy.end_peer(); ++i)
2665 peer_list_entry e;
2666 e.ip = i->second.ip();
2667 e.flags = i->second.banned ? peer_list_entry::banned : 0;
2668 e.failcount = i->second.failcount;
2669 e.source = i->second.source;
2670 v.push_back(e);
2674 void torrent::get_peer_info(std::vector<peer_info>& v)
2676 v.clear();
2677 for (peer_iterator i = begin();
2678 i != end(); ++i)
2680 peer_connection* peer = *i;
2682 // incoming peers that haven't finished the handshake should
2683 // not be included in this list
2684 if (peer->associated_torrent().expired()) continue;
2686 v.push_back(peer_info());
2687 peer_info& p = v.back();
2689 peer->get_peer_info(p);
2690 #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
2691 if (resolving_countries())
2692 resolve_peer_country(intrusive_ptr<peer_connection>(peer));
2693 #endif
2697 void torrent::get_download_queue(std::vector<partial_piece_info>& queue)
2699 queue.clear();
2700 if (!valid_metadata() || is_seed()) return;
2701 piece_picker const& p = picker();
2702 std::vector<piece_picker::downloading_piece> const& q
2703 = p.get_download_queue();
2705 for (std::vector<piece_picker::downloading_piece>::const_iterator i
2706 = q.begin(); i != q.end(); ++i)
2708 partial_piece_info pi;
2709 pi.piece_state = (partial_piece_info::state_t)i->state;
2710 pi.blocks_in_piece = p.blocks_in_piece(i->index);
2711 pi.finished = (int)i->finished;
2712 pi.writing = (int)i->writing;
2713 pi.requested = (int)i->requested;
2714 int piece_size = int(torrent_file().piece_size(i->index));
2715 for (int j = 0; j < pi.blocks_in_piece; ++j)
2717 block_info& bi = pi.blocks[j];
2718 bi.state = i->info[j].state;
2719 bi.block_size = j < pi.blocks_in_piece - 1 ? m_block_size
2720 : piece_size - (j * m_block_size);
2721 bool complete = bi.state == block_info::writing
2722 || bi.state == block_info::finished;
2723 if (i->info[j].peer == 0)
2725 bi.peer = tcp::endpoint();
2726 bi.bytes_progress = complete ? bi.block_size : 0;
2728 else
2730 policy::peer* p = static_cast<policy::peer*>(i->info[j].peer);
2731 if (p->connection)
2733 bi.peer = p->connection->remote();
2734 if (bi.state == block_info::requested)
2736 boost::optional<piece_block_progress> pbp
2737 = p->connection->downloading_piece_progress();
2738 if (pbp && pbp->piece_index == i->index && pbp->block_index == j)
2740 bi.bytes_progress = pbp->bytes_downloaded;
2741 TORRENT_ASSERT(bi.bytes_progress <= bi.block_size);
2743 else
2745 bi.bytes_progress = 0;
2748 else
2750 bi.bytes_progress = complete ? bi.block_size : 0;
2753 else
2755 bi.peer = p->ip();
2756 bi.bytes_progress = complete ? bi.block_size : 0;
2760 pi.blocks[j].num_peers = i->info[j].num_peers;
2762 pi.piece_index = i->index;
2763 queue.push_back(pi);
2768 bool torrent::connect_to_peer(policy::peer* peerinfo)
2770 INVARIANT_CHECK;
2772 TORRENT_ASSERT(peerinfo);
2773 TORRENT_ASSERT(peerinfo->connection == 0);
2775 peerinfo->connected = time_now();
2776 #ifndef NDEBUG
2777 // this asserts that we don't have duplicates in the policy's peer list
2778 peer_iterator i_ = std::find_if(m_connections.begin(), m_connections.end()
2779 , bind(&peer_connection::remote, _1) == peerinfo->ip());
2780 TORRENT_ASSERT(i_ == m_connections.end()
2781 || dynamic_cast<bt_peer_connection*>(*i_) == 0);
2782 #endif
2784 TORRENT_ASSERT(want_more_peers());
2785 TORRENT_ASSERT(m_ses.num_connections() < m_ses.max_connections());
2787 tcp::endpoint a(peerinfo->ip());
2788 TORRENT_ASSERT((m_ses.m_ip_filter.access(peerinfo->addr) & ip_filter::blocked) == 0);
2790 boost::shared_ptr<socket_type> s(new socket_type(m_ses.m_io_service));
2792 bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s);
2793 (void)ret;
2794 TORRENT_ASSERT(ret);
2795 std::pair<int, int> const& out_ports = m_ses.settings().outgoing_ports;
2796 error_code ec;
2797 if (out_ports.first > 0 && out_ports.second >= out_ports.first)
2798 s->bind(tcp::endpoint(address(), m_ses.next_port()), ec);
2800 boost::intrusive_ptr<peer_connection> c(new bt_peer_connection(
2801 m_ses, shared_from_this(), s, a, peerinfo));
2803 #ifndef NDEBUG
2804 c->m_in_constructor = false;
2805 #endif
2807 c->add_stat(peerinfo->prev_amount_download, peerinfo->prev_amount_upload);
2808 peerinfo->prev_amount_download = 0;
2809 peerinfo->prev_amount_upload = 0;
2811 #ifndef TORRENT_DISABLE_EXTENSIONS
2812 for (extension_list_t::iterator i = m_extensions.begin()
2813 , end(m_extensions.end()); i != end; ++i)
2815 #ifndef BOOST_NO_EXCEPTIONS
2816 try {
2817 #endif
2818 boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
2819 if (pp) c->add_extension(pp);
2820 #ifndef BOOST_NO_EXCEPTIONS
2821 } catch (std::exception&) {}
2822 #endif
2824 #endif
2826 // add the newly connected peer to this torrent's peer list
2827 m_connections.insert(boost::get_pointer(c));
2828 m_ses.m_connections.insert(c);
2829 peerinfo->connection = c.get();
2830 c->start();
2832 int timeout = settings().peer_connect_timeout;
2833 if (peerinfo) timeout += 3 * peerinfo->failcount;
2835 #ifndef BOOST_NO_EXCEPTIONS
2838 #endif
2839 m_ses.m_half_open.enqueue(
2840 bind(&peer_connection::connect, c, _1)
2841 , bind(&peer_connection::timed_out, c)
2842 , seconds(timeout));
2843 #ifndef BOOST_NO_EXCEPTIONS
2845 catch (std::exception& e)
2847 std::set<peer_connection*>::iterator i
2848 = m_connections.find(boost::get_pointer(c));
2849 if (i != m_connections.end()) m_connections.erase(i);
2850 c->disconnect(e.what());
2851 return false;
2853 #endif
2854 return true;
2857 bool torrent::set_metadata(lazy_entry const& metadata, std::string& error)
2859 INVARIANT_CHECK;
2861 TORRENT_ASSERT(!m_torrent_file->is_valid());
2862 if (!m_torrent_file->parse_info_section(metadata, error))
2864 // parse failed
2865 return false;
2868 if (m_ses.m_alerts.should_post<metadata_received_alert>())
2870 m_ses.m_alerts.post_alert(metadata_received_alert(
2871 get_handle()));
2874 init();
2876 return true;
2879 bool torrent::attach_peer(peer_connection* p)
2881 // INVARIANT_CHECK;
2883 TORRENT_ASSERT(p != 0);
2884 TORRENT_ASSERT(!p->is_local());
2886 m_has_incoming = true;
2888 if ((m_state == torrent_status::queued_for_checking
2889 || m_state == torrent_status::checking_files)
2890 && valid_metadata())
2892 p->disconnect("torrent is not ready to accept peers");
2893 return false;
2896 if (m_ses.m_connections.find(p) == m_ses.m_connections.end())
2898 p->disconnect("peer is not properly constructed");
2899 return false;
2902 if (m_ses.is_aborted())
2904 p->disconnect("session is closing");
2905 return false;
2908 if (int(m_connections.size()) >= m_max_connections)
2910 p->disconnect("reached connection limit");
2911 return false;
2914 #ifndef BOOST_NO_EXCEPTIONS
2917 #endif
2918 #ifndef TORRENT_DISABLE_EXTENSIONS
2919 for (extension_list_t::iterator i = m_extensions.begin()
2920 , end(m_extensions.end()); i != end; ++i)
2922 boost::shared_ptr<peer_plugin> pp((*i)->new_connection(p));
2923 if (pp) p->add_extension(pp);
2925 #endif
2926 if (!m_policy.new_connection(*p))
2927 return false;
2928 #ifndef BOOST_NO_EXCEPTIONS
2930 catch (std::exception& e)
2932 #if defined TORRENT_LOGGING
2933 (*m_ses.m_logger) << time_now_string() << " CLOSING CONNECTION "
2934 << p->remote() << " policy::new_connection threw: " << e.what() << "\n";
2935 #endif
2936 p->disconnect(e.what());
2937 return false;
2939 #endif
2940 TORRENT_ASSERT(m_connections.find(p) == m_connections.end());
2941 peer_iterator ci = m_connections.insert(p).first;
2942 #ifndef NDEBUG
2943 error_code ec;
2944 TORRENT_ASSERT(p->remote() == p->get_socket()->remote_endpoint(ec) || ec);
2945 #endif
2947 #if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
2948 m_policy.check_invariant();
2949 #endif
2950 return true;
2953 bool torrent::want_more_peers() const
2955 return int(m_connections.size()) < m_max_connections
2956 && !is_paused()
2957 && m_state != torrent_status::checking_files
2958 && (m_state != torrent_status::queued_for_checking
2959 || !valid_metadata())
2960 && m_policy.num_connect_candidates() > 0;
2963 void torrent::disconnect_all()
2965 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2967 INVARIANT_CHECK;
2969 while (!m_connections.empty())
2971 peer_connection* p = *m_connections.begin();
2972 TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
2974 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
2975 if (m_abort)
2976 (*p->m_logger) << "*** CLOSING CONNECTION 'aborting'\n";
2977 else
2978 (*p->m_logger) << "*** CLOSING CONNECTION 'pausing'\n";
2979 #endif
2980 #ifndef NDEBUG
2981 std::size_t size = m_connections.size();
2982 #endif
2983 if (p->is_disconnecting())
2984 m_connections.erase(m_connections.begin());
2985 else
2986 p->disconnect(m_abort?"stopping torrent":"pausing torrent");
2987 TORRENT_ASSERT(m_connections.size() <= size);
2991 namespace
2993 // this returns true if lhs is a better disconnect candidate than rhs
2994 bool compare_disconnect_peer(peer_connection const* lhs, peer_connection const* rhs)
2996 // prefer to disconnect peers we're not interested in
2997 if (lhs->is_interesting() != rhs->is_interesting())
2998 return rhs->is_interesting();
3000 // prefer to disconnect peers that are not seeds
3001 if (lhs->is_seed() != rhs->is_seed())
3002 return rhs->is_seed();
3004 // prefer to disconnect peers that are on parole
3005 if (lhs->on_parole() != rhs->on_parole())
3006 return lhs->on_parole();
3008 // prefer to disconnect peers that send data at a lower rate
3009 size_type lhs_transferred = lhs->statistics().total_payload_download();
3010 size_type rhs_transferred = rhs->statistics().total_payload_download();
3012 if (lhs_transferred != rhs_transferred
3013 && lhs_transferred > 0
3014 && rhs_transferred > 0)
3016 ptime now = time_now();
3017 size_type lhs_time_connected = total_seconds(now - lhs->connected_time());
3018 size_type rhs_time_connected = total_seconds(now - rhs->connected_time());
3020 double lhs_rate = double(lhs_transferred) / (lhs_time_connected + 1);
3021 double rhs_rate = double(rhs_transferred) / (rhs_time_connected + 1);
3023 return lhs_rate < rhs_rate;
3026 // prefer to disconnect peers that chokes us
3027 if (lhs->is_choked() != rhs->is_choked())
3028 return lhs->is_choked();
3030 return lhs->last_received() < rhs->last_received();
3034 int torrent::disconnect_peers(int num)
3036 int ret = 0;
3037 // buils a list of all connected peers and sort it by 'disconnectability'.
3038 std::vector<peer_connection*> peers(m_connections.size());
3039 std::copy(m_connections.begin(), m_connections.end(), peers.begin());
3040 std::sort(peers.begin(), peers.end(), boost::bind(&compare_disconnect_peer, _1, _2));
3042 // never disconnect peers that connected less than 90 seconds ago
3043 ptime cut_off = time_now() - seconds(90);
3045 for (std::vector<peer_connection*>::iterator i = peers.begin()
3046 , end(peers.end()); i != end && ret < num; ++i)
3048 peer_connection* p = *i;
3049 if (p->connected_time() > cut_off) continue;
3050 ++ret;
3051 p->disconnect("optimistic disconnect");
3053 return ret;
3056 int torrent::bandwidth_throttle(int channel) const
3058 return m_bandwidth_limit[channel].throttle();
3061 int torrent::bandwidth_queue_size(int channel) const
3063 return (int)m_bandwidth_queue[channel].size();
3066 void torrent::request_bandwidth(int channel
3067 , boost::intrusive_ptr<peer_connection> const& p
3068 , int max_block_size, int priority)
3070 TORRENT_ASSERT(max_block_size > 0);
3071 TORRENT_ASSERT(m_bandwidth_limit[channel].throttle() > 0);
3072 TORRENT_ASSERT(p->max_assignable_bandwidth(channel) > 0);
3073 TORRENT_ASSERT(p->m_channel_state[channel] == peer_info::bw_torrent);
3074 int block_size = (std::min)(m_bandwidth_limit[channel].throttle() / 10
3075 , max_block_size);
3076 if (block_size <= 0) block_size = 1;
3078 if (m_bandwidth_limit[channel].max_assignable() > 0)
3080 perform_bandwidth_request(channel, p, block_size, priority);
3082 else
3084 // skip forward in the queue until we find a prioritized peer
3085 // or hit the front of it.
3086 queue_t::reverse_iterator i = m_bandwidth_queue[channel].rbegin();
3087 while (i != m_bandwidth_queue[channel].rend() && priority > i->priority)
3089 ++i->priority;
3090 ++i;
3092 m_bandwidth_queue[channel].insert(i.base(), bw_queue_entry<peer_connection, torrent>(
3093 p, block_size, priority));
3097 void torrent::expire_bandwidth(int channel, int amount)
3099 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3101 INVARIANT_CHECK;
3103 TORRENT_ASSERT(amount > 0);
3104 m_bandwidth_limit[channel].expire(amount);
3105 queue_t tmp;
3106 while (!m_bandwidth_queue[channel].empty())
3108 bw_queue_entry<peer_connection, torrent> qe = m_bandwidth_queue[channel].front();
3109 if (m_bandwidth_limit[channel].max_assignable() == 0)
3110 break;
3111 m_bandwidth_queue[channel].pop_front();
3112 if (qe.peer->max_assignable_bandwidth(channel) <= 0)
3114 TORRENT_ASSERT(m_ses.m_bandwidth_manager[channel]->is_in_history(qe.peer.get()));
3115 if (!qe.peer->is_disconnecting()) tmp.push_back(qe);
3116 continue;
3118 perform_bandwidth_request(channel, qe.peer
3119 , qe.max_block_size, qe.priority);
3121 m_bandwidth_queue[channel].insert(m_bandwidth_queue[channel].begin(), tmp.begin(), tmp.end());
3124 void torrent::perform_bandwidth_request(int channel
3125 , boost::intrusive_ptr<peer_connection> const& p
3126 , int block_size
3127 , int priority)
3129 TORRENT_ASSERT(p->m_channel_state[channel] == peer_info::bw_torrent);
3130 p->m_channel_state[channel] = peer_info::bw_global;
3131 m_ses.m_bandwidth_manager[channel]->request_bandwidth(p
3132 , block_size, priority);
3133 m_bandwidth_limit[channel].assign(block_size);
3136 void torrent::assign_bandwidth(int channel, int amount, int blk)
3138 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3140 TORRENT_ASSERT(amount > 0);
3141 TORRENT_ASSERT(amount <= blk);
3142 if (amount < blk)
3143 expire_bandwidth(channel, blk - amount);
3146 // called when torrent is finished (all interesting
3147 // pieces have been downloaded)
3148 void torrent::finished()
3150 INVARIANT_CHECK;
3152 if (alerts().should_post<torrent_finished_alert>())
3154 alerts().post_alert(torrent_finished_alert(
3155 get_handle()));
3158 set_state(torrent_status::finished);
3159 set_queue_position(-1);
3161 // we have to call completed() before we start
3162 // disconnecting peers, since there's an assert
3163 // to make sure we're cleared the piece picker
3164 if (is_seed()) completed();
3166 // disconnect all seeds
3167 // TODO: should disconnect all peers that have the pieces we have
3168 // not just seeds
3169 std::vector<peer_connection*> seeds;
3170 for (peer_iterator i = m_connections.begin();
3171 i != m_connections.end(); ++i)
3173 peer_connection* p = *i;
3174 TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
3175 if (p->upload_only())
3177 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
3178 (*p->m_logger) << "*** SEED, CLOSING CONNECTION\n";
3179 #endif
3180 seeds.push_back(p);
3183 std::for_each(seeds.begin(), seeds.end()
3184 , bind(&peer_connection::disconnect, _1, "torrent finished, disconnecting seed", 0));
3186 TORRENT_ASSERT(m_storage);
3187 // we need to keep the object alive during this operation
3188 m_storage->async_release_files(
3189 bind(&torrent::on_files_released, shared_from_this(), _1, _2));
3192 // this is called when we were finished, but some files were
3193 // marked for downloading, and we are no longer finished
3194 void torrent::resume_download()
3196 INVARIANT_CHECK;
3198 TORRENT_ASSERT(!is_finished());
3199 set_state(torrent_status::downloading);
3200 set_queue_position((std::numeric_limits<int>::max)());
3203 // called when torrent is complete (all pieces downloaded)
3204 void torrent::completed()
3206 m_picker.reset();
3208 set_state(torrent_status::seeding);
3209 if (!m_complete_sent && m_announcing) announce_with_tracker();
3212 // this will move the tracker with the given index
3213 // to a prioritized position in the list (move it towards
3214 // the begining) and return the new index to the tracker.
3215 int torrent::prioritize_tracker(int index)
3217 INVARIANT_CHECK;
3219 TORRENT_ASSERT(index >= 0);
3220 if (index >= (int)m_trackers.size()) return (int)m_trackers.size()-1;
3222 while (index > 0 && m_trackers[index].tier == m_trackers[index-1].tier)
3224 std::swap(m_trackers[index].url, m_trackers[index-1].url);
3225 --index;
3227 return index;
3230 void torrent::try_next_tracker(tracker_request const& req)
3232 INVARIANT_CHECK;
3234 ++m_currently_trying_tracker;
3236 if ((unsigned)m_currently_trying_tracker < m_trackers.size())
3238 announce_with_tracker(req.event);
3239 return;
3242 int delay = tracker_retry_delay_min
3243 + (std::min)(int(m_failed_trackers), int(tracker_failed_max))
3244 * (tracker_retry_delay_max - tracker_retry_delay_min)
3245 / tracker_failed_max;
3247 ++m_failed_trackers;
3248 // if we've looped the tracker list, wait a bit before retrying
3249 m_currently_trying_tracker = 0;
3251 // if we're stopping, just give up. Don't bother retrying
3252 if (req.event == tracker_request::stopped)
3253 return;
3255 restart_tracker_timer(time_now() + seconds(delay));
3257 #ifndef TORRENT_DISABLE_DHT
3258 if (m_abort) return;
3260 // only start the announce if we want to announce with the dht
3261 ptime now = time_now();
3262 if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
3264 // force the DHT to reannounce
3265 m_last_dht_announce = now;
3266 boost::weak_ptr<torrent> self(shared_from_this());
3267 m_ses.m_dht->announce(m_torrent_file->info_hash()
3268 , m_ses.m_listen_sockets.front().external_port
3269 , bind(&torrent::on_dht_announce_response_disp, self, _1));
3271 #endif
3275 void torrent::files_checked()
3277 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3279 TORRENT_ASSERT(m_torrent_file->is_valid());
3280 INVARIANT_CHECK;
3282 set_state(torrent_status::downloading);
3284 if (m_ses.m_alerts.should_post<torrent_checked_alert>())
3286 m_ses.m_alerts.post_alert(torrent_checked_alert(
3287 get_handle()));
3290 if (!is_seed())
3292 if (m_sequential_download)
3293 picker().sequential_download(m_sequential_download);
3295 // if we just finished checking and we're not a seed, we are
3296 // likely to be unpaused
3297 if (m_ses.m_auto_manage_time_scaler > 1)
3298 m_ses.m_auto_manage_time_scaler = 1;
3300 if (is_finished()) finished();
3302 else
3304 m_complete_sent = true;
3305 finished();
3308 #ifndef TORRENT_DISABLE_EXTENSIONS
3309 for (extension_list_t::iterator i = m_extensions.begin()
3310 , end(m_extensions.end()); i != end; ++i)
3312 #ifndef BOOST_NO_EXCEPTIONS
3313 try {
3314 #endif
3315 (*i)->on_files_checked();
3316 #ifndef BOOST_NO_EXCEPTIONS
3317 } catch (std::exception&) {}
3318 #endif
3320 #endif
3322 if (!m_connections_initialized)
3324 m_connections_initialized = true;
3325 // all peer connections have to initialize themselves now that the metadata
3326 // is available
3327 for (torrent::peer_iterator i = m_connections.begin();
3328 i != m_connections.end();)
3330 peer_connection* pc = *i;
3331 ++i;
3332 pc->on_metadata();
3333 pc->init();
3337 m_files_checked = true;
3339 start_announcing();
3342 alert_manager& torrent::alerts() const
3344 return m_ses.m_alerts;
3347 fs::path torrent::save_path() const
3349 return m_save_path;
3352 bool torrent::rename_file(int index, std::string const& name)
3354 INVARIANT_CHECK;
3356 TORRENT_ASSERT(index >= 0);
3357 TORRENT_ASSERT(index < m_torrent_file->num_files());
3359 if (!m_owning_storage.get()) return false;
3361 m_owning_storage->async_rename_file(index, name
3362 , bind(&torrent::on_file_renamed, shared_from_this(), _1, _2));
3363 return true;
3366 void torrent::move_storage(fs::path const& save_path)
3368 INVARIANT_CHECK;
3370 if (m_owning_storage.get())
3372 m_owning_storage->async_move_storage(save_path
3373 , bind(&torrent::on_storage_moved, shared_from_this(), _1, _2));
3375 else
3377 m_save_path = save_path;
3381 void torrent::on_storage_moved(int ret, disk_io_job const& j)
3383 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3385 if (alerts().should_post<storage_moved_alert>())
3387 alerts().post_alert(storage_moved_alert(get_handle(), j.str));
3389 m_save_path = j.str;
3392 piece_manager& torrent::filesystem()
3394 TORRENT_ASSERT(m_owning_storage.get());
3395 TORRENT_ASSERT(m_storage);
3396 return *m_storage;
3400 torrent_handle torrent::get_handle()
3402 return torrent_handle(shared_from_this());
3405 session_settings const& torrent::settings() const
3407 return m_ses.settings();
3410 #ifndef NDEBUG
3411 void torrent::check_invariant() const
3413 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3415 if (!m_ses.m_queued_for_checking.empty())
3417 // if there are torrents waiting to be checked
3418 // assert that there's a torrent that is being
3419 // processed right now
3420 int found = 0;
3421 for (aux::session_impl::torrent_map::iterator i = m_ses.m_torrents.begin()
3422 , end(m_ses.m_torrents.end()); i != end; ++i)
3423 if (i->second->m_state == torrent_status::checking_files) ++found;
3424 // the case of 2 is in the special case where one switches over from
3425 // checking to complete
3426 TORRENT_ASSERT(found == 1 || found == 2);
3429 TORRENT_ASSERT(m_resume_entry.type() == lazy_entry::dict_t
3430 || m_resume_entry.type() == lazy_entry::none_t);
3432 TORRENT_ASSERT(m_bandwidth_queue[0].size() <= m_connections.size());
3433 TORRENT_ASSERT(m_bandwidth_queue[1].size() <= m_connections.size());
3435 for (int c = 0; c < 2; ++c)
3437 queue_t::const_iterator j = m_bandwidth_queue[c].begin();
3438 if (j == m_bandwidth_queue[c].end()) continue;
3439 ++j;
3440 for (queue_t::const_iterator i = m_bandwidth_queue[c].begin()
3441 , end(m_bandwidth_queue[c].end()); i != end && j != end; ++i, ++j)
3442 TORRENT_ASSERT(i->priority >= j->priority);
3445 int num_uploads = 0;
3446 std::map<piece_block, int> num_requests;
3447 for (const_peer_iterator i = begin(); i != end(); ++i)
3449 #ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
3450 // make sure this peer is not a dangling pointer
3451 TORRENT_ASSERT(m_ses.has_peer(*i));
3452 #endif
3453 peer_connection const& p = *(*i);
3454 for (std::deque<piece_block>::const_iterator i = p.request_queue().begin()
3455 , end(p.request_queue().end()); i != end; ++i)
3456 ++num_requests[*i];
3457 for (std::deque<pending_block>::const_iterator i = p.download_queue().begin()
3458 , end(p.download_queue().end()); i != end; ++i)
3459 ++num_requests[i->block];
3460 if (!p.is_choked()) ++num_uploads;
3461 torrent* associated_torrent = p.associated_torrent().lock().get();
3462 if (associated_torrent != this)
3463 TORRENT_ASSERT(false);
3465 TORRENT_ASSERT(num_uploads == m_num_uploads);
3467 if (has_picker())
3469 for (std::map<piece_block, int>::iterator i = num_requests.begin()
3470 , end(num_requests.end()); i != end; ++i)
3472 if (!m_picker->is_downloaded(i->first))
3473 TORRENT_ASSERT(m_picker->num_peers(i->first) == i->second);
3475 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
3478 if (valid_metadata())
3480 TORRENT_ASSERT(m_abort || !m_picker || m_picker->num_pieces() == m_torrent_file->num_pieces());
3482 else
3484 TORRENT_ASSERT(m_abort || m_picker->num_pieces() == 0);
3487 #ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
3488 for (policy::const_iterator i = m_policy.begin_peer()
3489 , end(m_policy.end_peer()); i != end; ++i)
3491 TORRENT_ASSERT(i->second.addr == i->first);
3493 #endif
3495 size_type total_done = quantized_bytes_done();
3496 if (m_torrent_file->is_valid())
3498 if (is_seed())
3499 TORRENT_ASSERT(total_done == m_torrent_file->total_size());
3500 else
3501 TORRENT_ASSERT(total_done != m_torrent_file->total_size() || !m_files_checked);
3503 TORRENT_ASSERT(m_block_size <= m_torrent_file->piece_length());
3505 else
3507 TORRENT_ASSERT(total_done == 0);
3510 if (m_picker && !m_abort)
3512 // make sure that pieces that have completed the download
3513 // of all their blocks are in the disk io thread's queue
3514 // to be checked.
3515 const std::vector<piece_picker::downloading_piece>& dl_queue
3516 = m_picker->get_download_queue();
3517 for (std::vector<piece_picker::downloading_piece>::const_iterator i =
3518 dl_queue.begin(); i != dl_queue.end(); ++i)
3520 const int blocks_per_piece = m_picker->blocks_in_piece(i->index);
3522 bool complete = true;
3523 for (int j = 0; j < blocks_per_piece; ++j)
3525 if (i->info[j].state == piece_picker::block_info::state_finished)
3526 continue;
3527 complete = false;
3528 break;
3533 // This check is very expensive.
3534 TORRENT_ASSERT(!valid_metadata() || m_block_size > 0);
3535 TORRENT_ASSERT(!valid_metadata() || (m_torrent_file->piece_length() % m_block_size) == 0);
3536 // if (is_seed()) TORRENT_ASSERT(m_picker.get() == 0);
3538 #endif
3540 void torrent::set_sequential_download(bool sd)
3542 m_sequential_download = sd;
3543 if (has_picker())
3545 picker().sequential_download(sd);
3549 void torrent::set_queue_position(int p)
3551 TORRENT_ASSERT((p == -1) == is_finished()
3552 || (!m_auto_managed && p == -1)
3553 || (m_abort && p == -1));
3554 if (is_finished() && p != -1) return;
3555 if (p == m_sequence_number) return;
3557 session_impl::torrent_map& torrents = m_ses.m_torrents;
3558 if (p >= 0 && m_sequence_number == -1)
3560 int max_seq = -1;
3561 for (session_impl::torrent_map::iterator i = torrents.begin()
3562 , end(torrents.end()); i != end; ++i)
3564 torrent* t = i->second.get();
3565 if (t->m_sequence_number > max_seq) max_seq = t->m_sequence_number;
3567 m_sequence_number = (std::min)(max_seq + 1, p);
3569 else if (p < 0)
3571 for (session_impl::torrent_map::iterator i = torrents.begin()
3572 , end(torrents.end()); i != end; ++i)
3574 torrent* t = i->second.get();
3575 if (t == this) continue;
3576 if (t->m_sequence_number >= m_sequence_number
3577 && t->m_sequence_number != -1)
3578 --t->m_sequence_number;
3580 m_sequence_number = p;
3582 else if (p < m_sequence_number)
3584 for (session_impl::torrent_map::iterator i = torrents.begin()
3585 , end(torrents.end()); i != end; ++i)
3587 torrent* t = i->second.get();
3588 if (t == this) continue;
3589 if (t->m_sequence_number >= p
3590 && t->m_sequence_number < m_sequence_number
3591 && t->m_sequence_number != -1)
3592 ++t->m_sequence_number;
3594 m_sequence_number = p;
3596 else if (p > m_sequence_number)
3598 int max_seq = 0;
3599 for (session_impl::torrent_map::iterator i = torrents.begin()
3600 , end(torrents.end()); i != end; ++i)
3602 torrent* t = i->second.get();
3603 int pos = t->m_sequence_number;
3604 if (pos > max_seq) max_seq = pos;
3605 if (t == this) continue;
3607 if (pos <= p
3608 && pos > m_sequence_number
3609 && pos != -1)
3610 --t->m_sequence_number;
3613 m_sequence_number = (std::min)(max_seq, p);
3616 if (m_ses.m_auto_manage_time_scaler > 2)
3617 m_ses.m_auto_manage_time_scaler = 2;
3620 void torrent::set_max_uploads(int limit)
3622 TORRENT_ASSERT(limit >= -1);
3623 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3624 m_max_uploads = limit;
3627 void torrent::set_max_connections(int limit)
3629 TORRENT_ASSERT(limit >= -1);
3630 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3631 m_max_connections = limit;
3634 void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit)
3636 TORRENT_ASSERT(limit >= -1);
3637 peer_iterator i = std::find_if(m_connections.begin(), m_connections.end()
3638 , bind(&peer_connection::remote, _1) == ip);
3639 if (i == m_connections.end()) return;
3640 (*i)->set_upload_limit(limit);
3643 void torrent::set_peer_download_limit(tcp::endpoint ip, int limit)
3645 TORRENT_ASSERT(limit >= -1);
3646 peer_iterator i = std::find_if(m_connections.begin(), m_connections.end()
3647 , bind(&peer_connection::remote, _1) == ip);
3648 if (i == m_connections.end()) return;
3649 (*i)->set_download_limit(limit);
3652 void torrent::set_upload_limit(int limit)
3654 TORRENT_ASSERT(limit >= -1);
3655 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3656 if (limit < num_peers() * 10) limit = num_peers() * 10;
3657 m_bandwidth_limit[peer_connection::upload_channel].throttle(limit);
3660 int torrent::upload_limit() const
3662 int limit = m_bandwidth_limit[peer_connection::upload_channel].throttle();
3663 if (limit == (std::numeric_limits<int>::max)()) limit = -1;
3664 return limit;
3667 void torrent::set_download_limit(int limit)
3669 TORRENT_ASSERT(limit >= -1);
3670 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3671 if (limit < num_peers() * 10) limit = num_peers() * 10;
3672 m_bandwidth_limit[peer_connection::download_channel].throttle(limit);
3675 int torrent::download_limit() const
3677 int limit = m_bandwidth_limit[peer_connection::download_channel].throttle();
3678 if (limit == (std::numeric_limits<int>::max)()) limit = -1;
3679 return limit;
3682 void torrent::delete_files()
3684 #if defined TORRENT_VERBOSE_LOGGING
3685 for (peer_iterator i = m_connections.begin();
3686 i != m_connections.end(); ++i)
3688 (*(*i)->m_logger) << "*** DELETING FILES IN TORRENT\n";
3690 #endif
3692 disconnect_all();
3693 stop_announcing();
3695 if (m_owning_storage.get())
3697 TORRENT_ASSERT(m_storage);
3698 m_storage->async_delete_files(
3699 bind(&torrent::on_files_deleted, shared_from_this(), _1, _2));
3703 void torrent::clear_error()
3705 if (m_error.empty()) return;
3706 if (m_ses.m_auto_manage_time_scaler > 2)
3707 m_ses.m_auto_manage_time_scaler = 2;
3708 m_error.clear();
3711 void torrent::auto_managed(bool a)
3713 INVARIANT_CHECK;
3715 if (m_auto_managed == a) return;
3716 m_auto_managed = a;
3717 // recalculate which torrents should be
3718 // paused
3719 m_ses.m_auto_manage_time_scaler = 0;
3722 // the higher seed rank, the more important to seed
3723 int torrent::seed_rank(session_settings const& s) const
3725 enum flags
3727 seed_ratio_not_met = 0x400000,
3728 recently_started = 0x200000,
3729 no_seeds = 0x100000,
3730 prio_mask = 0xfffff
3733 if (!is_seed()) return 0;
3735 int ret = 0;
3737 ptime now(time_now());
3739 int seed_time = total_seconds(m_seeding_time);
3740 int download_time = total_seconds(m_active_time) - seed_time;
3742 // if we haven't yet met the seed limits, set the seed_ratio_not_met
3743 // flag. That will make this seed prioritized
3744 size_type downloaded = (std::max)(m_total_downloaded, m_torrent_file->total_size());
3745 if (seed_time < s.seed_time_limit
3746 && (seed_time > 1 && download_time / float(seed_time) < s.seed_time_ratio_limit)
3747 && m_total_uploaded / downloaded < s.share_ratio_limit)
3748 ret |= seed_ratio_not_met;
3750 // if this torrent is running, and it was started less
3751 // than 30 minutes ago, give it priority, to avoid oscillation
3752 if (!is_paused() && now - m_started < minutes(30))
3753 ret |= recently_started;
3755 // if we have any scrape data, use it to calculate
3756 // seed rank
3757 int seeds = 0;
3758 int downloaders = 0;
3760 if (m_complete >= 0) seeds = m_complete;
3761 else seeds = m_policy.num_seeds();
3763 if (m_incomplete >= 0) downloaders = m_incomplete;
3764 else downloaders = m_policy.num_peers() - m_policy.num_seeds();
3766 if (seeds == 0)
3768 ret |= no_seeds;
3769 ret |= downloaders & prio_mask;
3771 else
3773 ret |= (downloaders * 100 / seeds) & prio_mask;
3776 return ret;
3779 // this is an async operation triggered by the client
3780 void torrent::save_resume_data()
3782 INVARIANT_CHECK;
3784 if (m_owning_storage.get())
3786 TORRENT_ASSERT(m_storage);
3787 if (m_state == torrent_status::queued_for_checking
3788 || m_state == torrent_status::checking_files)
3790 if (alerts().should_post<save_resume_data_failed_alert>())
3792 alerts().post_alert(save_resume_data_failed_alert(get_handle()
3793 , "won't save resume data, torrent does not have a complete resume state yet"));
3796 else
3798 m_storage->async_save_resume_data(
3799 bind(&torrent::on_save_resume_data, shared_from_this(), _1, _2));
3802 else
3804 if (alerts().should_post<save_resume_data_failed_alert>())
3806 alerts().post_alert(save_resume_data_failed_alert(get_handle()
3807 , "save resume data failed, torrent is being destructed"));
3812 bool torrent::is_paused() const
3814 return m_paused || m_ses.is_paused();
3817 void torrent::pause()
3819 INVARIANT_CHECK;
3821 if (m_paused) return;
3822 m_paused = true;
3823 if (m_ses.is_paused()) return;
3824 do_pause();
3827 void torrent::do_pause()
3829 if (!is_paused()) return;
3831 #ifndef TORRENT_DISABLE_EXTENSIONS
3832 for (extension_list_t::iterator i = m_extensions.begin()
3833 , end(m_extensions.end()); i != end; ++i)
3835 #ifndef BOOST_NO_EXCEPTIONS
3836 try {
3837 #endif
3838 if ((*i)->on_pause()) return;
3839 #ifndef BOOST_NO_EXCEPTIONS
3840 } catch (std::exception&) {}
3841 #endif
3843 #endif
3845 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
3846 for (peer_iterator i = m_connections.begin();
3847 i != m_connections.end(); ++i)
3849 (*(*i)->m_logger) << "*** PAUSING TORRENT\n";
3851 #endif
3853 // this will make the storage close all
3854 // files and flush all cached data
3855 if (m_owning_storage.get())
3857 TORRENT_ASSERT(m_storage);
3858 m_storage->async_release_files(
3859 bind(&torrent::on_torrent_paused, shared_from_this(), _1, _2));
3860 m_storage->async_clear_read_cache();
3862 else
3864 if (alerts().should_post<torrent_paused_alert>())
3865 alerts().post_alert(torrent_paused_alert(get_handle()));
3868 disconnect_all();
3869 stop_announcing();
3872 void torrent::resume()
3874 INVARIANT_CHECK;
3876 if (!m_paused) return;
3877 m_paused = false;
3878 do_resume();
3881 void torrent::do_resume()
3883 if (is_paused()) return;
3885 #ifndef TORRENT_DISABLE_EXTENSIONS
3886 for (extension_list_t::iterator i = m_extensions.begin()
3887 , end(m_extensions.end()); i != end; ++i)
3889 #ifndef BOOST_NO_EXCEPTIONS
3890 try {
3891 #endif
3892 if ((*i)->on_resume()) return;
3893 #ifndef BOOST_NO_EXCEPTIONS
3894 } catch (std::exception&) {}
3895 #endif
3897 #endif
3899 if (alerts().should_post<torrent_resumed_alert>())
3900 alerts().post_alert(torrent_resumed_alert(get_handle()));
3902 m_started = time_now();
3903 m_error.clear();
3904 start_announcing();
3907 void torrent::restart_tracker_timer(ptime announce_at)
3909 if (!m_announcing) return;
3911 m_next_tracker_announce = announce_at;
3912 error_code ec;
3913 boost::weak_ptr<torrent> self(shared_from_this());
3914 m_tracker_timer.expires_at(m_next_tracker_announce, ec);
3915 m_tracker_timer.async_wait(bind(&torrent::on_tracker_announce_disp, self, _1));
3918 void torrent::start_announcing()
3920 if (is_paused()) return;
3921 if (!m_files_checked) return;
3922 if (m_announcing) return;
3924 m_announcing = true;
3926 if (!m_trackers.empty())
3928 // tell the tracker that we're back
3929 m_start_sent = false;
3930 announce_with_tracker();
3933 // private torrents are never announced on LSD
3934 // or on DHT, we don't need this timer.
3935 if (!m_torrent_file->is_valid() || !m_torrent_file->priv())
3937 error_code ec;
3938 boost::weak_ptr<torrent> self(shared_from_this());
3939 m_lsd_announce_timer.expires_from_now(seconds(1), ec);
3940 m_lsd_announce_timer.async_wait(
3941 bind(&torrent::on_lsd_announce_disp, self, _1));
3945 void torrent::stop_announcing()
3947 if (!m_announcing) return;
3949 error_code ec;
3950 m_lsd_announce_timer.cancel(ec);
3951 m_tracker_timer.cancel(ec);
3953 m_announcing = false;
3955 if (!m_trackers.empty())
3956 announce_with_tracker(tracker_request::stopped);
3959 void torrent::second_tick(stat& accumulator, float tick_interval)
3961 INVARIANT_CHECK;
3963 #ifndef TORRENT_DISABLE_EXTENSIONS
3964 for (extension_list_t::iterator i = m_extensions.begin()
3965 , end(m_extensions.end()); i != end; ++i)
3967 #ifndef BOOST_NO_EXCEPTIONS
3968 try {
3969 #endif
3970 (*i)->tick();
3971 #ifndef BOOST_NO_EXCEPTIONS
3972 } catch (std::exception&) {}
3973 #endif
3975 #endif
3977 if (is_paused())
3979 // let the stats fade out to 0
3980 m_stat.second_tick(tick_interval);
3981 return;
3984 time_duration since_last_tick = microsec(tick_interval * 1000000L);
3985 if (is_seed()) m_seeding_time += since_last_tick;
3986 m_active_time += since_last_tick;
3988 // ---- WEB SEEDS ----
3990 // re-insert urls that are to be retrieds into the m_web_seeds
3991 typedef std::map<std::string, ptime>::iterator iter_t;
3992 for (iter_t i = m_web_seeds_next_retry.begin(); i != m_web_seeds_next_retry.end();)
3994 iter_t erase_element = i++;
3995 if (erase_element->second <= time_now())
3997 m_web_seeds.insert(erase_element->first);
3998 m_web_seeds_next_retry.erase(erase_element);
4002 // if we have everything we want we don't need to connect to any web-seed
4003 if (!is_finished() && !m_web_seeds.empty())
4005 // keep trying web-seeds if there are any
4006 // first find out which web seeds we are connected to
4007 std::set<std::string> web_seeds;
4008 for (peer_iterator i = m_connections.begin();
4009 i != m_connections.end(); ++i)
4011 web_peer_connection* p
4012 = dynamic_cast<web_peer_connection*>(*i);
4013 if (!p) continue;
4014 web_seeds.insert(p->url());
4017 for (std::set<std::string>::iterator i = m_resolving_web_seeds.begin()
4018 , end(m_resolving_web_seeds.end()); i != end; ++i)
4019 web_seeds.insert(web_seeds.begin(), *i);
4021 // from the list of available web seeds, subtract the ones we are
4022 // already connected to.
4023 std::vector<std::string> not_connected_web_seeds;
4024 std::set_difference(m_web_seeds.begin(), m_web_seeds.end(), web_seeds.begin()
4025 , web_seeds.end(), std::back_inserter(not_connected_web_seeds));
4027 // connect to all of those that we aren't connected to
4028 std::for_each(not_connected_web_seeds.begin(), not_connected_web_seeds.end()
4029 , bind(&torrent::connect_to_url_seed, this, _1));
4032 for (peer_iterator i = m_connections.begin();
4033 i != m_connections.end();)
4035 peer_connection* p = *i;
4036 ++i;
4037 p->calc_ip_overhead();
4038 m_stat += p->statistics();
4039 // updates the peer connection's ul/dl bandwidth
4040 // resource requests
4041 #ifndef BOOST_NO_EXCEPTIONS
4044 #endif
4045 p->second_tick(tick_interval);
4046 #ifndef BOOST_NO_EXCEPTIONS
4048 catch (std::exception& e)
4050 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
4051 (*p->m_logger) << "**ERROR**: " << e.what() << "\n";
4052 #endif
4053 p->disconnect(e.what(), 1);
4055 #endif
4057 accumulator += m_stat;
4058 m_total_uploaded += m_stat.last_payload_uploaded();
4059 m_total_downloaded += m_stat.last_payload_downloaded();
4060 m_stat.second_tick(tick_interval);
4062 m_time_scaler--;
4063 if (m_time_scaler <= 0)
4065 m_time_scaler = 10;
4066 m_policy.pulse();
4070 void torrent::retry_url_seed(std::string const& url)
4072 m_web_seeds_next_retry[url] = time_now()
4073 + seconds(m_ses.settings().urlseed_wait_retry);
4076 bool torrent::try_connect_peer()
4078 TORRENT_ASSERT(want_more_peers());
4079 if (m_deficit_counter < 100) return false;
4080 m_deficit_counter -= 100;
4081 bool ret = m_policy.connect_one_peer();
4082 return ret;
4085 void torrent::give_connect_points(int points)
4087 TORRENT_ASSERT(points <= 100);
4088 TORRENT_ASSERT(points > 0);
4089 TORRENT_ASSERT(want_more_peers());
4090 m_deficit_counter += points;
4093 void torrent::async_verify_piece(int piece_index, boost::function<void(int)> const& f)
4095 // INVARIANT_CHECK;
4097 TORRENT_ASSERT(m_storage);
4098 TORRENT_ASSERT(m_storage->refcount() > 0);
4099 TORRENT_ASSERT(piece_index >= 0);
4100 TORRENT_ASSERT(piece_index < m_torrent_file->num_pieces());
4101 TORRENT_ASSERT(piece_index < (int)m_picker->num_pieces());
4102 #ifndef NDEBUG
4103 if (m_picker)
4105 int blocks_in_piece = m_picker->blocks_in_piece(piece_index);
4106 for (int i = 0; i < blocks_in_piece; ++i)
4108 TORRENT_ASSERT(m_picker->num_peers(piece_block(piece_index, i)) == 0);
4111 #endif
4113 m_storage->async_hash(piece_index, bind(&torrent::on_piece_verified
4114 , shared_from_this(), _1, _2, f));
4115 #if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
4116 check_invariant();
4117 #endif
4120 void torrent::on_piece_verified(int ret, disk_io_job const& j
4121 , boost::function<void(int)> f)
4123 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4125 // return value:
4126 // 0: success, piece passed hash check
4127 // -1: disk failure
4128 // -2: hash check failed
4130 if (ret == -1)
4132 if (alerts().should_post<file_error_alert>())
4133 alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str));
4134 m_error = j.str;
4135 pause();
4137 f(ret);
4140 const tcp::endpoint& torrent::current_tracker() const
4142 return m_tracker_address;
4145 void torrent::file_progress(std::vector<float>& fp) const
4147 fp.clear();
4148 fp.resize(m_torrent_file->num_files(), 1.f);
4149 if (is_seed()) return;
4151 std::vector<size_type> progress;
4152 file_progress(progress);
4153 for (int i = 0; i < m_torrent_file->num_files(); ++i)
4155 file_entry const& f = m_torrent_file->file_at(i);
4156 if (f.size == 0) fp[i] = 1.f;
4157 else fp[i] = float(progress[i]) / f.size;
4161 void torrent::file_progress(std::vector<size_type>& fp) const
4163 TORRENT_ASSERT(valid_metadata());
4165 fp.resize(m_torrent_file->num_files(), 0);
4167 if (is_seed())
4169 for (int i = 0; i < m_torrent_file->num_files(); ++i)
4170 fp[i] = m_torrent_file->files().at(i).size;
4171 return;
4174 TORRENT_ASSERT(has_picker());
4176 for (int i = 0; i < m_torrent_file->num_files(); ++i)
4178 peer_request ret = m_torrent_file->files().map_file(i, 0, 0);
4179 size_type size = m_torrent_file->files().at(i).size;
4181 // zero sized files are considered
4182 // 100% done all the time
4183 if (size == 0)
4185 fp[i] = 0;
4186 continue;
4189 size_type done = 0;
4190 while (size > 0)
4192 size_type bytes_step = (std::min)(size_type(m_torrent_file->piece_size(ret.piece)
4193 - ret.start), size);
4194 if (m_picker->have_piece(ret.piece)) done += bytes_step;
4195 ++ret.piece;
4196 ret.start = 0;
4197 size -= bytes_step;
4199 TORRENT_ASSERT(size == 0);
4201 fp[i] = done;
4204 const std::vector<piece_picker::downloading_piece>& q
4205 = m_picker->get_download_queue();
4207 for (std::vector<piece_picker::downloading_piece>::const_iterator
4208 i = q.begin(), end(q.end()); i != end; ++i)
4210 size_type offset = size_type(i->index) * m_torrent_file->piece_length();
4211 torrent_info::file_iterator file = m_torrent_file->file_at_offset(offset);
4212 int file_index = file - m_torrent_file->begin_files();
4213 int num_blocks = m_picker->blocks_in_piece(i->index);
4214 piece_picker::block_info const* info = i->info;
4215 for (int k = 0; k < num_blocks; ++k)
4217 TORRENT_ASSERT(file != m_torrent_file->end_files());
4218 TORRENT_ASSERT(offset == size_type(i->index) * m_torrent_file->piece_length()
4219 + k * m_block_size);
4220 TORRENT_ASSERT(offset < m_torrent_file->total_size());
4221 while (offset >= file->offset + file->size)
4223 ++file;
4224 ++file_index;
4226 TORRENT_ASSERT(file != m_torrent_file->end_files());
4228 size_type block_size = m_block_size;
4230 if (info[k].state == piece_picker::block_info::state_none)
4232 offset += m_block_size;
4233 continue;
4236 if (info[k].state == piece_picker::block_info::state_requested)
4238 block_size = 0;
4239 policy::peer* p = static_cast<policy::peer*>(info[k].peer);
4240 if (p && p->connection)
4242 boost::optional<piece_block_progress> pbp
4243 = p->connection->downloading_piece_progress();
4244 if (pbp && pbp->piece_index == i->index && pbp->block_index == k)
4245 block_size = pbp->bytes_downloaded;
4246 TORRENT_ASSERT(block_size <= m_block_size);
4249 if (block_size == 0)
4251 offset += m_block_size;
4252 continue;
4256 if (offset + block_size > file->offset + file->size)
4258 int left_over = m_block_size - block_size;
4259 // split the block on multiple files
4260 while (block_size > 0)
4262 TORRENT_ASSERT(offset <= file->offset + file->size);
4263 size_type slice = (std::min)(file->offset + file->size - offset
4264 , block_size);
4265 fp[file_index] += slice;
4266 offset += slice;
4267 block_size -= slice;
4268 TORRENT_ASSERT(offset <= file->offset + file->size);
4269 if (offset == file->offset + file->size)
4271 ++file;
4272 ++file_index;
4273 if (file == m_torrent_file->end_files())
4275 offset += block_size;
4276 break;
4280 offset += left_over;
4281 TORRENT_ASSERT(offset == size_type(i->index) * m_torrent_file->piece_length()
4282 + (k+1) * m_block_size);
4284 else
4286 fp[file_index] += block_size;
4287 offset += m_block_size;
4289 TORRENT_ASSERT(file_index <= m_torrent_file->num_files());
4294 void torrent::set_state(torrent_status::state_t s)
4296 if (m_state == s) return;
4297 m_state = s;
4298 if (m_ses.m_alerts.should_post<state_changed_alert>())
4299 m_ses.m_alerts.post_alert(state_changed_alert(get_handle(), s));
4302 torrent_status torrent::status() const
4304 INVARIANT_CHECK;
4306 ptime now = time_now();
4308 torrent_status st;
4310 st.has_incoming = m_has_incoming;
4311 st.error = m_error;
4313 if (m_last_scrape == min_time())
4315 st.last_scrape = -1;
4317 else
4319 st.last_scrape = total_seconds(now - m_last_scrape);
4321 st.up_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::upload_channel].size();
4322 st.down_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::download_channel].size();
4324 st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end()
4325 , !boost::bind(&peer_connection::is_connecting, _1));
4327 st.list_peers = m_policy.num_peers();
4328 st.list_seeds = m_policy.num_seeds();
4329 st.connect_candidates = m_policy.num_connect_candidates();
4330 st.seed_rank = seed_rank(m_ses.m_settings);
4332 st.all_time_upload = m_total_uploaded;
4333 st.all_time_download = m_total_downloaded;
4335 st.active_time = total_seconds(m_active_time);
4336 st.seeding_time = total_seconds(m_seeding_time);
4338 st.storage_mode = m_storage_mode;
4340 st.num_complete = m_complete;
4341 st.num_incomplete = m_incomplete;
4342 st.paused = m_paused;
4343 boost::tie(st.total_done, st.total_wanted_done) = bytes_done();
4344 TORRENT_ASSERT(st.total_wanted_done >= 0);
4345 TORRENT_ASSERT(st.total_done >= st.total_wanted_done);
4347 // payload transfer
4348 st.total_payload_download = m_stat.total_payload_download();
4349 st.total_payload_upload = m_stat.total_payload_upload();
4351 // total transfer
4352 st.total_download = m_stat.total_payload_download()
4353 + m_stat.total_protocol_download();
4354 st.total_upload = m_stat.total_payload_upload()
4355 + m_stat.total_protocol_upload();
4357 // failed bytes
4358 st.total_failed_bytes = m_total_failed_bytes;
4359 st.total_redundant_bytes = m_total_redundant_bytes;
4361 // transfer rate
4362 st.download_rate = m_stat.download_rate();
4363 st.upload_rate = m_stat.upload_rate();
4364 st.download_payload_rate = m_stat.download_payload_rate();
4365 st.upload_payload_rate = m_stat.upload_payload_rate();
4367 st.next_announce = boost::posix_time::seconds(
4368 total_seconds(next_announce() - now));
4369 if (st.next_announce.is_negative() || is_paused())
4370 st.next_announce = boost::posix_time::seconds(0);
4372 st.announce_interval = boost::posix_time::seconds(m_duration);
4374 if (m_last_working_tracker >= 0)
4376 st.current_tracker
4377 = m_trackers[m_last_working_tracker].url;
4380 st.num_uploads = m_num_uploads;
4381 st.uploads_limit = m_max_uploads;
4382 st.num_connections = int(m_connections.size());
4383 st.connections_limit = m_max_connections;
4384 // if we don't have any metadata, stop here
4386 st.state = m_state;
4388 if (!valid_metadata())
4390 st.state = torrent_status::downloading_metadata;
4391 st.progress = m_progress;
4392 st.block_size = 0;
4393 return st;
4396 st.block_size = block_size();
4398 // fill in status that depends on metadata
4400 st.total_wanted = m_torrent_file->total_size();
4401 TORRENT_ASSERT(st.total_wanted >= 0);
4402 TORRENT_ASSERT(st.total_wanted >= m_torrent_file->piece_length()
4403 * (m_torrent_file->num_pieces() - 1));
4405 if (m_picker.get() && (m_picker->num_filtered() > 0
4406 || m_picker->num_have_filtered() > 0))
4408 int num_filtered_pieces = m_picker->num_filtered()
4409 + m_picker->num_have_filtered();
4410 int last_piece_index = m_torrent_file->num_pieces() - 1;
4411 if (m_picker->piece_priority(last_piece_index) == 0)
4413 st.total_wanted -= m_torrent_file->piece_size(last_piece_index);
4414 --num_filtered_pieces;
4417 st.total_wanted -= size_type(num_filtered_pieces) * m_torrent_file->piece_length();
4420 TORRENT_ASSERT(st.total_wanted >= st.total_wanted_done);
4422 if (m_state == torrent_status::checking_files)
4423 st.progress = m_progress;
4424 else if (st.total_wanted == 0) st.progress = 1.f;
4425 else st.progress = st.total_wanted_done
4426 / static_cast<float>(st.total_wanted);
4428 if (has_picker())
4430 int num_pieces = m_picker->num_pieces();
4431 st.pieces.resize(num_pieces, false);
4432 for (int i = 0; i < num_pieces; ++i)
4433 if (m_picker->have_piece(i)) st.pieces.set_bit(i);
4435 st.num_pieces = num_have();
4436 st.num_seeds = num_seeds();
4437 if (m_picker.get())
4438 st.distributed_copies = m_picker->distributed_copies();
4439 else
4440 st.distributed_copies = -1;
4441 return st;
4444 void torrent::add_redundant_bytes(int b)
4446 TORRENT_ASSERT(b > 0);
4447 m_total_redundant_bytes += b;
4448 m_ses.add_redundant_bytes(b);
4451 void torrent::add_failed_bytes(int b)
4453 TORRENT_ASSERT(b > 0);
4454 m_total_failed_bytes += b;
4455 m_ses.add_failed_bytes(b);
4458 int torrent::num_seeds() const
4460 INVARIANT_CHECK;
4462 return (int)std::count_if(m_connections.begin(), m_connections.end()
4463 , boost::bind(&peer_connection::is_seed, _1));
4466 void torrent::tracker_request_timed_out(
4467 tracker_request const& r)
4469 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4471 INVARIANT_CHECK;
4473 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4474 debug_log("*** tracker timed out");
4475 #endif
4477 if (r.kind == tracker_request::announce_request)
4479 if (m_ses.m_alerts.should_post<tracker_error_alert>())
4481 m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
4482 , m_failed_trackers + 1, 0, r.url, "tracker timed out"));
4485 else if (r.kind == tracker_request::scrape_request)
4487 if (m_ses.m_alerts.should_post<scrape_failed_alert>())
4489 m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle()
4490 , r.url, "tracker timed out"));
4494 if (r.kind == tracker_request::announce_request)
4495 try_next_tracker(r);
4498 // TODO: with some response codes, we should just consider
4499 // the tracker as a failure and not retry
4500 // it anymore
4501 void torrent::tracker_request_error(tracker_request const& r
4502 , int response_code, const std::string& str)
4504 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4506 INVARIANT_CHECK;
4508 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4509 debug_log(std::string("*** tracker error: ") + str);
4510 #endif
4511 if (r.kind == tracker_request::announce_request)
4513 if (m_ses.m_alerts.should_post<tracker_error_alert>())
4515 m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
4516 , m_failed_trackers + 1, response_code, r.url, str));
4519 else if (r.kind == tracker_request::scrape_request)
4521 if (m_ses.m_alerts.should_post<scrape_failed_alert>())
4523 m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), r.url, str));
4527 if (r.kind == tracker_request::announce_request)
4528 try_next_tracker(r);
4532 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4533 void torrent::debug_log(const std::string& line)
4535 (*m_ses.m_logger) << time_now_string() << " " << line << "\n";
4537 #endif