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