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