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
26namespace boost {
27namespace asio {
28namespace 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 */
42template <typename Executor = any_io_executor>
43class basic_stream_handle
44 : public basic_overlapped_handle<Executor>
45{
46private:
47 class initiate_async_write_some;
48 class initiate_async_read_some;
49
50public:
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
476private:
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

source code of boost/libs/asio/include/boost/asio/windows/basic_stream_handle.hpp