mirror of
https://github.com/transmission/transmission
synced 2025-01-31 03:12:44 +00:00
refactor: migrate methods to buffer reader (#5533)
This commit is contained in:
parent
4fd5f3a490
commit
52b03c2489
8 changed files with 147 additions and 297 deletions
|
@ -49,6 +49,8 @@ using namespace std::literals;
|
|||
using tau_connection_t = uint64_t;
|
||||
using tau_transaction_t = uint32_t;
|
||||
|
||||
using InBuf = libtransmission::BufferReader<std::byte>;
|
||||
|
||||
constexpr auto TauConnectionTtlSecs = time_t{ 45 };
|
||||
|
||||
auto tau_transaction_new()
|
||||
|
@ -114,7 +116,7 @@ struct tau_scrape_request
|
|||
requestFinished();
|
||||
}
|
||||
|
||||
void onResponse(tau_action_t action, libtransmission::Buffer& buf)
|
||||
void onResponse(tau_action_t action, InBuf& buf)
|
||||
{
|
||||
response.did_connect = true;
|
||||
response.did_timeout = false;
|
||||
|
@ -214,7 +216,7 @@ struct tau_announce_request
|
|||
this->requestFinished();
|
||||
}
|
||||
|
||||
void onResponse(tau_action_t action, libtransmission::Buffer& buf)
|
||||
void onResponse(tau_action_t action, InBuf& buf)
|
||||
{
|
||||
auto const buflen = std::size(buf);
|
||||
|
||||
|
@ -227,8 +229,7 @@ struct tau_announce_request
|
|||
response.leechers = buf.to_uint32();
|
||||
response.seeders = buf.to_uint32();
|
||||
|
||||
auto const [bytes, n_bytes] = buf.pullup();
|
||||
response.pex = tr_pex::from_compact_ipv4(bytes, n_bytes, nullptr, 0);
|
||||
response.pex = tr_pex::from_compact_ipv4(std::data(buf), std::size(buf), nullptr, 0);
|
||||
requestFinished();
|
||||
}
|
||||
else
|
||||
|
@ -310,7 +311,7 @@ struct tau_tracker
|
|||
mediator_.sendto(buf, buflen, reinterpret_cast<sockaddr const*>(&ss), sslen);
|
||||
}
|
||||
|
||||
void on_connection_response(tau_action_t action, libtransmission::Buffer& buf)
|
||||
void on_connection_response(tau_action_t action, InBuf& buf)
|
||||
{
|
||||
this->connecting_at = 0;
|
||||
this->connection_transaction_id = 0;
|
||||
|
@ -378,8 +379,7 @@ struct tau_tracker
|
|||
buf.add_uint32(TAU_ACTION_CONNECT);
|
||||
buf.add_uint32(this->connection_transaction_id);
|
||||
|
||||
auto const [bytes, n_bytes] = buf.pullup();
|
||||
this->sendto(bytes, n_bytes);
|
||||
this->sendto(std::data(buf), std::size(buf));
|
||||
}
|
||||
|
||||
if (timeout_reqs)
|
||||
|
@ -539,8 +539,7 @@ private:
|
|||
buf.add_uint64(this->connection_id);
|
||||
buf.add(payload, payload_len);
|
||||
|
||||
auto const [bytes, n_bytes] = buf.pullup();
|
||||
this->sendto(bytes, n_bytes);
|
||||
this->sendto(std::data(buf), std::size(buf));
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -139,7 +139,8 @@ public:
|
|||
|
||||
// Write all the data from `buf`.
|
||||
// This is a destructive add: `buf` is empty after this call.
|
||||
void write(libtransmission::Buffer& buf, bool is_piece_data)
|
||||
template<typename T>
|
||||
void write(libtransmission::BufferReader<T>& buf, bool is_piece_data)
|
||||
{
|
||||
auto const n_bytes = std::size(buf);
|
||||
write_bytes(std::data(buf), n_bytes, is_piece_data);
|
||||
|
|
|
@ -47,7 +47,9 @@
|
|||
#endif
|
||||
|
||||
using namespace std::literals;
|
||||
using Buffer = libtransmission::Buffer;
|
||||
using MessageBuffer = libtransmission::Buffer;
|
||||
using MessageReader = libtransmission::BufferReader<std::byte>;
|
||||
using MessageWriter = libtransmission::BufferWriter<std::byte>;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -218,7 +220,7 @@ struct tr_incoming
|
|||
{
|
||||
std::optional<uint32_t> length; // the full message payload length. Includes the +1 for id length
|
||||
std::optional<uint8_t> id; // the protocol message, e.g. BtPeerMsgs::Piece
|
||||
Buffer payload;
|
||||
MessageBuffer payload;
|
||||
|
||||
struct incoming_piece_data
|
||||
{
|
||||
|
@ -677,8 +679,8 @@ public:
|
|||
tr_bitfield have_;
|
||||
|
||||
private:
|
||||
friend ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, libtransmission::Buffer& payload);
|
||||
friend void parseLtepHandshake(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload);
|
||||
friend ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, MessageReader& payload);
|
||||
friend void parseLtepHandshake(tr_peerMsgsImpl* msgs, MessageReader& payload);
|
||||
|
||||
tr_peer_callback const callback_;
|
||||
void* const callback_data_;
|
||||
|
@ -757,23 +759,23 @@ template<typename T>
|
|||
|
||||
// ---
|
||||
|
||||
void add_param(Buffer& buffer, uint8_t param) noexcept
|
||||
void add_param(MessageWriter& buffer, uint8_t param) noexcept
|
||||
{
|
||||
buffer.add_uint8(param);
|
||||
}
|
||||
|
||||
void add_param(Buffer& buffer, uint16_t param) noexcept
|
||||
void add_param(MessageWriter& buffer, uint16_t param) noexcept
|
||||
{
|
||||
buffer.add_uint16(param);
|
||||
}
|
||||
|
||||
void add_param(Buffer& buffer, uint32_t param) noexcept
|
||||
void add_param(MessageWriter& buffer, uint32_t param) noexcept
|
||||
{
|
||||
buffer.add_uint32(param);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void add_param(Buffer& buffer, T const& param) noexcept
|
||||
void add_param(MessageWriter& buffer, T const& param) noexcept
|
||||
{
|
||||
buffer.add(param);
|
||||
}
|
||||
|
@ -811,19 +813,16 @@ template<typename... Args>
|
|||
} // namespace
|
||||
|
||||
template<typename... Args>
|
||||
void build_peer_message(tr_peerMsgsImpl const* const msgs, Buffer& out, uint8_t type, Args const&... args)
|
||||
void build_peer_message(tr_peerMsgsImpl const* const msgs, MessageWriter& out, uint8_t type, Args const&... args)
|
||||
{
|
||||
logtrace(msgs, build_log_message(type, args...));
|
||||
|
||||
auto const old_len = std::size(out);
|
||||
auto msg_len = sizeof(type);
|
||||
((msg_len += get_param_length(args)), ...);
|
||||
out.reserve(old_len + msg_len);
|
||||
out.add_uint32(msg_len);
|
||||
out.add_uint8(type);
|
||||
(add_param(out, args), ...);
|
||||
|
||||
TR_ASSERT(old_len + sizeof(uint32_t) + msg_len);
|
||||
TR_ASSERT(messageLengthIsCorrect(msgs->torrent, type, msg_len));
|
||||
}
|
||||
} // namespace protocol_send_message_helpers
|
||||
|
@ -833,7 +832,7 @@ size_t protocol_send_message(tr_peerMsgsImpl const* const msgs, uint8_t type, Ar
|
|||
{
|
||||
using namespace protocol_send_message_helpers;
|
||||
|
||||
auto out = Buffer{};
|
||||
auto out = MessageBuffer{};
|
||||
build_peer_message(msgs, out, type, args...);
|
||||
auto const n_bytes_added = std::size(out);
|
||||
msgs->io->write(out, type == BtPeerMsgs::Piece);
|
||||
|
@ -844,7 +843,7 @@ size_t protocol_send_keepalive(tr_peerMsgsImpl* msgs)
|
|||
{
|
||||
logtrace(msgs, "sending 'keepalive'");
|
||||
|
||||
auto out = Buffer{};
|
||||
auto out = MessageBuffer{};
|
||||
out.add_uint32(0);
|
||||
|
||||
auto const n_bytes_added = std::size(out);
|
||||
|
@ -1035,7 +1034,7 @@ void sendLtepHandshake(tr_peerMsgsImpl* msgs)
|
|||
tr_variantClear(&val);
|
||||
}
|
||||
|
||||
void parseLtepHandshake(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload)
|
||||
void parseLtepHandshake(tr_peerMsgsImpl* msgs, MessageReader& payload)
|
||||
{
|
||||
msgs->peerSentLtepHandshake = true;
|
||||
|
||||
|
@ -1145,7 +1144,7 @@ void parseLtepHandshake(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload)
|
|||
tr_variantClear(&val);
|
||||
}
|
||||
|
||||
void parseUtMetadata(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload_in)
|
||||
void parseUtMetadata(tr_peerMsgsImpl* msgs, MessageReader& payload_in)
|
||||
{
|
||||
int64_t msg_type = -1;
|
||||
int64_t piece = -1;
|
||||
|
@ -1200,7 +1199,7 @@ void parseUtMetadata(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload_in)
|
|||
}
|
||||
}
|
||||
|
||||
void parseUtPex(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload)
|
||||
void parseUtPex(tr_peerMsgsImpl* msgs, MessageReader& payload)
|
||||
{
|
||||
auto* const tor = msgs->torrent;
|
||||
if (!tor->allows_pex())
|
||||
|
@ -1248,7 +1247,7 @@ void parseUtPex(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload)
|
|||
}
|
||||
}
|
||||
|
||||
void parseLtep(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload)
|
||||
void parseLtep(tr_peerMsgsImpl* msgs, MessageReader& payload)
|
||||
{
|
||||
TR_ASSERT(!std::empty(payload));
|
||||
|
||||
|
@ -1283,7 +1282,7 @@ void parseLtep(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload)
|
|||
}
|
||||
}
|
||||
|
||||
ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, libtransmission::Buffer& payload);
|
||||
ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, MessageReader& payload);
|
||||
|
||||
void prefetchPieces(tr_peerMsgsImpl* msgs)
|
||||
{
|
||||
|
@ -1348,7 +1347,7 @@ void peerMadeRequest(tr_peerMsgsImpl* msgs, struct peer_request const* req)
|
|||
|
||||
int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr<Cache::BlockData> block_data, tr_block_index_t block);
|
||||
|
||||
ReadResult read_piece_data(tr_peerMsgsImpl* msgs, libtransmission::Buffer& payload)
|
||||
ReadResult read_piece_data(tr_peerMsgsImpl* msgs, MessageReader& payload)
|
||||
{
|
||||
// <index><begin><block>
|
||||
auto const piece = payload.to_uint32();
|
||||
|
@ -1396,7 +1395,7 @@ ReadResult read_piece_data(tr_peerMsgsImpl* msgs, libtransmission::Buffer& paylo
|
|||
return { ok ? READ_NOW : READ_ERR, len };
|
||||
}
|
||||
|
||||
ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, libtransmission::Buffer& payload)
|
||||
ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, MessageReader& payload)
|
||||
{
|
||||
bool const fext = msgs->io->supports_fext();
|
||||
|
||||
|
@ -1477,15 +1476,12 @@ ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, libtransmissi
|
|||
break;
|
||||
|
||||
case BtPeerMsgs::Bitfield:
|
||||
{
|
||||
logtrace(msgs, "got a bitfield");
|
||||
auto const [buf, buflen] = payload.pullup();
|
||||
msgs->have_ = tr_bitfield{ msgs->torrent->has_metainfo() ? msgs->torrent->piece_count() : buflen * 8 };
|
||||
msgs->have_.set_raw(reinterpret_cast<uint8_t const*>(buf), buflen);
|
||||
msgs->publish(tr_peer_event::GotBitfield(&msgs->have_));
|
||||
msgs->invalidatePercentDone();
|
||||
break;
|
||||
}
|
||||
logtrace(msgs, "got a bitfield");
|
||||
msgs->have_ = tr_bitfield{ msgs->torrent->has_metainfo() ? msgs->torrent->piece_count() : std::size(payload) * 8 };
|
||||
msgs->have_.set_raw(reinterpret_cast<uint8_t const*>(std::data(payload)), std::size(payload));
|
||||
msgs->publish(tr_peer_event::GotBitfield(&msgs->have_));
|
||||
msgs->invalidatePercentDone();
|
||||
break;
|
||||
|
||||
case BtPeerMsgs::Request:
|
||||
{
|
||||
|
@ -1785,7 +1781,7 @@ 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 = libtransmission::Buffer{};
|
||||
auto payload = MessageBuffer{};
|
||||
std::swap(payload, current_payload);
|
||||
|
||||
auto const [read_state, n_piece_bytes_read] = process_peer_message(msgs, message_type, payload);
|
||||
|
|
|
@ -85,10 +85,10 @@ size_t tr_peer_socket::try_write(Buffer& buf, size_t max, tr_error** error) cons
|
|||
#ifdef WITH_UTP
|
||||
if (is_utp())
|
||||
{
|
||||
auto const [data, datalen] = buf.pullup();
|
||||
|
||||
errno = 0;
|
||||
auto const n_written = utp_write(handle.utp, data, std::min(datalen, max));
|
||||
// NB: utp_write() does not modify its 2nd arg, but a wart in
|
||||
// libutp's public API requires it to be non-const anyway :shrug:
|
||||
auto const n_written = utp_write(handle.utp, const_cast<std::byte*>(std::data(buf)), std::min(std::size(buf), max));
|
||||
auto const error_code = errno;
|
||||
|
||||
if (n_written > 0)
|
||||
|
|
|
@ -39,6 +39,25 @@ public:
|
|||
return size() == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto const* begin() const noexcept
|
||||
{
|
||||
return data();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto const* end() const noexcept
|
||||
{
|
||||
return begin() + size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] TR_CONSTEXPR20 bool starts_with(T const& needle) const
|
||||
{
|
||||
auto const n_bytes = std::size(needle);
|
||||
auto const needle_begin = reinterpret_cast<std::byte const*>(std::data(needle));
|
||||
auto const needle_end = needle_begin + n_bytes;
|
||||
return n_bytes <= size() && std::equal(needle_begin, needle_end, data());
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string_view() const
|
||||
{
|
||||
return std::string_view{ reinterpret_cast<char const*>(data()), size() };
|
||||
|
@ -83,6 +102,27 @@ public:
|
|||
to_buf(&tmp, sizeof(tmp));
|
||||
return tr_ntohll(tmp);
|
||||
}
|
||||
|
||||
// Returns the number of bytes written. Check `error` for error.
|
||||
size_t to_socket(tr_socket_t sockfd, size_t n_bytes, tr_error** error = nullptr)
|
||||
{
|
||||
n_bytes = std::min(n_bytes, size());
|
||||
|
||||
if (n_bytes == 0U)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (auto const n_sent = send(sockfd, reinterpret_cast<char const*>(data()), n_bytes, 0); n_sent >= 0U)
|
||||
{
|
||||
drain(n_sent);
|
||||
return n_sent;
|
||||
}
|
||||
|
||||
auto const err = sockerrno;
|
||||
tr_error_set(error, err, tr_net_strerror(err));
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename value_type>
|
||||
|
@ -164,143 +204,6 @@ class Buffer final
|
|||
public:
|
||||
using value_type = std::byte;
|
||||
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
using difference_type = long;
|
||||
using value_type = std::byte;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
constexpr Iterator(evbuffer* const buf, size_t offset)
|
||||
: buf_{ buf }
|
||||
, buf_offset_{ offset }
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] value_type& operator*() noexcept
|
||||
{
|
||||
auto& info = iov();
|
||||
return static_cast<value_type*>(info.iov.iov_base)[info.offset];
|
||||
}
|
||||
|
||||
[[nodiscard]] value_type operator*() const noexcept
|
||||
{
|
||||
auto const& info = iov();
|
||||
return static_cast<value_type*>(info.iov.iov_base)[info.offset];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Iterator operator+(size_t n_bytes)
|
||||
{
|
||||
return Iterator{ buf_, offset() + n_bytes };
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Iterator operator-(size_t n_bytes)
|
||||
{
|
||||
return Iterator{ buf_, offset() - n_bytes };
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator-(Iterator const& that) const noexcept
|
||||
{
|
||||
return offset() - that.offset();
|
||||
}
|
||||
|
||||
constexpr Iterator& operator++() noexcept
|
||||
{
|
||||
inc_offset(1U);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator& operator+=(size_t n_bytes)
|
||||
{
|
||||
inc_offset(n_bytes);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator& operator--() noexcept
|
||||
{
|
||||
dec_offset(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(Iterator const& that) const noexcept
|
||||
{
|
||||
return this->buf_ == that.buf_ && this->offset() == that.offset();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator!=(Iterator const& that) const noexcept
|
||||
{
|
||||
return !(*this == that);
|
||||
}
|
||||
|
||||
private:
|
||||
struct IovInfo
|
||||
{
|
||||
evbuffer_iovec iov = {};
|
||||
size_t offset = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr size_t offset() const noexcept
|
||||
{
|
||||
return buf_offset_;
|
||||
}
|
||||
|
||||
constexpr void dec_offset(size_t increment)
|
||||
{
|
||||
buf_offset_ -= increment;
|
||||
|
||||
if (iov_)
|
||||
{
|
||||
if (iov_->offset >= increment)
|
||||
{
|
||||
iov_->offset -= increment;
|
||||
}
|
||||
else
|
||||
{
|
||||
iov_.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void inc_offset(size_t increment)
|
||||
{
|
||||
buf_offset_ += increment;
|
||||
|
||||
if (iov_)
|
||||
{
|
||||
if (iov_->offset + increment < iov_->iov.iov_len)
|
||||
{
|
||||
iov_->offset += increment;
|
||||
}
|
||||
else
|
||||
{
|
||||
iov_.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] IovInfo& iov() const noexcept
|
||||
{
|
||||
if (!iov_)
|
||||
{
|
||||
auto ptr = evbuffer_ptr{};
|
||||
auto iov = IovInfo{};
|
||||
evbuffer_ptr_set(buf_, &ptr, buf_offset_, EVBUFFER_PTR_SET);
|
||||
evbuffer_peek(buf_, std::numeric_limits<ev_ssize_t>::max(), &ptr, &iov.iov, 1);
|
||||
iov.offset = 0;
|
||||
iov_ = iov;
|
||||
}
|
||||
|
||||
return *iov_;
|
||||
}
|
||||
|
||||
mutable std::optional<IovInfo> iov_;
|
||||
|
||||
evbuffer* buf_;
|
||||
size_t buf_offset_ = 0;
|
||||
};
|
||||
|
||||
Buffer() = default;
|
||||
Buffer(Buffer&&) = default;
|
||||
Buffer(Buffer const&) = delete;
|
||||
|
@ -320,7 +223,7 @@ public:
|
|||
return evbuffer_get_length(buf_.get());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::byte const* data() const override
|
||||
[[nodiscard]] value_type const* data() const override
|
||||
{
|
||||
return reinterpret_cast<std::byte*>(evbuffer_pullup(buf_.get(), -1));
|
||||
}
|
||||
|
@ -352,64 +255,6 @@ public:
|
|||
|
||||
//
|
||||
|
||||
[[nodiscard]] auto begin() noexcept
|
||||
{
|
||||
return Iterator{ buf_.get(), 0U };
|
||||
}
|
||||
|
||||
[[nodiscard]] auto end() noexcept
|
||||
{
|
||||
return Iterator{ buf_.get(), size() };
|
||||
}
|
||||
|
||||
[[nodiscard]] auto begin() const noexcept
|
||||
{
|
||||
return Iterator{ buf_.get(), 0U };
|
||||
}
|
||||
|
||||
[[nodiscard]] auto end() const noexcept
|
||||
{
|
||||
return Iterator{ buf_.get(), size() };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] TR_CONSTEXPR20 bool starts_with(T const& needle) const
|
||||
{
|
||||
auto const n_bytes = std::size(needle);
|
||||
auto const needle_begin = reinterpret_cast<std::byte const*>(std::data(needle));
|
||||
auto const needle_end = needle_begin + n_bytes;
|
||||
return n_bytes <= size() && std::equal(needle_begin, needle_end, cbegin());
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
drain(size());
|
||||
}
|
||||
|
||||
// Returns the number of bytes written. Check `error` for error.
|
||||
size_t to_socket(tr_socket_t sockfd, size_t n_bytes, tr_error** error = nullptr)
|
||||
{
|
||||
EVUTIL_SET_SOCKET_ERROR(0);
|
||||
auto const res = evbuffer_write_atmost(buf_.get(), sockfd, n_bytes);
|
||||
auto const err = EVUTIL_SOCKET_ERROR();
|
||||
if (res >= 0)
|
||||
{
|
||||
return static_cast<size_t>(res);
|
||||
}
|
||||
tr_error_set(error, err, tr_net_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::pair<std::byte*, size_t> pullup()
|
||||
{
|
||||
return { reinterpret_cast<std::byte*>(evbuffer_pullup(buf_.get(), -1)), size() };
|
||||
}
|
||||
|
||||
void reserve(size_t n_bytes)
|
||||
{
|
||||
evbuffer_expand(buf_.get(), n_bytes - size());
|
||||
}
|
||||
|
||||
size_t add_socket(tr_socket_t sockfd, size_t n_bytes, tr_error** error = nullptr)
|
||||
{
|
||||
EVUTIL_SET_SOCKET_ERROR(0);
|
||||
|
@ -436,16 +281,6 @@ public:
|
|||
private:
|
||||
evhelpers::evbuffer_unique_ptr buf_{ evbuffer_new() };
|
||||
std::optional<evbuffer_iovec> reserved_space_;
|
||||
|
||||
[[nodiscard]] Iterator cbegin() const noexcept
|
||||
{
|
||||
return Iterator{ buf_.get(), 0U };
|
||||
}
|
||||
|
||||
[[nodiscard]] Iterator cend() const noexcept
|
||||
{
|
||||
return Iterator{ buf_.get(), size() };
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace libtransmission
|
||||
|
|
|
@ -277,34 +277,40 @@ namespace
|
|||
{
|
||||
namespace to_string_helpers
|
||||
{
|
||||
using Buffer = libtransmission::Buffer;
|
||||
using OutBuf = libtransmission::Buffer;
|
||||
|
||||
void saveIntFunc(tr_variant const* val, void* vout)
|
||||
{
|
||||
auto buf = std::array<char, 64>{};
|
||||
auto const* const out = fmt::format_to(std::data(buf), FMT_COMPILE("i{:d}e"), val->val.i);
|
||||
static_cast<Buffer*>(vout)->add(std::data(buf), static_cast<size_t>(out - std::data(buf)));
|
||||
auto out = static_cast<OutBuf*>(vout);
|
||||
|
||||
auto const [buf, buflen] = out->reserve_space(64U);
|
||||
auto* walk = reinterpret_cast<char*>(buf);
|
||||
auto const* const begin = walk;
|
||||
walk = fmt::format_to(walk, FMT_COMPILE("i{:d}e"), val->val.i);
|
||||
out->commit_space(walk - begin);
|
||||
}
|
||||
|
||||
void saveBoolFunc(tr_variant const* val, void* vout)
|
||||
{
|
||||
static_cast<Buffer*>(vout)->add(val->val.b ? "i1e"sv : "i0e"sv);
|
||||
static_cast<OutBuf*>(vout)->add(val->val.b ? "i1e"sv : "i0e"sv);
|
||||
}
|
||||
|
||||
void saveStringImpl(Buffer* tgt, std::string_view sv)
|
||||
void saveStringImpl(OutBuf* out, std::string_view sv)
|
||||
{
|
||||
// `${sv.size()}:${sv}`
|
||||
auto prefix = std::array<char, 32>{};
|
||||
auto const* const out = fmt::format_to(std::data(prefix), FMT_COMPILE("{:d}:"), std::size(sv));
|
||||
tgt->add(std::data(prefix), out - std::data(prefix));
|
||||
tgt->add(sv);
|
||||
auto const [buf, buflen] = out->reserve_space(std::size(sv) + 32U);
|
||||
auto* walk = reinterpret_cast<char*>(buf);
|
||||
auto const* const begin = walk;
|
||||
walk = fmt::format_to(walk, FMT_COMPILE("{:d}:"), std::size(sv));
|
||||
walk = std::copy_n(std::data(sv), std::size(sv), walk);
|
||||
out->commit_space(walk - begin);
|
||||
}
|
||||
|
||||
void saveStringFunc(tr_variant const* v, void* vout)
|
||||
{
|
||||
auto sv = std::string_view{};
|
||||
(void)!tr_variantGetStrView(v, &sv);
|
||||
saveStringImpl(static_cast<Buffer*>(vout), sv);
|
||||
saveStringImpl(static_cast<OutBuf*>(vout), sv);
|
||||
}
|
||||
|
||||
void saveRealFunc(tr_variant const* val, void* vout)
|
||||
|
@ -313,22 +319,22 @@ void saveRealFunc(tr_variant const* val, void* vout)
|
|||
|
||||
auto buf = std::array<char, 64>{};
|
||||
auto const* const out = fmt::format_to(std::data(buf), FMT_COMPILE("{:f}"), val->val.d);
|
||||
saveStringImpl(static_cast<Buffer*>(vout), { std::data(buf), static_cast<size_t>(out - std::data(buf)) });
|
||||
saveStringImpl(static_cast<OutBuf*>(vout), { std::data(buf), static_cast<size_t>(out - std::data(buf)) });
|
||||
}
|
||||
|
||||
void saveDictBeginFunc(tr_variant const* /*val*/, void* vbuf)
|
||||
{
|
||||
static_cast<Buffer*>(vbuf)->push_back('d');
|
||||
static_cast<OutBuf*>(vbuf)->push_back('d');
|
||||
}
|
||||
|
||||
void saveListBeginFunc(tr_variant const* /*val*/, void* vbuf)
|
||||
{
|
||||
static_cast<Buffer*>(vbuf)->push_back('l');
|
||||
static_cast<OutBuf*>(vbuf)->push_back('l');
|
||||
}
|
||||
|
||||
void saveContainerEndFunc(tr_variant const* /*val*/, void* vbuf)
|
||||
{
|
||||
static_cast<Buffer*>(vbuf)->push_back('e');
|
||||
static_cast<OutBuf*>(vbuf)->push_back('e');
|
||||
}
|
||||
|
||||
struct VariantWalkFuncs const walk_funcs = {
|
||||
|
@ -348,7 +354,7 @@ std::string tr_variantToStrBenc(tr_variant const* top)
|
|||
{
|
||||
using namespace to_string_helpers;
|
||||
|
||||
auto buf = libtransmission::Buffer{};
|
||||
auto buf = OutBuf{};
|
||||
tr_variantWalk(top, &walk_funcs, &buf, true);
|
||||
return buf.to_string();
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include "libtransmission/variant.h"
|
||||
|
||||
using namespace std::literals;
|
||||
using Buffer = libtransmission::Buffer;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -443,7 +442,7 @@ struct JsonWalk
|
|||
}
|
||||
|
||||
std::deque<ParentState> parents;
|
||||
Buffer out;
|
||||
libtransmission::Buffer out;
|
||||
bool doIndent;
|
||||
};
|
||||
|
||||
|
@ -547,25 +546,27 @@ void jsonBoolFunc(tr_variant const* val, void* vdata)
|
|||
|
||||
void jsonRealFunc(tr_variant const* val, void* vdata)
|
||||
{
|
||||
auto* data = static_cast<struct JsonWalk*>(vdata);
|
||||
auto* const data = static_cast<struct JsonWalk*>(vdata);
|
||||
|
||||
auto const [buf, buflen] = data->out.reserve_space(64);
|
||||
auto* walk = reinterpret_cast<char*>(buf);
|
||||
auto const* const begin = walk;
|
||||
|
||||
if (fabs(val->val.d - (int)val->val.d) < 0.00001)
|
||||
{
|
||||
auto buf = std::array<char, 64>{};
|
||||
auto const* const out = fmt::format_to(std::data(buf), FMT_COMPILE("{:.0f}"), val->val.d);
|
||||
data->out.add(std::data(buf), static_cast<size_t>(out - std::data(buf)));
|
||||
walk = fmt::format_to(walk, FMT_COMPILE("{:.0f}"), val->val.d);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto buf = std::array<char, 64>{};
|
||||
auto const* const out = fmt::format_to(std::data(buf), FMT_COMPILE("{:.4f}"), val->val.d);
|
||||
data->out.add(std::data(buf), static_cast<size_t>(out - std::data(buf)));
|
||||
walk = fmt::format_to(walk, FMT_COMPILE("{:.4f}"), val->val.d);
|
||||
}
|
||||
|
||||
data->out.commit_space(walk - begin);
|
||||
|
||||
jsonChildFunc(data);
|
||||
}
|
||||
|
||||
void write_escaped_char(Buffer& out, std::string_view& sv)
|
||||
[[nodiscard]] char* write_escaped_char(char* buf, char const* const end, std::string_view& sv)
|
||||
{
|
||||
auto u16buf = std::array<std::uint16_t, 2>{};
|
||||
|
||||
|
@ -577,85 +578,97 @@ void write_escaped_char(Buffer& out, std::string_view& sv)
|
|||
|
||||
for (auto it = std::cbegin(u16buf); it != end16; ++it)
|
||||
{
|
||||
auto arr = std::array<char, 16>{};
|
||||
auto const result = fmt::format_to_n(std::data(arr), std::size(arr), FMT_COMPILE("\\u{:04x}"), *it);
|
||||
out.add(std::data(arr), result.size);
|
||||
buf = fmt::format_to_n(buf, end - buf - 1, FMT_COMPILE("\\u{:04x}"), *it).out;
|
||||
}
|
||||
|
||||
sv.remove_prefix(walk8 - begin8 - 1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void jsonStringFunc(tr_variant const* val, void* vdata)
|
||||
{
|
||||
auto* data = static_cast<struct JsonWalk*>(vdata);
|
||||
auto* const data = static_cast<struct JsonWalk*>(vdata);
|
||||
|
||||
auto sv = std::string_view{};
|
||||
(void)!tr_variantGetStrView(val, &sv);
|
||||
|
||||
auto& out = data->out;
|
||||
out.reserve(std::size(data->out) + std::size(sv) * 6 + 2);
|
||||
out.push_back('"');
|
||||
auto const [buf, buflen] = out.reserve_space(std::size(sv) * 6 + 2);
|
||||
auto* walk = reinterpret_cast<char*>(buf);
|
||||
auto const* const begin = walk;
|
||||
auto const* const end = begin + buflen;
|
||||
|
||||
*walk++ = '"';
|
||||
|
||||
for (; !std::empty(sv); sv.remove_prefix(1))
|
||||
{
|
||||
switch (sv.front())
|
||||
{
|
||||
case '\b':
|
||||
out.add(R"(\b)"sv);
|
||||
*walk++ = '\\';
|
||||
*walk++ = 'b';
|
||||
break;
|
||||
|
||||
case '\f':
|
||||
out.add(R"(\f)"sv);
|
||||
*walk++ = '\\';
|
||||
*walk++ = 'f';
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
out.add(R"(\n)"sv);
|
||||
*walk++ = '\\';
|
||||
*walk++ = 'n';
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
out.add(R"(\r)"sv);
|
||||
*walk++ = '\\';
|
||||
*walk++ = 'r';
|
||||
break;
|
||||
|
||||
case '\t':
|
||||
out.add(R"(\t)"sv);
|
||||
*walk++ = '\\';
|
||||
*walk++ = 't';
|
||||
break;
|
||||
|
||||
case '"':
|
||||
out.add(R"(\")"sv);
|
||||
*walk++ = '\\';
|
||||
*walk++ = '"';
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
out.add(R"(\\)"sv);
|
||||
*walk++ = '\\';
|
||||
*walk++ = '\\';
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isprint((unsigned char)sv.front()) != 0)
|
||||
{
|
||||
out.push_back(sv.front());
|
||||
*walk++ = sv.front();
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
write_escaped_char(out, sv);
|
||||
walk = write_escaped_char(walk, end, sv);
|
||||
}
|
||||
catch (utf8::exception const&)
|
||||
{
|
||||
out.push_back('?');
|
||||
*walk++ = '?';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out.push_back('"');
|
||||
*walk++ = '"';
|
||||
TR_ASSERT(walk <= end);
|
||||
out.commit_space(walk - begin);
|
||||
|
||||
jsonChildFunc(data);
|
||||
}
|
||||
|
||||
void jsonDictBeginFunc(tr_variant const* val, void* vdata)
|
||||
{
|
||||
auto* data = static_cast<struct JsonWalk*>(vdata);
|
||||
auto* const data = static_cast<struct JsonWalk*>(vdata);
|
||||
|
||||
jsonPushParent(data, val);
|
||||
data->out.push_back('{');
|
||||
|
@ -669,7 +682,7 @@ void jsonDictBeginFunc(tr_variant const* val, void* vdata)
|
|||
void jsonListBeginFunc(tr_variant const* val, void* vdata)
|
||||
{
|
||||
size_t const n_children = tr_variantListSize(val);
|
||||
auto* data = static_cast<struct JsonWalk*>(vdata);
|
||||
auto* const data = static_cast<struct JsonWalk*>(vdata);
|
||||
|
||||
jsonPushParent(data, val);
|
||||
data->out.push_back('[');
|
||||
|
@ -682,7 +695,7 @@ void jsonListBeginFunc(tr_variant const* val, void* vdata)
|
|||
|
||||
void jsonContainerEndFunc(tr_variant const* val, void* vdata)
|
||||
{
|
||||
auto* data = static_cast<struct JsonWalk*>(vdata);
|
||||
auto* const data = static_cast<struct JsonWalk*>(vdata);
|
||||
|
||||
jsonPopParent(data);
|
||||
|
||||
|
|
|
@ -551,7 +551,7 @@ TEST_F(AnnouncerUdpTest, handleMessageReturnsFalseOnInvalidMessage)
|
|||
EXPECT_FALSE(announcer->handle_message(std::data(arr), response_size));
|
||||
|
||||
// send a connection response but with an *invalid* action
|
||||
buf.clear();
|
||||
buf = {};
|
||||
buf.add_uint32(ScrapeAction);
|
||||
buf.add_uint32(transaction_id);
|
||||
buf.add_uint64(tr_rand_obj<uint64_t>());
|
||||
|
|
Loading…
Reference in a new issue