diff --git a/libtorrent/bindings/python/src/torrent_status.cpp b/libtorrent/bindings/python/src/torrent_status.cpp index ebe955a8a..091dbf7d4 100755 --- a/libtorrent/bindings/python/src/torrent_status.cpp +++ b/libtorrent/bindings/python/src/torrent_status.cpp @@ -13,7 +13,7 @@ object pieces(torrent_status const& s) { list result; - for (bitfield::const_iterator i(s.pieces->begin()), e(s.pieces->end()); i != e; ++i) + for (bitfield::const_iterator i(s.pieces.begin()), e(s.pieces.end()); i != e; ++i) result.append(*i); return result; diff --git a/libtorrent/include/libtorrent/bt_peer_connection.hpp b/libtorrent/include/libtorrent/bt_peer_connection.hpp index 370bd3ab8..09b665b4a 100755 --- a/libtorrent/include/libtorrent/bt_peer_connection.hpp +++ b/libtorrent/include/libtorrent/bt_peer_connection.hpp @@ -209,7 +209,7 @@ namespace libtorrent void write_not_interested(); void write_request(peer_request const& r); void write_cancel(peer_request const& r); - void write_bitfield(bitfield const& bits); + void write_bitfield(); void write_have(int index); void write_piece(peer_request const& r, disk_buffer_holder& buffer); void write_handshake(); diff --git a/libtorrent/include/libtorrent/config.hpp b/libtorrent/include/libtorrent/config.hpp index dc9769840..1ee97bd57 100755 --- a/libtorrent/include/libtorrent/config.hpp +++ b/libtorrent/include/libtorrent/config.hpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_CONFIG_HPP_INCLUDED #include +#include #if defined(__GNUC__) && __GNUC__ >= 4 @@ -81,7 +82,12 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_BSD #endif - +// should wpath or path be used? +#if defined UNICODE && !defined BOOST_FILESYSTEM_NARROW_ONLY && BOOST_VERSION >= 103400 +#define TORRENT_USE_WPATH 1 +#else +#define TORRENT_USE_WPATH 0 +#endif #endif // TORRENT_CONFIG_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/piece_picker.hpp b/libtorrent/include/libtorrent/piece_picker.hpp index 6be92ffa1..4b9e6bcc5 100755 --- a/libtorrent/include/libtorrent/piece_picker.hpp +++ b/libtorrent/include/libtorrent/piece_picker.hpp @@ -129,18 +129,13 @@ namespace libtorrent boost::int16_t requested; }; - piece_picker(int blocks_per_piece - , int total_num_blocks); + piece_picker(); void get_availability(std::vector& avail) const; void sequential_download(bool sd); bool sequential_download() const { return m_sequential_download >= 0; } - // the vector tells which pieces we already have - // and which we don't have. - void init(bitfield const& pieces); - // increases the peer count for the given piece // (is used when a HAVE message is received) void inc_refcount(int index); @@ -164,6 +159,17 @@ namespace libtorrent // we are not interested in this piece anymore // (i.e. we don't have to maintain a refcount) void we_have(int index); + void we_dont_have(int index); + + void init(int blocks_per_piece, int total_num_blocks); + int num_pieces() const { return int(m_piece_map.size()); } + + bool have_piece(int index) const + { + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < int(m_piece_map.size())); + return m_piece_map[index].index == piece_pos::we_have_index; + } // sets the priority of a piece. // returns true if the priority was changed from 0 to non-0 @@ -276,6 +282,8 @@ namespace libtorrent // the number of filtered pieces we already have int num_have_filtered() const { return m_num_have_filtered; } + int num_have() const { return m_num_have; } + #ifndef NDEBUG // used in debug mode void verify_priority(int start, int end, int prio) const; @@ -350,6 +358,7 @@ namespace libtorrent bool have() const { return index == we_have_index; } void set_have() { index = we_have_index; TORRENT_ASSERT(have()); } + void set_not_have() { index = 0; TORRENT_ASSERT(!have()); } bool filtered() const { return piece_priority == filter_priority; } void filtered(bool f) { piece_priority = f ? filter_priority : 0; } @@ -466,10 +475,6 @@ namespace libtorrent // if this is set to true, it means update_pieces() // has to be called before accessing m_pieces. mutable bool m_dirty; - -#ifndef NDEBUG - bool m_files_checked_called; -#endif }; inline int piece_picker::blocks_in_piece(int index) const diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp index ebd6b7ea5..fcae0be32 100755 --- a/libtorrent/include/libtorrent/session.hpp +++ b/libtorrent/include/libtorrent/session.hpp @@ -129,7 +129,7 @@ namespace libtorrent , resume_data(0) , storage_mode(storage_mode_sparse) , paused(true) - , auto_managed(false) + , auto_managed(true) , duplicate_is_error(false) , storage(sc) , userdata(0) diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index dec649c24..778d4d4aa 100755 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -149,6 +149,7 @@ namespace libtorrent void init(); void on_resume_data_checked(int ret, disk_io_job const& j); + void on_force_recheck(int ret, disk_io_job const& j); void on_piece_checked(int ret, disk_io_job const& j); void files_checked(); void start_checking(); @@ -180,6 +181,7 @@ namespace libtorrent std::string name() const; stat statistics() const { return m_stat; } + void add_stats(stat const& s) { m_stat += s; } size_type bytes_left() const; boost::tuples::tuple bytes_done() const; size_type quantized_bytes_done() const; @@ -190,6 +192,7 @@ namespace libtorrent void pause(); void resume(); bool is_paused() const { return m_paused; } + void force_recheck(); void save_resume_data(); bool is_auto_managed() const { return m_auto_managed; } @@ -377,14 +380,15 @@ namespace libtorrent // returns true if we have downloaded the given piece bool have_piece(int index) const { - TORRENT_ASSERT(index >= 0 && index < (signed)m_have_pieces.size()); - return m_have_pieces[index]; + return has_picker()?m_picker->have_piece(index):true; } - bitfield const& pieces() const - { return m_have_pieces; } - - int num_pieces() const { return m_num_pieces; } + int num_have() const + { + return has_picker() + ?m_picker->num_have() + :m_torrent_file->num_pieces(); + } // when we get a have message, this is called for that piece void peer_has(int index) @@ -392,7 +396,6 @@ namespace libtorrent if (m_picker.get()) { TORRENT_ASSERT(!is_seed()); - TORRENT_ASSERT(index >= 0 && index < (signed)m_have_pieces.size()); m_picker->inc_refcount(index); } #ifndef NDEBUG @@ -439,7 +442,6 @@ namespace libtorrent if (m_picker.get()) { TORRENT_ASSERT(!is_seed()); - TORRENT_ASSERT(index >= 0 && index < (signed)m_have_pieces.size()); m_picker->dec_refcount(index); } #ifndef NDEBUG @@ -506,7 +508,9 @@ namespace libtorrent bool is_seed() const { return valid_metadata() - && m_num_pieces == m_torrent_file->num_pieces(); + && (!m_picker + || m_state == torrent_status::seeding + || m_picker->num_have() == m_picker->num_pieces()); } // this is true if we have all the pieces that we want @@ -514,7 +518,7 @@ namespace libtorrent { if (is_seed()) return true; return valid_metadata() && m_torrent_file->num_pieces() - - m_num_pieces - m_picker->num_filtered() == 0; + - m_picker->num_have() - m_picker->num_filtered() == 0; } fs::path save_path() const; @@ -740,9 +744,6 @@ namespace libtorrent std::vector m_trackers; // this is an index into m_trackers - // the bitmask that says which pieces we have - bitfield m_have_pieces; - // the number of bytes that has been // downloaded that failed the hash-test size_type m_total_failed_bytes; @@ -781,11 +782,6 @@ namespace libtorrent float m_progress; - // the number of pieces we have. The same as - // std::accumulate(m_have_pieces.begin(), - // m_have_pieces.end(), 0) - int m_num_pieces; - // the upload/download ratio that each peer // tries to maintain. // 0 is infinite @@ -908,9 +904,14 @@ namespace libtorrent // has been initialized with files_checked(). bool m_connections_initialized:1; -#ifndef NDEBUG + // is set to true every time there is an incoming + // connection to this torrent + bool m_has_incoming:1; + + // this is set to true when the files are checked + // before the files are checked, we don't try to + // connect to peers bool m_files_checked:1; -#endif }; inline ptime torrent::next_announce() const diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index cd499a033..636e842f0 100755 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -100,7 +100,6 @@ namespace libtorrent , num_incomplete(-1) , list_seeds(0) , list_peers(0) - , pieces(0) , num_pieces(0) , total_done(0) , total_wanted_done(0) @@ -120,6 +119,7 @@ namespace libtorrent , seeding_time(0) , seed_rank(0) , last_scrape(0) + , has_incoming(false) {} enum state_t @@ -200,7 +200,7 @@ namespace libtorrent // we potentially could connect to int connect_candidates; - bitfield const* pieces; + bitfield pieces; // this is the number of pieces the client has // downloaded. it is equal to: @@ -266,6 +266,10 @@ namespace libtorrent // number of seconds since last scrape, or -1 if // there hasn't been a scrape int last_scrape; + + // true if there are incoming connections to this + // torrent + bool has_incoming; }; struct TORRENT_EXPORT block_info @@ -341,6 +345,7 @@ namespace libtorrent bool is_paused() const; void pause() const; void resume() const; + void force_recheck() const; void save_resume_data() const; bool is_auto_managed() const; diff --git a/libtorrent/include/libtorrent/web_peer_connection.hpp b/libtorrent/include/libtorrent/web_peer_connection.hpp index c37608232..f8e7af99f 100755 --- a/libtorrent/include/libtorrent/web_peer_connection.hpp +++ b/libtorrent/include/libtorrent/web_peer_connection.hpp @@ -173,6 +173,9 @@ namespace libtorrent // response. used to know where in the buffer the // next response starts int m_received_body; + + // position in the current range response + int m_range_pos; }; } diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index eeb40e478..307bcd4d2 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -245,7 +245,7 @@ namespace libtorrent { boost::shared_ptr t = associated_torrent().lock(); TORRENT_ASSERT(t); - write_bitfield(t->pieces()); + write_bitfield(); #ifndef TORRENT_DISABLE_DHT if (m_supports_dht_port && m_ses.m_dht) write_dht_port(m_ses.get_dht_settings().service_port); @@ -1416,7 +1416,7 @@ namespace libtorrent send_buffer(msg, sizeof(msg)); } - void bt_peer_connection::write_bitfield(bitfield const& bits) + void bt_peer_connection::write_bitfield() { INVARIANT_CHECK; @@ -1426,7 +1426,7 @@ namespace libtorrent TORRENT_ASSERT(t->valid_metadata()); // in this case, have_all or have_none should be sent instead - TORRENT_ASSERT(!m_supports_fast || !t->is_seed() || t->num_pieces() != 0); + TORRENT_ASSERT(!m_supports_fast || !t->is_seed() || t->num_have() != 0); if (m_supports_fast && t->is_seed()) { @@ -1434,13 +1434,13 @@ namespace libtorrent send_allowed_set(); return; } - else if (m_supports_fast && t->num_pieces() == 0) + else if (m_supports_fast && t->num_have() == 0) { write_have_none(); send_allowed_set(); return; } - else if (t->num_pieces() == 0) + else if (t->num_have() == 0) { // don't send a bitfield if we don't have any pieces #ifndef NDEBUG @@ -1449,14 +1449,11 @@ namespace libtorrent return; } - int num_pieces = bits.size(); + int num_pieces = t->torrent_file().num_pieces(); int lazy_pieces[50]; int num_lazy_pieces = 0; int lazy_piece = 0; - TORRENT_ASSERT(t->is_seed() == (bits.count() - == num_pieces)); - if (t->is_seed() && m_ses.settings().lazy_bitfields) { num_lazy_pieces = (std::min)(50, num_pieces / 10); @@ -1470,26 +1467,6 @@ namespace libtorrent lazy_piece = 0; } -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() << " ==> BITFIELD "; - - std::stringstream bitfield_string; - for (int i = 0; i < (int)get_bitfield().size(); ++i) - { - if (lazy_piece < num_lazy_pieces - && lazy_pieces[lazy_piece] == i) - { - bitfield_string << "0"; - ++lazy_piece; - continue; - } - if (bits[i]) bitfield_string << "1"; - else bitfield_string << "0"; - } - bitfield_string << "\n"; - (*m_logger) << bitfield_string.str(); - lazy_piece = 0; -#endif const int packet_size = (num_pieces + 7) / 8 + 5; buffer::interval i = allocate_send_buffer(packet_size); @@ -1498,15 +1475,46 @@ namespace libtorrent detail::write_int32(packet_size - 4, i.begin); detail::write_uint8(msg_bitfield, i.begin); - memcpy(i.begin, bits.bytes(), packet_size - 5); + if (t->is_seed()) + { + memset(i.begin, 0xff, packet_size - 5); + } + else + { + memset(i.begin, 0, packet_size - 5); + piece_picker const& p = t->picker(); + int mask = 0x80; + unsigned char* byte = (unsigned char*)i.begin; + for (int i = 0; i < num_pieces; ++i) + { + if (p.have_piece(i)) *byte |= mask; + mask >>= 1; + if (mask == 0) + { + mask = 0x80; + ++byte; + } + } + } for (int c = 0; c < num_lazy_pieces; ++c) i.begin[lazy_pieces[c] / 8] &= ~(0x80 >> (lazy_pieces[c] & 7)); TORRENT_ASSERT(i.end - i.begin == (num_pieces + 7) / 8); +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << time_now_string() << " ==> BITFIELD "; + + std::stringstream bitfield_string; + for (int k = 0; k < num_pieces; ++k) + { + if (i.begin[k / 8] & (0x80 >> (k % 8))) bitfield_string << "1"; + else bitfield_string << "0"; + } + bitfield_string << "\n"; + (*m_logger) << bitfield_string.str(); +#endif #ifndef NDEBUG m_sent_bitfield = true; #endif - setup_send(); if (num_lazy_pieces > 0) { @@ -1522,6 +1530,7 @@ namespace libtorrent if (m_supports_fast) send_allowed_set(); + setup_send(); } #ifndef TORRENT_DISABLE_EXTENSIONS @@ -2377,7 +2386,7 @@ namespace libtorrent // sent the handshake if (!is_local()) write_handshake(); // if (t->valid_metadata()) -// write_bitfield(t->pieces()); +// write_bitfield(); if (is_disconnecting()) return; @@ -2511,7 +2520,7 @@ namespace libtorrent reset_recv_buffer(5); if (t->valid_metadata()) { - write_bitfield(t->pieces()); + write_bitfield(); #ifndef TORRENT_DISABLE_DHT if (m_supports_dht_port && m_ses.m_dht) write_dht_port(m_ses.get_dht_settings().service_port); diff --git a/libtorrent/src/http_connection.cpp b/libtorrent/src/http_connection.cpp index 0351925f6..183c60e97 100644 --- a/libtorrent/src/http_connection.cpp +++ b/libtorrent/src/http_connection.cpp @@ -301,8 +301,11 @@ void http_connection::connect(int ticket, tcp::endpoint target_address) void http_connection::on_connect(error_code const& e) { - TORRENT_ASSERT(m_connection_ticket >= 0); - m_cc.done(m_connection_ticket); + if (m_connection_ticket >= 0) + { + m_cc.done(m_connection_ticket); + m_connection_ticket = -1; + } m_last_receive = time_now(); if (!e) diff --git a/libtorrent/src/http_parser.cpp b/libtorrent/src/http_parser.cpp index 4c2839178..eb717420f 100755 --- a/libtorrent/src/http_parser.cpp +++ b/libtorrent/src/http_parser.cpp @@ -63,9 +63,10 @@ namespace libtorrent { TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left()); boost::tuple ret(0, 0); + int start_pos = m_recv_buffer.left(); // early exit if there's nothing new in the receive buffer - if (recv_buffer.left() == m_recv_buffer.left()) return ret; + if (start_pos == recv_buffer.left()) return ret; m_recv_buffer = recv_buffer; if (m_state == error_state) @@ -80,7 +81,11 @@ namespace libtorrent TORRENT_ASSERT(!m_finished); char const* newline = std::find(pos, recv_buffer.end, '\n'); // if we don't have a full line yet, wait. - if (newline == recv_buffer.end) return ret; + if (newline == recv_buffer.end) + { + boost::get<1>(ret) += m_recv_buffer.left() - start_pos; + return ret; + } if (newline == pos) { @@ -96,7 +101,7 @@ namespace libtorrent ++newline; int incoming = (int)std::distance(pos, newline); m_recv_pos += incoming; - boost::get<1>(ret) += incoming; + boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos); pos = newline; line >> m_protocol; @@ -114,6 +119,7 @@ namespace libtorrent m_status_code = 0; } m_state = read_header; + start_pos = pos - recv_buffer.begin; } if (m_state == read_header) @@ -131,7 +137,6 @@ namespace libtorrent line.assign(pos, line_end); ++newline; m_recv_pos += newline - pos; - boost::get<1>(ret) += newline - pos; pos = newline; std::string::size_type separator = line.find(':'); @@ -187,6 +192,7 @@ namespace libtorrent TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left()); newline = std::find(pos, recv_buffer.end, '\n'); } + boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos); } if (m_state == read_body) diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp index 288ee7267..df0715ca6 100755 --- a/libtorrent/src/http_tracker_connection.cpp +++ b/libtorrent/src/http_tracker_connection.cpp @@ -225,7 +225,14 @@ namespace libtorrent } // handle tracker response - entry e = bdecode(data, data + size); + 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/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 1a72ca148..f01193b96 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -326,15 +326,19 @@ namespace libtorrent TORRENT_ASSERT(t); bool interested = false; - bitfield const& we_have = t->pieces(); - for (int j = 0; j != (int)we_have.size(); ++j) + if (!t->is_finished()) { - if (!we_have[j] - && t->piece_priority(j) > 0 - && m_have_piece[j]) + piece_picker const& p = t->picker(); + int num_pieces = p.num_pieces(); + for (int j = 0; j != num_pieces; ++j) { - interested = true; - break; + if (!p.have_piece(j) + && t->piece_priority(j) > 0 + && m_have_piece[j]) + { + interested = true; + break; + } } } try @@ -2218,6 +2222,10 @@ namespace libtorrent if (t) { + // make sure we keep all the stats! + calc_ip_overhead(); + t->add_stats(statistics()); + if (t->has_picker()) { piece_picker& picker = t->picker(); diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index 0b75b425e..f0b7fb937 100755 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -58,10 +58,9 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - piece_picker::piece_picker(int blocks_per_piece, int total_num_blocks) + piece_picker::piece_picker() : m_seeds(0) , m_priority_boundries(1, int(m_pieces.size())) - , m_piece_map((total_num_blocks + blocks_per_piece-1) / blocks_per_piece) , m_num_filtered(0) , m_num_have_filtered(0) , m_num_have(0) @@ -69,13 +68,22 @@ namespace libtorrent , m_dirty(false) { #ifdef TORRENT_PICKER_LOG - std::cout << "new piece_picker" << std::endl; + std::cerr << "new piece_picker" << std::endl; #endif +#ifndef NDEBUG + check_invariant(); +#endif + } + + void piece_picker::init(int blocks_per_piece, int total_num_blocks) + { TORRENT_ASSERT(blocks_per_piece > 0); TORRENT_ASSERT(total_num_blocks >= 0); -#ifndef NDEBUG - m_files_checked_called = false; -#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)); // the piece index is stored in 20 bits, which limits the allowed // number of pieces somewhat @@ -87,15 +95,6 @@ namespace libtorrent 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); - - // allocate the piece_map to cover all pieces - // and make them invalid (as if we don't have a single piece) - std::fill(m_piece_map.begin(), m_piece_map.end() - , piece_pos(0, 0)); - m_num_have = 0; -#ifndef NDEBUG - check_invariant(); -#endif } void piece_picker::sequential_download(bool sd) @@ -122,24 +121,6 @@ namespace libtorrent } } - // pieces is a bitmask with the pieces we have - void piece_picker::init(bitfield const& pieces) - { - TORRENT_PIECE_PICKER_INVARIANT_CHECK; -#ifndef NDEBUG - m_files_checked_called = true; -#endif - int index = 0; - for (bitfield::const_iterator i = pieces.begin(); - i != pieces.end(); ++i, ++index) - { - TORRENT_ASSERT(index < pieces.size()); - piece_pos& p = m_piece_map[index]; - if (*i) we_have(index); - else TORRENT_ASSERT(p.index == 0); - } - } - void piece_picker::piece_info(int index, piece_picker::downloading_piece& st) const { TORRENT_PIECE_PICKER_INVARIANT_CHECK; @@ -249,7 +230,7 @@ namespace libtorrent for (std::vector::const_iterator i = m_priority_boundries.begin() , end(m_priority_boundries.end()); i != end; ++i) { - std::cout << *i << " "; + std::cerr << *i << " "; } std::cout << std::endl; int index = 0; @@ -260,12 +241,12 @@ namespace libtorrent if (*i == -1) break; while (j != m_priority_boundries.end() && *j <= index) { - std::cout << "| "; + std::cerr << "| "; ++j; } - std::cout << *i << "(" << m_piece_map[*i].index << ") "; + std::cerr << *i << "(" << m_piece_map[*i].index << ") "; } - std::cout << std::endl; + std::cerr << std::endl; } void piece_picker::check_invariant(const torrent* t) const @@ -534,7 +515,7 @@ namespace libtorrent else new_index = rand() % (range_end - range_start) + range_start; #ifdef TORRENT_PICKER_LOG - std::cout << "add " << index << " (" << priority << ")" << std::endl; + std::cerr << "add " << index << " (" << priority << ")" << std::endl; print_pieces(); #endif m_pieces.push_back(-1); @@ -554,7 +535,7 @@ namespace libtorrent new_index = temp; #ifdef TORRENT_PICKER_LOG print_pieces(); - std::cout << " index: " << index + std::cerr << " index: " << index << " prio: " << priority << " new_index: " << new_index << std::endl; @@ -581,7 +562,7 @@ namespace libtorrent TORRENT_ASSERT(m_sequential_download == -1); #ifdef TORRENT_PICKER_LOG - std::cout << "remove " << m_pieces[elem_index] << " (" << priority << ")" << std::endl; + std::cerr << "remove " << m_pieces[elem_index] << " (" << priority << ")" << std::endl; #endif int next_index = elem_index; TORRENT_ASSERT(m_piece_map[m_pieces[elem_index]].priority(this) == -1); @@ -624,7 +605,6 @@ namespace libtorrent TORRENT_ASSERT(!m_dirty); TORRENT_ASSERT(priority >= 0); TORRENT_ASSERT(elem_index >= 0); - TORRENT_ASSERT(m_files_checked_called); TORRENT_ASSERT(m_sequential_download == -1); TORRENT_ASSERT(int(m_priority_boundries.size()) > priority); @@ -648,7 +628,7 @@ namespace libtorrent m_priority_boundries.resize(new_priority + 1, m_pieces.size()); #ifdef TORRENT_PICKER_LOG - std::cout << "update " << index << " (" << priority << "->" << new_priority << ")" << std::endl; + std::cerr << "update " << index << " (" << priority << "->" << new_priority << ")" << std::endl; #endif if (priority > new_priority) { @@ -772,7 +752,6 @@ namespace libtorrent TORRENT_ASSERT(index >= 0); TORRENT_ASSERT(index < (int)m_piece_map.size()); - TORRENT_ASSERT(m_files_checked_called); TORRENT_ASSERT(m_piece_map[index].downloading == 1); @@ -804,7 +783,6 @@ namespace libtorrent void piece_picker::inc_refcount_all() { TORRENT_PIECE_PICKER_INVARIANT_CHECK; - TORRENT_ASSERT(m_files_checked_called); ++m_seeds; if (m_sequential_download >= 0) return; if (m_seeds == 1) @@ -819,7 +797,6 @@ namespace libtorrent void piece_picker::dec_refcount_all() { TORRENT_PIECE_PICKER_INVARIANT_CHECK; - TORRENT_ASSERT(m_files_checked_called); if (m_sequential_download >= 0) { @@ -935,7 +912,7 @@ namespace libtorrent TORRENT_ASSERT(m_sequential_download == -1); if (m_priority_boundries.empty()) m_priority_boundries.resize(1, 0); #ifdef TORRENT_PICKER_LOG - std::cout << "update_pieces" << std::endl; + std::cerr << "update_pieces" << std::endl; #endif std::fill(m_priority_boundries.begin(), m_priority_boundries.end(), 0); for (std::vector::iterator i = m_piece_map.begin() @@ -1004,6 +981,33 @@ namespace libtorrent #endif } + void piece_picker::we_dont_have(int index) + { + TORRENT_PIECE_PICKER_INVARIANT_CHECK; + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < (int)m_piece_map.size()); + + piece_pos& p = m_piece_map[index]; + TORRENT_ASSERT(p.downloading == 0); + + if (!p.have()) return; + + if (m_sequential_download > index) + m_sequential_download = index; + + if (p.filtered()) + { + ++m_num_filtered; + --m_num_have_filtered; + } + + --m_num_have; + p.set_not_have(); + + if (m_dirty) return; + if (!p.filtered()) add(index); + } + // this is used to indicate that we succesfully have // downloaded a piece, and that no further attempts // to pick that piece should be made. The piece will @@ -1167,7 +1171,6 @@ namespace libtorrent TORRENT_PIECE_PICKER_INVARIANT_CHECK; TORRENT_ASSERT(num_blocks > 0); TORRENT_ASSERT(pieces.size() == m_piece_map.size()); - TORRENT_ASSERT(m_files_checked_called); TORRENT_ASSERT(!m_priority_boundries.empty() || m_sequential_download >= 0 diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index 8c01d09ec..d73fc1a9f 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -200,7 +200,7 @@ namespace libtorrent int prefer_whole_pieces = c.prefer_whole_pieces(); - bool rarest_first = t.num_pieces() >= t.settings().initial_picker_threshold; + bool rarest_first = t.num_have() >= t.settings().initial_picker_threshold; if (prefer_whole_pieces == 0) { @@ -644,7 +644,7 @@ namespace libtorrent error_code ec; TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec); - if (m_peers.size() >= m_torrent->settings().max_peerlist_size) + if (int(m_peers.size()) >= m_torrent->settings().max_peerlist_size) { c.disconnect("peer list size exceeded, refusing incoming connection"); return false; @@ -773,7 +773,7 @@ namespace libtorrent return 0; } - if (m_peers.size() >= m_torrent->settings().max_peerlist_size) + if (int(m_peers.size()) >= m_torrent->settings().max_peerlist_size) return 0; // we don't have any info about this peer. @@ -1018,11 +1018,14 @@ namespace libtorrent TORRENT_ASSERT(!p->second.connection); TORRENT_ASSERT(p->second.type == peer::connectable); + TORRENT_ASSERT(is_connect_candidate(p->second, m_torrent->is_finished())); if (!m_torrent->connect_to_peer(&p->second)) { ++p->second.failcount; return false; } + TORRENT_ASSERT(!is_connect_candidate(p->second, m_torrent->is_finished())); + --m_num_connect_candidates; return true; } diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index bb9c49264..3a8090144 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -95,9 +95,12 @@ POSSIBILITY OF SUCH DAMAGE. #include #endif -#if defined(_WIN32) && defined(UNICODE) +#if TORRENT_USE_WPATH +#ifdef BOOST_WINDOWS #include +#endif + #include #include "libtorrent/utf8.hpp" #include "libtorrent/buffer.hpp" @@ -249,7 +252,53 @@ namespace namespace libtorrent { + template + void recursive_copy(Path const& old_path, Path const& new_path, std::string& error) + { + using boost::filesystem::directory_iterator; +#ifndef BOOST_NO_EXCEPTIONS + try { +#endif + TORRENT_ASSERT(error.empty()); + if (is_directory(old_path)) + { + create_directory(new_path); + for (directory_iterator i(old_path), end; i != end; ++i) + { + recursive_copy(i->path(), new_path / i->leaf(), error); + if (!error.empty()) return; + } + } + else + { + copy_file(old_path, new_path); + } +#ifndef BOOST_NO_EXCEPTIONS + } catch (std::exception& e) { error = e.what(); } +#endif + } + template + void recursive_remove(Path const& old_path) + { + using boost::filesystem::directory_iterator; +#ifndef BOOST_NO_EXCEPTIONS + try { +#endif + if (is_directory(old_path)) + { + for (directory_iterator i(old_path), end; i != end; ++i) + recursive_remove(i->path()); + remove(old_path); + } + else + { + remove(old_path); + } +#ifndef BOOST_NO_EXCEPTIONS + } catch (std::exception& e) {} +#endif + } std::vector > get_filesizes( file_storage const& s, fs::path p) { @@ -260,7 +309,7 @@ namespace libtorrent { size_type size = 0; std::time_t time = 0; -#if defined(_WIN32) && defined(UNICODE) +#if TORRENT_USE_WPATH fs::wpath f = safe_convert((p / i->path).string()); #else fs::path f = p / i->path; @@ -310,7 +359,7 @@ namespace libtorrent size_type size = 0; std::time_t time = 0; -#if defined(_WIN32) && defined(UNICODE) +#if TORRENT_USE_WPATH fs::wpath f = safe_convert((p / i->path).string()); #else fs::path f = p / i->path; @@ -443,7 +492,7 @@ namespace libtorrent last_path = dir; if (!exists_win(last_path)) create_directories_win(last_path); -#elif defined(_WIN32) && defined(UNICODE) +#elif TORRENT_USE_WPATH last_path = dir; fs::wpath wp = safe_convert(last_path.string()); if (!exists(wp)) @@ -506,9 +555,9 @@ namespace libtorrent fs::path old_name = m_save_path / files().at(index).path; m_pool.release(old_name); -#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 - fs::wpath old_path = safe_convert(old_name); - fs::wpath new_path = safe_convert(m_save_path / new_filename); +#if TORRENT_USE_WPATH + fs::wpath old_path = safe_convert(old_name.string()); + fs::wpath new_path = safe_convert((m_save_path / new_filename).string()); #else fs::path const& old_path = old_name; fs::path new_path = m_save_path / new_filename; @@ -565,7 +614,7 @@ namespace libtorrent std::pair ret = directories.insert((m_save_path / bp).string()); bp = bp.branch_path(); } -#if defined(_WIN32) && defined(UNICODE) +#if TORRENT_USE_WPATH try { fs::remove(safe_convert(p)); } catch (std::exception& e) @@ -590,7 +639,7 @@ namespace libtorrent for (std::set::reverse_iterator i = directories.rbegin() , end(directories.rend()); i != end; ++i) { -#if defined(_WIN32) && defined(UNICODE) +#if TORRENT_USE_WPATH try { fs::remove(safe_convert(*i)); } catch (std::exception& e) @@ -725,7 +774,7 @@ namespace libtorrent // returns true on success bool storage::move_storage(fs::path save_path) { -#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 +#if TORRENT_USE_WPATH fs::wpath old_path; fs::wpath new_path; #else @@ -741,7 +790,7 @@ namespace libtorrent CreateDirectory(wsave_path.c_str(), 0); else if ((GetFileAttributes(wsave_path.c_str()) & FILE_ATTRIBUTE_DIRECTORY) == 0) return false; -#elif defined(_WIN32) && defined(UNICODE) +#elif TORRENT_USE_WPATH fs::wpath wp = safe_convert(save_path.string()); if (!exists(wp)) create_directory(wp); @@ -756,7 +805,7 @@ namespace libtorrent m_pool.release(this); -#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 +#if TORRENT_USE_WPATH old_path = safe_convert((m_save_path / files().name()).string()); new_path = safe_convert((save_path / files().name()).string()); #else @@ -770,7 +819,6 @@ namespace libtorrent #endif #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400 rename_win(old_path, new_path); - rename(old_path, new_path); #else rename(old_path, new_path); #endif @@ -780,8 +828,15 @@ namespace libtorrent } catch (std::exception& e) { - set_error((m_save_path / files().name()).string(), e.what()); - return true; + std::string err; + recursive_copy(old_path, new_path, err); + if (!err.empty()) + { + set_error((m_save_path / files().name()).string(), e.what()); + return true; + } + m_save_path = save_path; + recursive_remove(old_path); } #endif return false; @@ -1648,7 +1703,7 @@ namespace libtorrent #endif #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400 file_exists = exists_win(f); -#elif defined(_WIN32) && defined(UNICODE) +#elif TORRENT_USE_WPATH fs::wpath wf = safe_convert(f.string()); file_exists = exists(wf); #else diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 54358e9fe..e5a5d721b 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -164,7 +164,7 @@ namespace libtorrent , m_last_dht_announce(time_now() - minutes(15)) #endif , m_ses(ses) - , m_picker(0) + , m_picker(new piece_picker()) , m_trackers(m_torrent_file->trackers()) , m_total_failed_bytes(0) , m_total_redundant_bytes(0) @@ -175,7 +175,6 @@ namespace libtorrent , m_settings(ses.settings()) , m_storage_constructor(sc) , m_progress(0.f) - , m_num_pieces(0) , m_ratio(0.f) , m_max_uploads((std::numeric_limits::max)()) , m_num_uploads(0) @@ -201,11 +200,10 @@ namespace libtorrent , m_sequential_download(false) , m_got_tracker_response(false) , m_connections_initialized(true) + , m_has_incoming(false) + , m_files_checked(false) { if (resume_data) m_resume_data = *resume_data; -#ifndef NDEBUG - m_files_checked = false; -#endif } torrent::torrent( @@ -239,7 +237,7 @@ namespace libtorrent , m_last_dht_announce(time_now() - minutes(15)) #endif , m_ses(ses) - , m_picker(0) + , m_picker(new piece_picker()) , m_total_failed_bytes(0) , m_total_redundant_bytes(0) , m_net_interface(net_interface.address(), 0) @@ -249,7 +247,6 @@ namespace libtorrent , m_settings(ses.settings()) , m_storage_constructor(sc) , m_progress(0.f) - , m_num_pieces(0) , m_ratio(0.f) , m_max_uploads((std::numeric_limits::max)()) , m_num_uploads(0) @@ -275,6 +272,7 @@ namespace libtorrent , m_sequential_download(false) , m_got_tracker_response(false) , m_connections_initialized(false) + , m_has_incoming(false) { if (resume_data) m_resume_data = *resume_data; #ifndef NDEBUG @@ -308,10 +306,10 @@ namespace libtorrent if (m_ses.m_listen_sockets.empty()) return false; if (!m_ses.m_dht) return false; + if (!m_files_checked) return false; // don't announce private torrents if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false; - if (m_trackers.empty()) return true; return m_failed_trackers > 0 || !m_ses.settings().use_dht_as_fallback; @@ -407,16 +405,14 @@ namespace libtorrent TORRENT_ASSERT(m_torrent_file->num_files() > 0); TORRENT_ASSERT(m_torrent_file->total_size() >= 0); - m_have_pieces.resize(m_torrent_file->num_pieces(), false); // 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 , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor , m_storage_mode); m_storage = m_owning_storage.get(); - m_picker.reset(new piece_picker( - m_torrent_file->piece_length() / m_block_size - , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size))); + m_picker->init(m_torrent_file->piece_length() / m_block_size + , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size)); std::vector const& url_seeds = m_torrent_file->url_seeds(); std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds @@ -473,8 +469,6 @@ namespace libtorrent " ]\n"; #endif } - m_have_pieces.clear_all(); - m_num_pieces = 0; m_error = j.str; pause(); return; @@ -548,8 +542,6 @@ namespace libtorrent // there are either no files for this torrent // or the resume_data was accepted - m_num_pieces = 0; - m_have_pieces.clear_all(); if (!fastresume_rejected) { TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t); @@ -563,8 +555,7 @@ namespace libtorrent for (int i = 0, end(pieces_str.size()); i < end; ++i) { if ((pieces_str[i] & 1) == 0) continue; - m_have_pieces.set_bit(i); - ++m_num_pieces; + m_picker->we_have(i); } } @@ -587,11 +578,8 @@ namespace libtorrent if (piece_index < 0 || piece_index >= torrent_file().num_pieces()) continue; - if (m_have_pieces[piece_index]) - { - m_have_pieces.clear_bit(piece_index); - --m_num_pieces; - } + if (m_picker->have_piece(piece_index)) + m_picker->we_dont_have(piece_index); entry const* bitmask_ent = i->find_key("bitmask"); if (bitmask_ent == 0 || bitmask_ent->type() != entry::string_t) break; @@ -617,13 +605,6 @@ namespace libtorrent } } } - - int index = 0; - for (bitfield::const_iterator i = m_have_pieces.begin() - , end(m_have_pieces.end()); i != end; ++i, ++index) - { - if (*i) m_picker->we_have(index); - } } files_checked(); @@ -636,6 +617,51 @@ namespace libtorrent } } + void torrent::force_recheck() + { + disconnect_all(); + + m_owning_storage->async_release_files(); + m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file + , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor + , m_storage_mode); + m_storage = m_owning_storage.get(); + m_picker.reset(new piece_picker); + m_picker->init(m_torrent_file->piece_length() / m_block_size + , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size)); + // assume that we don't have anything + m_files_checked = false; + m_state = torrent_status::queued_for_checking; + + m_resume_data = entry(); + m_storage->async_check_fastresume(&m_resume_data + , bind(&torrent::on_force_recheck + , shared_from_this(), _1, _2)); + } + + void torrent::on_force_recheck(int ret, disk_io_job const& j) + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + + if (ret == piece_manager::fatal_disk_error) + { + if (m_ses.m_alerts.should_post(alert::fatal)) + { + m_ses.m_alerts.post_alert(file_error_alert(j.error_file, get_handle(), j.str)); +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + (*m_ses.m_logger) << time_now_string() << ": fatal disk error [" + " error: " << j.str << + " torrent: " << torrent_file().name() << + " ]\n"; +#endif + } + m_error = j.str; + pause(); + return; + } + m_ses.check_torrent(shared_from_this()); + } + void torrent::start_checking() { m_state = torrent_status::checking_files; @@ -661,8 +687,6 @@ namespace libtorrent " ]\n"; #endif } - m_have_pieces.clear_all(); - m_num_pieces = 0; m_error = j.str; pause(); m_ses.done_checking(shared_from_this()); @@ -671,13 +695,9 @@ namespace libtorrent m_progress = j.piece / float(torrent_file().num_pieces()); - if (j.offset >= 0 && !m_have_pieces[j.offset]) - { - m_have_pieces.set_bit(j.offset); - ++m_num_pieces; - TORRENT_ASSERT(m_picker); + TORRENT_ASSERT(m_picker); + if (j.offset >= 0 && !m_picker->have_piece(j.offset)) m_picker->we_have(j.offset); - } // we're not done checking yet // this handler will be called repeatedly until @@ -793,6 +813,7 @@ namespace libtorrent // INVARIANT_CHECK; if (m_trackers.empty()) return false; + if (!m_files_checked) return false; if (m_just_paused) { @@ -982,12 +1003,12 @@ namespace libtorrent const int last_piece = m_torrent_file->num_pieces() - 1; size_type total_done - = size_type(m_num_pieces) * m_torrent_file->piece_length(); + = size_type(num_have()) * m_torrent_file->piece_length(); // if we have the last piece, we have to correct // the amount we have, since the first calculation // assumed all pieces were of equal size - if (m_have_pieces[last_piece]) + if (m_picker->have_piece(last_piece)) { int corr = m_torrent_file->piece_size(last_piece) - m_torrent_file->piece_length(); @@ -1013,19 +1034,19 @@ namespace libtorrent return make_tuple(m_torrent_file->total_size() , m_torrent_file->total_size()); - TORRENT_ASSERT(m_num_pieces >= m_picker->num_have_filtered()); - size_type wanted_done = size_type(m_num_pieces - m_picker->num_have_filtered()) + TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered()); + size_type wanted_done = size_type(num_have() - m_picker->num_have_filtered()) * piece_size; TORRENT_ASSERT(wanted_done >= 0); size_type total_done - = size_type(m_num_pieces) * piece_size; - TORRENT_ASSERT(m_num_pieces < m_torrent_file->num_pieces()); + = size_type(num_have()) * piece_size; + TORRENT_ASSERT(num_have() < m_torrent_file->num_pieces()); // if we have the last piece, we have to correct // the amount we have, since the first calculation // assumed all pieces were of equal size - if (m_have_pieces[last_piece]) + if (m_picker->have_piece(last_piece)) { TORRENT_ASSERT(total_done >= piece_size); int corr = m_torrent_file->piece_size(last_piece) @@ -1054,7 +1075,7 @@ namespace libtorrent { int corr = 0; int index = i->index; - if (m_have_pieces[index]) continue; + if (m_picker->have_piece(index)) continue; TORRENT_ASSERT(i->finished <= m_picker->blocks_in_piece(index)); #ifndef NDEBUG @@ -1099,7 +1120,7 @@ namespace libtorrent = pc->downloading_piece_progress(); if (p) { - if (m_have_pieces[p->piece_index]) + if (m_picker->have_piece(p->piece_index)) continue; piece_block block(p->piece_index, p->block_index); @@ -1136,16 +1157,16 @@ namespace libtorrent wanted_done += i->second; } + TORRENT_ASSERT(total_done <= m_torrent_file->total_size()); + TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size()); + #ifndef NDEBUG if (total_done >= m_torrent_file->total_size()) { // Thist happens when a piece has been downloaded completely // but not yet verified against the hash - std::copy(m_have_pieces.begin(), m_have_pieces.end() - , std::ostream_iterator(std::cerr, " ")); - std::cerr << std::endl; - std::cerr << "num_pieces: " << m_num_pieces << std::endl; + std::cerr << "num_have: " << num_have() << std::endl; std::cerr << "unfinished:" << std::endl; @@ -1195,7 +1216,7 @@ namespace libtorrent ?"disk failed":"failed") << " ]\n"; #endif - bool was_finished = m_picker->num_filtered() + num_pieces() + bool was_finished = m_picker->num_filtered() + num_have() == torrent_file().num_pieces(); if (passed_hash_check == 0) @@ -1226,7 +1247,7 @@ namespace libtorrent if (!was_finished && (is_seed() - || m_picker->num_filtered() + num_pieces() + || m_picker->num_filtered() + num_have() == torrent_file().num_pieces())) { TORRENT_ASSERT(passed_hash_check == 0); @@ -1350,7 +1371,7 @@ namespace libtorrent m_picker->restore_piece(index); TORRENT_ASSERT(m_storage); - TORRENT_ASSERT(m_have_pieces[index] == false); + TORRENT_ASSERT(m_picker->have_piece(index) == false); #ifndef NDEBUG for (std::vector::iterator i = downloaders.begin() @@ -1486,13 +1507,6 @@ namespace libtorrent std::set peers; std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin())); - if (!m_have_pieces[index]) - m_num_pieces++; - m_have_pieces.set_bit(index); - - TORRENT_ASSERT(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0) - == m_num_pieces); - m_picker->we_have(index); for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i) (*i)->announce_piece(index); @@ -1558,7 +1572,7 @@ namespace libtorrent bool was_finished = is_finished(); bool filter_updated = m_picker->set_piece_priority(index, priority); - TORRENT_ASSERT(m_num_pieces >= m_picker->num_have_filtered()); + TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered()); if (filter_updated) update_peer_interest(was_finished); } @@ -1596,7 +1610,7 @@ namespace libtorrent TORRENT_ASSERT(*i >= 0); TORRENT_ASSERT(*i <= 7); filter_updated |= m_picker->set_piece_priority(index, *i); - TORRENT_ASSERT(m_num_pieces >= m_picker->num_have_filtered()); + TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered()); } if (filter_updated) update_peer_interest(was_finished); } @@ -2442,8 +2456,16 @@ namespace libtorrent // write have bitmask entry::string_type& pieces = ret["pieces"].string(); pieces.resize(m_torrent_file->num_pieces()); - for (int i = 0, end(pieces.size()); i < end; ++i) - pieces[i] = m_have_pieces[i] ? 1 : 0; + if (is_seed()) + { + for (int i = 0, end(pieces.size()); i < end; ++i) + pieces[i] = 1; + } + else + { + for (int i = 0, end(pieces.size()); i < end; ++i) + pieces[i] = m_picker->have_piece(i) ? 1 : 0; + } // write local peers @@ -2714,6 +2736,8 @@ namespace libtorrent TORRENT_ASSERT(p != 0); TORRENT_ASSERT(!p->is_local()); + m_has_incoming = true; + if ((m_state == torrent_status::queued_for_checking || m_state == torrent_status::checking_files) && valid_metadata()) @@ -3115,7 +3139,6 @@ namespace libtorrent if (!is_seed()) { - m_picker->init(m_have_pieces); if (m_sequential_download) picker().sequential_download(m_sequential_download); } @@ -3169,9 +3192,7 @@ namespace libtorrent , "torrent finished checking")); } -#ifndef NDEBUG m_files_checked = true; -#endif } alert_manager& torrent::alerts() const @@ -3289,16 +3310,16 @@ namespace libtorrent if (!m_picker->is_downloaded(i->first)) TORRENT_ASSERT(m_picker->num_peers(i->first) == i->second); } - TORRENT_ASSERT(m_num_pieces >= m_picker->num_have_filtered()); + TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered()); } if (valid_metadata()) { - TORRENT_ASSERT(m_abort || int(m_have_pieces.size()) == m_torrent_file->num_pieces()); + TORRENT_ASSERT(m_abort || !m_picker || m_picker->num_pieces() == m_torrent_file->num_pieces()); } else { - TORRENT_ASSERT(m_abort || m_have_pieces.empty()); + TORRENT_ASSERT(m_abort || m_picker->num_pieces() == 0); } for (policy::const_iterator i = m_policy.begin_peer() @@ -3313,7 +3334,7 @@ namespace libtorrent if (is_seed()) TORRENT_ASSERT(total_done == m_torrent_file->total_size()); else - TORRENT_ASSERT(total_done != m_torrent_file->total_size()); + TORRENT_ASSERT(total_done != m_torrent_file->total_size() || !m_files_checked); } else { @@ -3344,8 +3365,6 @@ namespace libtorrent } // This check is very expensive. - TORRENT_ASSERT(m_num_pieces - == std::count(m_have_pieces.begin(), m_have_pieces.end(), true)); TORRENT_ASSERT(!valid_metadata() || m_block_size > 0); TORRENT_ASSERT(!valid_metadata() || (m_torrent_file->piece_length() % m_block_size) == 0); // if (is_seed()) TORRENT_ASSERT(m_picker.get() == 0); @@ -3412,6 +3431,9 @@ namespace libtorrent } m_sequence_number = (std::min)(max_seq + 1, p); } + + if (m_ses.m_auto_manage_time_scaler > 2) + m_ses.m_auto_manage_time_scaler = 2; } void torrent::set_max_uploads(int limit) @@ -3814,7 +3836,7 @@ namespace libtorrent TORRENT_ASSERT(m_storage->refcount() > 0); TORRENT_ASSERT(piece_index >= 0); TORRENT_ASSERT(piece_index < m_torrent_file->num_pieces()); - TORRENT_ASSERT(piece_index < (int)m_have_pieces.size()); + TORRENT_ASSERT(piece_index < (int)m_picker->num_pieces()); #ifndef NDEBUG if (m_picker) { @@ -3865,6 +3887,12 @@ namespace libtorrent TORRENT_ASSERT(valid_metadata()); fp.clear(); + if (is_seed()) + { + fp.resize(m_torrent_file->num_files(), 1.f); + return; + } + fp.resize(m_torrent_file->num_files(), 0.f); for (int i = 0; i < m_torrent_file->num_files(); ++i) @@ -3885,7 +3913,7 @@ namespace libtorrent { size_type bytes_step = (std::min)(size_type(m_torrent_file->piece_size(ret.piece) - ret.start), size); - if (m_have_pieces[ret.piece]) done += bytes_step; + if (m_picker->have_piece(ret.piece)) done += bytes_step; ++ret.piece; ret.start = 0; size -= bytes_step; @@ -3900,15 +3928,11 @@ namespace libtorrent { INVARIANT_CHECK; - TORRENT_ASSERT(std::accumulate( - m_have_pieces.begin() - , m_have_pieces.end() - , 0) == m_num_pieces); - ptime now = time_now(); torrent_status st; + st.has_incoming = m_has_incoming; st.error = m_error; if (m_last_scrape == min_time()) @@ -4030,8 +4054,14 @@ namespace libtorrent else st.progress = st.total_wanted_done / static_cast(st.total_wanted); - st.pieces = &m_have_pieces; - st.num_pieces = m_num_pieces; + if (has_picker()) + { + int num_pieces = m_picker->num_pieces(); + st.pieces.resize(num_pieces, false); + for (int i = 0; i < num_pieces; ++i) + if (m_picker->have_piece(i)) st.pieces.set_bit(i); + } + st.num_pieces = num_have(); st.num_seeds = num_seeds(); if (m_picker.get()) st.distributed_copies = m_picker->distributed_copies(); diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index 257a05563..fe70c4b92 100755 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -265,6 +265,12 @@ namespace libtorrent TORRENT_FORWARD(save_resume_data()); } + void torrent_handle::force_recheck() const + { + INVARIANT_CHECK; + TORRENT_FORWARD(force_recheck()); + } + void torrent_handle::resume() const { INVARIANT_CHECK; diff --git a/libtorrent/src/web_peer_connection.cpp b/libtorrent/src/web_peer_connection.cpp index a2dc059e2..50402cd34 100755 --- a/libtorrent/src/web_peer_connection.cpp +++ b/libtorrent/src/web_peer_connection.cpp @@ -67,6 +67,7 @@ namespace libtorrent : peer_connection(ses, t, s, remote, peerinfo) , m_url(url) , m_first_request(true) + , m_range_pos(0) { INVARIANT_CHECK; @@ -350,7 +351,8 @@ namespace libtorrent { bool error = false; boost::tie(payload, protocol) = m_parser.incoming(recv_buffer, error); - m_statistics.received_bytes(payload, protocol); + m_statistics.received_bytes(0, protocol); + bytes_transferred -= protocol; if (error) { @@ -363,7 +365,12 @@ namespace libtorrent TORRENT_ASSERT(recv_buffer.left() <= packet_size()); // this means the entire status line hasn't been received yet - if (m_parser.status_code() == -1) break; + if (m_parser.status_code() == -1) + { + TORRENT_ASSERT(payload == 0); + TORRENT_ASSERT(bytes_transferred == 0); + break; + } // if the status code is not one of the accepted ones, abort if (m_parser.status_code() != 206 // partial content @@ -388,15 +395,16 @@ namespace libtorrent disconnect(error_msg.c_str(), 1); return; } - if (!m_parser.header_finished()) break; + if (!m_parser.header_finished()) + { + TORRENT_ASSERT(payload == 0); + TORRENT_ASSERT(bytes_transferred == 0); + break; + } m_body_start = m_parser.body_start(); m_received_body = 0; } - else - { - m_statistics.received_bytes(bytes_transferred, 0); - } // we just completed reading the header if (!header_finished) @@ -460,9 +468,11 @@ namespace libtorrent m_body_start = m_parser.body_start(); m_received_body = 0; + m_range_pos = 0; } recv_buffer.begin += m_body_start; + // we only received the header, no data if (recv_buffer.left() == 0) break; @@ -499,6 +509,13 @@ namespace libtorrent } } + int left_in_response = range_end - range_start - m_range_pos; + int payload_transferred = (std::min)(left_in_response, int(bytes_transferred)); + m_statistics.received_bytes(payload_transferred, 0); + bytes_transferred -= payload_transferred; + m_range_pos += payload_transferred;; + if (m_range_pos > range_end - range_start) m_range_pos = range_end - range_start; + // std::cerr << "REQUESTS: m_requests: " << m_requests.size() // << " file_requests: " << m_file_requests.size() << std::endl; @@ -641,8 +658,9 @@ namespace libtorrent m_received_body = 0; continue; } - break; + if (bytes_transferred == 0) break; } + TORRENT_ASSERT(bytes_transferred == 0); } void web_peer_connection::get_specific_peer_info(peer_info& p) const