MySQL 26.7.0
Source Code Documentation
ssl_io_completion.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2021, 2026, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef ROUTER_SRC_OPENSSL_INCLUDE_TLS_DETAILS_SSL_OPERATION_H_
27#define ROUTER_SRC_OPENSSL_INCLUDE_TLS_DETAILS_SSL_OPERATION_H_
28
29#include <openssl/bio.h>
30
31#include <utility>
32
37
38namespace net {
39namespace tls {
40
42 const mutable_buffer &b) noexcept {
43 return std::addressof(b);
44}
45
47 const mutable_buffer &b) noexcept {
48 return std::addressof(b) + 1;
49}
50
52 const const_buffer &b) noexcept {
53 return std::addressof(b);
54}
55
57 const const_buffer &b) noexcept {
58 return std::addressof(b) + 1;
59}
60
61template <class C>
62inline auto tls_buffer_sequence_begin(const C &c) noexcept
63 -> decltype(c.begin()) {
64 return c.begin();
65}
66
67template <class C>
68inline auto tls_buffer_sequence_end(const C &c) noexcept -> decltype(c.end()) {
69 return c.end();
70}
71
73 public:
74 template <typename Layer, typename Handler>
75 auto recv(Layer *layer, FlexibleInputBuffer &input, Handler &&handler) {
76 return layer->async_receive(input, handler);
77 }
78
79 template <typename Layer, typename Handler>
80 auto send(Layer *layer, FlexibleOutputBuffer &output, Handler &&handler) {
81 return layer->async_send(output, handler);
82 }
83};
84
86 public:
87 struct Unexpected {};
90
91 template <typename Layer, typename Handler>
92 auto recv(Layer *layer, FlexibleInputBuffer &input, Handler &&) {
93 return read_result_ = layer->read_some(input);
94 }
95
96 template <typename Layer, typename Handler>
97 auto send(Layer *layer, FlexibleOutputBuffer &output, Handler &&) {
98 return write_result_ = layer->write_some(output);
99 }
100
101 template <typename Handler>
103 auto result = write_result_;
104 write_result_ = {};
105 if (result.has_value()) {
106 return handler->handle_write({}, result.value());
107 }
108
109 return handler->handle_write(result.error(), 0);
110 }
111
112 template <typename Handler>
114 auto result = read_result_;
115 read_result_ = {};
116 if (result.has_value()) {
117 return handler->handle_read({}, result.value());
118 }
119
120 return handler->handle_read(result.error(), 0);
121 }
122
125};
126
127template <typename SslIO, typename BufferSequence, typename Token,
128 typename TlsLayer, typename Action = AsyncAction>
130 public:
131 using Token_result = std::decay_t<Token>;
135
136 template <typename UniToken>
137 SslIoCompletionToken(TlsLayer &tls_layer, const BufferSequence &buffer,
138 UniToken &&token, Action action = Action())
139 : tls_layer_{tls_layer},
143 token_{std::forward<UniToken>(token)},
144 action_{action} {}
145
148 tls_layer_{other.tls_layer_},
151 buffer_{other.buffer_},
152 token_{other.token_},
153 action_{other.action_} {}
154
157 tls_layer_{other.tls_layer_},
160 buffer_{other.buffer_},
161 token_{other.token_},
162 action_{other.action_} {}
163
164 Operation::Result handle_read(std::error_code ec, size_t size) {
165 if (ec) {
166 do_token(ec, 0);
167 return Operation::Result::fatal;
168 }
169
171 return do_read();
172 }
173
174 Operation::Result handle_write(std::error_code ec, size_t size) {
175 if (ec) {
176 do_token(ec, 0);
177 return Operation::Result::fatal;
178 }
179
181 if (0 != net::buffer_size(output_)) {
182 return do_write();
183 }
184
185 return do_it();
186 }
187
190 auto it_next = it;
192
193 ++it_next;
194 size_t page_begin = 0;
195 size_t page_end = it->size();
196
197 while (it != end) {
198 const bool is_last = it_next == end;
199 if (!is_last && number_bytes_transfered_ >= page_end) {
200 it = it_next++;
201 page_begin = page_end;
202 if (it != end) page_end += it->size();
203 continue;
204 }
205
206 auto page_offset = number_bytes_transfered_ - page_begin;
207 size_t number_of_bytes = 0;
208 auto result =
209 SslIO::op(tls_layer_.network_bio_.get(), tls_layer_.ssl_.get(),
210 cast_and_increment<uint8_t>(it->data(), page_offset),
211 it->size() - page_offset, &number_of_bytes);
212
213 number_bytes_transfered_ += number_of_bytes;
214
215 debug_print("do_it - ", (SslIO::is_read_operation() ? "read" : "write"),
216 " - result:", result,
217 " - number_bytes_transfered_:", number_bytes_transfered_);
218 switch (result) {
219 case Operation::Result::fatal: {
221 return result;
222 }
223
225 do_token(std::make_error_code(std::errc::broken_pipe), 0);
226 return result;
227
228 case Operation::Result::ok:
230 return result;
231
232 case Operation::Result::want_read: {
233 if (number_bytes_transfered_ && SslIO::is_read_operation()) {
235 return Operation::Result::ok;
236 }
237 return do_read();
238 }
239
240 case Operation::Result::want_write:
241 return do_write();
242 }
243 }
245 return Operation::Result::ok;
246 }
247
248 template <typename HandlerToken>
250 HandlerToken &&token) {
252 std::forward<HandlerToken>(token), NOP_token());
253 }
254
255 template <typename HandlerToken>
257 HandlerToken &&token) {
259 std::forward<HandlerToken>(token), NOP_token());
260 }
261
262 void do_token(const std::error_code &ec, const size_t no_of_bytes) {
263 token_(ec, no_of_bytes);
264 }
265
266 std::error_code make_fatal_result_error() {
267 auto ec = make_tls_error();
268 // Workaround: our previous assumption that every terminal/fatal TLS
269 // condition always yields a non-zero OpenSSL error (via ERR_get_error
270 // / make_tls_error()) is too strong. In some alert-driven shutdown
271 // paths (observed with user_cancelled followed by close_notify),
272 // OpenSSL can report a terminal state while the error queue remains
273 // empty, so make_tls_error() returns ec==0. If propagated as-is,
274 // upper layers may treat this as "no error" and spin forever on
275 // zero-byte callbacks. Force a non-zero error code on this path to
276 // reliably signal termination.
277 if (ec) return ec;
278
279 const auto shutdown_state = SSL_get_shutdown(tls_layer_.ssl_.get());
280 if ((shutdown_state & SSL_RECEIVED_SHUTDOWN) != 0)
282
283 return std::make_error_code(std::errc::io_error);
284 }
285
286 int bio_read_ex(size_t *out_readbytes) {
287 auto bio = tls_layer_.network_bio_.get();
288 *out_readbytes = 0;
289#if OPENSSL_VERSION_NUMBER >= NET_TLS_USE_BACKWARD_COMPATIBLE_OPENSSL
290 auto result = BIO_read_ex(bio, output_.data_free(), output_.size_free(),
291 out_readbytes);
292#else
293 auto result = BIO_read(bio, output_.data_free(), output_.size_free());
294 if (result > 0) *out_readbytes = result;
295#endif
296
297 return result;
298 }
299
300 int bio_write_ex(size_t *out_written) {
301 auto bio = tls_layer_.network_bio_.get();
302 *out_written = 0;
303#if OPENSSL_VERSION_NUMBER >= NET_TLS_USE_BACKWARD_COMPATIBLE_OPENSSL
304 auto result =
305 BIO_write_ex(bio, input_.data_used(), input_.size_used(), out_written);
306#else
307 auto result = BIO_write(bio, input_.data_used(), input_.size_used());
308 if (result > 0) *out_written = result;
309#endif
310
311 return result;
312 }
313
315 debug_print("do_write - ", (SslIO::is_read_operation() ? "read" : "write"));
316
317 if (0 == net::buffer_size(output_)) {
318 size_t readbytes;
319 bio_read_ex(&readbytes);
320 output_.push(readbytes);
321 }
322
323 action_.send(&tls_layer_.lower_layer_, output_,
324 get_write_handler(std::move(*this)));
325
326 return Operation::Result::want_write;
327 }
328
330 debug_print("do_read - ", (SslIO::is_read_operation() ? "read" : "write"));
331 if (0 == input_.size_used()) {
332 action_.recv(&tls_layer_.lower_layer_, input_,
333 get_read_handler(std::move(*this)));
334 return Operation::Result::want_read;
335 }
336
337 size_t written;
338 bio_write_ex(&written);
339 input_.pop(written);
340 return do_it();
341 }
342
343 template <typename... Parameters>
344 void debug_print([[maybe_unused]] Parameters &&...parameters) const {
345 // (std::cout << ... << std::forward<Parameters>(parameters));
346 // std::cout << std::endl;
347 }
348
349 template <typename Type>
350 static const Type *cast_and_increment(const void *ptr, int value) {
351 return static_cast<const Type *>(ptr) + value;
352 }
353
354 template <typename Type>
355 static Type *cast_and_increment(void *ptr, int value) {
356 return static_cast<Type *>(ptr) + value;
357 }
358
360 TlsLayer &tls_layer_;
363 const BufferSequence buffer_;
364 Token token_;
366};
367
368} // namespace tls
369} // namespace net
370
371#endif // ROUTER_SRC_OPENSSL_INCLUDE_TLS_DETAILS_SSL_OPERATION_H_
The handler class is the interface for dynamically loadable storage engines.
Definition: handler.h:4753
Definition: buffer.h:135
Definition: buffer.h:113
Definition: ssl_io_completion.h:72
auto send(Layer *layer, FlexibleOutputBuffer &output, Handler &&handler)
Definition: ssl_io_completion.h:80
auto recv(Layer *layer, FlexibleInputBuffer &input, Handler &&handler)
Definition: ssl_io_completion.h:75
size_t size_used() const
Definition: flexible_buffer.h:59
bool pop(size_t v) noexcept
Definition: flexible_buffer.h:67
void * data_free() const
Definition: flexible_buffer.h:57
void * data_used() const noexcept
Definition: flexible_buffer.h:56
bool push(size_t v) noexcept
Definition: flexible_buffer.h:78
size_t size_free() const
Definition: flexible_buffer.h:58
Definition: flexible_buffer.h:105
Definition: flexible_buffer.h:91
Definition: lower_layer_completion.h:40
Definition: lower_layer_completion.h:77
Definition: lower_layer_completion.h:34
Result
Definition: ssl_operation.h:41
Definition: ssl_io_completion.h:129
FlexibleInputBuffer & input_
Definition: ssl_io_completion.h:362
int bio_write_ex(size_t *out_written)
Definition: ssl_io_completion.h:300
static Type * cast_and_increment(void *ptr, int value)
Definition: ssl_io_completion.h:355
LowerLayerReadCompletionToken< HandlerToken, NOP_token > get_read_handler(HandlerToken &&token)
Definition: ssl_io_completion.h:256
Operation::Result handle_read(std::error_code ec, size_t size)
Definition: ssl_io_completion.h:164
FlexibleOutputBuffer & output_
Definition: ssl_io_completion.h:361
int bio_read_ex(size_t *out_readbytes)
Definition: ssl_io_completion.h:286
Action action_
Definition: ssl_io_completion.h:365
Token token_
Definition: ssl_io_completion.h:364
std::error_code make_fatal_result_error()
Definition: ssl_io_completion.h:266
Operation::Result do_write()
Definition: ssl_io_completion.h:314
SslIoCompletionToken(TlsLayer &tls_layer, const BufferSequence &buffer, UniToken &&token, Action action=Action())
Definition: ssl_io_completion.h:137
std::decay_t< Token > Token_result
Definition: ssl_io_completion.h:131
std::conditional_t< std::is_same< Token, Token_result >::value, Token_result &, Token_result > Token_handler
Definition: ssl_io_completion.h:134
Operation::Result handle_write(std::error_code ec, size_t size)
Definition: ssl_io_completion.h:174
SslIoCompletionToken(SslIoCompletionToken &&other)
Definition: ssl_io_completion.h:146
SslIoCompletionToken(const SslIoCompletionToken &other)
Definition: ssl_io_completion.h:155
Operation::Result do_it()
Definition: ssl_io_completion.h:188
TlsLayer & tls_layer_
Definition: ssl_io_completion.h:360
const BufferSequence buffer_
Definition: ssl_io_completion.h:363
LowerLayerWriteCompletionToken< HandlerToken > get_write_handler(HandlerToken &&token)
Definition: ssl_io_completion.h:249
size_t number_bytes_transfered_
Definition: ssl_io_completion.h:359
Operation::Result do_read()
Definition: ssl_io_completion.h:329
void debug_print(Parameters &&...parameters) const
Definition: ssl_io_completion.h:344
static const Type * cast_and_increment(const void *ptr, int value)
Definition: ssl_io_completion.h:350
void do_token(const std::error_code &ec, const size_t no_of_bytes)
Definition: ssl_io_completion.h:262
Definition: ssl_io_completion.h:85
Handler_result handle_write_result(Handler *handler)
Definition: ssl_io_completion.h:102
auto send(Layer *layer, FlexibleOutputBuffer &output, Handler &&)
Definition: ssl_io_completion.h:97
Handler_result handle_read_result(Handler *handler)
Definition: ssl_io_completion.h:113
Handler_arguments write_result_
Definition: ssl_io_completion.h:123
Handler_arguments read_result_
Definition: ssl_io_completion.h:124
auto recv(Layer *layer, FlexibleInputBuffer &input, Handler &&)
Definition: ssl_io_completion.h:92
Definition: expected.h:286
MediaType
Definition: media_type.h:33
ValueType value(const std::optional< ValueType > &v)
Definition: gtid.h:83
std::map< std::string, std::string > Parameters
Definition: rest_handler.h:60
std::error_code make_error_code(DynamicLoaderErrc ec)
make error_code from a DynamicLoaderErrc.
Definition: dynamic_loader.cc:97
size_t size(const char *const c)
Definition: base64.h:46
stdx::expected< void, std::error_code > close(file_handle_type native_handle)
close file handle.
Definition: file.h:239
const mutable_buffer * tls_buffer_sequence_begin(const mutable_buffer &b) noexcept
Definition: ssl_io_completion.h:41
const mutable_buffer * tls_buffer_sequence_end(const mutable_buffer &b) noexcept
Definition: ssl_io_completion.h:46
Definition: buffer.h:45
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:418
size_t buffer_size(const ConstBufferSequence &buffers) noexcept
Definition: buffer.h:313
std::error_code make_error_code(net::stream_errc e) noexcept
Definition: buffer.h:103
Define std::hash<Gtid>.
Definition: gtid.h:355
Definition: tls_keylog_dumper.h:35
static ulint page_offset(const void *ptr)
Gets the offset within a page.
struct result result
Definition: result.h:34
message Action
Definition: replication_group_member_actions.proto:30
repeated Action action
Definition: replication_group_member_actions.proto:43
Definition: ssl_io_completion.h:87
Definition: result.h:30
HARNESS_TLS_EXPORT std::error_code make_tls_error()
make a std::error_code from ERR_get_error().
Definition: tls_error.cc:100