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