diff --git a/libtransmission/handshake.cc b/libtransmission/handshake.cc index d6fb7c03a..c35beed07 100644 --- a/libtransmission/handshake.cc +++ b/libtransmission/handshake.cc @@ -185,7 +185,7 @@ ReadState tr_handshake::read_yb(tr_peerIo* peer_io) /* now send these: HASH('req1', S), HASH('req2', SKEY) xor HASH('req3', S), * ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA) */ - auto outbuf = libtransmission::Buffer{}; + auto outbuf = libtransmission::StackBuffer<1024U, std::byte>{}; /* HASH('req1', S) */ outbuf.add(tr_sha1::digest("req1"sv, dh_.secret())); @@ -600,7 +600,7 @@ ReadState tr_handshake::read_ia(tr_peerIo* peer_io) auto const& info_hash = peer_io->torrent_hash(); TR_ASSERT_MSG(info_hash != tr_sha1_digest_t{}, "readIA requires an info_hash"); peer_io->encrypt_init(peer_io->is_incoming(), dh_, info_hash); - auto outbuf = libtransmission::Buffer{}; + auto outbuf = libtransmission::StackBuffer<1024U, std::byte>{}; // send VC tr_logAddTraceHand(this, "sending vc"); diff --git a/libtransmission/peer-io.h b/libtransmission/peer-io.h index 215634bd7..54a768fe9 100644 --- a/libtransmission/peer-io.h +++ b/libtransmission/peer-io.h @@ -20,6 +20,7 @@ #include "transmission.h" #include "bandwidth.h" +#include "block-info.h" #include "net.h" // tr_address #include "peer-mse.h" #include "peer-socket.h" @@ -291,10 +292,14 @@ public: static void utp_init(struct_utp_context* ctx); private: - // our target socket receive buffer size + // Our target socket receive buffer size. + // Gets read from the socket buffer into the PeerBuffer inbuf_. static constexpr auto RcvBuf = size_t{ 256 * 1024 }; - using PeerBuffer = libtransmission::Buffer; + // The buffer size for incoming & outgoing peer messages. + // Starts off with enough capacity to read a single BT Piece message, + // but has a 5x GrowthFactor so that it can quickly to high volume. + using PeerBuffer = libtransmission::StackBuffer>; friend class libtransmission::test::HandshakeTest; diff --git a/libtransmission/peer-msgs.cc b/libtransmission/peer-msgs.cc index 9aff92578..ea375a164 100644 --- a/libtransmission/peer-msgs.cc +++ b/libtransmission/peer-msgs.cc @@ -47,7 +47,9 @@ #endif using namespace std::literals; -using MessageBuffer = libtransmission::Buffer; + +// initial capacity is big enough to hold a BtPeerMsgs::Piece message +using MessageBuffer = libtransmission::StackBuffer>; using MessageReader = libtransmission::BufferReader; using MessageWriter = libtransmission::BufferWriter; @@ -1800,8 +1802,10 @@ ReadState canRead(tr_peerIo* io, void* vmsgs, size_t* piece) current_message_len.reset(); auto const message_type = *current_message_type; current_message_type.reset(); + auto payload = MessageBuffer{}; - std::swap(payload, current_payload); + payload.add(current_payload); + current_payload.clear(); auto const [read_state, n_piece_bytes_read] = process_peer_message(msgs, message_type, payload); *piece = n_piece_bytes_read; diff --git a/libtransmission/tr-buffer.h b/libtransmission/tr-buffer.h index 710e4708d..5e62085df 100644 --- a/libtransmission/tr-buffer.h +++ b/libtransmission/tr-buffer.h @@ -14,6 +14,8 @@ #include #include +#include + #include #include "error.h" @@ -123,6 +125,11 @@ public: tr_error_set(error, err, tr_net_strerror(err)); return {}; } + + void clear() + { + drain(size()); + } }; template @@ -223,6 +230,61 @@ public: } }; +template> +class StackBuffer final + : public BufferReader + , public BufferWriter +{ +public: + StackBuffer() = default; + StackBuffer(StackBuffer&&) = delete; + StackBuffer(StackBuffer const&) = delete; + StackBuffer& operator=(StackBuffer&&) = delete; + StackBuffer& operator=(StackBuffer const&) = delete; + + template + explicit StackBuffer(ContiguousContainer const& data) + { + BufferWriter::add(data); + } + + [[nodiscard]] size_t size() const noexcept override + { + return end_pos_ - begin_pos_; + } + + [[nodiscard]] value_type const* data() const override + { + return std::data(buf_) + begin_pos_; + } + + void drain(size_t n_bytes) override + { + begin_pos_ += std::min(n_bytes, size()); + + if (begin_pos_ == end_pos_) // empty; reuse the buf + { + begin_pos_ = end_pos_ = 0U; + } + } + + virtual std::pair reserve_space(size_t n_bytes) override + { + buf_.resize(end_pos_ + n_bytes); + return { buf_.data() + end_pos_, n_bytes }; + } + + virtual void commit_space(size_t n_bytes) override + { + end_pos_ += n_bytes; + } + +private: + small::vector, std::true_type, size_t, GrowthFactor> buf_ = {}; + size_t begin_pos_ = {}; + size_t end_pos_ = {}; +}; + class Buffer final : public BufferReader , public BufferWriter diff --git a/libtransmission/variant-benc.cc b/libtransmission/variant-benc.cc index 383f53deb..a6f29971d 100644 --- a/libtransmission/variant-benc.cc +++ b/libtransmission/variant-benc.cc @@ -277,7 +277,7 @@ namespace { namespace to_string_helpers { -using OutBuf = libtransmission::Buffer; +using OutBuf = libtransmission::StackBuffer<1024U * 8U, std::byte>; void saveIntFunc(tr_variant const* val, void* vout) { diff --git a/libtransmission/variant-json.cc b/libtransmission/variant-json.cc index 095ecda01..17481c6c7 100644 --- a/libtransmission/variant-json.cc +++ b/libtransmission/variant-json.cc @@ -442,7 +442,7 @@ struct JsonWalk } std::deque parents; - libtransmission::Buffer out; + libtransmission::StackBuffer<1024U * 8U, std::byte> out; bool doIndent; };