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