use array_view instead of std::vector in crypto_plugin interface (#835)

use array_view instead of std::vector in crypto_plugin interface. return a vector of const_buffers for prepending new buffers. use stack allocated (single buffer) iovecs for receives. general cleanup
This commit is contained in:
Arvid Norberg 2016-06-19 23:05:59 -04:00 committed by GitHub
parent b2358666a1
commit a9dbbdea37
13 changed files with 206 additions and 165 deletions

View File

@ -46,11 +46,12 @@ namespace libtorrent { namespace aux {
// T -> const T conversion constructor // T -> const T conversion constructor
template <typename U, typename template <typename U, typename
= std::enable_if<std::is_convertible<U, T>::value> = std::enable_if<std::is_convertible<U*, T*>::value>
> >
array_view(array_view<U> const& v) array_view(array_view<U> const& v)
: m_ptr(v.data()), m_len(v.size()) {} : m_ptr(v.data()), m_len(v.size()) {}
array_view(T& p) : m_ptr(&p), m_len(1) {}
array_view(T* p, int l) : m_ptr(p), m_len(l) array_view(T* p, int l) : m_ptr(p), m_len(l)
{ {
TORRENT_ASSERT(l >= 0); TORRENT_ASSERT(l >= 0);
@ -69,8 +70,14 @@ namespace libtorrent { namespace aux {
size_t size() const { return m_len; } size_t size() const { return m_len; }
T* data() const { return m_ptr; } T* data() const { return m_ptr; }
using iterator = T*;
using reverse_iterator = std::reverse_iterator<T*>;
T* begin() const { return m_ptr; } T* begin() const { return m_ptr; }
T* end() const { return m_ptr + m_len; } T* end() const { return m_ptr + m_len; }
reverse_iterator rbegin() const { return reverse_iterator(end()); }
reverse_iterator rend() const { return reverse_iterator(begin()); }
T& front() const { TORRENT_ASSERT(m_len > 0); return m_ptr[0]; } T& front() const { TORRENT_ASSERT(m_len > 0); return m_ptr[0]; }
T& back() const { TORRENT_ASSERT(m_len > 0); return m_ptr[m_len-1]; } T& back() const { TORRENT_ASSERT(m_len > 0); return m_ptr[m_len-1]; }

View File

@ -159,7 +159,10 @@ namespace libtorrent
void on_receive_impl(std::size_t bytes_transferred); void on_receive_impl(std::size_t bytes_transferred);
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
virtual int hit_send_barrier(std::vector<boost::asio::mutable_buffer>& iovec) override; // next_barrier, buffers-to-prepend
virtual
std::tuple<int, aux::array_view<boost::asio::const_buffer>>
hit_send_barrier(aux::array_view<boost::asio::mutable_buffer> iovec) override;
#endif #endif
virtual void get_specific_peer_info(peer_info& p) const override; virtual void get_specific_peer_info(peer_info& p) const override;

View File

@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
// TODO: 2 this type should probably be renamed to send_buffer
struct TORRENT_EXTRA_EXPORT chained_buffer : private single_threaded struct TORRENT_EXTRA_EXPORT chained_buffer : private single_threaded
{ {
chained_buffer(): m_bytes(0), m_capacity(0) chained_buffer(): m_bytes(0), m_capacity(0)
@ -67,6 +68,9 @@ namespace libtorrent
{ {
free_buffer_fun free_fun; free_buffer_fun free_fun;
void* userdata; void* userdata;
// TODO: 2 the pointers here should probably be const, since
// they're not supposed to be mutated once inserted into the send
// buffer
char* buf; // the first byte of the buffer char* buf; // the first byte of the buffer
char* start; // the first byte to send/receive in the buffer char* start; // the first byte to send/receive in the buffer
int size; // the total size of the buffer int size; // the total size of the buffer

View File

@ -173,6 +173,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/sha1_hash.hpp" // for sha1_hash #include "libtorrent/sha1_hash.hpp" // for sha1_hash
#include "libtorrent/error_code.hpp" #include "libtorrent/error_code.hpp"
#include "libtorrent/session_handle.hpp" #include "libtorrent/session_handle.hpp"
#include "libtorrent/aux_/array_view.hpp"
namespace libtorrent namespace libtorrent
{ {
@ -502,9 +503,13 @@ namespace libtorrent
// are now ready to be sent to the lower layer. This must be at least // are now ready to be sent to the lower layer. This must be at least
// as large as the number of bytes passed in and may be larger if there // as large as the number of bytes passed in and may be larger if there
// is additional data to be inserted at the head of the send buffer. // is additional data to be inserted at the head of the send buffer.
// The additional data is retrieved from the passed in vector. The // The additional data is returned as the second tupled value. Any
// vector must be cleared if no additional data is to be inserted. // returned buffer as well as the iovec itself, to be prepended to the
virtual int encrypt(std::vector<boost::asio::mutable_buffer>& /*send_vec*/) = 0; // send buffer, must be owned by the crypto plugin and guaranteed to stay
// alive until the crypto_plugin is destructed or this function is called
// again.
virtual std::tuple<int, aux::array_view<boost::asio::const_buffer>>
encrypt(aux::array_view<boost::asio::mutable_buffer> /*send_vec*/) = 0;
// decrypt the provided buffers. // decrypt the provided buffers.
// consume is set to the number of bytes which should be trimmed from the // consume is set to the number of bytes which should be trimmed from the
@ -515,7 +520,7 @@ namespace libtorrent
// //
// packet_size is set to the minimum number of bytes which must be read to // packet_size is set to the minimum number of bytes which must be read to
// advance the next step of decryption. default is 0 // advance the next step of decryption. default is 0
virtual void decrypt(std::vector<boost::asio::mutable_buffer>& /*receive_vec*/ virtual void decrypt(aux::array_view<boost::asio::mutable_buffer> /*receive_vec*/
, int& /* consume */, int& /*produce*/, int& /*packet_size*/) = 0; , int& /* consume */, int& /*produce*/, int& /*packet_size*/) = 0;
}; };
} }

View File

@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/sha1_hash.hpp" #include "libtorrent/sha1_hash.hpp"
#include "libtorrent/extensions.hpp" #include "libtorrent/extensions.hpp"
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
#include "libtorrent/aux_/array_view.hpp"
#include <list> #include <list>
#include <array> #include <array>
@ -98,8 +99,11 @@ namespace libtorrent
struct encryption_handler struct encryption_handler
{ {
int encrypt(std::vector<boost::asio::mutable_buffer>& iovec); std::tuple<int, aux::array_view<boost::asio::const_buffer>>
int decrypt(crypto_receive_buffer& recv_buffer, std::size_t& bytes_transferred); encrypt(aux::array_view<boost::asio::mutable_buffer> iovec);
int decrypt(crypto_receive_buffer& recv_buffer
, std::size_t& bytes_transferred);
bool switch_send_crypto(boost::shared_ptr<crypto_plugin> crypto bool switch_send_crypto(boost::shared_ptr<crypto_plugin> crypto
, int pending_encryption); , int pending_encryption);
@ -140,8 +144,10 @@ namespace libtorrent
void set_incoming_key(unsigned char const* key, int len) override; void set_incoming_key(unsigned char const* key, int len) override;
void set_outgoing_key(unsigned char const* key, int len) override; void set_outgoing_key(unsigned char const* key, int len) override;
int encrypt(std::vector<boost::asio::mutable_buffer>& buf) override; std::tuple<int, aux::array_view<boost::asio::const_buffer>>
void decrypt(std::vector<boost::asio::mutable_buffer>& buf encrypt(aux::array_view<boost::asio::mutable_buffer> buf) override;
void decrypt(aux::array_view<boost::asio::mutable_buffer> buf
, int& consume , int& consume
, int& produce , int& produce
, int& packet_size) override; , int& packet_size) override;

View File

@ -61,19 +61,21 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/receive_buffer.hpp" #include "libtorrent/receive_buffer.hpp"
#include "libtorrent/aux_/allocating_handler.hpp" #include "libtorrent/aux_/allocating_handler.hpp"
#include "libtorrent/debug.hpp" #include "libtorrent/debug.hpp"
#include "libtorrent/aux_/array_view.hpp"
#include "libtorrent/aux_/disable_warnings_push.hpp"
#include <ctime> #include <ctime>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <string> #include <string>
#include <utility> // for std::forward #include <utility> // for std::forward
#include <tuple> // for make_tuple
#include <array>
#include "libtorrent/aux_/disable_warnings_push.hpp"
#include <boost/smart_ptr.hpp> #include <boost/smart_ptr.hpp>
#include <boost/weak_ptr.hpp> #include <boost/weak_ptr.hpp>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <array>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <cstdint> #include <cstdint>
@ -747,8 +749,10 @@ namespace libtorrent
void send_piece_suggestions(int num); void send_piece_suggestions(int num);
virtual int hit_send_barrier(std::vector<boost::asio::mutable_buffer>&) virtual
{ return INT_MAX; } std::tuple<int, aux::array_view<boost::asio::const_buffer>>
hit_send_barrier(aux::array_view<boost::asio::mutable_buffer> /* iovec */)
{ return std::make_tuple(INT_MAX, aux::array_view<boost::asio::const_buffer>()); }
void attach_to_torrent(sha1_hash const& ih); void attach_to_torrent(sha1_hash const& ih);

View File

@ -36,7 +36,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <libtorrent/buffer.hpp> #include <libtorrent/buffer.hpp>
#include <libtorrent/disk_buffer_holder.hpp> #include <libtorrent/disk_buffer_holder.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <vector>
namespace libtorrent { namespace libtorrent {
@ -110,7 +109,7 @@ struct TORRENT_EXTRA_EXPORT receive_buffer
buffer::interval mutable_buffer(); buffer::interval mutable_buffer();
// returns the last 'bytes' from the receive buffer // returns the last 'bytes' from the receive buffer
boost::asio::mutable_buffer mutable_buffers(int bytes); boost::asio::mutable_buffer mutable_buffer(int bytes);
#endif #endif
// the purpose of this function is to free up and cut off all messages // the purpose of this function is to free up and cut off all messages
@ -226,7 +225,7 @@ struct crypto_receive_buffer
buffer::const_interval get() const; buffer::const_interval get() const;
boost::asio::mutable_buffer mutable_buffers(std::size_t bytes); boost::asio::mutable_buffer mutable_buffer(std::size_t bytes);
private: private:
// explicitly disallow assignment, to silence msvc warning // explicitly disallow assignment, to silence msvc warning

View File

@ -515,7 +515,7 @@ namespace libtorrent
return; return;
} }
int pad_size = random() % 512; int const pad_size = random() % 512;
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::info, "ENCRYPTION", "pad size: %d", pad_size); peer_log(peer_log_alert::info, "ENCRYPTION", "pad size: %d", pad_size);
@ -523,7 +523,7 @@ namespace libtorrent
char msg[dh_key_len + 512]; char msg[dh_key_len + 512];
char* ptr = msg; char* ptr = msg;
int buf_size = dh_key_len + pad_size; int const buf_size = dh_key_len + pad_size;
mp::export_bits(m_dh_key_exchange->get_local_key() mp::export_bits(m_dh_key_exchange->get_local_key()
, reinterpret_cast<std::uint8_t*>(ptr), 8); , reinterpret_cast<std::uint8_t*>(ptr), 8);
@ -610,8 +610,7 @@ namespace libtorrent
#endif #endif
write_pe_vc_cryptofield(ptr, encrypt_size, crypto_provide, pad_size); write_pe_vc_cryptofield(ptr, encrypt_size, crypto_provide, pad_size);
std::vector<boost::asio::mutable_buffer> vec; boost::asio::mutable_buffer vec(ptr, encrypt_size);
vec.push_back(boost::asio::mutable_buffer(ptr, encrypt_size));
m_rc4->encrypt(vec); m_rc4->encrypt(vec);
send_buffer(msg, sizeof(msg) - 512 + pad_size); send_buffer(msg, sizeof(msg) - 512 + pad_size);
} }
@ -626,14 +625,13 @@ namespace libtorrent
TORRENT_ASSERT(crypto_select == 0x02 || crypto_select == 0x01); TORRENT_ASSERT(crypto_select == 0x02 || crypto_select == 0x01);
TORRENT_ASSERT(!m_sent_handshake); TORRENT_ASSERT(!m_sent_handshake);
int pad_size = random() % 512; int const pad_size = random() % 512;
const int buf_size = 8 + 4 + 2 + pad_size; int const buf_size = 8 + 4 + 2 + pad_size;
char msg[512 + 8 + 4 + 2]; char msg[512 + 8 + 4 + 2];
write_pe_vc_cryptofield(msg, sizeof(msg), crypto_select, pad_size); write_pe_vc_cryptofield(msg, sizeof(msg), crypto_select, pad_size);
std::vector<boost::asio::mutable_buffer> vec; boost::asio::mutable_buffer vec(msg, buf_size);
vec.push_back(boost::asio::mutable_buffer(msg, buf_size));
m_rc4->encrypt(vec); m_rc4->encrypt(vec);
send_buffer(msg, buf_size); send_buffer(msg, buf_size);
@ -649,8 +647,10 @@ namespace libtorrent
#endif #endif
} }
void bt_peer_connection::write_pe_vc_cryptofield(char* write_buf, int len void bt_peer_connection::write_pe_vc_cryptofield(char* write_buf
, int crypto_field, int pad_size) , int const len
, int const crypto_field
, int const pad_size)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
#if !TORRENT_USE_ASSERTS #if !TORRENT_USE_ASSERTS
@ -682,15 +682,15 @@ namespace libtorrent
detail::write_uint16(handshake_len, write_buf); // len(IA) detail::write_uint16(handshake_len, write_buf); // len(IA)
} }
int bt_peer_connection::get_syncoffset(char const* src, int src_size, int bt_peer_connection::get_syncoffset(char const* src, int const src_size
char const* target, int target_size) const , char const* target, int const target_size) const
{ {
TORRENT_ASSERT(target_size >= src_size); TORRENT_ASSERT(target_size >= src_size);
TORRENT_ASSERT(src_size > 0); TORRENT_ASSERT(src_size > 0);
TORRENT_ASSERT(src); TORRENT_ASSERT(src);
TORRENT_ASSERT(target); TORRENT_ASSERT(target);
int traverse_limit = target_size - src_size; int const traverse_limit = target_size - src_size;
// TODO: this could be optimized using knuth morris pratt // TODO: this could be optimized using knuth morris pratt
for (int i = 0; i < traverse_limit; ++i) for (int i = 0; i < traverse_limit; ++i)
@ -700,40 +700,16 @@ namespace libtorrent
return i; return i;
} }
// Partial sync
// for (int i = 0; i < target_size; ++i)
// {
// // first is iterator in src[] at which mismatch occurs
// // second is iterator in target[] at which mismatch occurs
// std::pair<const char*, const char*> ret;
// int src_sync_size;
// if (i > traverse_limit) // partial sync test
// {
// ret = std::mismatch(src, src + src_size - (i - traverse_limit), &target[i]);
// src_sync_size = ret.first - src;
// if (src_sync_size == (src_size - (i - traverse_limit)))
// return i;
// }
// else // complete sync test
// {
// ret = std::mismatch(src, src + src_size, &target[i]);
// src_sync_size = ret.first - src;
// if (src_sync_size == src_size)
// return i;
// }
// }
// no complete sync // no complete sync
return -1; return -1;
} }
void bt_peer_connection::rc4_decrypt(char* pos, int len) void bt_peer_connection::rc4_decrypt(char* const pos, int const len)
{ {
std::vector<boost::asio::mutable_buffer> vec;
vec.push_back(boost::asio::mutable_buffer(pos, len));
int consume = 0; int consume = 0;
int produce = len; int produce = len;
int packet_size = 0; int packet_size = 0;
boost::asio::mutable_buffer vec(pos, len);
m_rc4->decrypt(vec, consume, produce, packet_size); m_rc4->decrypt(vec, consume, produce, packet_size);
} }
@ -2172,9 +2148,8 @@ namespace libtorrent
// add predictive pieces to the bitfield as well, since we won't // add predictive pieces to the bitfield as well, since we won't
// announce them again // announce them again
for (std::vector<int>::const_iterator i = t->predictive_pieces().begin() for (int p : t->predictive_pieces())
, end(t->predictive_pieces().end()); i != end; ++i) msg[5 + p / 8] |= (0x80 >> (p & 7));
msg[5 + *i / 8] |= (0x80 >> (*i & 7));
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
std::string bitfield_string; std::string bitfield_string;
@ -2531,7 +2506,7 @@ namespace libtorrent
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
if (!m_enc_handler.is_recv_plaintext()) if (!m_enc_handler.is_recv_plaintext())
{ {
int consumed = m_enc_handler.decrypt(m_recv_buffer, bytes_transferred); int const consumed = m_enc_handler.decrypt(m_recv_buffer, bytes_transferred);
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (consumed + bytes_transferred > 0) if (consumed + bytes_transferred > 0)
peer_log(peer_log_alert::incoming_message, "ENCRYPTION" peer_log(peer_log_alert::incoming_message, "ENCRYPTION"
@ -2974,7 +2949,7 @@ namespace libtorrent
bytes_transferred = 0; bytes_transferred = 0;
if (!m_recv_buffer.packet_finished()) return; if (!m_recv_buffer.packet_finished()) return;
int 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(); buffer::interval wr_buf = m_recv_buffer.mutable_buffer();
rc4_decrypt(wr_buf.begin, m_recv_buffer.packet_size()); rc4_decrypt(wr_buf.begin, m_recv_buffer.packet_size());
@ -3480,8 +3455,8 @@ namespace libtorrent
return; return;
} }
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
std::int64_t cur_payload_dl = statistics().last_payload_downloaded(); std::int64_t const cur_payload_dl = statistics().last_payload_downloaded();
std::int64_t cur_protocol_dl = statistics().last_protocol_downloaded(); std::int64_t const cur_protocol_dl = statistics().last_protocol_downloaded();
#endif #endif
if (dispatch_message(int(bytes_transferred))) if (dispatch_message(int(bytes_transferred)))
{ {
@ -3492,7 +3467,7 @@ namespace libtorrent
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
TORRENT_ASSERT(statistics().last_payload_downloaded() - cur_payload_dl >= 0); TORRENT_ASSERT(statistics().last_payload_downloaded() - cur_payload_dl >= 0);
TORRENT_ASSERT(statistics().last_protocol_downloaded() - cur_protocol_dl >= 0); TORRENT_ASSERT(statistics().last_protocol_downloaded() - cur_protocol_dl >= 0);
std::int64_t stats_diff = statistics().last_payload_downloaded() - cur_payload_dl + std::int64_t const stats_diff = statistics().last_payload_downloaded() - cur_payload_dl +
statistics().last_protocol_downloaded() - cur_protocol_dl; statistics().last_protocol_downloaded() - cur_protocol_dl;
TORRENT_ASSERT(stats_diff == std::int64_t(bytes_transferred)); TORRENT_ASSERT(stats_diff == std::int64_t(bytes_transferred));
TORRENT_ASSERT(!m_recv_buffer.packet_finished()); TORRENT_ASSERT(!m_recv_buffer.packet_finished());
@ -3504,15 +3479,19 @@ namespace libtorrent
} }
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
int bt_peer_connection::hit_send_barrier(std::vector<boost::asio::mutable_buffer>& iovec) std::tuple<int, aux::array_view<boost::asio::const_buffer>>
bt_peer_connection::hit_send_barrier(
aux::array_view<boost::asio::mutable_buffer> iovec)
{ {
int next_barrier = m_enc_handler.encrypt(iovec); int next_barrier;
aux::array_view<boost::asio::const_buffer> out_iovec;
std::tie(next_barrier, out_iovec) = m_enc_handler.encrypt(iovec);
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (next_barrier != 0) if (next_barrier != 0)
peer_log(peer_log_alert::outgoing, "SEND_BARRIER" peer_log(peer_log_alert::outgoing, "SEND_BARRIER"
, "encrypted block s = %d", next_barrier); , "encrypted block s = %d", next_barrier);
#endif #endif
return next_barrier; return std::make_tuple(next_barrier, out_iovec);
} }
#endif #endif
@ -3585,7 +3564,8 @@ namespace libtorrent
TORRENT_ASSERT( (bool(m_state != read_pe_dhkey) || m_dh_key_exchange.get()) TORRENT_ASSERT( (bool(m_state != read_pe_dhkey) || m_dh_key_exchange.get())
|| !is_outgoing()); || !is_outgoing());
TORRENT_ASSERT(!m_rc4_encrypted || (!m_encrypted && m_rc4) || (m_encrypted && !m_enc_handler.is_send_plaintext())); TORRENT_ASSERT(!m_rc4_encrypted || (!m_encrypted && m_rc4)
|| (m_encrypted && !m_enc_handler.is_send_plaintext()));
#endif #endif
if (!in_handshake()) if (!in_handshake())
{ {

View File

@ -50,9 +50,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include <random> #include <random>
#include "libtorrent/random.hpp" #include "libtorrent/random.hpp"
#include "libtorrent/alloca.hpp"
#include "libtorrent/pe_crypto.hpp" #include "libtorrent/pe_crypto.hpp"
#include "libtorrent/hasher.hpp" #include "libtorrent/hasher.hpp"
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
#include "libtorrent/aux_/array_view.hpp"
namespace libtorrent namespace libtorrent
{ {
@ -101,47 +103,55 @@ namespace libtorrent
m_xor_mask = h.final(); m_xor_mask = h.final();
} }
int encryption_handler::encrypt(std::vector<boost::asio::mutable_buffer>& iovec) std::tuple<int, aux::array_view<boost::asio::const_buffer>>
encryption_handler::encrypt(
aux::array_view<boost::asio::mutable_buffer> iovec)
{ {
using namespace boost::asio;
TORRENT_ASSERT(!m_send_barriers.empty()); TORRENT_ASSERT(!m_send_barriers.empty());
TORRENT_ASSERT(m_send_barriers.front().enc_handler); TORRENT_ASSERT(m_send_barriers.front().enc_handler);
int to_process = m_send_barriers.front().next; int to_process = m_send_barriers.front().next;
boost::asio::mutable_buffer* bufs;
int num_bufs;
bool need_destruct = false;
if (to_process != INT_MAX) if (to_process != INT_MAX)
{ {
for (std::vector<boost::asio::mutable_buffer>::iterator i = iovec.begin(); bufs = TORRENT_ALLOCA(mutable_buffer, iovec.size());
to_process >= 0; ++i) need_destruct = true;
num_bufs = 0;
for (int i = 0; to_process > 0; ++i)
{ {
if (to_process == 0) ++num_bufs;
int const size = buffer_size(iovec[i]);
if (to_process < size)
{ {
iovec.erase(i, iovec.end()); new (&bufs[i]) mutable_buffer(
break; buffer_cast<void*>(iovec[i]), to_process);
}
else if (to_process < boost::asio::buffer_size(*i))
{
*i = boost::asio::mutable_buffer(boost::asio::buffer_cast<void*>(*i), to_process);
iovec.erase(++i, iovec.end());
to_process = 0; to_process = 0;
break;
} }
to_process -= int(boost::asio::buffer_size(*i)); else
{
new (&bufs[i]) mutable_buffer(iovec[i]);
to_process -= size;
}
} }
TORRENT_ASSERT(to_process == 0); }
else
{
bufs = iovec.data();
num_bufs = iovec.size();
} }
#if TORRENT_USE_ASSERTS
to_process = 0;
for (std::vector<boost::asio::mutable_buffer>::iterator i = iovec.begin();
i != iovec.end(); ++i)
to_process += int(boost::asio::buffer_size(*i));
#endif
int next_barrier = 0; int next_barrier = 0;
bool process_barrier = iovec.empty(); aux::array_view<const_buffer> out_iovec;
bool process_barrier = num_bufs == 0;
if (!process_barrier) if (!process_barrier)
{ {
next_barrier = m_send_barriers.front().enc_handler->encrypt(iovec); std::tie(next_barrier, out_iovec)
= m_send_barriers.front().enc_handler->encrypt({bufs, num_bufs});
process_barrier = (next_barrier != 0); process_barrier = (next_barrier != 0);
} }
if (process_barrier) if (process_barrier)
@ -149,37 +159,43 @@ namespace libtorrent
if (m_send_barriers.front().next != INT_MAX) if (m_send_barriers.front().next != INT_MAX)
{ {
if (m_send_barriers.size() == 1) if (m_send_barriers.size() == 1)
{
// transitioning back to plaintext // transitioning back to plaintext
next_barrier = INT_MAX; next_barrier = INT_MAX;
}
m_send_barriers.pop_front(); m_send_barriers.pop_front();
} }
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
if (next_barrier != INT_MAX) if (next_barrier != INT_MAX)
{ {
int payload = 0;
for (int i = 0; i < num_bufs; ++i)
payload += int(buffer_size(bufs[i]));
int overhead = 0; int overhead = 0;
for (std::vector<boost::asio::mutable_buffer>::iterator i = iovec.begin(); for (auto buf : out_iovec)
i != iovec.end(); ++i) overhead += int(buffer_size(buf));
overhead += int(boost::asio::buffer_size(*i)); TORRENT_ASSERT(overhead + payload == next_barrier);
TORRENT_ASSERT(overhead + to_process == next_barrier);
} }
#endif #endif
} }
else if (need_destruct)
{ {
iovec.clear(); for (int i = 0; i < num_bufs; ++i)
bufs[i].~mutable_buffer();
} }
return next_barrier; return std::make_tuple(next_barrier, out_iovec);
} }
int encryption_handler::decrypt(crypto_receive_buffer& recv_buffer, std::size_t& bytes_transferred) int encryption_handler::decrypt(crypto_receive_buffer& recv_buffer
, std::size_t& bytes_transferred)
{ {
TORRENT_ASSERT(!is_recv_plaintext()); TORRENT_ASSERT(!is_recv_plaintext());
int consume = 0; int consume = 0;
if (recv_buffer.crypto_packet_finished()) if (recv_buffer.crypto_packet_finished())
{ {
std::vector<boost::asio::mutable_buffer> wr_buf; boost::asio::mutable_buffer wr_buf = recv_buffer.mutable_buffer(bytes_transferred);
wr_buf.push_back(recv_buffer.mutable_buffers(bytes_transferred));
int packet_size = 0; int packet_size = 0;
int produce = int(bytes_transferred); int produce = int(bytes_transferred);
m_dec_handler->decrypt(wr_buf, consume, produce, packet_size); m_dec_handler->decrypt(wr_buf, consume, produce, packet_size);
@ -249,11 +265,11 @@ namespace libtorrent
m_decrypt = true; m_decrypt = true;
rc4_init(key, len, &m_rc4_incoming); rc4_init(key, len, &m_rc4_incoming);
// Discard first 1024 bytes // Discard first 1024 bytes
char buf[1024];
std::vector<boost::asio::mutable_buffer> vec(1, boost::asio::mutable_buffer(buf, 1024));
int consume = 0; int consume = 0;
int produce = 0; int produce = 0;
int packet_size = 0; int packet_size = 0;
char buf[1024];
boost::asio::mutable_buffer vec(buf, sizeof(buf));
decrypt(vec, consume, produce, packet_size); decrypt(vec, consume, produce, packet_size);
} }
@ -263,21 +279,23 @@ namespace libtorrent
rc4_init(key, len, &m_rc4_outgoing); rc4_init(key, len, &m_rc4_outgoing);
// Discard first 1024 bytes // Discard first 1024 bytes
char buf[1024]; char buf[1024];
std::vector<boost::asio::mutable_buffer> vec(1, boost::asio::mutable_buffer(buf, 1024)); boost::asio::mutable_buffer vec(buf, sizeof(buf));
encrypt(vec); encrypt(vec);
} }
int rc4_handler::encrypt(std::vector<boost::asio::mutable_buffer>& buf) std::tuple<int, aux::array_view<boost::asio::const_buffer>>
rc4_handler::encrypt(aux::array_view<boost::asio::mutable_buffer> bufs)
{ {
if (!m_encrypt) return 0; using namespace boost::asio;
if (buf.empty()) return 0; aux::array_view<boost::asio::const_buffer> empty;
if (!m_encrypt) return std::make_tuple(0, empty);
if (bufs.size() == 0) return std::make_tuple(0, empty);
int bytes_processed = 0; int bytes_processed = 0;
for (std::vector<boost::asio::mutable_buffer>::iterator i = buf.begin(); for (auto& buf : bufs)
i != buf.end(); ++i)
{ {
unsigned char* pos = boost::asio::buffer_cast<unsigned char*>(*i); unsigned char* const pos = buffer_cast<unsigned char*>(buf);
int len = int(boost::asio::buffer_size(*i)); int const len = int(buffer_size(buf));
TORRENT_ASSERT(len >= 0); TORRENT_ASSERT(len >= 0);
TORRENT_ASSERT(pos); TORRENT_ASSERT(pos);
@ -285,11 +303,10 @@ namespace libtorrent
bytes_processed += len; bytes_processed += len;
rc4_encrypt(pos, len, &m_rc4_outgoing); rc4_encrypt(pos, len, &m_rc4_outgoing);
} }
buf.clear(); return std::make_tuple(bytes_processed, empty);
return bytes_processed;
} }
void rc4_handler::decrypt(std::vector<boost::asio::mutable_buffer>& buf void rc4_handler::decrypt(aux::array_view<boost::asio::mutable_buffer> bufs
, int& consume , int& consume
, int& produce , int& produce
, int& packet_size) , int& packet_size)
@ -301,11 +318,10 @@ namespace libtorrent
if (!m_decrypt) return; if (!m_decrypt) return;
int bytes_processed = 0; int bytes_processed = 0;
for (std::vector<boost::asio::mutable_buffer>::iterator i = buf.begin(); for (auto& buf : bufs)
i != buf.end(); ++i)
{ {
unsigned char* pos = boost::asio::buffer_cast<unsigned char*>(*i); unsigned char* const pos = boost::asio::buffer_cast<unsigned char*>(buf);
int len = int(boost::asio::buffer_size(*i)); int const len = int(boost::asio::buffer_size(buf));
TORRENT_ASSERT(len >= 0); TORRENT_ASSERT(len >= 0);
TORRENT_ASSERT(pos); TORRENT_ASSERT(pos);
@ -313,7 +329,6 @@ namespace libtorrent
bytes_processed += len; bytes_processed += len;
rc4_encrypt(pos, len, &m_rc4_incoming); rc4_encrypt(pos, len, &m_rc4_incoming);
} }
buf.clear();
produce = bytes_processed; produce = bytes_processed;
} }

View File

@ -5510,15 +5510,18 @@ namespace libtorrent
{ {
std::vector<boost::asio::mutable_buffer> vec; std::vector<boost::asio::mutable_buffer> vec;
m_send_buffer.build_mutable_iovec(m_send_buffer.size(), vec); m_send_buffer.build_mutable_iovec(m_send_buffer.size(), vec);
int next_barrier = hit_send_barrier(vec); int next_barrier;
for (std::vector<boost::asio::mutable_buffer>::reverse_iterator i = vec.rbegin(); aux::array_view<boost::asio::const_buffer> inject_vec;
i != vec.rend(); ++i) std::tie(next_barrier, inject_vec) = hit_send_barrier(vec);
for (auto i = inject_vec.rbegin(); i != inject_vec.rend(); ++i)
{ {
m_send_buffer.prepend_buffer(boost::asio::buffer_cast<char*>(*i) int const size = boost::asio::buffer_size(*i);
, int(boost::asio::buffer_size(*i)) // this const_cast is a here because chained_buffer need to be
, int(boost::asio::buffer_size(*i)) // fixed.
, &nop char* ptr = const_cast<char*>(
, NULL); boost::asio::buffer_cast<char const*>(*i));
m_send_buffer.prepend_buffer(ptr
, size, size, &nop, nullptr);
} }
set_send_barrier(next_barrier); set_send_barrier(next_barrier);
} }
@ -5530,7 +5533,7 @@ namespace libtorrent
return; return;
} }
int quota_left = m_quota[upload_channel]; int const quota_left = m_quota[upload_channel];
if (m_send_buffer.empty() if (m_send_buffer.empty()
&& m_reading_bytes > 0 && m_reading_bytes > 0

View File

@ -151,7 +151,7 @@ buffer::interval receive_buffer::mutable_buffer()
, &m_recv_buffer[0] + m_recv_start + rcv_pos); , &m_recv_buffer[0] + m_recv_start + rcv_pos);
} }
boost::asio::mutable_buffer receive_buffer::mutable_buffers(int const bytes) boost::asio::mutable_buffer receive_buffer::mutable_buffer(int const bytes)
{ {
namespace asio = boost::asio; namespace asio = boost::asio;
@ -305,13 +305,13 @@ buffer::const_interval crypto_receive_buffer::get() const
return recv_buffer; return recv_buffer;
} }
boost::asio::mutable_buffer crypto_receive_buffer::mutable_buffers( boost::asio::mutable_buffer crypto_receive_buffer::mutable_buffer(
std::size_t const bytes) std::size_t const bytes)
{ {
int const pending_decryption = (m_recv_pos != INT_MAX) int const pending_decryption = (m_recv_pos != INT_MAX)
? m_connection_buffer.packet_size() - m_recv_pos ? m_connection_buffer.packet_size() - m_recv_pos
: int(bytes); : int(bytes);
return m_connection_buffer.mutable_buffers(pending_decryption); return m_connection_buffer.mutable_buffer(pending_decryption);
} }
#endif // TORRENT_DISABLE_ENCRYPTION #endif // TORRENT_DISABLE_ENCRYPTION

