added missing file error_code.cpp
[libtorrent.git] / src / torrent.cpp
blob66d6d1c499ffb9c781df753335ed5fda266c456a
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_block_size = (std::min)(m_block_size, m_torrent_file->piece_length());
429 if (m_torrent_file->num_pieces()
430 > piece_picker::max_pieces)
432 m_error = "too many pieces in torrent";
433 pause();
436 // the shared_from_this() will create an intentional
437 // cycle of ownership, se the hpp file for description.
438 m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
439 , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor
440 , m_storage_mode);
441 m_storage = m_owning_storage.get();
442 m_picker->init((std::max)(m_torrent_file->piece_length() / m_block_size, 1)
443 , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
445 std::vector<std::string> const& url_seeds = m_torrent_file->url_seeds();
446 std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
447 , m_web_seeds.begin()));
449 set_state(torrent_status::queued_for_checking);
451 if (m_resume_entry.type() == lazy_entry::dict_t)
453 char const* error = 0;
454 if (m_resume_entry.dict_find_string_value("file-format") != "libtorrent resume file")
455 error = "invalid file format tag";
457 std::string info_hash = m_resume_entry.dict_find_string_value("info-hash");
458 if (!error && info_hash.empty())
459 error = "missing info-hash";
461 if (!error && sha1_hash(info_hash) != m_torrent_file->info_hash())
462 error = "mismatching info-hash";
464 if (error && m_ses.m_alerts.should_post<fastresume_rejected_alert>())
466 m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), error));
467 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
468 (*m_ses.m_logger) << "fastresume data for "
469 << torrent_file().name() << " rejected: "
470 << error << "\n";
471 #endif
474 if (error)
476 std::vector<char>().swap(m_resume_data);
477 lazy_entry().swap(m_resume_entry);
479 else
481 read_resume_data(m_resume_entry);
485 m_storage->async_check_fastresume(&m_resume_entry
486 , bind(&torrent::on_resume_data_checked
487 , shared_from_this(), _1, _2));
490 void torrent::on_resume_data_checked(int ret, disk_io_job const& j)
492 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
494 if (ret == piece_manager::fatal_disk_error)
496 if (m_ses.m_alerts.should_post<file_error_alert>())
498 m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
499 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
500 (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
501 " error: " << j.str <<
502 " torrent: " << torrent_file().name() <<
503 " ]\n";
504 #endif
506 m_error = j.str;
507 pause();
509 std::vector<char>().swap(m_resume_data);
510 lazy_entry().swap(m_resume_entry);
512 return;
515 if (m_resume_entry.type() == lazy_entry::dict_t)
517 // parse out "peers" from the resume data and add them to the peer list
518 if (lazy_entry const* peers_entry = m_resume_entry.dict_find_list("peers"))
520 peer_id id(0);
522 for (int i = 0; i < peers_entry->list_size(); ++i)
524 lazy_entry const* e = peers_entry->list_at(i);
525 if (e->type() != lazy_entry::dict_t) continue;
526 std::string ip = e->dict_find_string_value("ip");
527 int port = e->dict_find_int_value("port");
528 if (ip.empty() || port == 0) continue;
529 tcp::endpoint a(address::from_string(ip), (unsigned short)port);
530 m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
534 // parse out "banned_peers" and add them as banned
535 if (lazy_entry const* banned_peers_entry = m_resume_entry.dict_find_list("banned_peers"))
537 peer_id id(0);
539 for (int i = 0; i < banned_peers_entry->list_size(); ++i)
541 lazy_entry const* e = banned_peers_entry->list_at(i);
542 if (e->type() != lazy_entry::dict_t) continue;
543 std::string ip = e->dict_find_string_value("ip");
544 int port = e->dict_find_int_value("port");
545 if (ip.empty() || port == 0) continue;
546 tcp::endpoint a(address::from_string(ip), (unsigned short)port);
547 policy::peer* p = m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
548 if (p) p->banned = true;
553 bool fastresume_rejected = !j.str.empty();
555 if (fastresume_rejected && m_ses.m_alerts.should_post<fastresume_rejected_alert>())
557 m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), j.str));
558 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
559 (*m_ses.m_logger) << "fastresume data for "
560 << torrent_file().name() << " rejected: "
561 << j.str << "\n";
562 #endif
565 if (ret == 0)
567 // there are either no files for this torrent
568 // or the resume_data was accepted
570 if (!fastresume_rejected && m_resume_entry.type() == lazy_entry::dict_t)
572 // parse have bitmask
573 lazy_entry const* pieces = m_resume_entry.dict_find("pieces");
574 if (pieces && pieces->type() == lazy_entry::string_t
575 && int(pieces->string_length()) == m_torrent_file->num_pieces())
577 char const* pieces_str = pieces->string_ptr();
578 for (int i = 0, end(pieces->string_length()); i < end; ++i)
580 if ((pieces_str[i] & 1) == 0) continue;
581 m_picker->we_have(i);
585 // parse unfinished pieces
586 int num_blocks_per_piece =
587 static_cast<int>(torrent_file().piece_length()) / block_size();
589 if (lazy_entry const* unfinished_ent = m_resume_entry.dict_find_list("unfinished"))
591 for (int i = 0; i < unfinished_ent->list_size(); ++i)
593 lazy_entry const* e = unfinished_ent->list_at(i);
594 if (e->type() != lazy_entry::dict_t) continue;
595 int piece = e->dict_find_int_value("piece", -1);
596 if (piece < 0 || piece > torrent_file().num_pieces()) continue;
598 if (m_picker->have_piece(piece))
599 m_picker->we_dont_have(piece);
601 std::string bitmask = e->dict_find_string_value("bitmask");
602 if (bitmask.empty()) continue;
604 const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1);
605 if ((int)bitmask.size() != num_bitmask_bytes) continue;
606 for (int j = 0; j < num_bitmask_bytes; ++j)
608 unsigned char bits = bitmask[j];
609 int num_bits = (std::min)(num_blocks_per_piece - j*8, 8);
610 for (int k = 0; k < num_bits; ++k)
612 const int bit = j * 8 + k;
613 if (bits & (1 << k))
615 m_picker->mark_as_finished(piece_block(piece, bit), 0);
616 if (m_picker->is_piece_finished(piece))
617 async_verify_piece(piece, bind(&torrent::piece_finished
618 , shared_from_this(), piece, _1));
626 files_checked();
628 else
630 // either the fastresume data was rejected or there are
631 // some files
632 m_ses.check_torrent(shared_from_this());
635 std::vector<char>().swap(m_resume_data);
636 lazy_entry().swap(m_resume_entry);
639 void torrent::force_recheck()
641 if (m_state == torrent_status::checking_files
642 || m_state == torrent_status::queued_for_checking)
643 return;
645 disconnect_all();
647 m_owning_storage->async_release_files();
648 m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
649 , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor
650 , m_storage_mode);
651 m_storage = m_owning_storage.get();
652 m_picker.reset(new piece_picker);
653 m_picker->init(m_torrent_file->piece_length() / m_block_size
654 , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
655 // assume that we don't have anything
656 m_files_checked = false;
657 set_state(torrent_status::queued_for_checking);
659 if (m_auto_managed)
660 set_queue_position((std::numeric_limits<int>::max)());
662 std::vector<char>().swap(m_resume_data);
663 lazy_entry().swap(m_resume_entry);
664 m_storage->async_check_fastresume(&m_resume_entry
665 , bind(&torrent::on_force_recheck
666 , shared_from_this(), _1, _2));
669 void torrent::on_force_recheck(int ret, disk_io_job const& j)
671 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
673 if (ret == piece_manager::fatal_disk_error)
675 if (m_ses.m_alerts.should_post<file_error_alert>())
677 m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
678 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
679 (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
680 " error: " << j.str <<
681 " torrent: " << torrent_file().name() <<
682 " ]\n";
683 #endif
685 m_error = j.str;
686 pause();
687 return;
689 m_ses.check_torrent(shared_from_this());
692 void torrent::start_checking()
694 set_state(torrent_status::checking_files);
696 m_storage->async_check_files(bind(
697 &torrent::on_piece_checked
698 , shared_from_this(), _1, _2));
701 void torrent::on_piece_checked(int ret, disk_io_job const& j)
703 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
705 if (ret == piece_manager::disk_check_aborted)
707 m_error = "aborted";
708 m_ses.done_checking(shared_from_this());
709 return;
711 if (ret == piece_manager::fatal_disk_error)
713 if (m_ses.m_alerts.should_post<file_error_alert>())
715 m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str));
716 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
717 (*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
718 " error: " << j.str <<
719 " torrent: " << torrent_file().name() <<
720 " ]\n";
721 #endif
723 m_error = j.str;
724 pause();
725 m_ses.done_checking(shared_from_this());
726 return;
729 m_progress = j.piece / float(torrent_file().num_pieces());
731 TORRENT_ASSERT(m_picker);
732 if (j.offset >= 0 && !m_picker->have_piece(j.offset))
733 m_picker->we_have(j.offset);
735 // we're not done checking yet
736 // this handler will be called repeatedly until
737 // we're done, or encounter a failure
738 if (ret == piece_manager::need_full_check) return;
740 m_ses.done_checking(shared_from_this());
741 files_checked();
744 void torrent::use_interface(const char* net_interface)
746 INVARIANT_CHECK;
748 m_net_interface = tcp::endpoint(address::from_string(net_interface), 0);
751 void torrent::on_tracker_announce_disp(boost::weak_ptr<torrent> p
752 , error_code const& e)
754 if (e) return;
755 boost::shared_ptr<torrent> t = p.lock();
756 if (!t) return;
757 t->on_tracker_announce();
760 void torrent::on_tracker_announce()
762 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
764 if (m_abort) return;
765 announce_with_tracker();
768 void torrent::on_lsd_announce_disp(boost::weak_ptr<torrent> p
769 , error_code const& e)
771 if (e) return;
772 boost::shared_ptr<torrent> t = p.lock();
773 if (!t) return;
774 t->on_lsd_announce();
777 void torrent::on_lsd_announce()
779 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
781 if (m_abort) return;
783 TORRENT_ASSERT(!m_torrent_file->priv());
784 if (m_torrent_file->is_valid() && m_torrent_file->priv())
785 return;
787 if (is_paused()) return;
789 boost::weak_ptr<torrent> self(shared_from_this());
791 error_code ec;
793 // announce on local network every 5 minutes
794 m_lsd_announce_timer.expires_from_now(minutes(5), ec);
795 m_lsd_announce_timer.async_wait(
796 bind(&torrent::on_lsd_announce_disp, self, _1));
798 // announce with the local discovery service
799 m_ses.announce_lsd(m_torrent_file->info_hash());
801 #ifndef TORRENT_DISABLE_DHT
802 if (!m_ses.m_dht) return;
803 ptime now = time_now();
804 if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
806 m_last_dht_announce = now;
807 m_ses.m_dht->announce(m_torrent_file->info_hash()
808 , m_ses.m_listen_sockets.front().external_port
809 , bind(&torrent::on_dht_announce_response_disp, self, _1));
811 #endif
814 #ifndef TORRENT_DISABLE_DHT
816 void torrent::on_dht_announce_response_disp(boost::weak_ptr<libtorrent::torrent> t
817 , std::vector<tcp::endpoint> const& peers)
819 boost::shared_ptr<libtorrent::torrent> tor = t.lock();
820 if (!tor) return;
821 tor->on_dht_announce_response(peers);
824 void torrent::on_dht_announce_response(std::vector<tcp::endpoint> const& peers)
826 if (peers.empty()) return;
828 if (m_ses.m_alerts.should_post<dht_reply_alert>())
830 m_ses.m_alerts.post_alert(dht_reply_alert(
831 get_handle(), peers.size()));
833 std::for_each(peers.begin(), peers.end(), bind(
834 &policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0)
835 , peer_info::dht, 0));
838 #endif
840 void torrent::announce_with_tracker(tracker_request::event_t e)
842 INVARIANT_CHECK;
844 if (m_trackers.empty()) return;
846 restart_tracker_timer(time_now() + seconds(tracker_retry_delay_max));
848 if (e == tracker_request::none)
850 if (!m_start_sent) e = tracker_request::started;
851 if (!m_complete_sent && is_seed()) e = tracker_request::completed;
854 tracker_request req;
855 req.info_hash = m_torrent_file->info_hash();
856 req.pid = m_ses.get_peer_id();
857 req.downloaded = m_stat.total_payload_download();
858 req.uploaded = m_stat.total_payload_upload();
859 req.left = bytes_left();
860 if (req.left == -1) req.left = 16*1024;
861 req.event = e;
862 tcp::endpoint ep = m_ses.get_ipv6_interface();
863 if (ep != tcp::endpoint())
864 req.ipv6 = ep.address().to_string();
866 req.url = m_trackers[m_currently_trying_tracker].url;
867 // if we are aborting. we don't want any new peers
868 req.num_want = (req.event == tracker_request::stopped)
869 ?0:m_settings.num_want;
871 req.listen_port = m_ses.m_listen_sockets.empty()
872 ?0:m_ses.m_listen_sockets.front().external_port;
873 req.key = m_ses.m_key;
875 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
876 if (m_abort)
878 boost::shared_ptr<aux::tracker_logger> tl(new aux::tracker_logger(m_ses));
879 m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
880 , tracker_login(), m_ses.m_listen_interface.address(), tl);
882 else
883 #endif
884 m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
885 , tracker_login(), m_ses.m_listen_interface.address()
886 , m_abort?boost::shared_ptr<torrent>():shared_from_this());
888 if (m_ses.m_alerts.should_post<tracker_announce_alert>())
890 m_ses.m_alerts.post_alert(
891 tracker_announce_alert(get_handle(), req.url, req.event));
895 void torrent::scrape_tracker()
897 if (m_trackers.empty()) return;
899 TORRENT_ASSERT(m_currently_trying_tracker >= 0);
900 TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size()));
902 tracker_request req;
903 req.info_hash = m_torrent_file->info_hash();
904 req.kind = tracker_request::scrape_request;
905 req.url = m_trackers[m_currently_trying_tracker].url;
906 m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
907 , tracker_login(), m_ses.m_listen_interface.address(), shared_from_this());
909 m_last_scrape = time_now();
912 void torrent::tracker_warning(tracker_request const& req, std::string const& msg)
914 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
916 INVARIANT_CHECK;
918 if (m_ses.m_alerts.should_post<tracker_warning_alert>())
919 m_ses.m_alerts.post_alert(tracker_warning_alert(get_handle(), req.url, msg));
922 void torrent::tracker_scrape_response(tracker_request const& req
923 , int complete, int incomplete, int downloaded)
925 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
927 INVARIANT_CHECK;
928 TORRENT_ASSERT(req.kind == tracker_request::scrape_request);
930 if (complete >= 0) m_complete = complete;
931 if (incomplete >= 0) m_incomplete = incomplete;
933 if (m_ses.m_alerts.should_post<scrape_reply_alert>())
935 m_ses.m_alerts.post_alert(scrape_reply_alert(
936 get_handle(), m_incomplete, m_complete, req.url));
940 void torrent::tracker_response(
941 tracker_request const& r
942 , std::vector<peer_entry>& peer_list
943 , int interval
944 , int complete
945 , int incomplete
946 , address const& external_ip)
948 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
950 INVARIANT_CHECK;
951 TORRENT_ASSERT(r.kind == tracker_request::announce_request);
953 if (external_ip != address())
954 m_ses.set_external_address(external_ip);
956 if (!m_start_sent && r.event == tracker_request::started)
957 m_start_sent = true;
958 if (!m_complete_sent && r.event == tracker_request::completed)
959 m_complete_sent = true;
961 m_failed_trackers = 0;
962 // announce intervals less than 5 minutes
963 // are insane.
964 if (interval < 60 * 5) interval = 60 * 5;
966 m_last_working_tracker
967 = prioritize_tracker(m_currently_trying_tracker);
968 m_currently_trying_tracker = 0;
970 m_duration = interval;
971 restart_tracker_timer(time_now() + seconds(m_duration));
973 if (complete >= 0) m_complete = complete;
974 if (incomplete >= 0) m_incomplete = incomplete;
975 if (complete >= 0 && incomplete >= 0)
976 m_last_scrape = time_now();
978 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
979 std::stringstream s;
980 s << "TRACKER RESPONSE:\n"
981 "interval: " << m_duration << "\n"
982 "peers:\n";
983 for (std::vector<peer_entry>::const_iterator i = peer_list.begin();
984 i != peer_list.end(); ++i)
986 s << " " << std::setfill(' ') << std::setw(16) << i->ip
987 << " " << std::setw(5) << std::dec << i->port << " ";
988 if (!i->pid.is_all_zeros()) s << " " << i->pid << " " << identify_client(i->pid);
989 s << "\n";
991 s << "external ip: " << external_ip << "\n";
992 debug_log(s.str());
993 #endif
994 // for each of the peers we got from the tracker
995 for (std::vector<peer_entry>::iterator i = peer_list.begin();
996 i != peer_list.end(); ++i)
998 // don't make connections to ourself
999 if (i->pid == m_ses.get_peer_id())
1000 continue;
1002 error_code ec;
1003 tcp::endpoint a(address::from_string(i->ip, ec), i->port);
1005 if (ec)
1007 // assume this is because we got a hostname instead of
1008 // an ip address from the tracker
1010 tcp::resolver::query q(i->ip, boost::lexical_cast<std::string>(i->port));
1011 m_host_resolver.async_resolve(q,
1012 bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid));
1014 else
1016 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
1018 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
1019 debug_log("blocked ip from tracker: " + i->ip);
1020 #endif
1021 if (m_ses.m_alerts.should_post<peer_blocked_alert>())
1022 m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()));
1024 continue;
1027 m_policy.peer_from_tracker(a, i->pid, peer_info::tracker, 0);
1031 if (m_ses.m_alerts.should_post<tracker_reply_alert>())
1033 m_ses.m_alerts.post_alert(tracker_reply_alert(
1034 get_handle(), peer_list.size(), r.url));
1036 m_got_tracker_response = true;
1039 void torrent::on_peer_name_lookup(error_code const& e, tcp::resolver::iterator host
1040 , peer_id pid)
1042 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1044 INVARIANT_CHECK;
1046 if (e || host == tcp::resolver::iterator() ||
1047 m_ses.is_aborted()) return;
1049 if (m_ses.m_ip_filter.access(host->endpoint().address()) & ip_filter::blocked)
1051 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
1052 debug_log("blocked ip from tracker: " + host->endpoint().address().to_string());
1053 #endif
1054 if (m_ses.m_alerts.should_post<peer_blocked_alert>())
1056 m_ses.m_alerts.post_alert(peer_blocked_alert(host->endpoint().address()));
1059 return;
1062 m_policy.peer_from_tracker(*host, pid, peer_info::tracker, 0);
1065 size_type torrent::bytes_left() const
1067 // if we don't have the metadata yet, we
1068 // cannot tell how big the torrent is.
1069 if (!valid_metadata()) return -1;
1070 return m_torrent_file->total_size()
1071 - quantized_bytes_done();
1074 size_type torrent::quantized_bytes_done() const
1076 // INVARIANT_CHECK;
1078 if (!valid_metadata()) return 0;
1080 if (m_torrent_file->num_pieces() == 0)
1081 return 0;
1083 if (is_seed()) return m_torrent_file->total_size();
1085 const int last_piece = m_torrent_file->num_pieces() - 1;
1087 size_type total_done
1088 = size_type(num_have()) * m_torrent_file->piece_length();
1090 // if we have the last piece, we have to correct
1091 // the amount we have, since the first calculation
1092 // assumed all pieces were of equal size
1093 if (m_picker->have_piece(last_piece))
1095 int corr = m_torrent_file->piece_size(last_piece)
1096 - m_torrent_file->piece_length();
1097 total_done += corr;
1099 return total_done;
1102 // the first value is the total number of bytes downloaded
1103 // the second value is the number of bytes of those that haven't
1104 // been filtered as not wanted we have downloaded
1105 tuple<size_type, size_type> torrent::bytes_done() const
1107 INVARIANT_CHECK;
1109 if (!valid_metadata() || m_torrent_file->num_pieces() == 0)
1110 return tuple<size_type, size_type>(0,0);
1112 const int last_piece = m_torrent_file->num_pieces() - 1;
1113 const int piece_size = m_torrent_file->piece_length();
1115 if (is_seed())
1116 return make_tuple(m_torrent_file->total_size()
1117 , m_torrent_file->total_size());
1119 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1120 size_type wanted_done = size_type(num_have() - m_picker->num_have_filtered())
1121 * piece_size;
1122 TORRENT_ASSERT(wanted_done >= 0);
1124 size_type total_done
1125 = size_type(num_have()) * piece_size;
1126 TORRENT_ASSERT(num_have() < m_torrent_file->num_pieces());
1128 // if we have the last piece, we have to correct
1129 // the amount we have, since the first calculation
1130 // assumed all pieces were of equal size
1131 if (m_picker->have_piece(last_piece))
1133 TORRENT_ASSERT(total_done >= piece_size);
1134 int corr = m_torrent_file->piece_size(last_piece)
1135 - piece_size;
1136 TORRENT_ASSERT(corr <= 0);
1137 TORRENT_ASSERT(corr > -piece_size);
1138 total_done += corr;
1139 if (m_picker->piece_priority(last_piece) != 0)
1141 TORRENT_ASSERT(wanted_done >= piece_size);
1142 wanted_done += corr;
1146 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1147 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1148 TORRENT_ASSERT(total_done >= wanted_done);
1150 const std::vector<piece_picker::downloading_piece>& dl_queue
1151 = m_picker->get_download_queue();
1153 const int blocks_per_piece = piece_size / m_block_size;
1155 for (std::vector<piece_picker::downloading_piece>::const_iterator i =
1156 dl_queue.begin(); i != dl_queue.end(); ++i)
1158 int corr = 0;
1159 int index = i->index;
1160 if (m_picker->have_piece(index)) continue;
1161 TORRENT_ASSERT(i->finished <= m_picker->blocks_in_piece(index));
1163 #ifndef NDEBUG
1164 for (std::vector<piece_picker::downloading_piece>::const_iterator j = boost::next(i);
1165 j != dl_queue.end(); ++j)
1167 TORRENT_ASSERT(j->index != index);
1169 #endif
1171 for (int j = 0; j < blocks_per_piece; ++j)
1173 TORRENT_ASSERT(m_picker->is_finished(piece_block(index, j)) == (i->info[j].state == piece_picker::block_info::state_finished));
1174 corr += (i->info[j].state == piece_picker::block_info::state_finished) * m_block_size;
1175 TORRENT_ASSERT(corr >= 0);
1176 TORRENT_ASSERT(index != last_piece || j < m_picker->blocks_in_last_piece()
1177 || i->info[j].state != piece_picker::block_info::state_finished);
1180 // correction if this was the last piece
1181 // and if we have the last block
1182 if (i->index == last_piece
1183 && i->info[m_picker->blocks_in_last_piece()-1].state
1184 == piece_picker::block_info::state_finished)
1186 corr -= m_block_size;
1187 corr += m_torrent_file->piece_size(last_piece) % m_block_size;
1189 total_done += corr;
1190 if (m_picker->piece_priority(index) != 0)
1191 wanted_done += corr;
1194 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1195 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1197 std::map<piece_block, int> downloading_piece;
1198 for (const_peer_iterator i = begin(); i != end(); ++i)
1200 peer_connection* pc = *i;
1201 boost::optional<piece_block_progress> p
1202 = pc->downloading_piece_progress();
1203 if (p)
1205 if (m_picker->have_piece(p->piece_index))
1206 continue;
1208 piece_block block(p->piece_index, p->block_index);
1209 if (m_picker->is_finished(block))
1210 continue;
1212 std::map<piece_block, int>::iterator dp
1213 = downloading_piece.find(block);
1214 if (dp != downloading_piece.end())
1216 if (dp->second < p->bytes_downloaded)
1217 dp->second = p->bytes_downloaded;
1219 else
1221 downloading_piece[block] = p->bytes_downloaded;
1223 #ifndef NDEBUG
1224 TORRENT_ASSERT(p->bytes_downloaded <= p->full_block_bytes);
1225 int last_piece = m_torrent_file->num_pieces() - 1;
1226 if (p->piece_index == last_piece
1227 && p->block_index == m_torrent_file->piece_size(last_piece) / block_size())
1228 TORRENT_ASSERT(p->full_block_bytes == m_torrent_file->piece_size(last_piece) % block_size());
1229 else
1230 TORRENT_ASSERT(p->full_block_bytes == block_size());
1231 #endif
1234 for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
1235 i != downloading_piece.end(); ++i)
1237 total_done += i->second;
1238 if (m_picker->piece_priority(i->first.piece_index) != 0)
1239 wanted_done += i->second;
1242 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1243 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1245 #ifndef NDEBUG
1247 if (total_done >= m_torrent_file->total_size())
1249 // Thist happens when a piece has been downloaded completely
1250 // but not yet verified against the hash
1251 std::cerr << "num_have: " << num_have() << std::endl;
1253 std::cerr << "unfinished:" << std::endl;
1255 for (std::vector<piece_picker::downloading_piece>::const_iterator i =
1256 dl_queue.begin(); i != dl_queue.end(); ++i)
1258 std::cerr << " " << i->index << " ";
1259 for (int j = 0; j < blocks_per_piece; ++j)
1261 std::cerr << (i->info[j].state == piece_picker::block_info::state_finished ? "1" : "0");
1263 std::cerr << std::endl;
1266 std::cerr << "downloading pieces:" << std::endl;
1268 for (std::map<piece_block, int>::iterator i = downloading_piece.begin();
1269 i != downloading_piece.end(); ++i)
1271 std::cerr << " " << i->first.piece_index << ":" << i->first.block_index
1272 << " " << i->second << std::endl;
1277 TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
1278 TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
1280 #endif
1282 TORRENT_ASSERT(total_done >= wanted_done);
1283 return make_tuple(total_done, wanted_done);
1286 // passed_hash_check
1287 // 0: success, piece passed check
1288 // -1: disk failure
1289 // -2: piece failed check
1290 void torrent::piece_finished(int index, int passed_hash_check)
1292 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1294 #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
1295 (*m_ses.m_logger) << time_now_string() << " *** PIECE_FINISHED [ p: "
1296 << index << " chk: " << ((passed_hash_check == 0)
1297 ?"passed":passed_hash_check == -1
1298 ?"disk failed":"failed") << " ]\n";
1299 #endif
1301 TORRENT_ASSERT(valid_metadata());
1303 if (passed_hash_check == 0)
1305 // the following call may cause picker to become invalid
1306 // in case we just became a seed
1307 piece_passed(index);
1309 else if (passed_hash_check == -2)
1311 // piece_failed() will restore the piece
1312 piece_failed(index);
1314 else
1316 TORRENT_ASSERT(passed_hash_check == -1);
1317 m_picker->restore_piece(index);
1318 restore_piece_state(index);
1322 void torrent::piece_passed(int index)
1324 // INVARIANT_CHECK;
1326 TORRENT_ASSERT(index >= 0);
1327 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1329 if (m_ses.m_alerts.should_post<piece_finished_alert>())
1331 m_ses.m_alerts.post_alert(piece_finished_alert(get_handle()
1332 , index));
1335 bool was_finished = m_picker->num_filtered() + num_have()
1336 == torrent_file().num_pieces();
1338 std::vector<void*> downloaders;
1339 m_picker->get_downloaders(downloaders, index);
1341 // increase the trust point of all peers that sent
1342 // parts of this piece.
1343 std::set<void*> peers;
1344 std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
1346 m_picker->we_have(index);
1347 for (peer_iterator i = m_connections.begin(); i != m_connections.end();)
1349 peer_connection* p = *i;
1350 ++i;
1351 p->announce_piece(index);
1354 for (std::set<void*>::iterator i = peers.begin()
1355 , end(peers.end()); i != end; ++i)
1357 policy::peer* p = static_cast<policy::peer*>(*i);
1358 if (p == 0) continue;
1359 p->on_parole = false;
1360 ++p->trust_points;
1361 // TODO: make this limit user settable
1362 if (p->trust_points > 20) p->trust_points = 20;
1363 if (p->connection) p->connection->received_valid_data(index);
1366 #ifndef TORRENT_DISABLE_EXTENSIONS
1367 for (extension_list_t::iterator i = m_extensions.begin()
1368 , end(m_extensions.end()); i != end; ++i)
1370 #ifndef BOOST_NO_EXCEPTIONS
1371 try {
1372 #endif
1373 (*i)->on_piece_pass(index);
1374 #ifndef BOOST_NO_EXCEPTIONS
1375 } catch (std::exception&) {}
1376 #endif
1378 #endif
1380 // since this piece just passed, we might have
1381 // become uninterested in some peers where this
1382 // was the last piece we were interested in
1383 for (peer_iterator i = m_connections.begin()
1384 , end(m_connections.end()); i != end; ++i)
1386 peer_connection* p = *i;
1387 // if we're not interested already, no need to check
1388 if (!p->is_interesting()) continue;
1389 // if the peer doesn't have the piece we just got, it
1390 // wouldn't affect our interest
1391 if (!p->has_piece(index)) continue;
1392 p->update_interest();
1395 if (!was_finished && is_finished())
1397 // torrent finished
1398 // i.e. all the pieces we're interested in have
1399 // been downloaded. Release the files (they will open
1400 // in read only mode if needed)
1401 finished();
1402 // if we just became a seed, picker is now invalid, since it
1403 // is deallocated by the torrent once it starts seeding
1407 void torrent::piece_failed(int index)
1409 // if the last piece fails the peer connection will still
1410 // think that it has received all of it until this function
1411 // resets the download queue. So, we cannot do the
1412 // invariant check here since it assumes:
1413 // (total_done == m_torrent_file->total_size()) => is_seed()
1414 INVARIANT_CHECK;
1416 TORRENT_ASSERT(m_storage);
1417 TORRENT_ASSERT(m_storage->refcount() > 0);
1418 TORRENT_ASSERT(m_picker.get());
1419 TORRENT_ASSERT(index >= 0);
1420 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1422 if (m_ses.m_alerts.should_post<hash_failed_alert>())
1423 m_ses.m_alerts.post_alert(hash_failed_alert(get_handle(), index));
1425 // increase the total amount of failed bytes
1426 add_failed_bytes(m_torrent_file->piece_size(index));
1428 std::vector<void*> downloaders;
1429 m_picker->get_downloaders(downloaders, index);
1431 // decrease the trust point of all peers that sent
1432 // parts of this piece.
1433 // first, build a set of all peers that participated
1434 std::set<void*> peers;
1435 std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
1437 #ifndef NDEBUG
1438 for (std::vector<void*>::iterator i = downloaders.begin()
1439 , end(downloaders.end()); i != end; ++i)
1441 policy::peer* p = (policy::peer*)*i;
1442 if (p && p->connection)
1444 p->connection->piece_failed = true;
1447 #endif
1449 #ifndef TORRENT_DISABLE_EXTENSIONS
1450 for (extension_list_t::iterator i = m_extensions.begin()
1451 , end(m_extensions.end()); i != end; ++i)
1453 #ifndef BOOST_NO_EXCEPTIONS
1454 try {
1455 #endif
1456 (*i)->on_piece_failed(index);
1457 #ifndef BOOST_NO_EXCEPTIONS
1458 } catch (std::exception&) {}
1459 #endif
1461 #endif
1463 for (std::set<void*>::iterator i = peers.begin()
1464 , end(peers.end()); i != end; ++i)
1466 policy::peer* p = static_cast<policy::peer*>(*i);
1467 if (p == 0) continue;
1468 if (p->connection) p->connection->received_invalid_data(index);
1470 // either, we have received too many failed hashes
1471 // or this was the only peer that sent us this piece.
1472 // TODO: make this a changable setting
1473 if (p->trust_points <= -7
1474 || peers.size() == 1)
1476 // we don't trust this peer anymore
1477 // ban it.
1478 if (m_ses.m_alerts.should_post<peer_ban_alert>())
1480 peer_id pid;
1481 if (p->connection) pid = p->connection->pid();
1482 m_ses.m_alerts.post_alert(peer_ban_alert(
1483 get_handle(), p->ip(), pid));
1486 // mark the peer as banned
1487 p->banned = true;
1489 if (p->connection)
1491 #ifdef TORRENT_LOGGING
1492 (*m_ses.m_logger) << time_now_string() << " *** BANNING PEER [ " << p->ip()
1493 << " ] 'too many corrupt pieces'\n";
1494 #endif
1495 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
1496 (*p->connection->m_logger) << "*** BANNING PEER [ " << p->ip()
1497 << " ] 'too many corrupt pieces'\n";
1498 #endif
1499 p->connection->disconnect("too many corrupt pieces, banning peer");
1504 // we have to let the piece_picker know that
1505 // this piece failed the check as it can restore it
1506 // and mark it as being interesting for download
1507 // TODO: do this more intelligently! and keep track
1508 // of how much crap (data that failed hash-check) and
1509 // how much redundant data we have downloaded
1510 // if some clients has sent more than one piece
1511 // start with redownloading the pieces that the client
1512 // that has sent the least number of pieces
1513 m_picker->restore_piece(index);
1514 restore_piece_state(index);
1515 TORRENT_ASSERT(m_storage);
1517 TORRENT_ASSERT(m_picker->have_piece(index) == false);
1519 #ifndef NDEBUG
1520 for (std::vector<void*>::iterator i = downloaders.begin()
1521 , end(downloaders.end()); i != end; ++i)
1523 policy::peer* p = (policy::peer*)*i;
1524 if (p && p->connection)
1526 p->connection->piece_failed = false;
1529 #endif
1532 void torrent::restore_piece_state(int index)
1534 TORRENT_ASSERT(has_picker());
1535 for (peer_iterator i = m_connections.begin();
1536 i != m_connections.end(); ++i)
1538 peer_connection* p = *i;
1539 std::deque<pending_block> const& dq = p->download_queue();
1540 std::deque<piece_block> const& rq = p->request_queue();
1541 for (std::deque<pending_block>::const_iterator k = dq.begin()
1542 , end(dq.end()); k != end; ++k)
1544 if (k->block.piece_index != index) continue;
1545 m_picker->mark_as_downloading(k->block, p->peer_info_struct()
1546 , (piece_picker::piece_state_t)p->peer_speed());
1548 for (std::deque<piece_block>::const_iterator k = rq.begin()
1549 , end(rq.end()); k != end; ++k)
1551 if (k->piece_index != index) continue;
1552 m_picker->mark_as_downloading(*k, p->peer_info_struct()
1553 , (piece_picker::piece_state_t)p->peer_speed());
1558 void torrent::abort()
1560 INVARIANT_CHECK;
1562 m_abort = true;
1563 // if the torrent is paused, it doesn't need
1564 // to announce with even=stopped again.
1565 if (!is_paused())
1567 stop_announcing();
1570 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
1571 for (peer_iterator i = m_connections.begin();
1572 i != m_connections.end(); ++i)
1574 (*(*i)->m_logger) << "*** ABORTING TORRENT\n";
1576 #endif
1578 // disconnect all peers and close all
1579 // files belonging to the torrents
1580 disconnect_all();
1581 if (m_owning_storage.get())
1582 m_storage->async_release_files(
1583 bind(&torrent::on_files_released, shared_from_this(), _1, _2));
1585 m_owning_storage = 0;
1586 m_host_resolver.cancel();
1589 void torrent::on_files_deleted(int ret, disk_io_job const& j)
1591 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1593 if (ret != 0)
1595 if (alerts().should_post<torrent_delete_failed_alert>())
1596 alerts().post_alert(torrent_delete_failed_alert(get_handle(), j.str));
1598 else
1600 if (alerts().should_post<torrent_deleted_alert>())
1601 alerts().post_alert(torrent_deleted_alert(get_handle()));
1605 void torrent::on_files_released(int ret, disk_io_job const& j)
1608 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1610 if (alerts().should_post<torrent_paused_alert>())
1612 alerts().post_alert(torrent_paused_alert(get_handle()));
1617 void torrent::on_save_resume_data(int ret, disk_io_job const& j)
1619 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1621 if (!j.resume_data && alerts().should_post<save_resume_data_failed_alert>())
1623 alerts().post_alert(save_resume_data_failed_alert(get_handle(), j.str));
1624 return;
1627 if (j.resume_data && alerts().should_post<save_resume_data_alert>())
1629 write_resume_data(*j.resume_data);
1630 alerts().post_alert(save_resume_data_alert(j.resume_data
1631 , get_handle()));
1635 void torrent::on_file_renamed(int ret, disk_io_job const& j)
1637 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1640 if (ret == 0)
1642 if (alerts().should_post<file_renamed_alert>())
1643 alerts().post_alert(file_renamed_alert(get_handle(), j.str, j.piece));
1645 else
1647 if (alerts().should_post<file_rename_failed_alert>())
1648 alerts().post_alert(file_rename_failed_alert(get_handle(), j.str, j.piece));
1653 void torrent::on_torrent_paused(int ret, disk_io_job const& j)
1655 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
1657 if (alerts().should_post<torrent_paused_alert>())
1658 alerts().post_alert(torrent_paused_alert(get_handle()));
1661 std::string torrent::tracker_login() const
1663 if (m_username.empty() && m_password.empty()) return "";
1664 return m_username + ":" + m_password;
1667 void torrent::piece_availability(std::vector<int>& avail) const
1669 INVARIANT_CHECK;
1671 TORRENT_ASSERT(valid_metadata());
1672 if (is_seed())
1674 avail.clear();
1675 return;
1678 m_picker->get_availability(avail);
1681 void torrent::set_piece_priority(int index, int priority)
1683 // INVARIANT_CHECK;
1685 TORRENT_ASSERT(valid_metadata());
1686 if (is_seed()) return;
1688 // this call is only valid on torrents with metadata
1689 TORRENT_ASSERT(m_picker.get());
1690 TORRENT_ASSERT(index >= 0);
1691 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1693 bool was_finished = is_finished();
1694 bool filter_updated = m_picker->set_piece_priority(index, priority);
1695 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1696 if (filter_updated) update_peer_interest(was_finished);
1699 int torrent::piece_priority(int index) const
1701 // INVARIANT_CHECK;
1703 TORRENT_ASSERT(valid_metadata());
1704 if (is_seed()) return 1;
1706 // this call is only valid on torrents with metadata
1707 TORRENT_ASSERT(m_picker.get());
1708 TORRENT_ASSERT(index >= 0);
1709 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1711 return m_picker->piece_priority(index);
1714 void torrent::prioritize_pieces(std::vector<int> const& pieces)
1716 INVARIANT_CHECK;
1718 // this call is only valid on torrents with metadata
1719 TORRENT_ASSERT(valid_metadata());
1720 if (is_seed()) return;
1722 TORRENT_ASSERT(m_picker.get());
1724 int index = 0;
1725 bool filter_updated = false;
1726 bool was_finished = is_finished();
1727 for (std::vector<int>::const_iterator i = pieces.begin()
1728 , end(pieces.end()); i != end; ++i, ++index)
1730 TORRENT_ASSERT(*i >= 0);
1731 TORRENT_ASSERT(*i <= 7);
1732 filter_updated |= m_picker->set_piece_priority(index, *i);
1733 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
1735 if (filter_updated) update_peer_interest(was_finished);
1738 void torrent::piece_priorities(std::vector<int>& pieces) const
1740 INVARIANT_CHECK;
1742 // this call is only valid on torrents with metadata
1743 TORRENT_ASSERT(valid_metadata());
1744 if (is_seed())
1746 pieces.clear();
1747 pieces.resize(m_torrent_file->num_pieces(), 1);
1748 return;
1751 TORRENT_ASSERT(m_picker.get());
1752 m_picker->piece_priorities(pieces);
1755 namespace
1757 void set_if_greater(int& piece_prio, int file_prio)
1759 if (file_prio > piece_prio) piece_prio = file_prio;
1763 void torrent::prioritize_files(std::vector<int> const& files)
1765 INVARIANT_CHECK;
1767 // this call is only valid on torrents with metadata
1768 if (!valid_metadata() || is_seed()) return;
1770 // the bitmask need to have exactly one bit for every file
1771 // in the torrent
1772 TORRENT_ASSERT(int(files.size()) == m_torrent_file->num_files());
1774 size_type position = 0;
1776 if (m_torrent_file->num_pieces() == 0) return;
1778 bool was_finished = is_finished();
1780 int piece_length = m_torrent_file->piece_length();
1781 // initialize the piece priorities to 0, then only allow
1782 // setting higher priorities
1783 std::vector<int> pieces(m_torrent_file->num_pieces(), 0);
1784 for (int i = 0; i < int(files.size()); ++i)
1786 size_type start = position;
1787 size_type size = m_torrent_file->files().at(i).size;
1788 if (size == 0) continue;
1789 position += size;
1790 // mark all pieces of the file with this file's priority
1791 // but only if the priority is higher than the pieces
1792 // already set (to avoid problems with overlapping pieces)
1793 int start_piece = int(start / piece_length);
1794 int last_piece = int((position - 1) / piece_length);
1795 TORRENT_ASSERT(last_piece <= int(pieces.size()));
1796 // if one piece spans several files, we might
1797 // come here several times with the same start_piece, end_piece
1798 std::for_each(pieces.begin() + start_piece
1799 , pieces.begin() + last_piece + 1
1800 , bind(&set_if_greater, _1, files[i]));
1802 prioritize_pieces(pieces);
1803 update_peer_interest(was_finished);
1806 // this is called when piece priorities have been updated
1807 // updates the interested flag in peers
1808 void torrent::update_peer_interest(bool was_finished)
1810 for (peer_iterator i = begin(); i != end(); ++i)
1811 (*i)->update_interest();
1813 // if we used to be finished, but we aren't anymore
1814 // we may need to connect to peers again
1815 if (!is_finished() && was_finished)
1816 m_policy.recalculate_connect_candidates();
1818 // the torrent just became finished
1819 if (is_finished() && !was_finished)
1820 finished();
1821 else if (!is_finished() && was_finished)
1822 resume_download();
1825 void torrent::filter_piece(int index, bool filter)
1827 INVARIANT_CHECK;
1829 TORRENT_ASSERT(valid_metadata());
1830 if (is_seed()) return;
1832 // this call is only valid on torrents with metadata
1833 TORRENT_ASSERT(m_picker.get());
1834 TORRENT_ASSERT(index >= 0);
1835 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1837 bool was_finished = is_finished();
1838 m_picker->set_piece_priority(index, filter ? 1 : 0);
1839 update_peer_interest(was_finished);
1842 void torrent::filter_pieces(std::vector<bool> const& bitmask)
1844 INVARIANT_CHECK;
1846 // this call is only valid on torrents with metadata
1847 TORRENT_ASSERT(valid_metadata());
1848 if (is_seed()) return;
1850 TORRENT_ASSERT(m_picker.get());
1852 bool was_finished = is_finished();
1853 int index = 0;
1854 for (std::vector<bool>::const_iterator i = bitmask.begin()
1855 , end(bitmask.end()); i != end; ++i, ++index)
1857 if ((m_picker->piece_priority(index) == 0) == *i) continue;
1858 if (*i)
1859 m_picker->set_piece_priority(index, 0);
1860 else
1861 m_picker->set_piece_priority(index, 1);
1863 update_peer_interest(was_finished);
1866 bool torrent::is_piece_filtered(int index) const
1868 // this call is only valid on torrents with metadata
1869 TORRENT_ASSERT(valid_metadata());
1870 if (is_seed()) return false;
1872 TORRENT_ASSERT(m_picker.get());
1873 TORRENT_ASSERT(index >= 0);
1874 TORRENT_ASSERT(index < m_torrent_file->num_pieces());
1876 return m_picker->piece_priority(index) == 0;
1879 void torrent::filtered_pieces(std::vector<bool>& bitmask) const
1881 INVARIANT_CHECK;
1883 // this call is only valid on torrents with metadata
1884 TORRENT_ASSERT(valid_metadata());
1885 if (is_seed())
1887 bitmask.clear();
1888 bitmask.resize(m_torrent_file->num_pieces(), false);
1889 return;
1892 TORRENT_ASSERT(m_picker.get());
1893 m_picker->filtered_pieces(bitmask);
1896 void torrent::filter_files(std::vector<bool> const& bitmask)
1898 INVARIANT_CHECK;
1900 // this call is only valid on torrents with metadata
1901 if (!valid_metadata() || is_seed()) return;
1903 // the bitmask need to have exactly one bit for every file
1904 // in the torrent
1905 TORRENT_ASSERT((int)bitmask.size() == m_torrent_file->num_files());
1907 size_type position = 0;
1909 if (m_torrent_file->num_pieces())
1911 int piece_length = m_torrent_file->piece_length();
1912 // mark all pieces as filtered, then clear the bits for files
1913 // that should be downloaded
1914 std::vector<bool> piece_filter(m_torrent_file->num_pieces(), true);
1915 for (int i = 0; i < (int)bitmask.size(); ++i)
1917 size_type start = position;
1918 position += m_torrent_file->files().at(i).size;
1919 // is the file selected for download?
1920 if (!bitmask[i])
1922 // mark all pieces of the file as downloadable
1923 int start_piece = int(start / piece_length);
1924 int last_piece = int(position / piece_length);
1925 // if one piece spans several files, we might
1926 // come here several times with the same start_piece, end_piece
1927 std::fill(piece_filter.begin() + start_piece, piece_filter.begin()
1928 + last_piece + 1, false);
1931 filter_pieces(piece_filter);
1935 void torrent::replace_trackers(std::vector<announce_entry> const& urls)
1937 m_trackers = urls;
1938 if (m_currently_trying_tracker >= (int)m_trackers.size())
1939 m_currently_trying_tracker = (int)m_trackers.size()-1;
1940 m_last_working_tracker = -1;
1943 void torrent::choke_peer(peer_connection& c)
1945 INVARIANT_CHECK;
1947 TORRENT_ASSERT(!c.is_choked());
1948 TORRENT_ASSERT(m_num_uploads > 0);
1949 c.send_choke();
1950 --m_num_uploads;
1953 bool torrent::unchoke_peer(peer_connection& c)
1955 INVARIANT_CHECK;
1957 TORRENT_ASSERT(c.is_choked());
1958 if (m_num_uploads >= m_max_uploads) return false;
1959 c.send_unchoke();
1960 ++m_num_uploads;
1961 return true;
1964 void torrent::cancel_block(piece_block block)
1966 INVARIANT_CHECK;
1968 for (peer_iterator i = m_connections.begin()
1969 , end(m_connections.end()); i != end; ++i)
1971 (*i)->cancel_request(block);
1975 void torrent::remove_peer(peer_connection* p)
1977 // INVARIANT_CHECK;
1979 TORRENT_ASSERT(p != 0);
1981 peer_iterator i = m_connections.find(p);
1982 if (i == m_connections.end())
1984 TORRENT_ASSERT(false);
1985 return;
1988 if (ready_for_connections())
1990 TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
1992 if (p->is_seed())
1994 if (m_picker.get())
1996 m_picker->dec_refcount_all();
1999 else
2001 if (m_picker.get())
2003 bitfield const& pieces = p->get_bitfield();
2004 TORRENT_ASSERT(pieces.count() < int(pieces.size()));
2005 m_picker->dec_refcount(pieces);
2010 if (!p->is_choked())
2011 --m_num_uploads;
2013 m_policy.connection_closed(*p);
2014 p->set_peer_info(0);
2015 TORRENT_ASSERT(i != m_connections.end());
2016 m_connections.erase(i);
2018 // remove from bandwidth request-queue
2019 for (int c = 0; c < 2; ++c)
2021 for (queue_t::iterator i = m_bandwidth_queue[c].begin()
2022 , end(m_bandwidth_queue[c].end()); i != end; ++i)
2024 if (i->peer != p) continue;
2025 m_bandwidth_queue[c].erase(i);
2026 break;
2031 void torrent::connect_to_url_seed(std::string const& url)
2033 INVARIANT_CHECK;
2035 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2036 (*m_ses.m_logger) << time_now_string() << " resolving web seed: " << url << "\n";
2037 #endif
2039 std::string protocol;
2040 std::string auth;
2041 std::string hostname;
2042 int port;
2043 std::string path;
2044 char const* error;
2045 boost::tie(protocol, auth, hostname, port, path, error)
2046 = parse_url_components(url);
2048 if (error)
2050 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2051 (*m_ses.m_logger) << time_now_string() << " failed to parse web seed url: " << error << "\n";
2052 #endif
2053 // never try it again
2054 remove_url_seed(url);
2055 return;
2058 #ifdef TORRENT_USE_OPENSSL
2059 if (protocol != "http" && protocol != "https")
2060 #else
2061 if (protocol != "http")
2062 #endif
2064 if (m_ses.m_alerts.should_post<url_seed_alert>())
2066 m_ses.m_alerts.post_alert(
2067 url_seed_alert(get_handle(), url, "unknown protocol"));
2069 // never try it again
2070 remove_url_seed(url);
2071 return;
2074 if (hostname.empty())
2076 if (m_ses.m_alerts.should_post<url_seed_alert>())
2078 m_ses.m_alerts.post_alert(
2079 url_seed_alert(get_handle(), url, "invalid hostname"));
2081 // never try it again
2082 remove_url_seed(url);
2083 return;
2086 if (port == 0)
2088 if (m_ses.m_alerts.should_post<url_seed_alert>())
2090 m_ses.m_alerts.post_alert(
2091 url_seed_alert(get_handle(), url, "invalid port"));
2093 // never try it again
2094 remove_url_seed(url);
2095 return;
2098 m_resolving_web_seeds.insert(url);
2099 proxy_settings const& ps = m_ses.web_seed_proxy();
2100 if (ps.type == proxy_settings::http
2101 || ps.type == proxy_settings::http_pw)
2103 // use proxy
2104 tcp::resolver::query q(ps.hostname
2105 , boost::lexical_cast<std::string>(ps.port));
2106 m_host_resolver.async_resolve(q,
2107 bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, url));
2109 else
2111 if (m_ses.m_port_filter.access(port) & port_filter::blocked)
2113 if (m_ses.m_alerts.should_post<url_seed_alert>())
2115 m_ses.m_alerts.post_alert(
2116 url_seed_alert(get_handle(), url, "port blocked by port-filter"));
2118 // never try it again
2119 remove_url_seed(url);
2120 return;
2123 tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
2124 m_host_resolver.async_resolve(q,
2125 bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url
2126 , tcp::endpoint()));
2131 void torrent::on_proxy_name_lookup(error_code const& e, tcp::resolver::iterator host
2132 , std::string url)
2134 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2136 INVARIANT_CHECK;
2138 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2139 (*m_ses.m_logger) << time_now_string() << " completed resolve proxy hostname for: " << url << "\n";
2140 #endif
2142 if (e || host == tcp::resolver::iterator())
2144 if (m_ses.m_alerts.should_post<url_seed_alert>())
2146 m_ses.m_alerts.post_alert(
2147 url_seed_alert(get_handle(), url, e.message()));
2150 // the name lookup failed for the http host. Don't try
2151 // this host again
2152 remove_url_seed(url);
2153 return;
2156 if (m_ses.is_aborted()) return;
2158 tcp::endpoint a(host->endpoint());
2160 using boost::tuples::ignore;
2161 std::string hostname;
2162 int port;
2163 char const* error;
2164 boost::tie(ignore, ignore, hostname, port, ignore, error)
2165 = parse_url_components(url);
2167 if (error)
2169 if (m_ses.m_alerts.should_post<url_seed_alert>())
2171 m_ses.m_alerts.post_alert(
2172 url_seed_alert(get_handle(), url, error));
2174 remove_url_seed(url);
2175 return;
2178 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
2180 if (m_ses.m_alerts.should_post<peer_blocked_alert>())
2181 m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()));
2182 return;
2185 tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
2186 m_host_resolver.async_resolve(q,
2187 bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url, a));
2190 void torrent::on_name_lookup(error_code const& e, tcp::resolver::iterator host
2191 , std::string url, tcp::endpoint proxy)
2193 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2195 INVARIANT_CHECK;
2197 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
2198 (*m_ses.m_logger) << time_now_string() << " completed resolve: " << url << "\n";
2199 #endif
2201 std::set<std::string>::iterator i = m_resolving_web_seeds.find(url);
2202 if (i != m_resolving_web_seeds.end()) m_resolving_web_seeds.erase(i);
2204 if (e || host == tcp::resolver::iterator())
2206 if (m_ses.m_alerts.should_post<url_seed_alert>())
2208 std::stringstream msg;
2209 msg << "HTTP seed hostname lookup failed: " << e.message();
2210 m_ses.m_alerts.post_alert(
2211 url_seed_alert(get_handle(), url, msg.str()));
2213 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2214 (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << url << "\n";
2215 #endif
2217 // the name lookup failed for the http host. Don't try
2218 // this host again
2219 remove_url_seed(url);
2220 return;
2223 if (m_ses.is_aborted()) return;
2225 tcp::endpoint a(host->endpoint());
2227 if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
2229 if (m_ses.m_alerts.should_post<peer_blocked_alert>())
2230 m_ses.m_alerts.post_alert(peer_blocked_alert(a.address()));
2231 return;
2234 boost::shared_ptr<socket_type> s(new (std::nothrow) socket_type(m_ses.m_io_service));
2235 if (!s) return;
2237 bool ret = instantiate_connection(m_ses.m_io_service, m_ses.web_seed_proxy(), *s);
2238 TORRENT_ASSERT(ret);
2240 if (m_ses.web_seed_proxy().type == proxy_settings::http
2241 || m_ses.web_seed_proxy().type == proxy_settings::http_pw)
2243 // the web seed connection will talk immediately to
2244 // the proxy, without requiring CONNECT support
2245 s->get<http_stream>().set_no_connect(true);
2248 std::pair<int, int> const& out_ports = m_settings.outgoing_ports;
2249 error_code ec;
2250 if (out_ports.first > 0 && out_ports.second >= out_ports.first)
2251 s->bind(tcp::endpoint(address(), m_ses.next_port()), ec);
2253 boost::intrusive_ptr<peer_connection> c(new (std::nothrow) web_peer_connection(
2254 m_ses, shared_from_this(), s, a, url, 0));
2255 if (!c) return;
2257 #ifndef NDEBUG
2258 c->m_in_constructor = false;
2259 #endif
2261 #ifndef TORRENT_DISABLE_EXTENSIONS
2262 for (extension_list_t::iterator i = m_extensions.begin()
2263 , end(m_extensions.end()); i != end; ++i)
2265 boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
2266 if (pp) c->add_extension(pp);
2268 #endif
2270 // add the newly connected peer to this torrent's peer list
2271 m_connections.insert(boost::get_pointer(c));
2272 m_ses.m_connections.insert(c);
2274 #ifndef BOOST_NO_EXCEPTIONS
2277 #endif
2278 // add the newly connected peer to this torrent's peer list
2279 m_connections.insert(boost::get_pointer(c));
2280 m_ses.m_connections.insert(c);
2281 c->start();
2283 m_ses.m_half_open.enqueue(
2284 bind(&peer_connection::connect, c, _1)
2285 , bind(&peer_connection::timed_out, c)
2286 , seconds(settings().peer_connect_timeout));
2287 #ifndef BOOST_NO_EXCEPTIONS
2289 catch (std::exception& e)
2291 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2292 (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n";
2293 #endif
2294 c->disconnect(e.what(), 1);
2296 #endif
2299 #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
2300 namespace
2302 unsigned long swap_bytes(unsigned long a)
2304 return (a >> 24) | ((a & 0xff0000) >> 8) | ((a & 0xff00) << 8) | (a << 24);
2308 void torrent::resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const
2310 if (m_resolving_country
2311 || p->has_country()
2312 || p->is_connecting()
2313 || p->is_queued()
2314 || p->in_handshake()
2315 || p->remote().address().is_v6()) return;
2317 m_resolving_country = true;
2318 asio::ip::address_v4 reversed(swap_bytes(p->remote().address().to_v4().to_ulong()));
2319 tcp::resolver::query q(reversed.to_string() + ".zz.countries.nerd.dk", "0");
2320 m_host_resolver.async_resolve(q,
2321 bind(&torrent::on_country_lookup, shared_from_this(), _1, _2, p));
2324 namespace
2326 struct country_entry
2328 int code;
2329 char const* name;
2333 void torrent::on_country_lookup(error_code const& error, tcp::resolver::iterator i
2334 , intrusive_ptr<peer_connection> p) const
2336 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2338 INVARIANT_CHECK;
2340 m_resolving_country = false;
2342 // must be ordered in increasing order
2343 static const country_entry country_map[] =
2345 { 4, "AF"}, { 8, "AL"}, { 10, "AQ"}, { 12, "DZ"}, { 16, "AS"}
2346 , { 20, "AD"}, { 24, "AO"}, { 28, "AG"}, { 31, "AZ"}, { 32, "AR"}
2347 , { 36, "AU"}, { 40, "AT"}, { 44, "BS"}, { 48, "BH"}, { 50, "BD"}
2348 , { 51, "AM"}, { 52, "BB"}, { 56, "BE"}, { 60, "BM"}, { 64, "BT"}
2349 , { 68, "BO"}, { 70, "BA"}, { 72, "BW"}, { 74, "BV"}, { 76, "BR"}
2350 , { 84, "BZ"}, { 86, "IO"}, { 90, "SB"}, { 92, "VG"}, { 96, "BN"}
2351 , {100, "BG"}, {104, "MM"}, {108, "BI"}, {112, "BY"}, {116, "KH"}
2352 , {120, "CM"}, {124, "CA"}, {132, "CV"}, {136, "KY"}, {140, "CF"}
2353 , {144, "LK"}, {148, "TD"}, {152, "CL"}, {156, "CN"}, {158, "TW"}
2354 , {162, "CX"}, {166, "CC"}, {170, "CO"}, {174, "KM"}, {175, "YT"}
2355 , {178, "CG"}, {180, "CD"}, {184, "CK"}, {188, "CR"}, {191, "HR"}
2356 , {192, "CU"}, {203, "CZ"}, {204, "BJ"}, {208, "DK"}, {212, "DM"}
2357 , {214, "DO"}, {218, "EC"}, {222, "SV"}, {226, "GQ"}, {231, "ET"}
2358 , {232, "ER"}, {233, "EE"}, {234, "FO"}, {238, "FK"}, {239, "GS"}
2359 , {242, "FJ"}, {246, "FI"}, {248, "AX"}, {250, "FR"}, {254, "GF"}
2360 , {258, "PF"}, {260, "TF"}, {262, "DJ"}, {266, "GA"}, {268, "GE"}
2361 , {270, "GM"}, {275, "PS"}, {276, "DE"}, {288, "GH"}, {292, "GI"}
2362 , {296, "KI"}, {300, "GR"}, {304, "GL"}, {308, "GD"}, {312, "GP"}
2363 , {316, "GU"}, {320, "GT"}, {324, "GN"}, {328, "GY"}, {332, "HT"}
2364 , {334, "HM"}, {336, "VA"}, {340, "HN"}, {344, "HK"}, {348, "HU"}
2365 , {352, "IS"}, {356, "IN"}, {360, "ID"}, {364, "IR"}, {368, "IQ"}
2366 , {372, "IE"}, {376, "IL"}, {380, "IT"}, {384, "CI"}, {388, "JM"}
2367 , {392, "JP"}, {398, "KZ"}, {400, "JO"}, {404, "KE"}, {408, "KP"}
2368 , {410, "KR"}, {414, "KW"}, {417, "KG"}, {418, "LA"}, {422, "LB"}
2369 , {426, "LS"}, {428, "LV"}, {430, "LR"}, {434, "LY"}, {438, "LI"}
2370 , {440, "LT"}, {442, "LU"}, {446, "MO"}, {450, "MG"}, {454, "MW"}
2371 , {458, "MY"}, {462, "MV"}, {466, "ML"}, {470, "MT"}, {474, "MQ"}
2372 , {478, "MR"}, {480, "MU"}, {484, "MX"}, {492, "MC"}, {496, "MN"}
2373 , {498, "MD"}, {500, "MS"}, {504, "MA"}, {508, "MZ"}, {512, "OM"}
2374 , {516, "NA"}, {520, "NR"}, {524, "NP"}, {528, "NL"}, {530, "AN"}
2375 , {533, "AW"}, {540, "NC"}, {548, "VU"}, {554, "NZ"}, {558, "NI"}
2376 , {562, "NE"}, {566, "NG"}, {570, "NU"}, {574, "NF"}, {578, "NO"}
2377 , {580, "MP"}, {581, "UM"}, {583, "FM"}, {584, "MH"}, {585, "PW"}
2378 , {586, "PK"}, {591, "PA"}, {598, "PG"}, {600, "PY"}, {604, "PE"}
2379 , {608, "PH"}, {612, "PN"}, {616, "PL"}, {620, "PT"}, {624, "GW"}
2380 , {626, "TL"}, {630, "PR"}, {634, "QA"}, {634, "QA"}, {638, "RE"}
2381 , {642, "RO"}, {643, "RU"}, {646, "RW"}, {654, "SH"}, {659, "KN"}
2382 , {660, "AI"}, {662, "LC"}, {666, "PM"}, {670, "VC"}, {674, "SM"}
2383 , {678, "ST"}, {682, "SA"}, {686, "SN"}, {690, "SC"}, {694, "SL"}
2384 , {702, "SG"}, {703, "SK"}, {704, "VN"}, {705, "SI"}, {706, "SO"}
2385 , {710, "ZA"}, {716, "ZW"}, {724, "ES"}, {732, "EH"}, {736, "SD"}
2386 , {740, "SR"}, {744, "SJ"}, {748, "SZ"}, {752, "SE"}, {756, "CH"}
2387 , {760, "SY"}, {762, "TJ"}, {764, "TH"}, {768, "TG"}, {772, "TK"}
2388 , {776, "TO"}, {780, "TT"}, {784, "AE"}, {788, "TN"}, {792, "TR"}
2389 , {795, "TM"}, {796, "TC"}, {798, "TV"}, {800, "UG"}, {804, "UA"}
2390 , {807, "MK"}, {818, "EG"}, {826, "GB"}, {834, "TZ"}, {840, "US"}
2391 , {850, "VI"}, {854, "BF"}, {858, "UY"}, {860, "UZ"}, {862, "VE"}
2392 , {876, "WF"}, {882, "WS"}, {887, "YE"}, {891, "CS"}, {894, "ZM"}
2395 if (error || i == tcp::resolver::iterator())
2397 // this is used to indicate that we shouldn't
2398 // try to resolve it again
2399 p->set_country("--");
2400 return;
2403 while (i != tcp::resolver::iterator()
2404 && !i->endpoint().address().is_v4()) ++i;
2405 if (i != tcp::resolver::iterator())
2407 // country is an ISO 3166 country code
2408 int country = i->endpoint().address().to_v4().to_ulong() & 0xffff;
2410 // look up the country code in the map
2411 const int size = sizeof(country_map)/sizeof(country_map[0]);
2412 country_entry tmp = {country, ""};
2413 country_entry const* i =
2414 std::lower_bound(country_map, country_map + size, tmp
2415 , bind(&country_entry::code, _1) < bind(&country_entry::code, _2));
2416 if (i == country_map + size
2417 || i->code != country)
2419 // unknown country!
2420 p->set_country("!!");
2421 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
2422 (*m_ses.m_logger) << "IP " << p->remote().address() << " was mapped to unknown country: " << country << "\n";
2423 #endif
2424 return;
2427 p->set_country(i->name);
2430 #endif
2432 void torrent::read_resume_data(lazy_entry const& rd)
2434 m_total_uploaded = rd.dict_find_int_value("total_uploaded");
2435 m_total_downloaded = rd.dict_find_int_value("total_downloaded");
2436 m_active_time = seconds(rd.dict_find_int_value("active_time"));
2437 m_seeding_time = seconds(rd.dict_find_int_value("seeding_time"));
2438 m_complete = rd.dict_find_int_value("num_seeds", -1);
2439 m_incomplete = rd.dict_find_int_value("num_downloaders", -1);
2442 void torrent::write_resume_data(entry& ret) const
2444 ret["file-format"] = "libtorrent resume file";
2445 ret["file-version"] = 1;
2447 ret["total_uploaded"] = m_total_uploaded;
2448 ret["total_downloaded"] = m_total_downloaded;
2450 ret["active_time"] = total_seconds(m_active_time);
2451 ret["seeding_time"] = total_seconds(m_seeding_time);
2453 int seeds = 0;
2454 int downloaders = 0;
2455 if (m_complete >= 0) seeds = m_complete;
2456 else seeds = m_policy.num_seeds();
2457 if (m_incomplete >= 0) downloaders = m_incomplete;
2458 else downloaders = m_policy.num_peers() - m_policy.num_seeds();
2460 ret["num_seeds"] = seeds;
2461 ret["num_downloaders"] = downloaders;
2463 const sha1_hash& info_hash = torrent_file().info_hash();
2464 ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
2466 // blocks per piece
2467 int num_blocks_per_piece =
2468 static_cast<int>(torrent_file().piece_length()) / block_size();
2469 ret["blocks per piece"] = num_blocks_per_piece;
2471 // if this torrent is a seed, we won't have a piece picker
2472 // and there will be no half-finished pieces.
2473 if (!is_seed())
2475 const std::vector<piece_picker::downloading_piece>& q
2476 = m_picker->get_download_queue();
2478 // unfinished pieces
2479 ret["unfinished"] = entry::list_type();
2480 entry::list_type& up = ret["unfinished"].list();
2482 // info for each unfinished piece
2483 for (std::vector<piece_picker::downloading_piece>::const_iterator i
2484 = q.begin(); i != q.end(); ++i)
2486 if (i->finished == 0) continue;
2488 entry piece_struct(entry::dictionary_t);
2490 // the unfinished piece's index
2491 piece_struct["piece"] = i->index;
2493 std::string bitmask;
2494 const int num_bitmask_bytes
2495 = (std::max)(num_blocks_per_piece / 8, 1);
2497 for (int j = 0; j < num_bitmask_bytes; ++j)
2499 unsigned char v = 0;
2500 int bits = (std::min)(num_blocks_per_piece - j*8, 8);
2501 for (int k = 0; k < bits; ++k)
2502 v |= (i->info[j*8+k].state == piece_picker::block_info::state_finished)
2503 ? (1 << k) : 0;
2504 bitmask.insert(bitmask.end(), v);
2505 TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1);
2507 piece_struct["bitmask"] = bitmask;
2508 // push the struct onto the unfinished-piece list
2509 up.push_back(piece_struct);
2513 // write have bitmask
2514 entry::string_type& pieces = ret["pieces"].string();
2515 pieces.resize(m_torrent_file->num_pieces());
2516 if (is_seed())
2518 for (int i = 0, end(pieces.size()); i < end; ++i)
2519 pieces[i] = 1;
2521 else
2523 for (int i = 0, end(pieces.size()); i < end; ++i)
2524 pieces[i] = m_picker->have_piece(i) ? 1 : 0;
2527 // write local peers
2529 entry::list_type& peer_list = ret["peers"].list();
2530 entry::list_type& banned_peer_list = ret["banned_peers"].list();
2532 int max_failcount = m_ses.m_settings.max_failcount;
2534 for (policy::const_iterator i = m_policy.begin_peer()
2535 , end(m_policy.end_peer()); i != end; ++i)
2537 error_code ec;
2538 if (i->second.banned)
2540 entry peer(entry::dictionary_t);
2541 peer["ip"] = i->second.addr.to_string(ec);
2542 if (ec) continue;
2543 peer["port"] = i->second.port;
2544 banned_peer_list.push_back(peer);
2545 continue;
2547 // we cannot save remote connection
2548 // since we don't know their listen port
2549 // unless they gave us their listen port
2550 // through the extension handshake
2551 // so, if the peer is not connectable (i.e. we
2552 // don't know its listen port) or if it has
2553 // been banned, don't save it.
2554 if (i->second.type == policy::peer::not_connectable) continue;
2556 // don't save peers that doesn't work
2557 if (i->second.failcount >= max_failcount) continue;
2559 entry peer(entry::dictionary_t);
2560 peer["ip"] = i->second.addr.to_string(ec);
2561 if (ec) continue;
2562 peer["port"] = i->second.port;
2563 peer_list.push_back(peer);
2567 void torrent::get_full_peer_list(std::vector<peer_list_entry>& v) const
2569 v.clear();
2570 v.reserve(m_policy.num_peers());
2571 for (policy::const_iterator i = m_policy.begin_peer();
2572 i != m_policy.end_peer(); ++i)
2574 peer_list_entry e;
2575 e.ip = i->second.ip();
2576 e.flags = i->second.banned ? peer_list_entry::banned : 0;
2577 e.failcount = i->second.failcount;
2578 e.source = i->second.source;
2579 v.push_back(e);
2583 void torrent::get_peer_info(std::vector<peer_info>& v)
2585 v.clear();
2586 for (peer_iterator i = begin();
2587 i != end(); ++i)
2589 peer_connection* peer = *i;
2591 // incoming peers that haven't finished the handshake should
2592 // not be included in this list
2593 if (peer->associated_torrent().expired()) continue;
2595 v.push_back(peer_info());
2596 peer_info& p = v.back();
2598 peer->get_peer_info(p);
2599 #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
2600 if (resolving_countries())
2601 resolve_peer_country(intrusive_ptr<peer_connection>(peer));
2602 #endif
2606 void torrent::get_download_queue(std::vector<partial_piece_info>& queue)
2608 queue.clear();
2609 if (!valid_metadata() || is_seed()) return;
2610 piece_picker const& p = picker();
2611 std::vector<piece_picker::downloading_piece> const& q
2612 = p.get_download_queue();
2614 for (std::vector<piece_picker::downloading_piece>::const_iterator i
2615 = q.begin(); i != q.end(); ++i)
2617 partial_piece_info pi;
2618 pi.piece_state = (partial_piece_info::state_t)i->state;
2619 pi.blocks_in_piece = p.blocks_in_piece(i->index);
2620 pi.finished = (int)i->finished;
2621 pi.writing = (int)i->writing;
2622 pi.requested = (int)i->requested;
2623 int piece_size = int(torrent_file().piece_size(i->index));
2624 for (int j = 0; j < pi.blocks_in_piece; ++j)
2626 block_info& bi = pi.blocks[j];
2627 bi.state = i->info[j].state;
2628 bi.block_size = j < pi.blocks_in_piece - 1 ? m_block_size
2629 : piece_size - (j * m_block_size);
2630 bool complete = bi.state == block_info::writing
2631 || bi.state == block_info::finished;
2632 if (i->info[j].peer == 0)
2634 bi.peer = tcp::endpoint();
2635 bi.bytes_progress = complete ? bi.block_size : 0;
2637 else
2639 policy::peer* p = static_cast<policy::peer*>(i->info[j].peer);
2640 if (p->connection)
2642 bi.peer = p->connection->remote();
2643 if (bi.state == block_info::requested)
2645 boost::optional<piece_block_progress> pbp
2646 = p->connection->downloading_piece_progress();
2647 if (pbp && pbp->piece_index == i->index && pbp->block_index == j)
2649 bi.bytes_progress = pbp->bytes_downloaded;
2650 TORRENT_ASSERT(bi.bytes_progress <= bi.block_size);
2652 else
2654 bi.bytes_progress = 0;
2657 else
2659 bi.bytes_progress = complete ? bi.block_size : 0;
2662 else
2664 bi.peer = p->ip();
2665 bi.bytes_progress = complete ? bi.block_size : 0;
2669 pi.blocks[j].num_peers = i->info[j].num_peers;
2671 pi.piece_index = i->index;
2672 queue.push_back(pi);
2677 bool torrent::connect_to_peer(policy::peer* peerinfo)
2679 INVARIANT_CHECK;
2681 TORRENT_ASSERT(peerinfo);
2682 TORRENT_ASSERT(peerinfo->connection == 0);
2684 peerinfo->connected = time_now();
2685 #ifndef NDEBUG
2686 // this asserts that we don't have duplicates in the policy's peer list
2687 peer_iterator i_ = std::find_if(m_connections.begin(), m_connections.end()
2688 , bind(&peer_connection::remote, _1) == peerinfo->ip());
2689 TORRENT_ASSERT(i_ == m_connections.end()
2690 || dynamic_cast<bt_peer_connection*>(*i_) == 0);
2691 #endif
2693 TORRENT_ASSERT(want_more_peers());
2694 TORRENT_ASSERT(m_ses.num_connections() < m_ses.max_connections());
2696 tcp::endpoint a(peerinfo->ip());
2697 TORRENT_ASSERT((m_ses.m_ip_filter.access(peerinfo->addr) & ip_filter::blocked) == 0);
2699 boost::shared_ptr<socket_type> s(new socket_type(m_ses.m_io_service));
2701 bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s);
2702 TORRENT_ASSERT(ret);
2703 std::pair<int, int> const& out_ports = m_ses.settings().outgoing_ports;
2704 error_code ec;
2705 if (out_ports.first > 0 && out_ports.second >= out_ports.first)
2706 s->bind(tcp::endpoint(address(), m_ses.next_port()), ec);
2708 boost::intrusive_ptr<peer_connection> c(new bt_peer_connection(
2709 m_ses, shared_from_this(), s, a, peerinfo));
2711 #ifndef NDEBUG
2712 c->m_in_constructor = false;
2713 #endif
2715 c->add_stat(peerinfo->prev_amount_download, peerinfo->prev_amount_upload);
2716 peerinfo->prev_amount_download = 0;
2717 peerinfo->prev_amount_upload = 0;
2719 #ifndef TORRENT_DISABLE_EXTENSIONS
2720 for (extension_list_t::iterator i = m_extensions.begin()
2721 , end(m_extensions.end()); i != end; ++i)
2723 #ifndef BOOST_NO_EXCEPTIONS
2724 try {
2725 #endif
2726 boost::shared_ptr<peer_plugin> pp((*i)->new_connection(c.get()));
2727 if (pp) c->add_extension(pp);
2728 #ifndef BOOST_NO_EXCEPTIONS
2729 } catch (std::exception&) {}
2730 #endif
2732 #endif
2734 // add the newly connected peer to this torrent's peer list
2735 m_connections.insert(boost::get_pointer(c));
2736 m_ses.m_connections.insert(c);
2737 peerinfo->connection = c.get();
2738 c->start();
2740 int timeout = settings().peer_connect_timeout;
2741 if (peerinfo) timeout += 3 * peerinfo->failcount;
2743 #ifndef BOOST_NO_EXCEPTIONS
2746 #endif
2747 m_ses.m_half_open.enqueue(
2748 bind(&peer_connection::connect, c, _1)
2749 , bind(&peer_connection::timed_out, c)
2750 , seconds(timeout));
2751 #ifndef BOOST_NO_EXCEPTIONS
2753 catch (std::exception& e)
2755 std::set<peer_connection*>::iterator i
2756 = m_connections.find(boost::get_pointer(c));
2757 if (i != m_connections.end()) m_connections.erase(i);
2758 c->disconnect(e.what());
2759 return false;
2761 #endif
2762 return true;
2765 bool torrent::set_metadata(lazy_entry const& metadata, std::string& error)
2767 INVARIANT_CHECK;
2769 TORRENT_ASSERT(!m_torrent_file->is_valid());
2770 if (!m_torrent_file->parse_info_section(metadata, error))
2772 // parse failed
2773 return false;
2776 if (m_ses.m_alerts.should_post<metadata_received_alert>())
2778 m_ses.m_alerts.post_alert(metadata_received_alert(
2779 get_handle()));
2782 init();
2784 return true;
2787 bool torrent::attach_peer(peer_connection* p)
2789 // INVARIANT_CHECK;
2791 TORRENT_ASSERT(p != 0);
2792 TORRENT_ASSERT(!p->is_local());
2794 m_has_incoming = true;
2796 if ((m_state == torrent_status::queued_for_checking
2797 || m_state == torrent_status::checking_files)
2798 && valid_metadata())
2800 p->disconnect("torrent is not ready to accept peers");
2801 return false;
2804 if (m_ses.m_connections.find(p) == m_ses.m_connections.end())
2806 p->disconnect("peer is not properly constructed");
2807 return false;
2810 if (m_ses.is_aborted())
2812 p->disconnect("session is closing");
2813 return false;
2816 if (int(m_connections.size()) >= m_max_connections)
2818 p->disconnect("reached connection limit");
2819 return false;
2822 #ifndef BOOST_NO_EXCEPTIONS
2825 #endif
2826 #ifndef TORRENT_DISABLE_EXTENSIONS
2827 for (extension_list_t::iterator i = m_extensions.begin()
2828 , end(m_extensions.end()); i != end; ++i)
2830 boost::shared_ptr<peer_plugin> pp((*i)->new_connection(p));
2831 if (pp) p->add_extension(pp);
2833 #endif
2834 if (!m_policy.new_connection(*p))
2835 return false;
2836 #ifndef BOOST_NO_EXCEPTIONS
2838 catch (std::exception& e)
2840 #if defined TORRENT_LOGGING
2841 (*m_ses.m_logger) << time_now_string() << " CLOSING CONNECTION "
2842 << p->remote() << " policy::new_connection threw: " << e.what() << "\n";
2843 #endif
2844 p->disconnect(e.what());
2845 return false;
2847 #endif
2848 TORRENT_ASSERT(m_connections.find(p) == m_connections.end());
2849 peer_iterator ci = m_connections.insert(p).first;
2850 #ifndef NDEBUG
2851 error_code ec;
2852 TORRENT_ASSERT(p->remote() == p->get_socket()->remote_endpoint(ec) || ec);
2853 #endif
2855 #if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
2856 m_policy.check_invariant();
2857 #endif
2858 return true;
2861 bool torrent::want_more_peers() const
2863 return int(m_connections.size()) < m_max_connections
2864 && !is_paused()
2865 && m_state != torrent_status::checking_files
2866 && (m_state != torrent_status::queued_for_checking
2867 || !valid_metadata())
2868 && m_policy.num_connect_candidates() > 0;
2871 void torrent::disconnect_all()
2873 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
2875 INVARIANT_CHECK;
2877 while (!m_connections.empty())
2879 peer_connection* p = *m_connections.begin();
2880 TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
2882 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
2883 if (m_abort)
2884 (*p->m_logger) << "*** CLOSING CONNECTION 'aborting'\n";
2885 else
2886 (*p->m_logger) << "*** CLOSING CONNECTION 'pausing'\n";
2887 #endif
2888 #ifndef NDEBUG
2889 std::size_t size = m_connections.size();
2890 #endif
2891 if (p->is_disconnecting())
2892 m_connections.erase(m_connections.begin());
2893 else
2894 p->disconnect(m_abort?"stopping torrent":"pausing torrent");
2895 TORRENT_ASSERT(m_connections.size() <= size);
2899 namespace
2901 // this returns true if lhs is a better disconnect candidate than rhs
2902 bool compare_disconnect_peer(peer_connection const* lhs, peer_connection const* rhs)
2904 // prefer to disconnect peers we're not interested in
2905 if (lhs->is_interesting() != rhs->is_interesting())
2906 return rhs->is_interesting();
2908 // prefer to disconnect peers that are not seeds
2909 if (lhs->is_seed() != rhs->is_seed())
2910 return rhs->is_seed();
2912 // prefer to disconnect peers that are on parole
2913 if (lhs->on_parole() != rhs->on_parole())
2914 return lhs->on_parole();
2916 // prefer to disconnect peers that send data at a lower rate
2917 size_type lhs_transferred = lhs->statistics().total_payload_download();
2918 size_type rhs_transferred = rhs->statistics().total_payload_download();
2920 if (lhs_transferred != rhs_transferred
2921 && lhs_transferred > 0
2922 && rhs_transferred > 0)
2924 ptime now = time_now();
2925 size_type lhs_time_connected = total_seconds(now - lhs->connected_time());
2926 size_type rhs_time_connected = total_seconds(now - rhs->connected_time());
2928 double lhs_rate = double(lhs_transferred) / (lhs_time_connected + 1);
2929 double rhs_rate = double(rhs_transferred) / (rhs_time_connected + 1);
2931 return lhs_rate < rhs_rate;
2934 // prefer to disconnect peers that chokes us
2935 if (lhs->is_choked() != rhs->is_choked())
2936 return lhs->is_choked();
2938 return lhs->last_received() < rhs->last_received();
2942 int torrent::disconnect_peers(int num)
2944 int ret = 0;
2945 // buils a list of all connected peers and sort it by 'disconnectability'.
2946 std::vector<peer_connection*> peers(m_connections.size());
2947 std::copy(m_connections.begin(), m_connections.end(), peers.begin());
2948 std::sort(peers.begin(), peers.end(), boost::bind(&compare_disconnect_peer, _1, _2));
2950 // never disconnect peers that connected less than 90 seconds ago
2951 ptime cut_off = time_now() - seconds(90);
2953 for (std::vector<peer_connection*>::iterator i = peers.begin()
2954 , end(peers.end()); i != end && ret < num; ++i)
2956 peer_connection* p = *i;
2957 if (p->connected_time() > cut_off) continue;
2958 ++ret;
2959 p->disconnect("optimistic disconnect");
2961 return ret;
2964 int torrent::bandwidth_throttle(int channel) const
2966 return m_bandwidth_limit[channel].throttle();
2969 int torrent::bandwidth_queue_size(int channel) const
2971 return (int)m_bandwidth_queue[channel].size();
2974 void torrent::request_bandwidth(int channel
2975 , boost::intrusive_ptr<peer_connection> const& p
2976 , int max_block_size, int priority)
2978 TORRENT_ASSERT(max_block_size > 0);
2979 TORRENT_ASSERT(m_bandwidth_limit[channel].throttle() > 0);
2980 TORRENT_ASSERT(p->max_assignable_bandwidth(channel) > 0);
2981 TORRENT_ASSERT(p->m_channel_state[channel] == peer_info::bw_torrent);
2982 int block_size = (std::min)(m_bandwidth_limit[channel].throttle() / 10
2983 , max_block_size);
2984 if (block_size <= 0) block_size = 1;
2986 if (m_bandwidth_limit[channel].max_assignable() > 0)
2988 perform_bandwidth_request(channel, p, block_size, priority);
2990 else
2992 // skip forward in the queue until we find a prioritized peer
2993 // or hit the front of it.
2994 queue_t::reverse_iterator i = m_bandwidth_queue[channel].rbegin();
2995 while (i != m_bandwidth_queue[channel].rend() && priority > i->priority)
2997 ++i->priority;
2998 ++i;
3000 m_bandwidth_queue[channel].insert(i.base(), bw_queue_entry<peer_connection, torrent>(
3001 p, block_size, priority));
3005 void torrent::expire_bandwidth(int channel, int amount)
3007 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3009 INVARIANT_CHECK;
3011 TORRENT_ASSERT(amount > 0);
3012 m_bandwidth_limit[channel].expire(amount);
3013 queue_t tmp;
3014 while (!m_bandwidth_queue[channel].empty())
3016 bw_queue_entry<peer_connection, torrent> qe = m_bandwidth_queue[channel].front();
3017 if (m_bandwidth_limit[channel].max_assignable() == 0)
3018 break;
3019 m_bandwidth_queue[channel].pop_front();
3020 if (qe.peer->max_assignable_bandwidth(channel) <= 0)
3022 TORRENT_ASSERT(m_ses.m_bandwidth_manager[channel]->is_in_history(qe.peer.get()));
3023 if (!qe.peer->is_disconnecting()) tmp.push_back(qe);
3024 continue;
3026 perform_bandwidth_request(channel, qe.peer
3027 , qe.max_block_size, qe.priority);
3029 m_bandwidth_queue[channel].insert(m_bandwidth_queue[channel].begin(), tmp.begin(), tmp.end());
3032 void torrent::perform_bandwidth_request(int channel
3033 , boost::intrusive_ptr<peer_connection> const& p
3034 , int block_size
3035 , int priority)
3037 TORRENT_ASSERT(p->m_channel_state[channel] == peer_info::bw_torrent);
3038 p->m_channel_state[channel] = peer_info::bw_global;
3039 m_ses.m_bandwidth_manager[channel]->request_bandwidth(p
3040 , block_size, priority);
3041 m_bandwidth_limit[channel].assign(block_size);
3044 void torrent::assign_bandwidth(int channel, int amount, int blk)
3046 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3048 TORRENT_ASSERT(amount > 0);
3049 TORRENT_ASSERT(amount <= blk);
3050 if (amount < blk)
3051 expire_bandwidth(channel, blk - amount);
3054 // called when torrent is finished (all interesting
3055 // pieces have been downloaded)
3056 void torrent::finished()
3058 INVARIANT_CHECK;
3060 if (alerts().should_post<torrent_finished_alert>())
3062 alerts().post_alert(torrent_finished_alert(
3063 get_handle()));
3066 set_state(torrent_status::finished);
3067 set_queue_position(-1);
3069 // we have to call completed() before we start
3070 // disconnecting peers, since there's an assert
3071 // to make sure we're cleared the piece picker
3072 if (is_seed()) completed();
3074 // disconnect all seeds
3075 // TODO: should disconnect all peers that have the pieces we have
3076 // not just seeds
3077 std::vector<peer_connection*> seeds;
3078 for (peer_iterator i = m_connections.begin();
3079 i != m_connections.end(); ++i)
3081 peer_connection* p = *i;
3082 TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
3083 if (p->upload_only())
3085 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
3086 (*p->m_logger) << "*** SEED, CLOSING CONNECTION\n";
3087 #endif
3088 seeds.push_back(p);
3091 std::for_each(seeds.begin(), seeds.end()
3092 , bind(&peer_connection::disconnect, _1, "torrent finished, disconnecting seed", 0));
3094 TORRENT_ASSERT(m_storage);
3095 // we need to keep the object alive during this operation
3096 m_storage->async_release_files(
3097 bind(&torrent::on_files_released, shared_from_this(), _1, _2));
3100 // this is called when we were finished, but some files were
3101 // marked for downloading, and we are no longer finished
3102 void torrent::resume_download()
3104 INVARIANT_CHECK;
3106 TORRENT_ASSERT(!is_finished());
3107 set_state(torrent_status::downloading);
3108 set_queue_position((std::numeric_limits<int>::max)());
3111 // called when torrent is complete (all pieces downloaded)
3112 void torrent::completed()
3114 m_picker.reset();
3116 set_state(torrent_status::seeding);
3117 if (!m_complete_sent && m_announcing) announce_with_tracker();
3120 // this will move the tracker with the given index
3121 // to a prioritized position in the list (move it towards
3122 // the begining) and return the new index to the tracker.
3123 int torrent::prioritize_tracker(int index)
3125 INVARIANT_CHECK;
3127 TORRENT_ASSERT(index >= 0);
3128 if (index >= (int)m_trackers.size()) return (int)m_trackers.size()-1;
3130 while (index > 0 && m_trackers[index].tier == m_trackers[index-1].tier)
3132 std::swap(m_trackers[index].url, m_trackers[index-1].url);
3133 --index;
3135 return index;
3138 void torrent::try_next_tracker(tracker_request const& req)
3140 INVARIANT_CHECK;
3142 ++m_currently_trying_tracker;
3144 if ((unsigned)m_currently_trying_tracker < m_trackers.size())
3146 announce_with_tracker(req.event);
3147 return;
3150 int delay = tracker_retry_delay_min
3151 + (std::min)(int(m_failed_trackers), int(tracker_failed_max))
3152 * (tracker_retry_delay_max - tracker_retry_delay_min)
3153 / tracker_failed_max;
3155 ++m_failed_trackers;
3156 // if we've looped the tracker list, wait a bit before retrying
3157 m_currently_trying_tracker = 0;
3159 // if we're stopping, just give up. Don't bother retrying
3160 if (req.event == tracker_request::stopped)
3161 return;
3163 restart_tracker_timer(time_now() + seconds(delay));
3165 #ifndef TORRENT_DISABLE_DHT
3166 if (m_abort) return;
3168 // only start the announce if we want to announce with the dht
3169 ptime now = time_now();
3170 if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
3172 // force the DHT to reannounce
3173 m_last_dht_announce = now;
3174 boost::weak_ptr<torrent> self(shared_from_this());
3175 m_ses.m_dht->announce(m_torrent_file->info_hash()
3176 , m_ses.m_listen_sockets.front().external_port
3177 , bind(&torrent::on_dht_announce_response_disp, self, _1));
3179 #endif
3183 void torrent::files_checked()
3185 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3187 TORRENT_ASSERT(m_torrent_file->is_valid());
3188 INVARIANT_CHECK;
3190 set_state(torrent_status::connecting_to_tracker);
3192 if (!is_seed())
3194 if (m_sequential_download)
3195 picker().sequential_download(m_sequential_download);
3197 // if we just finished checking and we're not a seed, we are
3198 // likely to be unpaused
3199 if (m_ses.m_auto_manage_time_scaler > 1)
3200 m_ses.m_auto_manage_time_scaler = 1;
3203 #ifndef TORRENT_DISABLE_EXTENSIONS
3204 for (extension_list_t::iterator i = m_extensions.begin()
3205 , end(m_extensions.end()); i != end; ++i)
3207 #ifndef BOOST_NO_EXCEPTIONS
3208 try {
3209 #endif
3210 (*i)->on_files_checked();
3211 #ifndef BOOST_NO_EXCEPTIONS
3212 } catch (std::exception&) {}
3213 #endif
3215 #endif
3217 if (is_seed())
3219 m_complete_sent = true;
3220 finished();
3223 if (!m_connections_initialized)
3225 m_connections_initialized = true;
3226 // all peer connections have to initialize themselves now that the metadata
3227 // is available
3228 for (torrent::peer_iterator i = m_connections.begin();
3229 i != m_connections.end();)
3231 peer_connection* pc = *i;
3232 ++i;
3233 pc->on_metadata();
3234 pc->init();
3238 if (m_ses.m_alerts.should_post<torrent_checked_alert>())
3240 m_ses.m_alerts.post_alert(torrent_checked_alert(
3241 get_handle()));
3244 m_files_checked = true;
3246 start_announcing();
3249 alert_manager& torrent::alerts() const
3251 return m_ses.m_alerts;
3254 fs::path torrent::save_path() const
3256 return m_save_path;
3259 bool torrent::rename_file(int index, std::string const& name)
3261 INVARIANT_CHECK;
3263 TORRENT_ASSERT(index >= 0);
3264 TORRENT_ASSERT(index < m_torrent_file->num_files());
3266 if (!m_owning_storage.get()) return false;
3268 m_owning_storage->async_rename_file(index, name
3269 , bind(&torrent::on_file_renamed, shared_from_this(), _1, _2));
3270 return true;
3273 void torrent::move_storage(fs::path const& save_path)
3275 INVARIANT_CHECK;
3277 if (m_owning_storage.get())
3279 m_owning_storage->async_move_storage(save_path
3280 , bind(&torrent::on_storage_moved, shared_from_this(), _1, _2));
3282 else
3284 m_save_path = save_path;
3288 void torrent::on_storage_moved(int ret, disk_io_job const& j)
3290 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3292 if (alerts().should_post<storage_moved_alert>())
3294 alerts().post_alert(storage_moved_alert(get_handle(), j.str));
3296 m_save_path = j.str;
3299 piece_manager& torrent::filesystem()
3301 TORRENT_ASSERT(m_owning_storage.get());
3302 TORRENT_ASSERT(m_storage);
3303 return *m_storage;
3307 torrent_handle torrent::get_handle()
3309 return torrent_handle(shared_from_this());
3312 session_settings const& torrent::settings() const
3314 return m_ses.settings();
3317 #ifndef NDEBUG
3318 void torrent::check_invariant() const
3320 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
3322 TORRENT_ASSERT(m_resume_entry.type() == lazy_entry::dict_t
3323 || m_resume_entry.type() == lazy_entry::none_t);
3325 TORRENT_ASSERT(m_bandwidth_queue[0].size() <= m_connections.size());
3326 TORRENT_ASSERT(m_bandwidth_queue[1].size() <= m_connections.size());
3328 for (int c = 0; c < 2; ++c)
3330 queue_t::const_iterator j = m_bandwidth_queue[c].begin();
3331 if (j == m_bandwidth_queue[c].end()) continue;
3332 ++j;
3333 for (queue_t::const_iterator i = m_bandwidth_queue[c].begin()
3334 , end(m_bandwidth_queue[c].end()); i != end && j != end; ++i, ++j)
3335 TORRENT_ASSERT(i->priority >= j->priority);
3338 int num_uploads = 0;
3339 std::map<piece_block, int> num_requests;
3340 for (const_peer_iterator i = begin(); i != end(); ++i)
3342 #ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
3343 // make sure this peer is not a dangling pointer
3344 TORRENT_ASSERT(m_ses.has_peer(*i));
3345 #endif
3346 peer_connection const& p = *(*i);
3347 for (std::deque<piece_block>::const_iterator i = p.request_queue().begin()
3348 , end(p.request_queue().end()); i != end; ++i)
3349 ++num_requests[*i];
3350 for (std::deque<pending_block>::const_iterator i = p.download_queue().begin()
3351 , end(p.download_queue().end()); i != end; ++i)
3352 ++num_requests[i->block];
3353 if (!p.is_choked()) ++num_uploads;
3354 torrent* associated_torrent = p.associated_torrent().lock().get();
3355 if (associated_torrent != this)
3356 TORRENT_ASSERT(false);
3358 TORRENT_ASSERT(num_uploads == m_num_uploads);
3360 if (has_picker())
3362 for (std::map<piece_block, int>::iterator i = num_requests.begin()
3363 , end(num_requests.end()); i != end; ++i)
3365 if (!m_picker->is_downloaded(i->first))
3366 TORRENT_ASSERT(m_picker->num_peers(i->first) == i->second);
3368 TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered());
3371 if (valid_metadata())
3373 TORRENT_ASSERT(m_abort || !m_picker || m_picker->num_pieces() == m_torrent_file->num_pieces());
3375 else
3377 TORRENT_ASSERT(m_abort || m_picker->num_pieces() == 0);
3380 #ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
3381 for (policy::const_iterator i = m_policy.begin_peer()
3382 , end(m_policy.end_peer()); i != end; ++i)
3384 TORRENT_ASSERT(i->second.ip.address() == i->first);
3386 #endif
3388 size_type total_done = quantized_bytes_done();
3389 if (m_torrent_file->is_valid())
3391 if (is_seed())
3392 TORRENT_ASSERT(total_done == m_torrent_file->total_size());
3393 else
3394 TORRENT_ASSERT(total_done != m_torrent_file->total_size() || !m_files_checked);
3396 TORRENT_ASSERT(m_block_size <= m_torrent_file->piece_length());
3398 else
3400 TORRENT_ASSERT(total_done == 0);
3403 if (m_picker && !m_abort)
3405 // make sure that pieces that have completed the download
3406 // of all their blocks are in the disk io thread's queue
3407 // to be checked.
3408 const std::vector<piece_picker::downloading_piece>& dl_queue
3409 = m_picker->get_download_queue();
3410 for (std::vector<piece_picker::downloading_piece>::const_iterator i =
3411 dl_queue.begin(); i != dl_queue.end(); ++i)
3413 const int blocks_per_piece = m_picker->blocks_in_piece(i->index);
3415 bool complete = true;
3416 for (int j = 0; j < blocks_per_piece; ++j)
3418 if (i->info[j].state == piece_picker::block_info::state_finished)
3419 continue;
3420 complete = false;
3421 break;
3426 // This check is very expensive.
3427 TORRENT_ASSERT(!valid_metadata() || m_block_size > 0);
3428 TORRENT_ASSERT(!valid_metadata() || (m_torrent_file->piece_length() % m_block_size) == 0);
3429 // if (is_seed()) TORRENT_ASSERT(m_picker.get() == 0);
3431 #endif
3433 void torrent::set_sequential_download(bool sd)
3435 if (has_picker())
3437 picker().sequential_download(sd);
3439 else
3441 m_sequential_download = sd;
3445 void torrent::set_queue_position(int p)
3447 TORRENT_ASSERT((p == -1) == is_finished()
3448 || (!m_auto_managed && p == -1)
3449 || (m_abort && p == -1));
3450 if (is_finished() && p != -1) return;
3451 if (p == m_sequence_number) return;
3453 session_impl::torrent_map& torrents = m_ses.m_torrents;
3454 if (p >= 0 && m_sequence_number == -1)
3456 int max_seq = -1;
3457 for (session_impl::torrent_map::iterator i = torrents.begin()
3458 , end(torrents.end()); i != end; ++i)
3460 torrent* t = i->second.get();
3461 if (t->m_sequence_number > max_seq) max_seq = t->m_sequence_number;
3463 m_sequence_number = (std::min)(max_seq + 1, p);
3465 else if (p < 0)
3467 for (session_impl::torrent_map::iterator i = torrents.begin()
3468 , end(torrents.end()); i != end; ++i)
3470 torrent* t = i->second.get();
3471 if (t == this) continue;
3472 if (t->m_sequence_number >= m_sequence_number
3473 && t->m_sequence_number != -1)
3474 --t->m_sequence_number;
3476 m_sequence_number = p;
3478 else if (p < m_sequence_number)
3480 for (session_impl::torrent_map::iterator i = torrents.begin()
3481 , end(torrents.end()); i != end; ++i)
3483 torrent* t = i->second.get();
3484 if (t == this) continue;
3485 if (t->m_sequence_number >= p
3486 && t->m_sequence_number < m_sequence_number
3487 && t->m_sequence_number != -1)
3488 ++t->m_sequence_number;
3490 m_sequence_number = p;
3492 else if (p > m_sequence_number)
3494 int max_seq = 0;
3495 for (session_impl::torrent_map::iterator i = torrents.begin()
3496 , end(torrents.end()); i != end; ++i)
3498 torrent* t = i->second.get();
3499 int pos = t->m_sequence_number;
3500 if (pos > max_seq) max_seq = pos;
3501 if (t == this) continue;
3503 if (pos <= p
3504 && pos > m_sequence_number
3505 && pos != -1)
3506 --t->m_sequence_number;
3509 m_sequence_number = (std::min)(max_seq, p);
3512 if (m_ses.m_auto_manage_time_scaler > 2)
3513 m_ses.m_auto_manage_time_scaler = 2;
3516 void torrent::set_max_uploads(int limit)
3518 TORRENT_ASSERT(limit >= -1);
3519 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3520 m_max_uploads = limit;
3523 void torrent::set_max_connections(int limit)
3525 TORRENT_ASSERT(limit >= -1);
3526 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3527 m_max_connections = limit;
3530 void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit)
3532 TORRENT_ASSERT(limit >= -1);
3533 peer_iterator i = std::find_if(m_connections.begin(), m_connections.end()
3534 , bind(&peer_connection::remote, _1) == ip);
3535 if (i == m_connections.end()) return;
3536 (*i)->set_upload_limit(limit);
3539 void torrent::set_peer_download_limit(tcp::endpoint ip, int limit)
3541 TORRENT_ASSERT(limit >= -1);
3542 peer_iterator i = std::find_if(m_connections.begin(), m_connections.end()
3543 , bind(&peer_connection::remote, _1) == ip);
3544 if (i == m_connections.end()) return;
3545 (*i)->set_download_limit(limit);
3548 void torrent::set_upload_limit(int limit)
3550 TORRENT_ASSERT(limit >= -1);
3551 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3552 if (limit < num_peers() * 10) limit = num_peers() * 10;
3553 m_bandwidth_limit[peer_connection::upload_channel].throttle(limit);
3556 int torrent::upload_limit() const
3558 int limit = m_bandwidth_limit[peer_connection::upload_channel].throttle();
3559 if (limit == (std::numeric_limits<int>::max)()) limit = -1;
3560 return limit;
3563 void torrent::set_download_limit(int limit)
3565 TORRENT_ASSERT(limit >= -1);
3566 if (limit <= 0) limit = (std::numeric_limits<int>::max)();
3567 if (limit < num_peers() * 10) limit = num_peers() * 10;
3568 m_bandwidth_limit[peer_connection::download_channel].throttle(limit);
3571 int torrent::download_limit() const
3573 int limit = m_bandwidth_limit[peer_connection::download_channel].throttle();
3574 if (limit == (std::numeric_limits<int>::max)()) limit = -1;
3575 return limit;
3578 void torrent::delete_files()
3580 #if defined TORRENT_VERBOSE_LOGGING
3581 for (peer_iterator i = m_connections.begin();
3582 i != m_connections.end(); ++i)
3584 (*(*i)->m_logger) << "*** DELETING FILES IN TORRENT\n";
3586 #endif
3588 disconnect_all();
3589 stop_announcing();
3591 if (m_owning_storage.get())
3593 TORRENT_ASSERT(m_storage);
3594 m_storage->async_delete_files(
3595 bind(&torrent::on_files_deleted, shared_from_this(), _1, _2));
3599 void torrent::clear_error()
3601 if (m_error.empty()) return;
3602 if (m_ses.m_auto_manage_time_scaler > 2)
3603 m_ses.m_auto_manage_time_scaler = 2;
3604 m_error.clear();
3607 void torrent::auto_managed(bool a)
3609 INVARIANT_CHECK;
3611 if (m_auto_managed == a) return;
3612 m_auto_managed = a;
3613 // recalculate which torrents should be
3614 // paused
3615 m_ses.m_auto_manage_time_scaler = 0;
3618 // the higher seed rank, the more important to seed
3619 int torrent::seed_rank(session_settings const& s) const
3621 enum flags
3623 seed_ratio_not_met = 0x400000,
3624 recently_started = 0x200000,
3625 no_seeds = 0x100000,
3626 prio_mask = 0xfffff
3629 if (!is_seed()) return 0;
3631 int ret = 0;
3633 ptime now(time_now());
3635 int seed_time = total_seconds(m_seeding_time);
3636 int download_time = total_seconds(m_active_time) - seed_time;
3638 // if we haven't yet met the seed limits, set the seed_ratio_not_met
3639 // flag. That will make this seed prioritized
3640 size_type downloaded = (std::max)(m_total_downloaded, m_torrent_file->total_size());
3641 if (seed_time < s.seed_time_limit
3642 && (seed_time > 1 && download_time / float(seed_time) < s.seed_time_ratio_limit)
3643 && m_total_uploaded / downloaded < s.share_ratio_limit)
3644 ret |= seed_ratio_not_met;
3646 // if this torrent is running, and it was started less
3647 // than 30 minutes ago, give it priority, to avoid oscillation
3648 if (!is_paused() && now - m_started < minutes(30))
3649 ret |= recently_started;
3651 // if we have any scrape data, use it to calculate
3652 // seed rank
3653 int seeds = 0;
3654 int downloaders = 0;
3656 if (m_complete >= 0) seeds = m_complete;
3657 else seeds = m_policy.num_seeds();
3659 if (m_incomplete >= 0) downloaders = m_incomplete;
3660 else downloaders = m_policy.num_peers() - m_policy.num_seeds();
3662 if (seeds == 0)
3664 ret |= no_seeds;
3665 ret |= downloaders & prio_mask;
3667 else
3669 ret |= (downloaders * 100 / seeds) & prio_mask;
3672 return ret;
3675 // this is an async operation triggered by the client
3676 void torrent::save_resume_data()
3678 INVARIANT_CHECK;
3680 if (m_owning_storage.get())
3682 TORRENT_ASSERT(m_storage);
3683 if (m_state == torrent_status::queued_for_checking
3684 || m_state == torrent_status::checking_files)
3686 if (alerts().should_post<save_resume_data_failed_alert>())
3688 alerts().post_alert(save_resume_data_failed_alert(get_handle()
3689 , "won't save resume data, torrent does not have a complete resume state yet"));
3692 else
3694 m_storage->async_save_resume_data(
3695 bind(&torrent::on_save_resume_data, shared_from_this(), _1, _2));
3698 else
3700 if (alerts().should_post<save_resume_data_failed_alert>())
3702 alerts().post_alert(save_resume_data_failed_alert(get_handle()
3703 , "save resume data failed, torrent is being destructed"));
3708 bool torrent::is_paused() const
3710 return m_paused || m_ses.is_paused();
3713 void torrent::pause()
3715 INVARIANT_CHECK;
3717 if (m_paused) return;
3718 m_paused = true;
3719 if (m_ses.is_paused()) return;
3720 do_pause();
3723 void torrent::do_pause()
3725 if (!is_paused()) return;
3727 #ifndef TORRENT_DISABLE_EXTENSIONS
3728 for (extension_list_t::iterator i = m_extensions.begin()
3729 , end(m_extensions.end()); i != end; ++i)
3731 #ifndef BOOST_NO_EXCEPTIONS
3732 try {
3733 #endif
3734 if ((*i)->on_pause()) return;
3735 #ifndef BOOST_NO_EXCEPTIONS
3736 } catch (std::exception&) {}
3737 #endif
3739 #endif
3741 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
3742 for (peer_iterator i = m_connections.begin();
3743 i != m_connections.end(); ++i)
3745 (*(*i)->m_logger) << "*** PAUSING TORRENT\n";
3747 #endif
3749 // this will make the storage close all
3750 // files and flush all cached data
3751 if (m_owning_storage.get())
3753 TORRENT_ASSERT(m_storage);
3754 m_storage->async_release_files(
3755 bind(&torrent::on_torrent_paused, shared_from_this(), _1, _2));
3757 else
3759 if (alerts().should_post<torrent_paused_alert>())
3760 alerts().post_alert(torrent_paused_alert(get_handle()));
3763 disconnect_all();
3764 stop_announcing();
3767 void torrent::resume()
3769 INVARIANT_CHECK;
3771 if (!m_paused) return;
3772 m_paused = false;
3773 do_resume();
3776 void torrent::do_resume()
3778 if (is_paused()) return;
3780 #ifndef TORRENT_DISABLE_EXTENSIONS
3781 for (extension_list_t::iterator i = m_extensions.begin()
3782 , end(m_extensions.end()); i != end; ++i)
3784 #ifndef BOOST_NO_EXCEPTIONS
3785 try {
3786 #endif
3787 if ((*i)->on_resume()) return;
3788 #ifndef BOOST_NO_EXCEPTIONS
3789 } catch (std::exception&) {}
3790 #endif
3792 #endif
3794 if (alerts().should_post<torrent_resumed_alert>())
3795 alerts().post_alert(torrent_resumed_alert(get_handle()));
3797 m_started = time_now();
3798 m_error.clear();
3799 start_announcing();
3802 void torrent::restart_tracker_timer(ptime announce_at)
3804 if (!m_announcing) return;
3806 m_next_tracker_announce = announce_at;
3807 error_code ec;
3808 boost::weak_ptr<torrent> self(shared_from_this());
3809 m_tracker_timer.expires_at(m_next_tracker_announce, ec);
3810 m_tracker_timer.async_wait(bind(&torrent::on_tracker_announce_disp, self, _1));
3813 void torrent::start_announcing()
3815 if (is_paused()) return;
3816 if (!m_files_checked) return;
3817 if (m_announcing) return;
3819 m_announcing = true;
3821 if (!m_trackers.empty())
3823 // tell the tracker that we're back
3824 m_start_sent = false;
3825 announce_with_tracker();
3828 // private torrents are never announced on LSD
3829 // or on DHT, we don't need this timer.
3830 if (!m_torrent_file->is_valid() || !m_torrent_file->priv())
3832 error_code ec;
3833 boost::weak_ptr<torrent> self(shared_from_this());
3834 m_lsd_announce_timer.expires_from_now(seconds(1), ec);
3835 m_lsd_announce_timer.async_wait(
3836 bind(&torrent::on_lsd_announce_disp, self, _1));
3840 void torrent::stop_announcing()
3842 if (!m_announcing) return;
3844 error_code ec;
3845 m_lsd_announce_timer.cancel(ec);
3846 m_tracker_timer.cancel(ec);
3848 m_announcing = false;
3850 if (!m_trackers.empty())
3851 announce_with_tracker(tracker_request::stopped);
3854 void torrent::second_tick(stat& accumulator, float tick_interval)
3856 INVARIANT_CHECK;
3858 #ifndef TORRENT_DISABLE_EXTENSIONS
3859 for (extension_list_t::iterator i = m_extensions.begin()
3860 , end(m_extensions.end()); i != end; ++i)
3862 #ifndef BOOST_NO_EXCEPTIONS
3863 try {
3864 #endif
3865 (*i)->tick();
3866 #ifndef BOOST_NO_EXCEPTIONS
3867 } catch (std::exception&) {}
3868 #endif
3870 #endif
3872 if (is_paused())
3874 // let the stats fade out to 0
3875 m_stat.second_tick(tick_interval);
3876 return;
3879 time_duration since_last_tick = microsec(tick_interval * 1000000L);
3880 if (is_seed()) m_seeding_time += since_last_tick;
3881 m_active_time += since_last_tick;
3883 // ---- WEB SEEDS ----
3885 // re-insert urls that are to be retrieds into the m_web_seeds
3886 typedef std::map<std::string, ptime>::iterator iter_t;
3887 for (iter_t i = m_web_seeds_next_retry.begin(); i != m_web_seeds_next_retry.end();)
3889 iter_t erase_element = i++;
3890 if (erase_element->second <= time_now())
3892 m_web_seeds.insert(erase_element->first);
3893 m_web_seeds_next_retry.erase(erase_element);
3897 // if we have everything we want we don't need to connect to any web-seed
3898 if (!is_finished() && !m_web_seeds.empty())
3900 // keep trying web-seeds if there are any
3901 // first find out which web seeds we are connected to
3902 std::set<std::string> web_seeds;
3903 for (peer_iterator i = m_connections.begin();
3904 i != m_connections.end(); ++i)
3906 web_peer_connection* p
3907 = dynamic_cast<web_peer_connection*>(*i);
3908 if (!p) continue;
3909 web_seeds.insert(p->url());
3912 for (std::set<std::string>::iterator i = m_resolving_web_seeds.begin()
3913 , end(m_resolving_web_seeds.end()); i != end; ++i)
3914 web_seeds.insert(web_seeds.begin(), *i);
3916 // from the list of available web seeds, subtract the ones we are
3917 // already connected to.
3918 std::vector<std::string> not_connected_web_seeds;
3919 std::set_difference(m_web_seeds.begin(), m_web_seeds.end(), web_seeds.begin()
3920 , web_seeds.end(), std::back_inserter(not_connected_web_seeds));
3922 // connect to all of those that we aren't connected to
3923 std::for_each(not_connected_web_seeds.begin(), not_connected_web_seeds.end()
3924 , bind(&torrent::connect_to_url_seed, this, _1));
3927 for (peer_iterator i = m_connections.begin();
3928 i != m_connections.end();)
3930 peer_connection* p = *i;
3931 ++i;
3932 p->calc_ip_overhead();
3933 m_stat += p->statistics();
3934 // updates the peer connection's ul/dl bandwidth
3935 // resource requests
3936 #ifndef BOOST_NO_EXCEPTIONS
3939 #endif
3940 p->second_tick(tick_interval);
3941 #ifndef BOOST_NO_EXCEPTIONS
3943 catch (std::exception& e)
3945 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
3946 (*p->m_logger) << "**ERROR**: " << e.what() << "\n";
3947 #endif
3948 p->disconnect(e.what(), 1);
3950 #endif
3952 accumulator += m_stat;
3953 m_total_uploaded += m_stat.last_payload_uploaded();
3954 m_total_downloaded += m_stat.last_payload_downloaded();
3955 m_stat.second_tick(tick_interval);
3957 m_time_scaler--;
3958 if (m_time_scaler <= 0)
3960 m_time_scaler = 10;
3961 m_policy.pulse();
3965 void torrent::retry_url_seed(std::string const& url)
3967 m_web_seeds_next_retry[url] = time_now()
3968 + seconds(m_ses.settings().urlseed_wait_retry);
3971 bool torrent::try_connect_peer()
3973 TORRENT_ASSERT(want_more_peers());
3974 if (m_deficit_counter < 100) return false;
3975 m_deficit_counter -= 100;
3976 bool ret = m_policy.connect_one_peer();
3977 return ret;
3980 void torrent::give_connect_points(int points)
3982 TORRENT_ASSERT(points <= 100);
3983 TORRENT_ASSERT(points > 0);
3984 TORRENT_ASSERT(want_more_peers());
3985 m_deficit_counter += points;
3988 void torrent::async_verify_piece(int piece_index, boost::function<void(int)> const& f)
3990 // INVARIANT_CHECK;
3992 TORRENT_ASSERT(m_storage);
3993 TORRENT_ASSERT(m_storage->refcount() > 0);
3994 TORRENT_ASSERT(piece_index >= 0);
3995 TORRENT_ASSERT(piece_index < m_torrent_file->num_pieces());
3996 TORRENT_ASSERT(piece_index < (int)m_picker->num_pieces());
3997 #ifndef NDEBUG
3998 if (m_picker)
4000 int blocks_in_piece = m_picker->blocks_in_piece(piece_index);
4001 for (int i = 0; i < blocks_in_piece; ++i)
4003 TORRENT_ASSERT(m_picker->num_peers(piece_block(piece_index, i)) == 0);
4006 #endif
4008 m_storage->async_hash(piece_index, bind(&torrent::on_piece_verified
4009 , shared_from_this(), _1, _2, f));
4010 #if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
4011 check_invariant();
4012 #endif
4015 void torrent::on_piece_verified(int ret, disk_io_job const& j
4016 , boost::function<void(int)> f)
4018 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4020 // return value:
4021 // 0: success, piece passed hash check
4022 // -1: disk failure
4023 // -2: hash check failed
4025 if (ret == -1)
4027 if (alerts().should_post<file_error_alert>())
4028 alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str));
4029 m_error = j.str;
4030 pause();
4032 f(ret);
4035 const tcp::endpoint& torrent::current_tracker() const
4037 return m_tracker_address;
4040 void torrent::file_progress(std::vector<float>& fp) const
4042 fp.clear();
4043 fp.resize(m_torrent_file->num_files(), 1.f);
4044 if (is_seed()) return;
4046 std::vector<size_type> progress;
4047 file_progress(progress);
4048 for (int i = 0; i < m_torrent_file->num_files(); ++i)
4050 file_entry const& f = m_torrent_file->file_at(i);
4051 if (f.size == 0) fp[i] = 1.f;
4052 else fp[i] = float(progress[i]) / f.size;
4056 void torrent::file_progress(std::vector<size_type>& fp) const
4058 TORRENT_ASSERT(valid_metadata());
4060 fp.resize(m_torrent_file->num_files(), 0);
4061 TORRENT_ASSERT(has_picker());
4063 if (is_seed())
4065 for (int i = 0; i < m_torrent_file->num_files(); ++i)
4066 fp[i] = m_torrent_file->files().at(i).size;
4067 return;
4070 for (int i = 0; i < m_torrent_file->num_files(); ++i)
4072 peer_request ret = m_torrent_file->files().map_file(i, 0, 0);
4073 size_type size = m_torrent_file->files().at(i).size;
4075 // zero sized files are considered
4076 // 100% done all the time
4077 if (size == 0)
4079 fp[i] = 0;
4080 continue;
4083 size_type done = 0;
4084 while (size > 0)
4086 size_type bytes_step = (std::min)(size_type(m_torrent_file->piece_size(ret.piece)
4087 - ret.start), size);
4088 if (m_picker->have_piece(ret.piece)) done += bytes_step;
4089 ++ret.piece;
4090 ret.start = 0;
4091 size -= bytes_step;
4093 TORRENT_ASSERT(size == 0);
4095 fp[i] = done;
4098 const std::vector<piece_picker::downloading_piece>& q
4099 = m_picker->get_download_queue();
4101 for (std::vector<piece_picker::downloading_piece>::const_iterator
4102 i = q.begin(), end(q.end()); i != end; ++i)
4104 size_type offset = size_type(i->index) * m_torrent_file->piece_length();
4105 torrent_info::file_iterator file = m_torrent_file->file_at_offset(offset);
4106 int file_index = file - m_torrent_file->begin_files();
4107 int num_blocks = m_picker->blocks_in_piece(i->index);
4108 piece_picker::block_info const* info = i->info;
4109 for (int k = 0; k < num_blocks; ++k)
4111 TORRENT_ASSERT(file != m_torrent_file->end_files());
4112 TORRENT_ASSERT(offset == size_type(i->index) * m_torrent_file->piece_length()
4113 + k * m_block_size);
4114 TORRENT_ASSERT(offset < m_torrent_file->total_size());
4115 while (offset >= file->offset + file->size)
4117 ++file;
4118 ++file_index;
4120 TORRENT_ASSERT(file != m_torrent_file->end_files());
4122 size_type block_size = m_block_size;
4124 if (info[k].state == piece_picker::block_info::state_none)
4126 offset += m_block_size;
4127 continue;
4130 if (info[k].state == piece_picker::block_info::state_requested)
4132 block_size = 0;
4133 policy::peer* p = static_cast<policy::peer*>(info[k].peer);
4134 if (p && p->connection)
4136 boost::optional<piece_block_progress> pbp
4137 = p->connection->downloading_piece_progress();
4138 if (pbp && pbp->piece_index == i->index && pbp->block_index == k)
4139 block_size = pbp->bytes_downloaded;
4140 TORRENT_ASSERT(block_size <= m_block_size);
4143 if (block_size == 0)
4145 offset += m_block_size;
4146 continue;
4150 if (offset + block_size > file->offset + file->size)
4152 int left_over = m_block_size - block_size;
4153 // split the block on multiple files
4154 while (block_size > 0)
4156 TORRENT_ASSERT(offset <= file->offset + file->size);
4157 size_type slice = (std::min)(file->offset + file->size - offset
4158 , block_size);
4159 fp[file_index] += slice;
4160 offset += slice;
4161 block_size -= slice;
4162 TORRENT_ASSERT(offset <= file->offset + file->size);
4163 if (offset == file->offset + file->size)
4165 ++file;
4166 ++file_index;
4167 if (file == m_torrent_file->end_files())
4169 offset += block_size;
4170 break;
4174 offset += left_over;
4175 TORRENT_ASSERT(offset == size_type(i->index) * m_torrent_file->piece_length()
4176 + (k+1) * m_block_size);
4178 else
4180 fp[file_index] += block_size;
4181 offset += m_block_size;
4183 TORRENT_ASSERT(file_index <= m_torrent_file->num_files());
4188 void torrent::set_state(torrent_status::state_t s)
4190 if (m_state == s) return;
4191 m_state = s;
4192 if (m_ses.m_alerts.should_post<state_changed_alert>())
4193 m_ses.m_alerts.post_alert(state_changed_alert(get_handle(), s));
4196 torrent_status torrent::status() const
4198 INVARIANT_CHECK;
4200 ptime now = time_now();
4202 torrent_status st;
4204 st.has_incoming = m_has_incoming;
4205 st.error = m_error;
4207 if (m_last_scrape == min_time())
4209 st.last_scrape = -1;
4211 else
4213 st.last_scrape = total_seconds(now - m_last_scrape);
4215 st.up_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::upload_channel].size();
4216 st.down_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::download_channel].size();
4218 st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end()
4219 , !boost::bind(&peer_connection::is_connecting, _1));
4221 st.list_peers = m_policy.num_peers();
4222 st.list_seeds = m_policy.num_seeds();
4223 st.connect_candidates = m_policy.num_connect_candidates();
4224 st.seed_rank = seed_rank(m_ses.m_settings);
4226 st.all_time_upload = m_total_uploaded;
4227 st.all_time_download = m_total_downloaded;
4229 st.active_time = total_seconds(m_active_time);
4230 st.seeding_time = total_seconds(m_seeding_time);
4232 st.storage_mode = m_storage_mode;
4234 st.num_complete = m_complete;
4235 st.num_incomplete = m_incomplete;
4236 st.paused = m_paused;
4237 boost::tie(st.total_done, st.total_wanted_done) = bytes_done();
4238 TORRENT_ASSERT(st.total_wanted_done >= 0);
4239 TORRENT_ASSERT(st.total_done >= st.total_wanted_done);
4241 // payload transfer
4242 st.total_payload_download = m_stat.total_payload_download();
4243 st.total_payload_upload = m_stat.total_payload_upload();
4245 // total transfer
4246 st.total_download = m_stat.total_payload_download()
4247 + m_stat.total_protocol_download();
4248 st.total_upload = m_stat.total_payload_upload()
4249 + m_stat.total_protocol_upload();
4251 // failed bytes
4252 st.total_failed_bytes = m_total_failed_bytes;
4253 st.total_redundant_bytes = m_total_redundant_bytes;
4255 // transfer rate
4256 st.download_rate = m_stat.download_rate();
4257 st.upload_rate = m_stat.upload_rate();
4258 st.download_payload_rate = m_stat.download_payload_rate();
4259 st.upload_payload_rate = m_stat.upload_payload_rate();
4261 st.next_announce = boost::posix_time::seconds(
4262 total_seconds(next_announce() - now));
4263 if (st.next_announce.is_negative())
4264 st.next_announce = boost::posix_time::seconds(0);
4266 st.announce_interval = boost::posix_time::seconds(m_duration);
4268 if (m_last_working_tracker >= 0)
4270 st.current_tracker
4271 = m_trackers[m_last_working_tracker].url;
4274 st.num_uploads = m_num_uploads;
4275 st.uploads_limit = m_max_uploads;
4276 st.num_connections = int(m_connections.size());
4277 st.connections_limit = m_max_connections;
4278 // if we don't have any metadata, stop here
4280 st.state = m_state;
4282 if (!valid_metadata())
4284 if (m_got_tracker_response == false && m_connections.empty())
4285 st.state = torrent_status::connecting_to_tracker;
4286 else
4287 st.state = torrent_status::downloading_metadata;
4289 st.progress = m_progress;
4290 st.block_size = 0;
4291 return st;
4294 st.block_size = block_size();
4296 // fill in status that depends on metadata
4298 st.total_wanted = m_torrent_file->total_size();
4299 TORRENT_ASSERT(st.total_wanted >= 0);
4300 TORRENT_ASSERT(st.total_wanted >= m_torrent_file->piece_length()
4301 * (m_torrent_file->num_pieces() - 1));
4303 if (m_picker.get() && (m_picker->num_filtered() > 0
4304 || m_picker->num_have_filtered() > 0))
4306 int num_filtered_pieces = m_picker->num_filtered()
4307 + m_picker->num_have_filtered();
4308 int last_piece_index = m_torrent_file->num_pieces() - 1;
4309 if (m_picker->piece_priority(last_piece_index) == 0)
4311 st.total_wanted -= m_torrent_file->piece_size(last_piece_index);
4312 --num_filtered_pieces;
4315 st.total_wanted -= size_type(num_filtered_pieces) * m_torrent_file->piece_length();
4318 TORRENT_ASSERT(st.total_wanted >= st.total_wanted_done);
4320 if (m_state == torrent_status::checking_files)
4321 st.progress = m_progress;
4322 else if (st.total_wanted == 0) st.progress = 1.f;
4323 else st.progress = st.total_wanted_done
4324 / static_cast<float>(st.total_wanted);
4326 if (has_picker())
4328 int num_pieces = m_picker->num_pieces();
4329 st.pieces.resize(num_pieces, false);
4330 for (int i = 0; i < num_pieces; ++i)
4331 if (m_picker->have_piece(i)) st.pieces.set_bit(i);
4333 st.num_pieces = num_have();
4334 st.num_seeds = num_seeds();
4335 if (m_picker.get())
4336 st.distributed_copies = m_picker->distributed_copies();
4337 else
4338 st.distributed_copies = -1;
4339 return st;
4342 void torrent::add_redundant_bytes(int b)
4344 TORRENT_ASSERT(b > 0);
4345 m_total_redundant_bytes += b;
4346 m_ses.add_redundant_bytes(b);
4349 void torrent::add_failed_bytes(int b)
4351 TORRENT_ASSERT(b > 0);
4352 m_total_failed_bytes += b;
4353 m_ses.add_failed_bytes(b);
4356 int torrent::num_seeds() const
4358 INVARIANT_CHECK;
4360 return (int)std::count_if(m_connections.begin(), m_connections.end()
4361 , boost::bind(&peer_connection::is_seed, _1));
4364 void torrent::tracker_request_timed_out(
4365 tracker_request const& r)
4367 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4369 INVARIANT_CHECK;
4371 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4372 debug_log("*** tracker timed out");
4373 #endif
4375 if (r.kind == tracker_request::announce_request)
4377 if (m_ses.m_alerts.should_post<tracker_error_alert>())
4379 m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
4380 , m_failed_trackers + 1, 0, r.url, "tracker timed out"));
4383 else if (r.kind == tracker_request::scrape_request)
4385 if (m_ses.m_alerts.should_post<scrape_failed_alert>())
4387 m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle()
4388 , r.url, "tracker timed out"));
4392 if (r.kind == tracker_request::announce_request)
4393 try_next_tracker(r);
4396 // TODO: with some response codes, we should just consider
4397 // the tracker as a failure and not retry
4398 // it anymore
4399 void torrent::tracker_request_error(tracker_request const& r
4400 , int response_code, const std::string& str)
4402 session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
4404 INVARIANT_CHECK;
4406 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4407 debug_log(std::string("*** tracker error: ") + str);
4408 #endif
4409 if (r.kind == tracker_request::announce_request)
4411 if (m_ses.m_alerts.should_post<tracker_error_alert>())
4413 m_ses.m_alerts.post_alert(tracker_error_alert(get_handle()
4414 , m_failed_trackers + 1, response_code, r.url, str));
4417 else if (r.kind == tracker_request::scrape_request)
4419 if (m_ses.m_alerts.should_post<scrape_failed_alert>())
4421 m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), r.url, str));
4425 if (r.kind == tracker_request::announce_request)
4426 try_next_tracker(r);
4430 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
4431 void torrent::debug_log(const std::string& line)
4433 (*m_ses.m_logger) << time_now_string() << " " << line << "\n";
4435 #endif