diff --git a/libtorrent/include/libtorrent/bandwidth_manager.hpp b/libtorrent/include/libtorrent/bandwidth_manager.hpp index 68cb7c73a..89efcb9e8 100644 --- a/libtorrent/include/libtorrent/bandwidth_manager.hpp +++ b/libtorrent/include/libtorrent/bandwidth_manager.hpp @@ -124,6 +124,12 @@ struct bandwidth_manager bool is_in_history(PeerConnection const* peer) const { mutex_t::scoped_lock l(m_mutex); + return is_in_history(peer, l); + } + + bool is_in_history(PeerConnection const* peer, boost::mutex::scoped_lock& l) const + { + TORRENT_ASSERT(l.locked()); for (typename history_t::const_iterator i = m_history.begin(), end(m_history.end()); i != end; ++i) { @@ -133,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) throw() + , int blk, int priority) { + mutex_t::scoped_lock l(m_mutex); INVARIANT_CHECK; TORRENT_ASSERT(blk > 0); - - mutex_t::scoped_lock l(m_mutex); TORRENT_ASSERT(!peer->ignore_bandwidth_limits()); // make sure this peer isn't already in line @@ -157,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); } @@ -201,18 +186,24 @@ struct bandwidth_manager { current_quota += i->amount; } - TORRENT_ASSERT(current_quota == m_current_quota); + + typename queue_t::const_iterator j = m_queue.begin(); + if (j != m_queue.end()) + { + ++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 private: - void add_history_entry(history_entry const& e) throw() + void add_history_entry(history_entry const& e) { -#ifndef NDEBUG try { -#endif INVARIANT_CHECK; m_history.push_front(e); m_current_quota += e.amount; @@ -224,24 +215,19 @@ private: m_history_timer.expires_at(e.expires_at); m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1)); -#ifndef NDEBUG } - catch (std::exception&) { TORRENT_ASSERT(false); } -#endif + catch (std::exception&) {} } - void on_history_expire(asio::error_code const& e) throw() + void on_history_expire(asio::error_code const& e) { -#ifndef NDEBUG try { -#endif - INVARIANT_CHECK; - if (e) return; + mutex_t::scoped_lock l(m_mutex); + INVARIANT_CHECK; TORRENT_ASSERT(!m_history.empty()); - mutex_t::scoped_lock l(m_mutex); ptime now(time_now()); while (!m_history.empty() && m_history.back().expires_at <= now) { @@ -268,24 +254,19 @@ private: // means we can hand out more (in case there // are still consumers in line) if (!m_queue.empty()) hand_out_bandwidth(l); -#ifndef NDEBUG } - catch (std::exception&) - { - TORRENT_ASSERT(false); - } -#endif + catch (std::exception&) {} } void hand_out_bandwidth(boost::mutex::scoped_lock& l) throw() { + TORRENT_ASSERT(l.locked()); // if we're already handing out bandwidth, just return back // to the loop further down on the callstack if (m_in_hand_out_bandwidth) return; m_in_hand_out_bandwidth = true; -#ifndef NDEBUG + try { -#endif INVARIANT_CHECK; ptime now(time_now()); @@ -308,24 +289,20 @@ private: return; } - queue_t q; queue_t tmp; - m_queue.swap(q); - while (!q.empty() && amount > 0) + while (!m_queue.empty() && amount > 0) { - TORRENT_ASSERT(amount == limit - m_current_quota); - 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()) { l.unlock(); t->expire_bandwidth(m_channel, qe.max_block_size); l.lock(); - amount = limit - m_current_quota; continue; } @@ -335,7 +312,7 @@ private: int max_assignable = qe.peer->max_assignable_bandwidth(m_channel); if (max_assignable == 0) { - TORRENT_ASSERT(is_in_history(qe.peer.get())); + TORRENT_ASSERT(is_in_history(qe.peer.get(), l)); tmp.push_back(qe); continue; } @@ -379,11 +356,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 @@ -391,7 +363,6 @@ private: int hand_out_amount = (std::min)((std::min)(block_size, max_assignable) , amount); TORRENT_ASSERT(hand_out_amount > 0); - TORRENT_ASSERT(amount == limit - m_current_quota); amount -= hand_out_amount; TORRENT_ASSERT(hand_out_amount <= qe.max_block_size); l.unlock(); @@ -400,15 +371,14 @@ private: l.lock(); add_history_entry(history_entry( qe.peer, t, hand_out_amount, now + bw_window_size)); - amount = limit - m_current_quota; } - 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()); -#ifndef NDEBUG } catch (std::exception& e) - { TORRENT_ASSERT(false); }; -#endif + { + m_in_hand_out_bandwidth = false; + throw; + } m_in_hand_out_bandwidth = false; } 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/http_connection.hpp b/libtorrent/include/libtorrent/http_connection.hpp index 9d32af2e9..b65b303ae 100644 --- a/libtorrent/include/libtorrent/http_connection.hpp +++ b/libtorrent/include/libtorrent/http_connection.hpp @@ -78,7 +78,7 @@ struct http_connection : boost::enable_shared_from_this, boost: , m_download_quota(0) , m_limiter_timer_active(false) , m_limiter_timer(ios) - , m_redirect(true) + , m_redirects(5) , m_connection_ticket(-1) , m_cc(cc) { @@ -93,10 +93,10 @@ struct http_connection : boost::enable_shared_from_this, boost: std::string sendbuffer; void get(std::string const& url, time_duration timeout = seconds(30) - , bool handle_redirect = true); + , int handle_redirects = 5); void start(std::string const& hostname, std::string const& port - , time_duration timeout, bool handle_redirect = true); + , time_duration timeout, int handle_redirect = 5); void close(); tcp::socket const& socket() const { return m_sock; } @@ -153,9 +153,8 @@ private: // as all the quota was used. deadline_timer m_limiter_timer; - // if set to true, the connection should handle - // HTTP redirects. - bool m_redirect; + // the number of redirects to follow (in sequence) + int m_redirects; int m_connection_ticket; connection_queue& m_cc; diff --git a/libtorrent/include/libtorrent/invariant_check.hpp b/libtorrent/include/libtorrent/invariant_check.hpp index 3075b8975..c687b6a63 100755 --- a/libtorrent/include/libtorrent/invariant_check.hpp +++ b/libtorrent/include/libtorrent/invariant_check.hpp @@ -66,7 +66,7 @@ namespace libtorrent } } -#ifndef NDEBUG +#if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS #define INVARIANT_CHECK \ invariant_checker const& _invariant_check = make_invariant_checker(*this); \ (void)_invariant_check; \ diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index 60cb4bc17..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; } @@ -224,7 +226,7 @@ namespace libtorrent void add_stat(size_type downloaded, size_type uploaded); // is called once every second by the main loop - void second_tick(float tick_interval) throw(); + void second_tick(float tick_interval); boost::shared_ptr get_socket() const { return m_socket; } tcp::endpoint const& remote() const { return m_remote; } @@ -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/peer_info.hpp b/libtorrent/include/libtorrent/peer_info.hpp index b07acffd4..e65f33a18 100755 --- a/libtorrent/include/libtorrent/peer_info.hpp +++ b/libtorrent/include/libtorrent/peer_info.hpp @@ -96,8 +96,10 @@ namespace libtorrent // time since last download or upload time_duration last_active; - // the size of the send buffer for this peer + // the size of the send buffer for this peer, in bytes int send_buffer_size; + // the number bytes that's actually used of the send buffer + int used_send_buffer; // the number of failed hashes for this peer int num_hashfails; 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/disk_io_thread.cpp b/libtorrent/src/disk_io_thread.cpp index 886d5d891..e1cfbfe5f 100644 --- a/libtorrent/src/disk_io_thread.cpp +++ b/libtorrent/src/disk_io_thread.cpp @@ -333,7 +333,11 @@ namespace libtorrent catch (std::exception& e) { // std::cerr << "DISK THREAD: exception: " << e.what() << std::endl; - j.str = e.what(); + try + { + j.str = e.what(); + } + catch (std::exception&) {} ret = -1; } diff --git a/libtorrent/src/http_connection.cpp b/libtorrent/src/http_connection.cpp index a73d0a9af..359bd52f6 100644 --- a/libtorrent/src/http_connection.cpp +++ b/libtorrent/src/http_connection.cpp @@ -45,9 +45,8 @@ namespace libtorrent enum { max_bottled_buffer = 1024 * 1024 }; void http_connection::get(std::string const& url, time_duration timeout - , bool handle_redirect) + , int handle_redirects) { - m_redirect = handle_redirect; std::string protocol; std::string auth; std::string hostname; @@ -62,21 +61,23 @@ void http_connection::get(std::string const& url, time_duration timeout headers << "Authorization: Basic " << base64encode(auth) << "\r\n"; headers << "\r\n"; sendbuffer = headers.str(); - start(hostname, boost::lexical_cast(port), timeout); + start(hostname, boost::lexical_cast(port), timeout, handle_redirects); } void http_connection::start(std::string const& hostname, std::string const& port - , time_duration timeout, bool handle_redirect) + , time_duration timeout, int handle_redirects) { - m_redirect = handle_redirect; + m_redirects = handle_redirects; m_timeout = timeout; m_timer.expires_from_now(m_timeout); m_timer.async_wait(bind(&http_connection::on_timeout , boost::weak_ptr(shared_from_this()), _1)); m_called = false; + m_parser.reset(); + m_recvbuffer.clear(); + m_read_pos = 0; if (m_sock.is_open() && m_hostname == hostname && m_port == port) { - m_parser.reset(); asio::async_write(m_sock, asio::buffer(sendbuffer) , bind(&http_connection::on_write, shared_from_this(), _1)); } @@ -233,6 +234,7 @@ void http_connection::on_read(asio::error_code const& e if (e == asio::error::eof) { + TORRENT_ASSERT(bytes_transferred == 0); char const* data = 0; std::size_t size = 0; if (m_bottled && m_parser.header_finished()) @@ -247,6 +249,7 @@ void http_connection::on_read(asio::error_code const& e if (e) { + TORRENT_ASSERT(bytes_transferred == 0); callback(e); close(); return; @@ -255,31 +258,6 @@ void http_connection::on_read(asio::error_code const& e m_read_pos += bytes_transferred; TORRENT_ASSERT(m_read_pos <= int(m_recvbuffer.size())); - // having a nonempty path means we should handle redirects - if (m_redirect && m_parser.header_finished()) - { - int code = m_parser.status_code(); - if (code >= 300 && code < 400) - { - // attempt a redirect - std::string const& url = m_parser.header("location"); - if (url.empty()) - { - // missing location header - callback(e); - return; - } - - m_limiter_timer_active = false; - close(); - - get(url, m_timeout); - return; - } - - m_redirect = false; - } - if (m_bottled || !m_parser.header_finished()) { libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0] @@ -295,6 +273,32 @@ void http_connection::on_read(asio::error_code const& e m_handler.clear(); return; } + + // having a nonempty path means we should handle redirects + if (m_redirects && m_parser.header_finished()) + { + int code = m_parser.status_code(); + + if (code >= 300 && code < 400) + { + // attempt a redirect + std::string const& url = m_parser.header("location"); + if (url.empty()) + { + // missing location header + callback(e); + return; + } + + asio::error_code ec; + m_sock.close(ec); + get(url, m_timeout, m_redirects - 1); + return; + } + + m_redirects = 0; + } + if (!m_bottled && m_parser.header_finished()) { if (m_read_pos > m_parser.body_start()) diff --git a/libtorrent/src/pe_crypto.cpp b/libtorrent/src/pe_crypto.cpp index 093bb1265..a865b4c73 100644 --- a/libtorrent/src/pe_crypto.cpp +++ b/libtorrent/src/pe_crypto.cpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2007, Un Shyam +Copyright (c) 2007, Un Shyam & Arvid Norberg All rights reserved. Redistribution and use in source and binary forms, with or without @@ -40,23 +40,33 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/pe_crypto.hpp" #include "libtorrent/assert.hpp" -namespace libtorrent { +namespace libtorrent +{ - // Set the prime P and the generator, generate local public key - DH_key_exchange::DH_key_exchange () + DH_key_exchange::DH_key_exchange() { - m_DH = DH_new (); + m_DH = DH_new(); + if (m_DH == 0) throw std::bad_alloc(); + + m_DH->p = BN_bin2bn(m_dh_prime, sizeof(m_dh_prime), NULL); + m_DH->g = BN_bin2bn(m_dh_generator, sizeof(m_dh_generator), NULL); + if (m_DH->p == 0 || m_DH->g == 0) + { + DH_free(m_DH); + throw std::bad_alloc(); + } - m_DH->p = BN_bin2bn (m_dh_prime, sizeof(m_dh_prime), NULL); - m_DH->g = BN_bin2bn (m_dh_generator, sizeof(m_dh_generator), NULL); m_DH->length = 160l; TORRENT_ASSERT(sizeof(m_dh_prime) == DH_size(m_DH)); - DH_generate_key (m_DH); // TODO Check != 0 - - TORRENT_ASSERT(m_DH->pub_key); + DH_generate_key(m_DH); + if (m_DH->pub_key == 0) + { + DH_free(m_DH); + throw std::bad_alloc(); + } // DH can generate key sizes that are smaller than the size of // P with exponentially decreasing probability, in which case @@ -76,27 +86,29 @@ 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); + DH_free(m_DH); } - char const* DH_key_exchange::get_local_key () const + char const* DH_key_exchange::get_local_key() const { return m_dh_local_key; } // compute shared secret given remote public key - void DH_key_exchange::compute_secret (char const* remote_pubkey) + void DH_key_exchange::compute_secret(char const* remote_pubkey) { TORRENT_ASSERT(remote_pubkey); BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL); + if (bn_remote_pubkey == 0) throw std::bad_alloc(); char dh_secret[96]; - int secret_size = DH_compute_key ( (unsigned char*)dh_secret, - bn_remote_pubkey, m_DH); // TODO Check for errors + 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) { @@ -104,11 +116,10 @@ namespace libtorrent { std::fill(m_dh_secret, m_dh_secret + 96 - secret_size, 0); } std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size); - - BN_free (bn_remote_pubkey); + BN_free(bn_remote_pubkey); } - char const* DH_key_exchange::get_secret () const + char const* DH_key_exchange::get_secret() const { return m_dh_secret; } @@ -129,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 ac61f042f..0e120e3c8 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) @@ -376,6 +376,7 @@ namespace libtorrent peer_connection::~peer_connection() { // INVARIANT_CHECK; + TORRENT_ASSERT(!m_in_constructor); TORRENT_ASSERT(m_disconnecting); #ifdef TORRENT_VERBOSE_LOGGING @@ -593,6 +594,7 @@ namespace libtorrent // check to make sure we don't have another connection with the same // info_hash and peer_id. If we do. close this connection. t->attach_peer(this); + if (m_disconnecting) return; m_torrent = wpt; TORRENT_ASSERT(!m_torrent.expired()); @@ -1740,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()); @@ -1991,16 +1994,17 @@ namespace libtorrent { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(!m_in_constructor); boost::intrusive_ptr me(this); INVARIANT_CHECK; if (m_disconnecting) return; - m_disconnecting = true; - if (m_connecting) + if (m_connecting && m_connection_ticket >= 0) + { m_ses.m_half_open.done(m_connection_ticket); - - m_ses.m_io_service.post(boost::bind(&close_socket_ignore_error, m_socket)); + m_connection_ticket = -1; + } boost::shared_ptr t = m_torrent.lock(); @@ -2026,7 +2030,9 @@ namespace libtorrent m_torrent.reset(); } + m_disconnecting = true; m_ses.close_connection(me); + m_ses.m_io_service.post(boost::bind(&close_socket_ignore_error, m_socket)); } void peer_connection::set_upload_limit(int limit) @@ -2071,7 +2077,8 @@ namespace libtorrent bool peer_connection::on_local_network() const { - if (libtorrent::is_local(m_remote.address())) return true; + if (libtorrent::is_local(m_remote.address()) + || is_loopback(m_remote.address())) return true; return false; } @@ -2154,6 +2161,7 @@ namespace libtorrent } p.send_buffer_size = m_send_buffer.capacity(); + p.used_send_buffer = m_send_buffer.size(); } void peer_connection::cut_receive_buffer(int size, int packet_size) @@ -2178,7 +2186,7 @@ namespace libtorrent if (m_packet_size >= m_recv_pos) m_recv_buffer.resize(m_packet_size); } - void peer_connection::second_tick(float tick_interval) throw() + void peer_connection::second_tick(float tick_interval) { INVARIANT_CHECK; @@ -2355,8 +2363,7 @@ namespace libtorrent else if (buffer_size_watermark > 80 * 1024) buffer_size_watermark = 80 * 1024; while (!m_requests.empty() - && (send_buffer_size() + m_reading_bytes < buffer_size_watermark) - && !m_choked) + && (send_buffer_size() + m_reading_bytes < buffer_size_watermark)) { TORRENT_ASSERT(t->valid_metadata()); peer_request& r = m_requests.front(); @@ -2482,7 +2489,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; } @@ -2535,7 +2542,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; } @@ -3161,7 +3168,6 @@ namespace libtorrent bool peer_connection::is_seed() const { - INVARIANT_CHECK; // if m_num_pieces == 0, we probably don't have the // metadata yet. return m_num_pieces == (int)m_have_piece.size() && m_num_pieces > 0; diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index 055bf38db..209e833c3 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(); @@ -2437,6 +2441,7 @@ namespace detail boost::shared_ptr t = (*i)->associated_torrent().lock(); peer_connection* p = i->get(); + TORRENT_ASSERT(!p->is_disconnecting()); if (!p->is_choked()) ++unchokes; if (p->peer_info_struct() && p->peer_info_struct()->optimistically_unchoked) diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index 07878e7ee..2f3c7e7f9 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -452,15 +452,19 @@ namespace libtorrent // the directory exists. if (file_iter->size == 0) { - file(m_save_path / file_iter->path, file::out); + try { + file(m_save_path / file_iter->path, file::out); + } catch (std::exception&) {} continue; } - if (allocate_files) - { - m_files.open_file(this, m_save_path / file_iter->path, file::in | file::out) - ->set_size(file_iter->size); - } + try { + if (allocate_files) + { + m_files.open_file(this, m_save_path / file_iter->path, file::in | file::out) + ->set_size(file_iter->size); + } + } catch (std::exception&) {} } // close files that were opened in write mode m_files.release(this); diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 12db1e59b..e04e0be71 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -2164,13 +2164,8 @@ namespace libtorrent throw protocol_error("reached connection limit"); } - TORRENT_ASSERT(m_connections.find(p) == m_connections.end()); - peer_iterator ci = m_connections.insert(p).first; try { - // if new_connection throws, we have to remove the - // it from the list. - #ifndef TORRENT_DISABLE_EXTENSIONS for (extension_list_t::iterator i = m_extensions.begin() , end(m_extensions.end()); i != end; ++i) @@ -2179,15 +2174,14 @@ namespace libtorrent if (pp) p->add_extension(pp); } #endif - TORRENT_ASSERT(m_connections.find(p) == ci); - TORRENT_ASSERT(*ci == p); - m_policy.new_connection(**ci); + m_policy.new_connection(*p); } catch (std::exception& e) { - m_connections.erase(ci); throw; } + TORRENT_ASSERT(m_connections.find(p) == m_connections.end()); + peer_iterator ci = m_connections.insert(p).first; TORRENT_ASSERT(p->remote() == p->get_socket()->remote_endpoint()); #ifndef NDEBUG @@ -2222,7 +2216,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 +2232,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,16 +2241,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(); - 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)); } } @@ -2276,7 +2278,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()); } @@ -2284,10 +2286,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); } @@ -2620,6 +2622,16 @@ 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(); + if (j == m_bandwidth_queue[c].end()) continue; + ++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) @@ -3063,6 +3075,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();