Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:01

0001 //
0002 // posix/basic_stream_descriptor.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
0012 #define BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <boost/asio/posix/basic_descriptor.hpp>
0020 
0021 #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
0022   || defined(GENERATING_DOCUMENTATION)
0023 
0024 #include <boost/asio/detail/push_options.hpp>
0025 
0026 namespace boost {
0027 namespace asio {
0028 namespace posix {
0029 
0030 /// Provides stream-oriented descriptor functionality.
0031 /**
0032  * The posix::basic_stream_descriptor class template provides asynchronous and
0033  * blocking stream-oriented descriptor functionality.
0034  *
0035  * @par Thread Safety
0036  * @e Distinct @e objects: Safe.@n
0037  * @e Shared @e objects: Unsafe.
0038  *
0039  * Synchronous @c read_some and @c write_some operations are thread safe with
0040  * respect to each other, if the underlying operating system calls are also
0041  * thread safe. This means that it is permitted to perform concurrent calls to
0042  * these synchronous operations on a single descriptor object. Other synchronous
0043  * operations, such as @c close, are not thread safe.
0044  *
0045  * @par Concepts:
0046  * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
0047  */
0048 template <typename Executor = any_io_executor>
0049 class basic_stream_descriptor
0050   : public basic_descriptor<Executor>
0051 {
0052 private:
0053   class initiate_async_write_some;
0054   class initiate_async_read_some;
0055 
0056 public:
0057   /// The type of the executor associated with the object.
0058   typedef Executor executor_type;
0059 
0060   /// Rebinds the descriptor type to another executor.
0061   template <typename Executor1>
0062   struct rebind_executor
0063   {
0064     /// The descriptor type when rebound to the specified executor.
0065     typedef basic_stream_descriptor<Executor1> other;
0066   };
0067 
0068   /// The native representation of a descriptor.
0069   typedef typename basic_descriptor<Executor>::native_handle_type
0070     native_handle_type;
0071 
0072   /// Construct a stream descriptor without opening it.
0073   /**
0074    * This constructor creates a stream descriptor without opening it. The
0075    * descriptor needs to be opened and then connected or accepted before data
0076    * can be sent or received on it.
0077    *
0078    * @param ex The I/O executor that the descriptor will use, by default, to
0079    * dispatch handlers for any asynchronous operations performed on the
0080    * descriptor.
0081    */
0082   explicit basic_stream_descriptor(const executor_type& ex)
0083     : basic_descriptor<Executor>(ex)
0084   {
0085   }
0086 
0087   /// Construct a stream descriptor without opening it.
0088   /**
0089    * This constructor creates a stream descriptor without opening it. The
0090    * descriptor needs to be opened and then connected or accepted before data
0091    * can be sent or received on it.
0092    *
0093    * @param context An execution context which provides the I/O executor that
0094    * the descriptor will use, by default, to dispatch handlers for any
0095    * asynchronous operations performed on the descriptor.
0096    */
0097   template <typename ExecutionContext>
0098   explicit basic_stream_descriptor(ExecutionContext& context,
0099       constraint_t<
0100         is_convertible<ExecutionContext&, execution_context&>::value,
0101         defaulted_constraint
0102       > = defaulted_constraint())
0103     : basic_descriptor<Executor>(context)
0104   {
0105   }
0106 
0107   /// Construct a stream descriptor on an existing native descriptor.
0108   /**
0109    * This constructor creates a stream descriptor object to hold an existing
0110    * native descriptor.
0111    *
0112    * @param ex The I/O executor that the descriptor will use, by default, to
0113    * dispatch handlers for any asynchronous operations performed on the
0114    * descriptor.
0115    *
0116    * @param native_descriptor The new underlying descriptor implementation.
0117    *
0118    * @throws boost::system::system_error Thrown on failure.
0119    */
0120   basic_stream_descriptor(const executor_type& ex,
0121       const native_handle_type& native_descriptor)
0122     : basic_descriptor<Executor>(ex, native_descriptor)
0123   {
0124   }
0125 
0126   /// Construct a stream descriptor on an existing native descriptor.
0127   /**
0128    * This constructor creates a stream descriptor object to hold an existing
0129    * native descriptor.
0130    *
0131    * @param context An execution context which provides the I/O executor that
0132    * the descriptor will use, by default, to dispatch handlers for any
0133    * asynchronous operations performed on the descriptor.
0134    *
0135    * @param native_descriptor The new underlying descriptor implementation.
0136    *
0137    * @throws boost::system::system_error Thrown on failure.
0138    */
0139   template <typename ExecutionContext>
0140   basic_stream_descriptor(ExecutionContext& context,
0141       const native_handle_type& native_descriptor,
0142       constraint_t<
0143         is_convertible<ExecutionContext&, execution_context&>::value
0144       > = 0)
0145     : basic_descriptor<Executor>(context, native_descriptor)
0146   {
0147   }
0148 
0149   /// Move-construct a stream descriptor from another.
0150   /**
0151    * This constructor moves a stream descriptor from one object to another.
0152    *
0153    * @param other The other stream descriptor object from which the move
0154    * will occur.
0155    *
0156    * @note Following the move, the moved-from object is in the same state as if
0157    * constructed using the @c basic_stream_descriptor(const executor_type&)
0158    * constructor.
0159    */
0160   basic_stream_descriptor(basic_stream_descriptor&& other) noexcept
0161     : basic_descriptor<Executor>(std::move(other))
0162   {
0163   }
0164 
0165   /// Move-assign a stream descriptor from another.
0166   /**
0167    * This assignment operator moves a stream descriptor from one object to
0168    * another.
0169    *
0170    * @param other The other stream descriptor object from which the move
0171    * will occur.
0172    *
0173    * @note Following the move, the moved-from object is in the same state as if
0174    * constructed using the @c basic_stream_descriptor(const executor_type&)
0175    * constructor.
0176    */
0177   basic_stream_descriptor& operator=(basic_stream_descriptor&& other)
0178   {
0179     basic_descriptor<Executor>::operator=(std::move(other));
0180     return *this;
0181   }
0182 
0183   /// Move-construct a basic_stream_descriptor from a descriptor of another
0184   /// executor type.
0185   /**
0186    * This constructor moves a descriptor from one object to another.
0187    *
0188    * @param other The other basic_stream_descriptor object from which the move
0189    * will occur.
0190    *
0191    * @note Following the move, the moved-from object is in the same state as if
0192    * constructed using the @c basic_stream_descriptor(const executor_type&)
0193    * constructor.
0194    */
0195   template <typename Executor1>
0196   basic_stream_descriptor(basic_stream_descriptor<Executor1>&& other,
0197       constraint_t<
0198         is_convertible<Executor1, Executor>::value,
0199         defaulted_constraint
0200       > = defaulted_constraint())
0201     : basic_descriptor<Executor>(std::move(other))
0202   {
0203   }
0204 
0205   /// Move-assign a basic_stream_descriptor from a descriptor of another
0206   /// executor type.
0207   /**
0208    * This assignment operator moves a descriptor from one object to another.
0209    *
0210    * @param other The other basic_stream_descriptor object from which the move
0211    * will occur.
0212    *
0213    * @note Following the move, the moved-from object is in the same state as if
0214    * constructed using the @c basic_stream_descriptor(const executor_type&)
0215    * constructor.
0216    */
0217   template <typename Executor1>
0218   constraint_t<
0219     is_convertible<Executor1, Executor>::value,
0220     basic_stream_descriptor&
0221   > operator=(basic_stream_descriptor<Executor1> && other)
0222   {
0223     basic_descriptor<Executor>::operator=(std::move(other));
0224     return *this;
0225   }
0226 
0227   /// Write some data to the descriptor.
0228   /**
0229    * This function is used to write data to the stream descriptor. The function
0230    * call will block until one or more bytes of the data has been written
0231    * successfully, or until an error occurs.
0232    *
0233    * @param buffers One or more data buffers to be written to the descriptor.
0234    *
0235    * @returns The number of bytes written.
0236    *
0237    * @throws boost::system::system_error Thrown on failure. An error code of
0238    * boost::asio::error::eof indicates that the connection was closed by the
0239    * peer.
0240    *
0241    * @note The write_some operation may not transmit all of the data to the
0242    * peer. Consider using the @ref write function if you need to ensure that
0243    * all data is written before the blocking operation completes.
0244    *
0245    * @par Example
0246    * To write a single data buffer use the @ref buffer function as follows:
0247    * @code
0248    * descriptor.write_some(boost::asio::buffer(data, size));
0249    * @endcode
0250    * See the @ref buffer documentation for information on writing multiple
0251    * buffers in one go, and how to use it with arrays, boost::array or
0252    * std::vector.
0253    */
0254   template <typename ConstBufferSequence>
0255   std::size_t write_some(const ConstBufferSequence& buffers)
0256   {
0257     boost::system::error_code ec;
0258     std::size_t s = this->impl_.get_service().write_some(
0259         this->impl_.get_implementation(), buffers, ec);
0260     boost::asio::detail::throw_error(ec, "write_some");
0261     return s;
0262   }
0263 
0264   /// Write some data to the descriptor.
0265   /**
0266    * This function is used to write data to the stream descriptor. The function
0267    * call will block until one or more bytes of the data has been written
0268    * successfully, or until an error occurs.
0269    *
0270    * @param buffers One or more data buffers to be written to the descriptor.
0271    *
0272    * @param ec Set to indicate what error occurred, if any.
0273    *
0274    * @returns The number of bytes written. Returns 0 if an error occurred.
0275    *
0276    * @note The write_some operation may not transmit all of the data to the
0277    * peer. Consider using the @ref write function if you need to ensure that
0278    * all data is written before the blocking operation completes.
0279    */
0280   template <typename ConstBufferSequence>
0281   std::size_t write_some(const ConstBufferSequence& buffers,
0282       boost::system::error_code& ec)
0283   {
0284     return this->impl_.get_service().write_some(
0285         this->impl_.get_implementation(), buffers, ec);
0286   }
0287 
0288   /// Start an asynchronous write.
0289   /**
0290    * This function is used to asynchronously write data to the stream
0291    * descriptor. It is an initiating function for an @ref
0292    * asynchronous_operation, and always returns immediately.
0293    *
0294    * @param buffers One or more data buffers to be written to the descriptor.
0295    * Although the buffers object may be copied as necessary, ownership of the
0296    * underlying memory blocks is retained by the caller, which must guarantee
0297    * that they remain valid until the completion handler is called.
0298    *
0299    * @param token The @ref completion_token that will be used to produce a
0300    * completion handler, which will be called when the write completes.
0301    * Potential completion tokens include @ref use_future, @ref use_awaitable,
0302    * @ref yield_context, or a function object with the correct completion
0303    * signature. The function signature of the completion handler must be:
0304    * @code void handler(
0305    *   const boost::system::error_code& error, // Result of operation.
0306    *   std::size_t bytes_transferred // Number of bytes written.
0307    * ); @endcode
0308    * Regardless of whether the asynchronous operation completes immediately or
0309    * not, the completion handler will not be invoked from within this function.
0310    * On immediate completion, invocation of the handler will be performed in a
0311    * manner equivalent to using boost::asio::post().
0312    *
0313    * @par Completion Signature
0314    * @code void(boost::system::error_code, std::size_t) @endcode
0315    *
0316    * @note The write operation may not transmit all of the data to the peer.
0317    * Consider using the @ref async_write function if you need to ensure that all
0318    * data is written before the asynchronous operation completes.
0319    *
0320    * @par Example
0321    * To write a single data buffer use the @ref buffer function as follows:
0322    * @code
0323    * descriptor.async_write_some(boost::asio::buffer(data, size), handler);
0324    * @endcode
0325    * See the @ref buffer documentation for information on writing multiple
0326    * buffers in one go, and how to use it with arrays, boost::array or
0327    * std::vector.
0328    *
0329    * @par Per-Operation Cancellation
0330    * This asynchronous operation supports cancellation for the following
0331    * boost::asio::cancellation_type values:
0332    *
0333    * @li @c cancellation_type::terminal
0334    *
0335    * @li @c cancellation_type::partial
0336    *
0337    * @li @c cancellation_type::total
0338    */
0339   template <typename ConstBufferSequence,
0340       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
0341         std::size_t)) WriteToken = default_completion_token_t<executor_type>>
0342   auto async_write_some(const ConstBufferSequence& buffers,
0343       WriteToken&& token = default_completion_token_t<executor_type>())
0344     -> decltype(
0345       async_initiate<WriteToken,
0346         void (boost::system::error_code, std::size_t)>(
0347           initiate_async_write_some(this), token, buffers))
0348   {
0349     return async_initiate<WriteToken,
0350       void (boost::system::error_code, std::size_t)>(
0351         initiate_async_write_some(this), token, buffers);
0352   }
0353 
0354   /// Read some data from the descriptor.
0355   /**
0356    * This function is used to read data from the stream descriptor. The function
0357    * call will block until one or more bytes of data has been read successfully,
0358    * or until an error occurs.
0359    *
0360    * @param buffers One or more buffers into which the data will be read.
0361    *
0362    * @returns The number of bytes read.
0363    *
0364    * @throws boost::system::system_error Thrown on failure. An error code of
0365    * boost::asio::error::eof indicates that the connection was closed by the
0366    * peer.
0367    *
0368    * @note The read_some operation may not read all of the requested number of
0369    * bytes. Consider using the @ref read function if you need to ensure that
0370    * the requested amount of data is read before the blocking operation
0371    * completes.
0372    *
0373    * @par Example
0374    * To read into a single data buffer use the @ref buffer function as follows:
0375    * @code
0376    * descriptor.read_some(boost::asio::buffer(data, size));
0377    * @endcode
0378    * See the @ref buffer documentation for information on reading into multiple
0379    * buffers in one go, and how to use it with arrays, boost::array or
0380    * std::vector.
0381    */
0382   template <typename MutableBufferSequence>
0383   std::size_t read_some(const MutableBufferSequence& buffers)
0384   {
0385     boost::system::error_code ec;
0386     std::size_t s = this->impl_.get_service().read_some(
0387         this->impl_.get_implementation(), buffers, ec);
0388     boost::asio::detail::throw_error(ec, "read_some");
0389     return s;
0390   }
0391 
0392   /// Read some data from the descriptor.
0393   /**
0394    * This function is used to read data from the stream descriptor. The function
0395    * call will block until one or more bytes of data has been read successfully,
0396    * or until an error occurs.
0397    *
0398    * @param buffers One or more buffers into which the data will be read.
0399    *
0400    * @param ec Set to indicate what error occurred, if any.
0401    *
0402    * @returns The number of bytes read. Returns 0 if an error occurred.
0403    *
0404    * @note The read_some operation may not read all of the requested number of
0405    * bytes. Consider using the @ref read function if you need to ensure that
0406    * the requested amount of data is read before the blocking operation
0407    * completes.
0408    */
0409   template <typename MutableBufferSequence>
0410   std::size_t read_some(const MutableBufferSequence& buffers,
0411       boost::system::error_code& ec)
0412   {
0413     return this->impl_.get_service().read_some(
0414         this->impl_.get_implementation(), buffers, ec);
0415   }
0416 
0417   /// Start an asynchronous read.
0418   /**
0419    * This function is used to asynchronously read data from the stream
0420    * descriptor. It is an initiating function for an @ref
0421    * asynchronous_operation, and always returns immediately.
0422    *
0423    * @param buffers One or more buffers into which the data will be read.
0424    * Although the buffers object may be copied as necessary, ownership of the
0425    * underlying memory blocks is retained by the caller, which must guarantee
0426    * that they remain valid until the completion handler is called.
0427    *
0428    * @param token The @ref completion_token that will be used to produce a
0429    * completion handler, which will be called when the read completes.
0430    * Potential completion tokens include @ref use_future, @ref use_awaitable,
0431    * @ref yield_context, or a function object with the correct completion
0432    * signature. The function signature of the completion handler must be:
0433    * @code void handler(
0434    *   const boost::system::error_code& error, // Result of operation.
0435    *   std::size_t bytes_transferred // Number of bytes read.
0436    * ); @endcode
0437    * Regardless of whether the asynchronous operation completes immediately or
0438    * not, the completion handler will not be invoked from within this function.
0439    * On immediate completion, invocation of the handler will be performed in a
0440    * manner equivalent to using boost::asio::post().
0441    *
0442    * @par Completion Signature
0443    * @code void(boost::system::error_code, std::size_t) @endcode
0444    *
0445    * @note The read operation may not read all of the requested number of bytes.
0446    * Consider using the @ref async_read function if you need to ensure that the
0447    * requested amount of data is read before the asynchronous operation
0448    * completes.
0449    *
0450    * @par Example
0451    * To read into a single data buffer use the @ref buffer function as follows:
0452    * @code
0453    * descriptor.async_read_some(boost::asio::buffer(data, size), handler);
0454    * @endcode
0455    * See the @ref buffer documentation for information on reading into multiple
0456    * buffers in one go, and how to use it with arrays, boost::array or
0457    * std::vector.
0458    *
0459    * @par Per-Operation Cancellation
0460    * This asynchronous operation supports cancellation for the following
0461    * boost::asio::cancellation_type values:
0462    *
0463    * @li @c cancellation_type::terminal
0464    *
0465    * @li @c cancellation_type::partial
0466    *
0467    * @li @c cancellation_type::total
0468    */
0469   template <typename MutableBufferSequence,
0470       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
0471         std::size_t)) ReadToken = default_completion_token_t<executor_type>>
0472   auto async_read_some(const MutableBufferSequence& buffers,
0473       ReadToken&& token = default_completion_token_t<executor_type>())
0474     -> decltype(
0475       async_initiate<ReadToken,
0476         void (boost::system::error_code, std::size_t)>(
0477           declval<initiate_async_read_some>(), token, buffers))
0478   {
0479     return async_initiate<ReadToken,
0480       void (boost::system::error_code, std::size_t)>(
0481         initiate_async_read_some(this), token, buffers);
0482   }
0483 
0484 private:
0485   class initiate_async_write_some
0486   {
0487   public:
0488     typedef Executor executor_type;
0489 
0490     explicit initiate_async_write_some(basic_stream_descriptor* self)
0491       : self_(self)
0492     {
0493     }
0494 
0495     const executor_type& get_executor() const noexcept
0496     {
0497       return self_->get_executor();
0498     }
0499 
0500     template <typename WriteHandler, typename ConstBufferSequence>
0501     void operator()(WriteHandler&& handler,
0502         const ConstBufferSequence& buffers) const
0503     {
0504       // If you get an error on the following line it means that your handler
0505       // does not meet the documented type requirements for a WriteHandler.
0506       BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
0507 
0508       detail::non_const_lvalue<WriteHandler> handler2(handler);
0509       self_->impl_.get_service().async_write_some(
0510           self_->impl_.get_implementation(), buffers,
0511           handler2.value, self_->impl_.get_executor());
0512     }
0513 
0514   private:
0515     basic_stream_descriptor* self_;
0516   };
0517 
0518   class initiate_async_read_some
0519   {
0520   public:
0521     typedef Executor executor_type;
0522 
0523     explicit initiate_async_read_some(basic_stream_descriptor* self)
0524       : self_(self)
0525     {
0526     }
0527 
0528     const executor_type& get_executor() const noexcept
0529     {
0530       return self_->get_executor();
0531     }
0532 
0533     template <typename ReadHandler, typename MutableBufferSequence>
0534     void operator()(ReadHandler&& handler,
0535         const MutableBufferSequence& buffers) const
0536     {
0537       // If you get an error on the following line it means that your handler
0538       // does not meet the documented type requirements for a ReadHandler.
0539       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
0540 
0541       detail::non_const_lvalue<ReadHandler> handler2(handler);
0542       self_->impl_.get_service().async_read_some(
0543           self_->impl_.get_implementation(), buffers,
0544           handler2.value, self_->impl_.get_executor());
0545     }
0546 
0547   private:
0548     basic_stream_descriptor* self_;
0549   };
0550 };
0551 
0552 } // namespace posix
0553 } // namespace asio
0554 } // namespace boost
0555 
0556 #include <boost/asio/detail/pop_options.hpp>
0557 
0558 #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
0559        //   || defined(GENERATING_DOCUMENTATION)
0560 
0561 #endif // BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP