fixed bug in windows path of file.cpp
[libtorrent.git] / src / torrent.cpp
blobd2e1b8064ac4eeeef808ce33b60734aebb53e186
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);
211 torrent::torrent(
212 session_impl& ses
213 , char const* tracker_url
214 , sha1_hash const& info_hash
215 , char const* name
216 , fs::path const& save_path
217 , tcp::endpoint const& net_interface
218 , storage_mode_t storage_mode
219 , int block_size
220 , storage_constructor_type sc
221 , bool paused
222 , std::vector<char>* resume_data
223 , int seq
224 , bool auto_managed)
225 : m_policy(this)
226 , m_active_time(seconds(0))
227 , m_seeding_time(seconds(0))
228 , m_total_uploaded(0)
229 , m_total_downloaded(0)
230 , m_started(time_now())
231 , m_last_scrape(min_time())
232 , m_torrent_file(new torrent_info(info_hash))
233 , m_storage(0)
234 , m_next_tracker_announce(time_now())
235 , m_host_resolver(ses.m_io_service)
236 , m_lsd_announce_timer(ses.m_io_service)
237 , m_tracker_timer(ses.m_io_service)
238 #ifndef TORRENT_DISABLE_DHT
239 , m_last_dht_announce(time_now() - minutes(15))
240 #endif
241 , m_ses(ses)
242 , m_picker(new piece_picker())
243 , m_total_failed_bytes(0)
244 , m_total_redundant_bytes(0)
245 , m_net_interface(net_interface.address(), 0)
246 , m_save_path(complete(save_path))
247 , m_storage_mode(storage_mode)
248 , m_state(torrent_status::queued_for_checking)
249 , m_settings(ses.settings())
250 , m_storage_constructor(sc)
251 , m_progress(0.f)
252 , m_ratio(0.f)
253 , m_max_uploads((std::numeric_limits<int>::max)())
254 , m_num_uploads(0)
255 , m_max_connections((std::numeric_limits<int>::max)())
256 , m_block_size(block_size)
257 , m_complete(-1)
258 , m_incomplete(-1)
259 , m_deficit_counter(0)
260 , m_duration(1800)
261 , m_sequence_number(seq)
262 , m_last_working_tracker(-1)
263 , m_currently_trying_tracker(0)
264 , m_failed_trackers(0)
265 , m_time_scaler(0)
266 , m_abort(false)
267 , m_paused(paused)
268 , m_auto_managed(auto_managed)
269 #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
270 , m_resolving_country(false)
271 , m_resolve_countries(false)
272 #endif
273 , m_sequential_download(false)
274 , m_got_tracker_response(false)
275 , m_connections_initialized(false)
276 , m_has_incoming(false)
277 , m_files_checked(false)
278 , m_announcing(false)
279 , m_start_sent(false)
280 , m_complete_sent(false)
282 parse_resume_data(resume_data);
283 #ifndef NDEBUG
284 m_files_checked = false;
285 #endif
286 INVARIANT_CHECK;
288 if (name) m_name.reset(new std::string(name));
290 if (tracker_url)
292 m_trackers.push_back(announce_entry(tracker_url));
293 m_torrent_file->add_tracker(tracker_url);
297 void torrent::parse_resume_data(std::vector<char>* resume_data)
299 if (!resume_data) return;
300 m_resume_data.swap(*resume_data);
301 if (lazy_bdecode(&m_resume_data[0], &m_resume_data[0]
302 + m_resume_data.size(), m_resume_entry) != 0)
304 std::vector<char>().swap(m_resume_data);
305 if (m_ses.m_alerts.should_post<fastresume_rejected_alert>())
307 m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), "parse failed"));
308 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
309 (*m_ses.m_logger) << "fastresume data for "
310 << torrent_file().name() << " rejected: parse failed\n";
311 #endif
316 void torrent::start()
318 if (m_torrent_file->is_valid()) init();
319 if (m_abort) return;
322 #ifndef TORRENT_DISABLE_DHT
323 bool torrent::should_announce_dht() const
325 if (m_ses.m_listen_sockets.empty()) return false;
327 if (!m_ses.m_dht) return false;
328 if (!m_files_checked) return false;
330 // don't announce private torrents
331 if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false;
332 if (m_trackers.empty()) return true;
334 return m_failed_trackers > 0 || !m_ses.settings().use_dht_as_fallback;
336 #endif
338 torrent::~torrent()
340 // The invariant can't be maintained here, since the torrent
341 // is being destructed, all weak references to it have been
342 // reset, which means that all its peers already have an
343 // invalidated torrent pointer (so it cannot be verified to be correct)
345 // i.e. the invariant can only be maintained if all connections have
346 // been closed by the time the torrent is destructed. And they are
347 // supposed to be closed. So we can still do the invariant check.
349 TORRENT_ASSERT(m_connections.empty());
351 INVARIANT_CHECK;
353 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
354 for (peer_iterator i = m_connections.begin();
355 i != m_connections.end(); ++i)
357 (*(*i)->m_logger) << "*** DESTRUCTING TORRENT\n";
359 #endif
361 TORRENT_ASSERT(m_abort);
362 if (!m_connections.empty())
363 disconnect_all();
366 peer_request torrent::to_req(piece_block const& p)
368 int block_offset = p.block_index * m_block_size;
369 int block_size = (std::min)(torrent_file().piece_size(
370 p.piece_index) - block_offset, m_block_size);
371 TORRENT_ASSERT(block_size > 0);
372 TORRENT_ASSERT(block_size <= m_block_size);
374 peer_request r;
375 r.piece = p.piece_index;
376 r.start = block_offset;
377 r.length = block_size;
378 return r;
381 std::string torrent::name() const
383 if (valid_metadata()) return m_torrent_file->name();
384 if (m_name) return *m_name;
385 return "";
388 #ifndef TORRENT_DISABLE_EXTENSIONS
390 void torrent::add_extension(boost::shared_ptr<torrent_plugin> ext)
392 m_extensions.push_back(ext);
395 void torrent::add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
396 , void* userdata)
398 boost::shared_ptr<torrent_plugin> tp(ext(this, userdata));
399 if (!tp) return;
401 add_extension(tp);
403 for (peer_iterator i = m_connections.begin();
404 i != m_connections.end(); ++i)
406 peer_connection* p = *i;
407 boost::shared_ptr<peer_plugin> pp(tp->new_connection(p));
408 if (pp) p->add_extension(pp);
411 // if files are checked for this torrent, call the extension
412 // to let it initialize itself
413 if (m_connections_initialized)
414 tp->on_files_checked();
417 #endif
419 // this may not be called from a constructor because of the call to
420 // shared_from_this()
421 void torrent::init()
423 TORRENT_ASSERT(m_torrent_file->is_valid());
424 TORRENT_ASSERT(m_torrent_file->num_files() > 0);
425 TORRENT_ASSERT(m_torrent_file->total_size() >= 0);
427 m_file_priority.clear();
428 m_file_priority.resize(m_torrent_file->num_files(), 1);
430 m_block_size = (std::min)(m_block_size, m_torrent_file->piece_length());
432 if (m_torrent_file->num_pieces()
433 > piece_picker::max_pieces)
435 m_error = "too many pieces in torrent";
436 pause();
439 // the shared_from_this() will create an intentional
440 // cycle of ownership, se the hpp file for description.
441 m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
442 , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor
443 , m_storage_mode);
444 m_storage = m_owning_storage.get();
445 m_picker->init((std::max)(m_torrent_file->piece_length() / m_block_size, 1)
446 , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
448 std::vector<std::string> const& url_seeds = m_torrent_file->url_seeds();
449 std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
450 , m_web_seeds.begin()));
452 set_state(torrent_status::queued_for_checking);
454 if (m_resume_entry.type() == lazy_entry::dict_t)
456 char const* error = 0;
457 if (m_resume_entry.dict_find_string_value("file-format") != "libtorrent resume file")
458 error = "invalid file format tag";
460 std::string info_hash = m_resume_entry.dict_find_string_value("info-hash");
461 if (!error && info_hash.empty())
462 error = "missing info-hash";
464 if (!error && sha1_hash(info_hash) != m_torrent_file->info_hash())
465 error = "mismatching info-hash";
467 if (error && m_ses.m_alerts.should_post<fastresume_rejected_alert>())
469 m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), error));
470 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
471 (*m_ses.m_logger) << "fastresume data for "
472 << torrent_file().name() << " rejected: "
473 << error << "\n";
474 #endif
477 if (error)
479 std::vector<char>().swap(m_resume_data);
480 lazy_entry().swap(m_resume_entry);
482 else
484 read_resume_data(m_resume_entry);
488 m_storage->async_check_fastresume(&m_resume_entry
489 , bind(&torrent::on_resume_data_checked
490 , shared_from_this(), _1, _2));
493 void torrent::on_resume_data_checked(int ret, disk_io_job const& j)
495 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
497 if (ret == piece_manager::fatal_disk_error)
499 if (m_ses.m_alerts.should_post<file_error_alert>())
501 m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
502 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
503 (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
504 " error: " << j.str <<
505 " torrent: " << torrent_file().name() <<
506 " ]\n";
507 #endif
509 m_error = j.str;
510 pause();
512 std::vector<char>().swap(m_resume_data);
513 lazy_entry().swap(m_resume_entry);
515 return;
518 if (m_resume_entry.type() == lazy_entry::dict_t)
520 // parse out "peers" from the resume data and add them to the peer list
521 if (lazy_entry const* peers_entry = m_resume_entry.dict_find_list("peers"))
523 peer_id id(0);
525 for (int i = 0; i < peers_entry->list_size(); ++i)
527 lazy_entry const* e = peers_entry->list_at(i);
528 if (e->type() != lazy_entry::dict_t) continue;
529 std::string ip = e->dict_find_string_value("ip");
530 int port = e->dict_find_int_value("port");
531 if (ip.empty() || port == 0) continue;
532 tcp::endpoint a(address::from_string(ip), (unsigned short)port);
533 m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
537 // parse out "banned_peers" and add them as banned
538 if (lazy_entry const* banned_peers_entry = m_resume_entry.dict_find_list("banned_peers"))
540 peer_id id(0);
542 for (int i = 0; i < banned_peers_entry->list_size(); ++i)
544 lazy_entry const* e = banned_peers_entry->list_at(i);
545 if (e->type() != lazy_entry::dict_t) continue;
546 std::string ip = e->dict_find_string_value("ip");
547 int port = e->dict_find_int_value("port");
548 if (ip.empty() || port == 0) continue;
549 tcp::endpoint a(address::from_string(ip), (unsigned short)port);
550 policy::peer* p = m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
551 if (p) p->banned = true;
556 bool fastresume_rejected = !j.str.empty();
558 if (fastresume_rejected && m_ses.m_alerts.should_post<fastresume_rejected_alert>())
560 m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), j.str));
561 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
562 (*m_ses.m_logger) << "fastresume data for "
563 << torrent_file().name() << " rejected: "
564 << j.str << "\n";
565 #endif
568 if (ret == 0)
570 // there are either no files for this torrent
571 // or the resume_data was accepted
573 if (!fastresume_rejected && m_resume_entry.type() == lazy_entry::dict_t)
575 // parse have bitmask
576 lazy_entry const* pieces = m_resume_entry.dict_find("pieces");
577 if (pieces && pieces->type() == lazy_entry::string_t
578 && int(pieces->string_length()) == m_torrent_file->num_pieces())
580 char const* pieces_str = pieces->string_ptr();
581 for (int i = 0, end(pieces->string_length()); i < end; ++i)
583 if ((pieces_str[i] & 1) == 0) continue;
584 m_picker->we_have(i);
588 // parse unfinished pieces
589 int num_blocks_per_piece =
590 static_cast<int>(torrent_file().piece_length()) / block_size();
592 if (lazy_entry const* unfinished_ent = m_resume_entry.dict_find_list("unfinished"))
594 for (int i = 0; i < unfinished_ent->list_size(); ++i)
596 lazy_entry const* e = unfinished_ent->list_at(i);
597 if (e->type() != lazy_entry::dict_t) continue;
598 int piece = e->dict_find_int_value("piece", -1);
599 if (piece < 0 || piece > torrent_file().num_pieces()) continue;
601 if (m_picker->have_piece(piece))
602 m_picker->we_dont_have(piece);
604 std::string bitmask = e->dict_find_string_value("bitmask");
605 if (bitmask.empty()) continue;
607 const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1);
608 if ((int)bitmask.size() != num_bitmask_bytes) continue;
609 for (int j = 0; j < num_bitmask_bytes; ++j)
611 unsigned char bits = bitmask[j];
612 int num_bits = (std::min)(num_blocks_per_piece - j*8, 8);
613 for (int k = 0; k < num_bits; ++k)
615 const int bit = j * 8 + k;
616 if (bits & (1 << k))
618 m_picker->mark_as_finished(piece_block(piece, bit), 0);
619 if (m_picker->is_piece_finished(piece))
620 async_verify_piece(piece, bind(&torrent::piece_finished
621 , shared_from_this(), piece, _1));
629 files_checked();
631 else
633 // either the fastresume data was rejected or there are
634 // some files
635 m_ses.check_torrent(shared_from_this());
638 std::vector<char>().swap(m_resume_data);
639 lazy_entry().swap(m_resume_entry);
642 void torrent::force_recheck()
644 if (m_state == torrent_status::checking_files
645 || m_state == torrent_status::queued_for_checking)
646 return;
648 disconnect_all();
650 m_owning_storage->async_release_files();
651 m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
652 , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor
653 , m_storage_mode);
654 m_storage = m_owning_storage.get();
655 m_picker.reset(new piece_picker);
656 m_picker->init(m_torrent_file->piece_length() / m_block_size
657 , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
658 // assume that we don't have anything
659 m_files_checked = false;
660 set_state(torrent_status::queued_for_checking);
662 if (m_auto_managed)
663 set_queue_position((std::numeric_limits<int>::max)());
665 std::vector<char>().swap(m_resume_data);
666 lazy_entry().swap(m_resume_entry);
667 m_storage->async_check_fastresume(&m_resume_entry
668 , bind(&torrent::on_force_recheck
669 , shared_from_this(), _1, _2));
672 void torrent::on_force_recheck(int ret, disk_io_job const& j)
674 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
676 if (ret == piece_manager::fatal_disk_error)
678 if (m_ses.m_alerts.should_post<file_error_alert>())
680 m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
681 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
682 (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
683 " error: " << j.str <<
684 " torrent: " << torrent_file().name() <<
685 " ]\n";
686 #endif
688 m_error = j.str;
689 pause();
690 return;
692 m_ses.check_torrent(shared_from_this());
695 void torrent::start_checking()
697 set_state(torrent_status::checking_files);
699 m_storage->async_check_files(bind(
700 &torrent::on_piece_checked
701 , shared_from_this(), _1, _2));
704 void torrent::on_piece_checked(int ret, disk_io_job const& j)
706 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
708 if (ret == piece_manager::disk_check_aborted)
710 m_error = "aborted";
711 m_ses.done_checking(shared_from_this());
712 return;
714 if (ret == piece_manager::fatal_disk_error)
716 if (m_ses.m_alerts.should_post<file_error_alert>())
718 m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
719 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
720 (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
721 " error: " << j.str <<
722 " torrent: " << torrent_file().name() <<
723 " ]\n";
724 #endif
726 m_error = j.str;
727 pause();
728 m_ses.done_checking(shared_from_this());
729 return;
732 m_progress = j.piece / float(torrent_file().num_pieces());
734 TORRENT_ASSERT(m_picker);
735 if (j.offset >= 0 && !m_picker->have_piece(j.offset))
736 m_picker->we_have(j.offset);
738 // we're not done checking yet
739 // this handler will be called repeatedly until
740 // we're done, or encounter a failure
741 if (ret == piece_manager::need_full_check) return;
743 m_ses.done_checking(shared_from_this());
744 files_checked();
747 void torrent::use_interface(const char* net_interface)
749 INVARIANT_CHECK;
751 m_net_interface = tcp::endpoint(address::from_string(net_interface), 0);
754 void torrent::on_tracker_announce_disp(boost::weak_ptr<torrent> p
755 , error_code const& e)
757 if (e) return;
758 boost::shared_ptr<torrent> t = p.lock();
759 if (!t) return;
760 t->on_tracker_announce();
763 void torrent::on_tracker_announce()
765 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
767 if (m_abort) return;
768 announce_with_tracker();
771 void torrent::on_lsd_announce_disp(boost::weak_ptr<torrent> p
772 , error_code const& e)
774 if (e) return;
775 boost::shared_ptr<torrent> t = p.lock();
776 if (!t) return;
777 t->on_lsd_announce();
780 void torrent::on_lsd_announce()
782 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
784 if (m_abort) return;
786 TORRENT_ASSERT(!m_torrent_file->priv());
787 if (m_torrent_file->is_valid() && m_torrent_file->priv())
788 return;
790 if (is_paused()) return;
792 boost::weak_ptr<torrent> self(shared_from_this());
794 error_code ec;
796 // announce on local network every 5 minutes
797 m_lsd_announce_timer.expires_from_now(minutes(5), ec);
798 m_lsd_announce_timer.async_wait(
799 bind(&torrent::on_lsd_announce_disp, self, _1));
801 // announce with the local discovery service
802 m_ses.announce_lsd(m_torrent_file->info_hash());
804 #ifndef TORRENT_DISABLE_DHT
805 if (!m_ses.m_dht) return;
806 ptime now = time_now();
807 if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
809 m_last_dht_announce = now;
810 m_ses.m_dht->announce(m_torrent_file->info_hash()
811 , m_ses.m_listen_sockets.front().external_port
812 , bind(&torrent::on_dht_announce_response_disp, self, _1));
814 #endif
817 #ifndef TORRENT_DISABLE_DHT
819 void torrent::on_dht_announce_response_disp(boost::weak_ptr<libtorrent::torrent> t
820 , std::vector<tcp::endpoint> const& peers)
822 boost::shared_ptr<libtorrent::torrent> tor = t.lock();
823 if (!tor) return;
824 tor->on_dht_announce_response(peers);
827 void torrent::on_dht_announce_response(std::vector<tcp::endpoint> const& peers)
829 if (peers.empty()) return;
831 if (m_ses.m_alerts.should_post<dht_reply_alert>())
833 m_ses.m_alerts.post_alert(dht_reply_alert(
834 get_handle(), peers.size()));
836 std::for_each(peers.begin(), peers.end(), bind(
837 &policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0)
838 , peer_info::dht, 0));
841 #endif
843 void torrent::announce_with_tracker(tracker_request::event_t e)
845 INVARIANT_CHECK;
847 if (m_trackers.empty()) return;
849 restart_tracker_timer(time_now() + seconds(tracker_retry_delay_max));
851 if (e == tracker_request::none)
853 if (!m_start_sent) e = tracker_request::started;
854 if (!m_complete_sent && is_seed()) e = tracker_request::completed;
857 tracker_request req;
858 req.info_hash = m_torrent_file->info_hash();
859 req.pid = m_ses.get_peer_id();
860 req.downloaded = m_stat.total_payload_download();
861 req.uploaded = m_stat.total_payload_upload();
862 req.left = bytes_left();
863 if (req.left == -1) req.left = 16*1024;
864 req.event = e;
865 tcp::endpoint ep = m_ses.get_ipv6_interface();
866 if (ep != tcp::endpoint())
867 req.ipv6 = ep.address().to_string();
869 req.url = m_trackers[m_currently_trying_tracker].url;
870 // if we are aborting. we don't want any new peers
871 req.num_want = (req.event == tracker_request::stopped)
872 ?0:m_settings.num_want;
874 req.listen_port = m_ses.m_listen_sockets.empty()
875 ?0:m_ses.m_listen_sockets.front().external_port;
876 req.key = m_ses.m_key;
878 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
879 if (m_abort)
881 boost::shared_ptr<aux::tracker_logger> tl(new aux::tracker_logger(m_ses));
882 m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
883 , tracker_login(), m_ses.m_listen_interface.address(), tl);
885 else
886 #endif
887 m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
888 , tracker_login(), m_ses.m_listen_interface.address()
889 , m_abort?boost::shared_ptr<torrent>():shared_from_this());
891 if (m_ses.m_alerts.should_post<tracker_announce_alert>())
893 m_ses.m_alerts.post_alert(
894 tracker_announce_alert(get_handle(), req.url, req.event));
898 void torrent::scrape_tracker()
900 if (m_trackers.empty()) return;
902 TORRENT_ASSERT(m_currently_trying_tracker >= 0);
903 TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size()));
905 tracker_request req;
906 req.info_hash = m_torrent_file->info_hash();
907 req.kind = tracker_request::scrape_request;
908 req.url = m_trackers[m_currently_trying_tracker].url;
909 m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
910 , tracker_login(), m_ses.m_listen_interface.address(), shared_from_this());
912 m_last_scrape = time_now();
915 void torrent::tracker_warning(tracker_request const& req, std::string const& msg)
917 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
919 INVARIANT_CHECK;
921 if (m_ses.m_alerts.should_post<tracker_warning_alert>())
922 m_ses.m_alerts.post_alert(tracker_warning_alert(get_handle(), req.url, msg));
925 void torrent::tracker_scrape_response(tracker_request const& req
926 , int complete, int incomplete, int downloaded)
928 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
930 INVARIANT_CHECK;
931 TORRENT_ASSERT(req.kind == tracker_request::scrape_request);
933 if (complete >= 0) m_complete = complete;
934 if (incomplete >= 0) m_incomplete = incomplete;
936 if (m_ses.m_alerts.should_post<scrape_reply_alert>())
938 m_ses.m_alerts.post_alert(scrape_reply_alert(
939 get_handle(), m_incomplete, m_complete, req.url));
943 void torrent::tracker_response(
944 tracker_request const& r
945 , std::vector<peer_entry>& peer_list
946 , int interval
947 , int complete
948 , int incomplete
949 , address const& external_ip)
951 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
953 INVARIANT_CHECK;
954 TORRENT_ASSERT(r.kind == tracker_request::announce_request);
956 if (external_ip != address())
957 m_ses.set_external_address(external_ip);
959 if (!m_start_sent && r.event == tracker_request::started)
960 m_start_sent = true;
961 if (!m_complete_sent && r.event == tracker_request::completed)
962 m_complete_sent = true;
964 m_failed_trackers = 0;
965 // announce intervals less than 5 minutes
966 // are insane.
967 if (interval < 60 * 5) interval = 60 * 5;
969 m_last_working_tracker
970 = prioritize_tracker(m_currently_trying_tracker);
971 m_currently_trying_tracker = 0;
973 m_duration = interval;
974 restart_tracker_timer(time_now() + seconds(m_duration));
976 if (complete >= 0) m_complete = complete;
977 if (incomplete >= 0) m_incomplete = incomplete;
978 if (complete >= 0 && incomplete >= 0)
979 m_last_scrape = time_now();
981 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
982 std::stringstream s;
983 s << "TRACKER RESPONSE:\n"
984 "interval: " << m_duration << "\n"
985 "peers:\n";
986 for (std::vector<peer_entry>::const_iterator i = peer_list.begin();
987 i != peer_list.end(); ++i)
989 s << " " << std::setfill(' ') << std::setw(16) << i->ip
990 << " " << std::setw(5) << std::dec << i->port << " ";
991 if (!i->pid.is_all_zeros()) s << " " << i->pid << " " << identify_client(i->pid);
992 s << "\n";
994 s << "external ip: " << external_ip << "\n";
995 debug_log(s.str());
996 #endif
997 // for each of the peers we got from the tracker
998 for (std::vector<peer_entry>::iterator i = peer_list.begin();
999 i != peer_list.end(); ++i)
1001 // don't make connections to ourself
1002 if (i->pid == m_ses.get_peer_id())
1003 continue;
1005 error_code ec;
1006 tcp::endpoint a(address::from_string(i->ip, ec), i->port);
1008 if (ec)
1010 // assume this is because we got a hostname instead of
1011 // an ip address from the tracker
1013 tcp::resolver::query q(i->ip, boost::lexical_cast<std::string>(i->port));
1014 m_host_resolver.async_resolve(q,
1015 bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid));
1017 else
1019 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
1021 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
1022 debug_log("blocked ip from tracker: " + i->ip);
1023 #endif
1024 if (m_ses.m_alerts.should_post<peer_blocked_alert>())
1025 m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()));
1027 continue;
1030 m_policy.peer_from_tracker(a, i->pid, peer_info::tracker, 0);
1034 if (m_ses.m_alerts.should_post<tracker_reply_alert>())
1036 m_ses.m_alerts.post_alert(tracker_reply_alert(
1037 get_handle(), peer_list.size(), r.url));
1039 m_got_tracker_response = true;
1042 void torrent::on_peer_name_lookup(error_code const& e, tcp::resolver::iterator host
1043 , peer_id pid)
1045 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1047 INVARIANT_CHECK;
1049 if (e || host == tcp::resolver::iterator() ||
1050 m_ses.is_aborted()) return;
1052 if (m_ses.m_ip_filter.access(host->endpoint().address()) & ip_filter::blocked)
1054 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
1055 debug_log("blocked ip from tracker: " + host->endpoint().address().to_string());
1056 #endif
1057 if (m_ses.m_alerts.should_post<peer_blocked_alert>())
1059 m_ses.m_alerts.post_alert(peer_blocked_alert(host->endpoint().address()));
1062 return;
1065 m_policy.peer_from_tracker(*host, pid, peer_info::tracker, 0);
1068 size_type torrent::bytes_left() const
1070 // if we don't have the metadata yet, we
1071 // cannot tell how big the torrent is.
1072 if (!valid_metadata()) return -1;
1073 return m_torrent_file->total_size()
1074 - quantized_bytes_done();
1077 size_type torrent::quantized_bytes_done() const
1079 // INVARIANT_CHECK;
1081 if (!valid_metadata()) return 0;
1083 if (m_torrent_file->num_pieces() == 0)
1084 return 0;
1086 if (is_seed()) return m_torrent_file->total_size();
1088 const int last_piece = m_torrent_file->num_pieces() - 1;
1090 size_type total_done
1091 = size_type(num_have()) * m_torrent_file->piece_length();
1093 // if we have the last piece, we have to correct
1094 // the amount we have, since the first calculation
1095 // assumed all pieces were of equal size
1096 if (m_picker->have_piece(last_piece))
1098 int corr = m_torrent_file->piece_size(last_piece)
1099 - m_torrent_file->piece_length();
1100 total_done += corr;
1102 return total_done;
1105 // the first value is the total number of bytes downloaded
1106 // the second value is the number of bytes of those that haven't
1107 // been filtered as not wanted we have downloaded
1108 tuple<size_type, size_type> torrent::bytes_done() const
1110 INVARIANT_CHECK;
1112 if (!valid_metadata() || m_torrent_file->num_pieces() == 0)
1113 return tuple<size_type, size_type>(0,0);
1115 const int last_piece = m_torrent_file->num_pieces() - 1;
1116 const int piece_size = m_torrent_file->piece_length();
1118 if (is_seed())
1119 return make_tuple(m_torrent_file->total_size()
1120 , m_torrent_file->total_size());
1122 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1123 size_type wanted_done = size_type(num_have() - m_picker->num_have_filtered())
1124 * piece_size;
1125 TORRENT_ASSERT(wanted_done >= 0);
1127 size_type total_done
1128 = size_type(num_have()) * piece_size;
1129 TORRENT_ASSERT(num_have() < m_torrent_file->num_pieces());
1131 // if we have the last piece, we have to correct
1132 // the amount we have, since the first calculation
1133 // assumed all pieces were of equal size
1134 if (m_picker->have_piece(last_piece))
1136 TORRENT_ASSERT(total_done >= piece_size);
1137 int corr = m_torrent_file->piece_size(last_piece)
1138 - piece_size;
1139 TORRENT_ASSERT(corr <= 0);
1140 TORRENT_ASSERT(corr > -piece_size);
1141 total_done += corr;
1142 if (m_picker->piece_priority(last_piece) != 0)
1144 TORRENT_ASSERT(wanted_done >= piece_size);
1145 wanted_done += corr;
1149 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1150 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1151 TORRENT_ASSERT(total_done >= wanted_done);
1153 const std::vector<piece_picker::downloading_piece>& dl_queue
1154 = m_picker->get_download_queue();
1156 const int blocks_per_piece = piece_size / m_block_size;
1158 for (std::vector<piece_picker::downloading_piece>::const_iterator i =
1159 dl_queue.begin(); i != dl_queue.end(); ++i)
1161 int corr = 0;
1162 int index = i->index;
1163 if (m_picker->have_piece(index)) continue;
1164 TORRENT_ASSERT(i->finished <= m_picker->blocks_in_piece(index));
1166 #ifndef NDEBUG
1167 for (std::vector<piece_picker::downloading_piece>::const_iterator j = boost::next(i);
1168 j != dl_queue.end(); ++j)
1170 TORRENT_ASSERT(j->index != index);
1172 #endif
1174 for (int j = 0; j < blocks_per_piece; ++j)
1176 TORRENT_ASSERT(m_picker->is_finished(piece_block(index, j)) == (i->info[j].state == piece_picker::block_info::state_finished));
1177 corr += (i->info[j].state == piece_picker::block_info::state_finished) * m_block_size;
1178 TORRENT_ASSERT(corr >= 0);
1179 TORRENT_ASSERT(index != last_piece || j < m_picker->blocks_in_last_piece()
1180 || i->info[j].state != piece_picker::block_info::state_finished);
1183 // correction if this was the last piece
1184 // and if we have the last block
1185 if (i->index == last_piece
1186 && i->info[m_picker->blocks_in_last_piece()-1].state
1187 == piece_picker::block_info::state_finished)
1189 corr -= m_block_size;
1190 corr += m_torrent_file->piece_size(last_piece) % m_block_size;
1192 total_done += corr;
1193 if (m_picker->piece_priority(index) != 0)
1194 wanted_done += corr;
1197 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1198 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1200 std::map<piece_block, int> downloading_piece;
1201 for (const_peer_iterator i = begin(); i != end(); ++i)
1203 peer_connection* pc = *i;
1204 boost::optional<piece_block_progress> p
1205 = pc->downloading_piece_progress();
1206 if (p)
1208 if (m_picker->have_piece(p->piece_index))
1209 continue;
1211 piece_block block(p->piece_index, p->block_index);
1212 if (m_picker->is_finished(block))
1213 continue;
1215 std::map<piece_block, int>::iterator dp
1216 = downloading_piece.find(block);
1217 if (dp != downloading_piece.end())
1219 if (dp->second < p->bytes_downloaded)
1220 dp->second = p->bytes_downloaded;
1222 else
1224 downloading_piece[block] = p->bytes_downloaded;
1226 #ifndef NDEBUG
1227 TORRENT_ASSERT(p->bytes_downloaded <= p->full_block_bytes);
1228 int last_piece = m_torrent_file->num_pieces() - 1;
1229 if (p->piece_index == last_piece
1230 && p->block_index == m_torrent_file->piece_size(last_piece) / block_size())
1231 TORRENT_ASSERT(p->full_block_bytes == m_torrent_file->piece_size(last_piece) % block_size());
1232 else
1233 TORRENT_ASSERT(p->full_block_bytes == block_size());
1234 #endif
1237 for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
1238 i != downloading_piece.end(); ++i)
1240 total_done += i->second;
1241 if (m_picker->piece_priority(i->first.piece_index) != 0)
1242 wanted_done += i->second;
1245 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1246 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1248 #ifndef NDEBUG
1250 if (total_done >= m_torrent_file->total_size())
1252 // Thist happens when a piece has been downloaded completely
1253 // but not yet verified against the hash
1254 std::cerr << "num_have: " << num_have() << std::endl;
1256 std::cerr << "unfinished:" << std::endl;
1258 for (std::vector<piece_picker::downloading_piece>::const_iterator i =
1259 dl_queue.begin(); i != dl_queue.end(); ++i)
1261 std::cerr << " " << i->index << " ";
1262 for (int j = 0; j < blocks_per_piece; ++j)
1264 std::cerr << (i->info[j].state == piece_picker::block_info::state_finished ? "1" : "0");
1266 std::cerr << std::endl;
1269 std::cerr << "downloading pieces:" << std::endl;
1271 for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
1272 i != downloading_piece.end(); ++i)
1274 std::cerr << " " << i->first.piece_index << ":" << i->first.block_index
1275 << " " << i->second << std::endl;
1280 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1281 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1283 #endif
1285 TORRENT_ASSERT(total_done >= wanted_done);
1286 return make_tuple(total_done, wanted_done);
1289 // passed_hash_check
1290 // 0: success, piece passed check
1291 // -1: disk failure
1292 // -2: piece failed check
1293 void torrent::piece_finished(int index, int passed_hash_check)
1295 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1297 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
1298 (*m_ses.m_logger) << time_now_string() << " *** PIECE_FINISHED [ p: "
1299 << index << " chk: " << ((passed_hash_check == 0)
1300 ?"passed":passed_hash_check == -1
1301 ?"disk failed":"failed") << " ]\n";
1302 #endif
1304 TORRENT_ASSERT(valid_metadata());
1306 if (passed_hash_check == 0)
1308 // the following call may cause picker to become invalid
1309 // in case we just became a seed
1310 piece_passed(index);
1312 else if (passed_hash_check == -2)
1314 // piece_failed() will restore the piece
1315 piece_failed(index);
1317 else
1319 TORRENT_ASSERT(passed_hash_check == -1);
1320 m_picker->restore_piece(index);
1321 restore_piece_state(index);
1325 void torrent::piece_passed(int index)
1327 // INVARIANT_CHECK;
1329 TORRENT_ASSERT(index >= 0);
1330 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1332 if (m_ses.m_alerts.should_post<piece_finished_alert>())
1334 m_ses.m_alerts.post_alert(piece_finished_alert(get_handle()
1335 , index));
1338 bool was_finished = m_picker->num_filtered() + num_have()
1339 == torrent_file().num_pieces();
1341 std::vector<void*> downloaders;
1342 m_picker->get_downloaders(downloaders, index);
1344 // increase the trust point of all peers that sent
1345 // parts of this piece.
1346 std::set<void*> peers;
1347 std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
1349 m_picker->we_have(index);
1350 for (peer_iterator i = m_connections.begin(); i != m_connections.end();)
1352 peer_connection* p = *i;
1353 ++i;
1354 p->announce_piece(index);
1357 for (std::set<void*>::iterator i = peers.begin()
1358 , end(peers.end()); i != end; ++i)
1360 policy::peer* p = static_cast<policy::peer*>(*i);
1361 if (p == 0) continue;
1362 p->on_parole = false;
1363 ++p->trust_points;
1364 // TODO: make this limit user settable
1365 if (p->trust_points > 20) p->trust_points = 20;
1366 if (p->connection) p->connection->received_valid_data(index);
1369 #ifndef TORRENT_DISABLE_EXTENSIONS
1370 for (extension_list_t::iterator i = m_extensions.begin()
1371 , end(m_extensions.end()); i != end; ++i)
1373 #ifndef BOOST_NO_EXCEPTIONS
1374 try {
1375 #endif
1376 (*i)->on_piece_pass(index);
1377 #ifndef BOOST_NO_EXCEPTIONS
1378 } catch (std::exception&) {}
1379 #endif
1381 #endif
1383 // since this piece just passed, we might have
1384 // become uninterested in some peers where this
1385 // was the last piece we were interested in
1386 for (peer_iterator i = m_connections.begin()
1387 , end(m_connections.end()); i != end; ++i)
1389 peer_connection* p = *i;
1390 // if we're not interested already, no need to check
1391 if (!p->is_interesting()) continue;
1392 // if the peer doesn't have the piece we just got, it
1393 // wouldn't affect our interest
1394 if (!p->has_piece(index)) continue;
1395 p->update_interest();
1398 if (!was_finished && is_finished())
1400 // torrent finished
1401 // i.e. all the pieces we're interested in have
1402 // been downloaded. Release the files (they will open
1403 // in read only mode if needed)
1404 finished();
1405 // if we just became a seed, picker is now invalid, since it
1406 // is deallocated by the torrent once it starts seeding
1410 void torrent::piece_failed(int index)
1412 // if the last piece fails the peer connection will still
1413 // think that it has received all of it until this function
1414 // resets the download queue. So, we cannot do the
1415 // invariant check here since it assumes:
1416 // (total_done == m_torrent_file->total_size()) => is_seed()
1417 INVARIANT_CHECK;
1419 TORRENT_ASSERT(m_storage);
1420 TORRENT_ASSERT(m_storage->refcount() > 0);
1421 TORRENT_ASSERT(m_picker.get());
1422 TORRENT_ASSERT(index >= 0);
1423 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1425 if (m_ses.m_alerts.should_post<hash_failed_alert>())
1426 m_ses.m_alerts.post_alert(hash_failed_alert(get_handle(), index));
1428 // increase the total amount of failed bytes
1429 add_failed_bytes(m_torrent_file->piece_size(index));
1431 std::vector<void*> downloaders;
1432 m_picker->get_downloaders(downloaders, index);
1434 // decrease the trust point of all peers that sent
1435 // parts of this piece.
1436 // first, build a set of all peers that participated
1437 std::set<void*> peers;
1438 std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
1440 #ifndef NDEBUG
1441 for (std::vector<void*>::iterator i = downloaders.begin()
1442 , end(downloaders.end()); i != end; ++i)
1444 policy::peer* p = (policy::peer*)*i;
1445 if (p && p->connection)
1447 p->connection->piece_failed = true;
1450 #endif
1452 #ifndef TORRENT_DISABLE_EXTENSIONS
1453 for (extension_list_t::iterator i = m_extensions.begin()
1454 , end(m_extensions.end()); i != end; ++i)
1456 #ifndef BOOST_NO_EXCEPTIONS
1457 try {
1458 #endif
1459 (*i)->on_piece_failed(index);
1460 #ifndef BOOST_NO_EXCEPTIONS
1461 } catch (std::exception&) {}
1462 #endif
1464 #endif
1466 for (std::set<void*>::iterator i = peers.begin()
1467 , end(peers.end()); i != end; ++i)
1469 policy::peer* p = static_cast<policy::peer*>(*i);
1470 if (p == 0) continue;
1471 if (p->connection) p->connection->received_invalid_data(index);
1473 // either, we have received too many failed hashes
1474 // or this was the only peer that sent us this piece.
1475 // TODO: make this a changable setting
1476 if (p->trust_points <= -7
1477 || peers.size() == 1)
1479 // we don't trust this peer anymore
1480 // ban it.
1481 if (m_ses.m_alerts.should_post<peer_ban_alert>())
1483 peer_id pid;
1484 if (p->connection) pid = p->connection->pid();
1485 m_ses.m_alerts.post_alert(peer_ban_alert(
1486 get_handle(), p->ip(), pid));
1489 // mark the peer as banned
1490 p->banned = true;
1492 if (p->connection)
1494 #ifdef TORRENT_LOGGING
1495 (*m_ses.m_logger) << time_now_string() << " *** BANNING PEER [ " << p->ip()
1496 << " ] 'too many corrupt pieces'\n";
1497 #endif
1498 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
1499 (*p->connection->m_logger) << "*** BANNING PEER [ " << p->ip()
1500 << " ] 'too many corrupt pieces'\n";
1501 #endif
1502 p->connection->disconnect("too many corrupt pieces, banning peer");
1507 // we have to let the piece_picker know that
1508 // this piece failed the check as it can restore it
1509 // and mark it as being interesting for download
1510 // TODO: do this more intelligently! and keep track
1511 // of how much crap (data that failed hash-check) and
1512 // how much redundant data we have downloaded
1513 // if some clients has sent more than one piece
1514 // start with redownloading the pieces that the client
1515 // that has sent the least number of pieces
1516 m_picker->restore_piece(index);
1517 restore_piece_state(index);
1518 TORRENT_ASSERT(m_storage);
1520 TORRENT_ASSERT(m_picker->have_piece(index) == false);
1522 #ifndef NDEBUG
1523 for (std::vector<void*>::iterator i = downloaders.begin()
1524 , end(downloaders.end()); i != end; ++i)
1526 policy::peer* p = (policy::peer*)*i;
1527 if (p && p->connection)
1529 p->connection->piece_failed = false;
1532 #endif
1535 void torrent::restore_piece_state(int index)
1537 TORRENT_ASSERT(has_picker());
1538 for (peer_iterator i = m_connections.begin();
1539 i != m_connections.end(); ++i)
1541 peer_connection* p = *i;
1542 std::deque<pending_block> const& dq = p->download_queue();
1543 std::deque<piece_block> const& rq = p->request_queue();
1544 for (std::deque<pending_block>::const_iterator k = dq.begin()
1545 , end(dq.end()); k != end; ++k)
1547 if (k->block.piece_index != index) continue;
1548 m_picker->mark_as_downloading(k->block, p->peer_info_struct()
1549 , (piece_picker::piece_state_t)p->peer_speed());
1551 for (std::deque<piece_block>::const_iterator k = rq.begin()
1552 , end(rq.end()); k != end; ++k)
1554 if (k->piece_index != index) continue;
1555 m_picker->mark_as_downloading(*k, p->peer_info_struct()
1556 , (piece_picker::piece_state_t)p->peer_speed());
1561 void torrent::abort()
1563 INVARIANT_CHECK;
1565 m_abort = true;
1566 // if the torrent is paused, it doesn't need
1567 // to announce with even=stopped again.
1568 if (!is_paused())
1570 stop_announcing();
1573 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
1574 for (peer_iterator i = m_connections.begin();
1575 i != m_connections.end(); ++i)
1577 (*(*i)->m_logger) << "*** ABORTING TORRENT\n";
1579 #endif
1581 // disconnect all peers and close all
1582 // files belonging to the torrents
1583 disconnect_all();
1584 if (m_owning_storage.get())
1585 m_storage->async_release_files(
1586 bind(&torrent::on_files_released, shared_from_this(), _1, _2));
1588 m_owning_storage = 0;
1589 m_host_resolver.cancel();
1592 void torrent::on_files_deleted(int ret, disk_io_job const& j)
1594 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1596 if (ret != 0)
1598 if (alerts().should_post<torrent_delete_failed_alert>())
1599 alerts().post_alert(torrent_delete_failed_alert(get_handle(), j.str));
1601 else
1603 if (alerts().should_post<torrent_deleted_alert>())
1604 alerts().post_alert(torrent_deleted_alert(get_handle()));
1608 void torrent::on_files_released(int ret, disk_io_job const& j)
1611 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1613 if (alerts().should_post<torrent_paused_alert>())
1615 alerts().post_alert(torrent_paused_alert(get_handle()));
1620 void torrent::on_save_resume_data(int ret, disk_io_job const& j)
1622 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1624 if (!j.resume_data && alerts().should_post<save_resume_data_failed_alert>())
1626 alerts().post_alert(save_resume_data_failed_alert(get_handle(), j.str));
1627 return;
1630 if (j.resume_data && alerts().should_post<save_resume_data_alert>())
1632 write_resume_data(*j.resume_data);
1633 alerts().post_alert(save_resume_data_alert(j.resume_data
1634 , get_handle()));
1638 void torrent::on_file_renamed(int ret, disk_io_job const& j)
1640 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1643 if (ret == 0)
1645 if (alerts().should_post<file_renamed_alert>())
1646 alerts().post_alert(file_renamed_alert(get_handle(), j.str, j.piece));
1648 else
1650 if (alerts().should_post<file_rename_failed_alert>())
1651 alerts().post_alert(file_rename_failed_alert(get_handle(), j.str, j.piece));
1656 void torrent::on_torrent_paused(int ret, disk_io_job const& j)
1658 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1660 if (alerts().should_post<torrent_paused_alert>())
1661 alerts().post_alert(torrent_paused_alert(get_handle()));
1664 std::string torrent::tracker_login() const
1666 if (m_username.empty() && m_password.empty()) return "";
1667 return m_username + ":" + m_password;
1670 void torrent::piece_availability(std::vector<int>& avail) const
1672 INVARIANT_CHECK;
1674 TORRENT_ASSERT(valid_metadata());
1675 if (is_seed())
1677 avail.clear();
1678 return;
1681 m_picker->get_availability(avail);
1684 void torrent::set_piece_priority(int index, int priority)
1686 // INVARIANT_CHECK;
1688 TORRENT_ASSERT(valid_metadata());
1689 if (is_seed()) return;
1691 // this call is only valid on torrents with metadata
1692 TORRENT_ASSERT(m_picker.get());
1693 TORRENT_ASSERT(index >= 0);
1694 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1696 bool was_finished = is_finished();
1697 bool filter_updated = m_picker->set_piece_priority(index, priority);
1698 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1699 if (filter_updated) update_peer_interest(was_finished);
1702 int torrent::piece_priority(int index) const
1704 // INVARIANT_CHECK;
1706 TORRENT_ASSERT(valid_metadata());
1707 if (is_seed()) return 1;
1709 // this call is only valid on torrents with metadata
1710 TORRENT_ASSERT(m_picker.get());
1711 TORRENT_ASSERT(index >= 0);
1712 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1714 return m_picker->piece_priority(index);
1717 void torrent::prioritize_pieces(std::vector<int> const& pieces)
1719 INVARIANT_CHECK;
1721 // this call is only valid on torrents with metadata
1722 TORRENT_ASSERT(valid_metadata());
1723 if (is_seed()) return;
1725 TORRENT_ASSERT(m_picker.get());
1727 int index = 0;
1728 bool filter_updated = false;
1729 bool was_finished = is_finished();
1730 for (std::vector<int>::const_iterator i = pieces.begin()
1731 , end(pieces.end()); i != end; ++i, ++index)
1733 TORRENT_ASSERT(*i >= 0);
1734 TORRENT_ASSERT(*i <= 7);
1735 filter_updated |= m_picker->set_piece_priority(index, *i);
1736 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1738 if (filter_updated) update_peer_interest(was_finished);
1741 void torrent::piece_priorities(std::vector<int>& pieces) const
1743 INVARIANT_CHECK;
1745 // this call is only valid on torrents with metadata
1746 TORRENT_ASSERT(valid_metadata());
1747 if (is_seed())
1749 pieces.clear();
1750 pieces.resize(m_torrent_file->num_pieces(), 1);
1751 return;
1754 TORRENT_ASSERT(m_picker.get());
1755 m_picker->piece_priorities(pieces);
1758 namespace
1760 void set_if_greater(int& piece_prio, int file_prio)
1762 if (file_prio > piece_prio) piece_prio = file_prio;
1766 void torrent::prioritize_files(std::vector<int> const& files)
1768 INVARIANT_CHECK;
1770 // this call is only valid on torrents with metadata
1771 if (!valid_metadata() || is_seed()) return;
1773 // the bitmask need to have exactly one bit for every file
1774 // in the torrent
1775 TORRENT_ASSERT(int(files.size()) == m_torrent_file->num_files());
1777 if (m_torrent_file->num_pieces() == 0) return;
1779 std::copy(files.begin(), files.end(), m_file_priority.begin());
1780 update_piece_priorities();
1783 void torrent::set_file_priority(int index, int prio)
1785 INVARIANT_CHECK;
1786 TORRENT_ASSERT(index < m_torrent_file->num_files());
1787 TORRENT_ASSERT(index >= 0);
1788 if (m_file_priority[index] == prio) return;
1789 m_file_priority[index] = prio;
1790 update_piece_priorities();
1793 int torrent::file_priority(int index) const
1795 TORRENT_ASSERT(index < m_torrent_file->num_files());
1796 TORRENT_ASSERT(index >= 0);
1797 return m_file_priority[index];
1800 void torrent::file_priorities(std::vector<int>& files) const
1802 INVARIANT_CHECK;
1803 files.resize(m_file_priority.size());
1804 std::copy(m_file_priority.begin(), m_file_priority.end(), files.begin());
1807 void torrent::update_piece_priorities()
1809 INVARIANT_CHECK;
1811 if (m_torrent_file->num_pieces() == 0) return;
1812 bool was_finished = is_finished();
1814 size_type position = 0;
1815 int piece_length = m_torrent_file->piece_length();
1816 // initialize the piece priorities to 0, then only allow
1817 // setting higher priorities
1818 std::vector<int> pieces(m_torrent_file->num_pieces(), 0);
1819 for (int i = 0; i < int(m_file_priority.size()); ++i)
1821 size_type start = position;
1822 size_type size = m_torrent_file->files().at(i).size;
1823 if (size == 0) continue;
1824 position += size;
1825 // mark all pieces of the file with this file's priority
1826 // but only if the priority is higher than the pieces
1827 // already set (to avoid problems with overlapping pieces)
1828 int start_piece = int(start / piece_length);
1829 int last_piece = int((position - 1) / piece_length);
1830 TORRENT_ASSERT(last_piece < int(pieces.size()));
1831 // if one piece spans several files, we might
1832 // come here several times with the same start_piece, end_piece
1833 std::for_each(pieces.begin() + start_piece
1834 , pieces.begin() + last_piece + 1
1835 , bind(&set_if_greater, _1, m_file_priority[i]));
1837 prioritize_pieces(pieces);
1838 update_peer_interest(was_finished);
1841 // this is called when piece priorities have been updated
1842 // updates the interested flag in peers
1843 void torrent::update_peer_interest(bool was_finished)
1845 for (peer_iterator i = begin(); i != end(); ++i)
1846 (*i)->update_interest();
1848 // if we used to be finished, but we aren't anymore
1849 // we may need to connect to peers again
1850 if (!is_finished() && was_finished)
1851 m_policy.recalculate_connect_candidates();
1853 // the torrent just became finished
1854 if (is_finished() && !was_finished)
1855 finished();
1856 else if (!is_finished() && was_finished)
1857 resume_download();
1860 void torrent::filter_piece(int index, bool filter)
1862 INVARIANT_CHECK;
1864 TORRENT_ASSERT(valid_metadata());
1865 if (is_seed()) return;
1867 // this call is only valid on torrents with metadata
1868 TORRENT_ASSERT(m_picker.get());
1869 TORRENT_ASSERT(index >= 0);
1870 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1872 bool was_finished = is_finished();
1873 m_picker->set_piece_priority(index, filter ? 1 : 0);
1874 update_peer_interest(was_finished);
1877 void torrent::filter_pieces(std::vector<bool> const& bitmask)
1879 INVARIANT_CHECK;
1881 // this call is only valid on torrents with metadata
1882 TORRENT_ASSERT(valid_metadata());
1883 if (is_seed()) return;
1885 TORRENT_ASSERT(m_picker.get());
1887 bool was_finished = is_finished();
1888 int index = 0;
1889 for (std::vector<bool>::const_iterator i = bitmask.begin()
1890 , end(bitmask.end()); i != end; ++i, ++index)
1892 if ((m_picker->piece_priority(index) == 0) == *i) continue;
1893 if (*i)
1894 m_picker->set_piece_priority(index, 0);
1895 else
1896 m_picker->set_piece_priority(index, 1);
1898 update_peer_interest(was_finished);
1901 bool torrent::is_piece_filtered(int index) const
1903 // this call is only valid on torrents with metadata
1904 TORRENT_ASSERT(valid_metadata());
1905 if (is_seed()) return false;
1907 TORRENT_ASSERT(m_picker.get());
1908 TORRENT_ASSERT(index >= 0);
1909 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1911 return m_picker->piece_priority(index) == 0;
1914 void torrent::filtered_pieces(std::vector<bool>& bitmask) const
1916 INVARIANT_CHECK;
1918 // this call is only valid on torrents with metadata
1919 TORRENT_ASSERT(valid_metadata());
1920 if (is_seed())
1922 bitmask.clear();
1923 bitmask.resize(m_torrent_file->num_pieces(), false);
1924 return;
1927 TORRENT_ASSERT(m_picker.get());
1928 m_picker->filtered_pieces(bitmask);
1931 void torrent::filter_files(std::vector<bool> const& bitmask)
1933 INVARIANT_CHECK;
1935 // this call is only valid on torrents with metadata
1936 if (!valid_metadata() || is_seed()) return;
1938 // the bitmask need to have exactly one bit for every file
1939 // in the torrent
1940 TORRENT_ASSERT((int)bitmask.size() == m_torrent_file->num_files());
1942 size_type position = 0;
1944 if (m_torrent_file->num_pieces())
1946 int piece_length = m_torrent_file->piece_length();
1947 // mark all pieces as filtered, then clear the bits for files
1948 // that should be downloaded
1949 std::vector<bool> piece_filter(m_torrent_file->num_pieces(), true);
1950 for (int i = 0; i < (int)bitmask.size(); ++i)
1952 size_type start = position;
1953 position += m_torrent_file->files().at(i).size;
1954 // is the file selected for download?
1955 if (!bitmask[i])
1957 // mark all pieces of the file as downloadable
1958 int start_piece = int(start / piece_length);
1959 int last_piece = int(position / piece_length);
1960 // if one piece spans several files, we might
1961 // come here several times with the same start_piece, end_piece
1962 std::fill(piece_filter.begin() + start_piece, piece_filter.begin()
1963 + last_piece + 1, false);
1966 filter_pieces(piece_filter);
1970 void torrent::replace_trackers(std::vector<announce_entry> const& urls)
1972 m_trackers = urls;
1973 if (m_currently_trying_tracker >= (int)m_trackers.size())
1974 m_currently_trying_tracker = (int)m_trackers.size()-1;
1975 m_last_working_tracker = -1;
1978 void torrent::choke_peer(peer_connection& c)
1980 INVARIANT_CHECK;
1982 TORRENT_ASSERT(!c.is_choked());
1983 TORRENT_ASSERT(m_num_uploads > 0);
1984 c.send_choke();
1985 --m_num_uploads;
1988 bool torrent::unchoke_peer(peer_connection& c)
1990 INVARIANT_CHECK;
1992 TORRENT_ASSERT(c.is_choked());
1993 if (m_num_uploads >= m_max_uploads) return false;
1994 c.send_unchoke();
1995 ++m_num_uploads;
1996 return true;
1999 void torrent::cancel_block(piece_block block)
2001 INVARIANT_CHECK;
2003 for (peer_iterator i = m_connections.begin()
2004 , end(m_connections.end()); i != end; ++i)
2006 (*i)->cancel_request(block);
2010 void torrent::remove_peer(peer_connection* p)
2012 // INVARIANT_CHECK;
2014 TORRENT_ASSERT(p != 0);
2016 peer_iterator i = m_connections.find(p);
2017 if (i == m_connections.end())
2019 TORRENT_ASSERT(false);
2020 return;
2023 if (ready_for_connections())
2025 TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
2027 if (p->is_seed())
2029 if (m_picker.get())
2031 m_picker->dec_refcount_all();
2034 else
2036 if (m_picker.get())
2038 bitfield const& pieces = p->get_bitfield();
2039 TORRENT_ASSERT(pieces.count() < int(pieces.size()));
2040 m_picker->dec_refcount(pieces);
2045 if (!p->is_choked())
2046 --m_num_uploads;
2048 m_policy.connection_closed(*p);
2049 p->set_peer_info(0);
2050 TORRENT_ASSERT(i != m_connections.end());
2051 m_connections.erase(i);
2053 // remove from bandwidth request-queue
2054 for (int c = 0; c < 2; ++c)
2056 for (queue_t::iterator i = m_bandwidth_queue[c].begin()
2057 , end(m_bandwidth_queue[c].end()); i != end; ++i)
2059 if (i->peer != p) continue;
2060 m_bandwidth_queue[c].erase(i);
2061 break;
2066 void torrent::connect_to_url_seed(std::string const& url)
2068 INVARIANT_CHECK;
2070 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2071 (*m_ses.m_logger) << time_now_string() << " resolving web seed: " << url << "\n";
2072 #endif
2074 std::string protocol;
2075 std::string auth;
2076 std::string hostname;
2077 int port;
2078 std::string path;
2079 char const* error;
2080 boost::tie(protocol, auth, hostname, port, path, error)
2081 = parse_url_components(url);
2083 if (error)
2085 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2086 (*m_ses.m_logger) << time_now_string() << " failed to parse web seed url: " << error << "\n";
2087 #endif
2088 // never try it again
2089 remove_url_seed(url);
2090 return;
2093 #ifdef TORRENT_USE_OPENSSL
2094 if (protocol != "http" && protocol != "https")
2095 #else
2096 if (protocol != "http")
2097 #endif
2099 if (m_ses.m_alerts.should_post<url_seed_alert>())
2101 m_ses.m_alerts.post_alert(
2102 url_seed_alert(get_handle(), url, "unknown protocol"));
2104 // never try it again
2105 remove_url_seed(url);
2106 return;
2109 if (hostname.empty())
2111 if (m_ses.m_alerts.should_post<url_seed_alert>())
2113 m_ses.m_alerts.post_alert(
2114 url_seed_alert(get_handle(), url, "invalid hostname"));
2116 // never try it again
2117 remove_url_seed(url);
2118 return;
2121 if (port == 0)
2123 if (m_ses.m_alerts.should_post<url_seed_alert>())
2125 m_ses.m_alerts.post_alert(
2126 url_seed_alert(get_handle(), url, "invalid port"));
2128 // never try it again
2129 remove_url_seed(url);
2130 return;
2133 m_resolving_web_seeds.insert(url);
2134 proxy_settings const& ps = m_ses.web_seed_proxy();
2135 if (ps.type == proxy_settings::http
2136 || ps.type == proxy_settings::http_pw)
2138 // use proxy
2139 tcp::resolver::query q(ps.hostname
2140 , boost::lexical_cast<std::string>(ps.port));
2141 m_host_resolver.async_resolve(q,
2142 bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, url));
2144 else
2146 if (m_ses.m_port_filter.access(port) & port_filter::blocked)
2148 if (m_ses.m_alerts.should_post<url_seed_alert>())
2150 m_ses.m_alerts.post_alert(
2151 url_seed_alert(get_handle(), url, "port blocked by port-filter"));
2153 // never try it again
2154 remove_url_seed(url);
2155 return;
2158 tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
2159 m_host_resolver.async_resolve(q,
2160 bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url
2161 , tcp::endpoint()));
2166 void torrent::on_proxy_name_lookup(error_code const& e, tcp::resolver::iterator host
2167 , std::string url)
2169 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2171 INVARIANT_CHECK;
2173 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2174 (*m_ses.m_logger) << time_now_string() << " completed resolve proxy hostname for: " << url << "\n";
2175 #endif
2177 if (e || host == tcp::resolver::iterator())
2179 if (m_ses.m_alerts.should_post<url_seed_alert>())
2181 m_ses.m_alerts.post_alert(
2182 url_seed_alert(get_handle(), url, e.message()));
2185 // the name lookup failed for the http host. Don't try
2186 // this host again
2187 remove_url_seed(url);
2188 return;
2191 if (m_ses.is_aborted()) return;
2193 tcp::endpoint a(host->endpoint());
2195 using boost::tuples::ignore;
2196 std::string hostname;
2197 int port;
2198 char const* error;
2199 boost::tie(ignore, ignore, hostname, port, ignore, error)
2200 = parse_url_components(url);
2202 if (error)
2204 if (m_ses.m_alerts.should_post<url_seed_alert>())
2206 m_ses.m_alerts.post_alert(
2207 url_seed_alert(get_handle(), url, error));
2209 remove_url_seed(url);
2210 return;
2213 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
2215 if (m_ses.m_alerts.should_post<peer_blocked_alert>())
2216 m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()));
2217 return;
2220 tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
2221 m_host_resolver.async_resolve(q,
2222 bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url, a));
2225 void torrent::on_name_lookup(error_code const& e, tcp::resolver::iterator host
2226 , std::string url, tcp::endpoint proxy)
2228 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2230 INVARIANT_CHECK;
2232 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2233 (*m_ses.m_logger) << time_now_string() << " completed resolve: " << url << "\n";
2234 #endif
2236 std::set<std::string>::iterator i = m_resolving_web_seeds.find(url);
2237 if (i != m_resolving_web_seeds.end()) m_resolving_web_seeds.erase(i);
2239 if (e || host == tcp::resolver::iterator())
2241 if (m_ses.m_alerts.should_post<url_seed_alert>())
2243 std::stringstream msg;
2244 msg << "HTTP seed hostname lookup failed: " << e.message();
2245 m_ses.m_alerts.post_alert(
2246 url_seed_alert(get_handle(), url, msg.str()));
2248 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2249 (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << url << "\n";
2250 #endif
2252 // the name lookup failed for the http host. Don't try
2253 // this host again
2254 remove_url_seed(url);
2255 return;
2258 if (m_ses.is_aborted()) return;
2260 tcp::endpoint a(host->endpoint());
2262 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
2264 if (m_ses.m_alerts.should_post<peer_blocked_alert>())
2265 m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()));
2266 return;
2269 boost::shared_ptr<socket_type> s(new (std::nothrow) socket_type(m_ses.m_io_service));
2270 if (!s) return;
2272 bool ret = instantiate_connection(m_ses.m_io_service, m_ses.web_seed_proxy(), *s);
2273 TORRENT_ASSERT(ret);
2275 if (m_ses.web_seed_proxy().type == proxy_settings::http
2276 || m_ses.web_seed_proxy().type == proxy_settings::http_pw)
2278 // the web seed connection will talk immediately to
2279 // the proxy, without requiring CONNECT support
2280 s->get<http_stream>().set_no_connect(true);
2283 std::pair<int, int> const& out_ports = m_settings.outgoing_ports;
2284 error_code ec;
2285 if (out_ports.first > 0 && out_ports.second >= out_ports.first)
2286 s->bind(tcp::endpoint(address(), m_ses.next_port()), ec);
2288 boost::intrusive_ptr<peer_connection> c(new (std::nothrow) web_peer_connection(
2289 m_ses, shared_from_this(), s, a, url, 0));
2290 if (!c) return;
2292 #ifndef NDEBUG
2293 c->m_in_constructor = false;
2294 #endif
2296 #ifndef TORRENT_DISABLE_EXTENSIONS
2297 for (extension_list_t::iterator i = m_extensions.begin()
2298 , end(m_extensions.end()); i != end; ++i)
2300 boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
2301 if (pp) c->add_extension(pp);
2303 #endif
2305 // add the newly connected peer to this torrent's peer list
2306 m_connections.insert(boost::get_pointer(c));
2307 m_ses.m_connections.insert(c);
2309 #ifndef BOOST_NO_EXCEPTIONS
2312 #endif
2313 // add the newly connected peer to this torrent's peer list
2314 m_connections.insert(boost::get_pointer(c));
2315 m_ses.m_connections.insert(c);
2316 c->start();
2318 m_ses.m_half_open.enqueue(
2319 bind(&peer_connection::connect, c, _1)
2320 , bind(&peer_connection::timed_out, c)
2321 , seconds(settings().peer_connect_timeout));
2322 #ifndef BOOST_NO_EXCEPTIONS
2324 catch (std::exception& e)
2326 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2327 (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n";
2328 #endif
2329 c->disconnect(e.what(), 1);
2331 #endif
2334 #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
2335 namespace
2337 unsigned long swap_bytes(unsigned long a)
2339 return (a >> 24) | ((a & 0xff0000) >> 8) | ((a & 0xff00) << 8) | (a << 24);
2343 void torrent::resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const
2345 if (m_resolving_country
2346 || p->has_country()
2347 || p->is_connecting()
2348 || p->is_queued()
2349 || p->in_handshake()
2350 || p->remote().address().is_v6()) return;
2352 m_resolving_country = true;
2353 asio::ip::address_v4 reversed(swap_bytes(p->remote().address().to_v4().to_ulong()));
2354 tcp::resolver::query q(reversed.to_string() + ".zz.countries.nerd.dk", "0");
2355 m_host_resolver.async_resolve(q,
2356 bind(&torrent::on_country_lookup, shared_from_this(), _1, _2, p));
2359 namespace
2361 struct country_entry
2363 int code;
2364 char const* name;
2368 void torrent::on_country_lookup(error_code const& error, tcp::resolver::iterator i
2369 , intrusive_ptr<peer_connection> p) const
2371 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2373 INVARIANT_CHECK;
2375 m_resolving_country = false;
2377 // must be ordered in increasing order
2378 static const country_entry country_map[] =
2380 { 4, "AF"}, { 8, "AL"}, { 10, "AQ"}, { 12, "DZ"}, { 16, "AS"}
2381 , { 20, "AD"}, { 24, "AO"}, { 28, "AG"}, { 31, "AZ"}, { 32, "AR"}
2382 , { 36, "AU"}, { 40, "AT"}, { 44, "BS"}, { 48, "BH"}, { 50, "BD"}
2383 , { 51, "AM"}, { 52, "BB"}, { 56, "BE"}, { 60, "BM"}, { 64, "BT"}
2384 , { 68, "BO"}, { 70, "BA"}, { 72, "BW"}, { 74, "BV"}, { 76, "BR"}
2385 , { 84, "BZ"}, { 86, "IO"}, { 90, "SB"}, { 92, "VG"}, { 96, "BN"}
2386 , {100, "BG"}, {104, "MM"}, {108, "BI"}, {112, "BY"}, {116, "KH"}
2387 , {120, "CM"}, {124, "CA"}, {132, "CV"}, {136, "KY"}, {140, "CF"}
2388 , {144, "LK"}, {148, "TD"}, {152, "CL"}, {156, "CN"}, {158, "TW"}
2389 , {162, "CX"}, {166, "CC"}, {170, "CO"}, {174, "KM"}, {175, "YT"}
2390 , {178, "CG"}, {180, "CD"}, {184, "CK"}, {188, "CR"}, {191, "HR"}
2391 , {192, "CU"}, {203, "CZ"}, {204, "BJ"}, {208, "DK"}, {212, "DM"}
2392 , {214, "DO"}, {218, "EC"}, {222, "SV"}, {226, "GQ"}, {231, "ET"}
2393 , {232, "ER"}, {233, "EE"}, {234, "FO"}, {238, "FK"}, {239, "GS"}
2394 , {242, "FJ"}, {246, "FI"}, {248, "AX"}, {250, "FR"}, {254, "GF"}
2395 , {258, "PF"}, {260, "TF"}, {262, "DJ"}, {266, "GA"}, {268, "GE"}
2396 , {270, "GM"}, {275, "PS"}, {276, "DE"}, {288, "GH"}, {292, "GI"}
2397 , {296, "KI"}, {300, "GR"}, {304, "GL"}, {308, "GD"}, {312, "GP"}
2398 , {316, "GU"}, {320, "GT"}, {324, "GN"}, {328, "GY"}, {332, "HT"}
2399 , {334, "HM"}, {336, "VA"}, {340, "HN"}, {344, "HK"}, {348, "HU"}
2400 , {352, "IS"}, {356, "IN"}, {360, "ID"}, {364, "IR"}, {368, "IQ"}
2401 , {372, "IE"}, {376, "IL"}, {380, "IT"}, {384, "CI"}, {388, "JM"}
2402 , {392, "JP"}, {398, "KZ"}, {400, "JO"}, {404, "KE"}, {408, "KP"}
2403 , {410, "KR"}, {414, "KW"}, {417, "KG"}, {418, "LA"}, {422, "LB"}
2404 , {426, "LS"}, {428, "LV"}, {430, "LR"}, {434, "LY"}, {438, "LI"}
2405 , {440, "LT"}, {442, "LU"}, {446, "MO"}, {450, "MG"}, {454, "MW"}
2406 , {458, "MY"}, {462, "MV"}, {466, "ML"}, {470, "MT"}, {474, "MQ"}
2407 , {478, "MR"}, {480, "MU"}, {484, "MX"}, {492, "MC"}, {496, "MN"}
2408 , {498, "MD"}, {500, "MS"}, {504, "MA"}, {508, "MZ"}, {512, "OM"}
2409 , {516, "NA"}, {520, "NR"}, {524, "NP"}, {528, "NL"}, {530, "AN"}
2410 , {533, "AW"}, {540, "NC"}, {548, "VU"}, {554, "NZ"}, {558, "NI"}
2411 , {562, "NE"}, {566, "NG"}, {570, "NU"}, {574, "NF"}, {578, "NO"}
2412 , {580, "MP"}, {581, "UM"}, {583, "FM"}, {584, "MH"}, {585, "PW"}
2413 , {586, "PK"}, {591, "PA"}, {598, "PG"}, {600, "PY"}, {604, "PE"}
2414 , {608, "PH"}, {612, "PN"}, {616, "PL"}, {620, "PT"}, {624, "GW"}
2415 , {626, "TL"}, {630, "PR"}, {634, "QA"}, {634, "QA"}, {638, "RE"}
2416 , {642, "RO"}, {643, "RU"}, {646, "RW"}, {654, "SH"}, {659, "KN"}
2417 , {660, "AI"}, {662, "LC"}, {666, "PM"}, {670, "VC"}, {674, "SM"}
2418 , {678, "ST"}, {682, "SA"}, {686, "SN"}, {690, "SC"}, {694, "SL"}
2419 , {702, "SG"}, {703, "SK"}, {704, "VN"}, {705, "SI"}, {706, "SO"}
2420 , {710, "ZA"}, {716, "ZW"}, {724, "ES"}, {732, "EH"}, {736, "SD"}
2421 , {740, "SR"}, {744, "SJ"}, {748, "SZ"}, {752, "SE"}, {756, "CH"}
2422 , {760, "SY"}, {762, "TJ"}, {764, "TH"}, {768, "TG"}, {772, "TK"}
2423 , {776, "TO"}, {780, "TT"}, {784, "AE"}, {788, "TN"}, {792, "TR"}
2424 , {795, "TM"}, {796, "TC"}, {798, "TV"}, {800, "UG"}, {804, "UA"}
2425 , {807, "MK"}, {818, "EG"}, {826, "GB"}, {834, "TZ"}, {840, "US"}
2426 , {850, "VI"}, {854, "BF"}, {858, "UY"}, {860, "UZ"}, {862, "VE"}
2427 , {876, "WF"}, {882, "WS"}, {887, "YE"}, {891, "CS"}, {894, "ZM"}
2430 if (error || i == tcp::resolver::iterator())
2432 // this is used to indicate that we shouldn't
2433 // try to resolve it again
2434 p->set_country("--");
2435 return;
2438 while (i != tcp::resolver::iterator()
2439 && !i->endpoint().address().is_v4()) ++i;
2440 if (i != tcp::resolver::iterator())
2442 // country is an ISO 3166 country code
2443 int country = i->endpoint().address().to_v4().to_ulong() & 0xffff;
2445 // look up the country code in the map
2446 const int size = sizeof(country_map)/sizeof(country_map[0]);
2447 country_entry tmp = {country, ""};
2448 country_entry const* i =
2449 std::lower_bound(country_map, country_map + size, tmp
2450 , bind(&country_entry::code, _1) < bind(&country_entry::code, _2));
2451 if (i == country_map + size
2452 || i->code != country)
2454 // unknown country!
2455 p->set_country("!!");
2456 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2457 (*m_ses.m_logger) << "IP " << p->remote().address() << " was mapped to unknown country: " << country << "\n";
2458 #endif
2459 return;
2462 p->set_country(i->name);
2465 #endif
2467 void torrent::read_resume_data(lazy_entry const& rd)
2469 m_total_uploaded = rd.dict_find_int_value("total_uploaded");
2470 m_total_downloaded = rd.dict_find_int_value("total_downloaded");
2471 m_active_time = seconds(rd.dict_find_int_value("active_time"));
2472 m_seeding_time = seconds(rd.dict_find_int_value("seeding_time"));
2473 m_complete = rd.dict_find_int_value("num_seeds", -1);
2474 m_incomplete = rd.dict_find_int_value("num_downloaders", -1);
2475 set_upload_limit(rd.dict_find_int_value("upload_rate_limit", -1));
2476 set_download_limit(rd.dict_find_int_value("download_rate_limit", -1));
2477 set_max_connections(rd.dict_find_int_value("max_connections", -1));
2478 set_max_uploads(rd.dict_find_int_value("max_uploads", -1));
2480 lazy_entry const* file_priority = rd.dict_find_list("file_priority");
2481 if (file_priority && file_priority->list_size()
2482 == m_torrent_file->num_files())
2484 for (int i = 0; i < file_priority->list_size(); ++i)
2485 m_file_priority[i] = file_priority->list_int_value_at(i, 1);
2486 update_piece_priorities();
2488 lazy_entry const* piece_priority = rd.dict_find_string("piece_priority");
2489 if (piece_priority && piece_priority->string_length()
2490 == m_torrent_file->num_pieces())
2492 char const* p = piece_priority->string_ptr();
2493 for (int i = 0; i < piece_priority->string_length(); ++i)
2494 m_picker->set_piece_priority(i, p[i]);
2497 if (rd.dict_find_int_value("auto_managed")) auto_managed(true);
2498 if (rd.dict_find_int_value("paused")) pause();
2501 void torrent::write_resume_data(entry& ret) const
2503 ret["file-format"] = "libtorrent resume file";
2504 ret["file-version"] = 1;
2506 ret["total_uploaded"] = m_total_uploaded;
2507 ret["total_downloaded"] = m_total_downloaded;
2509 ret["active_time"] = total_seconds(m_active_time);
2510 ret["seeding_time"] = total_seconds(m_seeding_time);
2512 int seeds = 0;
2513 int downloaders = 0;
2514 if (m_complete >= 0) seeds = m_complete;
2515 else seeds = m_policy.num_seeds();
2516 if (m_incomplete >= 0) downloaders = m_incomplete;
2517 else downloaders = m_policy.num_peers() - m_policy.num_seeds();
2519 ret["num_seeds"] = seeds;
2520 ret["num_downloaders"] = downloaders;
2522 const sha1_hash& info_hash = torrent_file().info_hash();
2523 ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
2525 // blocks per piece
2526 int num_blocks_per_piece =
2527 static_cast<int>(torrent_file().piece_length()) / block_size();
2528 ret["blocks per piece"] = num_blocks_per_piece;
2530 // if this torrent is a seed, we won't have a piece picker
2531 // and there will be no half-finished pieces.
2532 if (!is_seed())
2534 const std::vector<piece_picker::downloading_piece>& q
2535 = m_picker->get_download_queue();
2537 // unfinished pieces
2538 ret["unfinished"] = entry::list_type();
2539 entry::list_type& up = ret["unfinished"].list();
2541 // info for each unfinished piece
2542 for (std::vector<piece_picker::downloading_piece>::const_iterator i
2543 = q.begin(); i != q.end(); ++i)
2545 if (i->finished == 0) continue;
2547 entry piece_struct(entry::dictionary_t);
2549 // the unfinished piece's index
2550 piece_struct["piece"] = i->index;
2552 std::string bitmask;
2553 const int num_bitmask_bytes
2554 = (std::max)(num_blocks_per_piece / 8, 1);
2556 for (int j = 0; j < num_bitmask_bytes; ++j)
2558 unsigned char v = 0;
2559 int bits = (std::min)(num_blocks_per_piece - j*8, 8);
2560 for (int k = 0; k < bits; ++k)
2561 v |= (i->info[j*8+k].state == piece_picker::block_info::state_finished)
2562 ? (1 << k) : 0;
2563 bitmask.insert(bitmask.end(), v);
2564 TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1);
2566 piece_struct["bitmask"] = bitmask;
2567 // push the struct onto the unfinished-piece list
2568 up.push_back(piece_struct);
2572 // write have bitmask
2573 entry::string_type& pieces = ret["pieces"].string();
2574 pieces.resize(m_torrent_file->num_pieces());
2575 if (is_seed())
2577 std::memset(&pieces[0], 1, pieces.size());
2579 else
2581 for (int i = 0, end(pieces.size()); i < end; ++i)
2582 pieces[i] = m_picker->have_piece(i) ? 1 : 0;
2585 // write local peers
2587 entry::list_type& peer_list = ret["peers"].list();
2588 entry::list_type& banned_peer_list = ret["banned_peers"].list();
2590 int max_failcount = m_ses.m_settings.max_failcount;
2592 for (policy::const_iterator i = m_policy.begin_peer()
2593 , end(m_policy.end_peer()); i != end; ++i)
2595 error_code ec;
2596 if (i->second.banned)
2598 entry peer(entry::dictionary_t);
2599 peer["ip"] = i->second.addr.to_string(ec);
2600 if (ec) continue;
2601 peer["port"] = i->second.port;
2602 banned_peer_list.push_back(peer);
2603 continue;
2605 // we cannot save remote connection
2606 // since we don't know their listen port
2607 // unless they gave us their listen port
2608 // through the extension handshake
2609 // so, if the peer is not connectable (i.e. we
2610 // don't know its listen port) or if it has
2611 // been banned, don't save it.
2612 if (i->second.type == policy::peer::not_connectable) continue;
2614 // don't save peers that doesn't work
2615 if (i->second.failcount >= max_failcount) continue;
2617 entry peer(entry::dictionary_t);
2618 peer["ip"] = i->second.addr.to_string(ec);
2619 if (ec) continue;
2620 peer["port"] = i->second.port;
2621 peer_list.push_back(peer);
2624 ret["upload_rate_limit"] = upload_limit();
2625 ret["download_rate_limit"] = download_limit();
2626 ret["max_connections"] = max_connections();
2627 ret["max_uploads"] = max_uploads();
2628 ret["paused"] = m_paused;
2629 ret["auto_managed"] = m_auto_managed;
2631 // write piece priorities
2632 entry::string_type& piece_priority = ret["piece_priority"].string();
2633 piece_priority.resize(m_torrent_file->num_pieces());
2634 if (is_seed())
2636 std::memset(&piece_priority[0], 1, pieces.size());
2638 else
2640 for (int i = 0, end(piece_priority.size()); i < end; ++i)
2641 piece_priority[i] = m_picker->piece_priority(i);
2644 // write file priorities
2645 entry::list_type& file_priority = ret["file_priority"].list();
2646 file_priority.clear();
2647 for (int i = 0, end(m_file_priority.size()); i < end; ++i)
2648 file_priority.push_back(m_file_priority[i]);
2652 void torrent::get_full_peer_list(std::vector<peer_list_entry>& v) const
2654 v.clear();
2655 v.reserve(m_policy.num_peers());
2656 for (policy::const_iterator i = m_policy.begin_peer();
2657 i != m_policy.end_peer(); ++i)
2659 peer_list_entry e;
2660 e.ip = i->second.ip();
2661 e.flags = i->second.banned ? peer_list_entry::banned : 0;
2662 e.failcount = i->second.failcount;
2663 e.source = i->second.source;
2664 v.push_back(e);
2668 void torrent::get_peer_info(std::vector<peer_info>& v)
2670 v.clear();
2671 for (peer_iterator i = begin();
2672 i != end(); ++i)
2674 peer_connection* peer = *i;
2676 // incoming peers that haven't finished the handshake should
2677 // not be included in this list
2678 if (peer->associated_torrent().expired()) continue;
2680 v.push_back(peer_info());
2681 peer_info& p = v.back();
2683 peer->get_peer_info(p);
2684 #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
2685 if (resolving_countries())
2686 resolve_peer_country(intrusive_ptr<peer_connection>(peer));
2687 #endif
2691 void torrent::get_download_queue(std::vector<partial_piece_info>& queue)
2693 queue.clear();
2694 if (!valid_metadata() || is_seed()) return;
2695 piece_picker const& p = picker();
2696 std::vector<piece_picker::downloading_piece> const& q
2697 = p.get_download_queue();
2699 for (std::vector<piece_picker::downloading_piece>::const_iterator i
2700 = q.begin(); i != q.end(); ++i)
2702 partial_piece_info pi;
2703 pi.piece_state = (partial_piece_info::state_t)i->state;
2704 pi.blocks_in_piece = p.blocks_in_piece(i->index);
2705 pi.finished = (int)i->finished;
2706 pi.writing = (int)i->writing;
2707 pi.requested = (int)i->requested;
2708 int piece_size = int(torrent_file().piece_size(i->index));
2709 for (int j = 0; j < pi.blocks_in_piece; ++j)
2711 block_info& bi = pi.blocks[j];
2712 bi.state = i->info[j].state;
2713 bi.block_size = j < pi.blocks_in_piece - 1 ? m_block_size
2714 : piece_size - (j * m_block_size);
2715 bool complete = bi.state == block_info::writing
2716 || bi.state == block_info::finished;
2717 if (i->info[j].peer == 0)
2719 bi.peer = tcp::endpoint();
2720 bi.bytes_progress = complete ? bi.block_size : 0;
2722 else
2724 policy::peer* p = static_cast<policy::peer*>(i->info[j].peer);
2725 if (p->connection)
2727 bi.peer = p->connection->remote();
2728 if (bi.state == block_info::requested)
2730 boost::optional<piece_block_progress> pbp
2731 = p->connection->downloading_piece_progress();
2732 if (pbp && pbp->piece_index == i->index && pbp->block_index == j)
2734 bi.bytes_progress = pbp->bytes_downloaded;
2735 TORRENT_ASSERT(bi.bytes_progress <= bi.block_size);
2737 else
2739 bi.bytes_progress = 0;
2742 else
2744 bi.bytes_progress = complete ? bi.block_size : 0;
2747 else
2749 bi.peer = p->ip();
2750 bi.bytes_progress = complete ? bi.block_size : 0;
2754 pi.blocks[j].num_peers = i->info[j].num_peers;
2756 pi.piece_index = i->index;
2757 queue.push_back(pi);
2762 bool torrent::connect_to_peer(policy::peer* peerinfo)
2764 INVARIANT_CHECK;
2766 TORRENT_ASSERT(peerinfo);
2767 TORRENT_ASSERT(peerinfo->connection == 0);
2769 peerinfo->connected = time_now();
2770 #ifndef NDEBUG
2771 // this asserts that we don't have duplicates in the policy's peer list
2772 peer_iterator i_ = std::find_if(m_connections.begin(), m_connections.end()
2773 , bind(&peer_connection::remote, _1) == peerinfo->ip());
2774 TORRENT_ASSERT(i_ == m_connections.end()
2775 || dynamic_cast<bt_peer_connection*>(*i_) == 0);
2776 #endif
2778 TORRENT_ASSERT(want_more_peers());
2779 TORRENT_ASSERT(m_ses.num_connections() < m_ses.max_connections());
2781 tcp::endpoint a(peerinfo->ip());
2782 TORRENT_ASSERT((m_ses.m_ip_filter.access(peerinfo->addr) & ip_filter::blocked) == 0);
2784 boost::shared_ptr<socket_type> s(new socket_type(m_ses.m_io_service));
2786 bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s);
2787 TORRENT_ASSERT(ret);
2788 std::pair<int, int> const& out_ports = m_ses.settings().outgoing_ports;
2789 error_code ec;
2790 if (out_ports.first > 0 && out_ports.second >= out_ports.first)
2791 s->bind(tcp::endpoint(address(), m_ses.next_port()), ec);
2793 boost::intrusive_ptr<peer_connection> c(new bt_peer_connection(
2794 m_ses, shared_from_this(), s, a, peerinfo));
2796 #ifndef NDEBUG
2797 c->m_in_constructor = false;
2798 #endif
2800 c->add_stat(peerinfo->prev_amount_download, peerinfo->prev_amount_upload);
2801 peerinfo->prev_amount_download = 0;
2802 peerinfo->prev_amount_upload = 0;
2804 #ifndef TORRENT_DISABLE_EXTENSIONS
2805 for (extension_list_t::iterator i = m_extensions.begin()
2806 , end(m_extensions.end()); i != end; ++i)
2808 #ifndef BOOST_NO_EXCEPTIONS
2809 try {
2810 #endif
2811 boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
2812 if (pp) c->add_extension(pp);
2813 #ifndef BOOST_NO_EXCEPTIONS
2814 } catch (std::exception&) {}
2815 #endif
2817 #endif
2819 // add the newly connected peer to this torrent's peer list
2820 m_connections.insert(boost::get_pointer(c));
2821 m_ses.m_connections.insert(c);
2822 peerinfo->connection = c.get();
2823 c->start();
2825 int timeout = settings().peer_connect_timeout;
2826 if (peerinfo) timeout += 3 * peerinfo->failcount;
2828 #ifndef BOOST_NO_EXCEPTIONS
2831 #endif
2832 m_ses.m_half_open.enqueue(
2833 bind(&peer_connection::connect, c, _1)
2834 , bind(&peer_connection::timed_out, c)
2835 , seconds(timeout));
2836 #ifndef BOOST_NO_EXCEPTIONS
2838 catch (std::exception& e)
2840 std::set<peer_connection*>::iterator i
2841 = m_connections.find(boost::get_pointer(c));
2842 if (i != m_connections.end()) m_connections.erase(i);
2843 c->disconnect(e.what());
2844 return false;
2846 #endif
2847 return true;
2850 bool torrent::set_metadata(lazy_entry const& metadata, std::string& error)
2852 INVARIANT_CHECK;
2854 TORRENT_ASSERT(!m_torrent_file->is_valid());
2855 if (!m_torrent_file->parse_info_section(metadata, error))
2857 // parse failed
2858 return false;
2861 if (m_ses.m_alerts.should_post<metadata_received_alert>())
2863 m_ses.m_alerts.post_alert(metadata_received_alert(
2864 get_handle()));
2867 init();
2869 return true;
2872 bool torrent::attach_peer(peer_connection* p)
2874 // INVARIANT_CHECK;
2876 TORRENT_ASSERT(p != 0);
2877 TORRENT_ASSERT(!p->is_local());
2879 m_has_incoming = true;
2881 if ((m_state == torrent_status::queued_for_checking
2882 || m_state == torrent_status::checking_files)
2883 && valid_metadata())
2885 p->disconnect("torrent is not ready to accept peers");
2886 return false;
2889 if (m_ses.m_connections.find(p) == m_ses.m_connections.end())
2891 p->disconnect("peer is not properly constructed");
2892 return false;
2895 if (m_ses.is_aborted())
2897 p->disconnect("session is closing");
2898 return false;
2901 if (int(m_connections.size()) >= m_max_connections)
2903 p->disconnect("reached connection limit");
2904 return false;
2907 #ifndef BOOST_NO_EXCEPTIONS
2910 #endif
2911 #ifndef TORRENT_DISABLE_EXTENSIONS
2912 for (extension_list_t::iterator i = m_extensions.begin()
2913 , end(m_extensions.end()); i != end; ++i)
2915 boost::shared_ptr<peer_plugin> pp((*i)->new_connection(p));
2916 if (pp) p->add_extension(pp);
2918 #endif
2919 if (!m_policy.new_connection(*p))
2920 return false;
2921 #ifndef BOOST_NO_EXCEPTIONS
2923 catch (std::exception& e)
2925 #if defined TORRENT_LOGGING
2926 (*m_ses.m_logger) << time_now_string() << " CLOSING CONNECTION "
2927 << p->remote() << " policy::new_connection threw: " << e.what() << "\n";
2928 #endif
2929 p->disconnect(e.what());
2930 return false;
2932 #endif
2933 TORRENT_ASSERT(m_connections.find(p) == m_connections.end());
2934 peer_iterator ci = m_connections.insert(p).first;
2935 #ifndef NDEBUG
2936 error_code ec;
2937 TORRENT_ASSERT(p->remote() == p->get_socket()->remote_endpoint(ec) || ec);
2938 #endif
2940 #if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
2941 m_policy.check_invariant();
2942 #endif
2943 return true;
2946 bool torrent::want_more_peers() const
2948 return int(m_connections.size()) < m_max_connections
2949 && !is_paused()
2950 && m_state != torrent_status::checking_files
2951 && (m_state != torrent_status::queued_for_checking
2952 || !valid_metadata())
2953 && m_policy.num_connect_candidates() > 0;
2956 void torrent::disconnect_all()
2958 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2960 INVARIANT_CHECK;
2962 while (!m_connections.empty())
2964 peer_connection* p = *m_connections.begin();
2965 TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
2967 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
2968 if (m_abort)
2969 (*p->m_logger) << "*** CLOSING CONNECTION 'aborting'\n";
2970 else
2971 (*p->m_logger) << "*** CLOSING CONNECTION 'pausing'\n";
2972 #endif
2973 #ifndef NDEBUG
2974 std::size_t size = m_connections.size();
2975 #endif
2976 if (p->is_disconnecting())
2977 m_connections.erase(m_connections.begin());
2978 else
2979 p->disconnect(m_abort?"stopping torrent":"pausing torrent");
2980 TORRENT_ASSERT(m_connections.size() <= size);
2984 namespace
2986 // this returns true if lhs is a better disconnect candidate than rhs
2987 bool compare_disconnect_peer(peer_connection const* lhs, peer_connection const* rhs)
2989 // prefer to disconnect peers we're not interested in
2990 if (lhs->is_interesting() != rhs->is_interesting())
2991 return rhs->is_interesting();
2993 // prefer to disconnect peers that are not seeds
2994 if (lhs->is_seed() != rhs->is_seed())
2995 return rhs->is_seed();
2997 // prefer to disconnect peers that are on parole
2998 if (lhs->on_parole() != rhs->on_parole())
2999 return lhs->on_parole();
3001 // prefer to disconnect peers that send data at a lower rate
3002 size_type lhs_transferred = lhs->statistics().total_payload_download();
3003 size_type rhs_transferred = rhs->statistics().total_payload_download();
3005 if (lhs_transferred != rhs_transferred
3006 && lhs_transferred > 0
3007 && rhs_transferred > 0)
3009 ptime now = time_now();
3010 size_type lhs_time_connected = total_seconds(now - lhs->connected_time());
3011 size_type rhs_time_connected = total_seconds(now - rhs->connected_time());
3013 double lhs_rate = double(lhs_transferred) / (lhs_time_connected + 1);
3014 double rhs_rate = double(rhs_transferred) / (rhs_time_connected + 1);
3016 return lhs_rate < rhs_rate;
3019 // prefer to disconnect peers that chokes us
3020 if (lhs->is_choked() != rhs->is_choked())
3021 return lhs->is_choked();
3023 return lhs->last_received() < rhs->last_received();
3027 int torrent::disconnect_peers(int num)
3029 int ret = 0;
3030 // buils a list of all connected peers and sort it by 'disconnectability'.
3031 std::vector<peer_connection*> peers(m_connections.size());
3032 std::copy(m_connections.begin(), m_connections.end(), peers.begin());
3033 std::sort(peers.begin(), peers.end(), boost::bind(&compare_disconnect_peer, _1, _2));
3035 // never disconnect peers that connected less than 90 seconds ago
3036 ptime cut_off = time_now() - seconds(90);
3038 for (std::vector<peer_connection*>::iterator i = peers.begin()
3039 , end(peers.end()); i != end && ret < num; ++i)
3041 peer_connection* p = *i;
3042 if (p->connected_time() > cut_off) continue;
3043 ++ret;
3044 p->disconnect("optimistic disconnect");
3046 return ret;
3049 int torrent::bandwidth_throttle(int channel) const
3051 return m_bandwidth_limit[channel].throttle();
3054 int torrent::bandwidth_queue_size(int channel) const
3056 return (int)m_bandwidth_queue[channel].size();
3059 void torrent::request_bandwidth(int channel
3060 , boost::intrusive_ptr<peer_connection> const& p
3061 , int max_block_size, int priority)
3063 TORRENT_ASSERT(max_block_size > 0);
3064 TORRENT_ASSERT(m_bandwidth_limit[channel].throttle() > 0);
3065 TORRENT_ASSERT(p->max_assignable_bandwidth(channel) > 0);
3066 TORRENT_ASSERT(p->m_channel_state[channel] == peer_info::bw_torrent);
3067 int block_size = (std::min)(m_bandwidth_limit[channel].throttle() / 10
3068 , max_block_size);
3069 if (block_size <= 0) block_size = 1;
3071 if (m_bandwidth_limit[channel].max_assignable() > 0)
3073 perform_bandwidth_request(channel, p, block_size, priority);
3075 else
3077 // skip forward in the queue until we find a prioritized peer
3078 // or hit the front of it.
3079 queue_t::reverse_iterator i = m_bandwidth_queue[channel].rbegin();
3080 while (i != m_bandwidth_queue[channel].rend() && priority > i->priority)
3082 ++i->priority;
3083 ++i;
3085 m_bandwidth_queue[channel].insert(i.base(), bw_queue_entry<peer_connection, torrent>(
3086 p, block_size, priority));
3090 void torrent::expire_bandwidth(int channel, int amount)
3092 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3094 INVARIANT_CHECK;
3096 TORRENT_ASSERT(amount > 0);
3097 m_bandwidth_limit[channel].expire(amount);
3098 queue_t tmp;
3099 while (!m_bandwidth_queue[channel].empty())
3101 bw_queue_entry<peer_connection, torrent> qe = m_bandwidth_queue[channel].front();
3102 if (m_bandwidth_limit[channel].max_assignable() == 0)
3103 break;
3104 m_bandwidth_queue[channel].pop_front();
3105 if (qe.peer->max_assignable_bandwidth(channel) <= 0)
3107 TORRENT_ASSERT(m_ses.m_bandwidth_manager[channel]->is_in_history(qe.peer.get()));
3108 if (!qe.peer->is_disconnecting()) tmp.push_back(qe);
3109 continue;
3111 perform_bandwidth_request(channel, qe.peer
3112 , qe.max_block_size, qe.priority);
3114 m_bandwidth_queue[channel].insert(m_bandwidth_queue[channel].begin(), tmp.begin(), tmp.end());
3117 void torrent::perform_bandwidth_request(int channel
3118 , boost::intrusive_ptr<peer_connection> const& p
3119 , int block_size
3120 , int priority)
3122 TORRENT_ASSERT(p->m_channel_state[channel] == peer_info::bw_torrent);
3123 p->m_channel_state[channel] = peer_info::bw_global;
3124 m_ses.m_bandwidth_manager[channel]->request_bandwidth(p
3125 , block_size, priority);
3126 m_bandwidth_limit[channel].assign(block_size);
3129 void torrent::assign_bandwidth(int channel, int amount, int blk)
3131 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3133 TORRENT_ASSERT(amount > 0);
3134 TORRENT_ASSERT(amount <= blk);
3135 if (amount < blk)
3136 expire_bandwidth(channel, blk - amount);
3139 // called when torrent is finished (all interesting
3140 // pieces have been downloaded)
3141 void torrent::finished()
3143 INVARIANT_CHECK;
3145 if (alerts().should_post<torrent_finished_alert>())
3147 alerts().post_alert(torrent_finished_alert(
3148 get_handle()));
3151 set_state(torrent_status::finished);
3152 set_queue_position(-1);
3154 // we have to call completed() before we start
3155 // disconnecting peers, since there's an assert
3156 // to make sure we're cleared the piece picker
3157 if (is_seed()) completed();
3159 // disconnect all seeds
3160 // TODO: should disconnect all peers that have the pieces we have
3161 // not just seeds
3162 std::vector<peer_connection*> seeds;
3163 for (peer_iterator i = m_connections.begin();
3164 i != m_connections.end(); ++i)
3166 peer_connection* p = *i;
3167 TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
3168 if (p->upload_only())
3170 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
3171 (*p->m_logger) << "*** SEED, CLOSING CONNECTION\n";
3172 #endif
3173 seeds.push_back(p);
3176 std::for_each(seeds.begin(), seeds.end()
3177 , bind(&peer_connection::disconnect, _1, "torrent finished, disconnecting seed", 0));
3179 TORRENT_ASSERT(m_storage);
3180 // we need to keep the object alive during this operation
3181 m_storage->async_release_files(
3182 bind(&torrent::on_files_released, shared_from_this(), _1, _2));
3185 // this is called when we were finished, but some files were
3186 // marked for downloading, and we are no longer finished
3187 void torrent::resume_download()
3189 INVARIANT_CHECK;
3191 TORRENT_ASSERT(!is_finished());
3192 set_state(torrent_status::downloading);
3193 set_queue_position((std::numeric_limits<int>::max)());
3196 // called when torrent is complete (all pieces downloaded)
3197 void torrent::completed()
3199 m_picker.reset();
3201 set_state(torrent_status::seeding);
3202 if (!m_complete_sent && m_announcing) announce_with_tracker();
3205 // this will move the tracker with the given index
3206 // to a prioritized position in the list (move it towards
3207 // the begining) and return the new index to the tracker.
3208 int torrent::prioritize_tracker(int index)
3210 INVARIANT_CHECK;
3212 TORRENT_ASSERT(index >= 0);
3213 if (index >= (int)m_trackers.size()) return (int)m_trackers.size()-1;
3215 while (index > 0 && m_trackers[index].tier == m_trackers[index-1].tier)
3217 std::swap(m_trackers[index].url, m_trackers[index-1].url);
3218 --index;
3220 return index;
3223 void torrent::try_next_tracker(tracker_request const& req)
3225 INVARIANT_CHECK;
3227 ++m_currently_trying_tracker;
3229 if ((unsigned)m_currently_trying_tracker < m_trackers.size())
3231 announce_with_tracker(req.event);
3232 return;
3235 int delay = tracker_retry_delay_min
3236 + (std::min)(int(m_failed_trackers), int(tracker_failed_max))
3237 * (tracker_retry_delay_max - tracker_retry_delay_min)
3238 / tracker_failed_max;
3240 ++m_failed_trackers;
3241 // if we've looped the tracker list, wait a bit before retrying
3242 m_currently_trying_tracker = 0;
3244 // if we're stopping, just give up. Don't bother retrying
3245 if (req.event == tracker_request::stopped)
3246 return;
3248 restart_tracker_timer(time_now() + seconds(delay));
3250 #ifndef TORRENT_DISABLE_DHT
3251 if (m_abort) return;
3253 // only start the announce if we want to announce with the dht
3254 ptime now = time_now();
3255 if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
3257 // force the DHT to reannounce
3258 m_last_dht_announce = now;
3259 boost::weak_ptr<torrent> self(shared_from_this());
3260 m_ses.m_dht->announce(m_torrent_file->info_hash()
3261 , m_ses.m_listen_sockets.front().external_port
3262 , bind(&torrent::on_dht_announce_response_disp, self, _1));
3264 #endif
3268 void torrent::files_checked()
3270 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3272 TORRENT_ASSERT(m_torrent_file->is_valid());
3273 INVARIANT_CHECK;
3275 set_state(torrent_status::connecting_to_tracker);
3277 if (!is_seed())
3279 if (m_sequential_download)
3280 picker().sequential_download(m_sequential_download);
3282 // if we just finished checking and we're not a seed, we are
3283 // likely to be unpaused
3284 if (m_ses.m_auto_manage_time_scaler > 1)
3285 m_ses.m_auto_manage_time_scaler = 1;
3288 #ifndef TORRENT_DISABLE_EXTENSIONS
3289 for (extension_list_t::iterator i = m_extensions.begin()
3290 , end(m_extensions.end()); i != end; ++i)
3292 #ifndef BOOST_NO_EXCEPTIONS
3293 try {
3294 #endif
3295 (*i)->on_files_checked();
3296 #ifndef BOOST_NO_EXCEPTIONS
3297 } catch (std::exception&) {}
3298 #endif
3300 #endif
3302 if (is_seed())
3304 m_complete_sent = true;
3305 finished();
3308 if (!m_connections_initialized)
3310 m_connections_initialized = true;
3311 // all peer connections have to initialize themselves now that the metadata
3312 // is available
3313 for (torrent::peer_iterator i = m_connections.begin();
3314 i != m_connections.end();)
3316 peer_connection* pc = *i;
3317 ++i;
3318 pc->on_metadata();
3319 pc->init();
3323 if (m_ses.m_alerts.should_post<torrent_checked_alert>())
3325 m_ses.m_alerts.post_alert(torrent_checked_alert(
3326 get_handle()));
3329 m_files_checked = true;
3331 start_announcing();
3334 alert_manager& torrent::alerts() const
3336 return m_ses.m_alerts;
3339 fs::path torrent::save_path() const
3341 return m_save_path;
3344 bool torrent::rename_file(int index, std::string const& name)
3346 INVARIANT_CHECK;
3348 TORRENT_ASSERT(index >= 0);
3349 TORRENT_ASSERT(index < m_torrent_file->num_files());
3351 if (!m_owning_storage.get()) return false;
3353 m_owning_storage->async_rename_file(index, name
3354 , bind(&torrent::on_file_renamed, shared_from_this(), _1, _2));
3355 return true;
3358 void torrent::move_storage(fs::path const& save_path)
3360 INVARIANT_CHECK;
3362 if (m_owning_storage.get())
3364 m_owning_storage->async_move_storage(save_path
3365 , bind(&torrent::on_storage_moved, shared_from_this(), _1, _2));
3367 else
3369 m_save_path = save_path;
3373 void torrent::on_storage_moved(int ret, disk_io_job const& j)
3375 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3377 if (alerts().should_post<storage_moved_alert>())
3379 alerts().post_alert(storage_moved_alert(get_handle(), j.str));
3381 m_save_path = j.str;
3384 piece_manager& torrent::filesystem()
3386 TORRENT_ASSERT(m_owning_storage.get());
3387 TORRENT_ASSERT(m_storage);
3388 return *m_storage;
3392 torrent_handle torrent::get_handle()
3394 return torrent_handle(shared_from_this());
3397 session_settings const& torrent::settings() const
3399 return m_ses.settings();
3402 #ifndef NDEBUG
3403 void torrent::check_invariant() const
3405 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3407 TORRENT_ASSERT(m_resume_entry.type() == lazy_entry::dict_t
3408 || m_resume_entry.type() == lazy_entry::none_t);
3410 TORRENT_ASSERT(m_bandwidth_queue[0].size() <= m_connections.size());
3411 TORRENT_ASSERT(m_bandwidth_queue[1].size() <= m_connections.size());
3413 for (int c = 0; c < 2; ++c)
3415 queue_t::const_iterator j = m_bandwidth_queue[c].begin();
3416 if (j == m_bandwidth_queue[c].end()) continue;
3417 ++j;
3418 for (queue_t::const_iterator i = m_bandwidth_queue[c].begin()
3419 , end(m_bandwidth_queue[c].end()); i != end && j != end; ++i, ++j)
3420 TORRENT_ASSERT(i->priority >= j->priority);
3423 int num_uploads = 0;
3424 std::map<piece_block, int> num_requests;
3425 for (const_peer_iterator i = begin(); i != end(); ++i)
3427 #ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
3428 // make sure this peer is not a dangling pointer
3429 TORRENT_ASSERT(m_ses.has_peer(*i));
3430 #endif
3431 peer_connection const& p = *(*i);
3432 for (std::deque<piece_block>::const_iterator i = p.request_queue().begin()
3433 , end(p.request_queue().end()); i != end; ++i)
3434 ++num_requests[*i];
3435 for (std::deque<pending_block>::const_iterator i = p.download_queue().begin()
3436 , end(p.download_queue().end()); i != end; ++i)
3437 ++num_requests[i->block];
3438 if (!p.is_choked()) ++num_uploads;
3439 torrent* associated_torrent = p.associated_torrent().lock().get();
3440 if (associated_torrent != this)
3441 TORRENT_ASSERT(false);
3443 TORRENT_ASSERT(num_uploads == m_num_uploads);
3445 if (has_picker())
3447 for (std::map<piece_block, int>::iterator i = num_requests.begin()
3448 , end(num_requests.end()); i != end; ++i)
3450 if (!m_picker->is_downloaded(i->first))
3451 TORRENT_ASSERT(m_picker->num_peers(i->first) == i->second);
3453 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
3456 if (valid_metadata())
3458 TORRENT_ASSERT(m_abort || !m_picker || m_picker->num_pieces() == m_torrent_file->num_pieces());
3460 else
3462 TORRENT_ASSERT(m_abort || m_picker->num_pieces() == 0);
3465 #ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
3466 for (policy::const_iterator i = m_policy.begin_peer()
3467 , end(m_policy.end_peer()); i != end; ++i)
3469 TORRENT_ASSERT(i->second.ip.address() == i->first);
3471 #endif
3473 size_type total_done = quantized_bytes_done();
3474 if (m_torrent_file->is_valid())
3476 if (is_seed())
3477 TORRENT_ASSERT(total_done == m_torrent_file->total_size());
3478 else
3479 TORRENT_ASSERT(total_done != m_torrent_file->total_size() || !m_files_checked);
3481 TORRENT_ASSERT(m_block_size <= m_torrent_file->piece_length());
3483 else
3485 TORRENT_ASSERT(total_done == 0);
3488 if (m_picker && !m_abort)
3490 // make sure that pieces that have completed the download
3491 // of all their blocks are in the disk io thread's queue
3492 // to be checked.
3493 const std::vector<piece_picker::downloading_piece>& dl_queue
3494 = m_picker->get_download_queue();
3495 for (std::vector<piece_picker::downloading_piece>::const_iterator i =
3496 dl_queue.begin(); i != dl_queue.end(); ++i)
3498 const int blocks_per_piece = m_picker->blocks_in_piece(i->index);
3500 bool complete = true;
3501 for (int j = 0; j < blocks_per_piece; ++j)
3503 if (i->info[j].state == piece_picker::block_info::state_finished)
3504 continue;
3505 complete = false;
3506 break;
3511 // This check is very expensive.
3512 TORRENT_ASSERT(!valid_metadata() || m_block_size > 0);
3513 TORRENT_ASSERT(!valid_metadata() || (m_torrent_file->piece_length() % m_block_size) == 0);
3514 // if (is_seed()) TORRENT_ASSERT(m_picker.get() == 0);
3516 #endif
3518 void torrent::set_sequential_download(bool sd)
3520 if (has_picker())
3522 picker().sequential_download(sd);
3524 else
3526 m_sequential_download = sd;
3530 void torrent::set_queue_position(int p)
3532 TORRENT_ASSERT((p == -1) == is_finished()
3533 || (!m_auto_managed && p == -1)
3534 || (m_abort && p == -1));
3535 if (is_finished() && p != -1) return;
3536 if (p == m_sequence_number) return;
3538 session_impl::torrent_map& torrents = m_ses.m_torrents;
3539 if (p >= 0 && m_sequence_number == -1)
3541 int max_seq = -1;
3542 for (session_impl::torrent_map::iterator i = torrents.begin()
3543 , end(torrents.end()); i != end; ++i)
3545 torrent* t = i->second.get();
3546 if (t->m_sequence_number > max_seq) max_seq = t->m_sequence_number;
3548 m_sequence_number = (std::min)(max_seq + 1, p);
3550 else if (p < 0)
3552 for (session_impl::torrent_map::iterator i = torrents.begin()
3553 , end(torrents.end()); i != end; ++i)
3555 torrent* t = i->second.get();
3556 if (t == this) continue;
3557 if (t->m_sequence_number >= m_sequence_number
3558 && t->m_sequence_number != -1)
3559 --t->m_sequence_number;
3561 m_sequence_number = p;
3563 else if (p < m_sequence_number)
3565 for (session_impl::torrent_map::iterator i = torrents.begin()
3566 , end(torrents.end()); i != end; ++i)
3568 torrent* t = i->second.get();
3569 if (t == this) continue;
3570 if (t->m_sequence_number >= p
3571 && t->m_sequence_number < m_sequence_number
3572 && t->m_sequence_number != -1)
3573 ++t->m_sequence_number;
3575 m_sequence_number = p;
3577 else if (p > m_sequence_number)
3579 int max_seq = 0;
3580 for (session_impl::torrent_map::iterator i = torrents.begin()
3581 , end(torrents.end()); i != end; ++i)
3583 torrent* t = i->second.get();
3584 int pos = t->m_sequence_number;
3585 if (pos > max_seq) max_seq = pos;
3586 if (t == this) continue;
3588 if (pos <= p
3589 && pos > m_sequence_number
3590 && pos != -1)
3591 --t->m_sequence_number;
3594 m_sequence_number = (std::min)(max_seq, p);
3597 if (m_ses.m_auto_manage_time_scaler > 2)
3598 m_ses.m_auto_manage_time_scaler = 2;
3601 void torrent::set_max_uploads(int limit)
3603 TORRENT_ASSERT(limit >= -1);
3604 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3605 m_max_uploads = limit;
3608 void torrent::set_max_connections(int limit)
3610 TORRENT_ASSERT(limit >= -1);
3611 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3612 m_max_connections = limit;
3615 void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit)
3617 TORRENT_ASSERT(limit >= -1);
3618 peer_iterator i = std::find_if(m_connections.begin(), m_connections.end()
3619 , bind(&peer_connection::remote, _1) == ip);
3620 if (i == m_connections.end()) return;
3621 (*i)->set_upload_limit(limit);
3624 void torrent::set_peer_download_limit(tcp::endpoint ip, int limit)
3626 TORRENT_ASSERT(limit >= -1);
3627 peer_iterator i = std::find_if(m_connections.begin(), m_connections.end()
3628 , bind(&peer_connection::remote, _1) == ip);
3629 if (i == m_connections.end()) return;
3630 (*i)->set_download_limit(limit);
3633 void torrent::set_upload_limit(int limit)
3635 TORRENT_ASSERT(limit >= -1);
3636 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3637 if (limit < num_peers() * 10) limit = num_peers() * 10;
3638 m_bandwidth_limit[peer_connection::upload_channel].throttle(limit);
3641 int torrent::upload_limit() const
3643 int limit = m_bandwidth_limit[peer_connection::upload_channel].throttle();
3644 if (limit == (std::numeric_limits<int>::max)()) limit = -1;
3645 return limit;
3648 void torrent::set_download_limit(int limit)
3650 TORRENT_ASSERT(limit >= -1);
3651 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3652 if (limit < num_peers() * 10) limit = num_peers() * 10;
3653 m_bandwidth_limit[peer_connection::download_channel].throttle(limit);
3656 int torrent::download_limit() const
3658 int limit = m_bandwidth_limit[peer_connection::download_channel].throttle();
3659 if (limit == (std::numeric_limits<int>::max)()) limit = -1;
3660 return limit;
3663 void torrent::delete_files()
3665 #if defined TORRENT_VERBOSE_LOGGING
3666 for (peer_iterator i = m_connections.begin();
3667 i != m_connections.end(); ++i)
3669 (*(*i)->m_logger) << "*** DELETING FILES IN TORRENT\n";
3671 #endif
3673 disconnect_all();
3674 stop_announcing();
3676 if (m_owning_storage.get())
3678 TORRENT_ASSERT(m_storage);
3679 m_storage->async_delete_files(
3680 bind(&torrent::on_files_deleted, shared_from_this(), _1, _2));
3684 void torrent::clear_error()
3686 if (m_error.empty()) return;
3687 if (m_ses.m_auto_manage_time_scaler > 2)
3688 m_ses.m_auto_manage_time_scaler = 2;
3689 m_error.clear();
3692 void torrent::auto_managed(bool a)
3694 INVARIANT_CHECK;
3696 if (m_auto_managed == a) return;
3697 m_auto_managed = a;
3698 // recalculate which torrents should be
3699 // paused
3700 m_ses.m_auto_manage_time_scaler = 0;
3703 // the higher seed rank, the more important to seed
3704 int torrent::seed_rank(session_settings const& s) const
3706 enum flags
3708 seed_ratio_not_met = 0x400000,
3709 recently_started = 0x200000,
3710 no_seeds = 0x100000,
3711 prio_mask = 0xfffff
3714 if (!is_seed()) return 0;
3716 int ret = 0;
3718 ptime now(time_now());
3720 int seed_time = total_seconds(m_seeding_time);
3721 int download_time = total_seconds(m_active_time) - seed_time;
3723 // if we haven't yet met the seed limits, set the seed_ratio_not_met
3724 // flag. That will make this seed prioritized
3725 size_type downloaded = (std::max)(m_total_downloaded, m_torrent_file->total_size());
3726 if (seed_time < s.seed_time_limit
3727 && (seed_time > 1 && download_time / float(seed_time) < s.seed_time_ratio_limit)
3728 && m_total_uploaded / downloaded < s.share_ratio_limit)
3729 ret |= seed_ratio_not_met;
3731 // if this torrent is running, and it was started less
3732 // than 30 minutes ago, give it priority, to avoid oscillation
3733 if (!is_paused() && now - m_started < minutes(30))
3734 ret |= recently_started;
3736 // if we have any scrape data, use it to calculate
3737 // seed rank
3738 int seeds = 0;
3739 int downloaders = 0;
3741 if (m_complete >= 0) seeds = m_complete;
3742 else seeds = m_policy.num_seeds();
3744 if (m_incomplete >= 0) downloaders = m_incomplete;
3745 else downloaders = m_policy.num_peers() - m_policy.num_seeds();
3747 if (seeds == 0)
3749 ret |= no_seeds;
3750 ret |= downloaders & prio_mask;
3752 else
3754 ret |= (downloaders * 100 / seeds) & prio_mask;
3757 return ret;
3760 // this is an async operation triggered by the client
3761 void torrent::save_resume_data()
3763 INVARIANT_CHECK;
3765 if (m_owning_storage.get())
3767 TORRENT_ASSERT(m_storage);
3768 if (m_state == torrent_status::queued_for_checking
3769 || m_state == torrent_status::checking_files)
3771 if (alerts().should_post<save_resume_data_failed_alert>())
3773 alerts().post_alert(save_resume_data_failed_alert(get_handle()
3774 , "won't save resume data, torrent does not have a complete resume state yet"));
3777 else
3779 m_storage->async_save_resume_data(
3780 bind(&torrent::on_save_resume_data, shared_from_this(), _1, _2));
3783 else
3785 if (alerts().should_post<save_resume_data_failed_alert>())
3787 alerts().post_alert(save_resume_data_failed_alert(get_handle()
3788 , "save resume data failed, torrent is being destructed"));
3793 bool torrent::is_paused() const
3795 return m_paused || m_ses.is_paused();
3798 void torrent::pause()
3800 INVARIANT_CHECK;
3802 if (m_paused) return;
3803 m_paused = true;
3804 if (m_ses.is_paused()) return;
3805 do_pause();
3808 void torrent::do_pause()
3810 if (!is_paused()) return;
3812 #ifndef TORRENT_DISABLE_EXTENSIONS
3813 for (extension_list_t::iterator i = m_extensions.begin()
3814 , end(m_extensions.end()); i != end; ++i)
3816 #ifndef BOOST_NO_EXCEPTIONS
3817 try {
3818 #endif
3819 if ((*i)->on_pause()) return;
3820 #ifndef BOOST_NO_EXCEPTIONS
3821 } catch (std::exception&) {}
3822 #endif
3824 #endif
3826 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
3827 for (peer_iterator i = m_connections.begin();
3828 i != m_connections.end(); ++i)
3830 (*(*i)->m_logger) << "*** PAUSING TORRENT\n";
3832 #endif
3834 // this will make the storage close all
3835 // files and flush all cached data
3836 if (m_owning_storage.get())
3838 TORRENT_ASSERT(m_storage);
3839 m_storage->async_release_files(
3840 bind(&torrent::on_torrent_paused, shared_from_this(), _1, _2));
3841 m_storage->async_clear_read_cache();
3843 else
3845 if (alerts().should_post<torrent_paused_alert>())
3846 alerts().post_alert(torrent_paused_alert(get_handle()));
3849 disconnect_all();
3850 stop_announcing();
3853 void torrent::resume()
3855 INVARIANT_CHECK;
3857 if (!m_paused) return;
3858 m_paused = false;
3859 do_resume();
3862 void torrent::do_resume()
3864 if (is_paused()) return;
3866 #ifndef TORRENT_DISABLE_EXTENSIONS
3867 for (extension_list_t::iterator i = m_extensions.begin()
3868 , end(m_extensions.end()); i != end; ++i)
3870 #ifndef BOOST_NO_EXCEPTIONS
3871 try {
3872 #endif
3873 if ((*i)->on_resume()) return;
3874 #ifndef BOOST_NO_EXCEPTIONS
3875 } catch (std::exception&) {}
3876 #endif
3878 #endif
3880 if (alerts().should_post<torrent_resumed_alert>())
3881 alerts().post_alert(torrent_resumed_alert(get_handle()));
3883 m_started = time_now();
3884 m_error.clear();
3885 start_announcing();
3888 void torrent::restart_tracker_timer(ptime announce_at)
3890 if (!m_announcing) return;
3892 m_next_tracker_announce = announce_at;
3893 error_code ec;
3894 boost::weak_ptr<torrent> self(shared_from_this());
3895 m_tracker_timer.expires_at(m_next_tracker_announce, ec);
3896 m_tracker_timer.async_wait(bind(&torrent::on_tracker_announce_disp, self, _1));
3899 void torrent::start_announcing()
3901 if (is_paused()) return;
3902 if (!m_files_checked) return;
3903 if (m_announcing) return;
3905 m_announcing = true;
3907 if (!m_trackers.empty())
3909 // tell the tracker that we're back
3910 m_start_sent = false;
3911 announce_with_tracker();
3914 // private torrents are never announced on LSD
3915 // or on DHT, we don't need this timer.
3916 if (!m_torrent_file->is_valid() || !m_torrent_file->priv())
3918 error_code ec;
3919 boost::weak_ptr<torrent> self(shared_from_this());
3920 m_lsd_announce_timer.expires_from_now(seconds(1), ec);
3921 m_lsd_announce_timer.async_wait(
3922 bind(&torrent::on_lsd_announce_disp, self, _1));
3926 void torrent::stop_announcing()
3928 if (!m_announcing) return;
3930 error_code ec;
3931 m_lsd_announce_timer.cancel(ec);
3932 m_tracker_timer.cancel(ec);
3934 m_announcing = false;
3936 if (!m_trackers.empty())
3937 announce_with_tracker(tracker_request::stopped);
3940 void torrent::second_tick(stat& accumulator, float tick_interval)
3942 INVARIANT_CHECK;
3944 #ifndef TORRENT_DISABLE_EXTENSIONS
3945 for (extension_list_t::iterator i = m_extensions.begin()
3946 , end(m_extensions.end()); i != end; ++i)
3948 #ifndef BOOST_NO_EXCEPTIONS
3949 try {
3950 #endif
3951 (*i)->tick();
3952 #ifndef BOOST_NO_EXCEPTIONS
3953 } catch (std::exception&) {}
3954 #endif
3956 #endif
3958 if (is_paused())
3960 // let the stats fade out to 0
3961 m_stat.second_tick(tick_interval);
3962 return;
3965 time_duration since_last_tick = microsec(tick_interval * 1000000L);
3966 if (is_seed()) m_seeding_time += since_last_tick;
3967 m_active_time += since_last_tick;
3969 // ---- WEB SEEDS ----
3971 // re-insert urls that are to be retrieds into the m_web_seeds
3972 typedef std::map<std::string, ptime>::iterator iter_t;
3973 for (iter_t i = m_web_seeds_next_retry.begin(); i != m_web_seeds_next_retry.end();)
3975 iter_t erase_element = i++;
3976 if (erase_element->second <= time_now())
3978 m_web_seeds.insert(erase_element->first);
3979 m_web_seeds_next_retry.erase(erase_element);
3983 // if we have everything we want we don't need to connect to any web-seed
3984 if (!is_finished() && !m_web_seeds.empty())
3986 // keep trying web-seeds if there are any
3987 // first find out which web seeds we are connected to
3988 std::set<std::string> web_seeds;
3989 for (peer_iterator i = m_connections.begin();
3990 i != m_connections.end(); ++i)
3992 web_peer_connection* p
3993 = dynamic_cast<web_peer_connection*>(*i);
3994 if (!p) continue;
3995 web_seeds.insert(p->url());
3998 for (std::set<std::string>::iterator i = m_resolving_web_seeds.begin()
3999 , end(m_resolving_web_seeds.end()); i != end; ++i)
4000 web_seeds.insert(web_seeds.begin(), *i);
4002 // from the list of available web seeds, subtract the ones we are
4003 // already connected to.
4004 std::vector<std::string> not_connected_web_seeds;
4005 std::set_difference(m_web_seeds.begin(), m_web_seeds.end(), web_seeds.begin()
4006 , web_seeds.end(), std::back_inserter(not_connected_web_seeds));
4008 // connect to all of those that we aren't connected to
4009 std::for_each(not_connected_web_seeds.begin(), not_connected_web_seeds.end()
4010 , bind(&torrent::connect_to_url_seed, this, _1));
4013 for (peer_iterator i = m_connections.begin();
4014 i != m_connections.end();)
4016 peer_connection* p = *i;
4017 ++i;
4018 p->calc_ip_overhead();
4019 m_stat += p->statistics();
4020 // updates the peer connection's ul/dl bandwidth
4021 // resource requests
4022 #ifndef BOOST_NO_EXCEPTIONS
4025 #endif
4026 p->second_tick(tick_interval);
4027 #ifndef BOOST_NO_EXCEPTIONS
4029 catch (std::exception& e)
4031 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
4032 (*p->m_logger) << "**ERROR**: " << e.what() << "\n";
4033 #endif
4034 p->disconnect(e.what(), 1);
4036 #endif
4038 accumulator += m_stat;
4039 m_total_uploaded += m_stat.last_payload_uploaded();
4040 m_total_downloaded += m_stat.last_payload_downloaded();
4041 m_stat.second_tick(tick_interval);
4043 m_time_scaler--;
4044 if (m_time_scaler <= 0)
4046 m_time_scaler = 10;
4047 m_policy.pulse();
4051 void torrent::retry_url_seed(std::string const& url)
4053 m_web_seeds_next_retry[url] = time_now()
4054 + seconds(m_ses.settings().urlseed_wait_retry);
4057 bool torrent::try_connect_peer()
4059 TORRENT_ASSERT(want_more_peers());
4060 if (m_deficit_counter < 100) return false;
4061 m_deficit_counter -= 100;
4062 bool ret = m_policy.connect_one_peer();
4063 return ret;
4066 void torrent::give_connect_points(int points)
4068 TORRENT_ASSERT(points <= 100);
4069 TORRENT_ASSERT(points > 0);
4070 TORRENT_ASSERT(want_more_peers());
4071 m_deficit_counter += points;
4074 void torrent::async_verify_piece(int piece_index, boost::function<void(int)> const& f)
4076 // INVARIANT_CHECK;
4078 TORRENT_ASSERT(m_storage);
4079 TORRENT_ASSERT(m_storage->refcount() > 0);
4080 TORRENT_ASSERT(piece_index >= 0);
4081 TORRENT_ASSERT(piece_index < m_torrent_file->num_pieces());
4082 TORRENT_ASSERT(piece_index < (int)m_picker->num_pieces());
4083 #ifndef NDEBUG
4084 if (m_picker)
4086 int blocks_in_piece = m_picker->blocks_in_piece(piece_index);
4087 for (int i = 0; i < blocks_in_piece; ++i)
4089 TORRENT_ASSERT(m_picker->num_peers(piece_block(piece_index, i)) == 0);
4092 #endif
4094 m_storage->async_hash(piece_index, bind(&torrent::on_piece_verified
4095 , shared_from_this(), _1, _2, f));
4096 #if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
4097 check_invariant();
4098 #endif
4101 void torrent::on_piece_verified(int ret, disk_io_job const& j
4102 , boost::function<void(int)> f)
4104 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4106 // return value:
4107 // 0: success, piece passed hash check
4108 // -1: disk failure
4109 // -2: hash check failed
4111 if (ret == -1)
4113 if (alerts().should_post<file_error_alert>())
4114 alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str));
4115 m_error = j.str;
4116 pause();
4118 f(ret);
4121 const tcp::endpoint& torrent::current_tracker() const
4123 return m_tracker_address;
4126 void torrent::file_progress(std::vector<float>& fp) const
4128 fp.clear();
4129 fp.resize(m_torrent_file->num_files(), 1.f);
4130 if (is_seed()) return;
4132 std::vector<size_type> progress;
4133 file_progress(progress);
4134 for (int i = 0; i < m_torrent_file->num_files(); ++i)
4136 file_entry const& f = m_torrent_file->file_at(i);
4137 if (f.size == 0) fp[i] = 1.f;
4138 else fp[i] = float(progress[i]) / f.size;
4142 void torrent::file_progress(std::vector<size_type>& fp) const
4144 TORRENT_ASSERT(valid_metadata());
4146 fp.resize(m_torrent_file->num_files(), 0);
4147 TORRENT_ASSERT(has_picker());
4149 if (is_seed())
4151 for (int i = 0; i < m_torrent_file->num_files(); ++i)
4152 fp[i] = m_torrent_file->files().at(i).size;
4153 return;
4156 for (int i = 0; i < m_torrent_file->num_files(); ++i)
4158 peer_request ret = m_torrent_file->files().map_file(i, 0, 0);
4159 size_type size = m_torrent_file->files().at(i).size;
4161 // zero sized files are considered
4162 // 100% done all the time
4163 if (size == 0)
4165 fp[i] = 0;
4166 continue;
4169 size_type done = 0;
4170 while (size > 0)
4172 size_type bytes_step = (std::min)(size_type(m_torrent_file->piece_size(ret.piece)
4173 - ret.start), size);
4174 if (m_picker->have_piece(ret.piece)) done += bytes_step;
4175 ++ret.piece;
4176 ret.start = 0;
4177 size -= bytes_step;
4179 TORRENT_ASSERT(size == 0);
4181 fp[i] = done;
4184 const std::vector<piece_picker::downloading_piece>& q
4185 = m_picker->get_download_queue();
4187 for (std::vector<piece_picker::downloading_piece>::const_iterator
4188 i = q.begin(), end(q.end()); i != end; ++i)
4190 size_type offset = size_type(i->index) * m_torrent_file->piece_length();
4191 torrent_info::file_iterator file = m_torrent_file->file_at_offset(offset);
4192 int file_index = file - m_torrent_file->begin_files();
4193 int num_blocks = m_picker->blocks_in_piece(i->index);
4194 piece_picker::block_info const* info = i->info;
4195 for (int k = 0; k < num_blocks; ++k)
4197 TORRENT_ASSERT(file != m_torrent_file->end_files());
4198 TORRENT_ASSERT(offset == size_type(i->index) * m_torrent_file->piece_length()
4199 + k * m_block_size);
4200 TORRENT_ASSERT(offset < m_torrent_file->total_size());
4201 while (offset >= file->offset + file->size)
4203 ++file;
4204 ++file_index;
4206 TORRENT_ASSERT(file != m_torrent_file->end_files());
4208 size_type block_size = m_block_size;
4210 if (info[k].state == piece_picker::block_info::state_none)
4212 offset += m_block_size;
4213 continue;
4216 if (info[k].state == piece_picker::block_info::state_requested)
4218 block_size = 0;
4219 policy::peer* p = static_cast<policy::peer*>(info[k].peer);
4220 if (p && p->connection)
4222 boost::optional<piece_block_progress> pbp
4223 = p->connection->downloading_piece_progress();
4224 if (pbp && pbp->piece_index == i->index && pbp->block_index == k)
4225 block_size = pbp->bytes_downloaded;
4226 TORRENT_ASSERT(block_size <= m_block_size);
4229 if (block_size == 0)
4231 offset += m_block_size;
4232 continue;
4236 if (offset + block_size > file->offset + file->size)
4238 int left_over = m_block_size - block_size;
4239 // split the block on multiple files
4240 while (block_size > 0)
4242 TORRENT_ASSERT(offset <= file->offset + file->size);
4243 size_type slice = (std::min)(file->offset + file->size - offset
4244 , block_size);
4245 fp[file_index] += slice;
4246 offset += slice;
4247 block_size -= slice;
4248 TORRENT_ASSERT(offset <= file->offset + file->size);
4249 if (offset == file->offset + file->size)
4251 ++file;
4252 ++file_index;
4253 if (file == m_torrent_file->end_files())
4255 offset += block_size;
4256 break;
4260 offset += left_over;
4261 TORRENT_ASSERT(offset == size_type(i->index) * m_torrent_file->piece_length()
4262 + (k+1) * m_block_size);
4264 else
4266 fp[file_index] += block_size;
4267 offset += m_block_size;
4269 TORRENT_ASSERT(file_index <= m_torrent_file->num_files());
4274 void torrent::set_state(torrent_status::state_t s)
4276 if (m_state == s) return;
4277 m_state = s;
4278 if (m_ses.m_alerts.should_post<state_changed_alert>())
4279 m_ses.m_alerts.post_alert(state_changed_alert(get_handle(), s));
4282 torrent_status torrent::status() const
4284 INVARIANT_CHECK;
4286 ptime now = time_now();
4288 torrent_status st;
4290 st.has_incoming = m_has_incoming;
4291 st.error = m_error;
4293 if (m_last_scrape == min_time())
4295 st.last_scrape = -1;
4297 else
4299 st.last_scrape = total_seconds(now - m_last_scrape);
4301 st.up_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::upload_channel].size();
4302 st.down_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::download_channel].size();
4304 st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end()
4305 , !boost::bind(&peer_connection::is_connecting, _1));
4307 st.list_peers = m_policy.num_peers();
4308 st.list_seeds = m_policy.num_seeds();
4309 st.connect_candidates = m_policy.num_connect_candidates();
4310 st.seed_rank = seed_rank(m_ses.m_settings);
4312 st.all_time_upload = m_total_uploaded;
4313 st.all_time_download = m_total_downloaded;
4315 st.active_time = total_seconds(m_active_time);
4316 st.seeding_time = total_seconds(m_seeding_time);
4318 st.storage_mode = m_storage_mode;
4320 st.num_complete = m_complete;
4321 st.num_incomplete = m_incomplete;
4322 st.paused = m_paused;
4323 boost::tie(st.total_done, st.total_wanted_done) = bytes_done();
4324 TORRENT_ASSERT(st.total_wanted_done >= 0);
4325 TORRENT_ASSERT(st.total_done >= st.total_wanted_done);
4327 // payload transfer
4328 st.total_payload_download = m_stat.total_payload_download();
4329 st.total_payload_upload = m_stat.total_payload_upload();
4331 // total transfer
4332 st.total_download = m_stat.total_payload_download()
4333 + m_stat.total_protocol_download();
4334 st.total_upload = m_stat.total_payload_upload()
4335 + m_stat.total_protocol_upload();
4337 // failed bytes
4338 st.total_failed_bytes = m_total_failed_bytes;
4339 st.total_redundant_bytes = m_total_redundant_bytes;
4341 // transfer rate
4342 st.download_rate = m_stat.download_rate();
4343 st.upload_rate = m_stat.upload_rate();
4344 st.download_payload_rate = m_stat.download_payload_rate();
4345 st.upload_payload_rate = m_stat.upload_payload_rate();
4347 st.next_announce = boost::posix_time::seconds(
4348 total_seconds(next_announce() - now));
4349 if (st.next_announce.is_negative() || is_paused())
4350 st.next_announce = boost::posix_time::seconds(0);
4352 st.announce_interval = boost::posix_time::seconds(m_duration);
4354 if (m_last_working_tracker >= 0)
4356 st.current_tracker
4357 = m_trackers[m_last_working_tracker].url;
4360 st.num_uploads = m_num_uploads;
4361 st.uploads_limit = m_max_uploads;
4362 st.num_connections = int(m_connections.size());
4363 st.connections_limit = m_max_connections;
4364 // if we don't have any metadata, stop here
4366 st.state = m_state;
4368 if (!valid_metadata())
4370 if (m_got_tracker_response == false && m_connections.empty())
4371 st.state = torrent_status::connecting_to_tracker;
4372 else
4373 st.state = torrent_status::downloading_metadata;
4375 st.progress = m_progress;
4376 st.block_size = 0;
4377 return st;
4380 st.block_size = block_size();
4382 // fill in status that depends on metadata
4384 st.total_wanted = m_torrent_file->total_size();
4385 TORRENT_ASSERT(st.total_wanted >= 0);
4386 TORRENT_ASSERT(st.total_wanted >= m_torrent_file->piece_length()
4387 * (m_torrent_file->num_pieces() - 1));
4389 if (m_picker.get() && (m_picker->num_filtered() > 0
4390 || m_picker->num_have_filtered() > 0))
4392 int num_filtered_pieces = m_picker->num_filtered()
4393 + m_picker->num_have_filtered();
4394 int last_piece_index = m_torrent_file->num_pieces() - 1;
4395 if (m_picker->piece_priority(last_piece_index) == 0)
4397 st.total_wanted -= m_torrent_file->piece_size(last_piece_index);
4398 --num_filtered_pieces;
4401 st.total_wanted -= size_type(num_filtered_pieces) * m_torrent_file->piece_length();
4404 TORRENT_ASSERT(st.total_wanted >= st.total_wanted_done);
4406 if (m_state == torrent_status::checking_files)
4407 st.progress = m_progress;
4408 else if (st.total_wanted == 0) st.progress = 1.f;
4409 else st.progress = st.total_wanted_done
4410 / static_cast<float>(st.total_wanted);
4412 if (has_picker())
4414 int num_pieces = m_picker->num_pieces();
4415 st.pieces.resize(num_pieces, false);
4416 for (int i = 0; i < num_pieces; ++i)
4417 if (m_picker->have_piece(i)) st.pieces.set_bit(i);
4419 st.num_pieces = num_have();
4420 st.num_seeds = num_seeds();
4421 if (m_picker.get())
4422 st.distributed_copies = m_picker->distributed_copies();
4423 else
4424 st.distributed_copies = -1;
4425 return st;
4428 void torrent::add_redundant_bytes(int b)
4430 TORRENT_ASSERT(b > 0);
4431 m_total_redundant_bytes += b;
4432 m_ses.add_redundant_bytes(b);
4435 void torrent::add_failed_bytes(int b)
4437 TORRENT_ASSERT(b > 0);
4438 m_total_failed_bytes += b;
4439 m_ses.add_failed_bytes(b);
4442 int torrent::num_seeds() const
4444 INVARIANT_CHECK;
4446 return (int)std::count_if(m_connections.begin(), m_connections.end()
4447 , boost::bind(&peer_connection::is_seed, _1));
4450 void torrent::tracker_request_timed_out(
4451 tracker_request const& r)
4453 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4455 INVARIANT_CHECK;
4457 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4458 debug_log("*** tracker timed out");
4459 #endif
4461 if (r.kind == tracker_request::announce_request)
4463 if (m_ses.m_alerts.should_post<tracker_error_alert>())
4465 m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
4466 , m_failed_trackers + 1, 0, r.url, "tracker timed out"));
4469 else if (r.kind == tracker_request::scrape_request)
4471 if (m_ses.m_alerts.should_post<scrape_failed_alert>())
4473 m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle()
4474 , r.url, "tracker timed out"));
4478 if (r.kind == tracker_request::announce_request)
4479 try_next_tracker(r);
4482 // TODO: with some response codes, we should just consider
4483 // the tracker as a failure and not retry
4484 // it anymore
4485 void torrent::tracker_request_error(tracker_request const& r
4486 , int response_code, const std::string& str)
4488 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4490 INVARIANT_CHECK;
4492 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4493 debug_log(std::string("*** tracker error: ") + str);
4494 #endif
4495 if (r.kind == tracker_request::announce_request)
4497 if (m_ses.m_alerts.should_post<tracker_error_alert>())
4499 m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
4500 , m_failed_trackers + 1, response_code, r.url, str));
4503 else if (r.kind == tracker_request::scrape_request)
4505 if (m_ses.m_alerts.should_post<scrape_failed_alert>())
4507 m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), r.url, str));
4511 if (r.kind == tracker_request::announce_request)
4512 try_next_tracker(r);
4516 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4517 void torrent::debug_log(const std::string& line)
4519 (*m_ses.m_logger) << time_now_string() << " " << line << "\n";
4521 #endif