mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 06:04:57 +00:00
LibTLS: Add segmentation to the application buffer to avoid memcpy churn
We were previously doing a *lot* of unnecessary memcpy work when transferring large files. This patch addresses the issue by introducing a simple segmented buffer with no additional work when appending new data, or when transfering out of the buffer.
This commit is contained in:
parent
40f87f0954
commit
27a294547d
3 changed files with 42 additions and 4 deletions
|
@ -498,7 +498,7 @@ ssize_t TLSv12::handle_message(ReadonlyBytes buffer)
|
|||
} else {
|
||||
dbgln_if(TLS_DEBUG, "application data message of size {}", plain.size());
|
||||
|
||||
if (m_context.application_buffer.try_append(plain.data(), plain.size()).is_error()) {
|
||||
if (m_context.application_buffer.try_append(plain).is_error()) {
|
||||
payload_res = (i8)Error::DecryptionFailed;
|
||||
auto packet = build_alert(true, (u8)AlertDescription::DECRYPTION_FAILED_RESERVED);
|
||||
write_packet(packet);
|
||||
|
|
|
@ -27,8 +27,7 @@ ErrorOr<Bytes> TLSv12::read_some(Bytes bytes)
|
|||
return Bytes {};
|
||||
}
|
||||
|
||||
TRY(m_context.application_buffer.slice(0, size_to_read)).span().copy_to(bytes);
|
||||
m_context.application_buffer = TRY(m_context.application_buffer.slice(size_to_read, m_context.application_buffer.size() - size_to_read));
|
||||
m_context.application_buffer.transfer(bytes, size_to_read);
|
||||
return Bytes { bytes.data(), size_to_read };
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "Certificate.h"
|
||||
#include <AK/IPv4Address.h>
|
||||
#include <AK/Queue.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <LibCore/Notifier.h>
|
||||
#include <LibCore/Socket.h>
|
||||
|
@ -197,6 +198,44 @@ struct Options {
|
|||
#undef OPTION_WITH_DEFAULTS
|
||||
};
|
||||
|
||||
class SegmentedBuffer {
|
||||
public:
|
||||
[[nodiscard]] size_t size() const { return m_size; }
|
||||
[[nodiscard]] bool is_empty() const { return m_size == 0; }
|
||||
void transfer(Bytes dest, size_t size)
|
||||
{
|
||||
VERIFY(size <= dest.size());
|
||||
size_t transferred = 0;
|
||||
while (transferred < size) {
|
||||
auto& buffer = m_buffers.head();
|
||||
size_t to_transfer = min(buffer.size() - m_offset_into_current_buffer, size - transferred);
|
||||
memcpy(dest.offset(transferred), buffer.data() + m_offset_into_current_buffer, to_transfer);
|
||||
transferred += to_transfer;
|
||||
m_offset_into_current_buffer += to_transfer;
|
||||
if (m_offset_into_current_buffer >= buffer.size()) {
|
||||
m_buffers.dequeue();
|
||||
m_offset_into_current_buffer = 0;
|
||||
}
|
||||
m_size -= to_transfer;
|
||||
}
|
||||
}
|
||||
|
||||
AK::ErrorOr<void> try_append(ReadonlyBytes data)
|
||||
{
|
||||
if (Checked<size_t>::addition_would_overflow(m_size, data.size()))
|
||||
return AK::Error::from_errno(EOVERFLOW);
|
||||
|
||||
m_size += data.size();
|
||||
m_buffers.enqueue(TRY(ByteBuffer::copy(data)));
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_size { 0 };
|
||||
Queue<ByteBuffer> m_buffers;
|
||||
size_t m_offset_into_current_buffer { 0 };
|
||||
};
|
||||
|
||||
struct Context {
|
||||
bool verify_chain(StringView host) const;
|
||||
bool verify_certificate_pair(Certificate const& subject, Certificate const& issuer) const;
|
||||
|
@ -237,7 +276,7 @@ struct Context {
|
|||
|
||||
ByteBuffer tls_buffer;
|
||||
|
||||
ByteBuffer application_buffer;
|
||||
SegmentedBuffer application_buffer;
|
||||
|
||||
bool is_child { false };
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue