]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/beast/_experimental/test/stream.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / 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