diff --git a/docs/manual.html b/docs/manual.html index f2f0ff795..9a84eb5cb 100755 --- a/docs/manual.html +++ b/docs/manual.html @@ -1321,9 +1321,10 @@ not trust the fast-resume data and just do the checking.

blocks per piece integer, the number of blocks per piece. Must be: piece_size -/ (16 * 1024). Clamped to be within the range [1, 128]. It +/ (16 * 1024). Clamped to be within the range [1, 256]. It is the number of blocks per (normal sized) piece. Usually -each block is 16 * 1024 bytes in size. +each block is 16 * 1024 bytes in size. But if piece size is +greater than 4 megabytes, the block size will increase. slots

list of integers. The list mappes slots ti piece indices. It diff --git a/docs/manual.rst b/docs/manual.rst index 9cf7c6b56..d4bdc0573 100755 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -559,7 +559,7 @@ It contains the following fields:: int num_peers; - std::vector pieces; + const std::vector* pieces; std::size_t total_done; }; @@ -601,8 +601,9 @@ uploaded to all peers, accumulated, *this session* only. send and received this session, but only the actual oayload data (i.e the interesting data), these counters ignore any protocol overhead. -``pieces`` is the bitmask that representw which pieces we have (set to true) and -the pieces we don't have. +``pieces`` is the bitmask that represents which pieces we have (set to true) and +the pieces we don't have. It's a pointer and may be set to 0 if the torrent isn't +downloading or seeding. ``download_rate`` and ``upload_rate`` are the total rates for all peers for this torrent. These will usually have better precision than summing the rates from @@ -750,7 +751,6 @@ that hasn't been answered with a piece yet. ``upload_queue_length`` is the number of piece-requests we have received from this peer that we haven't answered with a piece yet. - You can know which piece, and which part of that piece, that is currently being downloaded from a specific peer by looking at the next four members. ``downloading_piece_index`` is the index of the piece that is currently being downloaded. @@ -1401,9 +1401,10 @@ The file format is a bencoded dictionary containing the following fields: | | | +----------------------+--------------------------------------------------------------+ | ``blocks per piece`` | integer, the number of blocks per piece. Must be: piece_size | -| | / (16 * 1024). Clamped to be within the range [1, 128]. It | +| | / (16 * 1024). Clamped to be within the range [1, 256]. It | | | is the number of blocks per (normal sized) piece. Usually | -| | each block is 16 * 1024 bytes in size. | +| | each block is 16 * 1024 bytes in size. But if piece size is | +| | greater than 4 megabytes, the block size will increase. | | | | +----------------------+--------------------------------------------------------------+ | ``slots`` | list of integers. The list mappes slots ti piece indices. It | diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 78a789c4d..2cd22d5f6 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -194,6 +194,16 @@ std::string add_suffix(float val) return to_string(val, 6) + prefix[i]; } +std::string progress_bar(float progress, int width) +{ + std::vector bar; + bar.reserve(width); + + std::fill_n(std::back_inserter(bar), progress * width, '#'); + std::fill_n(std::back_inserter(bar), width - (progress * width), '-'); + return std::string(bar.begin(), bar.end()); +} + int main(int argc, char* argv[]) { using namespace libtorrent; @@ -335,15 +345,9 @@ int main(int argc, char* argv[]) out.width(5); out.fill(' '); out << (s.progress*100) << "% "; - for (int i = 0; i < 50; ++i) - { - if (i / 50.f > s.progress) - out << "-"; - else - out << "#"; - } + out << progress_bar(s.progress, 49); out << "\n"; - + out << "total downloaded: " << s.total_done << " Bytes\n"; out << "peers: " << num_peers << " " << "d:" << add_suffix(down) << "/s " << "(" << add_suffix(total_down) << ") " @@ -354,6 +358,8 @@ int main(int argc, char* argv[]) boost::posix_time::time_duration t = s.next_announce; out << "next announce: " << boost::posix_time::to_simple_string(t) << "\n"; + out << "___________________________________\n"; + for (std::vector::iterator i = peers.begin(); i != peers.end(); ++i) @@ -375,25 +381,20 @@ int main(int argc, char* argv[]) << static_cast((i->flags & peer_info::supports_extensions)?"e":"_") << static_cast((i->flags & peer_info::local_connection)?"l":"r") << "\n"; -/* + if (i->downloading_piece_index >= 0) { + out.width(5); + out.fill('0'); out << i->downloading_piece_index << ";" << i->downloading_block_index << ": "; - float progress - = i->downloading_progress - / static_cast(i->downloading_total) - * 35; - for (int j = 0; j < 35; ++j) - { - if (progress > j) out << "#"; - else out << "-"; - } + out << progress_bar( + i->downloading_progress / static_cast(i->downloading_total) + , 50); out << "\n"; } -*/ } -/* + out << "___________________________________\n"; i->get_download_queue(queue); @@ -407,14 +408,14 @@ int main(int argc, char* argv[]) for (int j = 0; j < i->blocks_in_piece; ++j) { if (i->finished_blocks[j]) out << "#"; - else if (i->requested_blocks[j]) out << "="; + else if (i->requested_blocks[j]) out << "+"; else out << "."; } out << "|\n"; } out << "___________________________________\n"; -*/ + } for (std::deque::iterator i = events.begin(); diff --git a/include/libtorrent/peer.hpp b/include/libtorrent/peer.hpp index 2825cccc8..1585c05cf 100755 --- a/include/libtorrent/peer.hpp +++ b/include/libtorrent/peer.hpp @@ -40,18 +40,18 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - struct peer + struct peer_entry { std::string ip; int port; peer_id id; - bool operator==(const peer& p) const + bool operator==(const peer_entry& p) const { return id == p.id; } - bool operator<(const peer& p) const + bool operator<(const peer_entry& p) const { return id < p.id; } diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 8ba26be76..8573024a9 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -199,8 +199,7 @@ namespace libtorrent detail::session_impl& ses , selector& sel , torrent* t - , boost::shared_ptr s - , const peer_id& p); + , boost::shared_ptr s); // with this constructor we have been contacted and we still don't know which torrent the // connection belongs to diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index b49c72147..fba4e7f14 100755 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -69,7 +69,7 @@ namespace libtorrent { public: - enum { max_blocks_per_piece = 128 }; + enum { max_blocks_per_piece = 256 }; struct block_info { @@ -189,6 +189,9 @@ namespace libtorrent int index; }; + int blocks_in_last_piece() const + { return m_blocks_in_last_piece; } + private: struct piece_pos diff --git a/include/libtorrent/policy.hpp b/include/libtorrent/policy.hpp index 51ae7a6ae..0e14ac186 100755 --- a/include/libtorrent/policy.hpp +++ b/include/libtorrent/policy.hpp @@ -101,46 +101,20 @@ namespace libtorrent void check_invariant(); #endif - private: - - // TODO: for the moment the peer_id is never updated - // when we get it from the peer. It's kindof useless - // in here right now. - - struct peer_identification - { - peer_identification() - : ip(0,0) - { - id.set_to_all_zero(); - } - - peer_identification(address a, const peer_id &p) - : ip(a) - , id(p) - { - } - // If this info comes from a remote connection, - // port should be set to 0 to denote that the port is unknown. - address ip; - peer_id id; - }; - struct peer { - peer(const peer_identification &pid); + peer(const address& ip); int total_download() const; int total_upload() const; - // the id of the peer. This is needed to store information - // about peers that aren't connected right now. This - // is to avoid peers reconnecting. unconnected entries - // will be saved a limited amount of time - + enum connection_type { local_connection, remote_connection }; // the ip/port pair this peer is or was connected on - - peer_identification id; + // if it was a remote (incoming) connection, type is + // set thereafter. If it was a peer we got from the + // tracker, type is set to local_connection. + address id; + connection_type type; // the time when this peer was optimistically unchoked // the last time. @@ -170,34 +144,7 @@ namespace libtorrent peer_connection* connection; }; - // predicate used to check if two peers with likelyness are the same one - struct peer_information_matches - { - peer_information_matches(const peer_identification &id) - : this_id(id) - { - } - - bool operator()(const peer&other_peer) const - { - return operator()(other_peer.id); - } - - bool operator()(const peer_identification &other_id) const - { - return - this_id.ip.ip() == other_id.ip.ip() -// && ( -// this_id.ip.port() == other_id.ip.port() -// || ((this_id.ip.port() == 0) ^ (other_id.ip.port() == 0)) // one of them unknown -// ) - && ( - this_id.id == other_id.id - || (this_id.id.is_all_zeros() ^ other_id.id.is_all_zeros()) // one of them unknown - ); - } - peer_identification this_id; - }; + private: bool unchoke_one_peer(); peer* find_choke_candidate(); diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 417eb946f..1dc13662f 100755 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -85,7 +85,7 @@ namespace libtorrent // workaround for microsofts // hardware exceptions that makes // it hard to debug stuff -#if !defined(NDEBUG) && defined(MSC_VER) +#if !defined(NDEBUG) && defined(_MSC_VER) struct eh_initializer { eh_initializer() diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index e83c02063..bdf809b7f 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -143,12 +143,11 @@ namespace libtorrent stat statistics() const { return m_stat; } size_type bytes_left() const; + size_type bytes_done() const; torrent_status status() const; - peer_connection& connect_to_peer( - const address& a - , const peer_id& id); + peer_connection& connect_to_peer(const address& a); const torrent_info& torrent_file() const { return m_torrent_file; } @@ -174,6 +173,7 @@ namespace libtorrent // this will remove the peer and make sure all // the pieces it had have their reference counter // decreased in the piece_picker + // called from the peer_connection destructor void remove_peer(peer_connection* p); peer_connection* connection_for(const address& a) @@ -188,7 +188,7 @@ namespace libtorrent // returns true if this torrent has a connection // to a peer with the given peer_id - bool has_peer(const peer_id& id) const; +// bool has_peer(const peer_id& id) const; typedef std::map::iterator peer_iterator; typedef std::map::const_iterator const_peer_iterator; @@ -207,7 +207,7 @@ namespace libtorrent // when this torrent got a response from its tracker request virtual void tracker_response(const entry& e); virtual void tracker_request_timed_out(); - virtual void tracker_request_error(const char* str); + virtual void tracker_request_error(int response_code, const char* str); // generates a request string for sending // to the tracker @@ -305,7 +305,7 @@ namespace libtorrent event_id m_event; - void parse_response(const entry& e, std::vector& peer_list); + void parse_response(const entry& e, std::vector& peer_list); torrent_info m_torrent_file; diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index 042edb1d5..51b618dc1 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -63,6 +63,8 @@ namespace libtorrent struct torrent_status { + typedef entry::integer_type size_type; + torrent_status() : state(queued_for_checking) , progress(0.f) @@ -73,6 +75,7 @@ namespace libtorrent , download_rate(0) , upload_rate(0) , num_peers(0) + , pieces(0) , total_done(0) {} @@ -91,12 +94,12 @@ namespace libtorrent // transferred this session! // total, payload plus protocol - std::size_t total_download; - std::size_t total_upload; + size_type total_download; + size_type total_upload; // payload only - std::size_t total_payload_download; - std::size_t total_payload_upload; + size_type total_payload_download; + size_type total_payload_upload; // current transfer rate // payload plus protocol @@ -107,10 +110,10 @@ namespace libtorrent // is connected to. int num_peers; - std::vector pieces; + const std::vector* pieces; // the number of bytes of the file we have - std::size_t total_done; + size_type total_done; }; struct partial_piece_info diff --git a/src/alert.cpp b/src/alert.cpp index 07dc8afe2..fdae1a2e6 100755 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -49,6 +49,7 @@ namespace libtorrent { void alert_manager::post_alert(const alert& alert_) { + // TODO: have an internal buffer limit boost::mutex::scoped_lock lock(m_mutex); if (m_severity <= alert_.severity()) diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index cd944b380..0853be309 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -76,8 +76,7 @@ namespace libtorrent detail::session_impl& ses , selector& sel , torrent* t - , boost::shared_ptr s - , const peer_id& p) + , boost::shared_ptr s) : m_state(read_protocol_length) , m_timeout(120) , m_packet_size(1) @@ -91,7 +90,6 @@ namespace libtorrent , m_ses(ses) , m_active(true) , m_added_to_selector(false) - , m_peer_id(p) , m_peer_interested(false) , m_peer_choked(true) , m_interesting(false) @@ -113,6 +111,8 @@ namespace libtorrent m_logger = m_ses.create_log(s->sender().as_string().c_str()); #endif + std::fill(m_peer_id.begin(), m_peer_id.end(), 0); + // initialize the extension list to zero, since // we don't know which extensions the other // end supports yet @@ -165,6 +165,8 @@ namespace libtorrent { assert(!m_socket->is_blocking()); + std::fill(m_peer_id.begin(), m_peer_id.end(), 0); + #ifndef NDEBUG m_logger = m_ses.create_log(s->sender().as_string().c_str()); #endif @@ -696,6 +698,8 @@ namespace libtorrent if (verified) { m_torrent->announce_piece(p.piece); + // TODO: if we bacame a seed, disconnect + // from all seeds } else { @@ -1128,7 +1132,6 @@ namespace libtorrent - m_statistics.total_payload_upload(); } - void peer_connection::second_tick() { m_statistics.second_tick(); @@ -1372,14 +1375,6 @@ namespace libtorrent // info_hash and peer_id. If we do. close this connection. std::copy(m_recv_buffer.begin(), m_recv_buffer.begin() + 20, (char*)m_peer_id.begin()); - if (m_torrent->has_peer(m_peer_id)) - { - #ifndef NDEBUG - (*m_logger) << " duplicate connection, closing\n"; - #endif - throw protocol_error("duplicate connection, closing"); - } - m_attached_to_torrent = true; m_torrent->attach_peer(this); assert(m_torrent->get_policy().has_connection(this)); diff --git a/src/policy.cpp b/src/policy.cpp index 1a84818e7..268915031 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -47,6 +47,11 @@ POSSIBILITY OF SUCH DAMAGE. # define for if (false) {} else for #endif +namespace libtorrent +{ + class peer_connection; +} + namespace { enum @@ -261,6 +266,32 @@ namespace } return free_upload; } + + struct match_peer_ip + { + match_peer_ip(const address& id) + : m_id(id) + {} + + bool operator()(const policy::peer& p) const + { return p.id.ip() == m_id.ip(); } + + address m_id; + }; + + struct match_peer_connection + { + match_peer_connection(const peer_connection& c) + : m_conn(c) + {} + + bool operator()(const policy::peer& p) const + { return p.connection == &m_conn; } + + const peer_connection& m_conn; + }; + + } namespace libtorrent @@ -366,10 +397,7 @@ namespace libtorrent { if(i->connection) continue; if(i->banned) continue; - if(i->id.ip.port()==0) continue; - - // TODO: Don't connect to peers that were discovered through - // remote connection, since we don't know the port. + if(i->type == peer::remote_connection) continue; assert(i->connected <= local_time); @@ -510,13 +538,11 @@ namespace libtorrent void policy::ban_peer(const peer_connection& c) { - address a(c.get_socket()->sender()); - if(!c.is_local()) - a=address(a.ip(),0); - peer_identification id(a,c.get_peer_id()); + std::vector::iterator i = std::find_if( + m_peers.begin() + , m_peers.end() + , match_peer_connection(c)); - std::vector::iterator i = - std::find_if(m_peers.begin(), m_peers.end(), peer_information_matches(id)); assert(i != m_peers.end()); i->banned = true; @@ -525,12 +551,11 @@ namespace libtorrent void policy::new_connection(peer_connection& c) { assert(!c.is_local()); - assert(!c.get_peer_id().is_all_zeros()); - peer_identification pid(address(c.get_socket()->sender().ip(),0),c.get_peer_id()); - - std::vector::iterator i = - std::find_if(m_peers.begin(), m_peers.end(), peer_information_matches(pid)); + std::vector::iterator i = std::find_if( + m_peers.begin() + , m_peers.end() + , match_peer_ip(c.get_socket()->sender())); if (i == m_peers.end()) { @@ -540,30 +565,33 @@ namespace libtorrent // we don't have ny info about this peer. // add a new entry - peer p(pid); + peer p(c.get_socket()->sender()); m_peers.push_back(p); i = m_peers.end()-1; } else { - assert(i->connection == 0); - if (i->banned) throw protocol_error("ip address banned, disconnected"); + if (i->connection != 0) + throw protocol_error("duplicate connection, closing"); + if (i->banned) + throw protocol_error("ip address banned, disconnected"); } + assert(i->connection == 0); i->connection = &c; i->connected = boost::posix_time::second_clock::local_time(); } void policy::peer_from_tracker(const address& remote, const peer_id& id) { - assert(remote.ip()!=0); - assert(remote.port()!=0); + assert(remote.ip() != 0); + assert(remote.port() != 0); try { - peer_identification pid(remote,id); - - std::vector::iterator i = - std::find_if(m_peers.begin(), m_peers.end(), peer_information_matches(pid)); + std::vector::iterator i = std::find_if( + m_peers.begin() + , m_peers.end() + , match_peer_ip(remote)); if (i == m_peers.end()) { @@ -572,20 +600,21 @@ namespace libtorrent // we don't have ny info about this peer. // add a new entry - peer p(pid); + peer p(remote); + p.type = peer::local_connection; m_peers.push_back(p); + // the iterator is invalid + // because of the push_back() i = m_peers.end()-1; } else { + i->type = peer::local_connection; + // in case we got the ip from a remote connection, port is // not known, so save it. Client may also have changed port // for some reason. - i->id.ip=remote; - - // fill in peer id if missing - if(!id.is_all_zeros()) - i->id.id=id; + i->id = remote; if (i->connection) { @@ -599,7 +628,7 @@ namespace libtorrent if (i->banned) return; - i->connection = &m_torrent->connect_to_peer(remote, id); + i->connection = &m_torrent->connect_to_peer(remote); i->connected = boost::posix_time::second_clock::local_time(); return; } @@ -707,12 +736,12 @@ namespace libtorrent bool policy::connect_one_peer() { peer* p = find_connect_candidate(); - if (p==0) return false; + if (p == 0) return false; assert(!p->banned); assert(!p->connection); - assert(p->id.ip.port()!=0); + assert(p->type != peer::remote_connection); - p->connection = &m_torrent->connect_to_peer(p->id.ip, p->id.id); + p->connection = &m_torrent->connect_to_peer(p->id); p->connected = boost::posix_time::second_clock::local_time(); return true; } @@ -720,16 +749,13 @@ namespace libtorrent // this is called whenever a peer connection is closed void policy::connection_closed(const peer_connection& c) { - address a(c.get_socket()->sender()); - if(!c.is_local()) - a=address(a.ip(),0); + std::vector::iterator i = std::find_if( + m_peers.begin() + , m_peers.end() + , match_peer_connection(c)); - peer_identification cid(a,c.get_peer_id()); - std::vector::iterator i = - std::find_if(m_peers.begin(), m_peers.end(), peer_information_matches(cid)); - - assert(i != m_peers.end()); - assert(i->connection==&c); + if (i == m_peers.end()) return; + assert(i->connection == &c); i->connected = boost::posix_time::second_clock::local_time(); i->prev_amount_download += c.statistics().total_payload_download(); @@ -768,13 +794,10 @@ namespace libtorrent #ifndef NDEBUG bool policy::has_connection(const peer_connection* c) { - address a(c->get_socket()->sender()); - if(!c->is_local()) - a=address(a.ip(),0); - peer_identification id(a,c->get_peer_id()); - - return m_peers.end() != - std::find_if(m_peers.begin(), m_peers.end(), peer_information_matches(id)); + return std::find_if( + m_peers.begin() + , m_peers.end() + , match_peer_ip(c->get_socket()->sender())) != m_peers.end(); } void policy::check_invariant() @@ -792,12 +815,11 @@ namespace libtorrent } #endif - policy::peer::peer( - const peer_identification& pid) + policy::peer::peer(const address& pid) : id(pid) + , type(remote_connection) , last_optimistically_unchoked( boost::gregorian::date(1970,boost::gregorian::Jan,1)) - //, connected(boost::posix_time::second_clock::local_time()) , connected(boost::gregorian::date(1970,boost::gregorian::Jan,1)) , prev_amount_upload(0) , prev_amount_download(0) @@ -810,18 +832,26 @@ namespace libtorrent int policy::peer::total_download() const { if (connection != 0) + { return connection->statistics().total_payload_download() + prev_amount_download; + } else + { return prev_amount_download; + } } int policy::peer::total_upload() const { if (connection != 0) + { return connection->statistics().total_payload_upload() + prev_amount_upload; + } else + { return prev_amount_upload; + } } } diff --git a/src/session.cpp b/src/session.cpp index 0cfa03217..c4667754b 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -935,7 +935,7 @@ namespace libtorrent int num_blocks_per_piece = rd.dict()["blocks per piece"].integer(); - if (num_blocks_per_piece > 128 || num_blocks_per_piece < 1) + if (num_blocks_per_piece != info.piece_length() / torrent_ptr->block_size()) return; // the unfinished pieces diff --git a/src/storage.cpp b/src/storage.cpp index d103dd291..f8ce41f30 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -465,7 +465,6 @@ namespace libtorrent { m_pimpl->export_piece_map(p); } - // TODO: daniel, make sure this function does everything it needs to do void piece_manager::impl::mark_failed(int piece_index) { // synchronization ------------------------------------------------------ diff --git a/src/torrent.cpp b/src/torrent.cpp index d34861b62..991ca9366 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -84,9 +84,9 @@ namespace } // if pieces are too large, adjust the block size - if (i.piece_length() / default_block_size > 128) + if (i.piece_length() / default_block_size > piece_picker::max_blocks_per_piece) { - return i.piece_length() / 128; + return i.piece_length() / piece_picker::max_blocks_per_piece; } // otherwise, go with the default @@ -94,9 +94,9 @@ namespace } - peer extract_peer_info(const entry& e) + peer_entry extract_peer_info(const entry& e) { - peer ret; + peer_entry ret; const entry::dictionary_type& info = e.dict(); @@ -126,6 +126,7 @@ namespace return ret; } +/* struct find_peer_by_id { find_peer_by_id(const peer_id& i, const torrent* t): id(i), tor(t) {} @@ -143,14 +144,14 @@ namespace const peer_id& id; const torrent* tor; }; - +*/ struct find_peer_by_ip { find_peer_by_ip(const address& a, const torrent* t): ip(a), tor(t) {} bool operator()(const detail::session_impl::connection_map::value_type& c) const { - if (c.first->sender() != ip) return false; + if (c.first->sender().ip() != ip.ip()) return false; if (tor != c.second->associated_torrent()) return false; return true; } @@ -159,7 +160,6 @@ namespace const torrent* tor; }; - struct peer_by_id { peer_by_id(const peer_id& i): id(i) {} @@ -269,7 +269,7 @@ namespace libtorrent void torrent::tracker_response(const entry& e) { - std::vector peer_list; + std::vector peer_list; try { // parse the response @@ -289,7 +289,7 @@ namespace libtorrent std::stringstream s; s << "interval: " << m_duration << "\n"; s << "peers:\n"; - for (std::vector::const_iterator i = peer_list.begin(); + for (std::vector::const_iterator i = peer_list.begin(); i != peer_list.end(); ++i) { @@ -300,7 +300,7 @@ namespace libtorrent debug_log(s.str()); #endif // for each of the peers we got from the tracker - for (std::vector::iterator i = peer_list.begin(); + for (std::vector::iterator i = peer_list.begin(); i != peer_list.end(); ++i) { @@ -310,39 +310,22 @@ namespace libtorrent address a(i->ip, i->port); - // if we aleady have a connection to the person, don't make another one - if (std::find_if( - m_ses.m_connections.begin() - , m_ses.m_connections.end() - , find_peer_by_id(i->id, this)) != m_ses.m_connections.end()) - { - continue; - } - - if (std::find_if( - m_ses.m_connections.begin() - , m_ses.m_connections.end() - , find_peer_by_ip(a, this)) != m_ses.m_connections.end()) - { - continue; - } - m_policy->peer_from_tracker(a, i->id); } } catch(type_error& e) { - tracker_request_error(e.what()); + tracker_request_error(-1, e.what()); } catch(std::runtime_error& e) { - tracker_request_error(e.what()); + tracker_request_error(-1, e.what()); } m_got_tracker_response = true; } - +/* bool torrent::has_peer(const peer_id& id) const { assert(std::count_if(m_connections.begin() @@ -360,21 +343,77 @@ namespace libtorrent , peer_by_id(id)) != m_connections.end(); } +*/ torrent::size_type torrent::bytes_left() const { - size_type have_bytes = m_num_pieces * m_torrent_file.piece_length(); - int last_piece = m_torrent_file.num_pieces()-1; - if (m_have_pieces[last_piece]) - { - have_bytes -= m_torrent_file.piece_length() - - m_torrent_file.piece_size(last_piece); - } - - return m_torrent_file.total_size() - - have_bytes; + return m_torrent_file.total_size() - bytes_done(); } + torrent::size_type torrent::bytes_done() const + { + const int last_piece = m_torrent_file.num_pieces()-1; + + torrent::size_type total_done + = m_num_pieces * 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]) + { + total_done -= m_torrent_file.piece_length(); + total_done += m_torrent_file.piece_size(last_piece); + } + + const std::vector& dl_queue + = m_picker.get_download_queue(); + + const int blocks_per_piece = m_torrent_file.piece_length() / m_block_size; + + for (std::vector::const_iterator i = + dl_queue.begin(); + i != dl_queue.end(); + ++i) + { + assert(!m_have_pieces[i->index]); + + for (int j = 0; j < blocks_per_piece; ++j) + { + total_done += (i->finished_blocks[j]) * m_block_size; + } + + // correction if this was the last piece + // and if we have the last block + if (i->index == last_piece + && i->finished_blocks[m_picker.blocks_in_last_piece()-1]) + { + total_done -= m_block_size; + total_done += m_torrent_file.piece_size(last_piece) % m_block_size; + } + } + + // TODO: may report too much if two peers are downloading + // the same block + for (const_peer_iterator i = begin(); + i != end(); + ++i) + { + boost::optional p + = i->second->downloading_piece(); + if (p) + { + if (m_have_pieces[p->piece_index]) + continue; + if (m_picker.is_finished(piece_block(p->piece_index, p->block_index))) + continue; + + total_done += p->bytes_downloaded; + assert(p->bytes_downloaded <= p->full_block_bytes); + } + } + return total_done; + } void torrent::piece_failed(int index) { @@ -422,7 +461,6 @@ namespace libtorrent m_picker.restore_piece(index); m_storage.mark_failed(index); - // TODO: make sure restore_piece() works assert(m_have_pieces[index] == false); } @@ -446,32 +484,6 @@ namespace libtorrent m_picker.we_have(index); for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i) i->second->announce_piece(index); - - // if we became a seed, disconnect from all other seeds - if (is_seed()) - { - for (peer_iterator i = m_connections.begin(); - i != m_connections.end();) - { - assert(i->second->associated_torrent() == this); - - if (!i->second->is_seed()) continue; - - detail::session_impl::connection_map::iterator j = - m_ses.m_connections.find(i->second->get_socket()); - - assert(j != m_ses.m_connections.end()); - - // in the destructor of the peer_connection - // it will remove itself from this torrent - // and from the list we're iterating over. - // so we need to increment the iterator riht - // away. - ++i; - - m_ses.m_connections.erase(j); - } - } } std::string torrent::generate_tracker_request(int port) @@ -515,7 +527,7 @@ namespace libtorrent return request; } - void torrent::parse_response(const entry& e, std::vector& peer_list) + void torrent::parse_response(const entry& e, std::vector& peer_list) { entry::dictionary_type::const_iterator i = e.dict().find("failure reason"); if (i != e.dict().end()) @@ -537,7 +549,7 @@ namespace libtorrent const entry::list_type& l = i->second.list(); for(entry::list_type::const_iterator i = l.begin(); i != l.end(); ++i) { - peer p = extract_peer_info(*i); + peer_entry p = extract_peer_info(*i); peer_list.push_back(p); } } @@ -585,7 +597,7 @@ namespace libtorrent #endif } - peer_connection& torrent::connect_to_peer(const address& a, const peer_id& id) + peer_connection& torrent::connect_to_peer(const address& a) { boost::shared_ptr s(new socket(socket::tcp, false)); s->connect(a); @@ -593,8 +605,7 @@ namespace libtorrent m_ses , m_ses.m_selector , this - , s - , id)); + , s)); if (m_ses.m_upload_rate != -1) c->set_send_quota(0); @@ -753,25 +764,14 @@ namespace libtorrent torrent_status torrent::status() const { + assert(std::accumulate( + m_have_pieces.begin() + , m_have_pieces.end() + , 0) == m_num_pieces); + torrent_status st; - const std::vector& p = m_have_pieces; - assert(std::accumulate(p.begin(), p.end(), 0) == m_num_pieces); - - int total_blocks - = (m_torrent_file.total_size()+m_block_size-1)/m_block_size; - int blocks_per_piece - = m_torrent_file.piece_length() / m_block_size; - - int unverified_blocks = m_picker.unverified_blocks(); - - int blocks_we_have = m_num_pieces * blocks_per_piece; - const int last_piece = m_torrent_file.num_pieces()-1; - if (p[last_piece]) - { - blocks_we_have += m_picker.blocks_in_piece(last_piece) - - blocks_per_piece; - } + st.total_done = bytes_done(); // payload transfer st.total_payload_download = m_stat.total_payload_download(); @@ -787,23 +787,19 @@ namespace libtorrent st.download_rate = m_stat.download_rate(); st.upload_rate = m_stat.upload_rate(); - st.progress = (blocks_we_have + unverified_blocks) - / static_cast(total_blocks); + st.progress = st.total_done + / static_cast(m_torrent_file.total_size()); st.next_announce = next_announce() - boost::posix_time::second_clock::local_time(); st.num_peers = m_connections.size(); - // TODO: this is not accurate because it assumes the last - // block is m_block_size bytes - // TODO: st.pieces could be a const pointer maybe? - st.total_done = (blocks_we_have + unverified_blocks) * m_block_size; - st.pieces = m_have_pieces; + st.pieces = &m_have_pieces; if (m_got_tracker_response == false) st.state = torrent_status::connecting_to_tracker; - else if (m_num_pieces == p.size()) + else if (m_num_pieces == m_have_pieces.size()) st.state = torrent_status::seeding; else st.state = torrent_status::downloading; @@ -837,7 +833,7 @@ namespace libtorrent // with some codes, we should just consider // the tracker as a failure and not retry // it anymore - void torrent::tracker_request_error(const char* str) + void torrent::tracker_request_error(int response_code, const char* str) { #ifndef NDEBUG debug_log(std::string("*** tracker error: ") + str); diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 9012927a4..013eba4c0 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -51,10 +51,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/hasher.hpp" #include "libtorrent/entry.hpp" #include "libtorrent/session.hpp" -// TODO: peer_connection is only used because of detail::write_int -// and detail::read_int, they should probably be moved to a common -// header. -#include "libtorrent/peer_connection.hpp" #if defined(_MSC_VER) && _MSC_VER < 1300 namespace std @@ -121,8 +117,6 @@ namespace libtorrent st.state = torrent_status::queued_for_checking; st.progress = d->progress; st.next_announce = boost::posix_time::time_duration(); - st.pieces.clear(); - st.pieces.resize(d->torrent_ptr->torrent_file().num_pieces(), false); return st; } }