fixed a serious bug where corrupt messages could be sent out.

This commit is contained in:
Arvid Norberg 2006-04-30 00:39:18 +00:00
parent d1c33c0d2b
commit 18cb6736ea
7 changed files with 85 additions and 33 deletions

View File

@ -147,17 +147,15 @@ namespace libtorrent
} }
template<class InIt> template<class InIt>
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); assert(len >= 0);
std::string ret;
for (int i = 0; i < len; ++i) for (int i = 0; i < len; ++i)
{ {
if (in == end) throw invalid_encoding(); if (in == end) throw invalid_encoding();
ret += *in; str += *in;
++in; ++in;
} }
return ret;
} }
template<class OutIt> template<class OutIt>
@ -265,7 +263,7 @@ namespace libtorrent
++in; // ':' ++in; // ':'
int len = std::atoi(len_s.c_str()); int len = std::atoi(len_s.c_str());
ret = entry(entry::string_t); ret = entry(entry::string_t);
ret.string() = read_string(in, end, len); read_string(in, end, len, ret.string());
} }
else else
{ {

View File

@ -313,7 +313,8 @@ namespace libtorrent
int send_buffer_size() const int send_buffer_size() const
{ {
return (int)m_send_buffer[0].size() 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 buffer::const_interval receive_buffer() const
@ -384,11 +385,17 @@ namespace libtorrent
// waiting for a async_write operation on one // waiting for a async_write operation on one
// buffer, the other is used to write data to // buffer, the other is used to write data to
// be queued up. // be queued up.
buffer m_send_buffer[2]; std::vector<char> m_send_buffer[2];
// buffer m_send_buffer[2];
// the current send buffer is the one to write to. // the current send buffer is the one to write to.
// (m_current_send_buffer + 1) % 2 is the // (m_current_send_buffer + 1) % 2 is the
// buffer we're currently waiting for. // buffer we're currently waiting for.
int m_current_send_buffer; 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 // timeouts
boost::posix_time::ptime m_last_receive; boost::posix_time::ptime m_last_receive;

View File

@ -60,8 +60,6 @@ namespace libtorrent
{ {
assert(given <= max); assert(given <= max);
assert(given >= min); assert(given >= min);
// TODO: TEMP!
// assert(given >= used);
return given - used; return given - used;
} }

View File

@ -42,6 +42,7 @@ namespace libtorrent
: piece_timeout(120) : piece_timeout(120)
, request_queue_time(3.f) , request_queue_time(3.f)
, sequenced_download_threshold(7) , sequenced_download_threshold(7)
, max_allowed_request_queue(200)
{} {}
// the number of seconds from a request is sent until // 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 // for example, if the threshold is 7, all pieces which 7
// or more peers have, will be downloaded in index order. // or more peers have, will be downloaded in index order.
int sequenced_download_threshold; 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;
}; };
} }

View File

@ -64,10 +64,10 @@ namespace libtorrent
, m_mean_download_payload_rate(0) , m_mean_download_payload_rate(0)
, m_mean_upload_payload_rate(0) , m_mean_upload_payload_rate(0)
{ {
std::fill(m_download_rate_history, m_download_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); 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); 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); std::fill(m_upload_payload_rate_history, m_upload_payload_rate_history+history, 0.f);
} }
void operator+=(const stat& s) void operator+=(const stat& s)

View File

