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