diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp index 6f41758fa..a1dcf4364 100755 --- a/include/libtorrent/alert_types.hpp +++ b/include/libtorrent/alert_types.hpp @@ -82,6 +82,35 @@ namespace libtorrent { return std::auto_ptr(new tracker_warning_alert(*this)); } }; + struct TORRENT_EXPORT scrape_reply_alert: torrent_alert + { + scrape_reply_alert(torrent_handle const& h + , int incomplete_ + , int complete_ + , std::string const& msg) + : torrent_alert(h, alert::info, msg) + , incomplete(incomplete_) + , complete(complete_) + {} + + int incomplete; + int complete; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new scrape_reply_alert(*this)); } + }; + + struct TORRENT_EXPORT scrape_failed_alert: torrent_alert + { + scrape_failed_alert(torrent_handle const& h + , std::string const& msg) + : torrent_alert(h, alert::warning, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new scrape_failed_alert(*this)); } + }; + struct TORRENT_EXPORT tracker_reply_alert: torrent_alert { tracker_reply_alert(torrent_handle const& h diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 5ee5ddb03..7aa779081 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -309,6 +309,8 @@ namespace libtorrent virtual void tracker_request_error(tracker_request const& r , int response_code, const std::string& str); virtual void tracker_warning(std::string const& msg); + virtual void tracker_scrape_response(tracker_request const& req + , int complete, int incomplete, int downloaded); // generates a request string for sending // to the tracker @@ -332,6 +334,7 @@ namespace libtorrent // forcefully sets next_announce to the current time void force_tracker_request(); void force_tracker_request(ptime); + void scrape_tracker(); // sets the username and password that will be sent to // the tracker diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index 7ddb218a6..48a17e2ec 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -94,15 +94,17 @@ namespace libtorrent , upload_rate(0) , download_payload_rate(0) , upload_payload_rate(0) + , num_seeds(0) , num_peers(0) , num_complete(-1) , num_incomplete(-1) + , list_seeds(0) + , list_peers(0) , pieces(0) , num_pieces(0) , total_done(0) , total_wanted_done(0) , total_wanted(0) - , num_seeds(0) , distributed_copies(0.f) , block_size(0) , num_uploads(0) @@ -159,8 +161,12 @@ namespace libtorrent float download_payload_rate; float upload_payload_rate; + // the number of peers this torrent is connected to + // that are seeding. + int num_seeds; + // the number of peers this torrent - // is connected to. + // is connected to (including seeds). int num_peers; // if the tracker sends scrape info in its @@ -171,6 +177,15 @@ namespace libtorrent int num_complete; int num_incomplete; + // this is the number of seeds whose IP we know + // but are not necessarily connected to + int list_seeds; + + // this is the number of peers whose IP we know + // (including seeds), but are not necessarily + // connected to + int list_peers; + const std::vector* pieces; // this is the number of pieces the client has @@ -193,10 +208,6 @@ namespace libtorrent // in case any pieces are filtered as not wanted size_type total_wanted; - // the number of peers this torrent is connected to - // that are seeding. - int num_seeds; - // the number of distributed copies of the file. // note that one copy may be spread out among many peers. // @@ -345,6 +356,9 @@ namespace libtorrent // timed out. void force_reannounce(boost::posix_time::time_duration) const; + // performs a scrape request + void scrape_tracker() const; + // returns the name of this torrent, in case it doesn't // have metadata it returns the name assigned to it // when it was added. diff --git a/include/libtorrent/tracker_manager.hpp b/include/libtorrent/tracker_manager.hpp index fdc3f6bbf..8fec9563c 100755 --- a/include/libtorrent/tracker_manager.hpp +++ b/include/libtorrent/tracker_manager.hpp @@ -122,6 +122,8 @@ namespace libtorrent request_callback(): m_manager(0) {} virtual ~request_callback() {} virtual void tracker_warning(std::string const& msg) = 0; + virtual void tracker_scrape_response(tracker_request const& req + , int complete, int incomplete, int downloads) {} virtual void tracker_response( tracker_request const& , std::vector& peers @@ -191,7 +193,7 @@ namespace libtorrent : timeout_handler { tracker_connection(tracker_manager& man - , tracker_request req + , tracker_request const& req , asio::strand& str , address bind_interface , boost::weak_ptr r); diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index ed9823b83..86d21e494 100755 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -797,7 +797,7 @@ namespace libtorrent return; } m_buffer.erase(m_buffer.begin(), m_buffer.begin() + m_parser.body_start()); - if (inflate_gzip(m_buffer, tracker_request(), cb.get(), + if (inflate_gzip(m_buffer, tracker_req(), cb.get(), m_settings.tracker_maximum_response_length)) { close(); @@ -897,21 +897,35 @@ namespace libtorrent } catch(type_error const&) {} - std::vector peer_list; - if (tracker_req().kind == tracker_request::scrape_request) { std::string ih; std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end() , std::back_inserter(ih)); entry scrape_data = e["files"][ih]; - int complete = scrape_data["complete"].integer(); - int incomplete = scrape_data["incomplete"].integer(); - cb->tracker_response(tracker_request(), peer_list, 0, complete - , incomplete); + + int complete = -1; + int incomplete = -1; + int downloaded = -1; + + entry const* complete_ent = scrape_data.find_key("complete"); + if (complete_ent && complete_ent->type() == entry::int_t) + complete = complete_ent->integer(); + + entry const* incomplete_ent = scrape_data.find_key("incomplete"); + if (incomplete_ent && incomplete_ent->type() == entry::int_t) + incomplete = incomplete_ent->integer(); + + entry const* downloaded_ent = scrape_data.find_key("downloaded"); + if (downloaded_ent && downloaded_ent->type() == entry::int_t) + downloaded = downloaded_ent->integer(); + + cb->tracker_scrape_response(tracker_req(), complete + , incomplete, downloaded); return; } + std::vector peer_list; int interval = (int)e["interval"].integer(); if (e["peers"].type() == entry::string_t) @@ -965,16 +979,16 @@ namespace libtorrent try { incomplete = e["incomplete"].integer(); } catch(type_error&) {} - cb->tracker_response(tracker_request(), peer_list, interval, complete + cb->tracker_response(tracker_req(), peer_list, interval, complete , incomplete); } catch(type_error& e) { - cb->tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); + cb->tracker_request_error(tracker_req(), m_parser.status_code(), e.what()); } catch(std::runtime_error& e) { - cb->tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); + cb->tracker_request_error(tracker_req(), m_parser.status_code(), e.what()); } } diff --git a/src/torrent.cpp b/src/torrent.cpp index 43625e958..9fce96e43 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -492,6 +492,21 @@ namespace libtorrent #endif + void torrent::scrape_tracker() + { + if (m_trackers.empty()) return; + + TORRENT_ASSERT(m_currently_trying_tracker >= 0); + TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size())); + + tracker_request req; + req.info_hash = m_torrent_file->info_hash(); + req.kind = tracker_request::scrape_request; + req.url = m_trackers[m_currently_trying_tracker].url; + m_ses.m_tracker_manager.queue_request(m_ses.m_strand, m_ses.m_half_open, req + , tracker_login(), m_ses.m_listen_interface.address(), shared_from_this()); + } + // returns true if it is time for this torrent to make another // tracker request bool torrent::should_request() @@ -520,6 +535,26 @@ namespace libtorrent } } + void torrent::tracker_scrape_response(tracker_request const& req + , int complete, int incomplete, int downloaded) + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + + INVARIANT_CHECK; + TORRENT_ASSERT(req.kind == tracker_request::scrape_request); + + if (complete >= 0) m_complete = complete; + if (incomplete >= 0) m_incomplete = incomplete; + + if (m_ses.m_alerts.should_post(alert::info)) + { + std::stringstream s; + s << "Got scrape response from tracker: " << req.url; + m_ses.m_alerts.post_alert(scrape_reply_alert( + get_handle(), m_incomplete, m_complete, s.str())); + } + } + void torrent::tracker_response( tracker_request const& , std::vector& peer_list @@ -530,6 +565,7 @@ namespace libtorrent session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); INVARIANT_CHECK; + TORRENT_ASSERT(r.kind == tracker_request::announce_request); m_failed_trackers = 0; // announce intervals less than 5 minutes @@ -606,8 +642,7 @@ namespace libtorrent if (m_ses.m_alerts.should_post(alert::info)) { std::stringstream s; - s << "Got response from tracker: " - << m_trackers[m_last_working_tracker].url; + s << "Got response from tracker: " << r.url; m_ses.m_alerts.post_alert(tracker_reply_alert( get_handle(), peer_list.size(), s.str())); } @@ -2860,8 +2895,12 @@ namespace libtorrent torrent_status st; - st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end(), - !boost::bind(&peer_connection::is_connecting, _1)); + st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end() + , !boost::bind(&peer_connection::is_connecting, _1)); + + st.list_peers = std::distance(m_policy.begin_peer(), m_policy.end_peer()); + st.list_seeds = (int)std::count_if(m_policy.begin_peer(), m_policy.end_peer() + , boost::bind(&policy::peer::seed, bind(&policy::iterator::value_type::second, _1))); st.storage_mode = m_storage_mode; @@ -2992,7 +3031,7 @@ namespace libtorrent } void torrent::tracker_request_timed_out( - tracker_request const&) + tracker_request const& r) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -3005,19 +3044,26 @@ namespace libtorrent if (m_ses.m_alerts.should_post(alert::warning)) { std::stringstream s; - s << "tracker: \"" - << m_trackers[m_currently_trying_tracker].url - << "\" timed out"; - m_ses.m_alerts.post_alert(tracker_alert(get_handle() - , m_failed_trackers + 1, 0, s.str())); + s << "tracker: \"" << r.url << "\" timed out"; + if (r.kind == tracker_request::announce_request) + { + m_ses.m_alerts.post_alert(tracker_alert(get_handle() + , m_failed_trackers + 1, 0, s.str())); + } + else if (r.kind == tracker_request::scrape_request) + { + m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), s.str())); + } } - try_next_tracker(); + + if (r.kind == tracker_request::announce_request) + try_next_tracker(); } // TODO: with some response codes, we should just consider // the tracker as a failure and not retry // it anymore - void torrent::tracker_request_error(tracker_request const& + void torrent::tracker_request_error(tracker_request const& r , int response_code, const std::string& str) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -3030,14 +3076,20 @@ namespace libtorrent if (m_ses.m_alerts.should_post(alert::warning)) { std::stringstream s; - s << "tracker: \"" - << m_trackers[m_currently_trying_tracker].url - << "\" " << str; - m_ses.m_alerts.post_alert(tracker_alert(get_handle() - , m_failed_trackers + 1, response_code, s.str())); + s << "tracker: \"" << r.url << "\" " << str; + if (r.kind == tracker_request::announce_request) + { + m_ses.m_alerts.post_alert(tracker_alert(get_handle() + , m_failed_trackers + 1, response_code, s.str())); + } + else if (r.kind == tracker_request::scrape_request) + { + m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), s.str())); + } } - try_next_tracker(); + if (r.kind == tracker_request::announce_request) + try_next_tracker(); } diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index b19e05bb4..aa517ac76 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -863,6 +863,20 @@ namespace libtorrent t->force_tracker_request(); } + void torrent_handle::scrape_tracker() const + { + INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + TORRENT_ASSERT(m_chk); + + session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); + boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); + if (!t) throw_invalid_handle(); + + t->scrape_tracker(); + } + void torrent_handle::set_ratio(float ratio) const { INVARIANT_CHECK; diff --git a/src/tracker_manager.cpp b/src/tracker_manager.cpp index 82c5cc948..19da33d4b 100755 --- a/src/tracker_manager.cpp +++ b/src/tracker_manager.cpp @@ -359,7 +359,7 @@ namespace libtorrent tracker_connection::tracker_connection( tracker_manager& man - , tracker_request req + , tracker_request const& req , asio::strand& str , address bind_interface_ , boost::weak_ptr r) diff --git a/src/udp_tracker_connection.cpp b/src/udp_tracker_connection.cpp index 6d76988d3..eb138e67a 100755 --- a/src/udp_tracker_connection.cpp +++ b/src/udp_tracker_connection.cpp @@ -548,7 +548,7 @@ namespace libtorrent } int complete = detail::read_int32(buf); - /*int downloaded = */detail::read_int32(buf); + int downloaded = detail::read_int32(buf); int incomplete = detail::read_int32(buf); boost::shared_ptr cb = requester(); @@ -559,9 +559,8 @@ namespace libtorrent return; } - std::vector peer_list; - cb->tracker_response(tracker_req(), peer_list, 0 - , complete, incomplete); + cb->tracker_scrape_response(tracker_req() + , complete, incomplete, downloaded); m_man.remove_request(this); close();