Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / beast / _experimental / test / stream.hpp
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 #ifndef BOOST_BEAST_TEST_STREAM_HPP
11 #define BOOST_BEAST_TEST_STREAM_HPP
12
13 #include <boost/beast/core/detail/config.hpp>
14 #include <boost/beast/core/bind_handler.hpp>
15 #include <boost/beast/core/flat_buffer.hpp>
16 #include <boost/beast/core/role.hpp>
17 #include <boost/beast/core/string.hpp>
18 #include <boost/beast/_experimental/test/fail_count.hpp>
19 #include <boost/asio/async_result.hpp>
20 #include <boost/asio/buffer.hpp>
21 #include <boost/asio/error.hpp>
22 #include <boost/asio/executor_work_guard.hpp>
23 #include <boost/asio/io_context.hpp>
24 #include <boost/asio/post.hpp>
25 #include <boost/assert.hpp>
26 #include <boost/shared_ptr.hpp>
27 #include <boost/weak_ptr.hpp>
28 #include <boost/throw_exception.hpp>
29 #include <condition_variable>
30 #include <limits>
31 #include <memory>
32 #include <mutex>
33 #include <utility>
34
35 #if ! BOOST_BEAST_DOXYGEN
36 namespace boost {
37 namespace asio {
38 namespace ssl {
39 template<typename> class stream;
40 } // ssl
41 } // asio
42 } // boost
43 #endif
44
45 namespace boost {
46 namespace beast {
47 namespace test {
48
49 /** A two-way socket useful for unit testing
50
51     An instance of this class simulates a traditional socket,
52     while also providing features useful for unit testing.
53     Each endpoint maintains an independent buffer called
54     the input area. Writes from one endpoint append data
55     to the peer's pending input area. When an endpoint performs
56     a read and data is present in the input area, the data is
57     delivered to the blocking or asynchronous operation. Otherwise
58     the operation is blocked or deferred until data is made
59     available, or until the endpoints become disconnected.
60
61     These streams may be used anywhere an algorithm accepts a
62     reference to a synchronous or asynchronous read or write
63     stream. It is possible to use a test stream in a call to
64     `net::read_until`, or in a call to
65     @ref boost::beast::http::async_write for example.
66
67     As with Boost.Asio I/O objects, a @ref stream constructs
68     with a reference to the `net::io_context` to use for
69     handling asynchronous I/O. For asynchronous operations, the
70     stream follows the same rules as a traditional asio socket
71     with respect to how completion handlers for asynchronous
72     operations are performed.
73
74     To facilitate testing, these streams support some additional
75     features:
76
77     @li The input area, represented by a @ref beast::basic_flat_buffer,
78     may be directly accessed by the caller to inspect the contents
79     before or after the remote endpoint writes data. This allows
80     a unit test to verify that the received data matches.
81
82     @li Data may be manually appended to the input area. This data
83     will delivered in the next call to
84     @ref stream::read_some or @ref stream::async_read_some.
85     This allows predefined test vectors to be set up for testing
86     read algorithms.
87
88     @li The stream may be constructed with a fail count. The
89     stream will eventually fail with a predefined error after a
90     certain number of operations, where the number of operations
91     is controlled by the test. When a test loops over a range of
92     operation counts, it is possible to exercise every possible
93     point of failure in the algorithm being tested. When used
94     correctly the technique allows the tests to reach a high
95     percentage of code coverage.
96
97     @par Thread Safety
98         @e Distinct @e objects: Safe.@n
99         @e Shared @e objects: Unsafe.
100         The application must also ensure that all asynchronous
101         operations are performed within the same implicit or explicit strand.
102
103     @par Concepts
104         @li <em>SyncReadStream</em>
105         @li <em>SyncWriteStream</em>
106         @li <em>AsyncReadStream</em>
107         @li <em>AsyncWriteStream</em>
108 */
109 class stream
110 {
111     struct state;
112
113     boost::shared_ptr<state> in_;
114     boost::weak_ptr<state> out_;
115
116     enum class status
117     {
118         ok,
119         eof,
120     };
121
122     class service;
123     struct service_impl;
124
125     struct read_op_base
126     {
127         virtual ~read_op_base() = default;
128         virtual void operator()(error_code ec) = 0;
129     };
130
131     struct state
132     {
133         friend class stream;
134
135         net::io_context& ioc;
136         boost::weak_ptr<service_impl> wp;
137         std::mutex m;
138         flat_buffer b;
139         std::condition_variable cv;
140         std::unique_ptr<read_op_base> op;
141         status code = status::ok;
142         fail_count* fc = nullptr;
143         std::size_t nread = 0;
144         std::size_t nread_bytes = 0;
145         std::size_t nwrite = 0;
146         std::size_t nwrite_bytes = 0;
147         std::size_t read_max =
148             (std::numeric_limits<std::size_t>::max)();
149         std::size_t write_max =
150             (std::numeric_limits<std::size_t>::max)();
151
152         BOOST_BEAST_DECL
153         state(
154             net::io_context& ioc_,
155             boost::weak_ptr<service_impl> wp_,
156             fail_count* fc_);
157
158
159         BOOST_BEAST_DECL
160         ~state();
161
162         BOOST_BEAST_DECL
163         void
164         remove() noexcept;
165
166         BOOST_BEAST_DECL
167         void
168         notify_read();
169
170         BOOST_BEAST_DECL
171         void
172         cancel_read();
173     };
174
175     template<class Handler, class Buffers>
176     class read_op;
177
178     struct run_read_op;
179     struct run_write_op;
180
181     BOOST_BEAST_DECL
182     static
183     void
184     initiate_read(
185         boost::shared_ptr<state> const& in,
186         std::unique_ptr<read_op_base>&& op,
187         std::size_t buf_size);
188
189 #if ! BOOST_BEAST_DOXYGEN
190     // boost::asio::ssl::stream needs these
191     // DEPRECATED
192     template<class>
193     friend class boost::asio::ssl::stream;
194     // DEPRECATED
195     using lowest_layer_type = stream;
196     // DEPRECATED
197     lowest_layer_type&
198     lowest_layer() noexcept
199     {
200         return *this;
201     }
202     // DEPRECATED
203     lowest_layer_type const&
204     lowest_layer() const noexcept
205     {
206         return *this;
207     }
208 #endif
209
210 public:
211     using buffer_type = flat_buffer;
212
213     /** Destructor
214
215         If an asynchronous read operation is pending, it will
216         simply be discarded with no notification to the completion
217         handler.
218
219         If a connection is established while the stream is destroyed,
220         the peer will see the error `net::error::connection_reset`
221         when performing any reads or writes.
222     */
223     BOOST_BEAST_DECL
224     ~stream();
225
226     /** Move Constructor
227
228         Moving the stream while asynchronous operations are pending
229         results in undefined behavior.
230     */
231     BOOST_BEAST_DECL
232     stream(stream&& other);
233
234     /** Move Assignment
235
236         Moving the stream while asynchronous operations are pending
237         results in undefined behavior.
238     */
239     BOOST_BEAST_DECL
240     stream&
241     operator=(stream&& other);
242
243     /** Construct a stream
244
245         The stream will be created in a disconnected state.
246
247         @param ioc The `io_context` object that the stream will use to
248         dispatch handlers for any asynchronous operations.
249     */
250     BOOST_BEAST_DECL
251     explicit
252     stream(net::io_context& ioc);
253
254     /** Construct a stream
255
256         The stream will be created in a disconnected state.
257
258         @param ioc The `io_context` object that the stream will use to
259         dispatch handlers for any asynchronous operations.
260
261         @param fc The @ref fail_count to associate with the stream.
262         Each I/O operation performed on the stream will increment the
263         fail count.  When the fail count reaches its internal limit,
264         a simulated failure error will be raised.
265     */
266     BOOST_BEAST_DECL
267     stream(
268         net::io_context& ioc,
269         fail_count& fc);
270
271     /** Construct a stream
272
273         The stream will be created in a disconnected state.
274
275         @param ioc The `io_context` object that the stream will use to
276         dispatch handlers for any asynchronous operations.
277
278         @param s A string which will be appended to the input area, not
279         including the null terminator.
280     */
281     BOOST_BEAST_DECL
282     stream(
283         net::io_context& ioc,
284         string_view s);
285
286     /** Construct a stream
287
288         The stream will be created in a disconnected state.
289
290         @param ioc The `io_context` object that the stream will use to
291         dispatch handlers for any asynchronous operations.
292
293         @param fc The @ref fail_count to associate with the stream.
294         Each I/O operation performed on the stream will increment the
295         fail count.  When the fail count reaches its internal limit,
296         a simulated failure error will be raised.
297
298         @param s A string which will be appended to the input area, not
299         including the null terminator.
300     */
301     BOOST_BEAST_DECL
302     stream(
303         net::io_context& ioc,
304         fail_count& fc,
305         string_view s);
306
307     /// Establish a connection
308     BOOST_BEAST_DECL
309     void
310     connect(stream& remote);
311
312     /// The type of the executor associated with the object.
313     using executor_type =
314         net::io_context::executor_type;
315
316     /// Return the executor associated with the object.
317     executor_type
318     get_executor() noexcept
319     {
320         return in_->ioc.get_executor();
321     };
322
323     /// Set the maximum number of bytes returned by read_some
324     void
325     read_size(std::size_t n) noexcept
326     {
327         in_->read_max = n;
328     }
329
330     /// Set the maximum number of bytes returned by write_some
331     void
332     write_size(std::size_t n) noexcept
333     {
334         in_->write_max = n;
335     }
336
337     /// Direct input buffer access
338     buffer_type&
339     buffer() noexcept
340     {
341         return in_->b;
342     }
343
344     /// Returns a string view representing the pending input data
345     BOOST_BEAST_DECL
346     string_view
347     str() const;
348
349     /// Appends a string to the pending input data
350     BOOST_BEAST_DECL
351     void
352     append(string_view s);
353
354     /// Clear the pending input area
355     BOOST_BEAST_DECL
356     void
357     clear();
358
359     /// Return the number of reads
360     std::size_t
361     nread() const noexcept
362     {
363         return in_->nread;
364     }
365
366     /// Return the number of bytes read
367     std::size_t
368     nread_bytes() const noexcept
369     {
370         return in_->nread_bytes;
371     }
372
373     /// Return the number of writes
374     std::size_t
375     nwrite() const noexcept
376     {
377         return in_->nwrite;
378     }
379
380     /// Return the number of bytes written
381     std::size_t
382     nwrite_bytes() const noexcept
383     {
384         return in_->nwrite_bytes;
385     }
386
387     /** Close the stream.
388
389         The other end of the connection will see
390         `error::eof` after reading all the remaining data.
391     */
392     BOOST_BEAST_DECL
393     void
394     close();
395
396     /** Close the other end of the stream.
397
398         This end of the connection will see
399         `error::eof` after reading all the remaining data.
400     */
401     BOOST_BEAST_DECL
402     void
403     close_remote();
404
405     /** Read some data from the stream.
406
407         This function is used to read data from the stream. The function call will
408         block until one or more bytes of data has been read successfully, or until
409         an error occurs.
410
411         @param buffers The buffers into which the data will be read.
412
413         @returns The number of bytes read.
414
415         @throws boost::system::system_error Thrown on failure.
416
417         @note The `read_some` operation may not read all of the requested number of
418         bytes. Consider using the function `net::read` if you need to ensure
419         that the requested amount of data is read before the blocking operation
420         completes.
421     */
422     template<class MutableBufferSequence>
423     std::size_t
424     read_some(MutableBufferSequence const& buffers);
425
426     /** Read some data from the stream.
427
428         This function is used to read data from the stream. The function call will
429         block until one or more bytes of data has been read successfully, or until
430         an error occurs.
431
432         @param buffers The buffers into which the data will be read.
433
434         @param ec Set to indicate what error occurred, if any.
435
436         @returns The number of bytes read.
437
438         @note The `read_some` operation may not read all of the requested number of
439         bytes. Consider using the function `net::read` if you need to ensure
440         that the requested amount of data is read before the blocking operation
441         completes.
442     */
443     template<class MutableBufferSequence>
444     std::size_t
445     read_some(MutableBufferSequence const& buffers,
446         error_code& ec);
447
448     /** Start an asynchronous read.
449
450         This function is used to asynchronously read one or more bytes of data from
451         the stream. The function call always returns immediately.
452
453         @param buffers The buffers into which the data will be read. Although the
454         buffers object may be copied as necessary, ownership of the underlying
455         buffers is retained by the caller, which must guarantee that they remain
456         valid until the handler is called.
457
458         @param handler The completion handler to invoke when the operation
459         completes. The implementation takes ownership of the handler by
460         performing a decay-copy. The equivalent function signature of
461         the handler must be:
462         @code
463         void handler(
464             error_code const& ec,           // Result of operation.
465             std::size_t bytes_transferred   // Number of bytes read.
466         );
467         @endcode
468         Regardless of whether the asynchronous operation completes
469         immediately or not, the handler will not be invoked from within
470         this function. Invocation of the handler will be performed in a
471         manner equivalent to using `net::post`.
472
473         @note The `async_read_some` operation may not read all of the requested number of
474         bytes. Consider using the function `net::async_read` if you need
475         to ensure that the requested amount of data is read before the asynchronous
476         operation completes.
477     */
478     template<
479         class MutableBufferSequence,
480         BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
481     BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
482     async_read_some(
483         MutableBufferSequence const& buffers,
484         ReadHandler&& handler);
485
486     /** Write some data to the stream.
487
488         This function is used to write data on the stream. The function call will
489         block until one or more bytes of data has been written successfully, or
490         until an error occurs.
491
492         @param buffers The data to be written.
493
494         @returns The number of bytes written.
495
496         @throws boost::system::system_error Thrown on failure.
497
498         @note The `write_some` operation may not transmit all of the data to the
499         peer. Consider using the function `net::write` if you need to
500         ensure that all data is written before the blocking operation completes.
501     */
502     template<class ConstBufferSequence>
503     std::size_t
504     write_some(ConstBufferSequence const& buffers);
505
506     /** Write some data to the stream.
507
508         This function is used to write data on the stream. The function call will
509         block until one or more bytes of data has been written successfully, or
510         until an error occurs.
511
512         @param buffers The data to be written.
513
514         @param ec Set to indicate what error occurred, if any.
515
516         @returns The number of bytes written.
517
518         @note The `write_some` operation may not transmit all of the data to the
519         peer. Consider using the function `net::write` if you need to
520         ensure that all data is written before the blocking operation completes.
521     */
522     template<class ConstBufferSequence>
523     std::size_t
524     write_some(
525         ConstBufferSequence const& buffers, error_code& ec);
526
527     /** Start an asynchronous write.
528
529         This function is used to asynchronously write one or more bytes of data to
530         the stream. The function call always returns immediately.
531
532         @param buffers The data to be written to the stream. Although the buffers
533         object may be copied as necessary, ownership of the underlying buffers is
534         retained by the caller, which must guarantee that they remain valid until
535         the handler is called.
536
537         @param handler The completion handler to invoke when the operation
538         completes. The implementation takes ownership of the handler by
539         performing a decay-copy. The equivalent function signature of
540         the handler must be:
541         @code
542         void handler(
543             error_code const& ec,           // Result of operation.
544             std::size_t bytes_transferred   // Number of bytes written.
545         );
546         @endcode
547         Regardless of whether the asynchronous operation completes
548         immediately or not, the handler will not be invoked from within
549         this function. Invocation of the handler will be performed in a
550         manner equivalent to using `net::post`.
551
552         @note The `async_write_some` operation may not transmit all of the data to
553         the peer. Consider using the function `net::async_write` if you need
554         to ensure that all data is written before the asynchronous operation completes.
555     */
556     template<
557         class ConstBufferSequence,
558         BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
559     BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
560     async_write_some(
561         ConstBufferSequence const& buffers,
562         WriteHandler&& handler);
563
564 #if ! BOOST_BEAST_DOXYGEN
565     friend
566     BOOST_BEAST_DECL
567     void
568     teardown(
569         role_type,
570         stream& s,
571         boost::system::error_code& ec);
572
573     template<class TeardownHandler>
574     friend
575     BOOST_BEAST_DECL
576     void
577     async_teardown(
578         role_type role,
579         stream& s,
580         TeardownHandler&& handler);
581 #endif
582 };
583
584 #if ! BOOST_BEAST_DOXYGEN
585 inline
586 void
587 beast_close_socket(stream& s)
588 {
589     s.close();
590 }
591 #endif
592
593 #if BOOST_BEAST_DOXYGEN
594 /** Return a new stream connected to the given stream
595
596     @param to The stream to connect to.
597
598     @param args Optional arguments forwarded to the new stream's constructor.
599
600     @return The new, connected stream.
601 */
602 template<class... Args>
603 stream
604 connect(stream& to, Args&&... args);
605
606 #else
607 BOOST_BEAST_DECL
608 stream
609 connect(stream& to);
610
611 BOOST_BEAST_DECL
612 void
613 connect(stream& s1, stream& s2);
614
615 template<class Arg1, class... ArgN>
616 stream
617 connect(stream& to, Arg1&& arg1, ArgN&&... argn);
618 #endif
619
620 } // test
621 } // beast
622 } // boost
623
624 #include <boost/beast/_experimental/test/impl/stream.hpp>
625 #ifdef BOOST_BEAST_HEADER_ONLY
626 #include <boost/beast/_experimental/test/impl/stream.ipp>
627 #endif
628
629 #endif