1 // 2 // posix/basic_descriptor.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2016 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 ASIO_POSIX_BASIC_DESCRIPTOR_HPP 12 #define ASIO_POSIX_BASIC_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 "asio/detail/config.hpp" 19 20 #if defined(ASIO_ENABLE_OLD_SERVICES) 21 22 #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ 23 || defined(GENERATING_DOCUMENTATION) 24 25 #include "asio/basic_io_object.hpp" 26 #include "asio/detail/throw_error.hpp" 27 #include "asio/error.hpp" 28 #include "asio/posix/descriptor_base.hpp" 29 30 #include "asio/detail/push_options.hpp" 31 32 namespace asio { 33 namespace posix { 34 35 /// Provides POSIX descriptor functionality. 36 /** 37 * The posix::basic_descriptor class template provides the ability to wrap a 38 * POSIX descriptor. 39 * 40 * @par Thread Safety 41 * @e Distinct @e objects: Safe.@n 42 * @e Shared @e objects: Unsafe. 43 */ 44 template <typename DescriptorService> 45 class basic_descriptor 46 : public basic_io_object<DescriptorService>, 47 public descriptor_base 48 { 49 public: 50 /// The native representation of a descriptor. 51 typedef typename DescriptorService::native_handle_type native_handle_type; 52 53 /// A basic_descriptor is always the lowest layer. 54 typedef basic_descriptor<DescriptorService> lowest_layer_type; 55 56 /// Construct a basic_descriptor without opening it. 57 /** 58 * This constructor creates a descriptor without opening it. 59 * 60 * @param io_context The io_context object that the descriptor will use to 61 * dispatch handlers for any asynchronous operations performed on the 62 * descriptor. 63 */ basic_descriptor(asio::io_context & io_context)64 explicit basic_descriptor(asio::io_context& io_context) 65 : basic_io_object<DescriptorService>(io_context) 66 { 67 } 68 69 /// Construct a basic_descriptor on an existing native descriptor. 70 /** 71 * This constructor creates a descriptor object to hold an existing native 72 * descriptor. 73 * 74 * @param io_context The io_context object that the descriptor will use to 75 * dispatch handlers for any asynchronous operations performed on the 76 * descriptor. 77 * 78 * @param native_descriptor A native descriptor. 79 * 80 * @throws asio::system_error Thrown on failure. 81 */ basic_descriptor(asio::io_context & io_context,const native_handle_type & native_descriptor)82 basic_descriptor(asio::io_context& io_context, 83 const native_handle_type& native_descriptor) 84 : basic_io_object<DescriptorService>(io_context) 85 { 86 asio::error_code ec; 87 this->get_service().assign(this->get_implementation(), 88 native_descriptor, ec); 89 asio::detail::throw_error(ec, "assign"); 90 } 91 92 #if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) 93 /// Move-construct a basic_descriptor from another. 94 /** 95 * This constructor moves a descriptor from one object to another. 96 * 97 * @param other The other basic_descriptor object from which the move will 98 * occur. 99 * 100 * @note Following the move, the moved-from object is in the same state as if 101 * constructed using the @c basic_descriptor(io_context&) constructor. 102 */ basic_descriptor(basic_descriptor && other)103 basic_descriptor(basic_descriptor&& other) 104 : basic_io_object<DescriptorService>( 105 ASIO_MOVE_CAST(basic_descriptor)(other)) 106 { 107 } 108 109 /// Move-assign a basic_descriptor from another. 110 /** 111 * This assignment operator moves a descriptor from one object to another. 112 * 113 * @param other The other basic_descriptor object from which the move will 114 * occur. 115 * 116 * @note Following the move, the moved-from object is in the same state as if 117 * constructed using the @c basic_descriptor(io_context&) constructor. 118 */ operator =(basic_descriptor && other)119 basic_descriptor& operator=(basic_descriptor&& other) 120 { 121 basic_io_object<DescriptorService>::operator=( 122 ASIO_MOVE_CAST(basic_descriptor)(other)); 123 return *this; 124 } 125 #endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) 126 127 /// Get a reference to the lowest layer. 128 /** 129 * This function returns a reference to the lowest layer in a stack of 130 * layers. Since a basic_descriptor cannot contain any further layers, it 131 * simply returns a reference to itself. 132 * 133 * @return A reference to the lowest layer in the stack of layers. Ownership 134 * is not transferred to the caller. 135 */ lowest_layer()136 lowest_layer_type& lowest_layer() 137 { 138 return *this; 139 } 140 141 /// Get a const reference to the lowest layer. 142 /** 143 * This function returns a const reference to the lowest layer in a stack of 144 * layers. Since a basic_descriptor cannot contain any further layers, it 145 * simply returns a reference to itself. 146 * 147 * @return A const reference to the lowest layer in the stack of layers. 148 * Ownership is not transferred to the caller. 149 */ lowest_layer() const150 const lowest_layer_type& lowest_layer() const 151 { 152 return *this; 153 } 154 155 /// Assign an existing native descriptor to the descriptor. 156 /* 157 * This function opens the descriptor to hold an existing native descriptor. 158 * 159 * @param native_descriptor A native descriptor. 160 * 161 * @throws asio::system_error Thrown on failure. 162 */ assign(const native_handle_type & native_descriptor)163 void assign(const native_handle_type& native_descriptor) 164 { 165 asio::error_code ec; 166 this->get_service().assign(this->get_implementation(), 167 native_descriptor, ec); 168 asio::detail::throw_error(ec, "assign"); 169 } 170 171 /// Assign an existing native descriptor to the descriptor. 172 /* 173 * This function opens the descriptor to hold an existing native descriptor. 174 * 175 * @param native_descriptor A native descriptor. 176 * 177 * @param ec Set to indicate what error occurred, if any. 178 */ assign(const native_handle_type & native_descriptor,asio::error_code & ec)179 ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor, 180 asio::error_code& ec) 181 { 182 this->get_service().assign( 183 this->get_implementation(), native_descriptor, ec); 184 ASIO_SYNC_OP_VOID_RETURN(ec); 185 } 186 187 /// Determine whether the descriptor is open. is_open() const188 bool is_open() const 189 { 190 return this->get_service().is_open(this->get_implementation()); 191 } 192 193 /// Close the descriptor. 194 /** 195 * This function is used to close the descriptor. Any asynchronous read or 196 * write operations will be cancelled immediately, and will complete with the 197 * asio::error::operation_aborted error. 198 * 199 * @throws asio::system_error Thrown on failure. Note that, even if 200 * the function indicates an error, the underlying descriptor is closed. 201 */ close()202 void close() 203 { 204 asio::error_code ec; 205 this->get_service().close(this->get_implementation(), ec); 206 asio::detail::throw_error(ec, "close"); 207 } 208 209 /// Close the descriptor. 210 /** 211 * This function is used to close the descriptor. Any asynchronous read or 212 * write operations will be cancelled immediately, and will complete with the 213 * asio::error::operation_aborted error. 214 * 215 * @param ec Set to indicate what error occurred, if any. Note that, even if 216 * the function indicates an error, the underlying descriptor is closed. 217 */ close(asio::error_code & ec)218 ASIO_SYNC_OP_VOID close(asio::error_code& ec) 219 { 220 this->get_service().close(this->get_implementation(), ec); 221 ASIO_SYNC_OP_VOID_RETURN(ec); 222 } 223 224 /// Get the native descriptor representation. 225 /** 226 * This function may be used to obtain the underlying representation of the 227 * descriptor. This is intended to allow access to native descriptor 228 * functionality that is not otherwise provided. 229 */ native_handle()230 native_handle_type native_handle() 231 { 232 return this->get_service().native_handle(this->get_implementation()); 233 } 234 235 /// Release ownership of the native descriptor implementation. 236 /** 237 * This function may be used to obtain the underlying representation of the 238 * descriptor. After calling this function, @c is_open() returns false. The 239 * caller is responsible for closing the descriptor. 240 * 241 * All outstanding asynchronous read or write operations will finish 242 * immediately, and the handlers for cancelled operations will be passed the 243 * asio::error::operation_aborted error. 244 */ release()245 native_handle_type release() 246 { 247 return this->get_service().release(this->get_implementation()); 248 } 249 250 /// Cancel all asynchronous operations associated with the descriptor. 251 /** 252 * This function causes all outstanding asynchronous read or write operations 253 * to finish immediately, and the handlers for cancelled operations will be 254 * passed the asio::error::operation_aborted error. 255 * 256 * @throws asio::system_error Thrown on failure. 257 */ cancel()258 void cancel() 259 { 260 asio::error_code ec; 261 this->get_service().cancel(this->get_implementation(), ec); 262 asio::detail::throw_error(ec, "cancel"); 263 } 264 265 /// Cancel all asynchronous operations associated with the descriptor. 266 /** 267 * This function causes all outstanding asynchronous read or write operations 268 * to finish immediately, and the handlers for cancelled operations will be 269 * passed the asio::error::operation_aborted error. 270 * 271 * @param ec Set to indicate what error occurred, if any. 272 */ cancel(asio::error_code & ec)273 ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) 274 { 275 this->get_service().cancel(this->get_implementation(), ec); 276 ASIO_SYNC_OP_VOID_RETURN(ec); 277 } 278 279 /// Perform an IO control command on the descriptor. 280 /** 281 * This function is used to execute an IO control command on the descriptor. 282 * 283 * @param command The IO control command to be performed on the descriptor. 284 * 285 * @throws asio::system_error Thrown on failure. 286 * 287 * @sa IoControlCommand @n 288 * asio::posix::descriptor_base::bytes_readable @n 289 * asio::posix::descriptor_base::non_blocking_io 290 * 291 * @par Example 292 * Getting the number of bytes ready to read: 293 * @code 294 * asio::posix::stream_descriptor descriptor(io_context); 295 * ... 296 * asio::posix::stream_descriptor::bytes_readable command; 297 * descriptor.io_control(command); 298 * std::size_t bytes_readable = command.get(); 299 * @endcode 300 */ 301 template <typename IoControlCommand> io_control(IoControlCommand & command)302 void io_control(IoControlCommand& command) 303 { 304 asio::error_code ec; 305 this->get_service().io_control(this->get_implementation(), command, ec); 306 asio::detail::throw_error(ec, "io_control"); 307 } 308 309 /// Perform an IO control command on the descriptor. 310 /** 311 * This function is used to execute an IO control command on the descriptor. 312 * 313 * @param command The IO control command to be performed on the descriptor. 314 * 315 * @param ec Set to indicate what error occurred, if any. 316 * 317 * @sa IoControlCommand @n 318 * asio::posix::descriptor_base::bytes_readable @n 319 * asio::posix::descriptor_base::non_blocking_io 320 * 321 * @par Example 322 * Getting the number of bytes ready to read: 323 * @code 324 * asio::posix::stream_descriptor descriptor(io_context); 325 * ... 326 * asio::posix::stream_descriptor::bytes_readable command; 327 * asio::error_code ec; 328 * descriptor.io_control(command, ec); 329 * if (ec) 330 * { 331 * // An error occurred. 332 * } 333 * std::size_t bytes_readable = command.get(); 334 * @endcode 335 */ 336 template <typename IoControlCommand> io_control(IoControlCommand & command,asio::error_code & ec)337 ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, 338 asio::error_code& ec) 339 { 340 this->get_service().io_control(this->get_implementation(), command, ec); 341 ASIO_SYNC_OP_VOID_RETURN(ec); 342 } 343 344 /// Gets the non-blocking mode of the descriptor. 345 /** 346 * @returns @c true if the descriptor's synchronous operations will fail with 347 * asio::error::would_block if they are unable to perform the requested 348 * operation immediately. If @c false, synchronous operations will block 349 * until complete. 350 * 351 * @note The non-blocking mode has no effect on the behaviour of asynchronous 352 * operations. Asynchronous operations will never fail with the error 353 * asio::error::would_block. 354 */ non_blocking() const355 bool non_blocking() const 356 { 357 return this->get_service().non_blocking(this->get_implementation()); 358 } 359 360 /// Sets the non-blocking mode of the descriptor. 361 /** 362 * @param mode If @c true, the descriptor's synchronous operations will fail 363 * with asio::error::would_block if they are unable to perform the 364 * requested operation immediately. If @c false, synchronous operations will 365 * block until complete. 366 * 367 * @throws asio::system_error Thrown on failure. 368 * 369 * @note The non-blocking mode has no effect on the behaviour of asynchronous 370 * operations. Asynchronous operations will never fail with the error 371 * asio::error::would_block. 372 */ non_blocking(bool mode)373 void non_blocking(bool mode) 374 { 375 asio::error_code ec; 376 this->get_service().non_blocking(this->get_implementation(), mode, ec); 377 asio::detail::throw_error(ec, "non_blocking"); 378 } 379 380 /// Sets the non-blocking mode of the descriptor. 381 /** 382 * @param mode If @c true, the descriptor's synchronous operations will fail 383 * with asio::error::would_block if they are unable to perform the 384 * requested operation immediately. If @c false, synchronous operations will 385 * block until complete. 386 * 387 * @param ec Set to indicate what error occurred, if any. 388 * 389 * @note The non-blocking mode has no effect on the behaviour of asynchronous 390 * operations. Asynchronous operations will never fail with the error 391 * asio::error::would_block. 392 */ non_blocking(bool mode,asio::error_code & ec)393 ASIO_SYNC_OP_VOID non_blocking( 394 bool mode, asio::error_code& ec) 395 { 396 this->get_service().non_blocking(this->get_implementation(), mode, ec); 397 ASIO_SYNC_OP_VOID_RETURN(ec); 398 } 399 400 /// Gets the non-blocking mode of the native descriptor implementation. 401 /** 402 * This function is used to retrieve the non-blocking mode of the underlying 403 * native descriptor. This mode has no effect on the behaviour of the 404 * descriptor object's synchronous operations. 405 * 406 * @returns @c true if the underlying descriptor is in non-blocking mode and 407 * direct system calls may fail with asio::error::would_block (or the 408 * equivalent system error). 409 * 410 * @note The current non-blocking mode is cached by the descriptor object. 411 * Consequently, the return value may be incorrect if the non-blocking mode 412 * was set directly on the native descriptor. 413 */ native_non_blocking() const414 bool native_non_blocking() const 415 { 416 return this->get_service().native_non_blocking( 417 this->get_implementation()); 418 } 419 420 /// Sets the non-blocking mode of the native descriptor implementation. 421 /** 422 * This function is used to modify the non-blocking mode of the underlying 423 * native descriptor. It has no effect on the behaviour of the descriptor 424 * object's synchronous operations. 425 * 426 * @param mode If @c true, the underlying descriptor is put into non-blocking 427 * mode and direct system calls may fail with asio::error::would_block 428 * (or the equivalent system error). 429 * 430 * @throws asio::system_error Thrown on failure. If the @c mode is 431 * @c false, but the current value of @c non_blocking() is @c true, this 432 * function fails with asio::error::invalid_argument, as the 433 * combination does not make sense. 434 */ native_non_blocking(bool mode)435 void native_non_blocking(bool mode) 436 { 437 asio::error_code ec; 438 this->get_service().native_non_blocking( 439 this->get_implementation(), mode, ec); 440 asio::detail::throw_error(ec, "native_non_blocking"); 441 } 442 443 /// Sets the non-blocking mode of the native descriptor implementation. 444 /** 445 * This function is used to modify the non-blocking mode of the underlying 446 * native descriptor. It has no effect on the behaviour of the descriptor 447 * object's synchronous operations. 448 * 449 * @param mode If @c true, the underlying descriptor is put into non-blocking 450 * mode and direct system calls may fail with asio::error::would_block 451 * (or the equivalent system error). 452 * 453 * @param ec Set to indicate what error occurred, if any. If the @c mode is 454 * @c false, but the current value of @c non_blocking() is @c true, this 455 * function fails with asio::error::invalid_argument, as the 456 * combination does not make sense. 457 */ native_non_blocking(bool mode,asio::error_code & ec)458 ASIO_SYNC_OP_VOID native_non_blocking( 459 bool mode, asio::error_code& ec) 460 { 461 this->get_service().native_non_blocking( 462 this->get_implementation(), mode, ec); 463 ASIO_SYNC_OP_VOID_RETURN(ec); 464 } 465 466 /// Wait for the descriptor to become ready to read, ready to write, or to 467 /// have pending error conditions. 468 /** 469 * This function is used to perform a blocking wait for a descriptor to enter 470 * a ready to read, write or error condition state. 471 * 472 * @param w Specifies the desired descriptor state. 473 * 474 * @par Example 475 * Waiting for a descriptor to become readable. 476 * @code 477 * asio::posix::stream_descriptor descriptor(io_context); 478 * ... 479 * descriptor.wait(asio::posix::stream_descriptor::wait_read); 480 * @endcode 481 */ wait(wait_type w)482 void wait(wait_type w) 483 { 484 asio::error_code ec; 485 this->get_service().wait(this->get_implementation(), w, ec); 486 asio::detail::throw_error(ec, "wait"); 487 } 488 489 /// Wait for the descriptor to become ready to read, ready to write, or to 490 /// have pending error conditions. 491 /** 492 * This function is used to perform a blocking wait for a descriptor to enter 493 * a ready to read, write or error condition state. 494 * 495 * @param w Specifies the desired descriptor state. 496 * 497 * @param ec Set to indicate what error occurred, if any. 498 * 499 * @par Example 500 * Waiting for a descriptor to become readable. 501 * @code 502 * asio::posix::stream_descriptor descriptor(io_context); 503 * ... 504 * asio::error_code ec; 505 * descriptor.wait(asio::posix::stream_descriptor::wait_read, ec); 506 * @endcode 507 */ wait(wait_type w,asio::error_code & ec)508 ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec) 509 { 510 this->get_service().wait(this->get_implementation(), w, ec); 511 ASIO_SYNC_OP_VOID_RETURN(ec); 512 } 513 514 /// Asynchronously wait for the descriptor to become ready to read, ready to 515 /// write, or to have pending error conditions. 516 /** 517 * This function is used to perform an asynchronous wait for a descriptor to 518 * enter a ready to read, write or error condition state. 519 * 520 * @param w Specifies the desired descriptor state. 521 * 522 * @param handler The handler to be called when the wait operation completes. 523 * Copies will be made of the handler as required. The function signature of 524 * the handler must be: 525 * @code void handler( 526 * const asio::error_code& error // Result of operation 527 * ); @endcode 528 * Regardless of whether the asynchronous operation completes immediately or 529 * not, the handler will not be invoked from within this function. Invocation 530 * of the handler will be performed in a manner equivalent to using 531 * asio::io_context::post(). 532 * 533 * @par Example 534 * @code 535 * void wait_handler(const asio::error_code& error) 536 * { 537 * if (!error) 538 * { 539 * // Wait succeeded. 540 * } 541 * } 542 * 543 * ... 544 * 545 * asio::posix::stream_descriptor descriptor(io_context); 546 * ... 547 * descriptor.async_wait( 548 * asio::posix::stream_descriptor::wait_read, 549 * wait_handler); 550 * @endcode 551 */ 552 template <typename WaitHandler> ASIO_INITFN_RESULT_TYPE(WaitHandler,void (asio::error_code))553 ASIO_INITFN_RESULT_TYPE(WaitHandler, 554 void (asio::error_code)) 555 async_wait(wait_type w, ASIO_MOVE_ARG(WaitHandler) handler) 556 { 557 // If you get an error on the following line it means that your handler does 558 // not meet the documented type requirements for a WaitHandler. 559 ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; 560 561 return this->get_service().async_wait(this->get_implementation(), 562 w, ASIO_MOVE_CAST(WaitHandler)(handler)); 563 } 564 565 protected: 566 /// Protected destructor to prevent deletion through this type. ~basic_descriptor()567 ~basic_descriptor() 568 { 569 } 570 }; 571 572 } // namespace posix 573 } // namespace asio 574 575 #include "asio/detail/pop_options.hpp" 576 577 #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) 578 // || defined(GENERATING_DOCUMENTATION) 579 580 #endif // defined(ASIO_ENABLE_OLD_SERVICES) 581 582 #endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP 583