From 72684497958440c78952a7be53e336cd423adf20 Mon Sep 17 00:00:00 2001 From: Igor Egorov Date: Wed, 18 Nov 2020 14:39:23 +0300 Subject: [PATCH 1/5] Noise::write now reports the correct amount of bytes Signed-off-by: Igor Egorov --- include/libp2p/security/noise/noise_connection.hpp | 1 + src/security/noise/noise_connection.cpp | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/libp2p/security/noise/noise_connection.hpp b/include/libp2p/security/noise/noise_connection.hpp index 703360b8..58c27f15 100644 --- a/include/libp2p/security/noise/noise_connection.hpp +++ b/include/libp2p/security/noise/noise_connection.hpp @@ -69,6 +69,7 @@ namespace libp2p::connection { std::shared_ptr framer_; size_t already_read_; size_t already_wrote_; + size_t plaintext_len_to_write_; common::ByteArray writing_; common::Logger log_ = common::createLogger("NoiseConn"); }; diff --git a/src/security/noise/noise_connection.cpp b/src/security/noise/noise_connection.cpp index 89b02940..fbf48c01 100644 --- a/src/security/noise/noise_connection.cpp +++ b/src/security/noise/noise_connection.cpp @@ -42,7 +42,8 @@ namespace libp2p::connection { framer_{std::make_shared( raw_connection_, frame_buffer_)}, already_read_{0}, - already_wrote_{0} { + already_wrote_{0}, + plaintext_len_to_write_{0} { BOOST_ASSERT(raw_connection_); BOOST_ASSERT(key_marshaller_); BOOST_ASSERT(encoder_cs_); @@ -99,9 +100,14 @@ namespace libp2p::connection { void NoiseConnection::write(gsl::span in, size_t bytes, libp2p::basic::Writer::WriteCallbackFunc cb) { + if (0 == plaintext_len_to_write_) { + plaintext_len_to_write_ = bytes; + } if (bytes == 0) { - auto n{already_wrote_}; + BOOST_ASSERT(already_wrote_ >= plaintext_len_to_write_); + auto n{plaintext_len_to_write_}; already_wrote_ = 0; + plaintext_len_to_write_ = 0; return cb(n); } auto n{std::min(bytes, security::noise::kMaxPlainText)}; From ae3c2ba8cc6928a8da44e4206787862fb10ebdd3 Mon Sep 17 00:00:00 2001 From: Igor Egorov Date: Thu, 21 Jan 2021 12:22:09 +0300 Subject: [PATCH 2/5] Noise fix amount of bytes written reporting Signed-off-by: Igor Egorov --- .../security/noise/noise_connection.hpp | 10 ++++-- src/security/noise/noise_connection.cpp | 31 ++++++++++--------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/include/libp2p/security/noise/noise_connection.hpp b/include/libp2p/security/noise/noise_connection.hpp index 58c27f15..cf77f741 100644 --- a/include/libp2p/security/noise/noise_connection.hpp +++ b/include/libp2p/security/noise/noise_connection.hpp @@ -21,6 +21,11 @@ namespace libp2p::connection { class NoiseConnection : public SecureConnection, public std::enable_shared_from_this { public: + struct WriteContext { + size_t bytes_written; + size_t to_write; + }; + ~NoiseConnection() override = default; NoiseConnection( @@ -59,6 +64,9 @@ namespace libp2p::connection { outcome::result remotePublicKey() const override; private: + void write(gsl::span in, size_t bytes, WriteContext ctx, + WriteCallbackFunc cb); + std::shared_ptr raw_connection_; crypto::PublicKey local_; crypto::PublicKey remote_; @@ -68,8 +76,6 @@ namespace libp2p::connection { std::shared_ptr frame_buffer_; std::shared_ptr framer_; size_t already_read_; - size_t already_wrote_; - size_t plaintext_len_to_write_; common::ByteArray writing_; common::Logger log_ = common::createLogger("NoiseConn"); }; diff --git a/src/security/noise/noise_connection.cpp b/src/security/noise/noise_connection.cpp index fbf48c01..a4756652 100644 --- a/src/security/noise/noise_connection.cpp +++ b/src/security/noise/noise_connection.cpp @@ -41,9 +41,7 @@ namespace libp2p::connection { std::make_shared(security::noise::kMaxMsgLen)}, framer_{std::make_shared( raw_connection_, frame_buffer_)}, - already_read_{0}, - already_wrote_{0}, - plaintext_len_to_write_{0} { + already_read_{0} { BOOST_ASSERT(raw_connection_); BOOST_ASSERT(key_marshaller_); BOOST_ASSERT(encoder_cs_); @@ -100,25 +98,28 @@ namespace libp2p::connection { void NoiseConnection::write(gsl::span in, size_t bytes, libp2p::basic::Writer::WriteCallbackFunc cb) { - if (0 == plaintext_len_to_write_) { - plaintext_len_to_write_ = bytes; - } - if (bytes == 0) { - BOOST_ASSERT(already_wrote_ >= plaintext_len_to_write_); - auto n{plaintext_len_to_write_}; - already_wrote_ = 0; - plaintext_len_to_write_ = 0; - return cb(n); + WriteContext context{.bytes_written = 0, .to_write = bytes}; + write(in, bytes, context, std::move(cb)); + } + + void NoiseConnection::write(gsl::span in, size_t bytes, + NoiseConnection::WriteContext ctx, + basic::Writer::WriteCallbackFunc cb) { + if (0 == bytes) { + BOOST_ASSERT(ctx.bytes_written >= ctx.to_write); + return cb(ctx.to_write); } auto n{std::min(bytes, security::noise::kMaxPlainText)}; OUTCOME_CB(encrypted, encoder_cs_->encrypt({}, in.subspan(0, n), {})); writing_ = std::move(encrypted); framer_->write(writing_, [self{shared_from_this()}, in{in.subspan(n)}, - bytes{bytes - n}, cb{std::move(cb)}](auto _n) { + bytes{bytes - n}, cb{std::move(cb)}, ctx](auto _n) { OUTCOME_CB(n, _n); - self->already_wrote_ += n; - self->write(in, bytes, cb); + WriteContext context{.bytes_written = ctx.bytes_written, + .to_write = ctx.to_write}; + context.bytes_written += n; + self->write(in, bytes, context, cb); }); } From 219a3ce21a082431f3856e2d5a73fdf9207a7a5e Mon Sep 17 00:00:00 2001 From: Igor Egorov Date: Mon, 23 Aug 2021 18:10:28 +0300 Subject: [PATCH 3/5] (Won't compile) Fix data handling in Noise::write() Signed-off-by: Igor Egorov --- .../security/noise/noise_connection.hpp | 17 ++++--- src/security/noise/noise_connection.cpp | 45 +++++++++++++------ 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/include/libp2p/security/noise/noise_connection.hpp b/include/libp2p/security/noise/noise_connection.hpp index 39fbcaf6..b1472166 100644 --- a/include/libp2p/security/noise/noise_connection.hpp +++ b/include/libp2p/security/noise/noise_connection.hpp @@ -6,6 +6,8 @@ #ifndef LIBP2P_INCLUDE_LIBP2P_SECURITY_NOISE_NOISE_CONNECTION_HPP #define LIBP2P_INCLUDE_LIBP2P_SECURITY_NOISE_NOISE_CONNECTION_HPP +#include + #include #include @@ -22,9 +24,12 @@ namespace libp2p::connection { class NoiseConnection : public SecureConnection, public std::enable_shared_from_this { public: - struct WriteContext { - size_t bytes_written; - size_t to_write; + using BufferList = std::list; + + struct OperationContext { + size_t bytes_served; /// written or read bytes count + const size_t total_bytes; /// total size to process + BufferList::iterator write_buffer; /// temporary data storage }; ~NoiseConnection() override = default; @@ -70,9 +75,11 @@ namespace libp2p::connection { outcome::result remotePublicKey() const override; private: - void write(gsl::span in, size_t bytes, WriteContext ctx, + void write(gsl::span in, size_t bytes, OperationContext ctx, WriteCallbackFunc cb); + void eraseWriteBuffer(BufferList::iterator &iterator); + std::shared_ptr raw_connection_; crypto::PublicKey local_; crypto::PublicKey remote_; @@ -82,7 +89,7 @@ namespace libp2p::connection { std::shared_ptr frame_buffer_; std::shared_ptr framer_; size_t already_read_; - common::ByteArray writing_; + BufferList write_buffers_; log::Logger log_ = log::createLogger("NoiseConnection"); public: diff --git a/src/security/noise/noise_connection.cpp b/src/security/noise/noise_connection.cpp index 41ff4d06..eaa7332f 100644 --- a/src/security/noise/noise_connection.cpp +++ b/src/security/noise/noise_connection.cpp @@ -12,10 +12,11 @@ #define UNIQUE_NAME(base) base##__LINE__ #endif // UNIQUE_NAME -#define OUTCOME_CB_I(var, res) \ - auto && (var) = (res); \ - if ((var).has_error()) { \ - return cb((var).error()); \ +#define OUTCOME_CB_I(var, res) \ + auto && (var) = (res); \ + if ((var).has_error()) { \ + self->eraseWriteBuffer(ctx.write_buffer); \ + return cb((var).error()); \ } #define OUTCOME_CB_NAME_I(var, val, res) \ @@ -98,28 +99,36 @@ namespace libp2p::connection { void NoiseConnection::write(gsl::span in, size_t bytes, libp2p::basic::Writer::WriteCallbackFunc cb) { - WriteContext context{.bytes_written = 0, .to_write = bytes}; + OperationContext context{.bytes_served = 0, + .total_bytes = bytes, + .write_buffer = write_buffers_.end()}; write(in, bytes, context, std::move(cb)); } void NoiseConnection::write(gsl::span in, size_t bytes, - NoiseConnection::WriteContext ctx, + NoiseConnection::OperationContext ctx, basic::Writer::WriteCallbackFunc cb) { + auto *self{this}; // for OUTCOME_CB if (0 == bytes) { - BOOST_ASSERT(ctx.bytes_written >= ctx.to_write); - return cb(ctx.to_write); + BOOST_ASSERT(ctx.bytes_served >= ctx.total_bytes); + eraseWriteBuffer(ctx.write_buffer); + return cb(ctx.total_bytes); } auto n{std::min(bytes, security::noise::kMaxPlainText)}; OUTCOME_CB(encrypted, encoder_cs_->encrypt({}, in.subspan(0, n), {})); - writing_ = std::move(encrypted); - framer_->write(writing_, + if (write_buffers_.end() == ctx.write_buffer) { + constexpr auto dummy_size = 1; + constexpr auto dummy_value = 0x0; + ctx.write_buffer = + write_buffers_.emplace(write_buffers_.end(), dummy_size, dummy_value); + } + ctx.write_buffer->swap(encrypted); + framer_->write(*ctx.write_buffer, [self{shared_from_this()}, in{in.subspan(n)}, bytes{bytes - n}, cb{std::move(cb)}, ctx](auto _n) mutable { OUTCOME_CB(n, _n); - WriteContext context{.bytes_written = ctx.bytes_written, - .to_write = ctx.to_write}; - context.bytes_written += n; - self->write(in, bytes, context, cb); + ctx.bytes_served += n; + self->write(in, bytes, ctx, std::move(cb)); }); } @@ -166,4 +175,12 @@ namespace libp2p::connection { const { return remote_; } + + void NoiseConnection::eraseWriteBuffer(BufferList::iterator &iterator) { + if (write_buffers_.end() == iterator) { + return; + } + write_buffers_.erase(iterator); + iterator = write_buffers_.end(); + } } // namespace libp2p::connection From 6beba48b81595323d7d64db4e5a16a528ea02967 Mon Sep 17 00:00:00 2001 From: Igor Egorov Date: Mon, 23 Aug 2021 18:35:28 +0300 Subject: [PATCH 4/5] Fix data handling in Noise::read() & Noise::readSome() Signed-off-by: Igor Egorov --- .../security/noise/noise_connection.hpp | 7 +++- src/security/noise/noise_connection.cpp | 40 +++++++++++++------ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/include/libp2p/security/noise/noise_connection.hpp b/include/libp2p/security/noise/noise_connection.hpp index b1472166..39d270fb 100644 --- a/include/libp2p/security/noise/noise_connection.hpp +++ b/include/libp2p/security/noise/noise_connection.hpp @@ -75,6 +75,12 @@ namespace libp2p::connection { outcome::result remotePublicKey() const override; private: + void read(gsl::span out, size_t bytes, OperationContext ctx, + ReadCallbackFunc cb); + + void readSome(gsl::span out, size_t bytes, OperationContext ctx, + ReadCallbackFunc cb); + void write(gsl::span in, size_t bytes, OperationContext ctx, WriteCallbackFunc cb); @@ -88,7 +94,6 @@ namespace libp2p::connection { std::shared_ptr decoder_cs_; std::shared_ptr frame_buffer_; std::shared_ptr framer_; - size_t already_read_; BufferList write_buffers_; log::Logger log_ = log::createLogger("NoiseConnection"); diff --git a/src/security/noise/noise_connection.cpp b/src/security/noise/noise_connection.cpp index eaa7332f..0d0c35d9 100644 --- a/src/security/noise/noise_connection.cpp +++ b/src/security/noise/noise_connection.cpp @@ -41,8 +41,7 @@ namespace libp2p::connection { frame_buffer_{ std::make_shared(security::noise::kMaxMsgLen)}, framer_{std::make_shared( - raw_connection_, frame_buffer_)}, - already_read_{0} { + raw_connection_, frame_buffer_)} { BOOST_ASSERT(raw_connection_); BOOST_ASSERT(key_marshaller_); BOOST_ASSERT(encoder_cs_); @@ -62,24 +61,39 @@ namespace libp2p::connection { void NoiseConnection::read(gsl::span out, size_t bytes, libp2p::basic::Reader::ReadCallbackFunc cb) { + OperationContext context{.bytes_served = 0, + .total_bytes = bytes, + .write_buffer = write_buffers_.end()}; + read(out, bytes, context, std::move(cb)); + } + + void NoiseConnection::read(gsl::span out, size_t bytes, + OperationContext ctx, ReadCallbackFunc cb) { size_t out_size{out.empty() ? 0u : static_cast(out.size())}; BOOST_ASSERT(out_size >= bytes); - if (bytes == 0) { - auto n{already_read_}; - already_read_ = 0; - return cb(n); + if (0 == bytes) { + BOOST_ASSERT(ctx.bytes_served == ctx.total_bytes); + return cb(ctx.bytes_served); } readSome(out, bytes, - [self{shared_from_this()}, out, bytes, - cb{std::move(cb)}](auto _n) mutable { + [self{shared_from_this()}, out, bytes, cb{std::move(cb)}, + ctx](auto _n) mutable { OUTCOME_CB(n, _n); - self->already_read_ += n; - self->read(out.subspan(n), bytes - n, std::move(cb)); + ctx.bytes_served += n; + self->read(out.subspan(n), bytes - n, ctx, std::move(cb)); }); } void NoiseConnection::readSome(gsl::span out, size_t bytes, libp2p::basic::Reader::ReadCallbackFunc cb) { + OperationContext context{.bytes_served = 0, + .total_bytes = bytes, + .write_buffer = write_buffers_.end()}; + readSome(out, bytes, context, std::move(cb)); + } + + void NoiseConnection::readSome(gsl::span out, size_t bytes, + OperationContext ctx, ReadCallbackFunc cb) { if (not frame_buffer_->empty()) { auto n{std::min(bytes, frame_buffer_->size())}; auto begin{frame_buffer_->begin()}; @@ -88,12 +102,12 @@ namespace libp2p::connection { frame_buffer_->erase(begin, end); return cb(n); } - framer_->read([self{shared_from_this()}, out, bytes, - cb{std::move(cb)}](auto _data) mutable { + framer_->read([self{shared_from_this()}, out, bytes, cb{std::move(cb)}, + ctx](auto _data) mutable { OUTCOME_CB(data, _data); OUTCOME_CB(decrypted, self->decoder_cs_->decrypt({}, *data, {})); self->frame_buffer_->assign(decrypted.begin(), decrypted.end()); - self->readSome(out, bytes, std::move(cb)); + self->readSome(out, bytes, ctx, std::move(cb)); }); } From 964f0f98b8b39cf1104233280ac9dbdfe651eca6 Mon Sep 17 00:00:00 2001 From: Igor Egorov Date: Mon, 23 Aug 2021 21:24:57 +0300 Subject: [PATCH 5/5] Fix clang-tidy issues Signed-off-by: Igor Egorov --- src/common/hexutil.cpp | 6 +++-- src/crypto/common_functions.cpp | 23 ++++++++++--------- .../hmac_provider/hmac_provider_ctr_impl.cpp | 7 +++--- .../key_marshaller/key_marshaller_impl.cpp | 4 ++-- .../handshake_message_marshaller_impl.cpp | 6 +++-- src/security/noise/noise_connection.cpp | 17 +++++++------- 6 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/common/hexutil.cpp b/src/common/hexutil.cpp index bb7494c6..65f359f4 100644 --- a/src/common/hexutil.cpp +++ b/src/common/hexutil.cpp @@ -3,6 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include @@ -24,13 +26,13 @@ namespace libp2p::common { std::string int_to_hex(uint64_t n, size_t fixed_width) noexcept { std::stringstream result; - result.width(fixed_width); + result.width(static_cast(fixed_width)); result.fill('0'); result << std::hex << std::uppercase << n; auto str = result.str(); if (str.length() % 2 != 0) { str.push_back('\0'); - for (int64_t i = str.length() - 2; i >= 0; --i) { + for (int64_t i = static_cast(str.length()) - 2; i >= 0; --i) { str[i + 1] = str[i]; } str[0] = '0'; diff --git a/src/crypto/common_functions.cpp b/src/crypto/common_functions.cpp index 038e9ffd..562822c8 100644 --- a/src/crypto/common_functions.cpp +++ b/src/crypto/common_functions.cpp @@ -25,8 +25,8 @@ namespace libp2p::crypto { } // turn private key bytes into big number - BIGNUM *private_bignum{ - BN_bin2bn(private_key.data(), private_key.size(), nullptr)}; + BIGNUM *private_bignum{BN_bin2bn( + private_key.data(), static_cast(private_key.size()), nullptr)}; if (nullptr == private_bignum) { return FAILED; } @@ -92,10 +92,11 @@ namespace libp2p::crypto { int, gsl::span, decltype(EVP_PKEY_new_raw_public_key) *); outcome::result> GenerateEcSignature( - gsl::span digest, - const std::shared_ptr &key) { + gsl::span digest, const std::shared_ptr &key) { std::shared_ptr signature{ - ECDSA_do_sign(digest.data(), digest.size(), key.get()), ECDSA_SIG_free}; + ECDSA_do_sign(digest.data(), static_cast(digest.size()), + key.get()), + ECDSA_SIG_free}; if (signature == nullptr) { return CryptoProviderError::SIGNATURE_GENERATION_FAILED; } @@ -110,12 +111,12 @@ namespace libp2p::crypto { return std::move(signature_bytes); } - outcome::result VerifyEcSignature( - gsl::span digest, - gsl::span signature, - const std::shared_ptr &key) { - int result = ECDSA_verify(0, digest.data(), digest.size(), signature.data(), - signature.size(), key.get()); + outcome::result VerifyEcSignature(gsl::span digest, + gsl::span signature, + const std::shared_ptr &key) { + int result = ECDSA_verify(0, digest.data(), static_cast(digest.size()), + signature.data(), + static_cast(signature.size()), key.get()); if (result < 0) { return CryptoProviderError::SIGNATURE_VERIFICATION_FAILED; } diff --git a/src/crypto/hmac_provider/hmac_provider_ctr_impl.cpp b/src/crypto/hmac_provider/hmac_provider_ctr_impl.cpp index 35658964..2145f142 100644 --- a/src/crypto/hmac_provider/hmac_provider_ctr_impl.cpp +++ b/src/crypto/hmac_provider/hmac_provider_ctr_impl.cpp @@ -40,7 +40,8 @@ namespace libp2p::crypto::hmac { return; } initialized_ = 1 - == HMAC_Init_ex(hmac_ctx_, key_.data(), key_.size(), hash_st_, nullptr); + == HMAC_Init_ex(hmac_ctx_, key_.data(), static_cast(key_.size()), + hash_st_, nullptr); } HmacProviderCtrImpl::~HmacProviderCtrImpl() { @@ -87,8 +88,8 @@ namespace libp2p::crypto::hmac { hmac_ctx_ = HMAC_CTX_new(); if (nullptr == hmac_ctx_ or 1 - != HMAC_Init_ex(hmac_ctx_, key_.data(), key_.size(), hash_st_, - nullptr)) { + != HMAC_Init_ex(hmac_ctx_, key_.data(), + static_cast(key_.size()), hash_st_, nullptr)) { return HmacProviderError::FAILED_INITIALIZE_CONTEXT; } initialized_ = true; diff --git a/src/crypto/key_marshaller/key_marshaller_impl.cpp b/src/crypto/key_marshaller/key_marshaller_impl.cpp index 99d65435..8fff134d 100644 --- a/src/crypto/key_marshaller/key_marshaller_impl.cpp +++ b/src/crypto/key_marshaller/key_marshaller_impl.cpp @@ -84,7 +84,7 @@ namespace libp2p::crypto::marshaller { const ProtobufKey &proto_key) const { protobuf::PublicKey protobuf_key; if (!protobuf_key.ParseFromArray(proto_key.key.data(), - proto_key.key.size())) { + static_cast(proto_key.key.size()))) { return CryptoProviderError::FAILED_UNMARSHAL_DATA; } @@ -101,7 +101,7 @@ namespace libp2p::crypto::marshaller { const ProtobufKey &proto_key) const { protobuf::PublicKey protobuf_key; if (!protobuf_key.ParseFromArray(proto_key.key.data(), - proto_key.key.size())) { + static_cast(proto_key.key.size()))) { return CryptoProviderError::FAILED_UNMARSHAL_DATA; } diff --git a/src/security/noise/handshake_message_marshaller_impl.cpp b/src/security/noise/handshake_message_marshaller_impl.cpp index 53eb843f..9042aa8b 100644 --- a/src/security/noise/handshake_message_marshaller_impl.cpp +++ b/src/security/noise/handshake_message_marshaller_impl.cpp @@ -59,7 +59,8 @@ namespace libp2p::security::noise { const HandshakeMessage &msg) const { OUTCOME_TRY(proto_msg, handyToProto(msg)); common::ByteArray out_msg(proto_msg.ByteSizeLong()); - if (not proto_msg.SerializeToArray(out_msg.data(), out_msg.size())) { + if (not proto_msg.SerializeToArray(out_msg.data(), + static_cast(out_msg.size()))) { return Error::MESSAGE_SERIALIZING_ERROR; } return out_msg; @@ -69,7 +70,8 @@ namespace libp2p::security::noise { HandshakeMessageMarshallerImpl::unmarshal( gsl::span msg_bytes) const { protobuf::NoiseHandshakePayload proto_msg; - if (not proto_msg.ParseFromArray(msg_bytes.data(), msg_bytes.size())) { + if (not proto_msg.ParseFromArray(msg_bytes.data(), + static_cast(msg_bytes.size()))) { return Error::MESSAGE_DESERIALIZING_ERROR; } return protoToHandy(proto_msg); diff --git a/src/security/noise/noise_connection.cpp b/src/security/noise/noise_connection.cpp index 0d0c35d9..d0bfd1b1 100644 --- a/src/security/noise/noise_connection.cpp +++ b/src/security/noise/noise_connection.cpp @@ -97,7 +97,7 @@ namespace libp2p::connection { if (not frame_buffer_->empty()) { auto n{std::min(bytes, frame_buffer_->size())}; auto begin{frame_buffer_->begin()}; - auto end{begin + n}; + auto end{begin + static_cast(n)}; std::copy(begin, end, out.begin()); frame_buffer_->erase(begin, end); return cb(n); @@ -137,13 +137,14 @@ namespace libp2p::connection { write_buffers_.emplace(write_buffers_.end(), dummy_size, dummy_value); } ctx.write_buffer->swap(encrypted); - framer_->write(*ctx.write_buffer, - [self{shared_from_this()}, in{in.subspan(n)}, - bytes{bytes - n}, cb{std::move(cb)}, ctx](auto _n) mutable { - OUTCOME_CB(n, _n); - ctx.bytes_served += n; - self->write(in, bytes, ctx, std::move(cb)); - }); + framer_->write( + *ctx.write_buffer, + [self{shared_from_this()}, in{in.subspan(static_cast(n))}, + bytes{bytes - n}, cb{std::move(cb)}, ctx](auto _n) mutable { + OUTCOME_CB(n, _n); + ctx.bytes_served += n; + self->write(in, bytes, ctx, std::move(cb)); + }); } void NoiseConnection::writeSome(gsl::span in, size_t bytes,