diff options
Diffstat (limited to 'src/lib/tls/asio')
-rw-r--r-- | src/lib/tls/asio/asio_async_base.h | 68 | ||||
-rw-r--r-- | src/lib/tls/asio/asio_async_handshake_op.h | 63 | ||||
-rw-r--r-- | src/lib/tls/asio/asio_async_read_op.h | 40 | ||||
-rw-r--r-- | src/lib/tls/asio/asio_async_write_op.h | 26 | ||||
-rw-r--r-- | src/lib/tls/asio/asio_stream.h | 17 | ||||
-rw-r--r-- | src/lib/tls/asio/info.txt | 1 |
6 files changed, 149 insertions, 66 deletions
diff --git a/src/lib/tls/asio/asio_async_base.h b/src/lib/tls/asio/asio_async_base.h new file mode 100644 index 000000000..af9199288 --- /dev/null +++ b/src/lib/tls/asio/asio_async_base.h @@ -0,0 +1,68 @@ +/* +* TLS ASIO Stream Helper +* (C) 2018-2019 Jack Lloyd +* 2018-2019 Hannes Rantzsch, Tim Oesterreich, Rene Meusel +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ASIO_ASYNC_BASE_H_ +#define BOTAN_ASIO_ASYNC_BASE_H_ + +#include <boost/beast/core/bind_handler.hpp> + +#include <botan/internal/asio_includes.h> + +namespace Botan { + +namespace TLS { + +template <class Handler, class Executor, class Allocator> +struct AsyncBase + { + using allocator_type = boost::asio::associated_allocator_t<Handler, Allocator>; + using executor_type = boost::asio::associated_executor_t<Handler, Executor>; + + allocator_type get_allocator() const noexcept + { + return boost::asio::get_associated_allocator(m_handler); + } + + executor_type get_executor() const noexcept + { + return boost::asio::get_associated_executor(m_handler, m_work.get_executor()); + } + + protected: + template <class HandlerT> + AsyncBase(HandlerT&& handler, const Executor& executor) + : m_handler(std::forward<HandlerT>(handler)) + , m_work(executor) + { + } + + template<class... Args> + void invoke(bool isContinuation, Args&& ... args) + { + if(!isContinuation) + { + boost::asio::post(boost::asio::bind_executor( + m_work.get_executor(), boost::beast::bind_handler(std::move(m_handler), args...)) + ); + + m_work.reset(); + } + else + { + m_handler(std::forward<Args>(args)...); + m_work.reset(); + } + } + + Handler m_handler; + boost::asio::executor_work_guard<executor_type> m_work; + }; +} +} + +#endif diff --git a/src/lib/tls/asio/asio_async_handshake_op.h b/src/lib/tls/asio/asio_async_handshake_op.h index c9a8b8058..1a93ab78b 100644 --- a/src/lib/tls/asio/asio_async_handshake_op.h +++ b/src/lib/tls/asio/asio_async_handshake_op.h @@ -18,24 +18,28 @@ namespace Botan { namespace TLS { -template <class Handler, class StreamLayer, class Channel> -struct AsyncHandshakeOperation +template <class Handler, class Stream, class Allocator = std::allocator<void>> +struct AsyncHandshakeOperation : public AsyncBase<Handler, typename Stream::executor_type, Allocator> { template<class HandlerT> AsyncHandshakeOperation( HandlerT&& handler, - StreamLayer& nextLayer, - Channel* channel, + Stream& stream, StreamCore& core) - : m_handler(std::forward<HandlerT>(handler)) - , m_nextLayer(nextLayer) - , m_channel(channel) - , m_core(core) {} + : AsyncBase<Handler, typename Stream::executor_type, Allocator>( + std::forward<HandlerT>(handler), + stream.get_executor()) + , m_stream(stream) + , m_core(core) + { + } AsyncHandshakeOperation(AsyncHandshakeOperation&&) = default; - void operator()(boost::system::error_code ec, - std::size_t bytesTransferred = 0, int start = 0) + using typename AsyncBase<Handler, typename Stream::executor_type, Allocator>::allocator_type; + using typename AsyncBase<Handler, typename Stream::executor_type, Allocator>::executor_type; + + void operator()(boost::system::error_code ec, std::size_t bytesTransferred, bool isContinuation = true) { // process tls packets from socket first if(bytesTransferred > 0) @@ -43,14 +47,12 @@ struct AsyncHandshakeOperation boost::asio::const_buffer read_buffer {m_core.input_buffer.data(), bytesTransferred}; try { - m_channel->received_data( - static_cast<const uint8_t*>(read_buffer.data()), - read_buffer.size()); + m_stream.native_handle()->received_data(static_cast<const uint8_t*>(read_buffer.data()), read_buffer.size()); } catch(const std::exception&) { ec = convertException(); - m_handler(ec); + this->invoke(isContinuation, ec); return; } } @@ -58,33 +60,32 @@ struct AsyncHandshakeOperation // send tls packets if(m_core.hasDataToSend()) { - AsyncWriteOperation<AsyncHandshakeOperation<typename std::decay<Handler>::type, StreamLayer, Channel>> - op{std::move(*this), m_core, 0}; - boost::asio::async_write(m_nextLayer, m_core.sendBuffer(), std::move(op)); + // TODO comment: plainBytesTransferred is 0 here because... we construct a write operation to use it only + // as a handler for our async_write call, not for actually calling it. However, once + // AsyncWriteOperation::operator() is called as the handler, it will consume the send buffer and call (this) + // as it's own handler. Now we know that AsyncHandshakeOperation::operator() checks bytesTransferred first. + // We want it to NOT receive data into the channel, hence we set plainBytesTransferred to 0 here. + AsyncWriteOperation< + AsyncHandshakeOperation<typename std::decay<Handler>::type, Stream, Allocator>, + Stream, + Allocator> + op{std::move(*this), m_stream, m_core, 0}; + boost::asio::async_write(m_stream.next_layer(), m_core.sendBuffer(), std::move(op)); return; } - if(!m_channel->is_active() && !ec) + // we need more tls data from the socket + if(!m_stream.native_handle()->is_active() && !ec) { - // we need more tls data from the socket - m_nextLayer.async_read_some(m_core.input_buffer, std::move(*this)); + m_stream.next_layer().async_read_some(m_core.input_buffer, std::move(*this)); return; } - if(start) - { - // don't call the handler directly, similar to io_context.post - m_nextLayer.async_read_some( - boost::asio::mutable_buffer(m_core.input_buffer.data(), 0), std::move(*this)); - return; - } - m_handler(ec); + this->invoke(isContinuation, ec); } private: - Handler m_handler; - StreamLayer& m_nextLayer; - Channel* m_channel; + Stream& m_stream; StreamCore& m_core; }; diff --git a/src/lib/tls/asio/asio_async_read_op.h b/src/lib/tls/asio/asio_async_read_op.h index 241f9ae5c..ed66df07d 100644 --- a/src/lib/tls/asio/asio_async_read_op.h +++ b/src/lib/tls/asio/asio_async_read_op.h @@ -9,6 +9,7 @@ #ifndef BOTAN_ASIO_ASYNC_READ_OP_H_ #define BOTAN_ASIO_ASYNC_READ_OP_H_ +#include <botan/internal/asio_async_base.h> #include <botan/internal/asio_convert_exceptions.h> #include <botan/internal/asio_includes.h> #include <botan/internal/asio_stream_core.h> @@ -17,34 +18,39 @@ namespace Botan { namespace TLS { -template <class Handler, class StreamLayer, class Channel, class MutableBufferSequence> -struct AsyncReadOperation +template <class Handler, class Stream, class MutableBufferSequence, class Allocator = std::allocator<void>> +struct AsyncReadOperation : public AsyncBase<Handler, typename Stream::executor_type, Allocator> { template <class HandlerT> AsyncReadOperation(HandlerT&& handler, - StreamLayer& nextLayer, - Channel* channel, + Stream& stream, StreamCore& core, const MutableBufferSequence& buffers) - : m_handler(std::forward<HandlerT>(handler)) - , m_nextLayer(nextLayer) - , m_channel(channel) + : AsyncBase<Handler, typename Stream::executor_type, Allocator>( + std::forward<HandlerT>(handler), + stream.get_executor()) + , m_stream(stream) , m_core(core) - , m_buffers(buffers) {} + , m_buffers(buffers) + { + } AsyncReadOperation(AsyncReadOperation&&) = default; - void operator()(boost::system::error_code ec, std::size_t bytes_transferred) + using typename AsyncBase<Handler, typename Stream::executor_type, Allocator>::allocator_type; + using typename AsyncBase<Handler, typename Stream::executor_type, Allocator>::executor_type; + + void operator()(boost::system::error_code ec, std::size_t bytes_transferred, bool isContinuation = true) { std::size_t decodedBytes = 0; if(bytes_transferred > 0 && !ec) { - boost::asio::const_buffer read_buffer {m_core.input_buffer.data(), bytes_transferred}; + boost::asio::const_buffer read_buffer{m_core.input_buffer.data(), bytes_transferred}; try { - m_channel->received_data(static_cast<const uint8_t*>(read_buffer.data()), - read_buffer.size()); + m_stream.native_handle()->received_data(static_cast<const uint8_t*>(read_buffer.data()), + read_buffer.size()); } catch(const std::exception&) { @@ -55,23 +61,21 @@ struct AsyncReadOperation if(!m_core.hasReceivedData() && !ec) { // we need more tls packets from the socket - m_nextLayer.async_read_some(m_core.input_buffer, std::move(*this)); + m_stream.next_layer().async_read_some(m_core.input_buffer, std::move(*this)); return; } if(m_core.hasReceivedData() && !ec) { decodedBytes = m_core.copyReceivedData(m_buffers); - ec = boost::system::error_code{}; + ec = {}; } - m_handler(ec, decodedBytes); + this->invoke(isContinuation, ec, decodedBytes); } private: - Handler m_handler; - StreamLayer& m_nextLayer; - Channel* m_channel; + Stream& m_stream; StreamCore& m_core; MutableBufferSequence m_buffers; }; diff --git a/src/lib/tls/asio/asio_async_write_op.h b/src/lib/tls/asio/asio_async_write_op.h index 3af7d7fee..4103987ae 100644 --- a/src/lib/tls/asio/asio_async_write_op.h +++ b/src/lib/tls/asio/asio_async_write_op.h @@ -11,32 +11,42 @@ #include <botan/internal/asio_stream_core.h> #include <botan/internal/asio_includes.h> +#include <botan/internal/asio_async_base.h> namespace Botan { namespace TLS { -template <typename Handler> -struct AsyncWriteOperation +template <typename Handler, class Stream, class Allocator = std::allocator<void>> +struct AsyncWriteOperation : public AsyncBase<Handler, typename Stream::executor_type, Allocator> { template <class HandlerT> AsyncWriteOperation(HandlerT&& handler, + Stream& stream, StreamCore& core, std::size_t plainBytesTransferred) - : m_handler(std::forward<HandlerT>(handler)) + : AsyncBase<Handler, typename Stream::executor_type, Allocator>( + std::forward<HandlerT>(handler), + stream.get_executor()) + , m_stream(stream) , m_core(core) - , m_plainBytesTransferred(plainBytesTransferred) {} + , m_plainBytesTransferred(plainBytesTransferred) + { + } AsyncWriteOperation(AsyncWriteOperation&&) = default; - void operator()(boost::system::error_code ec, std::size_t bytes_transferred) + using typename AsyncBase<Handler, typename Stream::executor_type, Allocator>::allocator_type; + using typename AsyncBase<Handler, typename Stream::executor_type, Allocator>::executor_type; + + void operator()(boost::system::error_code ec, std::size_t bytes_transferred, bool isContinuation = true) { m_core.consumeSendBuffer(bytes_transferred); - m_handler(ec, ec ? 0 : m_plainBytesTransferred); + this->invoke(isContinuation, ec, ec ? 0 : m_plainBytesTransferred); } - Handler m_handler; - StreamCore& m_core; + Stream& m_stream; + StreamCore& m_core; std::size_t m_plainBytesTransferred; }; diff --git a/src/lib/tls/asio/asio_stream.h b/src/lib/tls/asio/asio_stream.h index 1abad507a..8a28fc68e 100644 --- a/src/lib/tls/asio/asio_stream.h +++ b/src/lib/tls/asio/asio_stream.h @@ -191,10 +191,9 @@ class Stream final : public StreamBase<Channel> boost::asio::async_completion<HandshakeHandler, void(boost::system::error_code)> init(handler); - AsyncHandshakeOperation<typename std::decay<HandshakeHandler>::type, StreamLayer, Channel> - op{std::move(init.completion_handler), m_nextLayer, native_handle(), this->m_core}; - - op(boost::system::error_code{}, 0, 1); + AsyncHandshakeOperation<typename std::decay<HandshakeHandler>::type, Stream> + op{std::move(init.completion_handler), *this, this->m_core}; + op({}, 0, false); return init.result.get(); } @@ -407,8 +406,9 @@ class Stream final : public StreamBase<Channel> return init.result.get(); } - Botan::TLS::AsyncWriteOperation<typename std::decay<WriteHandler>::type> + Botan::TLS::AsyncWriteOperation<typename std::decay<WriteHandler>::type, Stream> op{std::move(init.completion_handler), + *this, this->m_core, sent}; boost::asio::async_write(m_nextLayer, this->m_core.sendBuffer(), std::move(op)); @@ -425,13 +425,12 @@ class Stream final : public StreamBase<Channel> boost::asio::async_completion<ReadHandler, void(boost::system::error_code, std::size_t)> init(handler); - AsyncReadOperation<typename std::decay<ReadHandler>::type, StreamLayer, Channel, MutableBufferSequence> + AsyncReadOperation<typename std::decay<ReadHandler>::type, Stream, MutableBufferSequence> op{std::move(init.completion_handler), - m_nextLayer, - native_handle(), + *this, this->m_core, buffers}; - op(boost::system::error_code{}, 0); + op({}, 0, false); return init.result.get(); } diff --git a/src/lib/tls/asio/info.txt b/src/lib/tls/asio/info.txt index 2b303c89e..cfca189a7 100644 --- a/src/lib/tls/asio/info.txt +++ b/src/lib/tls/asio/info.txt @@ -8,6 +8,7 @@ asio_error.h </header:public> <header:internal> +asio_async_base.h asio_async_handshake_op.h asio_async_read_op.h asio_async_write_op.h |