io.hpp 11 KB

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