]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/ssl/detail/io.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / asio / ssl / detail / io.hpp
CommitLineData
7c673cae
FG
1//
2// ssl/detail/io.hpp
3// ~~~~~~~~~~~~~~~~~
4//
92f5a8d4 5// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7c673cae
FG
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_SSL_DETAIL_IO_HPP
12#define BOOST_ASIO_SSL_DETAIL_IO_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
b32b8144
FG
20#include <boost/asio/ssl/detail/engine.hpp>
21#include <boost/asio/ssl/detail/stream_core.hpp>
22#include <boost/asio/write.hpp>
7c673cae
FG
23
24#include <boost/asio/detail/push_options.hpp>
25
26namespace boost {
27namespace asio {
28namespace ssl {
29namespace detail {
30
7c673cae
FG
31template <typename Stream, typename Operation>
32std::size_t io(Stream& next_layer, stream_core& core,
33 const Operation& op, boost::system::error_code& ec)
34{
92f5a8d4 35 boost::system::error_code io_ec;
7c673cae
FG
36 std::size_t bytes_transferred = 0;
37 do switch (op(core.engine_, ec, bytes_transferred))
38 {
39 case engine::want_input_and_retry:
40
41 // If the input buffer is empty then we need to read some more data from
42 // the underlying transport.
b32b8144 43 if (core.input_.size() == 0)
92f5a8d4 44 {
7c673cae 45 core.input_ = boost::asio::buffer(core.input_buffer_,
92f5a8d4
TL
46 next_layer.read_some(core.input_buffer_, io_ec));
47 if (!ec)
48 ec = io_ec;
49 }
7c673cae
FG
50
51 // Pass the new input data to the engine.
52 core.input_ = core.engine_.put_input(core.input_);
53
54 // Try the operation again.
55 continue;
56
57 case engine::want_output_and_retry:
58
59 // Get output data from the engine and write it to the underlying
60 // transport.
61 boost::asio::write(next_layer,
92f5a8d4
TL
62 core.engine_.get_output(core.output_buffer_), io_ec);
63 if (!ec)
64 ec = io_ec;
7c673cae
FG
65
66 // Try the operation again.
67 continue;
68
69 case engine::want_output:
70
71 // Get output data from the engine and write it to the underlying
72 // transport.
73 boost::asio::write(next_layer,
92f5a8d4
TL
74 core.engine_.get_output(core.output_buffer_), io_ec);
75 if (!ec)
76 ec = io_ec;
7c673cae
FG
77
78 // Operation is complete. Return result to caller.
79 core.engine_.map_error_code(ec);
80 return bytes_transferred;
81
82 default:
83
84 // Operation is complete. Return result to caller.
85 core.engine_.map_error_code(ec);
86 return bytes_transferred;
87
88 } while (!ec);
89
90 // Operation failed. Return result to caller.
91 core.engine_.map_error_code(ec);
92 return 0;
93}
94
95template <typename Stream, typename Operation, typename Handler>
96class io_op
97{
98public:
99 io_op(Stream& next_layer, stream_core& core,
100 const Operation& op, Handler& handler)
101 : next_layer_(next_layer),
102 core_(core),
103 op_(op),
104 start_(0),
105 want_(engine::want_nothing),
106 bytes_transferred_(0),
107 handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler))
108 {
109 }
110
111#if defined(BOOST_ASIO_HAS_MOVE)
112 io_op(const io_op& other)
113 : next_layer_(other.next_layer_),
114 core_(other.core_),
115 op_(other.op_),
116 start_(other.start_),
117 want_(other.want_),
118 ec_(other.ec_),
119 bytes_transferred_(other.bytes_transferred_),
120 handler_(other.handler_)
121 {
122 }
123
124 io_op(io_op&& other)
125 : next_layer_(other.next_layer_),
126 core_(other.core_),
11fdf7f2 127 op_(BOOST_ASIO_MOVE_CAST(Operation)(other.op_)),
7c673cae
FG
128 start_(other.start_),
129 want_(other.want_),
130 ec_(other.ec_),
131 bytes_transferred_(other.bytes_transferred_),
132 handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_))
133 {
134 }
135#endif // defined(BOOST_ASIO_HAS_MOVE)
136
137 void operator()(boost::system::error_code ec,
138 std::size_t bytes_transferred = ~std::size_t(0), int start = 0)
139 {
140 switch (start_ = start)
141 {
142 case 1: // Called after at least one async operation.
143 do
144 {
145 switch (want_ = op_(core_.engine_, ec_, bytes_transferred_))
146 {
147 case engine::want_input_and_retry:
148
149 // If the input buffer already has data in it we can pass it to the
150 // engine and then retry the operation immediately.
b32b8144 151 if (core_.input_.size() != 0)
7c673cae
FG
152 {
153 core_.input_ = core_.engine_.put_input(core_.input_);
154 continue;
155 }
156
157 // The engine wants more data to be read from input. However, we
158 // cannot allow more than one read operation at a time on the
159 // underlying transport. The pending_read_ timer's expiry is set to
160 // pos_infin if a read is in progress, and neg_infin otherwise.
b32b8144 161 if (core_.expiry(core_.pending_read_) == core_.neg_infin())
7c673cae
FG
162 {
163 // Prevent other read operations from being started.
164 core_.pending_read_.expires_at(core_.pos_infin());
165
166 // Start reading some data from the underlying transport.
167 next_layer_.async_read_some(
168 boost::asio::buffer(core_.input_buffer_),
169 BOOST_ASIO_MOVE_CAST(io_op)(*this));
170 }
171 else
172 {
173 // Wait until the current read operation completes.
174 core_.pending_read_.async_wait(BOOST_ASIO_MOVE_CAST(io_op)(*this));
175 }
176
177 // Yield control until asynchronous operation completes. Control
178 // resumes at the "default:" label below.
179 return;
180
181 case engine::want_output_and_retry:
182 case engine::want_output:
183
184 // The engine wants some data to be written to the output. However, we
185 // cannot allow more than one write operation at a time on the
186 // underlying transport. The pending_write_ timer's expiry is set to
187 // pos_infin if a write is in progress, and neg_infin otherwise.
b32b8144 188 if (core_.expiry(core_.pending_write_) == core_.neg_infin())
7c673cae
FG
189 {
190 // Prevent other write operations from being started.
191 core_.pending_write_.expires_at(core_.pos_infin());
192
193 // Start writing all the data to the underlying transport.
194 boost::asio::async_write(next_layer_,
195 core_.engine_.get_output(core_.output_buffer_),
196 BOOST_ASIO_MOVE_CAST(io_op)(*this));
197 }
198 else
199 {
200 // Wait until the current write operation completes.
201 core_.pending_write_.async_wait(BOOST_ASIO_MOVE_CAST(io_op)(*this));
202 }
203
204 // Yield control until asynchronous operation completes. Control
205 // resumes at the "default:" label below.
206 return;
207
208 default:
209
210 // The SSL operation is done and we can invoke the handler, but we
211 // have to keep in mind that this function might be being called from
212 // the async operation's initiating function. In this case we're not
213 // allowed to call the handler directly. Instead, issue a zero-sized
b32b8144 214 // read so the handler runs "as-if" posted using io_context::post().
7c673cae
FG
215 if (start)
216 {
217 next_layer_.async_read_some(
218 boost::asio::buffer(core_.input_buffer_, 0),
219 BOOST_ASIO_MOVE_CAST(io_op)(*this));
220
221 // Yield control until asynchronous operation completes. Control
222 // resumes at the "default:" label below.
223 return;
224 }
225 else
226 {
227 // Continue on to run handler directly.
228 break;
229 }
230 }
231
232 default:
233 if (bytes_transferred == ~std::size_t(0))
234 bytes_transferred = 0; // Timer cancellation, no data transferred.
235 else if (!ec_)
236 ec_ = ec;
237
238 switch (want_)
239 {
240 case engine::want_input_and_retry:
241
242 // Add received data to the engine's input.
243 core_.input_ = boost::asio::buffer(
244 core_.input_buffer_, bytes_transferred);
245 core_.input_ = core_.engine_.put_input(core_.input_);
246
247 // Release any waiting read operations.
248 core_.pending_read_.expires_at(core_.neg_infin());
249
250 // Try the operation again.
251 continue;
252
253 case engine::want_output_and_retry:
254
255 // Release any waiting write operations.
256 core_.pending_write_.expires_at(core_.neg_infin());
257
258 // Try the operation again.
259 continue;
260
261 case engine::want_output:
262
263 // Release any waiting write operations.
264 core_.pending_write_.expires_at(core_.neg_infin());
265
266 // Fall through to call handler.
267
268 default:
269
270 // Pass the result to the handler.
271 op_.call_handler(handler_,
272 core_.engine_.map_error_code(ec_),
273 ec_ ? 0 : bytes_transferred_);
274
275 // Our work here is done.
276 return;
277 }
278 } while (!ec_);
279
280 // Operation failed. Pass the result to the handler.
281 op_.call_handler(handler_, core_.engine_.map_error_code(ec_), 0);
282 }
283 }
284
285//private:
286 Stream& next_layer_;
287 stream_core& core_;
288 Operation op_;
289 int start_;
290 engine::want want_;
291 boost::system::error_code ec_;
292 std::size_t bytes_transferred_;
293 Handler handler_;
294};
295
b32b8144 296template <typename Stream, typename Operation, typename Handler>
7c673cae
FG
297inline void* asio_handler_allocate(std::size_t size,
298 io_op<Stream, Operation, Handler>* this_handler)
299{
300 return boost_asio_handler_alloc_helpers::allocate(
301 size, this_handler->handler_);
302}
303
304template <typename Stream, typename Operation, typename Handler>
305inline void asio_handler_deallocate(void* pointer, std::size_t size,
306 io_op<Stream, Operation, Handler>* this_handler)
307{
308 boost_asio_handler_alloc_helpers::deallocate(
309 pointer, size, this_handler->handler_);
310}
311
312template <typename Stream, typename Operation, typename Handler>
313inline bool asio_handler_is_continuation(
314 io_op<Stream, Operation, Handler>* this_handler)
315{
316 return this_handler->start_ == 0 ? true
317 : boost_asio_handler_cont_helpers::is_continuation(this_handler->handler_);
318}
319
320template <typename Function, typename Stream,
321 typename Operation, typename Handler>
322inline void asio_handler_invoke(Function& function,
323 io_op<Stream, Operation, Handler>* this_handler)
324{
325 boost_asio_handler_invoke_helpers::invoke(
326 function, this_handler->handler_);
327}
328
329template <typename Function, typename Stream,
330 typename Operation, typename Handler>
331inline void asio_handler_invoke(const Function& function,
332 io_op<Stream, Operation, Handler>* this_handler)
333{
334 boost_asio_handler_invoke_helpers::invoke(
335 function, this_handler->handler_);
336}
337
338template <typename Stream, typename Operation, typename Handler>
339inline void async_io(Stream& next_layer, stream_core& core,
340 const Operation& op, Handler& handler)
341{
342 io_op<Stream, Operation, Handler>(
343 next_layer, core, op, handler)(
344 boost::system::error_code(), 0, 1);
345}
346
7c673cae
FG
347} // namespace detail
348} // namespace ssl
b32b8144
FG
349
350template <typename Stream, typename Operation,
351 typename Handler, typename Allocator>
352struct associated_allocator<
353 ssl::detail::io_op<Stream, Operation, Handler>, Allocator>
354{
355 typedef typename associated_allocator<Handler, Allocator>::type type;
356
357 static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h,
358 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
359 {
360 return associated_allocator<Handler, Allocator>::get(h.handler_, a);
361 }
362};
363
364template <typename Stream, typename Operation,
365 typename Handler, typename Executor>
366struct associated_executor<
367 ssl::detail::io_op<Stream, Operation, Handler>, Executor>
368{
369 typedef typename associated_executor<Handler, Executor>::type type;
370
371 static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h,
372 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
373 {
374 return associated_executor<Handler, Executor>::get(h.handler_, ex);
375 }
376};
377
7c673cae
FG
378} // namespace asio
379} // namespace boost
380
381#include <boost/asio/detail/pop_options.hpp>
382
383#endif // BOOST_ASIO_SSL_DETAIL_IO_HPP