core_4_layers.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #include "snippets.hpp"
  10. #include <boost/beast/_experimental/unit_test/suite.hpp>
  11. #include <boost/beast/_experimental/test/stream.hpp>
  12. #include <boost/beast/core/async_base.hpp>
  13. #include <boost/beast/core/error.hpp>
  14. #include <boost/beast/core/stream_traits.hpp>
  15. #include <boost/beast/websocket.hpp>
  16. #include <cstdlib>
  17. #include <utility>
  18. namespace boost {
  19. namespace beast {
  20. void
  21. core_4_layers_snippets()
  22. {
  23. #include "snippets.ipp"
  24. {
  25. //[code_core_4_layers_1
  26. net::ssl::stream<net::ip::tcp::socket> ss(ioc, ctx);
  27. //]
  28. }
  29. {
  30. //[code_core_4_layers_2
  31. websocket::stream<net::ip::tcp::socket> ws(ioc);
  32. //]
  33. }
  34. //[code_core_4_layers_3
  35. websocket::stream<net::ssl::stream<net::ip::tcp::socket>> ws(ioc, ctx);
  36. //]
  37. }
  38. //[code_core_4_layers_4
  39. // Set non-blocking mode on a stack of stream
  40. // layers with a regular socket at the lowest layer.
  41. template <class Stream>
  42. void set_non_blocking (Stream& stream)
  43. {
  44. error_code ec;
  45. // A compile error here means your lowest layer is not the right type!
  46. get_lowest_layer(stream).non_blocking(true, ec);
  47. if(ec)
  48. throw system_error{ec};
  49. }
  50. //]
  51. //[code_core_4_layers_5
  52. // A layered stream which counts the bytes read and bytes written on the next layer
  53. template <class NextLayer>
  54. class counted_stream
  55. {
  56. NextLayer next_layer_; // Reads and writes are passed through to this
  57. std::size_t bytes_read_ = 0; // Holds the total bytes read
  58. std::size_t bytes_written_ = 0; // Holds the total bytes written
  59. // This is the "initiation" object passed to async_initiate to start the operation
  60. struct run_read_op
  61. {
  62. template<
  63. class ReadHandler,
  64. class MutableBufferSequence>
  65. void
  66. operator()(
  67. ReadHandler&& handler,
  68. counted_stream* stream,
  69. MutableBufferSequence const& buffers)
  70. {
  71. using handler_type = typename std::decay<ReadHandler>::type;
  72. // async_base handles all of the composed operation boilerplate for us
  73. using base = async_base<
  74. handler_type, beast::executor_type<NextLayer>>;
  75. // Our composed operation is implemented as a completion handler object
  76. struct op : base
  77. {
  78. counted_stream& stream_;
  79. op( counted_stream& stream,
  80. handler_type&& handler,
  81. MutableBufferSequence const& buffers)
  82. : base(std::move(handler), stream.get_executor())
  83. , stream_(stream)
  84. {
  85. // Start the asynchronous operation
  86. stream_.next_layer().async_read_some(buffers, std::move(*this));
  87. }
  88. void operator()(error_code ec, std::size_t bytes_transferred)
  89. {
  90. // Count the bytes transferred towards the total
  91. stream_.bytes_read_ += bytes_transferred;
  92. this->complete_now(ec, bytes_transferred);
  93. }
  94. };
  95. op(*stream, std::forward<ReadHandler>(handler), buffers);
  96. }
  97. };
  98. // This is the "initiation" object passed to async_initiate to start the operation
  99. struct run_write_op
  100. {
  101. template<
  102. class WriteHandler,
  103. class ConstBufferSequence>
  104. void
  105. operator()(
  106. WriteHandler&& handler,
  107. counted_stream* stream,
  108. ConstBufferSequence const& buffers)
  109. {
  110. using handler_type = typename std::decay<WriteHandler>::type;
  111. // async_base handles all of the composed operation boilerplate for us
  112. using base = async_base<
  113. handler_type, beast::executor_type<NextLayer>>;
  114. // Our composed operation is implemented as a completion handler object
  115. struct op : base
  116. {
  117. counted_stream& stream_;
  118. op( counted_stream& stream,
  119. handler_type&& handler,
  120. ConstBufferSequence const& buffers)
  121. : base(std::move(handler), stream.get_executor())
  122. , stream_(stream)
  123. {
  124. // Start the asynchronous operation
  125. stream_.next_layer().async_write_some(buffers, std::move(*this));
  126. }
  127. void operator()(error_code ec, std::size_t bytes_transferred)
  128. {
  129. // Count the bytes transferred towards the total
  130. stream_.bytes_written_ += bytes_transferred;
  131. this->complete_now(ec, bytes_transferred);
  132. }
  133. };
  134. op(*stream, std::forward<WriteHandler>(handler), buffers);
  135. }
  136. };
  137. public:
  138. /// The type of executor used by this stream
  139. using executor_type = beast::executor_type<NextLayer>;
  140. /// Constructor
  141. template <class... Args>
  142. explicit
  143. counted_stream(Args&&... args)
  144. : next_layer_(std::forward<Args>(args)...)
  145. {
  146. }
  147. /// Returns an instance of the executor used to submit completion handlers
  148. executor_type get_executor() noexcept
  149. {
  150. return next_layer_.get_executor();
  151. }
  152. /// Returns a reference to the next layer
  153. NextLayer& next_layer() noexcept
  154. {
  155. return next_layer_;
  156. }
  157. /// Returns a reference to the next layer
  158. NextLayer const& next_layer() const noexcept
  159. {
  160. return next_layer_;
  161. }
  162. /// Returns the total number of bytes read since the stream was constructed
  163. std::size_t bytes_read() const noexcept
  164. {
  165. return bytes_read_;
  166. }
  167. /// Returns the total number of bytes written since the stream was constructed
  168. std::size_t bytes_written() const noexcept
  169. {
  170. return bytes_written_;
  171. }
  172. /// Read some data from the stream
  173. template <class MutableBufferSequence>
  174. std::size_t read_some(MutableBufferSequence const& buffers)
  175. {
  176. auto const bytes_transferred = next_layer_.read_some(buffers);
  177. bytes_read_ += bytes_transferred;
  178. return bytes_transferred;
  179. }
  180. /// Read some data from the stream
  181. template <class MutableBufferSequence>
  182. std::size_t read_some(MutableBufferSequence const& buffers, error_code& ec)
  183. {
  184. auto const bytes_transferred = next_layer_.read_some(buffers, ec);
  185. bytes_read_ += bytes_transferred;
  186. return bytes_transferred;
  187. }
  188. /// Write some data to the stream
  189. template <class ConstBufferSequence>
  190. std::size_t write_some(ConstBufferSequence const& buffers)
  191. {
  192. auto const bytes_transferred = next_layer_.write_some(buffers);
  193. bytes_written_ += bytes_transferred;
  194. return bytes_transferred;
  195. }
  196. /// Write some data to the stream
  197. template <class ConstBufferSequence>
  198. std::size_t write_some(ConstBufferSequence const& buffers, error_code& ec)
  199. {
  200. auto const bytes_transferred = next_layer_.write_some(buffers, ec);
  201. bytes_written_ += bytes_transferred;
  202. return bytes_transferred;
  203. }
  204. /// Read some data from the stream asynchronously
  205. template<
  206. class MutableBufferSequence,
  207. class ReadHandler =
  208. net::default_completion_token_t<executor_type>>
  209. BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
  210. async_read_some(
  211. MutableBufferSequence const& buffers,
  212. ReadHandler&& handler =
  213. net::default_completion_token_t<executor_type>{})
  214. {
  215. return net::async_initiate<
  216. ReadHandler,
  217. void(error_code, std::size_t)>(
  218. run_read_op{},
  219. handler,
  220. this,
  221. buffers);
  222. }
  223. /// Write some data to the stream asynchronously
  224. template<
  225. class ConstBufferSequence,
  226. class WriteHandler =
  227. net::default_completion_token_t<executor_type>>
  228. BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
  229. async_write_some(
  230. ConstBufferSequence const& buffers,
  231. WriteHandler&& handler =
  232. net::default_completion_token_t<
  233. executor_type>{})
  234. {
  235. return net::async_initiate<
  236. WriteHandler,
  237. void(error_code, std::size_t)>(
  238. run_write_op{},
  239. handler,
  240. this,
  241. buffers);
  242. }
  243. };
  244. //]
  245. template class counted_stream<test::stream>;
  246. BOOST_STATIC_ASSERT(is_sync_read_stream<counted_stream<test::stream>>::value);
  247. BOOST_STATIC_ASSERT(is_sync_write_stream<counted_stream<test::stream>>::value);
  248. BOOST_STATIC_ASSERT(is_async_read_stream<counted_stream<test::stream>>::value);
  249. BOOST_STATIC_ASSERT(is_async_write_stream<counted_stream<test::stream>>::value);
  250. struct core_4_layers_test
  251. : public beast::unit_test::suite
  252. {
  253. struct handler
  254. {
  255. void operator()(error_code, std::size_t)
  256. {
  257. }
  258. };
  259. void
  260. run() override
  261. {
  262. BEAST_EXPECT(&core_4_layers_snippets);
  263. BEAST_EXPECT(&set_non_blocking<net::ip::tcp::socket>);
  264. }
  265. };
  266. BEAST_DEFINE_TESTSUITE(beast,doc,core_4_layers);
  267. } // beast
  268. } // boost