• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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