1 // 2 // impl/read.hpp 3 // ~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2015 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_IMPL_READ_HPP 12 #define ASIO_IMPL_READ_HPP 13 14 15 #include <algorithm> 16 #include "asio/buffer.hpp" 17 #include "asio/completion_condition.hpp" 18 #include "asio/detail/array_fwd.hpp" 19 #include "asio/detail/base_from_completion_cond.hpp" 20 #include "asio/detail/bind_handler.hpp" 21 #include "asio/detail/consuming_buffers.hpp" 22 #include "asio/detail/dependent_type.hpp" 23 #include "asio/detail/handler_alloc_helpers.hpp" 24 #include "asio/detail/handler_cont_helpers.hpp" 25 #include "asio/detail/handler_invoke_helpers.hpp" 26 #include "asio/detail/handler_type_requirements.hpp" 27 #include "asio/detail/throw_error.hpp" 28 #include "asio/error.hpp" 29 30 #include "asio/detail/push_options.hpp" 31 32 namespace asio { 33 34 template <typename SyncReadStream, typename MutableBufferSequence, 35 typename CompletionCondition> 36 std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, 37 CompletionCondition completion_condition, asio::error_code& ec) 38 { 39 ec = asio::error_code(); 40 asio::detail::consuming_buffers< 41 mutable_buffer, MutableBufferSequence> tmp(buffers); 42 std::size_t total_transferred = 0; 43 tmp.prepare(detail::adapt_completion_condition_result( 44 completion_condition(ec, total_transferred))); 45 while (tmp.begin() != tmp.end()) 46 { 47 std::size_t bytes_transferred = s.read_some(tmp, ec); 48 tmp.consume(bytes_transferred); 49 total_transferred += bytes_transferred; 50 tmp.prepare(detail::adapt_completion_condition_result( 51 completion_condition(ec, total_transferred))); 52 } 53 return total_transferred; 54 } 55 56 template <typename SyncReadStream, typename MutableBufferSequence> 57 inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers) 58 { 59 asio::error_code ec; 60 std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec); 61 asio::detail::throw_error(ec, "read"); 62 return bytes_transferred; 63 } 64 65 template <typename SyncReadStream, typename MutableBufferSequence> 66 inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, 67 asio::error_code& ec) 68 { 69 return read(s, buffers, transfer_all(), ec); 70 } 71 72 template <typename SyncReadStream, typename MutableBufferSequence, 73 typename CompletionCondition> 74 inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, 75 CompletionCondition completion_condition) 76 { 77 asio::error_code ec; 78 std::size_t bytes_transferred = read(s, buffers, completion_condition, ec); 79 asio::detail::throw_error(ec, "read"); 80 return bytes_transferred; 81 } 82 83 84 namespace detail 85 { 86 template <typename AsyncReadStream, typename MutableBufferSequence, 87 typename CompletionCondition, typename ReadHandler> 88 class read_op 89 : detail::base_from_completion_cond<CompletionCondition> 90 { 91 public: 92 read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, 93 CompletionCondition completion_condition, ReadHandler& handler) 94 : detail::base_from_completion_cond< 95 CompletionCondition>(completion_condition), 96 stream_(stream), 97 buffers_(buffers), 98 start_(0), 99 total_transferred_(0), 100 handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) 101 { 102 } 103 104 read_op(const read_op& other) 105 : detail::base_from_completion_cond<CompletionCondition>(other), 106 stream_(other.stream_), 107 buffers_(other.buffers_), 108 start_(other.start_), 109 total_transferred_(other.total_transferred_), 110 handler_(other.handler_) 111 { 112 } 113 114 read_op(read_op&& other) 115 : detail::base_from_completion_cond<CompletionCondition>(other), 116 stream_(other.stream_), 117 buffers_(other.buffers_), 118 start_(other.start_), 119 total_transferred_(other.total_transferred_), 120 handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) 121 { 122 } 123 124 void operator()(const asio::error_code& ec, 125 std::size_t bytes_transferred, int start = 0) 126 { 127 switch (start_ = start) 128 { 129 case 1: 130 buffers_.prepare(this->check_for_completion(ec, total_transferred_)); 131 for (;;) 132 { 133 stream_.async_read_some(buffers_, 134 ASIO_MOVE_CAST(read_op)(*this)); 135 return; default: 136 total_transferred_ += bytes_transferred; 137 buffers_.consume(bytes_transferred); 138 buffers_.prepare(this->check_for_completion(ec, total_transferred_)); 139 if ((!ec && bytes_transferred == 0) 140 || buffers_.begin() == buffers_.end()) 141 break; 142 } 143 144 handler_(ec, static_cast<const std::size_t&>(total_transferred_)); 145 } 146 } 147 148 //private: 149 AsyncReadStream& stream_; 150 asio::detail::consuming_buffers< 151 mutable_buffer, MutableBufferSequence> buffers_; 152 int start_; 153 std::size_t total_transferred_; 154 ReadHandler handler_; 155 }; 156 157 template <typename AsyncReadStream, 158 typename CompletionCondition, typename ReadHandler> 159 class read_op<AsyncReadStream, asio::mutable_buffers_1, 160 CompletionCondition, ReadHandler> 161 : detail::base_from_completion_cond<CompletionCondition> 162 { 163 public: 164 read_op(AsyncReadStream& stream, 165 const asio::mutable_buffers_1& buffers, 166 CompletionCondition completion_condition, ReadHandler& handler) 167 : detail::base_from_completion_cond< 168 CompletionCondition>(completion_condition), 169 stream_(stream), 170 buffer_(buffers), 171 start_(0), 172 total_transferred_(0), 173 handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) 174 { 175 } 176 177 read_op(const read_op& other) 178 : detail::base_from_completion_cond<CompletionCondition>(other), 179 stream_(other.stream_), 180 buffer_(other.buffer_), 181 start_(other.start_), 182 total_transferred_(other.total_transferred_), 183 handler_(other.handler_) 184 { 185 } 186 187 read_op(read_op&& other) 188 : detail::base_from_completion_cond<CompletionCondition>(other), 189 stream_(other.stream_), 190 buffer_(other.buffer_), 191 start_(other.start_), 192 total_transferred_(other.total_transferred_), 193 handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) 194 { 195 } 196 197 void operator()(const asio::error_code& ec, 198 std::size_t bytes_transferred, int start = 0) 199 { 200 std::size_t n = 0; 201 switch (start_ = start) 202 { 203 case 1: 204 n = this->check_for_completion(ec, total_transferred_); 205 for (;;) 206 { 207 stream_.async_read_some( 208 asio::buffer(buffer_ + total_transferred_, n), 209 ASIO_MOVE_CAST(read_op)(*this)); 210 return; default: 211 total_transferred_ += bytes_transferred; 212 if ((!ec && bytes_transferred == 0) 213 || (n = this->check_for_completion(ec, total_transferred_)) == 0 214 || total_transferred_ == asio::buffer_size(buffer_)) 215 break; 216 } 217 218 handler_(ec, static_cast<const std::size_t&>(total_transferred_)); 219 } 220 } 221 222 //private: 223 AsyncReadStream& stream_; 224 asio::mutable_buffer buffer_; 225 int start_; 226 std::size_t total_transferred_; 227 ReadHandler handler_; 228 }; 229 230 template <typename AsyncReadStream, typename Elem, 231 typename CompletionCondition, typename ReadHandler> 232 class read_op<AsyncReadStream, boost::array<Elem, 2>, 233 CompletionCondition, ReadHandler> 234 : detail::base_from_completion_cond<CompletionCondition> 235 { 236 public: 237 read_op(AsyncReadStream& stream, const boost::array<Elem, 2>& buffers, 238 CompletionCondition completion_condition, ReadHandler& handler) 239 : detail::base_from_completion_cond< 240 CompletionCondition>(completion_condition), 241 stream_(stream), 242 buffers_(buffers), 243 start_(0), 244 total_transferred_(0), 245 handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) 246 { 247 } 248 249 read_op(const read_op& other) 250 : detail::base_from_completion_cond<CompletionCondition>(other), 251 stream_(other.stream_), 252 buffers_(other.buffers_), 253 start_(other.start_), 254 total_transferred_(other.total_transferred_), 255 handler_(other.handler_) 256 { 257 } 258 259 read_op(read_op&& other) 260 : detail::base_from_completion_cond<CompletionCondition>(other), 261 stream_(other.stream_), 262 buffers_(other.buffers_), 263 start_(other.start_), 264 total_transferred_(other.total_transferred_), 265 handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) 266 { 267 } 268 269 void operator()(const asio::error_code& ec, 270 std::size_t bytes_transferred, int start = 0) 271 { 272 typename asio::detail::dependent_type<Elem, 273 boost::array<asio::mutable_buffer, 2> >::type bufs = {{ 274 asio::mutable_buffer(buffers_[0]), 275 asio::mutable_buffer(buffers_[1]) }}; 276 std::size_t buffer_size0 = asio::buffer_size(bufs[0]); 277 std::size_t buffer_size1 = asio::buffer_size(bufs[1]); 278 std::size_t n = 0; 279 switch (start_ = start) 280 { 281 case 1: 282 n = this->check_for_completion(ec, total_transferred_); 283 for (;;) 284 { 285 bufs[0] = asio::buffer(bufs[0] + total_transferred_, n); 286 bufs[1] = asio::buffer( 287 bufs[1] + (total_transferred_ < buffer_size0 288 ? 0 : total_transferred_ - buffer_size0), 289 n - asio::buffer_size(bufs[0])); 290 stream_.async_read_some(bufs, ASIO_MOVE_CAST(read_op)(*this)); 291 return; default: 292 total_transferred_ += bytes_transferred; 293 if ((!ec && bytes_transferred == 0) 294 || (n = this->check_for_completion(ec, total_transferred_)) == 0 295 || total_transferred_ == buffer_size0 + buffer_size1) 296 break; 297 } 298 299 handler_(ec, static_cast<const std::size_t&>(total_transferred_)); 300 } 301 } 302 303 //private: 304 AsyncReadStream& stream_; 305 boost::array<Elem, 2> buffers_; 306 int start_; 307 std::size_t total_transferred_; 308 ReadHandler handler_; 309 }; 310 311 312 template <typename AsyncReadStream, typename Elem, 313 typename CompletionCondition, typename ReadHandler> 314 class read_op<AsyncReadStream, std::array<Elem, 2>, 315 CompletionCondition, ReadHandler> 316 : detail::base_from_completion_cond<CompletionCondition> 317 { 318 public: 319 read_op(AsyncReadStream& stream, const std::array<Elem, 2>& buffers, 320 CompletionCondition completion_condition, ReadHandler& handler) 321 : detail::base_from_completion_cond< 322 CompletionCondition>(completion_condition), 323 stream_(stream), 324 buffers_(buffers), 325 start_(0), 326 total_transferred_(0), 327 handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) 328 { 329 } 330 331 read_op(const read_op& other) 332 : detail::base_from_completion_cond<CompletionCondition>(other), 333 stream_(other.stream_), 334 buffers_(other.buffers_), 335 start_(other.start_), 336 total_transferred_(other.total_transferred_), 337 handler_(other.handler_) 338 { 339 } 340 341 read_op(read_op&& other) 342 : detail::base_from_completion_cond<CompletionCondition>(other), 343 stream_(other.stream_), 344 buffers_(other.buffers_), 345 start_(other.start_), 346 total_transferred_(other.total_transferred_), 347 handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) 348 { 349 } 350 351 void operator()(const asio::error_code& ec, 352 std::size_t bytes_transferred, int start = 0) 353 { 354 typename asio::detail::dependent_type<Elem, 355 std::array<asio::mutable_buffer, 2> >::type bufs = {{ 356 asio::mutable_buffer(buffers_[0]), 357 asio::mutable_buffer(buffers_[1]) }}; 358 std::size_t buffer_size0 = asio::buffer_size(bufs[0]); 359 std::size_t buffer_size1 = asio::buffer_size(bufs[1]); 360 std::size_t n = 0; 361 switch (start_ = start) 362 { 363 case 1: 364 n = this->check_for_completion(ec, total_transferred_); 365 for (;;) 366 { 367 bufs[0] = asio::buffer(bufs[0] + total_transferred_, n); 368 bufs[1] = asio::buffer( 369 bufs[1] + (total_transferred_ < buffer_size0 370 ? 0 : total_transferred_ - buffer_size0), 371 n - asio::buffer_size(bufs[0])); 372 stream_.async_read_some(bufs, ASIO_MOVE_CAST(read_op)(*this)); 373 return; default: 374 total_transferred_ += bytes_transferred; 375 if ((!ec && bytes_transferred == 0) 376 || (n = this->check_for_completion(ec, total_transferred_)) == 0 377 || total_transferred_ == buffer_size0 + buffer_size1) 378 break; 379 } 380 381 handler_(ec, static_cast<const std::size_t&>(total_transferred_)); 382 } 383 } 384 385 //private: 386 AsyncReadStream& stream_; 387 std::array<Elem, 2> buffers_; 388 int start_; 389 std::size_t total_transferred_; 390 ReadHandler handler_; 391 }; 392 393 394 template <typename AsyncReadStream, typename MutableBufferSequence, 395 typename CompletionCondition, typename ReadHandler> 396 inline void* asio_handler_allocate(std::size_t size, 397 read_op<AsyncReadStream, MutableBufferSequence, 398 CompletionCondition, ReadHandler>* this_handler) 399 { 400 return asio_handler_alloc_helpers::allocate( 401 size, this_handler->handler_); 402 } 403 404 template <typename AsyncReadStream, typename MutableBufferSequence, 405 typename CompletionCondition, typename ReadHandler> 406 inline void asio_handler_deallocate(void* pointer, std::size_t size, 407 read_op<AsyncReadStream, MutableBufferSequence, 408 CompletionCondition, ReadHandler>* this_handler) 409 { 410 asio_handler_alloc_helpers::deallocate( 411 pointer, size, this_handler->handler_); 412 } 413 414 template <typename AsyncReadStream, typename MutableBufferSequence, 415 typename CompletionCondition, typename ReadHandler> 416 inline bool asio_handler_is_continuation( 417 read_op<AsyncReadStream, MutableBufferSequence, 418 CompletionCondition, ReadHandler>* this_handler) 419 { 420 return this_handler->start_ == 0 ? true 421 : asio_handler_cont_helpers::is_continuation( 422 this_handler->handler_); 423 } 424 425 template <typename Function, typename AsyncReadStream, 426 typename MutableBufferSequence, typename CompletionCondition, 427 typename ReadHandler> 428 inline void asio_handler_invoke(Function& function, 429 read_op<AsyncReadStream, MutableBufferSequence, 430 CompletionCondition, ReadHandler>* this_handler) 431 { 432 asio_handler_invoke_helpers::invoke( 433 function, this_handler->handler_); 434 } 435 436 template <typename Function, typename AsyncReadStream, 437 typename MutableBufferSequence, typename CompletionCondition, 438 typename ReadHandler> 439 inline void asio_handler_invoke(const Function& function, 440 read_op<AsyncReadStream, MutableBufferSequence, 441 CompletionCondition, ReadHandler>* this_handler) 442 { 443 asio_handler_invoke_helpers::invoke( 444 function, this_handler->handler_); 445 } 446 } // namespace detail 447 448 template <typename AsyncReadStream, typename MutableBufferSequence, 449 typename CompletionCondition, typename ReadHandler> 450 inline ASIO_INITFN_RESULT_TYPE(ReadHandler, 451 void (asio::error_code, std::size_t)) 452 async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, 453 CompletionCondition completion_condition, 454 ASIO_MOVE_ARG(ReadHandler) handler) 455 { 456 // If you get an error on the following line it means that your handler does 457 // not meet the documented type requirements for a ReadHandler. 458 ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; 459 460 detail::async_result_init< 461 ReadHandler, void (asio::error_code, std::size_t)> init( 462 ASIO_MOVE_CAST(ReadHandler)(handler)); 463 464 detail::read_op<AsyncReadStream, MutableBufferSequence, 465 CompletionCondition, ASIO_HANDLER_TYPE( 466 ReadHandler, void (asio::error_code, std::size_t))>( 467 s, buffers, completion_condition, init.handler)( 468 asio::error_code(), 0, 1); 469 470 return init.result.get(); 471 } 472 473 template <typename AsyncReadStream, typename MutableBufferSequence, 474 typename ReadHandler> 475 inline ASIO_INITFN_RESULT_TYPE(ReadHandler, 476 void (asio::error_code, std::size_t)) 477 async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, 478 ASIO_MOVE_ARG(ReadHandler) handler) 479 { 480 // If you get an error on the following line it means that your handler does 481 // not meet the documented type requirements for a ReadHandler. 482 ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; 483 484 detail::async_result_init< 485 ReadHandler, void (asio::error_code, std::size_t)> init( 486 ASIO_MOVE_CAST(ReadHandler)(handler)); 487 488 detail::read_op<AsyncReadStream, MutableBufferSequence, 489 detail::transfer_all_t, ASIO_HANDLER_TYPE( 490 ReadHandler, void (asio::error_code, std::size_t))>( 491 s, buffers, transfer_all(), init.handler)( 492 asio::error_code(), 0, 1); 493 494 return init.result.get(); 495 } 496 497 498 } // namespace asio 499 500 #include "asio/detail/pop_options.hpp" 501 502 #endif // ASIO_IMPL_READ_HPP 503