include/boost/corosio/tls_stream.hpp

85.7% Lines (6/7) 80.0% List of functions (4/5)
tls_stream.hpp
f(x) Functions (5)
Line 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 #ifndef BOOST_COROSIO_TLS_STREAM_HPP
12 #define BOOST_COROSIO_TLS_STREAM_HPP
13
14 #include <boost/corosio/detail/config.hpp>
15 #include <boost/capy/buffers.hpp>
16 #include <boost/capy/detail/buffer_array.hpp>
17 #include <boost/capy/io/any_stream.hpp>
18 #include <boost/capy/io_task.hpp>
19
20 #include <cstddef>
21 #include <string_view>
22
23 namespace boost::corosio {
24
25 /** Abstract base class for TLS streams.
26
27 This class provides a runtime-polymorphic interface for TLS
28 implementations. Derived classes (openssl_stream, wolfssl_stream)
29 implement the virtual functions to provide backend-specific
30 TLS functionality.
31
32 Unlike @ref io_stream which represents OS-level I/O completed
33 by the kernel, TLS streams are coroutine-based: their operations
34 are implemented as coroutines that orchestrate sub-operations
35 on the underlying stream.
36
37 The non-virtual template wrappers (`read_some`, `write_some`)
38 satisfy the `capy::Stream` concept, enabling TLS streams to
39 be used anywhere a Stream is expected.
40
41 @par Thread Safety
42 Distinct objects: Safe.@n
43 Shared objects: Unsafe.
44
45 @see openssl_stream, wolfssl_stream
46 */
47 class BOOST_COROSIO_DECL tls_stream
48 {
49 public:
50 /// Identify the TLS handshake role.
51 enum handshake_type
52 {
53 client, ///< Perform handshaking as a client.
54 server ///< Perform handshaking as a server.
55 };
56
57 /// Destroy the TLS stream.
58 2048x virtual ~tls_stream() = default;
59
60 tls_stream(tls_stream const&) = delete;
61 tls_stream& operator=(tls_stream const&) = delete;
62
63 /** Initiate an asynchronous read operation.
64
65 Reads decrypted data into the provided buffer sequence. The
66 operation completes when at least one byte has been read,
67 or an error occurs.
68
69 This non-virtual template wrapper satisfies the `capy::Stream`
70 concept by delegating to the virtual `do_read_some`.
71
72 @param buffers The buffer sequence to read data into.
73
74 @return An awaitable yielding `(error_code,std::size_t)`.
75 */
76 template<capy::MutableBufferSequence Buffers>
77 73841x auto read_some(Buffers const& buffers)
78 {
79 73841x return do_read_some(buffers);
80 }
81
82 /** Initiate an asynchronous write operation.
83
84 Encrypts and writes data from the provided buffer sequence.
85 The operation completes when at least one byte has been
86 written, or an error occurs.
87
88 This non-virtual template wrapper satisfies the `capy::Stream`
89 concept by delegating to the virtual `do_write_some`.
90
91 @param buffers The buffer sequence containing data to write.
92
93 @return An awaitable yielding `(error_code,std::size_t)`.
94 */
95 template<capy::ConstBufferSequence Buffers>
96 73919x auto write_some(Buffers const& buffers)
97 {
98 73919x return do_write_some(buffers);
99 }
100
101 /** Perform the TLS handshake asynchronously.
102
103 Initiates the TLS handshake process. For client connections,
104 this sends the ClientHello and processes the server's response.
105 For server connections, this waits for the ClientHello and
106 sends the server's response.
107
108 @param type The type of handshaking to perform (client or server).
109
110 @return An awaitable yielding `(error_code)`.
111 */
112 virtual capy::io_task<> handshake(handshake_type type) = 0;
113
114 /** Perform a graceful TLS shutdown asynchronously.
115
116 Initiates the TLS shutdown sequence by sending a close_notify
117 alert and waiting for the peer's close_notify response.
118
119 @return An awaitable yielding `(error_code)`.
120 */
121 virtual capy::io_task<> shutdown() = 0;
122
123 /** Reset TLS session state for reuse.
124
125 Releases TLS session state including session keys and peer
126 certificates, returning the stream to a state where
127 `handshake()` can be called again. Internal memory
128 allocations (I/O buffers) are preserved.
129
130 Calling `handshake()` on a previously-used stream
131 implicitly performs a reset first, so explicit calls
132 are only needed to eagerly release session state.
133
134 @par Preconditions
135 No TLS operation (handshake, read, write, shutdown) is
136 in progress.
137
138 @par Thread Safety
139 Not thread safe. The caller must ensure no concurrent
140 operations are in progress on this stream.
141
142 @note If called mid-session before `shutdown()`, pending
143 TLS data is discarded and the peer will observe a
144 truncated stream.
145 */
146 virtual void reset() = 0;
147
148 /** Returns a reference to the underlying stream.
149
150 Provides access to the type-erased underlying stream for
151 operations like cancellation or accessing native handles.
152
153 @warning Do not reseat (assign to) the returned reference.
154 The TLS implementation holds internal state bound to
155 the original stream. Replacing it causes undefined
156 behavior.
157
158 @return Reference to the wrapped stream.
159 */
160 virtual capy::any_stream& next_layer() noexcept = 0;
161
162 /** Returns a const reference to the underlying stream.
163
164 @return Const reference to the wrapped stream.
165 */
166 virtual capy::any_stream const& next_layer() const noexcept = 0;
167
168 /** Returns the name of the TLS backend.
169
170 @return A string identifying the TLS implementation,
171 such as "openssl" or "wolfssl".
172 */
173 virtual std::string_view name() const noexcept = 0;
174
175 /** Returns the ALPN protocol negotiated during the handshake.
176
177 Application-Layer Protocol Negotiation selects a single
178 application protocol (for example `"h2"` or `"http/1.1"`)
179 during the TLS handshake, from the list supplied via
180 @ref tls_context::set_alpn.
181
182 @return The negotiated protocol, or an empty view if no
183 protocol was negotiated, ALPN was not offered, the
184 handshake has not completed, or the backend/build does
185 not support ALPN.
186
187 @par Thread Safety
188 Safe to call after the handshake completes; not safe to call
189 concurrently with a handshake or reset.
190 */
191 virtual std::string_view alpn_protocol() const noexcept { return {}; }
192
193 protected:
194 2048x tls_stream() = default;
195
196 /** Virtual read implementation.
197
198 Derived classes override this to perform TLS decryption
199 and read operations.
200
201 @param buffers Buffer sequence to read into.
202
203 @return An awaitable yielding `(error_code,std::size_t)`.
204 */
205 virtual capy::io_task<std::size_t> do_read_some(
206 capy::detail::mutable_buffer_array<capy::detail::max_iovec_> buffers) = 0;
207
208 /** Virtual write implementation.
209
210 Derived classes override this to perform TLS encryption
211 and write operations.
212
213 @param buffers Buffer sequence to write from.
214
215 @return An awaitable yielding `(error_code,std::size_t)`.
216 */
217 virtual capy::io_task<std::size_t> do_write_some(
218 capy::detail::const_buffer_array<capy::detail::max_iovec_> buffers) = 0;
219 };
220
221 } // namespace boost::corosio
222
223 #endif
224