io.hpp 13 KB

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