Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

io.hpp 11KB

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