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