1 //
2 // posix/basic_descriptor.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2016 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 ASIO_POSIX_BASIC_DESCRIPTOR_HPP
12 #define ASIO_POSIX_BASIC_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 "asio/detail/config.hpp"
19 
20 #if defined(ASIO_ENABLE_OLD_SERVICES)
21 
22 #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \
23   || defined(GENERATING_DOCUMENTATION)
24 
25 #include "asio/basic_io_object.hpp"
26 #include "asio/detail/throw_error.hpp"
27 #include "asio/error.hpp"
28 #include "asio/posix/descriptor_base.hpp"
29 
30 #include "asio/detail/push_options.hpp"
31 
32 namespace asio {
33 namespace posix {
34 
35 /// Provides POSIX descriptor functionality.
36 /**
37  * The posix::basic_descriptor class template provides the ability to wrap a
38  * POSIX descriptor.
39  *
40  * @par Thread Safety
41  * @e Distinct @e objects: Safe.@n
42  * @e Shared @e objects: Unsafe.
43  */
44 template <typename DescriptorService>
45 class basic_descriptor
46   : public basic_io_object<DescriptorService>,
47     public descriptor_base
48 {
49 public:
50   /// The native representation of a descriptor.
51   typedef typename DescriptorService::native_handle_type native_handle_type;
52 
53   /// A basic_descriptor is always the lowest layer.
54   typedef basic_descriptor<DescriptorService> lowest_layer_type;
55 
56   /// Construct a basic_descriptor without opening it.
57   /**
58    * This constructor creates a descriptor without opening it.
59    *
60    * @param io_context The io_context object that the descriptor will use to
61    * dispatch handlers for any asynchronous operations performed on the
62    * descriptor.
63    */
basic_descriptor(asio::io_context & io_context)64   explicit basic_descriptor(asio::io_context& io_context)
65     : basic_io_object<DescriptorService>(io_context)
66   {
67   }
68 
69   /// Construct a basic_descriptor on an existing native descriptor.
70   /**
71    * This constructor creates a descriptor object to hold an existing native
72    * descriptor.
73    *
74    * @param io_context The io_context object that the descriptor will use to
75    * dispatch handlers for any asynchronous operations performed on the
76    * descriptor.
77    *
78    * @param native_descriptor A native descriptor.
79    *
80    * @throws asio::system_error Thrown on failure.
81    */
basic_descriptor(asio::io_context & io_context,const native_handle_type & native_descriptor)82   basic_descriptor(asio::io_context& io_context,
83       const native_handle_type& native_descriptor)
84     : basic_io_object<DescriptorService>(io_context)
85   {
86     asio::error_code ec;
87     this->get_service().assign(this->get_implementation(),
88         native_descriptor, ec);
89     asio::detail::throw_error(ec, "assign");
90   }
91 
92 #if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
93   /// Move-construct a basic_descriptor from another.
94   /**
95    * This constructor moves a descriptor from one object to another.
96    *
97    * @param other The other basic_descriptor object from which the move will
98    * occur.
99    *
100    * @note Following the move, the moved-from object is in the same state as if
101    * constructed using the @c basic_descriptor(io_context&) constructor.
102    */
basic_descriptor(basic_descriptor && other)103   basic_descriptor(basic_descriptor&& other)
104     : basic_io_object<DescriptorService>(
105         ASIO_MOVE_CAST(basic_descriptor)(other))
106   {
107   }
108 
109   /// Move-assign a basic_descriptor from another.
110   /**
111    * This assignment operator moves a descriptor from one object to another.
112    *
113    * @param other The other basic_descriptor object from which the move will
114    * occur.
115    *
116    * @note Following the move, the moved-from object is in the same state as if
117    * constructed using the @c basic_descriptor(io_context&) constructor.
118    */
operator =(basic_descriptor && other)119   basic_descriptor& operator=(basic_descriptor&& other)
120   {
121     basic_io_object<DescriptorService>::operator=(
122         ASIO_MOVE_CAST(basic_descriptor)(other));
123     return *this;
124   }
125 #endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
126 
127   /// Get a reference to the lowest layer.
128   /**
129    * This function returns a reference to the lowest layer in a stack of
130    * layers. Since a basic_descriptor cannot contain any further layers, it
131    * simply returns a reference to itself.
132    *
133    * @return A reference to the lowest layer in the stack of layers. Ownership
134    * is not transferred to the caller.
135    */
lowest_layer()136   lowest_layer_type& lowest_layer()
137   {
138     return *this;
139   }
140 
141   /// Get a const reference to the lowest layer.
142   /**
143    * This function returns a const reference to the lowest layer in a stack of
144    * layers. Since a basic_descriptor cannot contain any further layers, it
145    * simply returns a reference to itself.
146    *
147    * @return A const reference to the lowest layer in the stack of layers.
148    * Ownership is not transferred to the caller.
149    */
lowest_layer() const150   const lowest_layer_type& lowest_layer() const
151   {
152     return *this;
153   }
154 
155   /// Assign an existing native descriptor to the descriptor.
156   /*
157    * This function opens the descriptor to hold an existing native descriptor.
158    *
159    * @param native_descriptor A native descriptor.
160    *
161    * @throws asio::system_error Thrown on failure.
162    */
assign(const native_handle_type & native_descriptor)163   void assign(const native_handle_type& native_descriptor)
164   {
165     asio::error_code ec;
166     this->get_service().assign(this->get_implementation(),
167         native_descriptor, ec);
168     asio::detail::throw_error(ec, "assign");
169   }
170 
171   /// Assign an existing native descriptor to the descriptor.
172   /*
173    * This function opens the descriptor to hold an existing native descriptor.
174    *
175    * @param native_descriptor A native descriptor.
176    *
177    * @param ec Set to indicate what error occurred, if any.
178    */
assign(const native_handle_type & native_descriptor,asio::error_code & ec)179   ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor,
180       asio::error_code& ec)
181   {
182     this->get_service().assign(
183         this->get_implementation(), native_descriptor, ec);
184     ASIO_SYNC_OP_VOID_RETURN(ec);
185   }
186 
187   /// Determine whether the descriptor is open.
is_open() const188   bool is_open() const
189   {
190     return this->get_service().is_open(this->get_implementation());
191   }
192 
193   /// Close the descriptor.
194   /**
195    * This function is used to close the descriptor. Any asynchronous read or
196    * write operations will be cancelled immediately, and will complete with the
197    * asio::error::operation_aborted error.
198    *
199    * @throws asio::system_error Thrown on failure. Note that, even if
200    * the function indicates an error, the underlying descriptor is closed.
201    */
close()202   void close()
203   {
204     asio::error_code ec;
205     this->get_service().close(this->get_implementation(), ec);
206     asio::detail::throw_error(ec, "close");
207   }
208 
209   /// Close the descriptor.
210   /**
211    * This function is used to close the descriptor. Any asynchronous read or
212    * write operations will be cancelled immediately, and will complete with the
213    * asio::error::operation_aborted error.
214    *
215    * @param ec Set to indicate what error occurred, if any. Note that, even if
216    * the function indicates an error, the underlying descriptor is closed.
217    */
close(asio::error_code & ec)218   ASIO_SYNC_OP_VOID close(asio::error_code& ec)
219   {
220     this->get_service().close(this->get_implementation(), ec);
221     ASIO_SYNC_OP_VOID_RETURN(ec);
222   }
223 
224   /// Get the native descriptor representation.
225   /**
226    * This function may be used to obtain the underlying representation of the
227    * descriptor. This is intended to allow access to native descriptor
228    * functionality that is not otherwise provided.
229    */
native_handle()230   native_handle_type native_handle()
231   {
232     return this->get_service().native_handle(this->get_implementation());
233   }
234 
235   /// Release ownership of the native descriptor implementation.
236   /**
237    * This function may be used to obtain the underlying representation of the
238    * descriptor. After calling this function, @c is_open() returns false. The
239    * caller is responsible for closing the descriptor.
240    *
241    * All outstanding asynchronous read or write operations will finish
242    * immediately, and the handlers for cancelled operations will be passed the
243    * asio::error::operation_aborted error.
244    */
release()245   native_handle_type release()
246   {
247     return this->get_service().release(this->get_implementation());
248   }
249 
250   /// Cancel all asynchronous operations associated with the descriptor.
251   /**
252    * This function causes all outstanding asynchronous read or write operations
253    * to finish immediately, and the handlers for cancelled operations will be
254    * passed the asio::error::operation_aborted error.
255    *
256    * @throws asio::system_error Thrown on failure.
257    */
cancel()258   void cancel()
259   {
260     asio::error_code ec;
261     this->get_service().cancel(this->get_implementation(), ec);
262     asio::detail::throw_error(ec, "cancel");
263   }
264 
265   /// Cancel all asynchronous operations associated with the descriptor.
266   /**
267    * This function causes all outstanding asynchronous read or write operations
268    * to finish immediately, and the handlers for cancelled operations will be
269    * passed the asio::error::operation_aborted error.
270    *
271    * @param ec Set to indicate what error occurred, if any.
272    */
cancel(asio::error_code & ec)273   ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
274   {
275     this->get_service().cancel(this->get_implementation(), ec);
276     ASIO_SYNC_OP_VOID_RETURN(ec);
277   }
278 
279   /// Perform an IO control command on the descriptor.
280   /**
281    * This function is used to execute an IO control command on the descriptor.
282    *
283    * @param command The IO control command to be performed on the descriptor.
284    *
285    * @throws asio::system_error Thrown on failure.
286    *
287    * @sa IoControlCommand @n
288    * asio::posix::descriptor_base::bytes_readable @n
289    * asio::posix::descriptor_base::non_blocking_io
290    *
291    * @par Example
292    * Getting the number of bytes ready to read:
293    * @code
294    * asio::posix::stream_descriptor descriptor(io_context);
295    * ...
296    * asio::posix::stream_descriptor::bytes_readable command;
297    * descriptor.io_control(command);
298    * std::size_t bytes_readable = command.get();
299    * @endcode
300    */
301   template <typename IoControlCommand>
io_control(IoControlCommand & command)302   void io_control(IoControlCommand& command)
303   {
304     asio::error_code ec;
305     this->get_service().io_control(this->get_implementation(), command, ec);
306     asio::detail::throw_error(ec, "io_control");
307   }
308 
309   /// Perform an IO control command on the descriptor.
310   /**
311    * This function is used to execute an IO control command on the descriptor.
312    *
313    * @param command The IO control command to be performed on the descriptor.
314    *
315    * @param ec Set to indicate what error occurred, if any.
316    *
317    * @sa IoControlCommand @n
318    * asio::posix::descriptor_base::bytes_readable @n
319    * asio::posix::descriptor_base::non_blocking_io
320    *
321    * @par Example
322    * Getting the number of bytes ready to read:
323    * @code
324    * asio::posix::stream_descriptor descriptor(io_context);
325    * ...
326    * asio::posix::stream_descriptor::bytes_readable command;
327    * asio::error_code ec;
328    * descriptor.io_control(command, ec);
329    * if (ec)
330    * {
331    *   // An error occurred.
332    * }
333    * std::size_t bytes_readable = command.get();
334    * @endcode
335    */
336   template <typename IoControlCommand>
io_control(IoControlCommand & command,asio::error_code & ec)337   ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,
338       asio::error_code& ec)
339   {
340     this->get_service().io_control(this->get_implementation(), command, ec);
341     ASIO_SYNC_OP_VOID_RETURN(ec);
342   }
343 
344   /// Gets the non-blocking mode of the descriptor.
345   /**
346    * @returns @c true if the descriptor's synchronous operations will fail with
347    * asio::error::would_block if they are unable to perform the requested
348    * operation immediately. If @c false, synchronous operations will block
349    * until complete.
350    *
351    * @note The non-blocking mode has no effect on the behaviour of asynchronous
352    * operations. Asynchronous operations will never fail with the error
353    * asio::error::would_block.
354    */
non_blocking() const355   bool non_blocking() const
356   {
357     return this->get_service().non_blocking(this->get_implementation());
358   }
359 
360   /// Sets the non-blocking mode of the descriptor.
361   /**
362    * @param mode If @c true, the descriptor's synchronous operations will fail
363    * with asio::error::would_block if they are unable to perform the
364    * requested operation immediately. If @c false, synchronous operations will
365    * block until complete.
366    *
367    * @throws asio::system_error Thrown on failure.
368    *
369    * @note The non-blocking mode has no effect on the behaviour of asynchronous
370    * operations. Asynchronous operations will never fail with the error
371    * asio::error::would_block.
372    */
non_blocking(bool mode)373   void non_blocking(bool mode)
374   {
375     asio::error_code ec;
376     this->get_service().non_blocking(this->get_implementation(), mode, ec);
377     asio::detail::throw_error(ec, "non_blocking");
378   }
379 
380   /// Sets the non-blocking mode of the descriptor.
381   /**
382    * @param mode If @c true, the descriptor's synchronous operations will fail
383    * with asio::error::would_block if they are unable to perform the
384    * requested operation immediately. If @c false, synchronous operations will
385    * block until complete.
386    *
387    * @param ec Set to indicate what error occurred, if any.
388    *
389    * @note The non-blocking mode has no effect on the behaviour of asynchronous
390    * operations. Asynchronous operations will never fail with the error
391    * asio::error::would_block.
392    */
non_blocking(bool mode,asio::error_code & ec)393   ASIO_SYNC_OP_VOID non_blocking(
394       bool mode, asio::error_code& ec)
395   {
396     this->get_service().non_blocking(this->get_implementation(), mode, ec);
397     ASIO_SYNC_OP_VOID_RETURN(ec);
398   }
399 
400   /// Gets the non-blocking mode of the native descriptor implementation.
401   /**
402    * This function is used to retrieve the non-blocking mode of the underlying
403    * native descriptor. This mode has no effect on the behaviour of the
404    * descriptor object's synchronous operations.
405    *
406    * @returns @c true if the underlying descriptor is in non-blocking mode and
407    * direct system calls may fail with asio::error::would_block (or the
408    * equivalent system error).
409    *
410    * @note The current non-blocking mode is cached by the descriptor object.
411    * Consequently, the return value may be incorrect if the non-blocking mode
412    * was set directly on the native descriptor.
413    */
native_non_blocking() const414   bool native_non_blocking() const
415   {
416     return this->get_service().native_non_blocking(
417         this->get_implementation());
418   }
419 
420   /// Sets the non-blocking mode of the native descriptor implementation.
421   /**
422    * This function is used to modify the non-blocking mode of the underlying
423    * native descriptor. It has no effect on the behaviour of the descriptor
424    * object's synchronous operations.
425    *
426    * @param mode If @c true, the underlying descriptor is put into non-blocking
427    * mode and direct system calls may fail with asio::error::would_block
428    * (or the equivalent system error).
429    *
430    * @throws asio::system_error Thrown on failure. If the @c mode is
431    * @c false, but the current value of @c non_blocking() is @c true, this
432    * function fails with asio::error::invalid_argument, as the
433    * combination does not make sense.
434    */
native_non_blocking(bool mode)435   void native_non_blocking(bool mode)
436   {
437     asio::error_code ec;
438     this->get_service().native_non_blocking(
439         this->get_implementation(), mode, ec);
440     asio::detail::throw_error(ec, "native_non_blocking");
441   }
442 
443   /// Sets the non-blocking mode of the native descriptor implementation.
444   /**
445    * This function is used to modify the non-blocking mode of the underlying
446    * native descriptor. It has no effect on the behaviour of the descriptor
447    * object's synchronous operations.
448    *
449    * @param mode If @c true, the underlying descriptor is put into non-blocking
450    * mode and direct system calls may fail with asio::error::would_block
451    * (or the equivalent system error).
452    *
453    * @param ec Set to indicate what error occurred, if any. If the @c mode is
454    * @c false, but the current value of @c non_blocking() is @c true, this
455    * function fails with asio::error::invalid_argument, as the
456    * combination does not make sense.
457    */
native_non_blocking(bool mode,asio::error_code & ec)458   ASIO_SYNC_OP_VOID native_non_blocking(
459       bool mode, asio::error_code& ec)
460   {
461     this->get_service().native_non_blocking(
462         this->get_implementation(), mode, ec);
463     ASIO_SYNC_OP_VOID_RETURN(ec);
464   }
465 
466   /// Wait for the descriptor to become ready to read, ready to write, or to
467   /// have pending error conditions.
468   /**
469    * This function is used to perform a blocking wait for a descriptor to enter
470    * a ready to read, write or error condition state.
471    *
472    * @param w Specifies the desired descriptor state.
473    *
474    * @par Example
475    * Waiting for a descriptor to become readable.
476    * @code
477    * asio::posix::stream_descriptor descriptor(io_context);
478    * ...
479    * descriptor.wait(asio::posix::stream_descriptor::wait_read);
480    * @endcode
481    */
wait(wait_type w)482   void wait(wait_type w)
483   {
484     asio::error_code ec;
485     this->get_service().wait(this->get_implementation(), w, ec);
486     asio::detail::throw_error(ec, "wait");
487   }
488 
489   /// Wait for the descriptor to become ready to read, ready to write, or to
490   /// have pending error conditions.
491   /**
492    * This function is used to perform a blocking wait for a descriptor to enter
493    * a ready to read, write or error condition state.
494    *
495    * @param w Specifies the desired descriptor state.
496    *
497    * @param ec Set to indicate what error occurred, if any.
498    *
499    * @par Example
500    * Waiting for a descriptor to become readable.
501    * @code
502    * asio::posix::stream_descriptor descriptor(io_context);
503    * ...
504    * asio::error_code ec;
505    * descriptor.wait(asio::posix::stream_descriptor::wait_read, ec);
506    * @endcode
507    */
wait(wait_type w,asio::error_code & ec)508   ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec)
509   {
510     this->get_service().wait(this->get_implementation(), w, ec);
511     ASIO_SYNC_OP_VOID_RETURN(ec);
512   }
513 
514   /// Asynchronously wait for the descriptor to become ready to read, ready to
515   /// write, or to have pending error conditions.
516   /**
517    * This function is used to perform an asynchronous wait for a descriptor to
518    * enter a ready to read, write or error condition state.
519    *
520    * @param w Specifies the desired descriptor state.
521    *
522    * @param handler The handler to be called when the wait operation completes.
523    * Copies will be made of the handler as required. The function signature of
524    * the handler must be:
525    * @code void handler(
526    *   const asio::error_code& error // Result of operation
527    * ); @endcode
528    * Regardless of whether the asynchronous operation completes immediately or
529    * not, the handler will not be invoked from within this function. Invocation
530    * of the handler will be performed in a manner equivalent to using
531    * asio::io_context::post().
532    *
533    * @par Example
534    * @code
535    * void wait_handler(const asio::error_code& error)
536    * {
537    *   if (!error)
538    *   {
539    *     // Wait succeeded.
540    *   }
541    * }
542    *
543    * ...
544    *
545    * asio::posix::stream_descriptor descriptor(io_context);
546    * ...
547    * descriptor.async_wait(
548    *     asio::posix::stream_descriptor::wait_read,
549    *     wait_handler);
550    * @endcode
551    */
552   template <typename WaitHandler>
ASIO_INITFN_RESULT_TYPE(WaitHandler,void (asio::error_code))553   ASIO_INITFN_RESULT_TYPE(WaitHandler,
554       void (asio::error_code))
555   async_wait(wait_type w, ASIO_MOVE_ARG(WaitHandler) handler)
556   {
557     // If you get an error on the following line it means that your handler does
558     // not meet the documented type requirements for a WaitHandler.
559     ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
560 
561     return this->get_service().async_wait(this->get_implementation(),
562         w, ASIO_MOVE_CAST(WaitHandler)(handler));
563   }
564 
565 protected:
566   /// Protected destructor to prevent deletion through this type.
~basic_descriptor()567   ~basic_descriptor()
568   {
569   }
570 };
571 
572 } // namespace posix
573 } // namespace asio
574 
575 #include "asio/detail/pop_options.hpp"
576 
577 #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
578        //   || defined(GENERATING_DOCUMENTATION)
579 
580 #endif // defined(ASIO_ENABLE_OLD_SERVICES)
581 
582 #endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP
583