annotate DEPENDENCIES/generic/include/boost/asio/ssl/detail/io.hpp @ 133:4acb5d8d80b6 tip

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