1 //
2 // windows/basic_object_handle.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 // Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
7 //
8 // Distributed under the Boost Software License, Version 1.0. (See accompanying
9 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10 //
11 
12 #ifndef ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP
13 #define ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP
14 
15 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 # pragma once
17 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 
19 #include "asio/detail/config.hpp"
20 
21 #if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) \
22   || defined(GENERATING_DOCUMENTATION)
23 
24 #include "asio/async_result.hpp"
25 #include "asio/detail/io_object_impl.hpp"
26 #include "asio/detail/throw_error.hpp"
27 #include "asio/detail/win_object_handle_service.hpp"
28 #include "asio/error.hpp"
29 #include "asio/execution_context.hpp"
30 #include "asio/executor.hpp"
31 
32 #if defined(ASIO_HAS_MOVE)
33 # include <utility>
34 #endif // defined(ASIO_HAS_MOVE)
35 
36 #include "asio/detail/push_options.hpp"
37 
38 namespace asio {
39 namespace windows {
40 
41 /// Provides object-oriented handle functionality.
42 /**
43  * The windows::basic_object_handle class provides asynchronous and blocking
44  * object-oriented handle functionality.
45  *
46  * @par Thread Safety
47  * @e Distinct @e objects: Safe.@n
48  * @e Shared @e objects: Unsafe.
49  */
50 template <typename Executor = executor>
51 class basic_object_handle
52 {
53 public:
54   /// The type of the executor associated with the object.
55   typedef Executor executor_type;
56 
57   /// The native representation of a handle.
58 #if defined(GENERATING_DOCUMENTATION)
59   typedef implementation_defined native_handle_type;
60 #else
61   typedef asio::detail::win_object_handle_service::native_handle_type
62     native_handle_type;
63 #endif
64 
65   /// An object handle is always the lowest layer.
66   typedef basic_object_handle lowest_layer_type;
67 
68   /// Construct an object handle without opening it.
69   /**
70    * This constructor creates an object handle without opening it.
71    *
72    * @param ex The I/O executor that the object handle will use, by default, to
73    * dispatch handlers for any asynchronous operations performed on the
74    * object handle.
75    */
basic_object_handle(const executor_type & ex)76   explicit basic_object_handle(const executor_type& ex)
77     : impl_(ex)
78   {
79   }
80 
81   /// Construct an object handle without opening it.
82   /**
83    * This constructor creates an object handle without opening it.
84    *
85    * @param context An execution context which provides the I/O executor that
86    * the object handle will use, by default, to dispatch handlers for any
87    * asynchronous operations performed on the object handle.
88    */
89   template <typename ExecutionContext>
basic_object_handle(ExecutionContext & context,typename enable_if<is_convertible<ExecutionContext &,execution_context &>::value,basic_object_handle>::type * =0)90   explicit basic_object_handle(ExecutionContext& context,
91       typename enable_if<
92         is_convertible<ExecutionContext&, execution_context&>::value,
93         basic_object_handle
94       >::type* = 0)
95     : impl_(context)
96   {
97   }
98 
99   /// Construct an object handle on an existing native handle.
100   /**
101    * This constructor creates an object handle object to hold an existing native
102    * handle.
103    *
104    * @param ex The I/O executor that the object handle will use, by default, to
105    * dispatch handlers for any asynchronous operations performed on the
106    * object handle.
107    *
108    * @param native_handle The new underlying handle implementation.
109    *
110    * @throws asio::system_error Thrown on failure.
111    */
basic_object_handle(const executor_type & ex,const native_handle_type & native_handle)112   basic_object_handle(const executor_type& ex,
113       const native_handle_type& native_handle)
114     : impl_(ex)
115   {
116     asio::error_code ec;
117     impl_.get_service().assign(impl_.get_implementation(), native_handle, ec);
118     asio::detail::throw_error(ec, "assign");
119   }
120 
121   /// Construct an object handle on an existing native handle.
122   /**
123    * This constructor creates an object handle object to hold an existing native
124    * handle.
125    *
126    * @param context An execution context which provides the I/O executor that
127    * the object handle will use, by default, to dispatch handlers for any
128    * asynchronous operations performed on the object handle.
129    *
130    * @param native_handle The new underlying handle implementation.
131    *
132    * @throws asio::system_error Thrown on failure.
133    */
134   template <typename ExecutionContext>
basic_object_handle(ExecutionContext & context,const native_handle_type & native_handle,typename enable_if<is_convertible<ExecutionContext &,execution_context &>::value>::type * =0)135   basic_object_handle(ExecutionContext& context,
136       const native_handle_type& native_handle,
137       typename enable_if<
138         is_convertible<ExecutionContext&, execution_context&>::value
139       >::type* = 0)
140     : impl_(context)
141   {
142     asio::error_code ec;
143     impl_.get_service().assign(impl_.get_implementation(), native_handle, ec);
144     asio::detail::throw_error(ec, "assign");
145   }
146 
147 #if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
148   /// Move-construct an object handle from another.
149   /**
150    * This constructor moves an object handle from one object to another.
151    *
152    * @param other The other object handle object from which the move will
153    * occur.
154    *
155    * @note Following the move, the moved-from object is in the same state as if
156    * constructed using the @c basic_object_handle(const executor_type&)
157    * constructor.
158    */
basic_object_handle(basic_object_handle && other)159   basic_object_handle(basic_object_handle&& other)
160     : impl_(std::move(other.impl_))
161   {
162   }
163 
164   /// Move-assign an object handle from another.
165   /**
166    * This assignment operator moves an object handle from one object to another.
167    *
168    * @param other The other object handle object from which the move will
169    * occur.
170    *
171    * @note Following the move, the moved-from object is in the same state as if
172    * constructed using the @c basic_object_handle(const executor_type&)
173    * constructor.
174    */
operator =(basic_object_handle && other)175   basic_object_handle& operator=(basic_object_handle&& other)
176   {
177     impl_ = std::move(other.impl_);
178     return *this;
179   }
180 #endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
181 
182   /// Get the executor associated with the object.
get_executor()183   executor_type get_executor() ASIO_NOEXCEPT
184   {
185     return impl_.get_executor();
186   }
187 
188   /// Get a reference to the lowest layer.
189   /**
190    * This function returns a reference to the lowest layer in a stack of
191    * layers. Since an object handle cannot contain any further layers, it simply
192    * returns a reference to itself.
193    *
194    * @return A reference to the lowest layer in the stack of layers. Ownership
195    * is not transferred to the caller.
196    */
lowest_layer()197   lowest_layer_type& lowest_layer()
198   {
199     return *this;
200   }
201 
202   /// Get a const reference to the lowest layer.
203   /**
204    * This function returns a const reference to the lowest layer in a stack of
205    * layers. Since an object handle cannot contain any further layers, it simply
206    * returns a reference to itself.
207    *
208    * @return A const reference to the lowest layer in the stack of layers.
209    * Ownership is not transferred to the caller.
210    */
lowest_layer() const211   const lowest_layer_type& lowest_layer() const
212   {
213     return *this;
214   }
215 
216   /// Assign an existing native handle to the handle.
217   /*
218    * This function opens the handle to hold an existing native handle.
219    *
220    * @param handle A native handle.
221    *
222    * @throws asio::system_error Thrown on failure.
223    */
assign(const native_handle_type & handle)224   void assign(const native_handle_type& handle)
225   {
226     asio::error_code ec;
227     impl_.get_service().assign(impl_.get_implementation(), handle, ec);
228     asio::detail::throw_error(ec, "assign");
229   }
230 
231   /// Assign an existing native handle to the handle.
232   /*
233    * This function opens the handle to hold an existing native handle.
234    *
235    * @param handle A native handle.
236    *
237    * @param ec Set to indicate what error occurred, if any.
238    */
assign(const native_handle_type & handle,asio::error_code & ec)239   ASIO_SYNC_OP_VOID assign(const native_handle_type& handle,
240       asio::error_code& ec)
241   {
242     impl_.get_service().assign(impl_.get_implementation(), handle, ec);
243     ASIO_SYNC_OP_VOID_RETURN(ec);
244   }
245 
246   /// Determine whether the handle is open.
is_open() const247   bool is_open() const
248   {
249     return impl_.get_service().is_open(impl_.get_implementation());
250   }
251 
252   /// Close the handle.
253   /**
254    * This function is used to close the handle. Any asynchronous read or write
255    * operations will be cancelled immediately, and will complete with the
256    * asio::error::operation_aborted error.
257    *
258    * @throws asio::system_error Thrown on failure.
259    */
close()260   void close()
261   {
262     asio::error_code ec;
263     impl_.get_service().close(impl_.get_implementation(), ec);
264     asio::detail::throw_error(ec, "close");
265   }
266 
267   /// Close the handle.
268   /**
269    * This function is used to close the handle. Any asynchronous read or write
270    * operations will be cancelled immediately, and will complete with the
271    * asio::error::operation_aborted error.
272    *
273    * @param ec Set to indicate what error occurred, if any.
274    */
close(asio::error_code & ec)275   ASIO_SYNC_OP_VOID close(asio::error_code& ec)
276   {
277     impl_.get_service().close(impl_.get_implementation(), ec);
278     ASIO_SYNC_OP_VOID_RETURN(ec);
279   }
280 
281   /// Get the native handle representation.
282   /**
283    * This function may be used to obtain the underlying representation of the
284    * handle. This is intended to allow access to native handle functionality
285    * that is not otherwise provided.
286    */
native_handle()287   native_handle_type native_handle()
288   {
289     return impl_.get_service().native_handle(impl_.get_implementation());
290   }
291 
292   /// Cancel all asynchronous operations associated with the handle.
293   /**
294    * This function causes all outstanding asynchronous read or write operations
295    * to finish immediately, and the handlers for cancelled operations will be
296    * passed the asio::error::operation_aborted error.
297    *
298    * @throws asio::system_error Thrown on failure.
299    */
cancel()300   void cancel()
301   {
302     asio::error_code ec;
303     impl_.get_service().cancel(impl_.get_implementation(), ec);
304     asio::detail::throw_error(ec, "cancel");
305   }
306 
307   /// Cancel all asynchronous operations associated with the handle.
308   /**
309    * This function causes all outstanding asynchronous read or write operations
310    * to finish immediately, and the handlers for cancelled operations will be
311    * passed the asio::error::operation_aborted error.
312    *
313    * @param ec Set to indicate what error occurred, if any.
314    */
cancel(asio::error_code & ec)315   ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
316   {
317     impl_.get_service().cancel(impl_.get_implementation(), ec);
318     ASIO_SYNC_OP_VOID_RETURN(ec);
319   }
320 
321   /// Perform a blocking wait on the object handle.
322   /**
323    * This function is used to wait for the object handle to be set to the
324    * signalled state. This function blocks and does not return until the object
325    * handle has been set to the signalled state.
326    *
327    * @throws asio::system_error Thrown on failure.
328    */
wait()329   void wait()
330   {
331     asio::error_code ec;
332     impl_.get_service().wait(impl_.get_implementation(), ec);
333     asio::detail::throw_error(ec, "wait");
334   }
335 
336   /// Perform a blocking wait on the object handle.
337   /**
338    * This function is used to wait for the object handle to be set to the
339    * signalled state. This function blocks and does not return until the object
340    * handle has been set to the signalled state.
341    *
342    * @param ec Set to indicate what error occurred, if any.
343    */
wait(asio::error_code & ec)344   void wait(asio::error_code& ec)
345   {
346     impl_.get_service().wait(impl_.get_implementation(), ec);
347   }
348 
349   /// Start an asynchronous wait on the object handle.
350   /**
351    * This function is be used to initiate an asynchronous wait against the
352    * object handle. It always returns immediately.
353    *
354    * @param handler The handler to be called when the object handle is set to
355    * the signalled state. Copies will be made of the handler as required. The
356    * function signature of the handler must be:
357    * @code void handler(
358    *   const asio::error_code& error // Result of operation.
359    * ); @endcode
360    * Regardless of whether the asynchronous operation completes immediately or
361    * not, the handler will not be invoked from within this function. On
362    * immediate completion, invocation of the handler will be performed in a
363    * manner equivalent to using asio::post().
364    */
365   template <typename WaitHandler>
ASIO_INITFN_RESULT_TYPE(WaitHandler,void (asio::error_code))366   ASIO_INITFN_RESULT_TYPE(WaitHandler,
367       void (asio::error_code))
368   async_wait(ASIO_MOVE_ARG(WaitHandler) handler)
369   {
370     asio::async_completion<WaitHandler,
371       void (asio::error_code)> init(handler);
372 
373     impl_.get_service().async_wait(impl_.get_implementation(),
374         init.completion_handler, impl_.get_implementation_executor());
375 
376     return init.result.get();
377   }
378 
379 private:
380   // Disallow copying and assignment.
381   basic_object_handle(const basic_object_handle&) ASIO_DELETED;
382   basic_object_handle& operator=(const basic_object_handle&) ASIO_DELETED;
383 
384   asio::detail::io_object_impl<
385     asio::detail::win_object_handle_service, Executor> impl_;
386 };
387 
388 } // namespace windows
389 } // namespace asio
390 
391 #include "asio/detail/pop_options.hpp"
392 
393 #endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
394        //   || defined(GENERATING_DOCUMENTATION)
395 
396 #endif // ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP
397