diff options
author | Hannes Rantzsch <[email protected]> | 2019-04-05 15:26:25 +0200 |
---|---|---|
committer | Hannes Rantzsch <[email protected]> | 2019-04-16 10:48:19 +0200 |
commit | 6ea6a652212e8fd77a49f1eea0bd8d7e3568ecba (patch) | |
tree | d70ef4a07d4c34e073deff8d53fe71ed59bd79a0 /src | |
parent | 3ce24f23a3190f2ce0c2ec72d14171fcab3f2fda (diff) |
FIX: do not block when reading into zero-sized buffer
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/tls/asio/asio_async_read_op.h | 9 | ||||
-rw-r--r-- | src/tests/unit_asio_stream.cpp | 52 |
2 files changed, 58 insertions, 3 deletions
diff --git a/src/lib/tls/asio/asio_async_read_op.h b/src/lib/tls/asio/asio_async_read_op.h index 5c653c2ba..78243ce0f 100644 --- a/src/lib/tls/asio/asio_async_read_op.h +++ b/src/lib/tls/asio/asio_async_read_op.h @@ -53,6 +53,7 @@ struct AsyncReadOperation : public AsyncBase<Handler, typename Stream::executor_ { if(bytes_transferred > 0 && !ec) { + // We have transferred encrypted data from the socket, now hand it to the channel. boost::asio::const_buffer read_buffer{m_core.input_buffer.data(), bytes_transferred}; try { @@ -65,21 +66,23 @@ struct AsyncReadOperation : public AsyncBase<Handler, typename Stream::executor_ } } - if(!m_core.hasReceivedData() && !ec) + if(!m_core.hasReceivedData() && !ec && boost::asio::buffer_size(m_buffers) > 0) { - // we need more tls packets from the socket + // The channel did not decrypt a complete record yet, we need more data from the socket. m_stream.next_layer().async_read_some(m_core.input_buffer, std::move(*this)); return; } if(m_core.hasReceivedData() && !ec) { + // The channel has decrypted a TLS record, now copy it to the output buffers. m_decodedBytes = m_core.copyReceivedData(m_buffers); - ec = {}; } if(!isContinuation) { + // Make sure the handler is not called without an intermediate initiating function. + // "Reading" into a zero-byte buffer will "return" immediately. m_ec = ec; yield m_stream.next_layer().async_read_some(boost::asio::mutable_buffer(), std::move(*this)); ec = m_ec; diff --git a/src/tests/unit_asio_stream.cpp b/src/tests/unit_asio_stream.cpp index 1cc1ee7c1..25d65ff88 100644 --- a/src/tests/unit_asio_stream.cpp +++ b/src/tests/unit_asio_stream.cpp @@ -386,6 +386,28 @@ class Asio_Stream_Tests final : public Test results.push_back(result); } + void test_sync_read_zero_buffer(std::vector<Test::Result>& results) + { + net::io_context ioc; + + Botan::TLS::Context ctx; + AsioStream ssl(ctx, ioc); + + const std::size_t buf_size = 128; + uint8_t buf[buf_size]; + error_code ec; + + auto bytes_transferred = net::read(ssl, net::mutable_buffer(buf, std::size_t(0)), ec); + + Test::Result result("sync read_some into zero-size buffer"); + result.test_eq("reads the correct amount of data", bytes_transferred, 0); + // This relies on an implementation detail of TestStream: A "real" asio::tcp::stream + // would block here. TestStream sets error_code::eof. + result.confirm("does not report an error", !ec); + + results.push_back(result); + } + void test_async_read_some_success(std::vector<Test::Result>& results) { net::io_context ioc; @@ -494,6 +516,34 @@ class Asio_Stream_Tests final : public Test results.push_back(result); } + void test_async_read_zero_buffer(std::vector<Test::Result>& results) + { + net::io_context ioc; + TestStream remote{ioc}; + + Botan::TLS::Context ctx; + AsioStream ssl(ctx, ioc); + uint8_t data[TEST_DATA_SIZE]; + error_code ec; + + Test::Result result("async read_some into zero-size buffer"); + + auto read_handler = [&](const error_code &ec, std::size_t bytes_transferred) + { + result.test_eq("reads the correct amount of data", bytes_transferred, 0); + // This relies on an implementation detail of TestStream: A "real" asio::tcp::stream + // would block here. TestStream sets error_code::eof. + result.confirm("does not report an error", !ec); + }; + + net::mutable_buffer buf {data, std::size_t(0)}; + net::async_read(ssl, buf, read_handler); + + ssl.next_layer().close_remote(); + ioc.run(); + results.push_back(result); + } + void test_sync_write_some_success(std::vector<Test::Result>& results) { net::io_context ioc; @@ -727,11 +777,13 @@ class Asio_Stream_Tests final : public Test test_sync_read_some_buffer_sequence(results); test_sync_read_some_error(results); test_sync_read_some_throw(results); + test_sync_read_zero_buffer(results); test_async_read_some_success(results); test_async_read_some_buffer_sequence(results); test_async_read_some_error(results); test_async_read_some_throw(results); + test_async_read_zero_buffer(results); test_sync_write_some_success(results); test_sync_write_some_buffer_sequence(results); |