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