diff --git a/ChangeLog b/ChangeLog index f20286710..70c415bbc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -106,7 +106,7 @@ * improved LSD performance and made the interval configurable * improved UDP tracker support by caching connect tokens * fast piece optimization - * fixed error handling with torrents with invalid piece sizes + * added support for torrents with odd piece sizes * fixed issue with disk read cache not being cleared when removing torrents release 0.14.9 diff --git a/docs/manual.rst b/docs/manual.rst index 35d87c8f4..b36db463b 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -6275,8 +6275,7 @@ code symbol description ------ ----------------------------------------- ----------------------------------------------------------------- 81 packet_too_large The packet size exceeded the upper sanity check-limit ------ ----------------------------------------- ----------------------------------------------------------------- -82 torrent_invalid_piece_size The .torrent file has an invalid piece size. It needs to be an - even 16 kiB multiple +82 reserved ------ ----------------------------------------- ----------------------------------------------------------------- 83 http_error The web server responded with an error ------ ----------------------------------------- ----------------------------------------------------------------- diff --git a/include/libtorrent/error_code.hpp b/include/libtorrent/error_code.hpp index 16a29b2f4..3ca781803 100644 --- a/include/libtorrent/error_code.hpp +++ b/include/libtorrent/error_code.hpp @@ -139,7 +139,7 @@ namespace libtorrent duplicate_peer_id, torrent_removed, packet_too_large, - torrent_invalid_piece_size, + reserved, http_error, missing_location, invalid_redirection, diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index f08d1b743..38d2d62c6 100644 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -192,7 +192,7 @@ namespace libtorrent int sparse_regions() const { return m_sparse_regions; } // sets all pieces to dont-have - void init(int blocks_per_piece, int total_num_blocks); + void init(int blocks_per_piece, int blocks_in_last_piece, int total_num_pieces); int num_pieces() const { return int(m_piece_map.size()); } bool have_piece(int index) const diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 22f04b8ff..d5f36aadd 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -559,7 +559,7 @@ namespace libtorrent } int block_size() const { TORRENT_ASSERT(m_block_size_shift > 0); return 1 << m_block_size_shift; } - peer_request to_req(piece_block const& p); + peer_request to_req(piece_block const& p) const; void disconnect_all(error_code const& ec); int disconnect_peers(int num); diff --git a/src/error_code.cpp b/src/error_code.cpp index a066b33d8..00584ffe4 100644 --- a/src/error_code.cpp +++ b/src/error_code.cpp @@ -130,7 +130,7 @@ namespace libtorrent "duplicate peer-id", "torrent removed", "packet too large", - "invalid piece size in torrent file", + "", "HTTP error", "missing location header", "invalid redirection", diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index e53a7d309..cbf7848e5 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -1037,19 +1037,10 @@ namespace libtorrent torrent_info const& ti = t->torrent_file(); return p.piece >= 0 - && p.piece < t->torrent_file().num_pieces() - && p.length >= 0 + && p.piece < ti.num_pieces() && p.start >= 0 - && (p.length == t->block_size() - || (p.length < t->block_size() - && p.piece == ti.num_pieces()-1 - && p.start + p.length == ti.piece_size(p.piece)) - || (m_request_large_blocks - && p.length <= ti.piece_length() * (m_prefer_whole_pieces == 0 ? - 1 : m_prefer_whole_pieces))) - && p.piece * size_type(ti.piece_length()) + p.start + p.length - <= ti.total_size() - && (p.start % t->block_size() == 0); + && p.start < ti.piece_length() + && t->to_req(piece_block(p.piece, p.start / t->block_size())) == p; } void peer_connection::attach_to_torrent(sha1_hash const& ih) @@ -2088,7 +2079,7 @@ namespace libtorrent if (!t->is_seed()) { const int blocks_per_piece = static_cast( - t->torrent_file().piece_length() / t->block_size()); + (t->torrent_file().piece_length() + t->block_size() - 1) / t->block_size()); std::vector const& dl_queue = t->picker().get_download_queue(); @@ -2216,9 +2207,7 @@ namespace libtorrent std::vector finished_blocks; piece_block block_finished(p.piece, p.start / t->block_size()); - TORRENT_ASSERT(p.start % t->block_size() == 0); - TORRENT_ASSERT(p.length == t->block_size() - || p.length == t->torrent_file().total_size() % t->block_size()); + TORRENT_ASSERT(verify_piece(p)); std::vector::iterator b = std::find_if( @@ -4967,13 +4956,9 @@ namespace libtorrent in_download_queue = true; outstanding_bytes += p->full_block_bytes - m_received_in_piece; } - else if (i->block == last_block) - { - outstanding_bytes += last_block_size; - } else { - outstanding_bytes += block_size; + outstanding_bytes += t->to_req(i->block).length; } } //if (p && p->bytes_downloaded < p->full_block_bytes) TORRENT_ASSERT(in_download_queue); diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index 6f9b11b61..f393dd71f 100644 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -76,18 +76,17 @@ namespace libtorrent #endif } - void piece_picker::init(int blocks_per_piece, int total_num_blocks) + void piece_picker::init(int blocks_per_piece, int blocks_in_last_piece, int total_num_pieces) { TORRENT_ASSERT(blocks_per_piece > 0); - TORRENT_ASSERT(total_num_blocks >= 0); + TORRENT_ASSERT(total_num_pieces > 0); #ifdef TORRENT_PICKER_LOG std::cerr << "piece_picker::init()" << std::endl; #endif // allocate the piece_map to cover all pieces // and make them invalid (as if we don't have a single piece) - m_piece_map.resize((total_num_blocks + blocks_per_piece-1) / blocks_per_piece - , piece_pos(0, 0)); + m_piece_map.resize(total_num_pieces, piece_pos(0, 0)); m_reverse_cursor = int(m_piece_map.size()); m_cursor = 0; @@ -118,7 +117,7 @@ namespace libtorrent TORRENT_ASSERT(m_piece_map.size() < piece_pos::we_have_index); m_blocks_per_piece = blocks_per_piece; - m_blocks_in_last_piece = total_num_blocks % blocks_per_piece; + m_blocks_in_last_piece = blocks_in_last_piece; if (m_blocks_in_last_piece == 0) m_blocks_in_last_piece = blocks_per_piece; TORRENT_ASSERT(m_blocks_in_last_piece <= m_blocks_per_piece); diff --git a/src/torrent.cpp b/src/torrent.cpp index 84985213b..b5d420637 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -744,7 +744,7 @@ namespace libtorrent return m_torrent_file->add_merkle_nodes(nodes, piece); } - peer_request torrent::to_req(piece_block const& p) + peer_request torrent::to_req(piece_block const& p) const { int block_offset = p.block_index * block_size(); int block = (std::min)(torrent_file().piece_size( @@ -817,14 +817,6 @@ namespace libtorrent return; } - if (m_torrent_file->piece_length() % block_size() != 0) - { - // TODO: try to adjust the block size - set_error(errors::torrent_invalid_piece_size, ""); - pause(); - return; - } - // the shared_from_this() will create an intentional // cycle of ownership, se the hpp file for description. m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file @@ -834,8 +826,10 @@ namespace libtorrent if (has_picker()) { - m_picker->init((std::max)(m_torrent_file->piece_length() / block_size(), 1) - , int((m_torrent_file->total_size()+block_size()-1) / block_size())); + int blocks_per_piece = (m_torrent_file->piece_length() + block_size() - 1) / block_size(); + int blocks_in_last_piece = ((m_torrent_file->total_size() % m_torrent_file->piece_length()) + + block_size() - 1) / block_size(); + m_picker->init(blocks_per_piece, blocks_in_last_piece, m_torrent_file->num_pieces()); } std::vector const& url_seeds = m_torrent_file->url_seeds(); @@ -1153,8 +1147,11 @@ namespace libtorrent m_owning_storage->async_release_files(); if (!m_picker) m_picker.reset(new piece_picker()); std::fill(m_file_progress.begin(), m_file_progress.end(), 0); - m_picker->init(m_torrent_file->piece_length() / block_size() - , int((m_torrent_file->total_size() + block_size()-1)/block_size())); + + int blocks_per_piece = (m_torrent_file->piece_length() + block_size() - 1) / block_size(); + int blocks_in_last_piece = ((m_torrent_file->total_size() % m_torrent_file->piece_length()) + + block_size() - 1) / block_size(); + m_picker->init(blocks_per_piece, blocks_in_last_piece, m_torrent_file->num_pieces()); // assume that we don't have anything TORRENT_ASSERT(m_picker->num_have() == 0); m_files_checked = false; @@ -1972,11 +1969,8 @@ namespace libtorrent } #ifdef TORRENT_DEBUG TORRENT_ASSERT(p->bytes_downloaded <= p->full_block_bytes); - if (p->piece_index == last_piece_index - && p->block_index == m_torrent_file->piece_size(last_piece) / block_size()) - TORRENT_ASSERT(p->full_block_bytes == m_torrent_file->piece_size(last_piece) % block_size()); - else - TORRENT_ASSERT(p->full_block_bytes == block_size()); + TORRENT_ASSERT(p->full_block_bytes == to_req(piece_block( + p->piece_index, p->block_index)).length); #endif } for (std::map::iterator i = downloading_piece.begin(); @@ -4856,7 +4850,6 @@ namespace libtorrent if (m_files_checked && valid_metadata()) { TORRENT_ASSERT(block_size() > 0); - TORRENT_ASSERT((m_torrent_file->piece_length() & (block_size()-1)) == 0); } // if (is_seed()) TORRENT_ASSERT(m_picker.get() == 0);