aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHannes Rantzsch <[email protected]>2019-04-05 15:26:25 +0200
committerHannes Rantzsch <[email protected]>2019-04-16 10:48:19 +0200
commit6ea6a652212e8fd77a49f1eea0bd8d7e3568ecba (patch)
treed70ef4a07d4c34e073deff8d53fe71ed59bd79a0 /src
parent3ce24f23a3190f2ce0c2ec72d14171fcab3f2fda (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.h9
-rw-r--r--src/tests/unit_asio_stream.cpp52
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);