basic_stream_descriptor.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. //
  2. // posix/basic_stream_descriptor.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
  11. #define BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <boost/asio/posix/basic_descriptor.hpp>
  17. #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
  18. || defined(GENERATING_DOCUMENTATION)
  19. #include <boost/asio/detail/push_options.hpp>
  20. namespace boost {
  21. namespace asio {
  22. namespace posix {
  23. /// Provides stream-oriented descriptor functionality.
  24. /**
  25. * The posix::basic_stream_descriptor class template provides asynchronous and
  26. * blocking stream-oriented descriptor functionality.
  27. *
  28. * @par Thread Safety
  29. * @e Distinct @e objects: Safe.@n
  30. * @e Shared @e objects: Unsafe.
  31. *
  32. * Synchronous @c read_some and @c write_some operations are thread safe with
  33. * respect to each other, if the underlying operating system calls are also
  34. * thread safe. This means that it is permitted to perform concurrent calls to
  35. * these synchronous operations on a single descriptor object. Other synchronous
  36. * operations, such as @c close, are not thread safe.
  37. *
  38. * @par Concepts:
  39. * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
  40. */
  41. template <typename Executor = any_io_executor>
  42. class basic_stream_descriptor
  43. : public basic_descriptor<Executor>
  44. {
  45. private:
  46. class initiate_async_write_some;
  47. class initiate_async_read_some;
  48. public:
  49. /// The type of the executor associated with the object.
  50. typedef Executor executor_type;
  51. /// Rebinds the descriptor type to another executor.
  52. template <typename Executor1>
  53. struct rebind_executor
  54. {
  55. /// The descriptor type when rebound to the specified executor.
  56. typedef basic_stream_descriptor<Executor1> other;
  57. };
  58. /// The native representation of a descriptor.
  59. typedef typename basic_descriptor<Executor>::native_handle_type
  60. native_handle_type;
  61. /// Construct a stream descriptor without opening it.
  62. /**
  63. * This constructor creates a stream descriptor without opening it. The
  64. * descriptor needs to be opened and then connected or accepted before data
  65. * can be sent or received on it.
  66. *
  67. * @param ex The I/O executor that the descriptor will use, by default, to
  68. * dispatch handlers for any asynchronous operations performed on the
  69. * descriptor.
  70. */
  71. explicit basic_stream_descriptor(const executor_type& ex)
  72. : basic_descriptor<Executor>(ex)
  73. {
  74. }
  75. /// Construct a stream descriptor without opening it.
  76. /**
  77. * This constructor creates a stream descriptor without opening it. The
  78. * descriptor needs to be opened and then connected or accepted before data
  79. * can be sent or received on it.
  80. *
  81. * @param context An execution context which provides the I/O executor that
  82. * the descriptor will use, by default, to dispatch handlers for any
  83. * asynchronous operations performed on the descriptor.
  84. */
  85. template <typename ExecutionContext>
  86. explicit basic_stream_descriptor(ExecutionContext& context,
  87. constraint_t<
  88. is_convertible<ExecutionContext&, execution_context&>::value,
  89. defaulted_constraint
  90. > = defaulted_constraint())
  91. : basic_descriptor<Executor>(context)
  92. {
  93. }
  94. /// Construct a stream descriptor on an existing native descriptor.
  95. /**
  96. * This constructor creates a stream descriptor object to hold an existing
  97. * native descriptor.
  98. *
  99. * @param ex The I/O executor that the descriptor will use, by default, to
  100. * dispatch handlers for any asynchronous operations performed on the
  101. * descriptor.
  102. *
  103. * @param native_descriptor The new underlying descriptor implementation.
  104. *
  105. * @throws boost::system::system_error Thrown on failure.
  106. */
  107. basic_stream_descriptor(const executor_type& ex,
  108. const native_handle_type& native_descriptor)
  109. : basic_descriptor<Executor>(ex, native_descriptor)
  110. {
  111. }
  112. /// Construct a stream descriptor on an existing native descriptor.
  113. /**
  114. * This constructor creates a stream descriptor object to hold an existing
  115. * native descriptor.
  116. *
  117. * @param context An execution context which provides the I/O executor that
  118. * the descriptor will use, by default, to dispatch handlers for any
  119. * asynchronous operations performed on the descriptor.
  120. *
  121. * @param native_descriptor The new underlying descriptor implementation.
  122. *
  123. * @throws boost::system::system_error Thrown on failure.
  124. */
  125. template <typename ExecutionContext>
  126. basic_stream_descriptor(ExecutionContext& context,
  127. const native_handle_type& native_descriptor,
  128. constraint_t<
  129. is_convertible<ExecutionContext&, execution_context&>::value
  130. > = 0)
  131. : basic_descriptor<Executor>(context, native_descriptor)
  132. {
  133. }
  134. /// Move-construct a stream descriptor from another.
  135. /**
  136. * This constructor moves a stream descriptor from one object to another.
  137. *
  138. * @param other The other stream descriptor object from which the move
  139. * will occur.
  140. *
  141. * @note Following the move, the moved-from object is in the same state as if
  142. * constructed using the @c basic_stream_descriptor(const executor_type&)
  143. * constructor.
  144. */
  145. basic_stream_descriptor(basic_stream_descriptor&& other) noexcept
  146. : basic_descriptor<Executor>(std::move(other))
  147. {
  148. }
  149. /// Move-assign a stream descriptor from another.
  150. /**
  151. * This assignment operator moves a stream descriptor from one object to
  152. * another.
  153. *
  154. * @param other The other stream descriptor object from which the move
  155. * will occur.
  156. *
  157. * @note Following the move, the moved-from object is in the same state as if
  158. * constructed using the @c basic_stream_descriptor(const executor_type&)
  159. * constructor.
  160. */
  161. basic_stream_descriptor& operator=(basic_stream_descriptor&& other)
  162. {
  163. basic_descriptor<Executor>::operator=(std::move(other));
  164. return *this;
  165. }
  166. /// Move-construct a basic_stream_descriptor from a descriptor of another
  167. /// executor type.
  168. /**
  169. * This constructor moves a descriptor from one object to another.
  170. *
  171. * @param other The other basic_stream_descriptor object from which the move
  172. * will occur.
  173. *
  174. * @note Following the move, the moved-from object is in the same state as if
  175. * constructed using the @c basic_stream_descriptor(const executor_type&)
  176. * constructor.
  177. */
  178. template <typename Executor1>
  179. basic_stream_descriptor(basic_stream_descriptor<Executor1>&& other,
  180. constraint_t<
  181. is_convertible<Executor1, Executor>::value,
  182. defaulted_constraint
  183. > = defaulted_constraint())
  184. : basic_descriptor<Executor>(std::move(other))
  185. {
  186. }
  187. /// Move-assign a basic_stream_descriptor from a descriptor of another
  188. /// executor type.
  189. /**
  190. * This assignment operator moves a descriptor from one object to another.
  191. *
  192. * @param other The other basic_stream_descriptor object from which the move
  193. * will occur.
  194. *
  195. * @note Following the move, the moved-from object is in the same state as if
  196. * constructed using the @c basic_stream_descriptor(const executor_type&)
  197. * constructor.
  198. */
  199. template <typename Executor1>
  200. constraint_t<
  201. is_convertible<Executor1, Executor>::value,
  202. basic_stream_descriptor&
  203. > operator=(basic_stream_descriptor<Executor1> && other)
  204. {
  205. basic_descriptor<Executor>::operator=(std::move(other));
  206. return *this;
  207. }
  208. /// Write some data to the descriptor.
  209. /**
  210. * This function is used to write data to the stream descriptor. The function
  211. * call will block until one or more bytes of the data has been written
  212. * successfully, or until an error occurs.
  213. *
  214. * @param buffers One or more data buffers to be written to the descriptor.
  215. *
  216. * @returns The number of bytes written.
  217. *
  218. * @throws boost::system::system_error Thrown on failure. An error code of
  219. * boost::asio::error::eof indicates that the connection was closed by the
  220. * peer.
  221. *
  222. * @note The write_some operation may not transmit all of the data to the
  223. * peer. Consider using the @ref write function if you need to ensure that
  224. * all data is written before the blocking operation completes.
  225. *
  226. * @par Example
  227. * To write a single data buffer use the @ref buffer function as follows:
  228. * @code
  229. * descriptor.write_some(boost::asio::buffer(data, size));
  230. * @endcode
  231. * See the @ref buffer documentation for information on writing multiple
  232. * buffers in one go, and how to use it with arrays, boost::array or
  233. * std::vector.
  234. */
  235. template <typename ConstBufferSequence>
  236. std::size_t write_some(const ConstBufferSequence& buffers)
  237. {
  238. boost::system::error_code ec;
  239. std::size_t s = this->impl_.get_service().write_some(
  240. this->impl_.get_implementation(), buffers, ec);
  241. boost::asio::detail::throw_error(ec, "write_some");
  242. return s;
  243. }
  244. /// Write some data to the descriptor.
  245. /**
  246. * This function is used to write data to the stream descriptor. The function
  247. * call will block until one or more bytes of the data has been written
  248. * successfully, or until an error occurs.
  249. *
  250. * @param buffers One or more data buffers to be written to the descriptor.
  251. *
  252. * @param ec Set to indicate what error occurred, if any.
  253. *
  254. * @returns The number of bytes written. Returns 0 if an error occurred.
  255. *
  256. * @note The write_some operation may not transmit all of the data to the
  257. * peer. Consider using the @ref write function if you need to ensure that
  258. * all data is written before the blocking operation completes.
  259. */
  260. template <typename ConstBufferSequence>
  261. std::size_t write_some(const ConstBufferSequence& buffers,
  262. boost::system::error_code& ec)
  263. {
  264. return this->impl_.get_service().write_some(
  265. this->impl_.get_implementation(), buffers, ec);
  266. }
  267. /// Start an asynchronous write.
  268. /**
  269. * This function is used to asynchronously write data to the stream
  270. * descriptor. It is an initiating function for an @ref
  271. * asynchronous_operation, and always returns immediately.
  272. *
  273. * @param buffers One or more data buffers to be written to the descriptor.
  274. * Although the buffers object may be copied as necessary, ownership of the
  275. * underlying memory blocks is retained by the caller, which must guarantee
  276. * that they remain valid until the completion handler is called.
  277. *
  278. * @param token The @ref completion_token that will be used to produce a
  279. * completion handler, which will be called when the write completes.
  280. * Potential completion tokens include @ref use_future, @ref use_awaitable,
  281. * @ref yield_context, or a function object with the correct completion
  282. * signature. The function signature of the completion handler must be:
  283. * @code void handler(
  284. * const boost::system::error_code& error, // Result of operation.
  285. * std::size_t bytes_transferred // Number of bytes written.
  286. * ); @endcode
  287. * Regardless of whether the asynchronous operation completes immediately or
  288. * not, the completion handler will not be invoked from within this function.
  289. * On immediate completion, invocation of the handler will be performed in a
  290. * manner equivalent to using boost::asio::async_immediate().
  291. *
  292. * @par Completion Signature
  293. * @code void(boost::system::error_code, std::size_t) @endcode
  294. *
  295. * @note The write operation may not transmit all of the data to the peer.
  296. * Consider using the @ref async_write function if you need to ensure that all
  297. * data is written before the asynchronous operation completes.
  298. *
  299. * @par Example
  300. * To write a single data buffer use the @ref buffer function as follows:
  301. * @code
  302. * descriptor.async_write_some(boost::asio::buffer(data, size), handler);
  303. * @endcode
  304. * See the @ref buffer documentation for information on writing multiple
  305. * buffers in one go, and how to use it with arrays, boost::array or
  306. * std::vector.
  307. *
  308. * @par Per-Operation Cancellation
  309. * This asynchronous operation supports cancellation for the following
  310. * boost::asio::cancellation_type values:
  311. *
  312. * @li @c cancellation_type::terminal
  313. *
  314. * @li @c cancellation_type::partial
  315. *
  316. * @li @c cancellation_type::total
  317. */
  318. template <typename ConstBufferSequence,
  319. BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
  320. std::size_t)) WriteToken = default_completion_token_t<executor_type>>
  321. auto async_write_some(const ConstBufferSequence& buffers,
  322. WriteToken&& token = default_completion_token_t<executor_type>())
  323. -> decltype(
  324. async_initiate<WriteToken,
  325. void (boost::system::error_code, std::size_t)>(
  326. initiate_async_write_some(this), token, buffers))
  327. {
  328. return async_initiate<WriteToken,
  329. void (boost::system::error_code, std::size_t)>(
  330. initiate_async_write_some(this), token, buffers);
  331. }
  332. /// Read some data from the descriptor.
  333. /**
  334. * This function is used to read data from the stream descriptor. The function
  335. * call will block until one or more bytes of data has been read successfully,
  336. * or until an error occurs.
  337. *
  338. * @param buffers One or more buffers into which the data will be read.
  339. *
  340. * @returns The number of bytes read.
  341. *
  342. * @throws boost::system::system_error Thrown on failure. An error code of
  343. * boost::asio::error::eof indicates that the connection was closed by the
  344. * peer.
  345. *
  346. * @note The read_some operation may not read all of the requested number of
  347. * bytes. Consider using the @ref read function if you need to ensure that
  348. * the requested amount of data is read before the blocking operation
  349. * completes.
  350. *
  351. * @par Example
  352. * To read into a single data buffer use the @ref buffer function as follows:
  353. * @code
  354. * descriptor.read_some(boost::asio::buffer(data, size));
  355. * @endcode
  356. * See the @ref buffer documentation for information on reading into multiple
  357. * buffers in one go, and how to use it with arrays, boost::array or
  358. * std::vector.
  359. */
  360. template <typename MutableBufferSequence>
  361. std::size_t read_some(const MutableBufferSequence& buffers)
  362. {
  363. boost::system::error_code ec;
  364. std::size_t s = this->impl_.get_service().read_some(
  365. this->impl_.get_implementation(), buffers, ec);
  366. boost::asio::detail::throw_error(ec, "read_some");
  367. return s;
  368. }
  369. /// Read some data from the descriptor.
  370. /**
  371. * This function is used to read data from the stream descriptor. The function
  372. * call will block until one or more bytes of data has been read successfully,
  373. * or until an error occurs.
  374. *
  375. * @param buffers One or more buffers into which the data will be read.
  376. *
  377. * @param ec Set to indicate what error occurred, if any.
  378. *
  379. * @returns The number of bytes read. Returns 0 if an error occurred.
  380. *
  381. * @note The read_some operation may not read all of the requested number of
  382. * bytes. Consider using the @ref read function if you need to ensure that
  383. * the requested amount of data is read before the blocking operation
  384. * completes.
  385. */
  386. template <typename MutableBufferSequence>
  387. std::size_t read_some(const MutableBufferSequence& buffers,
  388. boost::system::error_code& ec)
  389. {
  390. return this->impl_.get_service().read_some(
  391. this->impl_.get_implementation(), buffers, ec);
  392. }
  393. /// Start an asynchronous read.
  394. /**
  395. * This function is used to asynchronously read data from the stream
  396. * descriptor. It is an initiating function for an @ref
  397. * asynchronous_operation, and always returns immediately.
  398. *
  399. * @param buffers One or more buffers into which the data will be read.
  400. * Although the buffers object may be copied as necessary, ownership of the
  401. * underlying memory blocks is retained by the caller, which must guarantee
  402. * that they remain valid until the completion handler is called.
  403. *
  404. * @param token The @ref completion_token that will be used to produce a
  405. * completion handler, which will be called when the read completes.
  406. * Potential completion tokens include @ref use_future, @ref use_awaitable,
  407. * @ref yield_context, or a function object with the correct completion
  408. * signature. The function signature of the completion handler must be:
  409. * @code void handler(
  410. * const boost::system::error_code& error, // Result of operation.
  411. * std::size_t bytes_transferred // Number of bytes read.
  412. * ); @endcode
  413. * Regardless of whether the asynchronous operation completes immediately or
  414. * not, the completion handler will not be invoked from within this function.
  415. * On immediate completion, invocation of the handler will be performed in a
  416. * manner equivalent to using boost::asio::async_immediate().
  417. *
  418. * @par Completion Signature
  419. * @code void(boost::system::error_code, std::size_t) @endcode
  420. *
  421. * @note The read operation may not read all of the requested number of bytes.
  422. * Consider using the @ref async_read function if you need to ensure that the
  423. * requested amount of data is read before the asynchronous operation
  424. * completes.
  425. *
  426. * @par Example
  427. * To read into a single data buffer use the @ref buffer function as follows:
  428. * @code
  429. * descriptor.async_read_some(boost::asio::buffer(data, size), handler);
  430. * @endcode
  431. * See the @ref buffer documentation for information on reading into multiple
  432. * buffers in one go, and how to use it with arrays, boost::array or
  433. * std::vector.
  434. *
  435. * @par Per-Operation Cancellation
  436. * This asynchronous operation supports cancellation for the following
  437. * boost::asio::cancellation_type values:
  438. *
  439. * @li @c cancellation_type::terminal
  440. *
  441. * @li @c cancellation_type::partial
  442. *
  443. * @li @c cancellation_type::total
  444. */
  445. template <typename MutableBufferSequence,
  446. BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
  447. std::size_t)) ReadToken = default_completion_token_t<executor_type>>
  448. auto async_read_some(const MutableBufferSequence& buffers,
  449. ReadToken&& token = default_completion_token_t<executor_type>())
  450. -> decltype(
  451. async_initiate<ReadToken,
  452. void (boost::system::error_code, std::size_t)>(
  453. declval<initiate_async_read_some>(), token, buffers))
  454. {
  455. return async_initiate<ReadToken,
  456. void (boost::system::error_code, std::size_t)>(
  457. initiate_async_read_some(this), token, buffers);
  458. }
  459. private:
  460. class initiate_async_write_some
  461. {
  462. public:
  463. typedef Executor executor_type;
  464. explicit initiate_async_write_some(basic_stream_descriptor* self)
  465. : self_(self)
  466. {
  467. }
  468. const executor_type& get_executor() const noexcept
  469. {
  470. return self_->get_executor();
  471. }
  472. template <typename WriteHandler, typename ConstBufferSequence>
  473. void operator()(WriteHandler&& handler,
  474. const ConstBufferSequence& buffers) const
  475. {
  476. // If you get an error on the following line it means that your handler
  477. // does not meet the documented type requirements for a WriteHandler.
  478. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  479. detail::non_const_lvalue<WriteHandler> handler2(handler);
  480. self_->impl_.get_service().async_write_some(
  481. self_->impl_.get_implementation(), buffers,
  482. handler2.value, self_->impl_.get_executor());
  483. }
  484. private:
  485. basic_stream_descriptor* self_;
  486. };
  487. class initiate_async_read_some
  488. {
  489. public:
  490. typedef Executor executor_type;
  491. explicit initiate_async_read_some(basic_stream_descriptor* self)
  492. : self_(self)
  493. {
  494. }
  495. const executor_type& get_executor() const noexcept
  496. {
  497. return self_->get_executor();
  498. }
  499. template <typename ReadHandler, typename MutableBufferSequence>
  500. void operator()(ReadHandler&& handler,
  501. const MutableBufferSequence& buffers) const
  502. {
  503. // If you get an error on the following line it means that your handler
  504. // does not meet the documented type requirements for a ReadHandler.
  505. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
  506. detail::non_const_lvalue<ReadHandler> handler2(handler);
  507. self_->impl_.get_service().async_read_some(
  508. self_->impl_.get_implementation(), buffers,
  509. handler2.value, self_->impl_.get_executor());
  510. }
  511. private:
  512. basic_stream_descriptor* self_;
  513. };
  514. };
  515. } // namespace posix
  516. } // namespace asio
  517. } // namespace boost
  518. #include <boost/asio/detail/pop_options.hpp>
  519. #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
  520. // || defined(GENERATING_DOCUMENTATION)
  521. #endif // BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP