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