From 2406d5e54dbd113b537453808f66aec462c2b546 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 12 Sep 2004 13:53:00 +0000 Subject: [PATCH] *** empty log message *** --- examples/client_test.cpp | 2 +- include/libtorrent/peer_connection.hpp | 10 +- include/libtorrent/torrent.hpp | 5 + src/http_tracker_connection.cpp | 3 +- src/peer_connection.cpp | 68 +++++++++----- src/storage.cpp | 7 +- src/torrent.cpp | 121 ++++++++++++++++++++----- 7 files changed, 164 insertions(+), 52 deletions(-) diff --git a/examples/client_test.cpp b/examples/client_test.cpp index df241f5cc..a937f67fe 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -55,7 +55,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/identify_client.hpp" #include "libtorrent/alert_types.hpp" -#ifdef WIN32 +#ifdef _WIN32 #if defined(_MSC_VER) # define for if (false) {} else for diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 800760ab0..7c65c0743 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -224,6 +224,8 @@ namespace libtorrent bool supports_extension(extension_index ex) const { return m_extension_messages[ex] != -1; } + bool has_metadata() const; + // the message handlers are called // each time a recv() returns some new // data, the last time it will be called @@ -264,8 +266,8 @@ namespace libtorrent void send_handshake(); void send_extensions(); void send_chat_message(const std::string& msg); - void send_metadata(int start, int size); - void send_metadata_request(int start, int size); + void send_metadata(std::pair req); + void send_metadata_request(std::pair req); // how much bandwidth we're using, how much we want, // and how much we are allowed to use. @@ -511,6 +513,10 @@ namespace libtorrent // request to this peer, and reset to false when // we receive a reply to our request. bool m_waiting_metadata_request; + + // if we're waiting for a metadata request + // this was the request we sent + std::pair m_last_metadata_request; }; } diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index df8a1be2d..99dce9372 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -79,6 +79,10 @@ namespace libtorrent struct piece_checker_data; } + int div_round_up(int numerator, int denominator); + std::pair req_to_offset(std::pair req, int total_size); + std::pair offset_to_req(std::pair offset, int total_size); + // a torrent is a class that holds information // for a specific download. It updates itself against // the tracker @@ -344,6 +348,7 @@ namespace libtorrent // returns a range of the metadata that // we should request. std::pair metadata_request(); + void cancel_metadata_request(std::pair req); private: diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 4a91b9d97..419fceb16 100755 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -161,7 +161,8 @@ namespace libtorrent m_send_buffer += key_string.str(); m_send_buffer += "&compact=1"; m_send_buffer += "&numwant="; - m_send_buffer += boost::lexical_cast(req.num_want); + m_send_buffer += boost::lexical_cast( + std::min(req.num_want, 999)); // extension that tells the tracker that // we don't need any peer_id's in the response diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 219a0c0e0..83719b154 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -1205,7 +1205,7 @@ namespace libtorrent throw protocol_error("invalid metadata request"); } - send_metadata(start, size); + send_metadata(std::make_pair(start, size)); } break; case 1: // data @@ -1221,12 +1221,22 @@ namespace libtorrent if (offset + data_size > total_size) throw protocol_error("invalid metadata message"); +#ifndef NDEBUG + using namespace boost::posix_time; + (*m_logger) << to_simple_string(second_clock::local_time()) + << " <== METADATA [ tot: " << total_size << " offset: " + << offset << " size: " << data_size << " ]\n"; +#endif + + m_waiting_metadata_request = false; m_torrent->received_metadata(&m_recv_buffer[5+9], data_size, offset, total_size); } break; case 2: // have no data m_no_metadata = boost::posix_time::second_clock::local_time(); + if (m_waiting_metadata_request) + m_torrent->cancel_metadata_request(m_last_metadata_request); m_waiting_metadata_request = false; break; } @@ -1276,6 +1286,12 @@ namespace libtorrent m_torrent->get_policy().peer_from_tracker(adr, m_peer_id); } + bool peer_connection::has_metadata() const + { + using namespace boost::posix_time; + return second_clock::local_time() - m_no_metadata > minutes(5); + } + void peer_connection::disconnect() { @@ -1427,11 +1443,12 @@ namespace libtorrent send_buffer_updated(); } - void peer_connection::send_metadata(int start, int size) + void peer_connection::send_metadata(std::pair req) { - assert(start >= 0); - assert(size > 0); - assert(start + size <= 256); + assert(req.first >= 0); + assert(req.second > 0); + assert(req.second <= 256); + assert(req.first + req.second <= 256); assert(m_torrent); INVARIANT_CHECK; @@ -1442,21 +1459,20 @@ namespace libtorrent if (m_torrent->valid_metadata()) { - int offset = start * (int)m_torrent->metadata().size() / 256; - int metadata_size - = (start + size) * (int)m_torrent->metadata().size() / 256 - offset; + std::pair offset + = req_to_offset(req, (int)m_torrent->metadata().size()); // yes, we have metadata, send it - assert(size <= (int)m_torrent->metadata().size()); - detail::write_uint32(5 + 9 + metadata_size, ptr); + detail::write_uint32(5 + 9 + offset.second, ptr); detail::write_uint8(msg_extended, ptr); detail::write_int32(m_extension_messages[extended_metadata_message], ptr); // means 'data packet' detail::write_uint8(1, ptr); detail::write_uint32((int)m_torrent->metadata().size(), ptr); - detail::write_uint32(offset, ptr); + detail::write_uint32(offset.first, ptr); std::vector const& metadata = m_torrent->metadata(); - std::copy(&metadata[offset], &metadata[offset + metadata_size], ptr); + std::copy(&metadata[offset.first], &metadata[offset.first + + offset.second], ptr); } else { @@ -1471,18 +1487,28 @@ namespace libtorrent send_buffer_updated(); } - void peer_connection::send_metadata_request(int start, int size) + void peer_connection::send_metadata_request(std::pair req) { - assert(start >= 0); - assert(size > 0); - assert(start + size <= 256); + assert(req.first >= 0); + assert(req.second > 0); + assert(req.first + req.second <= 256); assert(m_torrent); assert(!m_torrent->valid_metadata()); INVARIANT_CHECK; + int start = req.first; + int size = req.second; + // abort if the peer doesn't support the metadata extension if (!supports_extension(extended_metadata_message)) return; + #ifndef NDEBUG + using namespace boost::posix_time; + (*m_logger) << to_simple_string(second_clock::local_time()) + << " ==> METADATA_REQUEST [ start: " << req.first + << " size: " << req.second << " ]\n"; + #endif + std::back_insert_iterator > ptr(m_send_buffer); detail::write_uint32(1 + 4 + 3, ptr); @@ -1690,19 +1716,19 @@ namespace libtorrent // if we don't have any metadata, and this peer // supports the request metadata extension // and we aren't currently waiting for a request - // reply. + // reply. Then, send a request for some metadata. if (!m_torrent->valid_metadata() && supports_extension(extended_metadata_message) - && !m_waiting_metadata_request) + && !m_waiting_metadata_request + && has_metadata()) { assert(m_torrent); - std::pair req = m_torrent->metadata_request(); - send_metadata_request(req.first, req.second); + m_last_metadata_request = m_torrent->metadata_request(); + send_metadata_request(m_last_metadata_request); m_waiting_metadata_request = true; m_metadata_request = boost::posix_time::second_clock::local_time(); } - m_statistics.second_tick(); m_ul_bandwidth_quota.used = std::min( (int)ceil(statistics().upload_rate()) diff --git a/src/storage.cpp b/src/storage.cpp index 989e26958..4d35337a3 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -995,12 +995,11 @@ namespace libtorrent // first, create all missing directories for (torrent_info::file_iterator file_iter = m_info.begin_files(), - end_iter = m_info.end_files(); - file_iter != end_iter; - ++file_iter) + end_iter = m_info.end_files(); file_iter != end_iter; ++file_iter) { fs::path dir = m_save_path / get_filename(m_info, file_iter->path); - fs::create_directories(dir.branch_path()); + if (!fs::exists(dir.branch_path())) + fs::create_directories(dir.branch_path()); } std::vector piece_data(static_cast(m_info.piece_length())); diff --git a/src/torrent.cpp b/src/torrent.cpp index 07e4430a2..9963915b7 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -501,7 +501,7 @@ namespace libtorrent assert(!urls.empty()); m_trackers = urls; if (m_currently_trying_tracker >= (int)m_trackers.size()) - m_currently_trying_tracker = m_trackers.size()-1; + m_currently_trying_tracker = (int)m_trackers.size()-1; m_last_working_tracker = -1; } @@ -982,6 +982,43 @@ namespace libtorrent boost::bind(&std::map::value_type::second, _1))); } + int div_round_up(int numerator, int denominator) + { + return (numerator + denominator - 1) / denominator; + } + + std::pair req_to_offset(std::pair req, int total_size) + { + assert(req.first >= 0); + assert(req.second > 0); + assert(req.second <= 256); + assert(req.first + req.second <= 256); + + int start = div_round_up(req.first * total_size, 256); + int size = div_round_up((req.first + req.second) * total_size, 256) - start; + return std::make_pair(start, size); + } + + std::pair offset_to_req(std::pair offset, int total_size) + { + int start = offset.first * 256 / total_size; + int size = (offset.first + offset.second) * 256 / total_size - start; + + std::pair ret(start, size); + + assert(start >= 0); + assert(size > 0); + assert(start <= 256); + assert(start + size <= 256); + + // assert the identity of this function +#ifndef NDEBUG + std::pair identity = req_to_offset(ret, total_size); + assert(offset == identity); +#endif + return ret; + } + bool torrent::received_metadata(char const* buf, int size, int offset, int total_size) { INVARIANT_CHECK; @@ -997,28 +1034,19 @@ namespace libtorrent , &m_metadata[offset]); if (m_have_metadata.empty()) - m_have_metadata.resize(255, false); + m_have_metadata.resize(256, false); - int start = offset * 255 / (int)m_metadata.size(); - if ((offset * 255) % (int)m_metadata.size() != 0) - throw protocol_error("unaligned metadata message offset"); - - int block_size = size * (255 - offset) / (int)m_metadata.size() - start; - - assert(start >= 0); - assert(block_size > 0); - assert(start < 256); - assert(start + block_size <= 256); + std::pair req = offset_to_req(std::make_pair(offset, size), total_size); std::fill( - m_have_metadata.begin() + start - , m_have_metadata.begin() + start + block_size + m_have_metadata.begin() + req.first + , m_have_metadata.begin() + req.first + req.second , true); bool have_all = std::count( m_have_metadata.begin() , m_have_metadata.end() - , true) == 255; + , true) == 256; if (!have_all) return false; @@ -1030,7 +1058,7 @@ namespace libtorrent { std::fill( m_have_metadata.begin() - , m_have_metadata.end() + start + block_size + , m_have_metadata.end() + req.first + req.second , false); return false; } @@ -1055,8 +1083,9 @@ namespace libtorrent // all peer connections have to initialize themselves now that the metadata // is available - for (std::map::iterator i = m_connections.begin(); - i != m_connections.end(); ++i) + typedef std::map conn_map; + for (conn_map::iterator i = m_connections.begin() + , end(m_connections.end()); i != end; ++i) { i->second->init(); } @@ -1074,17 +1103,63 @@ namespace libtorrent std::pair torrent::metadata_request() { - // TODO: count the peers that supports the - // metadata extension - // check to see if we know how big the metadata - // is (if m_metadata.size() > 0) - std::pair ret(0, 256); + // count the number of peers that supports the + // extension and that has metadata + int peers = 0; + typedef std::map conn_map; + for (conn_map::iterator i = m_connections.begin() + , end(m_connections.end()); i != end; ++i) + { + if (!i->second->supports_extension( + peer_connection::extended_metadata_message)) + continue; + if (!i->second->has_metadata()) + continue; + ++peers; + } + // the number of blocks to request + int num_blocks = 256 / (peers + 1); + if (num_blocks < 1) num_blocks = 1; + assert(num_blocks <= 128); + + int min_element = std::numeric_limits::max(); + int best_index = 0; + for (int i = 0; i < 256 - num_blocks + 1; ++i) + { + int min = *std::min_element(m_requested_metadata.begin() + i + , m_requested_metadata.begin() + i + num_blocks); + min += std::accumulate(m_requested_metadata.begin() + i + , m_requested_metadata.begin() + i + num_blocks, (int)0); + + if (min_element > min) + { + best_index = i; + min_element = min; + } + } + + std::pair ret(best_index, num_blocks); for (int i = ret.first; i < ret.first + ret.second; ++i) m_requested_metadata[i]++; + + assert(ret.first >= 0); + assert(ret.second > 0); + assert(ret.second <= 256); + assert(ret.first + ret.second <= 256); + return ret; } + void torrent::cancel_metadata_request(std::pair req) + { + for (int i = req.first; i < req.first + req.second; ++i) + { + assert(m_requested_metadata[i] > 0); + --m_requested_metadata[i]; + } + } + void torrent::tracker_request_timed_out() { #ifndef NDEBUG