io.hpp 11 KB

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