@ -622,7 +622,7 @@ namespace libtorrent
int extended_id = detail::read_uint8(recv_buffer.begin); 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]) && !m_ses.m_extension_enabled[extended_id])
throw protocol_error("'extended' message using disabled extension"); throw protocol_error("'extended' message using disabled extension");
@ -1188,6 +1188,8 @@ namespace libtorrent
void bt_peer_connection::write_piece(peer_request const& r) void bt_peer_connection::write_piece(peer_request const& r)
{ {
INVARIANT_CHECK;
const int packet_size = 4 + 5 + 4 + r.length; const int packet_size = 4 + 5 + 4 + r.length;
boost::shared_ptr<torrent> t = associated_torrent().lock(); boost::shared_ptr<torrent> t = associated_torrent().lock();
@ -1425,7 +1427,9 @@ namespace libtorrent
if (packet_size > 1024*1024 || packet_size < 0) if (packet_size > 1024*1024 || packet_size < 0)
{ {
// packet too large // packet too large
throw std::runtime_error("packet > 1 MB"); throw std::runtime_error("packet > 1 MB ("
+ boost::lexical_cast<std::string>(
(unsigned int)packet_size) + " bytes)");
} }
if (packet_size == 0) if (packet_size == 0)
@ -1530,6 +1534,15 @@ namespace libtorrent
{ {
if (!m_in_constructor) if (!m_in_constructor)
peer_connection::check_invariant(); peer_connection::check_invariant();
if (!m_payloads.empty())
{
for (std::deque<range>::const_iterator i = m_payloads.begin();
i != m_payloads.end() - 1; ++i)
{
assert(i->start + i->length <= (i+1)->start);
}
}
} }
#endif #endif

View File

@ -87,6 +87,7 @@ namespace libtorrent
, m_packet_size(0) , m_packet_size(0)
, m_recv_pos(0) , m_recv_pos(0)
, m_current_send_buffer(0) , m_current_send_buffer(0)
, m_write_pos(0)
, m_last_receive(second_clock::universal_time()) , m_last_receive(second_clock::universal_time())
, m_last_sent(second_clock::universal_time()) , m_last_sent(second_clock::universal_time())
, m_socket(s) , m_socket(s)
@ -176,6 +177,7 @@ namespace libtorrent
, m_packet_size(0) , m_packet_size(0)
, m_recv_pos(0) , m_recv_pos(0)
, m_current_send_buffer(0) , m_current_send_buffer(0)
, m_write_pos(0)
, m_last_receive(second_clock::universal_time()) , m_last_receive(second_clock::universal_time())
, m_last_sent(second_clock::universal_time()) , m_last_sent(second_clock::universal_time())
, m_socket(s) , m_socket(s)
@ -790,7 +792,7 @@ namespace libtorrent
return; 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 // don't allow clients to abuse our
// memory consumption. // memory consumption.
@ -1604,19 +1606,26 @@ namespace libtorrent
assert(!m_writing); 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 // send the actual buffer
if (!m_send_buffer[m_current_send_buffer].empty()) if (!m_send_buffer[sending_buffer].empty())
{ {
int amount_to_send int amount_to_send
= std::min(m_ul_bandwidth_quota.left() = 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); assert(amount_to_send > 0);
/*
buffer::interval_type send_buffer buffer::interval_type send_buffer
= m_send_buffer[m_current_send_buffer].data(); = m_send_buffer[sending_buffer].data();
// swap the send buffer for the double buffered effect
m_current_send_buffer = (m_current_send_buffer + 1) & 1;
// we have data that's scheduled for sending // we have data that's scheduled for sending
int to_send = std::min(int(send_buffer.first.end - send_buffer.first.begin) 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]))); 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 m_socket->async_write_some(bufs, bind(&peer_connection::on_send_data
, self(), _1, _2)); , 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_writing = true;
m_last_write_size = amount_to_send; m_last_write_size = amount_to_send;
m_ul_bandwidth_quota.used += m_last_write_size; 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) 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(); setup_send();
} }
@ -1686,7 +1705,11 @@ namespace libtorrent
// return value is destructed // return value is destructed
buffer::interval peer_connection::allocate_send_buffer(int size) 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<class T> template<class T>
@ -1715,6 +1738,7 @@ namespace libtorrent
assert(m_reading); assert(m_reading);
assert(m_last_read_size > 0); assert(m_last_read_size > 0);
assert(m_last_read_size >= bytes_transferred);
m_reading = false; m_reading = false;
// correct the dl quota usage, if not all of the buffer was actually read // 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; 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"; (*m_ses.m_logger) << "CONNECTION FAILED: " << m_remote.address().to_string() << "\n";
#endif #endif
m_ses.connection_failed(m_socket, m_remote, e.what()); m_ses.connection_failed(m_socket, m_remote, e.what());
// disconnect();
return; return;
} }
@ -1873,27 +1896,28 @@ namespace libtorrent
// correct the ul quota usage, if not all of the buffer was sent // 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_ul_bandwidth_quota.used -= m_last_write_size - bytes_transferred;
m_last_write_size = 0; m_last_write_size = 0;
m_write_pos += bytes_transferred;
if (error) if (error)
throw std::runtime_error(error.what()); throw std::runtime_error(error.what());
if (m_disconnecting) return; if (m_disconnecting) return;
assert(!m_connecting); assert(!m_connecting);
// assert(bytes_transferred > 0); assert(bytes_transferred > 0);
int sending_buffer = (m_current_send_buffer + 1) & 1; 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(); m_last_sent = second_clock::universal_time();
on_sent(error, bytes_transferred); on_sent(error, bytes_transferred);
fill_send_buffer(); 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(); setup_send();
} }
catch (std::exception& e) catch (std::exception& e)
@ -1930,6 +1954,9 @@ namespace libtorrent
assert(false); assert(false);
} }
} }
assert(m_write_pos <= m_send_buffer[
(m_current_send_buffer + 1) & 1].size());
} }
#endif #endif