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.

382 lines
11KB

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