2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 #include "snippets.hpp"
12 #include <boost/beast/_experimental/unit_test/suite.hpp>
13 #include <boost/beast/_experimental/test/stream.hpp>
14 #include <boost/beast/core/async_base.hpp>
15 #include <boost/beast/core/error.hpp>
16 #include <boost/beast/core/stream_traits.hpp>
17 #include <boost/beast/websocket.hpp>
25 core_4_layers_snippets()
27 #include "snippets.ipp"
29 //[code_core_4_layers_1
31 net::ssl::stream<net::ip::tcp::socket> ss(ioc, ctx);
36 //[code_core_4_layers_2
38 websocket::stream<net::ip::tcp::socket> ws(ioc);
42 //[code_core_4_layers_3
44 websocket::stream<net::ssl::stream<net::ip::tcp::socket>> ws(ioc, ctx);
49 //[code_core_4_layers_4
51 // Set non-blocking mode on a stack of stream
52 // layers with a regular socket at the lowest layer.
53 template <class Stream>
54 void set_non_blocking (Stream& stream)
57 // A compile error here means your lowest layer is not the right type!
58 get_lowest_layer(stream).non_blocking(true, ec);
60 throw system_error{ec};
65 //[code_core_4_layers_5
67 // A layered stream which counts the bytes read and bytes written on the next layer
68 template <class NextLayer>
71 NextLayer next_layer_; // Reads and writes are passed through to this
72 std::size_t bytes_read_ = 0; // Holds the total bytes read
73 std::size_t bytes_written_ = 0; // Holds the total bytes written
75 // This is the "initiation" object passed to async_initiate to start the operation
80 class MutableBufferSequence>
83 ReadHandler&& handler,
84 counted_stream* stream,
85 MutableBufferSequence const& buffers)
87 using handler_type = typename std::decay<ReadHandler>::type;
89 // async_base handles all of the composed operation boilerplate for us
90 using base = async_base<
91 handler_type, beast::executor_type<NextLayer>>;
93 // Our composed operation is implemented as a completion handler object
96 counted_stream& stream_;
98 op( counted_stream& stream,
99 handler_type&& handler,
100 MutableBufferSequence const& buffers)
101 : base(std::move(handler), stream.get_executor())
104 // Start the asynchronous operation
105 stream_.next_layer().async_read_some(buffers, std::move(*this));
108 void operator()(error_code ec, std::size_t bytes_transferred)
110 // Count the bytes transferred towards the total
111 stream_.bytes_read_ += bytes_transferred;
113 this->complete_now(ec, bytes_transferred);
117 op(*stream, std::forward<ReadHandler>(handler), buffers);
121 // This is the "initiation" object passed to async_initiate to start the operation
126 class ConstBufferSequence>
129 WriteHandler&& handler,
130 counted_stream* stream,
131 ConstBufferSequence const& buffers)
133 using handler_type = typename std::decay<WriteHandler>::type;
135 // async_base handles all of the composed operation boilerplate for us
136 using base = async_base<
137 handler_type, beast::executor_type<NextLayer>>;
139 // Our composed operation is implemented as a completion handler object
142 counted_stream& stream_;
144 op( counted_stream& stream,
145 handler_type&& handler,
146 ConstBufferSequence const& buffers)
147 : base(std::move(handler), stream.get_executor())
150 // Start the asynchronous operation
151 stream_.next_layer().async_write_some(buffers, std::move(*this));
154 void operator()(error_code ec, std::size_t bytes_transferred)
156 // Count the bytes transferred towards the total
157 stream_.bytes_written_ += bytes_transferred;
159 this->complete_now(ec, bytes_transferred);
163 op(*stream, std::forward<WriteHandler>(handler), buffers);
168 /// The type of executor used by this stream
169 using executor_type = beast::executor_type<NextLayer>;
172 template <class... Args>
174 counted_stream(Args&&... args)
175 : next_layer_(std::forward<Args>(args)...)
179 /// Returns an instance of the executor used to submit completion handlers
180 executor_type get_executor() noexcept
182 return next_layer_.get_executor();
185 /// Returns a reference to the next layer
186 NextLayer& next_layer() noexcept
191 /// Returns a reference to the next layer
192 NextLayer const& next_layer() const noexcept
197 /// Returns the total number of bytes read since the stream was constructed
198 std::size_t bytes_read() const noexcept
203 /// Returns the total number of bytes written since the stream was constructed
204 std::size_t bytes_written() const noexcept
206 return bytes_written_;
209 /// Read some data from the stream
210 template <class MutableBufferSequence>
211 std::size_t read_some(MutableBufferSequence const& buffers)
213 auto const bytes_transferred = next_layer_.read_some(buffers);
214 bytes_read_ += bytes_transferred;
215 return bytes_transferred;
218 /// Read some data from the stream
219 template <class MutableBufferSequence>
220 std::size_t read_some(MutableBufferSequence const& buffers, error_code& ec)
222 auto const bytes_transferred = next_layer_.read_some(buffers, ec);
223 bytes_read_ += bytes_transferred;
224 return bytes_transferred;
227 /// Write some data to the stream
228 template <class ConstBufferSequence>
229 std::size_t write_some(ConstBufferSequence const& buffers)
231 auto const bytes_transferred = next_layer_.write_some(buffers);
232 bytes_written_ += bytes_transferred;
233 return bytes_transferred;
236 /// Write some data to the stream
237 template <class ConstBufferSequence>
238 std::size_t write_some(ConstBufferSequence const& buffers, error_code& ec)
240 auto const bytes_transferred = next_layer_.write_some(buffers, ec);
241 bytes_written_ += bytes_transferred;
242 return bytes_transferred;
245 /// Read some data from the stream asynchronously
247 class MutableBufferSequence,
249 net::default_completion_token_t<executor_type>>
250 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
252 MutableBufferSequence const& buffers,
253 ReadHandler&& handler =
254 net::default_completion_token_t<executor_type>{})
256 return net::async_initiate<
258 void(error_code, std::size_t)>(
265 /// Write some data to the stream asynchronously
267 class ConstBufferSequence,
269 net::default_completion_token_t<executor_type>>
270 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
272 ConstBufferSequence const& buffers,
273 WriteHandler&& handler =
274 net::default_completion_token_t<
277 return net::async_initiate<
279 void(error_code, std::size_t)>(
288 template class counted_stream<test::stream>;
290 BOOST_STATIC_ASSERT(is_sync_read_stream<counted_stream<test::stream>>::value);
291 BOOST_STATIC_ASSERT(is_sync_write_stream<counted_stream<test::stream>>::value);
292 BOOST_STATIC_ASSERT(is_async_read_stream<counted_stream<test::stream>>::value);
293 BOOST_STATIC_ASSERT(is_async_write_stream<counted_stream<test::stream>>::value);
295 struct core_4_layers_test
296 : public beast::unit_test::suite
300 void operator()(error_code, std::size_t)
308 BEAST_EXPECT(&core_4_layers_snippets);
309 BEAST_EXPECT(&set_non_blocking<net::ip::tcp::socket>);
313 BEAST_DEFINE_TESTSUITE(beast,doc,core_4_layers);