Back to home page

EIC code displayed by LXR

 
 

    


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