![]() |
|
|||
File indexing completed on 2025-07-02 08:07:09
0001 // 0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) 0003 // 0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying 0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 0006 // 0007 // Official repository: https://github.com/boostorg/beast 0008 // 0009 0010 #ifndef BOOST_BEAST_TEST_STREAM_HPP 0011 #define BOOST_BEAST_TEST_STREAM_HPP 0012 0013 #include <boost/beast/core/detail/config.hpp> 0014 #include <boost/beast/core/flat_buffer.hpp> 0015 #include <boost/beast/core/role.hpp> 0016 #include <boost/beast/core/string.hpp> 0017 #include <boost/beast/_experimental/test/fail_count.hpp> 0018 #include <boost/beast/_experimental/test/detail/stream_state.hpp> 0019 #include <boost/asio/async_result.hpp> 0020 #include <boost/asio/buffer.hpp> 0021 #include <boost/asio/error.hpp> 0022 #include <boost/asio/executor_work_guard.hpp> 0023 #include <boost/asio/any_io_executor.hpp> 0024 #include <boost/asio/io_context.hpp> 0025 #include <boost/assert.hpp> 0026 #include <boost/shared_ptr.hpp> 0027 #include <boost/weak_ptr.hpp> 0028 #include <boost/throw_exception.hpp> 0029 #include <condition_variable> 0030 #include <limits> 0031 #include <memory> 0032 #include <mutex> 0033 #include <utility> 0034 0035 #if ! BOOST_BEAST_DOXYGEN 0036 namespace boost { 0037 namespace asio { 0038 namespace ssl { 0039 template<typename> class stream; 0040 } // ssl 0041 } // asio 0042 } // boost 0043 #endif 0044 0045 namespace boost { 0046 namespace beast { 0047 namespace test { 0048 0049 /** A two-way socket useful for unit testing 0050 0051 An instance of this class simulates a traditional socket, 0052 while also providing features useful for unit testing. 0053 Each endpoint maintains an independent buffer called 0054 the input area. Writes from one endpoint append data 0055 to the peer's pending input area. When an endpoint performs 0056 a read and data is present in the input area, the data is 0057 delivered to the blocking or asynchronous operation. Otherwise 0058 the operation is blocked or deferred until data is made 0059 available, or until the endpoints become disconnected. 0060 0061 These streams may be used anywhere an algorithm accepts a 0062 reference to a synchronous or asynchronous read or write 0063 stream. It is possible to use a test stream in a call to 0064 `net::read_until`, or in a call to 0065 @ref boost::beast::http::async_write for example. 0066 0067 As with Boost.Asio I/O objects, a @ref stream constructs 0068 with a reference to the `net::io_context` to use for 0069 handling asynchronous I/O. For asynchronous operations, the 0070 stream follows the same rules as a traditional asio socket 0071 with respect to how completion handlers for asynchronous 0072 operations are performed. 0073 0074 To facilitate testing, these streams support some additional 0075 features: 0076 0077 @li The input area, represented by a @ref beast::basic_flat_buffer, 0078 may be directly accessed by the caller to inspect the contents 0079 before or after the remote endpoint writes data. This allows 0080 a unit test to verify that the received data matches. 0081 0082 @li Data may be manually appended to the input area. This data 0083 will delivered in the next call to 0084 @ref stream::read_some or @ref stream::async_read_some. 0085 This allows predefined test vectors to be set up for testing 0086 read algorithms. 0087 0088 @li The stream may be constructed with a fail count. The 0089 stream will eventually fail with a predefined error after a 0090 certain number of operations, where the number of operations 0091 is controlled by the test. When a test loops over a range of 0092 operation counts, it is possible to exercise every possible 0093 point of failure in the algorithm being tested. When used 0094 correctly the technique allows the tests to reach a high 0095 percentage of code coverage. 0096 0097 @par Thread Safety 0098 @e Distinct @e objects: Safe.@n 0099 @e Shared @e objects: Unsafe. 0100 The application must also ensure that all asynchronous 0101 operations are performed within the same implicit or explicit strand. 0102 0103 @par Concepts 0104 @li <em>SyncReadStream</em> 0105 @li <em>SyncWriteStream</em> 0106 @li <em>AsyncReadStream</em> 0107 @li <em>AsyncWriteStream</em> 0108 */ 0109 template<class Executor = net::any_io_executor> 0110 class basic_stream; 0111 0112 template<class Executor> 0113 void 0114 teardown( 0115 role_type, 0116 basic_stream<Executor>& s, 0117 boost::system::error_code& ec); 0118 0119 template<class Executor, class TeardownHandler> 0120 void 0121 async_teardown( 0122 role_type role, 0123 basic_stream<Executor>& s, 0124 TeardownHandler&& handler); 0125 0126 template<class Executor> 0127 class basic_stream 0128 { 0129 public: 0130 /// The type of the executor associated with the object. 0131 using executor_type = 0132 Executor; 0133 0134 /// Rebinds the socket type to another executor. 0135 template <typename Executor1> 0136 struct rebind_executor 0137 { 0138 /// The socket type when rebound to the specified executor. 0139 typedef basic_stream<Executor1> other; 0140 }; 0141 0142 private: 0143 template<class Executor2> 0144 friend class basic_stream; 0145 0146 boost::shared_ptr<detail::stream_state> in_; 0147 boost::weak_ptr<detail::stream_state> out_; 0148 0149 template<class Handler, class Buffers> 0150 class read_op; 0151 0152 struct run_read_op; 0153 struct run_write_op; 0154 0155 static 0156 void 0157 initiate_read( 0158 boost::shared_ptr<detail::stream_state> const& in, 0159 std::unique_ptr<detail::stream_read_op_base>&& op, 0160 std::size_t buf_size); 0161 0162 #if ! BOOST_BEAST_DOXYGEN 0163 // boost::asio::ssl::stream needs these 0164 // DEPRECATED 0165 template<class> 0166 friend class boost::asio::ssl::stream; 0167 // DEPRECATED 0168 using lowest_layer_type = basic_stream; 0169 // DEPRECATED 0170 lowest_layer_type& 0171 lowest_layer() noexcept 0172 { 0173 return *this; 0174 } 0175 // DEPRECATED 0176 lowest_layer_type const& 0177 lowest_layer() const noexcept 0178 { 0179 return *this; 0180 } 0181 #endif 0182 0183 public: 0184 using buffer_type = flat_buffer; 0185 0186 /** Destructor 0187 0188 If an asynchronous read operation is pending, it will 0189 simply be discarded with no notification to the completion 0190 handler. 0191 0192 If a connection is established while the stream is destroyed, 0193 the peer will see the error `net::error::connection_reset` 0194 when performing any reads or writes. 0195 */ 0196 ~basic_stream(); 0197 0198 /** Move Constructor 0199 0200 Moving the stream while asynchronous operations are pending 0201 results in undefined behavior. 0202 */ 0203 basic_stream(basic_stream&& other); 0204 0205 /** Move Constructor 0206 0207 Moving the stream while asynchronous operations are pending 0208 results in undefined behavior. 0209 */ 0210 template<class Executor2> 0211 basic_stream(basic_stream<Executor2>&& other) 0212 : in_(std::move(other.in_)) 0213 , out_(std::move(other.out_)) 0214 { 0215 BOOST_ASSERT(in_->exec.template target<Executor2>() != nullptr); 0216 in_->exec = executor_type(*in_->exec.template target<Executor2>()); 0217 } 0218 0219 /** Move Assignment 0220 0221 Moving the stream while asynchronous operations are pending 0222 results in undefined behavior. 0223 */ 0224 basic_stream& 0225 operator=(basic_stream&& other); 0226 0227 template<class Executor2> 0228 basic_stream& 0229 operator==(basic_stream<Executor2>&& other); 0230 0231 /** Construct a stream 0232 0233 The stream will be created in a disconnected state. 0234 0235 @param context The `io_context` object that the stream will use to 0236 dispatch handlers for any asynchronous operations. 0237 */ 0238 template <class ExecutionContext, 0239 class = typename std::enable_if< 0240 std::is_convertible<ExecutionContext&, net::execution_context&>::value>::type> 0241 explicit 0242 basic_stream(ExecutionContext& context) 0243 : basic_stream(context.get_executor()) 0244 { 0245 } 0246 0247 /** Construct a stream 0248 0249 The stream will be created in a disconnected state. 0250 0251 @param exec The `executor` object that the stream will use to 0252 dispatch handlers for any asynchronous operations. 0253 */ 0254 explicit 0255 basic_stream(executor_type exec); 0256 0257 /** Construct a stream 0258 0259 The stream will be created in a disconnected state. 0260 0261 @param ioc The `io_context` object that the stream will use to 0262 dispatch handlers for any asynchronous operations. 0263 0264 @param fc The @ref fail_count to associate with the stream. 0265 Each I/O operation performed on the stream will increment the 0266 fail count. When the fail count reaches its internal limit, 0267 a simulated failure error will be raised. 0268 */ 0269 basic_stream( 0270 net::io_context& ioc, 0271 fail_count& fc); 0272 0273 /** Construct a stream 0274 0275 The stream will be created in a disconnected state. 0276 0277 @param ioc The `io_context` object that the stream will use to 0278 dispatch handlers for any asynchronous operations. 0279 0280 @param s A string which will be appended to the input area, not 0281 including the null terminator. 0282 */ 0283 basic_stream( 0284 net::io_context& ioc, 0285 string_view s); 0286 0287 /** Construct a stream 0288 0289 The stream will be created in a disconnected state. 0290 0291 @param ioc The `io_context` object that the stream will use to 0292 dispatch handlers for any asynchronous operations. 0293 0294 @param fc The @ref fail_count to associate with the stream. 0295 Each I/O operation performed on the stream will increment the 0296 fail count. When the fail count reaches its internal limit, 0297 a simulated failure error will be raised. 0298 0299 @param s A string which will be appended to the input area, not 0300 including the null terminator. 0301 */ 0302 basic_stream( 0303 net::io_context& ioc, 0304 fail_count& fc, 0305 string_view s); 0306 0307 /// Establish a connection 0308 void 0309 connect(basic_stream& remote); 0310 0311 /// Return the executor associated with the object. 0312 executor_type 0313 get_executor() noexcept; 0314 0315 /// Set the maximum number of bytes returned by read_some 0316 void 0317 read_size(std::size_t n) noexcept 0318 { 0319 in_->read_max = n; 0320 } 0321 0322 /// Set the maximum number of bytes returned by write_some 0323 void 0324 write_size(std::size_t n) noexcept 0325 { 0326 in_->write_max = n; 0327 } 0328 0329 /// Direct input buffer access 0330 buffer_type& 0331 buffer() noexcept 0332 { 0333 return in_->b; 0334 } 0335 0336 /// Returns a string view representing the pending input data 0337 string_view 0338 str() const; 0339 0340 /// Appends a string to the pending input data 0341 void 0342 append(string_view s); 0343 0344 /// Clear the pending input area 0345 void 0346 clear(); 0347 0348 /// Return the number of reads 0349 std::size_t 0350 nread() const noexcept 0351 { 0352 return in_->nread; 0353 } 0354 0355 /// Return the number of bytes read 0356 std::size_t 0357 nread_bytes() const noexcept 0358 { 0359 return in_->nread_bytes; 0360 } 0361 0362 /// Return the number of writes 0363 std::size_t 0364 nwrite() const noexcept 0365 { 0366 return in_->nwrite; 0367 } 0368 0369 /// Return the number of bytes written 0370 std::size_t 0371 nwrite_bytes() const noexcept 0372 { 0373 return in_->nwrite_bytes; 0374 } 0375 0376 /** Close the stream. 0377 0378 The other end of the connection will see 0379 `error::eof` after reading all the remaining data. 0380 */ 0381 void 0382 close(); 0383 0384 /** Close the other end of the stream. 0385 0386 This end of the connection will see 0387 `error::eof` after reading all the remaining data. 0388 */ 0389 void 0390 close_remote(); 0391 0392 /** Read some data from the stream. 0393 0394 This function is used to read data from the stream. The function call will 0395 block until one or more bytes of data has been read successfully, or until 0396 an error occurs. 0397 0398 @param buffers The buffers into which the data will be read. 0399 0400 @returns The number of bytes read. 0401 0402 @throws boost::system::system_error Thrown on failure. 0403 0404 @note The `read_some` operation may not read all of the requested number of 0405 bytes. Consider using the function `net::read` if you need to ensure 0406 that the requested amount of data is read before the blocking operation 0407 completes. 0408 */ 0409 template<class MutableBufferSequence> 0410 std::size_t 0411 read_some(MutableBufferSequence const& buffers); 0412 0413 /** Read some data from the stream. 0414 0415 This function is used to read data from the stream. The function call will 0416 block until one or more bytes of data has been read successfully, or until 0417 an error occurs. 0418 0419 @param buffers The buffers into which the data will be read. 0420 0421 @param ec Set to indicate what error occurred, if any. 0422 0423 @returns The number of bytes read. 0424 0425 @note The `read_some` operation may not read all of the requested number of 0426 bytes. Consider using the function `net::read` if you need to ensure 0427 that the requested amount of data is read before the blocking operation 0428 completes. 0429 */ 0430 template<class MutableBufferSequence> 0431 std::size_t 0432 read_some(MutableBufferSequence const& buffers, 0433 error_code& ec); 0434 0435 /** Start an asynchronous read. 0436 0437 This function is used to asynchronously read one or more bytes of data from 0438 the stream. The function call always returns immediately. 0439 0440 @param buffers The buffers into which the data will be read. Although the 0441 buffers object may be copied as necessary, ownership of the underlying 0442 buffers is retained by the caller, which must guarantee that they remain 0443 valid until the handler is called. 0444 0445 @param handler The completion handler to invoke when the operation 0446 completes. The implementation takes ownership of the handler by 0447 performing a decay-copy. The equivalent function signature of 0448 the handler must be: 0449 @code 0450 void handler( 0451 error_code const& ec, // Result of operation. 0452 std::size_t bytes_transferred // Number of bytes read. 0453 ); 0454 @endcode 0455 If the handler has an associated immediate executor, 0456 an immediate completion will be dispatched to it. 0457 Otherwise, the handler will not be invoked from within 0458 this function. Invocation of the handler will be performed 0459 by dispatching to the immediate executor. If no 0460 immediate executor is specified, this is equivalent 0461 to using `net::post`. 0462 @note The `async_read_some` operation may not read all of the requested number of 0463 bytes. Consider using the function `net::async_read` if you need 0464 to ensure that the requested amount of data is read before the asynchronous 0465 operation completes. 0466 */ 0467 template< 0468 class MutableBufferSequence, 0469 BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, std::size_t)) ReadHandler 0470 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> 0471 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void(error_code, std::size_t)) 0472 async_read_some( 0473 MutableBufferSequence const& buffers, 0474 ReadHandler&& handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); 0475 0476 /** Write some data to the stream. 0477 0478 This function is used to write data on the stream. The function call will 0479 block until one or more bytes of data has been written successfully, or 0480 until an error occurs. 0481 0482 @param buffers The data to be written. 0483 0484 @returns The number of bytes written. 0485 0486 @throws boost::system::system_error Thrown on failure. 0487 0488 @note The `write_some` operation may not transmit all of the data to the 0489 peer. Consider using the function `net::write` if you need to 0490 ensure that all data is written before the blocking operation completes. 0491 */ 0492 template<class ConstBufferSequence> 0493 std::size_t 0494 write_some(ConstBufferSequence const& buffers); 0495 0496 /** Write some data to the stream. 0497 0498 This function is used to write data on the stream. The function call will 0499 block until one or more bytes of data has been written successfully, or 0500 until an error occurs. 0501 0502 @param buffers The data to be written. 0503 0504 @param ec Set to indicate what error occurred, if any. 0505 0506 @returns The number of bytes written. 0507 0508 @note The `write_some` operation may not transmit all of the data to the 0509 peer. Consider using the function `net::write` if you need to 0510 ensure that all data is written before the blocking operation completes. 0511 */ 0512 template<class ConstBufferSequence> 0513 std::size_t 0514 write_some( 0515 ConstBufferSequence const& buffers, error_code& ec); 0516 0517 /** Start an asynchronous write. 0518 0519 This function is used to asynchronously write one or more bytes of data to 0520 the stream. The function call always returns immediately. 0521 0522 @param buffers The data to be written to the stream. Although the buffers 0523 object may be copied as necessary, ownership of the underlying buffers is 0524 retained by the caller, which must guarantee that they remain valid until 0525 the handler is called. 0526 0527 @param handler The completion handler to invoke when the operation 0528 completes. The implementation takes ownership of the handler by 0529 performing a decay-copy. The equivalent function signature of 0530 the handler must be: 0531 @code 0532 void handler( 0533 error_code const& ec, // Result of operation. 0534 std::size_t bytes_transferred // Number of bytes written. 0535 ); 0536 @endcode 0537 If the handler has an associated immediate executor, 0538 an immediate completion will be dispatched to it. 0539 Otherwise, the handler will not be invoked from within 0540 this function. Invocation of the handler will be performed 0541 by dispatching to the immediate executor. If no 0542 immediate executor is specified, this is equivalent 0543 to using `net::post`. 0544 @note The `async_write_some` operation may not transmit all of the data to 0545 the peer. Consider using the function `net::async_write` if you need 0546 to ensure that all data is written before the asynchronous operation completes. 0547 */ 0548 template< 0549 class ConstBufferSequence, 0550 BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, std::size_t)) WriteHandler 0551 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> 0552 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void(error_code, std::size_t)) 0553 async_write_some( 0554 ConstBufferSequence const& buffers, 0555 WriteHandler&& handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type) 0556 ); 0557 0558 #if ! BOOST_BEAST_DOXYGEN 0559 friend 0560 void 0561 teardown<>( 0562 role_type, 0563 basic_stream& s, 0564 boost::system::error_code& ec); 0565 0566 template<class Ex2, class TeardownHandler> 0567 friend 0568 void 0569 async_teardown( 0570 role_type role, 0571 basic_stream<Ex2>& s, 0572 TeardownHandler&& handler); 0573 #endif 0574 }; 0575 0576 #if ! BOOST_BEAST_DOXYGEN 0577 template<class Executor> 0578 void 0579 beast_close_socket(basic_stream<Executor>& s) 0580 { 0581 s.close(); 0582 } 0583 #endif 0584 0585 #if BOOST_BEAST_DOXYGEN 0586 /** Return a new stream connected to the given stream 0587 0588 @param to The stream to connect to. 0589 0590 @param args Optional arguments forwarded to the new stream's constructor. 0591 0592 @return The new, connected stream. 0593 */ 0594 template<class Executor> 0595 template<class... Args> 0596 basic_stream 0597 connect(basic_stream& to, Args&&... args); 0598 0599 #else 0600 template<class Executor> 0601 basic_stream<Executor> 0602 connect(basic_stream<Executor>& to); 0603 0604 template<class Executor> 0605 void 0606 connect(basic_stream<Executor>& s1, basic_stream<Executor>& s2); 0607 0608 template<class Executor, class Arg1, class... ArgN> 0609 basic_stream<Executor> 0610 connect(basic_stream<Executor>& to, Arg1&& arg1, ArgN&&... argn); 0611 #endif 0612 0613 using stream = basic_stream<>; 0614 0615 } // test 0616 } // beast 0617 } // boost 0618 0619 #include <boost/beast/_experimental/test/impl/stream.hpp> 0620 //#ifdef BOOST_BEAST_HEADER_ONLY 0621 #include <boost/beast/_experimental/test/impl/stream.ipp> 0622 //#endif 0623 0624 #endif
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |