fixed a serious bug where corrupt messages could be sent out.
This commit is contained in:
parent
d1c33c0d2b
commit
18cb6736ea
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue