From 18cb6736ead421d186d368c8ecae250ca058644b Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 30 Apr 2006 00:39:18 +0000 Subject: [PATCH] fixed a serious bug where corrupt messages could be sent out. --- include/libtorrent/bencode.hpp | 8 ++-- include/libtorrent/peer_connection.hpp | 11 ++++- include/libtorrent/resource_request.hpp | 2 - include/libtorrent/session_settings.hpp | 9 ++++ include/libtorrent/stat.hpp | 8 ++-- src/bt_peer_connection.cpp | 17 ++++++- src/peer_connection.cpp | 63 ++++++++++++++++++------- 7 files changed, 85 insertions(+), 33 deletions(-) diff --git a/include/libtorrent/bencode.hpp b/include/libtorrent/bencode.hpp index ed52a1c76..75a135d8d 100755 --- a/include/libtorrent/bencode.hpp +++ b/include/libtorrent/bencode.hpp @@ -147,17 +147,15 @@ namespace libtorrent } template - std::string read_string(InIt& in, InIt end, int len) + void read_string(InIt& in, InIt end, int len, std::string& str) { assert(len >= 0); - std::string ret; for (int i = 0; i < len; ++i) { if (in == end) throw invalid_encoding(); - ret += *in; + str += *in; ++in; } - return ret; } template @@ -265,7 +263,7 @@ namespace libtorrent ++in; // ':' int len = std::atoi(len_s.c_str()); ret = entry(entry::string_t); - ret.string() = read_string(in, end, len); + read_string(in, end, len, ret.string()); } else { diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index a65976d15..8275a692b 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -313,7 +313,8 @@ namespace libtorrent int send_buffer_size() const { return (int)m_send_buffer[0].size() - + (int)m_send_buffer[1].size(); + + (int)m_send_buffer[1].size() + - m_write_pos; } buffer::const_interval receive_buffer() const @@ -384,11 +385,17 @@ namespace libtorrent // waiting for a async_write operation on one // buffer, the other is used to write data to // be queued up. - buffer m_send_buffer[2]; + std::vector m_send_buffer[2]; +// buffer m_send_buffer[2]; // the current send buffer is the one to write to. // (m_current_send_buffer + 1) % 2 is the // buffer we're currently waiting for. int m_current_send_buffer; + + // if the sending buffer doesn't finish in one send + // operation, this is the position within that buffer + // wher the next operation should continue + int m_write_pos; // timeouts boost::posix_time::ptime m_last_receive; diff --git a/include/libtorrent/resource_request.hpp b/include/libtorrent/resource_request.hpp index 7401163b5..83e4f6dbe 100755 --- a/include/libtorrent/resource_request.hpp +++ b/include/libtorrent/resource_request.hpp @@ -60,8 +60,6 @@ namespace libtorrent { assert(given <= max); assert(given >= min); -// TODO: TEMP! -// assert(given >= used); return given - used; } diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index 6ff4bf20a..926faf6a9 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -42,6 +42,7 @@ namespace libtorrent : piece_timeout(120) , request_queue_time(3.f) , sequenced_download_threshold(7) + , max_allowed_request_queue(200) {} // the number of seconds from a request is sent until @@ -62,6 +63,14 @@ namespace libtorrent // for example, if the threshold is 7, all pieces which 7 // or more peers have, will be downloaded in index order. int sequenced_download_threshold; + + // the number of outstanding block requests a peer is + // allowed to queue up in the client. If a peer sends + // more requests than this (before the first one has + // been sent) the last request will be dropped. + // the higher this is, the faster upload speeds the + // client can get to a single peer. + int max_allowed_request_queue; }; } diff --git a/include/libtorrent/stat.hpp b/include/libtorrent/stat.hpp index 50b4b7d4d..8e92c12a1 100755 --- a/include/libtorrent/stat.hpp +++ b/include/libtorrent/stat.hpp @@ -64,10 +64,10 @@ namespace libtorrent , m_mean_download_payload_rate(0) , m_mean_upload_payload_rate(0) { - std::fill(m_download_rate_history, m_download_rate_history+history, 0); - std::fill(m_upload_rate_history, m_upload_rate_history+history, 0); - std::fill(m_download_payload_rate_history, m_download_payload_rate_history+history, 0); - std::fill(m_upload_payload_rate_history, m_upload_payload_rate_history+history, 0); + std::fill(m_download_rate_history, m_download_rate_history+history, 0.f); + std::fill(m_upload_rate_history, m_upload_rate_history+history, 0.f); + std::fill(m_download_payload_rate_history, m_download_payload_rate_history+history, 0.f); + std::fill(m_upload_payload_rate_history, m_upload_payload_rate_history+history, 0.f); } void operator+=(const stat& s) diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index aa0d902cb..06610c7a3 100755 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -622,7 +622,7 @@ namespace libtorrent int extended_id = detail::read_uint8(recv_buffer.begin); - if (extended_id >= 0 && extended_id < num_supported_extensions + if (extended_id > 0 && extended_id < num_supported_extensions && !m_ses.m_extension_enabled[extended_id]) throw protocol_error("'extended' message using disabled extension"); @@ -1188,6 +1188,8 @@ namespace libtorrent void bt_peer_connection::write_piece(peer_request const& r) { + INVARIANT_CHECK; + const int packet_size = 4 + 5 + 4 + r.length; boost::shared_ptr t = associated_torrent().lock(); @@ -1425,7 +1427,9 @@ namespace libtorrent if (packet_size > 1024*1024 || packet_size < 0) { // packet too large - throw std::runtime_error("packet > 1 MB"); + throw std::runtime_error("packet > 1 MB (" + + boost::lexical_cast( + (unsigned int)packet_size) + " bytes)"); } if (packet_size == 0) @@ -1530,6 +1534,15 @@ namespace libtorrent { if (!m_in_constructor) peer_connection::check_invariant(); + + if (!m_payloads.empty()) + { + for (std::deque::const_iterator i = m_payloads.begin(); + i != m_payloads.end() - 1; ++i) + { + assert(i->start + i->length <= (i+1)->start); + } + } } #endif diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 4a61fcc82..eea438340 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -87,6 +87,7 @@ namespace libtorrent , m_packet_size(0) , m_recv_pos(0) , m_current_send_buffer(0) + , m_write_pos(0) , m_last_receive(second_clock::universal_time()) , m_last_sent(second_clock::universal_time()) , m_socket(s) @@ -176,6 +177,7 @@ namespace libtorrent , m_packet_size(0) , m_recv_pos(0) , m_current_send_buffer(0) + , m_write_pos(0) , m_last_receive(second_clock::universal_time()) , m_last_sent(second_clock::universal_time()) , m_socket(s) @@ -790,7 +792,7 @@ namespace libtorrent return; } - if (m_requests.size() > 100) + if (m_requests.size() > m_ses.m_settings.max_allowed_request_queue) { // don't allow clients to abuse our // memory consumption. @@ -1604,19 +1606,26 @@ namespace libtorrent assert(!m_writing); + int sending_buffer = (m_current_send_buffer + 1) & 1; + if (m_send_buffer[sending_buffer].empty()) + { + // thise means we have to swap buffer, because there's no + // previous buffer we're still waiting for. + std::swap(m_current_send_buffer, sending_buffer); + m_write_pos = 0; + } + // send the actual buffer - if (!m_send_buffer[m_current_send_buffer].empty()) + if (!m_send_buffer[sending_buffer].empty()) { int amount_to_send = std::min(m_ul_bandwidth_quota.left() - , (int)m_send_buffer[m_current_send_buffer].size()); + , (int)m_send_buffer[sending_buffer].size() - m_write_pos); assert(amount_to_send > 0); - +/* buffer::interval_type send_buffer - = m_send_buffer[m_current_send_buffer].data(); - // swap the send buffer for the double buffered effect - m_current_send_buffer = (m_current_send_buffer + 1) & 1; + = m_send_buffer[sending_buffer].data(); // we have data that's scheduled for sending int to_send = std::min(int(send_buffer.first.end - send_buffer.first.begin) @@ -1634,6 +1643,15 @@ namespace libtorrent assert(m_ul_bandwidth_quota.left() >= int(buffer_size(bufs[0]) + buffer_size(bufs[1]))); m_socket->async_write_some(bufs, bind(&peer_connection::on_send_data , self(), _1, _2)); +*/ + + assert(m_write_pos < (int)m_send_buffer[sending_buffer].size()); + m_socket->async_write_some(asio::buffer( + &m_send_buffer[sending_buffer][m_write_pos], amount_to_send) + , bind(&peer_connection::on_send_data, self(), _1, _2)); + +// -------------- + m_writing = true; m_last_write_size = amount_to_send; m_ul_bandwidth_quota.used += m_last_write_size; @@ -1678,7 +1696,8 @@ namespace libtorrent void peer_connection::send_buffer(char const* begin, char const* end) { - m_send_buffer[m_current_send_buffer].insert(begin, end); + m_send_buffer[m_current_send_buffer].insert( + m_send_buffer[m_current_send_buffer].end(), begin, end); setup_send(); } @@ -1686,7 +1705,11 @@ namespace libtorrent // return value is destructed buffer::interval peer_connection::allocate_send_buffer(int size) { - return m_send_buffer[m_current_send_buffer].allocate(size); + m_send_buffer[m_current_send_buffer].resize(m_send_buffer[m_current_send_buffer].size() + size); + buffer::interval ret(&m_send_buffer[m_current_send_buffer][m_send_buffer[m_current_send_buffer].size() - size] + , &m_send_buffer[m_current_send_buffer][0] + m_send_buffer[m_current_send_buffer].size()); + return ret; +// return m_send_buffer[m_current_send_buffer].allocate(size); } template @@ -1715,6 +1738,7 @@ namespace libtorrent assert(m_reading); assert(m_last_read_size > 0); + assert(m_last_read_size >= bytes_transferred); m_reading = false; // correct the dl quota usage, if not all of the buffer was actually read m_dl_bandwidth_quota.used -= m_last_read_size - bytes_transferred; @@ -1828,7 +1852,6 @@ namespace libtorrent (*m_ses.m_logger) << "CONNECTION FAILED: " << m_remote.address().to_string() << "\n"; #endif m_ses.connection_failed(m_socket, m_remote, e.what()); -// disconnect(); return; } @@ -1873,27 +1896,28 @@ namespace libtorrent // correct the ul quota usage, if not all of the buffer was sent m_ul_bandwidth_quota.used -= m_last_write_size - bytes_transferred; m_last_write_size = 0; + m_write_pos += bytes_transferred; if (error) throw std::runtime_error(error.what()); if (m_disconnecting) return; assert(!m_connecting); -// assert(bytes_transferred > 0); + assert(bytes_transferred > 0); int sending_buffer = (m_current_send_buffer + 1) & 1; - m_send_buffer[sending_buffer].erase(bytes_transferred); + + assert(int(m_send_buffer[sending_buffer].size()) >= m_write_pos); + if (int(m_send_buffer[sending_buffer].size()) == m_write_pos) + { + m_send_buffer[sending_buffer].clear(); + m_write_pos = 0; + } m_last_sent = second_clock::universal_time(); on_sent(error, bytes_transferred); fill_send_buffer(); - if (!m_send_buffer[sending_buffer].empty()) - { - // if the send operation didn't send all of the data in the buffer. - // send it again. - m_current_send_buffer = sending_buffer; - } setup_send(); } catch (std::exception& e) @@ -1930,6 +1954,9 @@ namespace libtorrent assert(false); } } + + assert(m_write_pos <= m_send_buffer[ + (m_current_send_buffer + 1) & 1].size()); } #endif