include/boost/corosio/openssl_stream.hpp

50.0% Lines (4/8) 50.0% Functions (2/4) 100.0% Branches (2/2)
include/boost/corosio/openssl_stream.hpp
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 #ifndef BOOST_COROSIO_OPENSSL_STREAM_HPP
11 #define BOOST_COROSIO_OPENSSL_STREAM_HPP
12
13 #include <boost/corosio/detail/config.hpp>
14 #include <boost/corosio/tls_context.hpp>
15 #include <boost/corosio/tls_stream.hpp>
16 #include <boost/capy/buffers/buffer_array.hpp>
17 #include <boost/capy/concept/stream.hpp>
18 #include <boost/capy/io/any_stream.hpp>
19 #include <boost/capy/io_task.hpp>
20
21 #include <concepts>
22
23 namespace boost::corosio {
24
25 /** A TLS stream using OpenSSL.
26
27 This class wraps an underlying stream satisfying `capy::Stream`
28 and provides TLS encryption using the OpenSSL library.
29
30 Derives from @ref tls_stream to provide a runtime-polymorphic
31 interface. The TLS operations are implemented as coroutines
32 that orchestrate reads and writes on the underlying stream.
33
34 @par Construction Modes
35
36 Two construction modes are supported:
37
38 - **Owning**: Pass stream by value. The openssl_stream takes
39 ownership and the stream is moved into internal storage.
40
41 - **Reference**: Pass stream by pointer. The openssl_stream
42 does not own the stream; the caller must ensure the stream
43 outlives this object.
44
45 @par Thread Safety
46 Distinct objects: Safe.@n
47 Shared objects: Unsafe.
48
49 @par Example
50 @code
51 tls_context ctx;
52 ctx.set_hostname("example.com");
53 ctx.set_verify_mode(tls_verify_mode::peer);
54
55 corosio::tcp_socket sock(ioc);
56 co_await sock.connect(endpoint);
57
58 // Reference mode - sock must outlive tls
59 corosio::openssl_stream tls(&sock, ctx);
60 auto [ec] = co_await tls.handshake(openssl_stream::client);
61
62 // Or owning mode - tls owns the socket
63 corosio::openssl_stream tls2(std::move(sock), ctx);
64 @endcode
65
66 @see tls_stream, wolfssl_stream
67 */
68 class BOOST_COROSIO_DECL openssl_stream final : public tls_stream
69 {
70 struct impl;
71 capy::any_stream stream_; // must be first - impl_ holds reference
72 impl* impl_;
73
74 public:
75 /** Construct an OpenSSL stream (owning mode).
76
77 Takes ownership of the underlying stream by moving it into
78 internal storage. The stream will be destroyed when this
79 openssl_stream is destroyed.
80
81 @param stream The stream to take ownership of. Must satisfy
82 `capy::Stream`.
83 @param ctx The TLS context containing configuration.
84 */
85 template<capy::Stream S>
86 requires(!std::same_as<std::decay_t<S>, openssl_stream>)
87 // NOLINTNEXTLINE(performance-unnecessary-value-param)
88 openssl_stream(S stream, tls_context ctx)
89 : stream_(std::move(stream))
90 , impl_(make_impl(stream_, ctx))
91 {
92 }
93
94 /** Construct an OpenSSL stream (reference mode).
95
96 Wraps the underlying stream without taking ownership. The
97 caller must ensure the stream remains valid for the lifetime
98 of this openssl_stream.
99
100 @param stream Pointer to the stream to wrap. Must satisfy
101 `capy::Stream`.
102 @param ctx The TLS context containing configuration.
103 */
104 template<capy::Stream S>
105 // NOLINTNEXTLINE(performance-unnecessary-value-param)
106 2171 openssl_stream(S* stream, tls_context ctx)
107 2171 : stream_(stream)
108
2/2
✓ Branch 3 → 4 taken 2171 times.
✓ Branch 4 → 5 taken 2171 times.
2171 , impl_(make_impl(stream_, ctx))
109 {
110 2171 }
111
112 /** Destructor.
113
114 Releases the underlying OpenSSL resources. If constructed
115 in owning mode, also destroys the underlying stream.
116 */
117 ~openssl_stream() override;
118
119 openssl_stream(openssl_stream&&) noexcept;
120 openssl_stream& operator=(openssl_stream&&) noexcept;
121
122 capy::io_task<> handshake(handshake_type type) override;
123
124 capy::io_task<> shutdown() override;
125
126 void reset() override;
127
128 capy::any_stream& next_layer() noexcept override
129 {
130 return stream_;
131 }
132
133 capy::any_stream const& next_layer() const noexcept override
134 {
135 return stream_;
136 }
137
138 std::string_view name() const noexcept override;
139
140 protected:
141 capy::io_task<std::size_t> do_read_some(
142 capy::mutable_buffer_array<capy::detail::max_iovec_> buffers) override;
143
144 capy::io_task<std::size_t> do_write_some(
145 capy::const_buffer_array<capy::detail::max_iovec_> buffers) override;
146
147 private:
148 static impl* make_impl(capy::any_stream& stream, tls_context const& ctx);
149 };
150
151 } // namespace boost::corosio
152
153 #endif
154