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
10 #include "snippets.hpp"
11
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>
18 #include <cstdlib>
19 #include <utility>
20
21 namespace boost {
22 namespace beast {
23
24 void
core_4_layers_snippets()25 core_4_layers_snippets()
26 {
27 #include "snippets.ipp"
28 {
29 //[code_core_4_layers_1
30
31 net::ssl::stream<net::ip::tcp::socket> ss(ioc, ctx);
32
33 //]
34 }
35 {
36 //[code_core_4_layers_2
37
38 websocket::stream<net::ip::tcp::socket> ws(ioc);
39
40 //]
41 }
42 //[code_core_4_layers_3
43
44 websocket::stream<net::ssl::stream<net::ip::tcp::socket>> ws(ioc, ctx);
45
46 //]
47 }
48
49 //[code_core_4_layers_4
50
51 // Set non-blocking mode on a stack of stream
52 // layers with a regular socket at the lowest layer.
53 template <class Stream>
set_non_blocking(Stream & stream)54 void set_non_blocking (Stream& stream)
55 {
56 error_code ec;
57 // A compile error here means your lowest layer is not the right type!
58 get_lowest_layer(stream).non_blocking(true, ec);
59 if(ec)
60 throw system_error{ec};
61 }
62
63 //]
64
65 //[code_core_4_layers_5
66
67 // A layered stream which counts the bytes read and bytes written on the next layer
68 template <class NextLayer>
69 class counted_stream
70 {
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
74
75 // This is the "initiation" object passed to async_initiate to start the operation
76 struct run_read_op
77 {
78 template<
79 class ReadHandler,
80 class MutableBufferSequence>
81 void
operator ()boost::beast::counted_stream::run_read_op82 operator()(
83 ReadHandler&& handler,
84 counted_stream* stream,
85 MutableBufferSequence const& buffers)
86 {
87 using handler_type = typename std::decay<ReadHandler>::type;
88
89 // async_base handles all of the composed operation boilerplate for us
90 using base = async_base<
91 handler_type, beast::executor_type<NextLayer>>;
92
93 // Our composed operation is implemented as a completion handler object
94 struct op : base
95 {
96 counted_stream& stream_;
97
98 op( counted_stream& stream,
99 handler_type&& handler,
100 MutableBufferSequence const& buffers)
101 : base(std::move(handler), stream.get_executor())
102 , stream_(stream)
103 {
104 // Start the asynchronous operation
105 stream_.next_layer().async_read_some(buffers, std::move(*this));
106 }
107
108 void operator()(error_code ec, std::size_t bytes_transferred)
109 {
110 // Count the bytes transferred towards the total
111 stream_.bytes_read_ += bytes_transferred;
112
113 this->complete_now(ec, bytes_transferred);
114 }
115 };
116
117 op(*stream, std::forward<ReadHandler>(handler), buffers);
118 }
119 };
120
121 // This is the "initiation" object passed to async_initiate to start the operation
122 struct run_write_op
123 {
124 template<
125 class WriteHandler,
126 class ConstBufferSequence>
127 void
operator ()boost::beast::counted_stream::run_write_op128 operator()(
129 WriteHandler&& handler,
130 counted_stream* stream,
131 ConstBufferSequence const& buffers)
132 {
133 using handler_type = typename std::decay<WriteHandler>::type;
134
135 // async_base handles all of the composed operation boilerplate for us
136 using base = async_base<
137 handler_type, beast::executor_type<NextLayer>>;
138
139 // Our composed operation is implemented as a completion handler object
140 struct op : base
141 {
142 counted_stream& stream_;
143
144 op( counted_stream& stream,
145 handler_type&& handler,
146 ConstBufferSequence const& buffers)
147 : base(std::move(handler), stream.get_executor())
148 , stream_(stream)
149 {
150 // Start the asynchronous operation
151 stream_.next_layer().async_write_some(buffers, std::move(*this));
152 }
153
154 void operator()(error_code ec, std::size_t bytes_transferred)
155 {
156 // Count the bytes transferred towards the total
157 stream_.bytes_written_ += bytes_transferred;
158
159 this->complete_now(ec, bytes_transferred);
160 }
161 };
162
163 op(*stream, std::forward<WriteHandler>(handler), buffers);
164 }
165 };
166
167 public:
168 /// The type of executor used by this stream
169 using executor_type = beast::executor_type<NextLayer>;
170
171 /// Constructor
172 template <class... Args>
173 explicit
counted_stream(Args &&...args)174 counted_stream(Args&&... args)
175 : next_layer_(std::forward<Args>(args)...)
176 {
177 }
178
179 /// Returns an instance of the executor used to submit completion handlers
get_executor()180 executor_type get_executor() noexcept
181 {
182 return next_layer_.get_executor();
183 }
184
185 /// Returns a reference to the next layer
next_layer()186 NextLayer& next_layer() noexcept
187 {
188 return next_layer_;
189 }
190
191 /// Returns a reference to the next layer
next_layer() const192 NextLayer const& next_layer() const noexcept
193 {
194 return next_layer_;
195 }
196
197 /// Returns the total number of bytes read since the stream was constructed
bytes_read() const198 std::size_t bytes_read() const noexcept
199 {
200 return bytes_read_;
201 }
202
203 /// Returns the total number of bytes written since the stream was constructed
bytes_written() const204 std::size_t bytes_written() const noexcept
205 {
206 return bytes_written_;
207 }
208
209 /// Read some data from the stream
210 template <class MutableBufferSequence>
read_some(MutableBufferSequence const & buffers)211 std::size_t read_some(MutableBufferSequence const& buffers)
212 {
213 auto const bytes_transferred = next_layer_.read_some(buffers);
214 bytes_read_ += bytes_transferred;
215 return bytes_transferred;
216 }
217
218 /// Read some data from the stream
219 template <class MutableBufferSequence>
read_some(MutableBufferSequence const & buffers,error_code & ec)220 std::size_t read_some(MutableBufferSequence const& buffers, error_code& ec)
221 {
222 auto const bytes_transferred = next_layer_.read_some(buffers, ec);
223 bytes_read_ += bytes_transferred;
224 return bytes_transferred;
225 }
226
227 /// Write some data to the stream
228 template <class ConstBufferSequence>
write_some(ConstBufferSequence const & buffers)229 std::size_t write_some(ConstBufferSequence const& buffers)
230 {
231 auto const bytes_transferred = next_layer_.write_some(buffers);
232 bytes_written_ += bytes_transferred;
233 return bytes_transferred;
234 }
235
236 /// Write some data to the stream
237 template <class ConstBufferSequence>
write_some(ConstBufferSequence const & buffers,error_code & ec)238 std::size_t write_some(ConstBufferSequence const& buffers, error_code& ec)
239 {
240 auto const bytes_transferred = next_layer_.write_some(buffers, ec);
241 bytes_written_ += bytes_transferred;
242 return bytes_transferred;
243 }
244
245 /// Read some data from the stream asynchronously
246 template<
247 class MutableBufferSequence,
248 class ReadHandler =
249 net::default_completion_token_t<executor_type>>
250 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
async_read_some(MutableBufferSequence const & buffers,ReadHandler && handler=net::default_completion_token_t<executor_type>{})251 async_read_some(
252 MutableBufferSequence const& buffers,
253 ReadHandler&& handler =
254 net::default_completion_token_t<executor_type>{})
255 {
256 return net::async_initiate<
257 ReadHandler,
258 void(error_code, std::size_t)>(
259 run_read_op{},
260 handler,
261 this,
262 buffers);
263 }
264
265 /// Write some data to the stream asynchronously
266 template<
267 class ConstBufferSequence,
268 class WriteHandler =
269 net::default_completion_token_t<executor_type>>
270 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
async_write_some(ConstBufferSequence const & buffers,WriteHandler && handler=net::default_completion_token_t<executor_type>{})271 async_write_some(
272 ConstBufferSequence const& buffers,
273 WriteHandler&& handler =
274 net::default_completion_token_t<
275 executor_type>{})
276 {
277 return net::async_initiate<
278 WriteHandler,
279 void(error_code, std::size_t)>(
280 run_write_op{},
281 handler,
282 this,
283 buffers);
284 }
285 };
286 //]
287
288 template class counted_stream<test::stream>;
289
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);
294
295 struct core_4_layers_test
296 : public beast::unit_test::suite
297 {
298 struct handler
299 {
operator ()boost::beast::core_4_layers_test::handler300 void operator()(error_code, std::size_t)
301 {
302 }
303 };
304
305 void
runboost::beast::core_4_layers_test306 run() override
307 {
308 BEAST_EXPECT(&core_4_layers_snippets);
309 BEAST_EXPECT(&set_non_blocking<net::ip::tcp::socket>);
310 }
311 };
312
313 BEAST_DEFINE_TESTSUITE(beast,doc,core_4_layers);
314
315 } // beast
316 } // boost
317