stream.hpp 19 KB

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