src/openssl/src/openssl_stream.cpp

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