Span conversion (#944)

complete http_parser transition to use span. make xml_parse use span. remove buffer::interval. convert some of receive buffer management to use span<>
This commit is contained in:
Arvid Norberg 2016-07-26 02:15:31 -04:00 committed by GitHub
parent 680a09cfa5
commit 634c2bce60
15 changed files with 108 additions and 146 deletions

View File

@ -286,7 +286,7 @@ namespace libtorrent
, char const* target, int target_size) const; , char const* target, int target_size) const;
// helper to cut down on boilerplate // helper to cut down on boilerplate
void rc4_decrypt(char* pos, int len); void rc4_decrypt(span<char> buf);
#endif #endif
public: public:

View File

@ -75,43 +75,8 @@ class buffer
{ {
public: public:
// TODO: 3 remove interval and const_interval
struct interval
{
interval()
: begin(0)
, end(0)
{}
interval(char* b, char* e)
: begin(b)
, end(e)
{}
char operator[](int index) const
{
TORRENT_ASSERT(begin + index < end);
return begin[index];
}
int left() const
{
TORRENT_ASSERT(end >= begin);
TORRENT_ASSERT(end - begin < (std::numeric_limits<int>::max)());
return int(end - begin);
}
char* begin;
char* end;
};
struct const_interval struct const_interval
{ {
const_interval(interval const& i)
: begin(i.begin)
, end(i.end)
{}
const_interval(char const* b, char const* e) const_interval(char const* b, char const* e)
: begin(b) : begin(b)
, end(e) , end(e)

View File

@ -85,6 +85,7 @@ namespace libtorrent
void pop_front(int bytes_to_pop); void pop_front(int bytes_to_pop);
//TODO: 3 use span<> instead of (buffer,s)
void append_buffer(char* buffer, int s, int used_size void append_buffer(char* buffer, int s, int used_size
, free_buffer_fun destructor, void* userdata , free_buffer_fun destructor, void* userdata
, block_cache_reference ref = block_cache_reference()); , block_cache_reference ref = block_cache_reference());

View File

@ -74,7 +74,7 @@ namespace libtorrent
std::string const& method() const { return m_method; } std::string const& method() const { return m_method; }
std::string const& path() const { return m_path; } std::string const& path() const { return m_path; }
std::string const& message() const { return m_server_message; } std::string const& message() const { return m_server_message; }
buffer::const_interval get_body() const; span<char const> get_body() const;
bool header_finished() const { return m_state == read_body; } bool header_finished() const { return m_state == read_body; }
bool finished() const { return m_finished; } bool finished() const { return m_finished; }
std::tuple<int, int> incoming(span<char const> recv_buffer std::tuple<int, int> incoming(span<char const> recv_buffer

View File

@ -89,8 +89,9 @@ struct TORRENT_EXTRA_EXPORT receive_buffer
buffer::const_interval get() const; buffer::const_interval get() const;
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
// returns the entire buffer // returns the buffer from the current packet start position to the last
buffer::interval mutable_buffer(); // received byte (possibly part of another packet)
span<char> mutable_buffer();
// returns the last 'bytes' from the receive buffer // returns the last 'bytes' from the receive buffer
aux::mutable_buffer mutable_buffer(int bytes); aux::mutable_buffer mutable_buffer(int bytes);
@ -107,6 +108,9 @@ struct TORRENT_EXTRA_EXPORT receive_buffer
void check_invariant() const void check_invariant() const
{ {
TORRENT_ASSERT(m_recv_end >= m_recv_start); TORRENT_ASSERT(m_recv_end >= m_recv_start);
TORRENT_ASSERT(m_recv_end <= int(m_recv_buffer.size()));
TORRENT_ASSERT(m_recv_start <= int(m_recv_buffer.size()));
TORRENT_ASSERT(m_recv_start + m_recv_pos <= int(m_recv_buffer.size()));
} }
#endif #endif
@ -116,7 +120,7 @@ private:
// m_recv_buffer.data() (start of actual receive buffer) // m_recv_buffer.data() (start of actual receive buffer)
// | // |
// | m_recv_start (tart of current packet) // | m_recv_start (start of current packet)
// | | // | |
// | | m_recv_pos (number of bytes consumed // | | m_recv_pos (number of bytes consumed
// | | | by upper layer, from logical receive buffer) // | | | by upper layer, from logical receive buffer)
@ -167,7 +171,7 @@ struct crypto_receive_buffer
: m_connection_buffer(next) : m_connection_buffer(next)
{} {}
buffer::interval mutable_buffer() { return m_connection_buffer.mutable_buffer(); } span<char> mutable_buffer() { return m_connection_buffer.mutable_buffer(); }
bool packet_finished() const; bool packet_finished() const;

View File

@ -33,17 +33,18 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef TORRENT_XML_PARSE_HPP #ifndef TORRENT_XML_PARSE_HPP
#define TORRENT_XML_PARSE_HPP #define TORRENT_XML_PARSE_HPP
#include "libtorrent/aux_/disable_warnings_push.hpp"
#include <cctype> #include <cctype>
#include <cstring> #include <cstring>
#include "libtorrent/aux_/disable_warnings_push.hpp"
#include <boost/function.hpp> #include <boost/function.hpp>
#include "libtorrent/aux_/disable_warnings_pop.hpp" #include "libtorrent/aux_/disable_warnings_pop.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
#include "libtorrent/span.hpp"
namespace libtorrent namespace libtorrent
{ {
@ -68,7 +69,8 @@ namespace libtorrent
// val is attribute value // val is attribute value
// neither string is 0-terminated, but their lengths are specified via // neither string is 0-terminated, but their lengths are specified via
// name_len and val_len respectively // name_len and val_len respectively
TORRENT_EXTRA_EXPORT void xml_parse(char const* p, char const* end // TODO: 3 use span<> for the callback
TORRENT_EXTRA_EXPORT void xml_parse(span<char const> input
, boost::function<void(int,char const*,int,char const*,int)> callback); , boost::function<void(int,char const*,int,char const*,int)> callback);
} }

View File

@ -700,20 +700,19 @@ namespace libtorrent
return -1; return -1;
} }
void bt_peer_connection::rc4_decrypt(char* const pos, int const len) void bt_peer_connection::rc4_decrypt(span<char> buf)
{ {
int consume = 0; int consume = 0;
int produce = len; int produce = int(buf.size());
int packet_size = 0; int packet_size = 0;
aux::mutable_buffer vec(pos, len); m_rc4->decrypt(buf, consume, produce, packet_size);
m_rc4->decrypt(vec, consume, produce, packet_size);
} }
namespace { namespace {
void regular_c_free(char* buf, void* /* userdata */ void regular_c_free(char* buf, void* /* userdata */
, block_cache_reference /* ref */) , block_cache_reference /* ref */)
{ {
::free(buf); std::free(buf);
} }
} }
@ -728,7 +727,7 @@ namespace libtorrent
{ {
// if we're encrypting this buffer, we need to make a copy // if we're encrypting this buffer, we need to make a copy
// since we'll mutate it // since we'll mutate it
char* buf = static_cast<char*>(malloc(size)); char* buf = static_cast<char*>(std::malloc(size));
std::memcpy(buf, buffer, size); std::memcpy(buf, buffer, size);
append_send_buffer(buf, size, &regular_c_free, nullptr); append_send_buffer(buf, size, &regular_c_free, nullptr);
destructor(const_cast<char*>(buffer), userdata, ref); destructor(const_cast<char*>(buffer), userdata, ref);
@ -2735,9 +2734,7 @@ namespace libtorrent
} }
// verify constant // verify constant
buffer::interval wr_recv_buf = m_recv_buffer.mutable_buffer(); rc4_decrypt(m_recv_buffer.mutable_buffer().subspan(20, 8));
rc4_decrypt(wr_recv_buf.begin + 20, 8);
wr_recv_buf.begin += 28;
const char sh_vc[] = {0,0,0,0, 0,0,0,0}; const char sh_vc[] = {0,0,0,0, 0,0,0,0};
if (!std::equal(sh_vc, sh_vc + 8, recv_buffer.begin + 20)) if (!std::equal(sh_vc, sh_vc + 8, recv_buffer.begin + 20))
@ -2781,7 +2778,7 @@ namespace libtorrent
return; return;
} }
std::fill(m_sync_vc.get(), m_sync_vc.get() + 8, 0); std::fill(m_sync_vc.get(), m_sync_vc.get() + 8, 0);
rc4_decrypt(m_sync_vc.get(), 8); rc4_decrypt({m_sync_vc.get(), 8});
} }
TORRENT_ASSERT(m_sync_vc.get()); TORRENT_ASSERT(m_sync_vc.get());
@ -2839,8 +2836,10 @@ namespace libtorrent
if (!m_recv_buffer.packet_finished()) return; if (!m_recv_buffer.packet_finished()) return;
buffer::interval wr_buf = m_recv_buffer.mutable_buffer(); // TODO: 3 this is weird buffer handling
rc4_decrypt(wr_buf.begin, m_recv_buffer.packet_size()); span<char> const buf = m_recv_buffer.mutable_buffer();
TORRENT_ASSERT(buf.size() >= m_recv_buffer.packet_size());
rc4_decrypt({buf.data(), size_t(m_recv_buffer.packet_size())});
recv_buffer = m_recv_buffer.get(); recv_buffer = m_recv_buffer.get();
@ -2944,8 +2943,10 @@ namespace libtorrent
int const pad_size = is_outgoing() ? m_recv_buffer.packet_size() : m_recv_buffer.packet_size() - 2; int const pad_size = is_outgoing() ? m_recv_buffer.packet_size() : m_recv_buffer.packet_size() - 2;
buffer::interval wr_buf = m_recv_buffer.mutable_buffer(); // TODO: 3 this is weird buffer handling
rc4_decrypt(wr_buf.begin, m_recv_buffer.packet_size()); span<char> const buf = m_recv_buffer.mutable_buffer();
TORRENT_ASSERT(buf.size() >= m_recv_buffer.packet_size());
rc4_decrypt({buf.data(), size_t(m_recv_buffer.packet_size())});
recv_buffer = m_recv_buffer.get(); recv_buffer = m_recv_buffer.get();
@ -3003,8 +3004,10 @@ namespace libtorrent
if (!m_recv_buffer.packet_finished()) return; if (!m_recv_buffer.packet_finished()) return;
// ia is always rc4, so decrypt it // ia is always rc4, so decrypt it
buffer::interval wr_buf = m_recv_buffer.mutable_buffer(); // TODO: 3 this is weird buffer handling
rc4_decrypt(wr_buf.begin, m_recv_buffer.packet_size()); span<char> const buf = m_recv_buffer.mutable_buffer();
TORRENT_ASSERT(buf.size() >= m_recv_buffer.packet_size());
rc4_decrypt({buf.data(), size_t(m_recv_buffer.packet_size())});
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::info, "ENCRYPTION" peer_log(peer_log_alert::info, "ENCRYPTION"
@ -3033,13 +3036,13 @@ namespace libtorrent
// decrypt remaining received bytes // decrypt remaining received bytes
if (m_rc4_encrypted) if (m_rc4_encrypted)
{ {
buffer::interval wr_buf = m_recv_buffer.mutable_buffer(); span<char> const remaining = m_recv_buffer.mutable_buffer()
wr_buf.begin += m_recv_buffer.packet_size(); .subspan(m_recv_buffer.packet_size());
rc4_decrypt(wr_buf.begin, wr_buf.left()); rc4_decrypt(remaining);
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::info, "ENCRYPTION" peer_log(peer_log_alert::info, "ENCRYPTION"
, "decrypted remaining %d bytes", wr_buf.left()); , "decrypted remaining %d bytes", int(remaining.size()));
#endif #endif
} }
m_rc4.reset(); m_rc4.reset();

