From 6cb4d27b7ee74c6003473565dd7fc7ec02aab38a Mon Sep 17 00:00:00 2001 From: Andrew Resch Date: Mon, 23 Jun 2008 22:58:46 +0000 Subject: [PATCH] lt sync 2453 --- libtorrent/include/libtorrent/bencode.hpp | 18 +- libtorrent/include/libtorrent/torrent.hpp | 20 +- libtorrent/src/http_tracker_connection.cpp | 6 - libtorrent/src/kademlia/dht_tracker.cpp | 9 + libtorrent/src/peer_connection.cpp | 11 ++ libtorrent/src/piece_picker.cpp | 7 +- libtorrent/src/storage.cpp | 41 ++++- libtorrent/src/torrent.cpp | 201 ++++++++++++--------- libtorrent/src/ut_metadata.cpp | 9 +- libtorrent/src/ut_pex.cpp | 7 +- 10 files changed, 207 insertions(+), 122 deletions(-) diff --git a/libtorrent/include/libtorrent/bencode.hpp b/libtorrent/include/libtorrent/bencode.hpp index bd77aa104..9443e7a65 100755 --- a/libtorrent/include/libtorrent/bencode.hpp +++ b/libtorrent/include/libtorrent/bencode.hpp @@ -394,14 +394,7 @@ namespace libtorrent bool err = false; detail::bdecode_recursive(start, end, e, err, 0); TORRENT_ASSERT(e.m_type_queried == false); - if (err) - { -#ifdef BOOST_NO_EXCEPTIONS - return entry(); -#else - throw invalid_encoding(); -#endif - } + if (err) return entry(); return e; } @@ -414,14 +407,7 @@ namespace libtorrent detail::bdecode_recursive(start, end, e, err, 0); len = std::distance(s, start); TORRENT_ASSERT(len >= 0); - if (err) - { -#ifdef BOOST_NO_EXCEPTIONS - return entry(); -#else - throw invalid_encoding(); -#endif - } + if (err) return entry(); return e; } } diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index 7f1e5f944..c0ddb798a 100755 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -459,11 +459,6 @@ namespace libtorrent int block_size() const { TORRENT_ASSERT(m_block_size > 0); return m_block_size; } peer_request to_req(piece_block const& p); - // this will tell all peers that we just got his piece - // and also let the piece picker know that we have this piece - // so it wont pick it for download - void announce_piece(int index); - void disconnect_all(); int disconnect_peers(int num); @@ -504,7 +499,22 @@ namespace libtorrent // each time a piece has failed the hash // test void piece_finished(int index, int passed_hash_check); + + // piece_passed is called when a piece passes the hash check + // this will tell all peers that we just got his piece + // and also let the piece picker know that we have this piece + // so it wont pick it for download + void piece_passed(int index); + + // piece_failed is called when a piece fails the hash check void piece_failed(int index); + + // this will restore the piece picker state for a piece + // by re marking all the requests to blocks in this piece + // that are still outstanding in peers' download queues. + // this is done when a piece fails + void restore_piece_state(int index); + void received_redundant_data(int num_bytes) { TORRENT_ASSERT(num_bytes > 0); m_total_redundant_bytes += num_bytes; } diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp index df0715ca6..b87ee0a28 100755 --- a/libtorrent/src/http_tracker_connection.cpp +++ b/libtorrent/src/http_tracker_connection.cpp @@ -226,13 +226,7 @@ namespace libtorrent // handle tracker response entry e; -#ifndef BOOST_NO_EXCEPTIONS - try { -#endif e = bdecode(data, data + size); -#ifndef BOOST_NO_EXCEPTIONS - } catch (std::exception&) {} -#endif if (e.type() != entry::undefined_t) { diff --git a/libtorrent/src/kademlia/dht_tracker.cpp b/libtorrent/src/kademlia/dht_tracker.cpp index 461ea9da6..4c781b9e7 100644 --- a/libtorrent/src/kademlia/dht_tracker.cpp +++ b/libtorrent/src/kademlia/dht_tracker.cpp @@ -444,6 +444,15 @@ namespace libtorrent { namespace dht TORRENT_ASSERT(bytes_transferred > 0); entry e = bdecode(buf, buf + bytes_transferred); + if (e.type() == entry::undefined_t) + { +#ifdef TORRENT_DHT_VERBOSE_LOGGING + std::string msg(buf, buf + bytes_transferred); + TORRENT_LOG(dht_tracker) << "invalid incoming packet: " + << e.what() << "\n" << msg << "\n"; +#endif + return; + } #ifdef TORRENT_DHT_VERBOSE_LOGGING std::stringstream log_line; diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index ad0ce2a14..0b842a8f3 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -53,6 +53,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket_type.hpp" #include "libtorrent/assert.hpp" +//#define TORRENT_CORRUPT_DATA + using boost::bind; using boost::shared_ptr; using libtorrent::aux::session_impl; @@ -1447,6 +1449,15 @@ namespace libtorrent TORRENT_ASSERT(!m_disk_recv_buffer); TORRENT_ASSERT(m_disk_recv_buffer_size == 0); +#ifdef TORRENT_CORRUPT_DATA + // corrupt all pieces from certain peers + if (m_remote.address().is_v4() + && (m_remote.address().to_v4().to_ulong() & 0xf) == 0) + { + data.get()[0] = ~data.get()[0]; + } +#endif + #ifndef TORRENT_DISABLE_EXTENSIONS for (extension_list_t::iterator i = m_extensions.begin() , end(m_extensions.end()); i != end; ++i) diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index 2fbe94c96..9e62e6379 100755 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -1775,18 +1775,13 @@ namespace libtorrent TORRENT_ASSERT(block.piece_index < (int)m_piece_map.size()); TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index)); - // this might be the case if a piece fails, is restored, and then - // completed from a different peer (from which the piece was requested - // before it failed the hash check) - if (m_piece_map[block.piece_index].downloading == 0) - mark_as_downloading(block, peer, piece_picker::none); - TORRENT_ASSERT(m_piece_map[block.piece_index].downloading); std::vector::iterator i = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); TORRENT_ASSERT(i != m_downloads.end()); block_info& info = i->info[block.block_index]; + info.peer = peer; TORRENT_ASSERT(info.state == block_info::state_requested); if (info.state == block_info::state_requested) --i->requested; diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index 1c16a866d..af71fcfaf 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -1445,6 +1445,9 @@ namespace libtorrent slots.push_back((*i >= 0) ? *i : unassigned); } } + + rd["allocation"] = m_storage_mode == storage_mode_sparse?"sparse" + :m_storage_mode == storage_mode_allocate?"full":"compact"; } void piece_manager::mark_failed(int piece_index) @@ -1838,7 +1841,7 @@ namespace libtorrent return check_no_fastresume(error); } - if (storage_mode == storage_mode_compact) + if (m_storage_mode == storage_mode_compact) { int num_pieces = int(m_files.num_pieces()); m_slot_to_piece.resize(num_pieces, unallocated); @@ -1931,6 +1934,42 @@ namespace libtorrent } } + else if (m_storage_mode == storage_mode_compact) + { + // read piece map + entry const* pieces = rd.find_key("pieces"); + if (pieces == 0 || pieces->type() != entry::string_t) + { + error = "missing pieces entry"; + return check_no_fastresume(error); + } + + if ((int)pieces->string().size() != m_files.num_pieces()) + { + error = "file has more slots than torrent (slots: " + + boost::lexical_cast(pieces->string().size()) + " size: " + + boost::lexical_cast(m_files.num_pieces()) + " )"; + return check_no_fastresume(error); + } + + int num_pieces = int(m_files.num_pieces()); + m_slot_to_piece.resize(num_pieces, unallocated); + m_piece_to_slot.resize(num_pieces, has_no_slot); + std::string const& have_pieces = pieces->string(); + for (int i = 0; i < num_pieces; ++i) + { + if (have_pieces[i] & 1) + { + m_slot_to_piece[i] = i; + m_piece_to_slot[i] = i; + } + else + { + m_free_slots.push_back(i); + } + } + if (m_unallocated_slots.empty()) switch_to_full_mode(); + } return check_init_storage(error); } diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 2a78a23d0..1bef95c6d 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -1238,47 +1238,13 @@ namespace libtorrent ?"disk failed":"failed") << " ]\n"; #endif - bool was_finished = m_picker->num_filtered() + num_have() - == torrent_file().num_pieces(); + TORRENT_ASSERT(valid_metadata()); if (passed_hash_check == 0) { - if (m_ses.m_alerts.should_post(alert::debug)) - { - m_ses.m_alerts.post_alert(piece_finished_alert(get_handle() - , index, "piece finished")); - } // the following call may cause picker to become invalid // in case we just became a seed - announce_piece(index); - TORRENT_ASSERT(valid_metadata()); - // if we just became a seed, picker is now invalid, since it - // is deallocated by the torrent once it starts seeding - - // since this piece just passed, we might have - // become uninterested in some peers where this - // was the last piece we were interested in - for (peer_iterator i = m_connections.begin() - , end(m_connections.end()); i != end; ++i) - { - peer_connection* p = *i; - // if we're not interested already, no need to check - if (!p->is_interesting()) continue; - // if the peer doesn't have the piece we just got, it - // wouldn't affect our interest - if (!p->has_piece(index)) continue; - p->update_interest(); - } - - if (!was_finished&& is_finished()) - { - TORRENT_ASSERT(passed_hash_check == 0); - // torrent finished - // i.e. all the pieces we're interested in have - // been downloaded. Release the files (they will open - // in read only mode if needed) - finished(); - } + piece_passed(index); } else if (passed_hash_check == -2) { @@ -1289,6 +1255,88 @@ namespace libtorrent { TORRENT_ASSERT(passed_hash_check == -1); m_picker->restore_piece(index); + restore_piece_state(index); + } + } + + void torrent::piece_passed(int index) + { +// INVARIANT_CHECK; + + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < m_torrent_file->num_pieces()); + + if (m_ses.m_alerts.should_post(alert::debug)) + { + m_ses.m_alerts.post_alert(piece_finished_alert(get_handle() + , index, "piece finished")); + } + + bool was_finished = m_picker->num_filtered() + num_have() + == torrent_file().num_pieces(); + + std::vector downloaders; + m_picker->get_downloaders(downloaders, index); + + // increase the trust point of all peers that sent + // parts of this piece. + std::set peers; + std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin())); + + m_picker->we_have(index); + for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i) + (*i)->announce_piece(index); + + for (std::set::iterator i = peers.begin() + , end(peers.end()); i != end; ++i) + { + policy::peer* p = static_cast(*i); + if (p == 0) continue; + p->on_parole = false; + ++p->trust_points; + // TODO: make this limit user settable + if (p->trust_points > 20) p->trust_points = 20; + if (p->connection) p->connection->received_valid_data(index); + } + +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { +#ifndef BOOST_NO_EXCEPTIONS + try { +#endif + (*i)->on_piece_pass(index); +#ifndef BOOST_NO_EXCEPTIONS + } catch (std::exception&) {} +#endif + } +#endif + + // since this piece just passed, we might have + // become uninterested in some peers where this + // was the last piece we were interested in + for (peer_iterator i = m_connections.begin() + , end(m_connections.end()); i != end; ++i) + { + peer_connection* p = *i; + // if we're not interested already, no need to check + if (!p->is_interesting()) continue; + // if the peer doesn't have the piece we just got, it + // wouldn't affect our interest + if (!p->has_piece(index)) continue; + p->update_interest(); + } + + if (!was_finished && is_finished()) + { + // torrent finished + // i.e. all the pieces we're interested in have + // been downloaded. Release the files (they will open + // in read only mode if needed) + finished(); + // if we just became a seed, picker is now invalid, since it + // is deallocated by the torrent once it starts seeding } } @@ -1402,6 +1450,7 @@ namespace libtorrent // start with redownloading the pieces that the client // that has sent the least number of pieces m_picker->restore_piece(index); + restore_piece_state(index); TORRENT_ASSERT(m_storage); TORRENT_ASSERT(m_picker->have_piece(index) == false); @@ -1419,6 +1468,32 @@ namespace libtorrent #endif } + void torrent::restore_piece_state(int index) + { + TORRENT_ASSERT(has_picker()); + for (peer_iterator i = m_connections.begin(); + i != m_connections.end(); ++i) + { + peer_connection* p = *i; + std::deque const& dq = p->download_queue(); + std::deque const& rq = p->request_queue(); + for (std::deque::const_iterator k = dq.begin() + , end(dq.end()); k != end; ++k) + { + if (k->piece_index != index) continue; + m_picker->mark_as_downloading(*k, p->peer_info_struct() + , (piece_picker::piece_state_t)p->peer_speed()); + } + for (std::deque::const_iterator k = rq.begin() + , end(rq.end()); k != end; ++k) + { + if (k->piece_index != index) continue; + m_picker->mark_as_downloading(*k, p->peer_info_struct() + , (piece_picker::piece_state_t)p->peer_speed()); + } + } + } + void torrent::abort() { INVARIANT_CHECK; @@ -1525,52 +1600,6 @@ namespace libtorrent } } - void torrent::announce_piece(int index) - { -// INVARIANT_CHECK; - - TORRENT_ASSERT(index >= 0); - TORRENT_ASSERT(index < m_torrent_file->num_pieces()); - - std::vector downloaders; - m_picker->get_downloaders(downloaders, index); - - // increase the trust point of all peers that sent - // parts of this piece. - std::set peers; - std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin())); - - m_picker->we_have(index); - for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i) - (*i)->announce_piece(index); - - for (std::set::iterator i = peers.begin() - , end(peers.end()); i != end; ++i) - { - policy::peer* p = static_cast(*i); - if (p == 0) continue; - p->on_parole = false; - ++p->trust_points; - // TODO: make this limit user settable - if (p->trust_points > 20) p->trust_points = 20; - if (p->connection) p->connection->received_valid_data(index); - } - -#ifndef TORRENT_DISABLE_EXTENSIONS - for (extension_list_t::iterator i = m_extensions.begin() - , end(m_extensions.end()); i != end; ++i) - { -#ifndef BOOST_NO_EXCEPTIONS - try { -#endif - (*i)->on_piece_pass(index); -#ifndef BOOST_NO_EXCEPTIONS - } catch (std::exception&) {} -#endif - } -#endif - } - std::string torrent::tracker_login() const { if (m_username.empty() && m_password.empty()) return ""; @@ -2433,9 +2462,6 @@ namespace libtorrent ret["num_seeds"] = seeds; ret["num_downloaders"] = downloaders; - ret["allocation"] = m_storage_mode == storage_mode_sparse?"sparse" - :m_storage_mode == storage_mode_allocate?"full":"compact"; - const sha1_hash& info_hash = torrent_file().info_hash(); ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end()); @@ -3175,6 +3201,11 @@ namespace libtorrent { if (m_sequential_download) picker().sequential_download(m_sequential_download); + + // if we just finished checking and we're not a seed, we are + // likely to be unpaused + if (m_ses.m_auto_manage_time_scaler > 1) + m_ses.m_auto_manage_time_scaler = 1; } #ifndef TORRENT_DISABLE_EXTENSIONS diff --git a/libtorrent/src/ut_metadata.cpp b/libtorrent/src/ut_metadata.cpp index f92fa88d4..0a1f139d7 100644 --- a/libtorrent/src/ut_metadata.cpp +++ b/libtorrent/src/ut_metadata.cpp @@ -306,7 +306,7 @@ namespace libtorrent { namespace if (length > 17 * 1024) { - m_pc.disconnect("ut_metadata message larger than 17 kB"); + m_pc.disconnect("ut_metadata message larger than 17 kB", 2); return true; } @@ -314,6 +314,11 @@ namespace libtorrent { namespace int len; entry msg = bdecode(body.begin, body.end, len); + if (msg.type() == entry::undefined_t) + { + m_pc.disconnect("invalid bencoding in ut_metadata message", 2); + return true; + } int type = msg["msg_type"].integer(); int piece = msg["piece"].integer(); @@ -364,7 +369,7 @@ namespace libtorrent { namespace { std::stringstream msg; msg << "unknown ut_metadata extension message: " << type; - m_pc.disconnect(msg.str().c_str()); + m_pc.disconnect(msg.str().c_str(), 2); } } return true; diff --git a/libtorrent/src/ut_pex.cpp b/libtorrent/src/ut_pex.cpp index a98fc9508..4341564f7 100644 --- a/libtorrent/src/ut_pex.cpp +++ b/libtorrent/src/ut_pex.cpp @@ -216,13 +216,18 @@ namespace libtorrent { namespace if (length > 500 * 1024) { - m_pc.disconnect("peer exchange message larger than 500 kB"); + m_pc.disconnect("peer exchange message larger than 500 kB", 2); return true; } if (body.left() < length) return true; entry pex_msg = bdecode(body.begin, body.end); + if (pex_msg.type() == entry::undefined_t) + { + m_pc.disconnect("invalid bencoding in ut_metadata message", 2); + return true; + } entry const* p = pex_msg.find_key("added"); entry const* pf = pex_msg.find_key("added.f");