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