View File

@ -622,6 +622,7 @@ void http_connection::on_connect(error_code const& e)
} }
} }
// TODO: 3 use span<char> instead of data, size
void http_connection::callback(error_code e, char* data, int size) void http_connection::callback(error_code e, char* data, int size)
{ {
if (m_bottled && m_called) return; if (m_bottled && m_called) return;
@ -720,14 +721,13 @@ void http_connection::on_read(error_code const& e
{ {
error_code ec = boost::asio::error::eof; error_code ec = boost::asio::error::eof;
TORRENT_ASSERT(bytes_transferred == 0); TORRENT_ASSERT(bytes_transferred == 0);
char* data = nullptr; span<char> body;
std::size_t size = 0;
if (m_bottled && m_parser.header_finished()) if (m_bottled && m_parser.header_finished())
{ {
data = &m_recvbuffer[0] + m_parser.body_start(); body = span<char>(m_recvbuffer.data() + m_parser.body_start()
size = m_parser.get_body().left(); , m_parser.get_body().size());
} }
callback(ec, data, int(size)); callback(ec, body.data(), int(body.size()));
return; return;
} }
@ -802,7 +802,9 @@ void http_connection::on_read(error_code const& e
{ {
error_code ec; error_code ec;
m_timer.cancel(ec); m_timer.cancel(ec);
callback(e, &m_recvbuffer[0] + m_parser.body_start(), m_parser.get_body().left()); span<char> body(m_recvbuffer.data() + m_parser.body_start()
, m_parser.get_body().size());
callback(e, body.data(), int(body.size()));
} }
} }
else else

View File

@ -518,18 +518,16 @@ restart_response:
return false; return false;
} }
buffer::const_interval http_parser::get_body() const span<char const> http_parser::get_body() const
{ {
TORRENT_ASSERT(m_state == read_body); TORRENT_ASSERT(m_state == read_body);
std::int64_t last_byte = m_chunked_encoding && !m_chunked_ranges.empty() std::int64_t const received = m_recv_pos - m_body_start_pos;
? (std::min)(m_chunked_ranges.back().second, m_recv_pos)
: m_content_length < 0
? m_recv_pos : (std::min)(m_body_start_pos + m_content_length, m_recv_pos);
TORRENT_ASSERT(last_byte >= m_body_start_pos); std::int64_t const body_length = m_chunked_encoding && !m_chunked_ranges.empty()
return buffer::const_interval(m_recv_buffer.data() ? (std::min)(m_chunked_ranges.back().second - m_body_start_pos, received)
+ m_body_start_pos : m_content_length < 0 ? received : (std::min)(m_content_length, received);
, m_recv_buffer.data() + last_byte);
return m_recv_buffer.subspan(m_body_start_pos, body_length);
} }
void http_parser::reset() void http_parser::reset()
@ -563,7 +561,7 @@ restart_response:
// the offsets in the array are from the start of the // the offsets in the array are from the start of the
// buffer, not start of the body, so subtract the size // buffer, not start of the body, so subtract the size
// of the HTTP header from them // of the HTTP header from them
int offset = body_start(); int const offset = body_start();
std::vector<std::pair<std::int64_t, std::int64_t> > const& c = chunks(); std::vector<std::pair<std::int64_t, std::int64_t> > const& c = chunks();
for (std::vector<std::pair<std::int64_t, std::int64_t> >::const_iterator i = c.begin() for (std::vector<std::pair<std::int64_t, std::int64_t> >::const_iterator i = c.begin()
, end(c.end()); i != end; ++i) , end(c.end()); i != end; ++i)

