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