src/openssl/src/openssl_stream.cpp

82.0% Lines (388/473) 100.0% List of functions (34/34) 44.5% Branches (490/1100)
openssl_stream.cpp
f(x) Functions (34)
Function Calls Lines Branches Blocks
boost::corosio::(anonymous namespace)::tls_method_compat() :66 2021x 100.0% 50.0% 66.0% boost::corosio::(anonymous namespace)::apply_hostname_verification(ssl_st*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&) :76 2047x 100.0% 100.0% 100.0% boost::corosio::(anonymous namespace)::normalize_openssl_shutdown_read_error(std::__1::error_code) :92 9x 70.0% 50.0% 63.0% boost::corosio::(anonymous namespace)::openssl_category_impl::~openssl_category_impl() :106 2x 100.0% 100.0% boost::corosio::(anonymous namespace)::openssl_category_impl::name() const :109 1x 100.0% 100.0% boost::corosio::(anonymous namespace)::openssl_category_impl::message(int) const :115 2x 100.0% 100.0% boost::corosio::(anonymous namespace)::make_openssl_error(unsigned long) :128 11x 66.7% 33.3% 57.0% boost::corosio::openssl_category() :139 14x 100.0% 75.0% 100.0% boost::corosio::detail::password_callback(char*, int, int, void*) :154 1x 83.3% 50.0% 71.0% boost::corosio::detail::sni_callback(ssl_st*, int*, void*) :176 3x 100.0% 75.0% 100.0% boost::corosio::detail::openssl_native_context::openssl_native_context(boost::corosio::detail::tls_context_data const&) :201 4042x 96.8% 60.7% 100.0% boost::corosio::detail::openssl_native_context::~openssl_native_context() :333 6063x 100.0% 50.0% 100.0% boost::corosio::detail::get_openssl_context(boost::corosio::detail::tls_context_data const&) :341 2027x 100.0% 100.0% boost::corosio::detail::get_openssl_context(boost::corosio::detail::tls_context_data const&)::'lambda'()::operator()() const :344 2021x 100.0% 50.0% 50.0% boost::corosio::openssl_stream::impl::impl(boost::capy::any_stream&, boost::corosio::tls_context) :363 4054x 100.0% 50.0% 100.0% boost::corosio::openssl_stream::impl::~impl() :369 4054x 100.0% 50.0% 100.0% boost::corosio::openssl_stream::impl::reset() :377 20x 80.0% 50.0% 71.0% boost::corosio::openssl_stream::impl::flush_output() :397 176119x 88.5% 50.0% 53.0% boost::corosio::openssl_stream::impl::read_input() :428 24649x 86.7% 44.6% 48.0% boost::corosio::openssl_stream::impl::do_read_some(boost::capy::detail::buffer_array<16ul, false>) :449 150621x 65.5% 37.3% 44.0% boost::corosio::openssl_stream::impl::do_write_some(boost::capy::detail::buffer_array<16ul, true>) :532 150624x 48.8% 19.7% 26.0% boost::corosio::openssl_stream::impl::do_handshake(int) :592 1441x 86.1% 46.9% 51.0% boost::corosio::openssl_stream::impl::do_shutdown() :644 37x 69.8% 44.6% 47.0% boost::corosio::openssl_stream::impl::init_ssl() :711 2027x 60.0% 50.0% 62.0% boost::corosio::openssl_stream::make_impl(boost::capy::any_stream&, boost::corosio::tls_context const&) :746 2027x 75.0% 25.0% 36.0% boost::corosio::openssl_stream::~openssl_stream() :760 4058x 100.0% 100.0% 100.0% boost::corosio::openssl_stream::openssl_stream(boost::corosio::openssl_stream&&) :765 4x 100.0% 50.0% 100.0% boost::corosio::openssl_stream::operator=(boost::corosio::openssl_stream&&) :775 1x 100.0% 50.0% 100.0% boost::corosio::openssl_stream::do_read_some(boost::capy::detail::buffer_array<16ul, false>) :790 150621x 100.0% 50.0% 48.0% boost::corosio::openssl_stream::do_write_some(boost::capy::detail::buffer_array<16ul, true>) :797 150624x 100.0% 50.0% 48.0% boost::corosio::openssl_stream::handshake(boost::corosio::tls_stream::handshake_type) :804 1441x 100.0% 50.0% 48.0% boost::corosio::openssl_stream::shutdown() :810 37x 100.0% 50.0% 48.0% boost::corosio::openssl_stream::reset() :816 16x 100.0% 100.0% boost::corosio::openssl_stream::name() const :822 1x 100.0% 50.0% 66.0%
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco ([email protected])
3 // Copyright (c) 2026 Michael Vandeberg
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/corosio
9 //
10
11 #include <boost/corosio/openssl_stream.hpp>
12 #include <boost/corosio/detail/config.hpp>
13 #include <boost/capy/detail/buffer_array.hpp>
14 #include <boost/capy/ex/async_mutex.hpp>
15 #include <boost/capy/error.hpp>
16 #include <boost/capy/write.hpp>
17
18 // Internal context implementation
19 #include "src/tls/detail/context_impl.hpp"
20
21 #include <openssl/ssl.h>
22 #include <openssl/err.h>
23 #include <openssl/bio.h>
24 #include <openssl/x509.h>
25
26 #include <algorithm>
27 #include <array>
28 #include <cstring>
29 #include <vector>
30
31 /*
32 openssl_stream Architecture
33 ===========================
34
35 TLS layer wrapping an underlying stream (via any_stream). Supports one
36 concurrent read_some and one concurrent write_some (like Asio's ssl::stream).
37
38 Data Flow (using BIO pairs)
39 ---------------------------
40 App -> SSL_write -> int_bio_ -> BIO_read(ext_bio_) -> out_buf_ -> s_->write_some -> Network
41 App <- SSL_read <- int_bio_ <- BIO_write(ext_bio_) <- in_buf_ <- s_->read_some <- Network
42
43 WANT_READ / WANT_WRITE Pattern
44 ------------------------------
45 OpenSSL's SSL_read/SSL_write return SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE
46 when they need I/O. Our coroutine handles this by:
47
48 1. Call SSL_read or SSL_write
49 2. Check for pending output in ext_bio_ via BIO_ctrl_pending
50 3. If output pending: write to network via s_->write_some
51 4. If SSL_ERROR_WANT_READ: read from network into ext_bio_ via s_->read_some + BIO_write
52 5. Loop back to step 1
53
54 Renegotiation causes cross-direction I/O: SSL_read may need to write
55 handshake data, SSL_write may need to read. Each operation handles
56 whatever I/O direction OpenSSL requests.
57 */
58
59 namespace boost::corosio {
60
61 namespace {
62
63 constexpr std::size_t default_buffer_size = 16384;
64
65 inline SSL_METHOD const*
66 2021x tls_method_compat() noexcept
67 {
68 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
69
1/2
✓ Branch 0 taken 2021 times.
✗ Branch 1 not taken.
2021x return TLS_method();
70 #else
71 return SSLv23_method();
72 #endif
73 }
74
75 inline void
76 2047x apply_hostname_verification(SSL* ssl, std::string const& hostname)
77 {
78
2/2
✓ Branch 0 taken 2043 times.
✓ Branch 1 taken 4 times.
2047x if (hostname.empty())
79 2043x return;
80
81 4x SSL_set_tlsext_host_name(ssl, hostname.c_str());
82
83 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
84 4x SSL_set1_host(ssl, hostname.c_str());
85 #else
86 if (auto* param = SSL_get0_param(ssl))
87 X509_VERIFY_PARAM_set1_host(param, hostname.c_str(), 0);
88 #endif
89 2047x }
90
91 inline std::error_code
92 9x normalize_openssl_shutdown_read_error(std::error_code ec) noexcept
93 {
94
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9x if (!ec)
95 return ec;
96
97
3/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
10x if (ec == make_error_code(capy::error::eof) ||
98
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x ec == make_error_code(capy::error::canceled) ||
99
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1x ec == std::errc::connection_reset ||
100 ec == std::errc::connection_aborted || ec == std::errc::broken_pipe)
101 9x return make_error_code(capy::error::stream_truncated);
102
103 return ec;
104 9x }
105
106 class openssl_category_impl final : public std::error_category
107 {
108 char const*
109 1x name() const noexcept override
110 {
111 1x return "corosio.openssl";
112 }
113
114 std::string
115 2x message(int value) const override
116 {
117 char buf[256];
118 2x ::ERR_error_string_n(
119 2x static_cast<unsigned long>(value), buf, sizeof(buf));
120 2x return buf;
121 }
122 };
123
124 // Convert a packed OpenSSL error (from ERR_get_error) into an error_code.
125 // Codes from the ERR_LIB_SYS library carry a genuine errno reason and are
126 // reported with the system category; everything else uses openssl_category.
127 inline std::error_code
128 11x make_openssl_error(unsigned long err) noexcept
129 {
130
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11x if (ERR_GET_LIB(err) == ERR_LIB_SYS)
131 return std::error_code(
132 static_cast<int>(ERR_GET_REASON(err)), std::system_category());
133 11x return std::error_code(static_cast<int>(err), openssl_category());
134 11x }
135
136 } // namespace
137
138 std::error_category const&
139 14x openssl_category() noexcept
140 {
141
3/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
14x static openssl_category_impl instance;
142 14x return instance;
143 }
144
145 //
146 // Native context caching
147 //
148
149 namespace detail {
150
151 static int sni_ctx_data_index = -1;
152
153 static int
154 1x password_callback(char* buf, int size, int rwflag, void* userdata)
155 {
156 1x auto* cd = static_cast<tls_context_data const*>(userdata);
157
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1x if (!cd || !cd->password_callback)
158 return 0;
159
160 1x tls_password_purpose purpose = (rwflag == 0)
161 ? tls_password_purpose::for_reading
162 : tls_password_purpose::for_writing;
163
164 std::string password =
165 1x cd->password_callback(static_cast<std::size_t>(size), purpose);
166
167 1x int len = static_cast<int>(password.size());
168
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x if (len > size)
169 len = size;
170
171 1x std::memcpy(buf, password.data(), static_cast<std::size_t>(len));
172 1x return len;
173 1x }
174
175 static int
176 3x sni_callback(SSL* ssl, int* /* alert */, void* /* arg */)
177 {
178 3x char const* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
179
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3x if (!servername)
180 1x return SSL_TLSEXT_ERR_NOACK;
181
182 2x SSL_CTX* ctx = SSL_get_SSL_CTX(ssl);
183 2x auto* cd = static_cast<tls_context_data const*>(
184 2x SSL_CTX_get_ex_data(ctx, sni_ctx_data_index));
185
186
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2x if (cd && cd->servername_callback)
187 {
188
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2x if (!cd->servername_callback(servername))
189 1x return SSL_TLSEXT_ERR_ALERT_FATAL;
190 1x }
191
192 1x return SSL_TLSEXT_ERR_OK;
193 3x }
194
195 class openssl_native_context : public native_context_base
196 {
197 public:
198 SSL_CTX* ctx_;
199 tls_context_data const* cd_;
200
201 4042x explicit openssl_native_context(tls_context_data const& cd)
202 2021x : ctx_(nullptr)
203 2021x , cd_(&cd)
204 4042x {
205
1/2
✓ Branch 0 taken 2021 times.
✗ Branch 1 not taken.
2021x ctx_ = SSL_CTX_new(tls_method_compat());
206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2021 times.
2021x if (!ctx_)
207 return;
208
209
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2017 times.
2021x if (sni_ctx_data_index < 0)
210 4x sni_ctx_data_index =
211
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4x SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
212
213
1/2
✓ Branch 0 taken 2021 times.
✗ Branch 1 not taken.
2021x SSL_CTX_set_ex_data(
214 2021x ctx_, sni_ctx_data_index, const_cast<tls_context_data*>(&cd));
215
216
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2018 times.
2021x if (cd.servername_callback)
217
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3x SSL_CTX_set_tlsext_servername_callback(ctx_, sni_callback);
218
219
1/2
✓ Branch 0 taken 2021 times.
✗ Branch 1 not taken.
2021x SSL_CTX_set_mode(ctx_, SSL_MODE_ENABLE_PARTIAL_WRITE);
220
1/2
✓ Branch 0 taken 2021 times.
✗ Branch 1 not taken.
2021x SSL_CTX_set_mode(ctx_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
221 #if defined(SSL_MODE_RELEASE_BUFFERS)
222
1/2
✓ Branch 0 taken 2021 times.
✗ Branch 1 not taken.
2021x SSL_CTX_set_mode(ctx_, SSL_MODE_RELEASE_BUFFERS);
223 #endif
224
225 2021x int verify_mode_flag = SSL_VERIFY_NONE;
226
2/2
✓ Branch 0 taken 1006 times.
✓ Branch 1 taken 1015 times.
2021x if (cd.verification_mode == tls_verify_mode::peer)
227 1006x verify_mode_flag = SSL_VERIFY_PEER;
228
2/2
✓ Branch 0 taken 1012 times.
✓ Branch 1 taken 3 times.
1015x else if (cd.verification_mode == tls_verify_mode::require_peer)
229 3x verify_mode_flag =
230 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
231
1/2
✓ Branch 0 taken 2021 times.
✗ Branch 1 not taken.
2021x SSL_CTX_set_verify(ctx_, verify_mode_flag, nullptr);
232
233
2/2
✓ Branch 0 taken 1011 times.
✓ Branch 1 taken 1010 times.
2021x if (!cd.entity_certificate.empty())
234 {
235
1/2
✓ Branch 0 taken 1011 times.
✗ Branch 1 not taken.
1011x BIO* bio = BIO_new_mem_buf(
236 1011x cd.entity_certificate.data(),
237 1011x static_cast<int>(cd.entity_certificate.size()));
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1011 times.
1011x if (bio)
239 {
240 1011x X509* cert = nullptr;
241
1/2
✓ Branch 0 taken 1011 times.
✗ Branch 1 not taken.
1011x if (cd.entity_cert_format == tls_file_format::pem)
242
1/2
✓ Branch 0 taken 1011 times.
✗ Branch 1 not taken.
1011x cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
243 else
244 cert = d2i_X509_bio(bio, nullptr);
245
2/2
✓ Branch 0 taken 1010 times.
✓ Branch 1 taken 1 time.
1011x if (cert)
246 {
247
1/2
✓ Branch 0 taken 1010 times.
✗ Branch 1 not taken.
1010x SSL_CTX_use_certificate(ctx_, cert);
248
1/2
✓ Branch 0 taken 1010 times.
✗ Branch 1 not taken.
1010x X509_free(cert);
249 1010x }
250
1/2
✓ Branch 0 taken 1011 times.
✗ Branch 1 not taken.
1011x BIO_free(bio);
251 1011x }
252 1011x }
253
254
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2020 times.
2021x if (!cd.certificate_chain.empty())
255 {
256
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x BIO* bio = BIO_new_mem_buf(
257 1x cd.certificate_chain.data(),
258 1x static_cast<int>(cd.certificate_chain.size()));
259
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x if (bio)
260 {
261 1x X509* entity =
262
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
263
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x if (entity)
264 {
265
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x SSL_CTX_use_certificate(ctx_, entity);
266
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x X509_free(entity);
267 1x }
268
269 X509* cert;
270
5/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 1 time.
2x while ((cert = PEM_read_bio_X509(
271 2x bio, nullptr, nullptr, nullptr)) != nullptr)
272 {
273
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x SSL_CTX_add_extra_chain_cert(ctx_, cert);
274 }
275
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x ERR_clear_error();
276
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x BIO_free(bio);
277 1x }
278 1x }
279
280
2/2
✓ Branch 0 taken 1012 times.
✓ Branch 1 taken 1009 times.
2021x if (!cd.private_key.empty())
281 {
282
1/2
✓ Branch 0 taken 1012 times.
✗ Branch 1 not taken.
1012x BIO* bio = BIO_new_mem_buf(
283 1012x cd.private_key.data(), static_cast<int>(cd.private_key.size()));
284
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1012 times.
1012x if (bio)
285 {
286 1012x EVP_PKEY* pkey = nullptr;
287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1012 times.
1012x if (cd.private_key_format == tls_file_format::pem)
288 {
289
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1011 times.
1012x if (cd.password_callback)
290
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x pkey = PEM_read_bio_PrivateKey(
291 1x bio, nullptr, password_callback,
292 1x const_cast<tls_context_data*>(&cd));
293 else
294
1/2
✓ Branch 0 taken 1011 times.
✗ Branch 1 not taken.
1011x pkey = PEM_read_bio_PrivateKey(
295 1011x bio, nullptr, nullptr, nullptr);
296 1012x }
297 else
298 pkey = d2i_PrivateKey_bio(bio, nullptr);
299
2/2
✓ Branch 0 taken 1011 times.
✓ Branch 1 taken 1 time.
1012x if (pkey)
300 {
301
1/2
✓ Branch 0 taken 1011 times.
✗ Branch 1 not taken.
1011x SSL_CTX_use_PrivateKey(ctx_, pkey);
302
1/2
✓ Branch 0 taken 1011 times.
✗ Branch 1 not taken.
1011x EVP_PKEY_free(pkey);
303 1011x }
304
1/2
✓ Branch 0 taken 1012 times.
✗ Branch 1 not taken.
1012x BIO_free(bio);
305 1012x }
306 1012x }
307
308
1/2
✓ Branch 0 taken 2021 times.
✗ Branch 1 not taken.
2021x X509_STORE* store = SSL_CTX_get_cert_store(ctx_);
309
2/2
✓ Branch 0 taken 2021 times.
✓ Branch 1 taken 1020 times.
3041x for (auto const& ca : cd.ca_certificates)
310 {
311
1/2
✓ Branch 0 taken 1020 times.
✗ Branch 1 not taken.
1020x BIO* bio = BIO_new_mem_buf(ca.data(), static_cast<int>(ca.size()));
312
1/2
✓ Branch 0 taken 1020 times.
✗ Branch 1 not taken.
1020x if (bio)
313 {
314
1/2
✓ Branch 0 taken 1020 times.
✗ Branch 1 not taken.
1020x X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
315
2/2
✓ Branch 0 taken 1019 times.
✓ Branch 1 taken 1 time.
1020x if (cert)
316 {
317
1/2
✓ Branch 0 taken 1019 times.
✗ Branch 1 not taken.
1019x X509_STORE_add_cert(store, cert);
318
1/2
✓ Branch 0 taken 1019 times.
✗ Branch 1 not taken.
1019x X509_free(cert);
319 1019x }
320
1/2
✓ Branch 0 taken 1020 times.
✗ Branch 1 not taken.
1020x BIO_free(bio);
321 1020x }
322 }
323
324
1/2
✓ Branch 0 taken 2021 times.
✗ Branch 1 not taken.
2021x SSL_CTX_set_verify_depth(ctx_, cd.verify_depth);
325
326
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2017 times.
2021x if (!cd.ciphersuites.empty())
327 {
328
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4x SSL_CTX_set_security_level(ctx_, 0);
329
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4x SSL_CTX_set_cipher_list(ctx_, cd.ciphersuites.c_str());
330 4x }
331 4042x }
332
333 6063x ~openssl_native_context() override
334 6063x {
335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2021 times.
2021x if (ctx_)
336
1/2
✓ Branch 0 taken 2021 times.
✗ Branch 1 not taken.
2021x SSL_CTX_free(ctx_);
337 6063x }
338 };
339
340 inline SSL_CTX*
341 2027x get_openssl_context(tls_context_data const& cd)
342 {
343 static char key;
344
1/2
✓ Branch 0 taken 2021 times.
✗ Branch 1 not taken.
4048x auto* p = cd.find(&key, [&] { return new openssl_native_context(cd); });
345 2027x return static_cast<openssl_native_context*>(p)->ctx_;
346 }
347
348 } // namespace detail
349
350 struct openssl_stream::impl
351 {
352 capy::any_stream* s_;
353 tls_context ctx_;
354 2027x SSL* ssl_ = nullptr;
355 2027x BIO* ext_bio_ = nullptr;
356 2027x bool used_ = false;
357
358 std::vector<char> in_buf_;
359 std::vector<char> out_buf_;
360
361 capy::async_mutex io_cm_;
362
363 6081x impl(capy::any_stream& s, tls_context ctx) : s_(&s), ctx_(std::move(ctx))
364 2027x {
365
1/2
✓ Branch 0 taken 2027 times.
✗ Branch 1 not taken.
2027x in_buf_.resize(default_buffer_size);
366
1/2
✓ Branch 0 taken 2027 times.
✗ Branch 1 not taken.
2027x out_buf_.resize(default_buffer_size);
367 4054x }
368
369 4054x ~impl()
370 2027x {
371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2027 times.
2027x if (ext_bio_)
372
1/2
✓ Branch 0 taken 2027 times.
✗ Branch 1 not taken.
2027x BIO_free(ext_bio_);
373
1/2
✓ Branch 0 taken 2027 times.
✗ Branch 1 not taken.
2027x if (ssl_)
374
1/2
✓ Branch 0 taken 2027 times.
✗ Branch 1 not taken.
2027x SSL_free(ssl_);
375 4054x }
376
377 20x void reset()
378 {
379
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20x if (!ssl_)
380 return;
381
382 // Preserves SSL* and BIO pair, releases session state
383 20x SSL_clear(ssl_);
384
385 // Drain stale data from the external BIO
386 char drain[1024];
387
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20x while (BIO_ctrl_pending(ext_bio_) > 0)
388 BIO_read(ext_bio_, drain, sizeof(drain));
389
390 // SSL_clear clears per-session settings; reapply hostname
391 20x auto& cd = detail::get_tls_context_data(ctx_);
392 20x apply_hostname_verification(ssl_, cd.hostname);
393
394 20x used_ = false;
395 20x }
396
397
10/24
✓ Branch 0 taken 176119 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 176119 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 176119 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 176119 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 176119 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 176119 times.
✓ Branch 15 taken 176119 times.
✓ Branch 16 taken 176119 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 305844 times.
✓ Branch 19 taken 176119 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
1492283x capy::task<std::error_code> flush_output()
398 176119x {
399
3/4
✓ Branch 0 taken 329040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 176118 times.
✓ Branch 3 taken 152922 times.
329040x while (BIO_ctrl_pending(ext_bio_) > 0)
400 {
401 152922x std::size_t got = 0;
402
5/6
✓ Branch 0 taken 305844 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 152916 times.
✓ Branch 3 taken 152928 times.
✓ Branch 4 taken 152922 times.
✓ Branch 5 taken 152922 times.
305844x while (BIO_ctrl_pending(ext_bio_) > 0 && got < out_buf_.size())
403 {
404
1/2
✓ Branch 0 taken 152922 times.
✗ Branch 1 not taken.
152922x int put = static_cast<int>(BIO_ctrl_pending(ext_bio_));
405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 152922 times.
152922x put = (std::min)(put, static_cast<int>(out_buf_.size() - got));
406
1/2
✓ Branch 0 taken 152922 times.
✗ Branch 1 not taken.
152922x int r = BIO_read(ext_bio_, out_buf_.data() + got, put);
407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 152922 times.
152922x if (r <= 0)
408 break;
409 152922x got += static_cast<std::size_t>(r);
410 152922x }
411
1/2
✓ Branch 0 taken 152922 times.
✗ Branch 1 not taken.
152922x if (got == 0)
412 break;
413
414 {
415
5/12
✓ Branch 0 taken 152922 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 152922 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 152922 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 305844 times.
✓ Branch 11 taken 458766 times.
152922x auto [lec] = co_await io_cm_.lock();
416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 458766 times.
458766x if (lec)
417 co_return lec;
418 458766x capy::async_mutex::lock_guard io_guard(&io_cm_);
419
10/18
✗ Branch 0 not taken.
✓ Branch 1 taken 458766 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 458766 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 458766 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 458766 times.
✓ Branch 8 taken 152922 times.
✓ Branch 9 taken 305844 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 152922 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 152922 times.
✓ Branch 15 taken 152922 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 152922 times.
1529220x auto [ec, n] = co_await capy::write(
420 917532x *s_, capy::const_buffer(out_buf_.data(), got));
421
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 152921 times.
152922x if (ec)
422
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
2x co_return ec;
423 458766x }
424 458766x }
425
1/2
✓ Branch 0 taken 176118 times.
✗ Branch 1 not taken.
176118x co_return std::error_code{};
426 305844x }
427
428
10/24
✓ Branch 0 taken 24649 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24649 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24649 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 24649 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 24649 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 24649 times.
✓ Branch 15 taken 24649 times.
✓ Branch 16 taken 24649 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 49298 times.
✓ Branch 19 taken 24649 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
221841x capy::task<std::error_code> read_input()
429 24649x {
430
4/10
✓ Branch 0 taken 24649 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24649 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 49298 times.
✓ Branch 9 taken 73947 times.
24649x auto [lec] = co_await io_cm_.lock();
431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73947 times.
73947x if (lec)
432 co_return lec;
433 73947x capy::async_mutex::lock_guard io_guard(&io_cm_);
434
9/16
✓ Branch 0 taken 73947 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 73947 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 73947 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 24649 times.
✓ Branch 7 taken 49298 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 24649 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 24649 times.
✓ Branch 13 taken 24649 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 24649 times.
172543x auto [ec, n] = co_await s_->read_some(
435 73947x capy::mutable_buffer(in_buf_.data(), in_buf_.size()));
436
2/2
✓ Branch 0 taken 627 times.
✓ Branch 1 taken 24022 times.
24649x if (ec)
437
2/4
✓ Branch 0 taken 627 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 627 times.
✗ Branch 3 not taken.
1254x co_return ec;
438
439
2/4
✓ Branch 0 taken 24022 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24022 times.
✗ Branch 3 not taken.
48044x int got = BIO_write(ext_bio_, in_buf_.data(), static_cast<int>(n));
440
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 24022 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24022 times.
48044x if (got < static_cast<int>(n))
441 {
442 co_return make_error_code(std::errc::no_buffer_space);
443 }
444
445
1/2
✓ Branch 0 taken 24022 times.
✗ Branch 1 not taken.
24022x co_return std::error_code{};
446 123245x }
447
448 capy::io_task<std::size_t>
449
9/24
✓ Branch 0 taken 150621 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 150621 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 150621 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 150621 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 150621 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 150621 times.
✓ Branch 15 taken 150621 times.
✓ Branch 16 taken 150621 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 19 taken 150621 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
753105x do_read_some(capy::detail::mutable_buffer_array<capy::detail::max_iovec_> buffers)
450 150621x {
451 150621x std::error_code ec;
452 150621x std::size_t total_read = 0;
453
454
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 150621 times.
✓ Branch 2 taken 150621 times.
✗ Branch 3 not taken.
301242x for (auto& buf : buffers)
455 {
456 150621x char* dest = static_cast<char*>(buf.data());
457 150621x int remaining = static_cast<int>(buf.size());
458
459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218859 times.
218859x while (remaining > 0)
460 {
461
1/2
✓ Branch 0 taken 218859 times.
✗ Branch 1 not taken.
218859x ERR_clear_error();
462
1/2
✓ Branch 0 taken 218859 times.
✗ Branch 1 not taken.
218859x int ret = SSL_read(ssl_, dest, remaining);
463
464
2/2
✓ Branch 0 taken 150593 times.
✓ Branch 1 taken 68266 times.
218859x if (ret > 0)
465 {
466 150593x dest += ret;
467 150593x remaining -= ret;
468 150593x total_read += static_cast<std::size_t>(ret);
469
470
1/2
✓ Branch 0 taken 150593 times.
✗ Branch 1 not taken.
150593x if (total_read > 0)
471
2/4
✓ Branch 0 taken 150593 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 150593 times.
✗ Branch 3 not taken.
301214x co_return {std::error_code{}, total_read};
472 }
473 else
474 {
475
1/2
✓ Branch 0 taken 68266 times.
✗ Branch 1 not taken.
68266x int err = SSL_get_error(ssl_, ret);
476
477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68266 times.
68266x if (err == SSL_ERROR_WANT_WRITE)
478 {
479 ec = co_await flush_output();
480 if (ec)
481 co_return {ec, total_read};
482 }
483
2/2
✓ Branch 0 taken 68244 times.
✓ Branch 1 taken 22 times.
68266x else if (err == SSL_ERROR_WANT_READ)
484 {
485
9/14
✓ Branch 0 taken 68244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 68244 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22748 times.
✓ Branch 5 taken 45496 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 22748 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 22748 times.
✓ Branch 11 taken 22748 times.
✓ Branch 12 taken 45496 times.
✓ Branch 13 taken 68244 times.
90992x ec = co_await flush_output();
486
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68244 times.
68244x if (ec)
487 co_return {ec, total_read};
488
489
8/14
✓ Branch 0 taken 68244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 68244 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22748 times.
✓ Branch 5 taken 45496 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 22748 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 22748 times.
✓ Branch 11 taken 22748 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 22748 times.
90992x ec = co_await read_input();
490
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 22742 times.
22748x if (ec)
491 {
492
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6x if (ec == make_error_code(capy::error::eof))
493 {
494
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3x if (SSL_get_shutdown(ssl_) &
495 SSL_RECEIVED_SHUTDOWN)
496 ec = make_error_code(capy::error::eof);
497 else
498 3x ec = make_error_code(
499 capy::error::stream_truncated);
500 3x }
501
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6x co_return {ec, total_read};
502 }
503 22742x }
504
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22x else if (err == SSL_ERROR_ZERO_RETURN)
505 {
506
3/6
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
44x co_return {
507 22x make_error_code(capy::error::eof), total_read};
508 }
509 else if (err == SSL_ERROR_SYSCALL)
510 {
511 unsigned long ssl_err = ERR_get_error();
512 if (ssl_err == 0)
513 ec = make_error_code(capy::error::stream_truncated);
514 else
515 ec = make_openssl_error(ssl_err);
516 co_return {ec, total_read};
517 }
518 else
519 {
520 unsigned long ssl_err = ERR_get_error();
521 ec = make_openssl_error(ssl_err);
522 co_return {ec, total_read};
523 }
524 68266x }
525 218859x }
526 150621x }
527
528 co_return {std::error_code{}, total_read};
529 241613x }
530
531 capy::io_task<std::size_t>
532
9/24
✓ Branch 0 taken 150624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 150624 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 150624 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 150624 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 150624 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 150624 times.
✓ Branch 15 taken 150624 times.
✓ Branch 16 taken 150624 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 150624 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
753120x do_write_some(capy::detail::const_buffer_array<capy::detail::max_iovec_> buffers)
533 150624x {
534 150624x std::error_code ec;
535 150624x std::size_t total_written = 0;
536
537
2/4
✓ Branch 0 taken 150624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 150624 times.
✗ Branch 3 not taken.
301248x for (auto const& buf : buffers)
538 {
539 150624x char const* src = static_cast<char const*>(buf.data());
540 150624x int remaining = static_cast<int>(buf.size());
541
542
1/2
✓ Branch 0 taken 451872 times.
✗ Branch 1 not taken.
451872x while (remaining > 0)
543 {
544
1/2
✓ Branch 0 taken 451872 times.
✗ Branch 1 not taken.
451872x ERR_clear_error();
545
1/2
✓ Branch 0 taken 451872 times.
✗ Branch 1 not taken.
451872x int ret = SSL_write(ssl_, src, remaining);
546
547
1/2
✓ Branch 0 taken 451872 times.
✗ Branch 1 not taken.
451872x if (ret > 0)
548 {
549 451872x src += ret;
550 451872x remaining -= ret;
551 451872x total_written += static_cast<std::size_t>(ret);
552
553
1/2
✓ Branch 0 taken 451872 times.
✗ Branch 1 not taken.
451872x if (total_written > 0)
554 {
555
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 451872 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 451872 times.
✓ Branch 4 taken 150624 times.
✓ Branch 5 taken 301248 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 150624 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 150624 times.
✓ Branch 11 taken 150624 times.
✓ Branch 12 taken 150624 times.
✗ Branch 13 not taken.
753120x ec = co_await flush_output();
556
2/4
✓ Branch 0 taken 150624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 150624 times.
✗ Branch 3 not taken.
150624x co_return {ec, total_written};
557 }
558 }
559 else
560 {
561 int err = SSL_get_error(ssl_, ret);
562
563 if (err == SSL_ERROR_WANT_WRITE)
564 {
565 ec = co_await flush_output();
566 if (ec)
567 co_return {ec, total_written};
568 }
569 else if (err == SSL_ERROR_WANT_READ)
570 {
571 ec = co_await flush_output();
572 if (ec)
573 co_return {ec, total_written};
574
575 ec = co_await read_input();
576 if (ec)
577 co_return {ec, total_written};
578 }
579 else
580 {
581 unsigned long ssl_err = ERR_get_error();
582 ec = make_openssl_error(ssl_err);
583 co_return {ec, total_written};
584 }
585 }
586 150624x }
587 150624x }
588
589 co_return {std::error_code{}, total_written};
590 451872x }
591
592
11/24
✓ Branch 0 taken 1441 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1441 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1441 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1636 times.
✓ Branch 7 taken 3077 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1441 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1441 times.
✓ Branch 15 taken 1441 times.
✓ Branch 16 taken 1441 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1636 times.
✓ Branch 19 taken 1441 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
8841x capy::io_task<> do_handshake(int type)
593 1441x {
594
2/2
✓ Branch 0 taken 3073 times.
✓ Branch 1 taken 4 times.
3077x if (used_)
595
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4x reset();
596
597 3077x std::error_code ec;
598
599 8039x while (true)
600 {
601
1/2
✓ Branch 0 taken 8039 times.
✗ Branch 1 not taken.
8039x ERR_clear_error();
602 8039x int ret;
603
2/2
✓ Branch 0 taken 1439 times.
✓ Branch 1 taken 6600 times.
8039x if (type == openssl_stream::client)
604
1/2
✓ Branch 0 taken 1439 times.
✗ Branch 1 not taken.
1439x ret = SSL_connect(ssl_);
605 else
606
1/2
✓ Branch 0 taken 6600 times.
✗ Branch 1 not taken.
6600x ret = SSL_accept(ssl_);
607
608
2/2
✓ Branch 0 taken 2454 times.
✓ Branch 1 taken 5585 times.
8039x if (ret == 1)
609 {
610 2454x used_ = true;
611
8/14
✓ Branch 0 taken 2454 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2454 times.
✓ Branch 4 taken 818 times.
✓ Branch 5 taken 1636 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 818 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 818 times.
✓ Branch 11 taken 818 times.
✓ Branch 12 taken 818 times.
✗ Branch 13 not taken.
4713x ec = co_await flush_output();
612
2/4
✓ Branch 0 taken 818 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 818 times.
✗ Branch 3 not taken.
818x co_return {ec};
613 }
614 else
615 {
616
1/2
✓ Branch 0 taken 5585 times.
✗ Branch 1 not taken.
5585x int err = SSL_get_error(ssl_, ret);
617
618
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5585 times.
5585x if (err == SSL_ERROR_WANT_WRITE)
619 {
620 ec = co_await flush_output();
621 if (ec)
622 co_return {ec};
623 }
624
2/2
✓ Branch 0 taken 5574 times.
✓ Branch 1 taken 11 times.
5585x else if (err == SSL_ERROR_WANT_READ)
625 {
626
9/14
✗ Branch 0 not taken.
✓ Branch 1 taken 5574 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5574 times.
✓ Branch 4 taken 1858 times.
✓ Branch 5 taken 3716 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1858 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1858 times.
✓ Branch 11 taken 1858 times.
✓ Branch 12 taken 3716 times.
✓ Branch 13 taken 5574 times.
7432x ec = co_await flush_output();
627
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5574 times.
5574x if (ec)
628 co_return {ec};
629
630
8/14
✓ Branch 0 taken 5574 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5574 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1858 times.
✓ Branch 5 taken 3716 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1858 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1858 times.
✓ Branch 11 taken 1858 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1858 times.
7432x ec = co_await read_input();
631
2/2
✓ Branch 0 taken 612 times.
✓ Branch 1 taken 1246 times.
1858x if (ec)
632
2/4
✓ Branch 0 taken 612 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 612 times.
✗ Branch 3 not taken.
612x co_return {ec};
633 1246x }
634 else
635 {
636
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11x unsigned long ssl_err = ERR_get_error();
637 11x ec = make_openssl_error(ssl_err);
638
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11x co_return {ec};
639 11x }
640 5585x }
641 6403x }
642 10509x }
643
644
11/24
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 56 times.
✓ Branch 7 taken 93 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 37 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 37 times.
✓ Branch 15 taken 37 times.
✓ Branch 16 taken 37 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 37 times.
✓ Branch 19 taken 56 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
241x capy::io_task<> do_shutdown()
645 37x {
646 93x std::error_code ec;
647
648 213x while (true)
649 {
650
1/2
✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
213x ERR_clear_error();
651
1/2
✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
213x int ret = SSL_shutdown(ssl_);
652
653
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 129 times.
213x if (ret == 1)
654 {
655
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 28 times.
✓ Branch 5 taken 56 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 28 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 28 times.
✓ Branch 11 taken 28 times.
✓ Branch 12 taken 28 times.
✗ Branch 13 not taken.
112x ec = co_await flush_output();
656
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28x co_return {ec};
657 }
658
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 69 times.
129x else if (ret == 0)
659 {
660
9/14
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69 times.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 46 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 23 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 23 times.
✓ Branch 11 taken 23 times.
✓ Branch 12 taken 46 times.
✓ Branch 13 taken 69 times.
92x ec = co_await flush_output();
661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
69x if (ec)
662 co_return {ec};
663
664
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69 times.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 46 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 23 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 23 times.
✓ Branch 11 taken 23 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 23 times.
92x ec = co_await read_input();
665
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 20 times.
23x if (ec)
666 {
667 3x ec = normalize_openssl_shutdown_read_error(ec);
668
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3x co_return {ec};
669 }
670 20x }
671 else
672 {
673
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60x int err = SSL_get_error(ssl_, ret);
674
675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60x if (err == SSL_ERROR_WANT_WRITE)
676 {
677 ec = co_await flush_output();
678 if (ec)
679 co_return {ec};
680 }
681
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60x else if (err == SSL_ERROR_WANT_READ)
682 {
683
9/14
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 40 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 20 times.
✓ Branch 11 taken 20 times.
✓ Branch 12 taken 40 times.
✓ Branch 13 taken 60 times.
80x ec = co_await flush_output();
684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60x if (ec)
685 co_return {ec};
686
687
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 40 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 20 times.
✓ Branch 11 taken 20 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 20 times.
80x ec = co_await read_input();
688
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 14 times.
20x if (ec)
689 {
690 6x ec = normalize_openssl_shutdown_read_error(ec);
691
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6x co_return {ec};
692 }
693 14x }
694 else
695 {
696 unsigned long ssl_err = ERR_get_error();
697 if (ssl_err == 0 && err == SSL_ERROR_SYSCALL)
698 {
699 ec = {};
700 }
701 else
702 {
703 ec = make_openssl_error(ssl_err);
704 }
705 co_return {ec};
706 }
707 60x }
708 157x }
709 265x }
710
711 2027x std::error_code init_ssl()
712 {
713 2027x auto& cd = detail::get_tls_context_data(ctx_);
714 2027x SSL_CTX* native_ctx = detail::get_openssl_context(cd);
715
1/2
✓ Branch 0 taken 2027 times.
✗ Branch 1 not taken.
2027x if (!native_ctx)
716 {
717 unsigned long err = ERR_get_error();
718 return make_openssl_error(err);
719 }
720
721 2027x ssl_ = SSL_new(native_ctx);
722
1/2
✓ Branch 0 taken 2027 times.
✗ Branch 1 not taken.
2027x if (!ssl_)
723 {
724 unsigned long err = ERR_get_error();
725 return make_openssl_error(err);
726 }
727
728 2027x BIO* int_bio = nullptr;
729
1/2
✓ Branch 0 taken 2027 times.
✗ Branch 1 not taken.
2027x if (!BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0))
730 {
731 unsigned long err = ERR_get_error();
732 SSL_free(ssl_);
733 ssl_ = nullptr;
734 return make_openssl_error(err);
735 }
736
737 2027x SSL_set_bio(ssl_, int_bio, int_bio);
738
739 2027x apply_hostname_verification(ssl_, cd.hostname);
740
741 2027x return {};
742 2027x }
743 };
744
745 openssl_stream::impl*
746 2027x openssl_stream::make_impl(capy::any_stream& stream, tls_context const& ctx)
747 {
748
1/4
✓ Branch 0 taken 2027 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2027x auto* p = new impl(stream, ctx);
749
750 2027x auto ec = p->init_ssl();
751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2027 times.
2027x if (ec)
752 {
753 delete p;
754 return nullptr;
755 }
756
757 2027x return p;
758 2027x }
759
760 4058x openssl_stream::~openssl_stream()
761 2029x {
762
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2026 times.
2029x delete impl_;
763 4058x }
764
765 4x openssl_stream::openssl_stream(openssl_stream&& other) noexcept
766 2x : stream_(std::move(other.stream_))
767 2x , impl_(other.impl_)
768 4x {
769 2x other.impl_ = nullptr;
770
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2x if (impl_)
771 2x impl_->s_ = &stream_;
772 4x }
773
774 openssl_stream&
775 1x openssl_stream::operator=(openssl_stream&& other) noexcept
776 {
777
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1x if (this != &other)
778 {
779
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1x delete impl_;
780 1x stream_ = std::move(other.stream_);
781 1x impl_ = other.impl_;
782 1x other.impl_ = nullptr;
783
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1x if (impl_)
784 1x impl_->s_ = &stream_;
785 1x }
786 1x return *this;
787 }
788
789 capy::io_task<std::size_t>
790
11/24
✓ Branch 0 taken 150621 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 150621 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 150621 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 301242 times.
✓ Branch 7 taken 451863 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 150621 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 150621 times.
✓ Branch 15 taken 150621 times.
✓ Branch 16 taken 150621 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 301242 times.
✓ Branch 19 taken 150621 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
1054347x openssl_stream::do_read_some(
791 capy::detail::mutable_buffer_array<capy::detail::max_iovec_> buffers)
792 150621x {
793
9/16
✓ Branch 0 taken 451863 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 451863 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 150621 times.
✓ Branch 5 taken 301242 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 150621 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 150621 times.
✓ Branch 11 taken 150621 times.
✓ Branch 12 taken 150621 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 150621 times.
753105x co_return co_await impl_->do_read_some(buffers);
794 301242x }
795
796 capy::io_task<std::size_t>
797
11/24
✓ Branch 0 taken 150624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 150624 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 150624 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 301248 times.
✓ Branch 7 taken 451872 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 150624 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 150624 times.
✓ Branch 15 taken 150624 times.
✓ Branch 16 taken 150624 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 301248 times.
✓ Branch 19 taken 150624 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
1054368x openssl_stream::do_write_some(
798 capy::detail::const_buffer_array<capy::detail::max_iovec_> buffers)
799 150624x {
800
9/16
✓ Branch 0 taken 451872 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 451872 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 150624 times.
✓ Branch 5 taken 301248 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 150624 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 150624 times.
✓ Branch 11 taken 150624 times.
✓ Branch 12 taken 150624 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 150624 times.
753120x co_return co_await impl_->do_write_some(buffers);
801 301248x }
802
803 capy::io_task<>
804
11/24
✓ Branch 0 taken 1441 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1441 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1441 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2882 times.
✓ Branch 7 taken 4323 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1441 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1441 times.
✓ Branch 15 taken 1441 times.
✓ Branch 16 taken 1441 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 2882 times.
✓ Branch 19 taken 1441 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
10087x openssl_stream::handshake(handshake_type type)
805 1441x {
806
9/16
✓ Branch 0 taken 4323 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4323 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1441 times.
✓ Branch 5 taken 2882 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1441 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1441 times.
✓ Branch 11 taken 1441 times.
✓ Branch 12 taken 1441 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1441 times.
7205x co_return co_await impl_->do_handshake(type);
807 2882x }
808
809 capy::io_task<>
810
11/24
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 74 times.
✓ Branch 7 taken 111 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 37 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 37 times.
✓ Branch 15 taken 37 times.
✓ Branch 16 taken 37 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 74 times.
✓ Branch 19 taken 37 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
259x openssl_stream::shutdown()
811 37x {
812
9/16
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 111 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✓ Branch 5 taken 74 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 37 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 37 times.
✓ Branch 11 taken 37 times.
✓ Branch 12 taken 37 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 37 times.
148x co_return co_await impl_->do_shutdown();
813 74x }
814
815 void
816 16x openssl_stream::reset()
817 {
818 16x impl_->reset();
819 16x }
820
821 std::string_view
822 1x openssl_stream::name() const noexcept
823 {
824
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x return "openssl";
825 }
826
827 } // namespace boost::corosio
828