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