stream.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  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/bind_handler.hpp>
  13. #include <boost/beast/core/flat_buffer.hpp>
  14. #include <boost/beast/core/role.hpp>
  15. #include <boost/beast/core/string.hpp>
  16. #include <boost/beast/_experimental/test/fail_count.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/io_context.hpp>
  22. #include <boost/asio/post.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. class stream
  96. {
  97. struct state;
  98. boost::shared_ptr<state> in_;
  99. boost::weak_ptr<state> out_;
  100. enum class status
  101. {
  102. ok,
  103. eof,
  104. };
  105. class service;
  106. struct service_impl;
  107. struct read_op_base
  108. {
  109. virtual ~read_op_base() = default;
  110. virtual void operator()(error_code ec) = 0;
  111. };
  112. struct state
  113. {
  114. friend class stream;
  115. net::io_context& ioc;
  116. boost::weak_ptr<service_impl> wp;
  117. std::mutex m;
  118. flat_buffer b;
  119. std::condition_variable cv;
  120. std::unique_ptr<read_op_base> op;
  121. status code = status::ok;
  122. fail_count* fc = nullptr;
  123. std::size_t nread = 0;
  124. std::size_t nread_bytes = 0;
  125. std::size_t nwrite = 0;
  126. std::size_t nwrite_bytes = 0;
  127. std::size_t read_max =
  128. (std::numeric_limits<std::size_t>::max)();
  129. std::size_t write_max =
  130. (std::numeric_limits<std::size_t>::max)();
  131. BOOST_BEAST_DECL
  132. state(
  133. net::io_context& ioc_,
  134. boost::weak_ptr<service_impl> wp_,
  135. fail_count* fc_);
  136. BOOST_BEAST_DECL
  137. ~state();
  138. BOOST_BEAST_DECL
  139. void
  140. remove() noexcept;
  141. BOOST_BEAST_DECL
  142. void
  143. notify_read();
  144. BOOST_BEAST_DECL
  145. void
  146. cancel_read();
  147. };
  148. template<class Handler, class Buffers>
  149. class read_op;
  150. struct run_read_op;
  151. struct run_write_op;
  152. BOOST_BEAST_DECL
  153. static
  154. void
  155. initiate_read(
  156. boost::shared_ptr<state> const& in,
  157. std::unique_ptr<read_op_base>&& op,
  158. std::size_t buf_size);
  159. #if ! BOOST_BEAST_DOXYGEN
  160. // boost::asio::ssl::stream needs these
  161. // DEPRECATED
  162. template<class>
  163. friend class boost::asio::ssl::stream;
  164. // DEPRECATED
  165. using lowest_layer_type = stream;
  166. // DEPRECATED
  167. lowest_layer_type&
  168. lowest_layer() noexcept
  169. {
  170. return *this;
  171. }
  172. // DEPRECATED
  173. lowest_layer_type const&
  174. lowest_layer() const noexcept
  175. {
  176. return *this;
  177. }
  178. #endif
  179. public:
  180. using buffer_type = flat_buffer;
  181. /** Destructor
  182. If an asynchronous read operation is pending, it will
  183. simply be discarded with no notification to the completion
  184. handler.
  185. If a connection is established while the stream is destroyed,
  186. the peer will see the error `net::error::connection_reset`
  187. when performing any reads or writes.
  188. */
  189. BOOST_BEAST_DECL
  190. ~stream();
  191. /** Move Constructor
  192. Moving the stream while asynchronous operations are pending
  193. results in undefined behavior.
  194. */
  195. BOOST_BEAST_DECL
  196. stream(stream&& other);
  197. /** Move Assignment
  198. Moving the stream while asynchronous operations are pending
  199. results in undefined behavior.
  200. */
  201. BOOST_BEAST_DECL
  202. stream&
  203. operator=(stream&& other);
  204. /** Construct a stream
  205. The stream will be created in a disconnected state.
  206. @param ioc The `io_context` object that the stream will use to
  207. dispatch handlers for any asynchronous operations.
  208. */
  209. BOOST_BEAST_DECL
  210. explicit
  211. stream(net::io_context& ioc);
  212. /** Construct a stream
  213. The stream will be created in a disconnected state.
  214. @param ioc The `io_context` object that the stream will use to
  215. dispatch handlers for any asynchronous operations.
  216. @param fc The @ref fail_count to associate with the stream.
  217. Each I/O operation performed on the stream will increment the
  218. fail count. When the fail count reaches its internal limit,
  219. a simulated failure error will be raised.
  220. */
  221. BOOST_BEAST_DECL
  222. stream(
  223. net::io_context& ioc,
  224. fail_count& fc);
  225. /** Construct a stream
  226. The stream will be created in a disconnected state.
  227. @param ioc The `io_context` object that the stream will use to
  228. dispatch handlers for any asynchronous operations.
  229. @param s A string which will be appended to the input area, not
  230. including the null terminator.
  231. */
  232. BOOST_BEAST_DECL
  233. 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. BOOST_BEAST_DECL
  248. stream(
  249. net::io_context& ioc,
  250. fail_count& fc,
  251. string_view s);
  252. /// Establish a connection
  253. BOOST_BEAST_DECL
  254. void
  255. connect(stream& remote);
  256. /// The type of the executor associated with the object.
  257. using executor_type =
  258. net::io_context::executor_type;
  259. /// Return the executor associated with the object.
  260. executor_type
  261. get_executor() noexcept
  262. {
  263. return in_->ioc.get_executor();
  264. };
  265. /// Set the maximum number of bytes returned by read_some
  266. void
  267. read_size(std::size_t n) noexcept
  268. {
  269. in_->read_max = n;
  270. }
  271. /// Set the maximum number of bytes returned by write_some
  272. void
  273. write_size(std::size_t n) noexcept
  274. {
  275. in_->write_max = n;
  276. }
  277. /// Direct input buffer access
  278. buffer_type&
  279. buffer() noexcept
  280. {
  281. return in_->b;
  282. }
  283. /// Returns a string view representing the pending input data
  284. BOOST_BEAST_DECL
  285. string_view
  286. str() const;
  287. /// Appends a string to the pending input data
  288. BOOST_BEAST_DECL
  289. void
  290. append(string_view s);
  291. /// Clear the pending input area
  292. BOOST_BEAST_DECL
  293. void
  294. clear();
  295. /// Return the number of reads
  296. std::size_t
  297. nread() const noexcept
  298. {
  299. return in_->nread;
  300. }
  301. /// Return the number of bytes read
  302. std::size_t
  303. nread_bytes() const noexcept
  304. {
  305. return in_->nread_bytes;
  306. }
  307. /// Return the number of writes
  308. std::size_t
  309. nwrite() const noexcept
  310. {
  311. return in_->nwrite;
  312. }
  313. /// Return the number of bytes written
  314. std::size_t
  315. nwrite_bytes() const noexcept
  316. {
  317. return in_->nwrite_bytes;
  318. }
  319. /** Close the stream.
  320. The other end of the connection will see
  321. `error::eof` after reading all the remaining data.
  322. */
  323. BOOST_BEAST_DECL
  324. void
  325. close();
  326. /** Close the other end of the stream.
  327. This end of the connection will see
  328. `error::eof` after reading all the remaining data.
  329. */
  330. BOOST_BEAST_DECL
  331. void
  332. close_remote();
  333. /** Read some data from the stream.
  334. This function is used to read data from the stream. The function call will
  335. block until one or more bytes of data has been read successfully, or until
  336. an error occurs.
  337. @param buffers The buffers into which the data will be read.
  338. @returns The number of bytes read.
  339. @throws boost::system::system_error Thrown on failure.
  340. @note The `read_some` operation may not read all of the requested number of
  341. bytes. Consider using the function `net::read` if you need to ensure
  342. that the requested amount of data is read before the blocking operation
  343. completes.
  344. */
  345. template<class MutableBufferSequence>
  346. std::size_t
  347. read_some(MutableBufferSequence const& buffers);
  348. /** Read some data from the stream.
  349. This function is used to read data from the stream. The function call will
  350. block until one or more bytes of data has been read successfully, or until
  351. an error occurs.
  352. @param buffers The buffers into which the data will be read.
  353. @param ec Set to indicate what error occurred, if any.
  354. @returns The number of bytes read.
  355. @note The `read_some` operation may not read all of the requested number of
  356. bytes. Consider using the function `net::read` if you need to ensure
  357. that the requested amount of data is read before the blocking operation
  358. completes.
  359. */
  360. template<class MutableBufferSequence>
  361. std::size_t
  362. read_some(MutableBufferSequence const& buffers,
  363. error_code& ec);
  364. /** Start an asynchronous read.
  365. This function is used to asynchronously read one or more bytes of data from
  366. the stream. The function call always returns immediately.
  367. @param buffers The buffers into which the data will be read. Although the
  368. buffers object may be copied as necessary, ownership of the underlying
  369. buffers is retained by the caller, which must guarantee that they remain
  370. valid until the handler is called.
  371. @param handler The completion handler to invoke when the operation
  372. completes. The implementation takes ownership of the handler by
  373. performing a decay-copy. The equivalent function signature of
  374. the handler must be:
  375. @code
  376. void handler(
  377. error_code const& ec, // Result of operation.
  378. std::size_t bytes_transferred // Number of bytes read.
  379. );
  380. @endcode
  381. Regardless of whether the asynchronous operation completes
  382. immediately or not, the handler will not be invoked from within
  383. this function. Invocation of the handler will be performed in a
  384. manner equivalent to using `net::post`.
  385. @note The `async_read_some` operation may not read all of the requested number of
  386. bytes. Consider using the function `net::async_read` if you need
  387. to ensure that the requested amount of data is read before the asynchronous
  388. operation completes.
  389. */
  390. template<
  391. class MutableBufferSequence,
  392. BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
  393. BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
  394. async_read_some(
  395. MutableBufferSequence const& buffers,
  396. ReadHandler&& handler);
  397. /** Write some data to the stream.
  398. This function is used to write data on the stream. The function call will
  399. block until one or more bytes of data has been written successfully, or
  400. until an error occurs.
  401. @param buffers The data to be written.
  402. @returns The number of bytes written.
  403. @throws boost::system::system_error Thrown on failure.
  404. @note The `write_some` operation may not transmit all of the data to the
  405. peer. Consider using the function `net::write` if you need to
  406. ensure that all data is written before the blocking operation completes.
  407. */
  408. template<class ConstBufferSequence>
  409. std::size_t
  410. write_some(ConstBufferSequence const& buffers);
  411. /** Write some data to the stream.
  412. This function is used to write data on the stream. The function call will
  413. block until one or more bytes of data has been written successfully, or
  414. until an error occurs.
  415. @param buffers The data to be written.
  416. @param ec Set to indicate what error occurred, if any.
  417. @returns The number of bytes written.
  418. @note The `write_some` operation may not transmit all of the data to the
  419. peer. Consider using the function `net::write` if you need to
  420. ensure that all data is written before the blocking operation completes.
  421. */
  422. template<class ConstBufferSequence>
  423. std::size_t
  424. write_some(
  425. ConstBufferSequence const& buffers, error_code& ec);
  426. /** Start an asynchronous write.
  427. This function is used to asynchronously write one or more bytes of data to
  428. the stream. The function call always returns immediately.
  429. @param buffers The data to be written to the stream. Although the buffers
  430. object may be copied as necessary, ownership of the underlying buffers is
  431. retained by the caller, which must guarantee that they remain valid until
  432. the handler is called.
  433. @param handler The completion handler to invoke when the operation
  434. completes. The implementation takes ownership of the handler by
  435. performing a decay-copy. The equivalent function signature of
  436. the handler must be:
  437. @code
  438. void handler(
  439. error_code const& ec, // Result of operation.
  440. std::size_t bytes_transferred // Number of bytes written.
  441. );
  442. @endcode
  443. Regardless of whether the asynchronous operation completes
  444. immediately or not, the handler will not be invoked from within
  445. this function. Invocation of the handler will be performed in a
  446. manner equivalent to using `net::post`.
  447. @note The `async_write_some` operation may not transmit all of the data to
  448. the peer. Consider using the function `net::async_write` if you need
  449. to ensure that all data is written before the asynchronous operation completes.
  450. */
  451. template<
  452. class ConstBufferSequence,
  453. BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
  454. BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
  455. async_write_some(
  456. ConstBufferSequence const& buffers,
  457. WriteHandler&& handler);
  458. #if ! BOOST_BEAST_DOXYGEN
  459. friend
  460. BOOST_BEAST_DECL
  461. void
  462. teardown(
  463. role_type,
  464. stream& s,
  465. boost::system::error_code& ec);
  466. template<class TeardownHandler>
  467. friend
  468. BOOST_BEAST_DECL
  469. void
  470. async_teardown(
  471. role_type role,
  472. stream& s,
  473. TeardownHandler&& handler);
  474. #endif
  475. };
  476. #if ! BOOST_BEAST_DOXYGEN
  477. inline
  478. void
  479. beast_close_socket(stream& s)
  480. {
  481. s.close();
  482. }
  483. #endif
  484. #if BOOST_BEAST_DOXYGEN
  485. /** Return a new stream connected to the given stream
  486. @param to The stream to connect to.
  487. @param args Optional arguments forwarded to the new stream's constructor.
  488. @return The new, connected stream.
  489. */
  490. template<class... Args>
  491. stream
  492. connect(stream& to, Args&&... args);
  493. #else
  494. BOOST_BEAST_DECL
  495. stream
  496. connect(stream& to);
  497. BOOST_BEAST_DECL
  498. void
  499. connect(stream& s1, stream& s2);
  500. template<class Arg1, class... ArgN>
  501. stream
  502. connect(stream& to, Arg1&& arg1, ArgN&&... argn);
  503. #endif
  504. } // test
  505. } // beast
  506. } // boost
  507. #include <boost/beast/_experimental/test/impl/stream.hpp>
  508. #ifdef BOOST_BEAST_HEADER_ONLY
  509. #include <boost/beast/_experimental/test/impl/stream.ipp>
  510. #endif
  511. #endif