View File

@ -37,15 +37,18 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/pe_crypto.hpp" #include "libtorrent/pe_crypto.hpp"
#include "libtorrent/session.hpp" #include "libtorrent/session.hpp"
#include "libtorrent/random.hpp" #include "libtorrent/random.hpp"
#include "libtorrent/aux_/array_view.hpp"
#include "setup_transfer.hpp" #include "setup_transfer.hpp"
#include "test.hpp" #include "test.hpp"
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
void test_enc_handler(libtorrent::crypto_plugin* a, libtorrent::crypto_plugin* b) namespace lt = libtorrent;
void test_enc_handler(libtorrent::crypto_plugin& a, libtorrent::crypto_plugin& b)
{ {
const int repcount = 128; int const repcount = 128;
for (int rep = 0; rep < repcount; ++rep) for (int rep = 0; rep < repcount; ++rep)
{ {
int const buf_len = rand() % (512 * 1024); int const buf_len = rand() % (512 * 1024);
@ -56,36 +59,48 @@ void test_enc_handler(libtorrent::crypto_plugin* a, libtorrent::crypto_plugin* b
std::copy(buf.begin(), buf.end(), cmp_buf.begin()); std::copy(buf.begin(), buf.end(), cmp_buf.begin());
using namespace boost::asio; using namespace boost::asio;
std::vector<mutable_buffer> iovec;
iovec.push_back(mutable_buffer(&buf[0], buf_len));
a->encrypt(iovec);
TEST_CHECK(!std::equal(buf.begin(), buf.end(), cmp_buf.begin()));
TEST_CHECK(iovec.empty());
int consume = 0;
int produce = buf_len;
int packet_size = 0;
iovec.push_back(mutable_buffer(&buf[0], buf_len));
b->decrypt(iovec, consume, produce, packet_size);
TEST_CHECK(std::equal(buf.begin(), buf.end(), cmp_buf.begin()));
TEST_CHECK(iovec.empty());
TEST_EQUAL(consume, 0);
TEST_EQUAL(produce, buf_len);
TEST_EQUAL(packet_size, 0);
iovec.push_back(mutable_buffer(&buf[0], buf_len)); {
b->encrypt(iovec); mutable_buffer iovec(&buf[0], buf_len);
TEST_CHECK(!std::equal(buf.begin(), buf.end(), cmp_buf.begin())); int next_barrier;
TEST_CHECK(iovec.empty()); lt::aux::array_view<const_buffer> iovec_out;
consume = 0; std::tie(next_barrier, iovec_out) = a.encrypt(iovec);
produce = buf_len; TEST_CHECK(buf != cmp_buf);
packet_size = 0; TEST_EQUAL(iovec_out.size(), 0);
iovec.push_back(mutable_buffer(&buf[0], buf_len)); TEST_EQUAL(next_barrier, buf_len);
a->decrypt(iovec, consume, produce, packet_size); }
TEST_CHECK(std::equal(buf.begin(), buf.end(), cmp_buf.begin()));
TEST_CHECK(iovec.empty()); {
TEST_EQUAL(consume, 0); int consume = 0;
TEST_EQUAL(produce, buf_len); int produce = buf_len;
TEST_EQUAL(packet_size, 0); int packet_size = 0;
mutable_buffer iovec(&buf[0], buf_len);
b.decrypt(iovec, consume, produce, packet_size);
TEST_CHECK(buf == cmp_buf);
TEST_EQUAL(consume, 0);
TEST_EQUAL(produce, buf_len);
TEST_EQUAL(packet_size, 0);
}
{
mutable_buffer iovec(&buf[0], buf_len);
int next_barrier;
lt::aux::array_view<const_buffer> iovec_out;
std::tie(next_barrier, iovec_out) = b.encrypt(iovec);
TEST_EQUAL(iovec_out.size(), 0);
TEST_CHECK(buf != cmp_buf);
TEST_EQUAL(next_barrier, buf_len);
int consume = 0;
int produce = buf_len;
int packet_size = 0;
mutable_buffer iovec2(&buf[0], buf_len);
a.decrypt(iovec2, consume, produce, packet_size);
TEST_CHECK(buf == cmp_buf);
TEST_EQUAL(consume, 0);
TEST_EQUAL(produce, buf_len);
TEST_EQUAL(packet_size, 0);
}
} }
} }
@ -134,7 +149,7 @@ TORRENT_TEST(rc4)
rc4_handler rc42; rc4_handler rc42;
rc42.set_incoming_key(&test1_key[0], 20); rc42.set_incoming_key(&test1_key[0], 20);
rc42.set_outgoing_key(&test2_key[0], 20); rc42.set_outgoing_key(&test2_key[0], 20);
test_enc_handler(&rc41, &rc42); test_enc_handler(rc41, rc42);
} }
#else #else

View File

@ -107,7 +107,7 @@ TORRENT_TEST(recv_buffer_mutable_buffers)
b.cut(100, 1000); // packet size = 1000 b.cut(100, 1000); // packet size = 1000
packet_transferred = b.advance_pos(999); packet_transferred = b.advance_pos(999);
TEST_EQUAL(packet_transferred, 999); TEST_EQUAL(packet_transferred, 999);
boost::asio::mutable_buffer vec = b.mutable_buffers(999); boost::asio::mutable_buffer vec = b.mutable_buffer(999);
// previous packet // previous packet
// | // |