basic_writable_pipe.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. //
  2. // basic_writable_pipe.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 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 ASIO_BASIC_WRITABLE_PIPE_HPP
  11. #define ASIO_BASIC_WRITABLE_PIPE_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include "asio/detail/config.hpp"
  16. #if defined(ASIO_HAS_PIPE) \
  17. || defined(GENERATING_DOCUMENTATION)
  18. #include <string>
  19. #include <utility>
  20. #include "asio/any_io_executor.hpp"
  21. #include "asio/async_result.hpp"
  22. #include "asio/detail/handler_type_requirements.hpp"
  23. #include "asio/detail/io_object_impl.hpp"
  24. #include "asio/detail/non_const_lvalue.hpp"
  25. #include "asio/detail/throw_error.hpp"
  26. #include "asio/detail/type_traits.hpp"
  27. #include "asio/error.hpp"
  28. #include "asio/execution_context.hpp"
  29. #if defined(ASIO_HAS_IOCP)
  30. # include "asio/detail/win_iocp_handle_service.hpp"
  31. #elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
  32. # include "asio/detail/io_uring_descriptor_service.hpp"
  33. #else
  34. # include "asio/detail/reactive_descriptor_service.hpp"
  35. #endif
  36. #include "asio/detail/push_options.hpp"
  37. namespace asio {
  38. /// Provides pipe functionality.
  39. /**
  40. * The basic_writable_pipe class provides a wrapper over pipe
  41. * functionality.
  42. *
  43. * @par Thread Safety
  44. * @e Distinct @e objects: Safe.@n
  45. * @e Shared @e objects: Unsafe.
  46. */
  47. template <typename Executor = any_io_executor>
  48. class basic_writable_pipe
  49. {
  50. private:
  51. class initiate_async_write_some;
  52. public:
  53. /// The type of the executor associated with the object.
  54. typedef Executor executor_type;
  55. /// Rebinds the pipe type to another executor.
  56. template <typename Executor1>
  57. struct rebind_executor
  58. {
  59. /// The pipe type when rebound to the specified executor.
  60. typedef basic_writable_pipe<Executor1> other;
  61. };
  62. /// The native representation of a pipe.
  63. #if defined(GENERATING_DOCUMENTATION)
  64. typedef implementation_defined native_handle_type;
  65. #elif defined(ASIO_HAS_IOCP)
  66. typedef detail::win_iocp_handle_service::native_handle_type
  67. native_handle_type;
  68. #elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
  69. typedef detail::io_uring_descriptor_service::native_handle_type
  70. native_handle_type;
  71. #else
  72. typedef detail::reactive_descriptor_service::native_handle_type
  73. native_handle_type;
  74. #endif
  75. /// A basic_writable_pipe is always the lowest layer.
  76. typedef basic_writable_pipe lowest_layer_type;
  77. /// Construct a basic_writable_pipe without opening it.
  78. /**
  79. * This constructor creates a pipe without opening it.
  80. *
  81. * @param ex The I/O executor that the pipe will use, by default, to dispatch
  82. * handlers for any asynchronous operations performed on the pipe.
  83. */
  84. explicit basic_writable_pipe(const executor_type& ex)
  85. : impl_(0, ex)
  86. {
  87. }
  88. /// Construct a basic_writable_pipe without opening it.
  89. /**
  90. * This constructor creates a pipe without opening it.
  91. *
  92. * @param context An execution context which provides the I/O executor that
  93. * the pipe will use, by default, to dispatch handlers for any asynchronous
  94. * operations performed on the pipe.
  95. */
  96. template <typename ExecutionContext>
  97. explicit basic_writable_pipe(ExecutionContext& context,
  98. constraint_t<
  99. is_convertible<ExecutionContext&, execution_context&>::value,
  100. defaulted_constraint
  101. > = defaulted_constraint())
  102. : impl_(0, 0, context)
  103. {
  104. }
  105. /// Construct a basic_writable_pipe on an existing native pipe.
  106. /**
  107. * This constructor creates a pipe object to hold an existing native
  108. * pipe.
  109. *
  110. * @param ex The I/O executor that the pipe will use, by default, to
  111. * dispatch handlers for any asynchronous operations performed on the
  112. * pipe.
  113. *
  114. * @param native_pipe A native pipe.
  115. *
  116. * @throws asio::system_error Thrown on failure.
  117. */
  118. basic_writable_pipe(const executor_type& ex,
  119. const native_handle_type& native_pipe)
  120. : impl_(0, ex)
  121. {
  122. asio::error_code ec;
  123. impl_.get_service().assign(impl_.get_implementation(),
  124. native_pipe, ec);
  125. asio::detail::throw_error(ec, "assign");
  126. }
  127. /// Construct a basic_writable_pipe on an existing native pipe.
  128. /**
  129. * This constructor creates a pipe object to hold an existing native
  130. * pipe.
  131. *
  132. * @param context An execution context which provides the I/O executor that
  133. * the pipe will use, by default, to dispatch handlers for any
  134. * asynchronous operations performed on the pipe.
  135. *
  136. * @param native_pipe A native pipe.
  137. *
  138. * @throws asio::system_error Thrown on failure.
  139. */
  140. template <typename ExecutionContext>
  141. basic_writable_pipe(ExecutionContext& context,
  142. const native_handle_type& native_pipe,
  143. constraint_t<
  144. is_convertible<ExecutionContext&, execution_context&>::value
  145. > = 0)
  146. : impl_(0, 0, context)
  147. {
  148. asio::error_code ec;
  149. impl_.get_service().assign(impl_.get_implementation(),
  150. native_pipe, ec);
  151. asio::detail::throw_error(ec, "assign");
  152. }
  153. /// Move-construct a basic_writable_pipe from another.
  154. /**
  155. * This constructor moves a pipe from one object to another.
  156. *
  157. * @param other The other basic_writable_pipe object from which the move will
  158. * occur.
  159. *
  160. * @note Following the move, the moved-from object is in the same state as if
  161. * constructed using the @c basic_writable_pipe(const executor_type&)
  162. * constructor.
  163. */
  164. basic_writable_pipe(basic_writable_pipe&& other)
  165. : impl_(std::move(other.impl_))
  166. {
  167. }
  168. /// Move-assign a basic_writable_pipe from another.
  169. /**
  170. * This assignment operator moves a pipe from one object to another.
  171. *
  172. * @param other The other basic_writable_pipe object from which the move will
  173. * occur.
  174. *
  175. * @note Following the move, the moved-from object is in the same state as if
  176. * constructed using the @c basic_writable_pipe(const executor_type&)
  177. * constructor.
  178. */
  179. basic_writable_pipe& operator=(basic_writable_pipe&& other)
  180. {
  181. impl_ = std::move(other.impl_);
  182. return *this;
  183. }
  184. // All pipes have access to each other's implementations.
  185. template <typename Executor1>
  186. friend class basic_writable_pipe;
  187. /// Move-construct a basic_writable_pipe from a pipe of another executor type.
  188. /**
  189. * This constructor moves a pipe from one object to another.
  190. *
  191. * @param other The other basic_writable_pipe object from which the move will
  192. * occur.
  193. *
  194. * @note Following the move, the moved-from object is in the same state as if
  195. * constructed using the @c basic_writable_pipe(const executor_type&)
  196. * constructor.
  197. */
  198. template <typename Executor1>
  199. basic_writable_pipe(basic_writable_pipe<Executor1>&& other,
  200. constraint_t<
  201. is_convertible<Executor1, Executor>::value,
  202. defaulted_constraint
  203. > = defaulted_constraint())
  204. : impl_(std::move(other.impl_))
  205. {
  206. }
  207. /// Move-assign a basic_writable_pipe from a pipe of another executor type.
  208. /**
  209. * This assignment operator moves a pipe from one object to another.
  210. *
  211. * @param other The other basic_writable_pipe object from which the move will
  212. * occur.
  213. *
  214. * @note Following the move, the moved-from object is in the same state as if
  215. * constructed using the @c basic_writable_pipe(const executor_type&)
  216. * constructor.
  217. */
  218. template <typename Executor1>
  219. constraint_t<
  220. is_convertible<Executor1, Executor>::value,
  221. basic_writable_pipe&
  222. > operator=(basic_writable_pipe<Executor1>&& other)
  223. {
  224. basic_writable_pipe tmp(std::move(other));
  225. impl_ = std::move(tmp.impl_);
  226. return *this;
  227. }
  228. /// Destroys the pipe.
  229. /**
  230. * This function destroys the pipe, cancelling any outstanding
  231. * asynchronous wait operations associated with the pipe as if by
  232. * calling @c cancel.
  233. */
  234. ~basic_writable_pipe()
  235. {
  236. }
  237. /// Get the executor associated with the object.
  238. const executor_type& get_executor() noexcept
  239. {
  240. return impl_.get_executor();
  241. }
  242. /// Get a reference to the lowest layer.
  243. /**
  244. * This function returns a reference to the lowest layer in a stack of
  245. * layers. Since a basic_writable_pipe cannot contain any further layers, it
  246. * simply returns a reference to itself.
  247. *
  248. * @return A reference to the lowest layer in the stack of layers. Ownership
  249. * is not transferred to the caller.
  250. */
  251. lowest_layer_type& lowest_layer()
  252. {
  253. return *this;
  254. }
  255. /// Get a const reference to the lowest layer.
  256. /**
  257. * This function returns a const reference to the lowest layer in a stack of
  258. * layers. Since a basic_writable_pipe cannot contain any further layers, it
  259. * simply returns a reference to itself.
  260. *
  261. * @return A const reference to the lowest layer in the stack of layers.
  262. * Ownership is not transferred to the caller.
  263. */
  264. const lowest_layer_type& lowest_layer() const
  265. {
  266. return *this;
  267. }
  268. /// Assign an existing native pipe to the pipe.
  269. /*
  270. * This function opens the pipe to hold an existing native pipe.
  271. *
  272. * @param native_pipe A native pipe.
  273. *
  274. * @throws asio::system_error Thrown on failure.
  275. */
  276. void assign(const native_handle_type& native_pipe)
  277. {
  278. asio::error_code ec;
  279. impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
  280. asio::detail::throw_error(ec, "assign");
  281. }
  282. /// Assign an existing native pipe to the pipe.
  283. /*
  284. * This function opens the pipe to hold an existing native pipe.
  285. *
  286. * @param native_pipe A native pipe.
  287. *
  288. * @param ec Set to indicate what error occurred, if any.
  289. */
  290. ASIO_SYNC_OP_VOID assign(const native_handle_type& native_pipe,
  291. asio::error_code& ec)
  292. {
  293. impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
  294. ASIO_SYNC_OP_VOID_RETURN(ec);
  295. }
  296. /// Determine whether the pipe is open.
  297. bool is_open() const
  298. {
  299. return impl_.get_service().is_open(impl_.get_implementation());
  300. }
  301. /// Close the pipe.
  302. /**
  303. * This function is used to close the pipe. Any asynchronous write operations
  304. * will be cancelled immediately, and will complete with the
  305. * asio::error::operation_aborted error.
  306. *
  307. * @throws asio::system_error Thrown on failure.
  308. */
  309. void close()
  310. {
  311. asio::error_code ec;
  312. impl_.get_service().close(impl_.get_implementation(), ec);
  313. asio::detail::throw_error(ec, "close");
  314. }
  315. /// Close the pipe.
  316. /**
  317. * This function is used to close the pipe. Any asynchronous write operations
  318. * will be cancelled immediately, and will complete with the
  319. * asio::error::operation_aborted error.
  320. *
  321. * @param ec Set to indicate what error occurred, if any.
  322. */
  323. ASIO_SYNC_OP_VOID close(asio::error_code& ec)
  324. {
  325. impl_.get_service().close(impl_.get_implementation(), ec);
  326. ASIO_SYNC_OP_VOID_RETURN(ec);
  327. }
  328. /// Release ownership of the underlying native pipe.
  329. /**
  330. * This function causes all outstanding asynchronous write operations to
  331. * finish immediately, and the handlers for cancelled operations will be
  332. * passed the asio::error::operation_aborted error. Ownership of the
  333. * native pipe is then transferred to the caller.
  334. *
  335. * @throws asio::system_error Thrown on failure.
  336. *
  337. * @note This function is unsupported on Windows versions prior to Windows
  338. * 8.1, and will fail with asio::error::operation_not_supported on
  339. * these platforms.
  340. */
  341. #if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
  342. && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
  343. __declspec(deprecated("This function always fails with "
  344. "operation_not_supported when used on Windows versions "
  345. "prior to Windows 8.1."))
  346. #endif
  347. native_handle_type release()
  348. {
  349. asio::error_code ec;
  350. native_handle_type s = impl_.get_service().release(
  351. impl_.get_implementation(), ec);
  352. asio::detail::throw_error(ec, "release");
  353. return s;
  354. }
  355. /// Release ownership of the underlying native pipe.
  356. /**
  357. * This function causes all outstanding asynchronous write operations to
  358. * finish immediately, and the handlers for cancelled operations will be
  359. * passed the asio::error::operation_aborted error. Ownership of the
  360. * native pipe is then transferred to the caller.
  361. *
  362. * @param ec Set to indicate what error occurred, if any.
  363. *
  364. * @note This function is unsupported on Windows versions prior to Windows
  365. * 8.1, and will fail with asio::error::operation_not_supported on
  366. * these platforms.
  367. */
  368. #if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
  369. && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
  370. __declspec(deprecated("This function always fails with "
  371. "operation_not_supported when used on Windows versions "
  372. "prior to Windows 8.1."))
  373. #endif
  374. native_handle_type release(asio::error_code& ec)
  375. {
  376. return impl_.get_service().release(impl_.get_implementation(), ec);
  377. }
  378. /// Get the native pipe representation.
  379. /**
  380. * This function may be used to obtain the underlying representation of the
  381. * pipe. This is intended to allow access to native pipe
  382. * functionality that is not otherwise provided.
  383. */
  384. native_handle_type native_handle()
  385. {
  386. return impl_.get_service().native_handle(impl_.get_implementation());
  387. }
  388. /// Cancel all asynchronous operations associated with the pipe.
  389. /**
  390. * This function causes all outstanding asynchronous write operations to
  391. * finish immediately, and the handlers for cancelled operations will be
  392. * passed the asio::error::operation_aborted error.
  393. *
  394. * @throws asio::system_error Thrown on failure.
  395. */
  396. void cancel()
  397. {
  398. asio::error_code ec;
  399. impl_.get_service().cancel(impl_.get_implementation(), ec);
  400. asio::detail::throw_error(ec, "cancel");
  401. }
  402. /// Cancel all asynchronous operations associated with the pipe.
  403. /**
  404. * This function causes all outstanding asynchronous write operations to
  405. * finish immediately, and the handlers for cancelled operations will be
  406. * passed the asio::error::operation_aborted error.
  407. *
  408. * @param ec Set to indicate what error occurred, if any.
  409. */
  410. ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
  411. {
  412. impl_.get_service().cancel(impl_.get_implementation(), ec);
  413. ASIO_SYNC_OP_VOID_RETURN(ec);
  414. }
  415. /// Write some data to the pipe.
  416. /**
  417. * This function is used to write data to the pipe. The function call will
  418. * block until one or more bytes of the data has been written successfully,
  419. * or until an error occurs.
  420. *
  421. * @param buffers One or more data buffers to be written to the pipe.
  422. *
  423. * @returns The number of bytes written.
  424. *
  425. * @throws asio::system_error Thrown on failure. An error code of
  426. * asio::error::eof indicates that the connection was closed by the
  427. * peer.
  428. *
  429. * @note The write_some operation may not transmit all of the data to the
  430. * peer. Consider using the @ref write function if you need to ensure that
  431. * all data is written before the blocking operation completes.
  432. *
  433. * @par Example
  434. * To write a single data buffer use the @ref buffer function as follows:
  435. * @code
  436. * pipe.write_some(asio::buffer(data, size));
  437. * @endcode
  438. * See the @ref buffer documentation for information on writing multiple
  439. * buffers in one go, and how to use it with arrays, boost::array or
  440. * std::vector.
  441. */
  442. template <typename ConstBufferSequence>
  443. std::size_t write_some(const ConstBufferSequence& buffers)
  444. {
  445. asio::error_code ec;
  446. std::size_t s = impl_.get_service().write_some(
  447. impl_.get_implementation(), buffers, ec);
  448. asio::detail::throw_error(ec, "write_some");
  449. return s;
  450. }
  451. /// Write some data to the pipe.
  452. /**
  453. * This function is used to write data to the pipe. The function call will
  454. * block until one or more bytes of the data has been written successfully,
  455. * or until an error occurs.
  456. *
  457. * @param buffers One or more data buffers to be written to the pipe.
  458. *
  459. * @param ec Set to indicate what error occurred, if any.
  460. *
  461. * @returns The number of bytes written. Returns 0 if an error occurred.
  462. *
  463. * @note The write_some operation may not transmit all of the data to the
  464. * peer. Consider using the @ref write function if you need to ensure that
  465. * all data is written before the blocking operation completes.
  466. */
  467. template <typename ConstBufferSequence>
  468. std::size_t write_some(const ConstBufferSequence& buffers,
  469. asio::error_code& ec)
  470. {
  471. return impl_.get_service().write_some(
  472. impl_.get_implementation(), buffers, ec);
  473. }
  474. /// Start an asynchronous write.
  475. /**
  476. * This function is used to asynchronously write data to the pipe. It is an
  477. * initiating function for an @ref asynchronous_operation, and always returns
  478. * immediately.
  479. *
  480. * @param buffers One or more data buffers to be written to the pipe.
  481. * Although the buffers object may be copied as necessary, ownership of the
  482. * underlying memory blocks is retained by the caller, which must guarantee
  483. * that they remain valid until the completion handler is called.
  484. *
  485. * @param token The @ref completion_token that will be used to produce a
  486. * completion handler, which will be called when the write completes.
  487. * Potential completion tokens include @ref use_future, @ref use_awaitable,
  488. * @ref yield_context, or a function object with the correct completion
  489. * signature. The function signature of the completion handler must be:
  490. * @code void handler(
  491. * const asio::error_code& error, // Result of operation.
  492. * std::size_t bytes_transferred // Number of bytes written.
  493. * ); @endcode
  494. * Regardless of whether the asynchronous operation completes immediately or
  495. * not, the completion handler will not be invoked from within this function.
  496. * On immediate completion, invocation of the handler will be performed in a
  497. * manner equivalent to using asio::post().
  498. *
  499. * @par Completion Signature
  500. * @code void(asio::error_code, std::size_t) @endcode
  501. *
  502. * @note The write operation may not transmit all of the data to the peer.
  503. * Consider using the @ref async_write function if you need to ensure that all
  504. * data is written before the asynchronous operation completes.
  505. *
  506. * @par Example
  507. * To write a single data buffer use the @ref buffer function as follows:
  508. * @code
  509. * pipe.async_write_some(asio::buffer(data, size), handler);
  510. * @endcode
  511. * See the @ref buffer documentation for information on writing multiple
  512. * buffers in one go, and how to use it with arrays, boost::array or
  513. * std::vector.
  514. */
  515. template <typename ConstBufferSequence,
  516. ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
  517. std::size_t)) WriteToken = default_completion_token_t<executor_type>>
  518. auto async_write_some(const ConstBufferSequence& buffers,
  519. WriteToken&& token = default_completion_token_t<executor_type>())
  520. -> decltype(
  521. async_initiate<WriteToken,
  522. void (asio::error_code, std::size_t)>(
  523. declval<initiate_async_write_some>(), token, buffers))
  524. {
  525. return async_initiate<WriteToken,
  526. void (asio::error_code, std::size_t)>(
  527. initiate_async_write_some(this), token, buffers);
  528. }
  529. private:
  530. // Disallow copying and assignment.
  531. basic_writable_pipe(const basic_writable_pipe&) = delete;
  532. basic_writable_pipe& operator=(const basic_writable_pipe&) = delete;
  533. class initiate_async_write_some
  534. {
  535. public:
  536. typedef Executor executor_type;
  537. explicit initiate_async_write_some(basic_writable_pipe* self)
  538. : self_(self)
  539. {
  540. }
  541. const executor_type& get_executor() const noexcept
  542. {
  543. return self_->get_executor();
  544. }
  545. template <typename WriteHandler, typename ConstBufferSequence>
  546. void operator()(WriteHandler&& handler,
  547. const ConstBufferSequence& buffers) const
  548. {
  549. // If you get an error on the following line it means that your handler
  550. // does not meet the documented type requirements for a WriteHandler.
  551. ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  552. detail::non_const_lvalue<WriteHandler> handler2(handler);
  553. self_->impl_.get_service().async_write_some(
  554. self_->impl_.get_implementation(), buffers,
  555. handler2.value, self_->impl_.get_executor());
  556. }
  557. private:
  558. basic_writable_pipe* self_;
  559. };
  560. #if defined(ASIO_HAS_IOCP)
  561. detail::io_object_impl<detail::win_iocp_handle_service, Executor> impl_;
  562. #elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
  563. detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_;
  564. #else
  565. detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;
  566. #endif
  567. };
  568. } // namespace asio
  569. #include "asio/detail/pop_options.hpp"
  570. #endif // defined(ASIO_HAS_PIPE)
  571. // || defined(GENERATING_DOCUMENTATION)
  572. #endif // ASIO_BASIC_WRITABLE_PIPE_HPP