src/corosio/src/tls/detail/engine_types.hpp

94.7% Lines (18/0/19) 100.0% List of functions (2/0/2)
engine_types.hpp
f(x) Functions (2)
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Steve Gerbino
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 SRC_TLS_DETAIL_ENGINE_TYPES_HPP
11 #define SRC_TLS_DETAIL_ENGINE_TYPES_HPP
12
13 #include <boost/corosio/ipv4_address.hpp>
14 #include <boost/corosio/ipv6_address.hpp>
15
16 #include <boost/capy/cond.hpp>
17 #include <boost/capy/error.hpp>
18
19 #include <cstddef>
20 #include <string>
21 #include <system_error>
22
23 namespace boost::corosio {
24
25 namespace detail {
26
27 /** What the TLS engine needs from its driver after a `perform` call.
28
29 The driver owns the transport; the engine only stages bytes. Each
30 verdict tells the driver which transport action unblocks the
31 engine before the operation can make progress.
32 */
33 enum class engine_want
34 {
35 /// The operation finished; `ec` and `bytes` carry the outcome.
36 done,
37
38 /// The engine needs more input bytes before it can retry.
39 input,
40
41 /// Pending output must reach the peer, then retry the operation.
42 output_then_retry,
43
44 /// Pending output must reach the peer; the operation finished.
45 output_then_done
46 };
47
48 /// Outcome of one synchronous engine step.
49 struct engine_result
50 {
51 /// Required driver action.
52 engine_want want;
53
54 /// Mapped, final error for `done` verdicts; empty otherwise.
55 std::error_code ec;
56
57 /// Application bytes transferred by this step.
58 std::size_t bytes;
59 };
60
61 /// Operation selector for `engine::perform`.
62 enum class engine_op
63 {
64 handshake_client,
65 handshake_server,
66 read,
67 write,
68 shutdown
69 };
70
71 /** Check whether a peer name is an IP literal rather than a DNS name.
72
73 RFC 6066 excludes IP literals from SNI, and a literal must be matched
74 against a certificate's iPAddress entries rather than its DNS names,
75 so both backends branch on this when applying hostname verification.
76
77 @param s The peer name.
78
79 @return `true` when `s` parses as an IPv4 or IPv6 address.
80 */
81 inline bool
82 13x is_ip_literal(std::string const& s) noexcept
83 {
84 24x return !std::get<0>(make_ipv4_address(s)) ||
85 24x !std::get<0>(make_ipv6_address(s));
86 }
87
88 /** Map a transport error observed while filling engine input.
89
90 What a transport failure means depends on which operation was
91 starved of input and on close_notify visibility, but not on the
92 backend; the whole policy lives once here.
93
94 For `read` / `write`, a transport end-of-stream after the peer's
95 close_notify is a clean `eof`; without one it is a truncation
96 attack per the TLS contract. Other errors pass through unchanged.
97
98 For `shutdown`, a member of the eof/reset/aborted/broken_pipe
99 family may reflect the peer's close_notify that a concurrent
100 reader already consumed during the shutdown's flush rather than a
101 genuine truncation; the received-shutdown bit distinguishes a
102 completed close (success) from an unannounced one
103 (`stream_truncated`). `canceled` and errors outside that family
104 pass through unchanged so the received-shutdown race window can
105 never absorb an unrelated fault.
106
107 Handshake operations pass every error through: no close is clean
108 before the session is established.
109
110 @param op The operation whose input fill failed.
111 @param ec The transport error.
112 @param received_shutdown Whether the peer's close_notify was seen.
113
114 @return The mapped error.
115 */
116 inline std::error_code
117 1352x map_fill_error(
118 engine_op op, std::error_code ec, bool received_shutdown) noexcept
119 {
120 1352x if (op == engine_op::shutdown)
121 {
122 30x if (!ec || ec == capy::cond::canceled)
123 8x return ec;
124
125 42x if (ec != capy::cond::eof && ec != std::errc::connection_reset &&
126 60x ec != std::errc::connection_aborted &&
127 40x ec != std::errc::broken_pipe)
128 18x return ec;
129
130 4x if (received_shutdown)
131 return {};
132
133 // A peer that closed without a proper close_notify is a
134 // truncated stream.
135 4x return make_error_code(capy::error::stream_truncated);
136 }
137
138 1364x if ((op == engine_op::read || op == engine_op::write) &&
139 1364x ec == capy::cond::eof)
140 5x return make_error_code(
141 received_shutdown ? capy::error::eof
142 5x : capy::error::stream_truncated);
143
144 1317x return ec;
145 }
146
147 } // namespace detail
148
149 } // namespace boost::corosio
150
151 #endif
152