io.hpp 10 KB

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