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