diff --git a/libtorrent/include/libtorrent/bandwidth_manager.hpp b/libtorrent/include/libtorrent/bandwidth_manager.hpp index 70ed67c7c..b6ba86069 100644 --- a/libtorrent/include/libtorrent/bandwidth_manager.hpp +++ b/libtorrent/include/libtorrent/bandwidth_manager.hpp @@ -139,17 +139,21 @@ struct bandwidth_manager } #endif + int queue_size() const + { + mutex_t::scoped_lock l(m_mutex); + return m_queue.size(); + } + // non prioritized means that, if there's a line for bandwidth, // others will cut in front of the non-prioritized peers. // this is used by web seeds void request_bandwidth(intrusive_ptr peer - , int blk - , bool non_prioritized) + , int blk, int priority) { mutex_t::scoped_lock l(m_mutex); INVARIANT_CHECK; TORRENT_ASSERT(blk > 0); - TORRENT_ASSERT(!peer->ignore_bandwidth_limits()); // make sure this peer isn't already in line @@ -163,38 +167,13 @@ struct bandwidth_manager #endif TORRENT_ASSERT(peer->max_assignable_bandwidth(m_channel) > 0); - boost::shared_ptr t = peer->associated_torrent().lock(); - - if (peer->max_assignable_bandwidth(m_channel) == 0) - { - t->expire_bandwidth(m_channel, blk); - peer->assign_bandwidth(m_channel, 0); - return; - } - m_queue.push_back(bw_queue_entry(peer, blk, non_prioritized)); - if (!non_prioritized) - { - typename queue_t::reverse_iterator i = m_queue.rbegin(); - typename queue_t::reverse_iterator j(i); - for (++j; j != m_queue.rend(); ++j) - { - // if the peer's torrent is not the same one - // continue looking for a peer from the same torrent - if (j->peer->associated_torrent().lock() != t) - continue; - // if we found a peer from the same torrent that - // is prioritized, there is no point looking - // any further. - if (!j->non_prioritized) break; - - using std::swap; - swap(*i, *j); - i = j; - } - } -#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT - std::cerr << " req_bandwidht. m_queue.size() = " << m_queue.size() << std::endl; -#endif + typename queue_t::reverse_iterator i(m_queue.rbegin()); + while (i != m_queue.rend() && priority > i->priority) + { + ++i->priority; + ++i; + } + m_queue.insert(i.base(), bw_queue_entry(peer, blk, priority)); if (!m_queue.empty()) hand_out_bandwidth(l); } @@ -207,8 +186,13 @@ struct bandwidth_manager { current_quota += i->amount; } - TORRENT_ASSERT(current_quota == m_current_quota); + + typename queue_t::const_iterator j = m_queue.begin(); + ++j; + for (typename queue_t::const_iterator i = m_queue.begin() + , end(m_queue.end()); i != end && j != end; ++i, ++j) + TORRENT_ASSERT(i->priority >= j->priority); } #endif @@ -302,16 +286,14 @@ private: return; } - queue_t q; queue_t tmp; - m_queue.swap(q); - while (!q.empty() && amount > 0) + while (!m_queue.empty() && amount > 0) { - bw_queue_entry qe = q.front(); + bw_queue_entry qe = m_queue.front(); TORRENT_ASSERT(qe.max_block_size > 0); - q.pop_front(); + m_queue.pop_front(); - shared_ptr t = qe.peer->associated_torrent().lock(); + shared_ptr t = qe.torrent.lock(); if (!t) continue; if (qe.peer->is_disconnecting()) { @@ -371,11 +353,6 @@ private: #ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT std::cerr << " block_size = " << block_size << " amount = " << amount << std::endl; #endif - if (amount < block_size / 2) - { - tmp.push_back(qe); - break; - } // so, hand out max_assignable, but no more than // the available bandwidth (amount) and no more @@ -392,7 +369,6 @@ private: add_history_entry(history_entry( qe.peer, t, hand_out_amount, now + bw_window_size)); } - if (!q.empty()) m_queue.insert(m_queue.begin(), q.begin(), q.end()); if (!tmp.empty()) m_queue.insert(m_queue.begin(), tmp.begin(), tmp.end()); } catch (std::exception& e) diff --git a/libtorrent/include/libtorrent/bandwidth_queue_entry.hpp b/libtorrent/include/libtorrent/bandwidth_queue_entry.hpp index 76c119d96..f8b44846c 100644 --- a/libtorrent/include/libtorrent/bandwidth_queue_entry.hpp +++ b/libtorrent/include/libtorrent/bandwidth_queue_entry.hpp @@ -40,12 +40,15 @@ namespace libtorrent { template struct bw_queue_entry { + typedef typename PeerConnection::torrent_type torrent_type; bw_queue_entry(boost::intrusive_ptr const& pe - , int blk, bool no_prio) - : peer(pe), max_block_size(blk), non_prioritized(no_prio) {} + , int blk, int prio) + : peer(pe), torrent(peer->associated_torrent()) + , max_block_size(blk), priority(prio) {} boost::intrusive_ptr peer; + boost::weak_ptr torrent; int max_block_size; - bool non_prioritized; + int priority; // 0 is low prio }; } diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index 29600ac94..13fab90ca 100755 --- a/libtorrent/include/libtorrent/peer_connection.hpp +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -98,6 +98,8 @@ namespace libtorrent friend class invariant_access; public: + typedef torrent torrent_type; + enum channels { upload_channel, @@ -173,8 +175,8 @@ namespace libtorrent void request_large_blocks(bool b) { m_request_large_blocks = b; } - void set_non_prioritized(bool b) - { m_non_prioritized = b; } + void set_priority(int p) + { m_priority = p; } void fast_reconnect(bool r); bool fast_reconnect() const { return m_fast_reconnect; } @@ -683,11 +685,9 @@ namespace libtorrent // at a time. bool m_request_large_blocks; - // if this is true, other (prioritized) peers will - // skip ahead of it in the queue for bandwidth. The - // effect is that non prioritized peers will only use - // the left-over bandwidth (suitable for web seeds). - bool m_non_prioritized; + // this is the priority with which this peer gets + // download bandwidth quota assigned to it. + int m_priority; int m_upload_limit; int m_download_limit; diff --git a/libtorrent/include/libtorrent/session_status.hpp b/libtorrent/include/libtorrent/session_status.hpp index adbb1b57d..e0a9b88a7 100644 --- a/libtorrent/include/libtorrent/session_status.hpp +++ b/libtorrent/include/libtorrent/session_status.hpp @@ -55,6 +55,9 @@ namespace libtorrent int num_peers; + int up_bandwidth_queue; + int down_bandwidth_queue; + #ifndef TORRENT_DISABLE_DHT int dht_nodes; int dht_node_cache; diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index f66620999..773188cce 100755 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -229,13 +229,12 @@ namespace libtorrent void request_bandwidth(int channel , boost::intrusive_ptr const& p - , bool non_prioritized); + , int priority); void perform_bandwidth_request(int channel , boost::intrusive_ptr const& p - , int block_size - , bool non_prioritized); - + , int block_size, int priority); + void expire_bandwidth(int channel, int amount); void assign_bandwidth(int channel, int amount, int blk); diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index 48a17e2ec..14217d9a4 100755 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -112,6 +112,8 @@ namespace libtorrent , uploads_limit(0) , connections_limit(0) , storage_mode(storage_mode_sparse) + , up_bandwidth_queue(0) + , down_bandwidth_queue(0) {} enum state_t @@ -231,6 +233,9 @@ namespace libtorrent // true if the torrent is saved in compact mode // false if it is saved in full allocation mode storage_mode_t storage_mode; + + int up_bandwidth_queue; + int down_bandwidth_queue; }; struct TORRENT_EXPORT block_info diff --git a/libtorrent/src/pe_crypto.cpp b/libtorrent/src/pe_crypto.cpp index 2e1a7e890..a865b4c73 100644 --- a/libtorrent/src/pe_crypto.cpp +++ b/libtorrent/src/pe_crypto.cpp @@ -86,7 +86,7 @@ namespace libtorrent BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key); // TODO Check return value } - DH_key_exchange::~DH_key_exchange () + DH_key_exchange::~DH_key_exchange() { TORRENT_ASSERT(m_DH); DH_free(m_DH); @@ -108,6 +108,7 @@ namespace libtorrent int secret_size = DH_compute_key((unsigned char*)dh_secret , bn_remote_pubkey, m_DH); + if (secret_size < 0 || secret_size > 96) throw std::bad_alloc(); if (secret_size != 96) { @@ -139,3 +140,4 @@ namespace libtorrent } // namespace libtorrent #endif // #ifndef TORRENT_DISABLE_ENCRYPTION + diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 0cadaabf8..78f1c5ab7 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -109,7 +109,7 @@ namespace libtorrent , m_reading(false) , m_prefer_whole_pieces(false) , m_request_large_blocks(false) - , m_non_prioritized(false) + , m_priority(1) , m_upload_limit(bandwidth_limit::inf) , m_download_limit(bandwidth_limit::inf) , m_peer_info(peerinfo) @@ -186,7 +186,7 @@ namespace libtorrent , m_reading(false) , m_prefer_whole_pieces(false) , m_request_large_blocks(false) - , m_non_prioritized(false) + , m_priority(1) , m_upload_limit(bandwidth_limit::inf) , m_download_limit(bandwidth_limit::inf) , m_peer_info(peerinfo) @@ -1742,7 +1742,8 @@ namespace libtorrent INVARIANT_CHECK; boost::shared_ptr t = m_torrent.lock(); - TORRENT_ASSERT(t); + // this peer might be disconnecting + if (!t) return; TORRENT_ASSERT(t->valid_metadata()); @@ -2485,7 +2486,7 @@ namespace libtorrent // peers that we are not interested in are non-prioritized m_writing = true; t->request_bandwidth(upload_channel, self() - , !(is_interesting() && !has_peer_choked())); + , is_interesting() * 2); } return; } @@ -2538,7 +2539,7 @@ namespace libtorrent (*m_logger) << "req bandwidth [ " << download_channel << " ]\n"; #endif m_reading = true; - t->request_bandwidth(download_channel, self(), m_non_prioritized); + t->request_bandwidth(download_channel, self(), m_priority); } return; } diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index 055bf38db..e435eb619 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -1068,7 +1068,7 @@ namespace detail } // don't allow more connections than the max setting - if (num_connections() > max_connections()) + if (num_connections() >= max_connections()) { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << "number of connections limit exceeded (conns: " @@ -2015,6 +2015,10 @@ namespace detail // INVARIANT_CHECK; session_status s; + + s.up_bandwidth_queue = m_upload_channel.queue_size(); + s.down_bandwidth_queue = m_download_channel.queue_size(); + s.has_incoming_connections = m_incoming_connection; s.num_peers = (int)m_connections.size(); diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index c56090f5d..44062b485 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -2222,7 +2222,11 @@ namespace libtorrent #ifndef NDEBUG std::size_t size = m_connections.size(); #endif - p->disconnect(); + + if (p->is_disconnecting()) + m_connections.erase(m_connections.begin()); + else + p->disconnect(); TORRENT_ASSERT(m_connections.size() <= size); } } @@ -2234,7 +2238,7 @@ namespace libtorrent void torrent::request_bandwidth(int channel , boost::intrusive_ptr const& p - , bool non_prioritized) + , int priority) { TORRENT_ASSERT(m_bandwidth_limit[channel].throttle() > 0); TORRENT_ASSERT(p->max_assignable_bandwidth(channel) > 0); @@ -2243,17 +2247,20 @@ namespace libtorrent if (m_bandwidth_limit[channel].max_assignable() > 0) { - perform_bandwidth_request(channel, p, block_size, non_prioritized); + perform_bandwidth_request(channel, p, block_size, priority); } else { // skip forward in the queue until we find a prioritized peer // or hit the front of it. queue_t::reverse_iterator i = m_bandwidth_queue[channel].rbegin(); - if (!non_prioritized) - while (i != m_bandwidth_queue[channel].rend() && i->non_prioritized) ++i; + while (i != m_bandwidth_queue[channel].rend() && priority > i->priority) + { + ++i->priority; + ++i; + } m_bandwidth_queue[channel].insert(i.base(), bw_queue_entry( - p, block_size, non_prioritized)); + p, block_size, priority)); } } @@ -2277,7 +2284,7 @@ namespace libtorrent continue; } perform_bandwidth_request(channel, qe.peer - , qe.max_block_size, qe.non_prioritized); + , qe.max_block_size, qe.priority); } m_bandwidth_queue[channel].insert(m_bandwidth_queue[channel].begin(), tmp.begin(), tmp.end()); } @@ -2285,10 +2292,10 @@ namespace libtorrent void torrent::perform_bandwidth_request(int channel , boost::intrusive_ptr const& p , int block_size - , bool non_prioritized) + , int priority) { m_ses.m_bandwidth_manager[channel]->request_bandwidth(p - , block_size, non_prioritized); + , block_size, priority); m_bandwidth_limit[channel].assign(block_size); } @@ -2621,6 +2628,15 @@ namespace libtorrent TORRENT_ASSERT(m_bandwidth_queue[0].size() <= m_connections.size()); TORRENT_ASSERT(m_bandwidth_queue[1].size() <= m_connections.size()); + for (int c = 0; c < 2; ++c) + { + queue_t::const_iterator j = m_bandwidth_queue[c].begin(); + ++j; + for (queue_t::const_iterator i = m_bandwidth_queue[c].begin() + , end(m_bandwidth_queue[c].end()); i != end && j != end; ++i, ++j) + TORRENT_ASSERT(i->priority >= j->priority); + } + int num_uploads = 0; std::map num_requests; for (const_peer_iterator i = begin(); i != end(); ++i) @@ -3064,6 +3080,9 @@ namespace libtorrent torrent_status st; + st.up_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::upload_channel].size(); + st.down_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::download_channel].size(); + st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end() , !boost::bind(&peer_connection::is_connecting, _1)); diff --git a/libtorrent/src/web_peer_connection.cpp b/libtorrent/src/web_peer_connection.cpp index 71ce2d430..54eefb8fc 100755 --- a/libtorrent/src/web_peer_connection.cpp +++ b/libtorrent/src/web_peer_connection.cpp @@ -73,7 +73,7 @@ namespace libtorrent // we can request more bytes at once request_large_blocks(true); // we only want left-over bandwidth - set_non_prioritized(true); + set_priority(0); shared_ptr tor = t.lock(); TORRENT_ASSERT(tor); int blocks_per_piece = tor->torrent_file().piece_length() / tor->block_size();