io.hpp 11 KB

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