View File

@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <libtorrent/receive_buffer.hpp> #include <libtorrent/receive_buffer.hpp>
#include <libtorrent/invariant_check.hpp>
namespace libtorrent { namespace libtorrent {
@ -41,6 +42,7 @@ int receive_buffer::max_receive() const
boost::asio::mutable_buffer receive_buffer::reserve(int size) boost::asio::mutable_buffer receive_buffer::reserve(int size)
{ {
INVARIANT_CHECK;
TORRENT_ASSERT(size > 0); TORRENT_ASSERT(size > 0);
TORRENT_ASSERT(m_recv_pos >= 0); TORRENT_ASSERT(m_recv_pos >= 0);
@ -64,6 +66,7 @@ boost::asio::mutable_buffer receive_buffer::reserve(int size)
void receive_buffer::grow(int const limit) void receive_buffer::grow(int const limit)
{ {
INVARIANT_CHECK;
int const current_size = int(m_recv_buffer.size()); int const current_size = int(m_recv_buffer.size());
TORRENT_ASSERT(current_size < std::numeric_limits<int>::max() / 3); TORRENT_ASSERT(current_size < std::numeric_limits<int>::max() / 3);
@ -83,6 +86,7 @@ void receive_buffer::grow(int const limit)
int receive_buffer::advance_pos(int bytes) int receive_buffer::advance_pos(int bytes)
{ {
INVARIANT_CHECK;
int const limit = m_packet_size > m_recv_pos ? m_packet_size - m_recv_pos : m_packet_size; int const limit = m_packet_size > m_recv_pos ? m_packet_size - m_recv_pos : m_packet_size;
int const sub_transferred = (std::min)(bytes, limit); int const sub_transferred = (std::min)(bytes, limit);
m_recv_pos += sub_transferred; m_recv_pos += sub_transferred;
@ -94,6 +98,7 @@ int receive_buffer::advance_pos(int bytes)
// offset = the offset into the receive buffer where to remove `size` bytes // offset = the offset into the receive buffer where to remove `size` bytes
void receive_buffer::cut(int const size, int const packet_size, int const offset) void receive_buffer::cut(int const size, int const packet_size, int const offset)
{ {
INVARIANT_CHECK;
TORRENT_ASSERT(packet_size > 0); TORRENT_ASSERT(packet_size > 0);
TORRENT_ASSERT(int(m_recv_buffer.size()) >= size); TORRENT_ASSERT(int(m_recv_buffer.size()) >= size);
TORRENT_ASSERT(int(m_recv_buffer.size()) >= m_recv_pos); TORRENT_ASSERT(int(m_recv_buffer.size()) >= m_recv_pos);
@ -136,37 +141,28 @@ buffer::const_interval receive_buffer::get() const
if (m_recv_buffer.empty()) if (m_recv_buffer.empty())
{ {
TORRENT_ASSERT(m_recv_pos == 0); TORRENT_ASSERT(m_recv_pos == 0);
return buffer::interval(nullptr,nullptr); return buffer::const_interval(nullptr,nullptr);
} }
int rcv_pos = (std::min)(m_recv_pos, int(m_recv_buffer.size()) - m_recv_start); TORRENT_ASSERT(m_recv_start + m_recv_pos <= m_recv_buffer.size());
return buffer::const_interval(&m_recv_buffer[0] + m_recv_start return buffer::const_interval(&m_recv_buffer[0] + m_recv_start
, &m_recv_buffer[0] + m_recv_start + rcv_pos); , &m_recv_buffer[0] + m_recv_start + m_recv_pos);
} }
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
buffer::interval receive_buffer::mutable_buffer() span<char> receive_buffer::mutable_buffer()
{ {
if (m_recv_buffer.empty()) INVARIANT_CHECK;
{ return span<char>(m_recv_buffer).subspan(m_recv_start, m_recv_pos);
TORRENT_ASSERT(m_recv_pos == 0);
return buffer::interval(nullptr,nullptr);
}
int const rcv_pos = (std::min)(m_recv_pos, int(m_recv_buffer.size()));
return buffer::interval(&m_recv_buffer[0] + m_recv_start
, &m_recv_buffer[0] + m_recv_start + rcv_pos);
} }
aux::mutable_buffer receive_buffer::mutable_buffer(int const bytes) aux::mutable_buffer receive_buffer::mutable_buffer(int const bytes)
{ {
INVARIANT_CHECK;
// bytes is the number of bytes we just received, and m_recv_pos has // bytes is the number of bytes we just received, and m_recv_pos has
// already been adjusted for these bytes. The receive pos immediately // already been adjusted for these bytes. The receive pos immediately
// before we received these bytes was (m_recv_pos - bytes) // before we received these bytes was (m_recv_pos - bytes)
int const last_recv_pos = m_recv_pos - bytes; return span<char>(m_recv_buffer).subspan(m_recv_start + m_recv_pos - bytes, bytes);
TORRENT_ASSERT(bytes <= m_recv_pos);
return aux::mutable_buffer(&m_recv_buffer[0] + m_recv_start
+ last_recv_pos, bytes);
} }
#endif #endif
@ -176,6 +172,7 @@ aux::mutable_buffer receive_buffer::mutable_buffer(int const bytes)
// enough of it lately. // enough of it lately.
void receive_buffer::normalize(int force_shrink) void receive_buffer::normalize(int force_shrink)
{ {
INVARIANT_CHECK;
TORRENT_ASSERT(m_recv_end >= m_recv_start); TORRENT_ASSERT(m_recv_end >= m_recv_start);
m_watermark.add_sample(std::max(m_recv_end, m_packet_size)); m_watermark.add_sample(std::max(m_recv_end, m_packet_size));
@ -218,6 +215,7 @@ void receive_buffer::normalize(int force_shrink)
void receive_buffer::reset(int packet_size) void receive_buffer::reset(int packet_size)
{ {
INVARIANT_CHECK;
TORRENT_ASSERT(m_recv_buffer.size() >= m_recv_end); TORRENT_ASSERT(m_recv_buffer.size() >= m_recv_end);
TORRENT_ASSERT(packet_size > 0); TORRENT_ASSERT(packet_size > 0);
if (m_recv_end > m_packet_size) if (m_recv_end > m_packet_size)

View File

@ -940,8 +940,7 @@ void upnp::on_upnp_xml(error_code const& e
} }
parse_state s; parse_state s;
xml_parse(p.get_body().begin, p.get_body().end xml_parse(p.get_body(), std::bind(&find_control_url, _1, _2, _3, boost::ref(s)));
, std::bind(&find_control_url, _1, _2, _3, boost::ref(s)));
if (s.control_url.empty()) if (s.control_url.empty())
{ {
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
@ -1231,14 +1230,14 @@ void upnp::on_upnp_get_ip_address_response(error_code const& e
// </s:Body> // </s:Body>
// </s:Envelope> // </s:Envelope>
span<char const> body = p.get_body();
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
log("get external IP address response: %s" log("get external IP address response: %s"
, std::string(p.get_body().begin, p.get_body().end).c_str()); , std::string(body.data(), body.size()).c_str());
#endif #endif
ip_address_parse_state s; ip_address_parse_state s;
xml_parse(const_cast<char*>(p.get_body().begin), const_cast<char*>(p.get_body().end) xml_parse(body, std::bind(&find_ip_address, _1, _2, boost::ref(s)));
, std::bind(&find_ip_address, _1, _2, boost::ref(s)));
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (s.error_code != -1) if (s.error_code != -1)
{ {
@ -1335,9 +1334,8 @@ void upnp::on_upnp_map_response(error_code const& e
// since those might contain valid UPnP error codes // since those might contain valid UPnP error codes
error_code_parse_state s; error_code_parse_state s;
xml_parse(const_cast<char*>(p.get_body().begin) span<char const> body = p.get_body();
, const_cast<char*>(p.get_body().end) xml_parse(body, std::bind(&find_error_code, _1, _2, boost::ref(s)));
, std::bind(&find_error_code, _1, _2, boost::ref(s)));
if (s.error_code != -1) if (s.error_code != -1)
{ {
@ -1380,7 +1378,7 @@ void upnp::on_upnp_map_response(error_code const& e
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
log("map response: %s" log("map response: %s"
, std::string(p.get_body().begin, p.get_body().end).c_str()); , std::string(body.data(), body.size()).c_str());
#endif #endif
if (s.error_code == -1) if (s.error_code == -1)
@ -1468,17 +1466,16 @@ void upnp::on_upnp_unmap_response(error_code const& e
else else
{ {
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
span<char const> body = p.get_body();
log("unmap response: %s" log("unmap response: %s"
, std::string(p.get_body().begin, p.get_body().end).c_str()); , std::string(body.data(), body.size()).c_str());
#endif #endif
} }
error_code_parse_state s; error_code_parse_state s;
if (p.header_finished()) if (p.header_finished())
{ {
xml_parse(const_cast<char*>(p.get_body().begin) xml_parse(p.get_body(), std::bind(&find_error_code, _1, _2, boost::ref(s)));
, const_cast<char*>(p.get_body().end)
, std::bind(&find_error_code, _1, _2, boost::ref(s)));
} }
int const proto = m_mappings[mapping].protocol; int const proto = m_mappings[mapping].protocol;

View File

@ -95,10 +95,7 @@ namespace libtorrent { namespace
struct ut_metadata_plugin final struct ut_metadata_plugin final
: torrent_plugin : torrent_plugin
{ {
explicit ut_metadata_plugin(torrent& t) explicit ut_metadata_plugin(torrent& t) : m_torrent(t)
: m_torrent(t)
// , m_metadata_progress(0)
, m_metadata_size(0)
{ {
// initialize m_metadata_size // initialize m_metadata_size
if (m_torrent.valid_metadata()) if (m_torrent.valid_metadata())
@ -137,9 +134,9 @@ namespace libtorrent { namespace
return m_metadata_size; return m_metadata_size;
} }
buffer::const_interval metadata() const span<char const> metadata() const
{ {
if (!m_torrent.need_loaded()) return buffer::const_interval(nullptr, nullptr); if (!m_torrent.need_loaded()) return span<char const>();
TORRENT_ASSERT(m_torrent.valid_metadata()); TORRENT_ASSERT(m_torrent.valid_metadata());
if (!m_metadata) if (!m_metadata)
{ {
@ -148,8 +145,7 @@ namespace libtorrent { namespace
TORRENT_ASSERT(hasher(m_metadata.get(), m_metadata_size).final() TORRENT_ASSERT(hasher(m_metadata.get(), m_metadata_size).final()
== m_torrent.torrent_file().info_hash()); == m_torrent.torrent_file().info_hash());
} }
return buffer::const_interval(m_metadata.get(), m_metadata.get() return span<char const>(m_metadata.get(), m_metadata_size);
+ m_metadata_size);
} }
bool received_metadata(ut_metadata_peer_plugin& source bool received_metadata(ut_metadata_peer_plugin& source
@ -159,16 +155,7 @@ namespace libtorrent { namespace
// we should request. // we should request.
// returns -1 if we should hold off the request // returns -1 if we should hold off the request
int metadata_request(bool has_metadata); int metadata_request(bool has_metadata);
/*
// this is called from the peer_connection for
// each piece of metadata it receives
void metadata_progress(int total_size, int received)
{
m_metadata_progress += received;
m_metadata_size = total_size;
m_torrent.set_progress_ppm(std::int64_t(m_metadata_progress) * 1000000 / m_metadata_size);
}
*/
void on_piece_pass(int) override void on_piece_pass(int) override
{ {
// if we became a seed, copy the metadata from // if we became a seed, copy the metadata from
@ -194,8 +181,7 @@ namespace libtorrent { namespace
// it is mutable because it's generated lazily // it is mutable because it's generated lazily
mutable boost::shared_array<char> m_metadata; mutable boost::shared_array<char> m_metadata;
// int m_metadata_progress; mutable int m_metadata_size = 0;
mutable int m_metadata_size;
struct metadata_piece struct metadata_piece
{ {
@ -300,7 +286,7 @@ namespace libtorrent { namespace
// unloaded torrents don't have any metadata. Since we're // unloaded torrents don't have any metadata. Since we're
// about to send the metadata, we need it to be loaded // about to send the metadata, we need it to be loaded
if (!m_tp.need_loaded()) return; if (!m_tp.need_loaded()) return;
metadata = m_tp.metadata().begin + offset; metadata = m_tp.metadata().data() + offset;
metadata_piece_size = (std::min)( metadata_piece_size = (std::min)(
int(m_tp.get_metadata_size() - offset), 16 * 1024); int(m_tp.get_metadata_size() - offset), 16 * 1024);
TORRENT_ASSERT(metadata_piece_size > 0); TORRENT_ASSERT(metadata_piece_size > 0);

View File

@ -37,9 +37,11 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
TORRENT_EXTRA_EXPORT void xml_parse(char const* p, char const* end TORRENT_EXTRA_EXPORT void xml_parse(span<char const> input
, boost::function<void(int,char const*,int,char const*,int)> callback) , boost::function<void(int,char const*,int,char const*,int)> callback)
{ {
char const* p = input.data();
char const* end = input.data() + input.size();
for(;p != end; ++p) for(;p != end; ++p)
{ {
char const* start = p; char const* start = p;

View File

@ -88,7 +88,8 @@ TORRENT_TEST(http_parser)
TEST_CHECK(received == std::make_tuple(4, 64, false)); TEST_CHECK(received == std::make_tuple(4, 64, false));
TEST_CHECK(parser.finished()); TEST_CHECK(parser.finished());
TEST_CHECK(std::equal(parser.get_body().begin, parser.get_body().end, "test")); span<char const> body = parser.get_body();
TEST_CHECK(std::equal(body.begin(), body.end(), "test"));
TEST_CHECK(parser.header("content-type") == "text/plain"); TEST_CHECK(parser.header("content-type") == "text/plain");
TEST_CHECK(atoi(parser.header("content-length").c_str()) == 4); TEST_CHECK(atoi(parser.header("content-length").c_str()) == 4);
@ -109,7 +110,7 @@ TORRENT_TEST(http_parser)
received = feed_bytes(parser, upnp_response); received = feed_bytes(parser, upnp_response);
TEST_CHECK(received == std::make_tuple(0, int(strlen(upnp_response)), false)); TEST_CHECK(received == std::make_tuple(0, int(strlen(upnp_response)), false));
TEST_CHECK(parser.get_body().left() == 0); TEST_CHECK(parser.get_body().empty());
TEST_CHECK(parser.header("st") == "upnp:rootdevice"); TEST_CHECK(parser.header("st") == "upnp:rootdevice");
TEST_CHECK(parser.header("location") TEST_CHECK(parser.header("location")
== "http://192.168.1.1:5431/dyndev/uuid:000f-66d6-7296000099dc"); == "http://192.168.1.1:5431/dyndev/uuid:000f-66d6-7296000099dc");
@ -130,7 +131,7 @@ TORRENT_TEST(http_parser)
received = feed_bytes(parser, http1_response); received = feed_bytes(parser, http1_response);
TEST_CHECK(received == std::make_tuple(0, int(strlen(http1_response)), false)); TEST_CHECK(received == std::make_tuple(0, int(strlen(http1_response)), false));
TEST_CHECK(parser.get_body().left() == 0); TEST_CHECK(parser.get_body().empty());
TEST_CHECK(parser.header("date") == "Fri, 02 Jan 1970 08:10:38 GMT"); TEST_CHECK(parser.header("date") == "Fri, 02 Jan 1970 08:10:38 GMT");
TEST_EQUAL(parser.connection_close(), true); TEST_EQUAL(parser.connection_close(), true);
@ -146,7 +147,7 @@ TORRENT_TEST(http_parser)
received = feed_bytes(parser, close_response); received = feed_bytes(parser, close_response);
TEST_CHECK(received == std::make_tuple(0, int(strlen(close_response)), false)); TEST_CHECK(received == std::make_tuple(0, int(strlen(close_response)), false));
TEST_CHECK(parser.get_body().left() == 0); TEST_CHECK(parser.get_body().empty());
TEST_CHECK(parser.header("date") == "Fri, 02 Jan 1970 08:10:38 GMT"); TEST_CHECK(parser.header("date") == "Fri, 02 Jan 1970 08:10:38 GMT");
TEST_EQUAL(parser.connection_close(), true); TEST_EQUAL(parser.connection_close(), true);
@ -162,7 +163,7 @@ TORRENT_TEST(http_parser)
received = feed_bytes(parser, keep_alive_response); received = feed_bytes(parser, keep_alive_response);
TEST_CHECK(received == std::make_tuple(0, int(strlen(keep_alive_response)), false)); TEST_CHECK(received == std::make_tuple(0, int(strlen(keep_alive_response)), false));
TEST_CHECK(parser.get_body().left() == 0); TEST_CHECK(parser.get_body().empty());
TEST_CHECK(parser.header("date") == "Fri, 02 Jan 1970 08:10:38 GMT"); TEST_CHECK(parser.header("date") == "Fri, 02 Jan 1970 08:10:38 GMT");
TEST_EQUAL(parser.connection_close(), false); TEST_EQUAL(parser.connection_close(), false);
@ -226,7 +227,7 @@ TORRENT_TEST(http_parser)
std::printf("payload: %d protocol: %d\n", std::get<0>(received), std::get<1>(received)); std::printf("payload: %d protocol: %d\n", std::get<0>(received), std::get<1>(received));
TEST_CHECK(received == std::make_tuple(20, int(strlen(chunked_test)) - 20, false)); TEST_CHECK(received == std::make_tuple(20, int(strlen(chunked_test)) - 20, false));
TEST_CHECK(parser.finished()); TEST_CHECK(parser.finished());
TEST_CHECK(std::equal(parser.get_body().begin, parser.get_body().end TEST_CHECK(std::equal(parser.get_body().begin(), parser.get_body().end()
, "4\r\ntest\r\n10\r\n0123456789abcdef")); , "4\r\ntest\r\n10\r\n0123456789abcdef"));
TEST_CHECK(parser.header("test-header") == "foobar"); TEST_CHECK(parser.header("test-header") == "foobar");
TEST_CHECK(parser.header("content-type") == "text/plain"); TEST_CHECK(parser.header("content-type") == "text/plain");
@ -249,7 +250,7 @@ TORRENT_TEST(http_parser)
received = feed_bytes(parser, tracker_response); received = feed_bytes(parser, tracker_response);
TEST_CHECK(received == std::make_tuple(5, int(strlen(tracker_response) - 5), false)); TEST_CHECK(received == std::make_tuple(5, int(strlen(tracker_response) - 5), false));
TEST_CHECK(parser.get_body().left() == 5); TEST_CHECK(parser.get_body().size() == 5);
parser.reset(); parser.reset();
@ -469,8 +470,9 @@ TORRENT_TEST(chunked_encoding)
TEST_CHECK(parser.finished()); TEST_CHECK(parser.finished());
char mutable_buffer[100]; char mutable_buffer[100];
memcpy(mutable_buffer, parser.get_body().begin, parser.get_body().left()); span<char const> body = parser.get_body();
int len = parser.collapse_chunk_headers(mutable_buffer, parser.get_body().left()); memcpy(mutable_buffer, body.begin(), body.size());
int const len = parser.collapse_chunk_headers(mutable_buffer, int(body.size()));
TEST_CHECK(std::equal(mutable_buffer, mutable_buffer + len, "test12340123456789abcdef")); TEST_CHECK(std::equal(mutable_buffer, mutable_buffer + len, "test12340123456789abcdef"));
} }

View File

@ -264,11 +264,15 @@ void parser_callback(std::string& out, int token, char const* s, int len
TEST_CHECK(val == nullptr); TEST_CHECK(val == nullptr);
} }
} }
span<char const> str(char const* in)
{
return span<char const>(in, strlen(in));
}
void test_parse(char const* in, char const* expected) void test_parse(char const* in, char const* expected)
{ {
std::string out; std::string out;
xml_parse(in, in + strlen(in), std::bind(&parser_callback xml_parse(str(in), std::bind(&parser_callback
, boost::ref(out), _1, _2, _3, _4, _5)); , boost::ref(out), _1, _2, _3, _4, _5));
std::fprintf(stderr, "in: %s\n out: %s\nexpected: %s\n" std::fprintf(stderr, "in: %s\n out: %s\nexpected: %s\n"
, in, out.c_str(), expected); , in, out.c_str(), expected);
@ -278,8 +282,7 @@ void test_parse(char const* in, char const* expected)
TORRENT_TEST(upnp_parser1) TORRENT_TEST(upnp_parser1)
{ {
parse_state xml_s; parse_state xml_s;
xml_parse(upnp_xml, upnp_xml + sizeof(upnp_xml) xml_parse(upnp_xml, std::bind(&find_control_url, _1, _2, _3, boost::ref(xml_s)));
, std::bind(&find_control_url, _1, _2, _3, boost::ref(xml_s)));
std::cerr << "namespace " << xml_s.service_type << std::endl; std::cerr << "namespace " << xml_s.service_type << std::endl;
std::cerr << "url_base: " << xml_s.url_base << std::endl; std::cerr << "url_base: " << xml_s.url_base << std::endl;
@ -293,8 +296,7 @@ TORRENT_TEST(upnp_parser1)
TORRENT_TEST(upnp_parser2) TORRENT_TEST(upnp_parser2)
{ {
parse_state xml_s; parse_state xml_s;
xml_parse(upnp_xml2, upnp_xml2 + sizeof(upnp_xml2) xml_parse(upnp_xml2, std::bind(&find_control_url, _1, _2, _3, boost::ref(xml_s)));
, std::bind(&find_control_url, _1, _2, _3, boost::ref(xml_s)));
std::cerr << "namespace " << xml_s.service_type << std::endl; std::cerr << "namespace " << xml_s.service_type << std::endl;
std::cerr << "url_base: " << xml_s.url_base << std::endl; std::cerr << "url_base: " << xml_s.url_base << std::endl;