io.hpp 12 KB

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