Back to home page

EIC code displayed by LXR

 
 

    


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