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

source code of boost/libs/asio/include/boost/asio/posix/basic_stream_descriptor.hpp