1 // 2 // basic_socket_streambuf.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_BASIC_SOCKET_STREAMBUF_HPP 12 #define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_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 20 #if !defined(BOOST_ASIO_NO_IOSTREAM) 21 22 #include <streambuf> 23 #include <vector> 24 #include <boost/asio/basic_socket.hpp> 25 #include <boost/asio/basic_stream_socket.hpp> 26 #include <boost/asio/detail/buffer_sequence_adapter.hpp> 27 #include <boost/asio/detail/memory.hpp> 28 #include <boost/asio/detail/throw_error.hpp> 29 #include <boost/asio/io_context.hpp> 30 31 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ 32 && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 33 # include <boost/asio/detail/deadline_timer_service.hpp> 34 #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) 35 // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 36 # include <boost/asio/steady_timer.hpp> 37 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) 38 // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 39 40 #if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 41 42 # include <boost/asio/detail/variadic_templates.hpp> 43 44 // A macro that should expand to: 45 // template <typename T1, ..., typename Tn> 46 // basic_socket_streambuf* connect(T1 x1, ..., Tn xn) 47 // { 48 // init_buffers(); 49 // typedef typename Protocol::resolver resolver_type; 50 // resolver_type resolver(socket().get_executor()); 51 // connect_to_endpoints( 52 // resolver.resolve(x1, ..., xn, ec_)); 53 // return !ec_ ? this : 0; 54 // } 55 // This macro should only persist within this file. 56 57 # define BOOST_ASIO_PRIVATE_CONNECT_DEF(n) \ 58 template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 59 basic_socket_streambuf* connect(BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n)) \ 60 { \ 61 init_buffers(); \ 62 typedef typename Protocol::resolver resolver_type; \ 63 resolver_type resolver(socket().get_executor()); \ 64 connect_to_endpoints( \ 65 resolver.resolve(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \ 66 return !ec_ ? this : 0; \ 67 } \ 68 /**/ 69 70 #endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 71 72 #include <boost/asio/detail/push_options.hpp> 73 74 namespace boost { 75 namespace asio { 76 namespace detail { 77 78 // A separate base class is used to ensure that the io_context member is 79 // initialised prior to the basic_socket_streambuf's basic_socket base class. 80 class socket_streambuf_io_context 81 { 82 protected: socket_streambuf_io_context(io_context * ctx)83 socket_streambuf_io_context(io_context* ctx) 84 : default_io_context_(ctx) 85 { 86 } 87 88 shared_ptr<io_context> default_io_context_; 89 }; 90 91 // A separate base class is used to ensure that the dynamically allocated 92 // buffers are constructed prior to the basic_socket_streambuf's basic_socket 93 // base class. This makes moving the socket is the last potentially throwing 94 // step in the streambuf's move constructor, giving the constructor a strong 95 // exception safety guarantee. 96 class socket_streambuf_buffers 97 { 98 protected: socket_streambuf_buffers()99 socket_streambuf_buffers() 100 : get_buffer_(buffer_size), 101 put_buffer_(buffer_size) 102 { 103 } 104 105 enum { buffer_size = 512 }; 106 std::vector<char> get_buffer_; 107 std::vector<char> put_buffer_; 108 }; 109 110 } // namespace detail 111 112 #if !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) 113 #define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL 114 115 // Forward declaration with defaulted arguments. 116 template <typename Protocol, 117 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ 118 && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 119 typename Clock = boost::posix_time::ptime, 120 typename WaitTraits = time_traits<Clock> > 121 #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) 122 // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 123 typename Clock = chrono::steady_clock, 124 typename WaitTraits = wait_traits<Clock> > 125 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) 126 // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 127 class basic_socket_streambuf; 128 129 #endif // !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) 130 131 /// Iostream streambuf for a socket. 132 #if defined(GENERATING_DOCUMENTATION) 133 template <typename Protocol, 134 typename Clock = chrono::steady_clock, 135 typename WaitTraits = wait_traits<Clock> > 136 #else // defined(GENERATING_DOCUMENTATION) 137 template <typename Protocol, typename Clock, typename WaitTraits> 138 #endif // defined(GENERATING_DOCUMENTATION) 139 class basic_socket_streambuf 140 : public std::streambuf, 141 private detail::socket_streambuf_io_context, 142 private detail::socket_streambuf_buffers, 143 #if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) 144 private basic_socket<Protocol> 145 #else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) 146 public basic_socket<Protocol> 147 #endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) 148 { 149 private: 150 // These typedefs are intended keep this class's implementation independent 151 // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono. 152 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ 153 && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 154 typedef WaitTraits traits_helper; 155 #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) 156 // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 157 typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper; 158 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) 159 // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 160 161 public: 162 /// The protocol type. 163 typedef Protocol protocol_type; 164 165 /// The endpoint type. 166 typedef typename Protocol::endpoint endpoint_type; 167 168 /// The clock type. 169 typedef Clock clock_type; 170 171 #if defined(GENERATING_DOCUMENTATION) 172 /// (Deprecated: Use time_point.) The time type. 173 typedef typename WaitTraits::time_type time_type; 174 175 /// The time type. 176 typedef typename WaitTraits::time_point time_point; 177 178 /// (Deprecated: Use duration.) The duration type. 179 typedef typename WaitTraits::duration_type duration_type; 180 181 /// The duration type. 182 typedef typename WaitTraits::duration duration; 183 #else 184 # if !defined(BOOST_ASIO_NO_DEPRECATED) 185 typedef typename traits_helper::time_type time_type; 186 typedef typename traits_helper::duration_type duration_type; 187 # endif // !defined(BOOST_ASIO_NO_DEPRECATED) 188 typedef typename traits_helper::time_type time_point; 189 typedef typename traits_helper::duration_type duration; 190 #endif 191 192 /// Construct a basic_socket_streambuf without establishing a connection. basic_socket_streambuf()193 basic_socket_streambuf() 194 : detail::socket_streambuf_io_context(new io_context), 195 basic_socket<Protocol>(*default_io_context_), 196 expiry_time_(max_expiry_time()) 197 { 198 init_buffers(); 199 } 200 201 #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) 202 /// Construct a basic_socket_streambuf from the supplied socket. basic_socket_streambuf(basic_stream_socket<protocol_type> s)203 explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s) 204 : detail::socket_streambuf_io_context(0), 205 basic_socket<Protocol>(std::move(s)), 206 expiry_time_(max_expiry_time()) 207 { 208 init_buffers(); 209 } 210 211 /// Move-construct a basic_socket_streambuf from another. basic_socket_streambuf(basic_socket_streambuf && other)212 basic_socket_streambuf(basic_socket_streambuf&& other) 213 : detail::socket_streambuf_io_context(other), 214 basic_socket<Protocol>(std::move(other.socket())), 215 ec_(other.ec_), 216 expiry_time_(other.expiry_time_) 217 { 218 get_buffer_.swap(other.get_buffer_); 219 put_buffer_.swap(other.put_buffer_); 220 setg(other.eback(), other.gptr(), other.egptr()); 221 setp(other.pptr(), other.epptr()); 222 other.ec_ = boost::system::error_code(); 223 other.expiry_time_ = max_expiry_time(); 224 other.init_buffers(); 225 } 226 227 /// Move-assign a basic_socket_streambuf from another. operator =(basic_socket_streambuf && other)228 basic_socket_streambuf& operator=(basic_socket_streambuf&& other) 229 { 230 this->close(); 231 socket() = std::move(other.socket()); 232 detail::socket_streambuf_io_context::operator=(other); 233 ec_ = other.ec_; 234 expiry_time_ = other.expiry_time_; 235 get_buffer_.swap(other.get_buffer_); 236 put_buffer_.swap(other.put_buffer_); 237 setg(other.eback(), other.gptr(), other.egptr()); 238 setp(other.pptr(), other.epptr()); 239 other.ec_ = boost::system::error_code(); 240 other.expiry_time_ = max_expiry_time(); 241 other.put_buffer_.resize(buffer_size); 242 other.init_buffers(); 243 return *this; 244 } 245 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) 246 247 /// Destructor flushes buffered data. ~basic_socket_streambuf()248 virtual ~basic_socket_streambuf() 249 { 250 if (pptr() != pbase()) 251 overflow(traits_type::eof()); 252 } 253 254 /// Establish a connection. 255 /** 256 * This function establishes a connection to the specified endpoint. 257 * 258 * @return \c this if a connection was successfully established, a null 259 * pointer otherwise. 260 */ connect(const endpoint_type & endpoint)261 basic_socket_streambuf* connect(const endpoint_type& endpoint) 262 { 263 init_buffers(); 264 ec_ = boost::system::error_code(); 265 this->connect_to_endpoints(&endpoint, &endpoint + 1); 266 return !ec_ ? this : 0; 267 } 268 269 #if defined(GENERATING_DOCUMENTATION) 270 /// Establish a connection. 271 /** 272 * This function automatically establishes a connection based on the supplied 273 * resolver query parameters. The arguments are used to construct a resolver 274 * query object. 275 * 276 * @return \c this if a connection was successfully established, a null 277 * pointer otherwise. 278 */ 279 template <typename T1, ..., typename TN> 280 basic_socket_streambuf* connect(T1 t1, ..., TN tn); 281 #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 282 template <typename... T> connect(T...x)283 basic_socket_streambuf* connect(T... x) 284 { 285 init_buffers(); 286 typedef typename Protocol::resolver resolver_type; 287 resolver_type resolver(socket().get_executor()); 288 connect_to_endpoints(resolver.resolve(x..., ec_)); 289 return !ec_ ? this : 0; 290 } 291 #else BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CONNECT_DEF)292 BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CONNECT_DEF) 293 #endif 294 295 /// Close the connection. 296 /** 297 * @return \c this if a connection was successfully established, a null 298 * pointer otherwise. 299 */ 300 basic_socket_streambuf* close() 301 { 302 sync(); 303 socket().close(ec_); 304 if (!ec_) 305 init_buffers(); 306 return !ec_ ? this : 0; 307 } 308 309 /// Get a reference to the underlying socket. socket()310 basic_socket<Protocol>& socket() 311 { 312 return *this; 313 } 314 315 /// Get the last error associated with the stream buffer. 316 /** 317 * @return An \c error_code corresponding to the last error from the stream 318 * buffer. 319 */ error() const320 const boost::system::error_code& error() const 321 { 322 return ec_; 323 } 324 325 #if !defined(BOOST_ASIO_NO_DEPRECATED) 326 /// (Deprecated: Use error().) Get the last error associated with the stream 327 /// buffer. 328 /** 329 * @return An \c error_code corresponding to the last error from the stream 330 * buffer. 331 */ puberror() const332 const boost::system::error_code& puberror() const 333 { 334 return error(); 335 } 336 337 /// (Deprecated: Use expiry().) Get the stream buffer's expiry time as an 338 /// absolute time. 339 /** 340 * @return An absolute time value representing the stream buffer's expiry 341 * time. 342 */ expires_at() const343 time_point expires_at() const 344 { 345 return expiry_time_; 346 } 347 #endif // !defined(BOOST_ASIO_NO_DEPRECATED) 348 349 /// Get the stream buffer's expiry time as an absolute time. 350 /** 351 * @return An absolute time value representing the stream buffer's expiry 352 * time. 353 */ expiry() const354 time_point expiry() const 355 { 356 return expiry_time_; 357 } 358 359 /// Set the stream buffer's expiry time as an absolute time. 360 /** 361 * This function sets the expiry time associated with the stream. Stream 362 * operations performed after this time (where the operations cannot be 363 * completed using the internal buffers) will fail with the error 364 * boost::asio::error::operation_aborted. 365 * 366 * @param expiry_time The expiry time to be used for the stream. 367 */ expires_at(const time_point & expiry_time)368 void expires_at(const time_point& expiry_time) 369 { 370 expiry_time_ = expiry_time; 371 } 372 373 /// Set the stream buffer's expiry time relative to now. 374 /** 375 * This function sets the expiry time associated with the stream. Stream 376 * operations performed after this time (where the operations cannot be 377 * completed using the internal buffers) will fail with the error 378 * boost::asio::error::operation_aborted. 379 * 380 * @param expiry_time The expiry time to be used for the timer. 381 */ expires_after(const duration & expiry_time)382 void expires_after(const duration& expiry_time) 383 { 384 expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time); 385 } 386 387 #if !defined(BOOST_ASIO_NO_DEPRECATED) 388 /// (Deprecated: Use expiry().) Get the stream buffer's expiry time relative 389 /// to now. 390 /** 391 * @return A relative time value representing the stream buffer's expiry time. 392 */ expires_from_now() const393 duration expires_from_now() const 394 { 395 return traits_helper::subtract(expires_at(), traits_helper::now()); 396 } 397 398 /// (Deprecated: Use expires_after().) Set the stream buffer's expiry time 399 /// relative to now. 400 /** 401 * This function sets the expiry time associated with the stream. Stream 402 * operations performed after this time (where the operations cannot be 403 * completed using the internal buffers) will fail with the error 404 * boost::asio::error::operation_aborted. 405 * 406 * @param expiry_time The expiry time to be used for the timer. 407 */ expires_from_now(const duration & expiry_time)408 void expires_from_now(const duration& expiry_time) 409 { 410 expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time); 411 } 412 #endif // !defined(BOOST_ASIO_NO_DEPRECATED) 413 414 protected: underflow()415 int_type underflow() 416 { 417 #if defined(BOOST_ASIO_WINDOWS_RUNTIME) 418 ec_ = boost::asio::error::operation_not_supported; 419 return traits_type::eof(); 420 #else // defined(BOOST_ASIO_WINDOWS_RUNTIME) 421 if (gptr() != egptr()) 422 return traits_type::eof(); 423 424 for (;;) 425 { 426 // Check if we are past the expiry time. 427 if (traits_helper::less_than(expiry_time_, traits_helper::now())) 428 { 429 ec_ = boost::asio::error::timed_out; 430 return traits_type::eof(); 431 } 432 433 // Try to complete the operation without blocking. 434 if (!socket().native_non_blocking()) 435 socket().native_non_blocking(true, ec_); 436 detail::buffer_sequence_adapter<mutable_buffer, mutable_buffer> 437 bufs(boost::asio::buffer(get_buffer_) + putback_max); 438 detail::signed_size_type bytes = detail::socket_ops::recv( 439 socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_); 440 441 // Check if operation succeeded. 442 if (bytes > 0) 443 { 444 setg(&get_buffer_[0], &get_buffer_[0] + putback_max, 445 &get_buffer_[0] + putback_max + bytes); 446 return traits_type::to_int_type(*gptr()); 447 } 448 449 // Check for EOF. 450 if (bytes == 0) 451 { 452 ec_ = boost::asio::error::eof; 453 return traits_type::eof(); 454 } 455 456 // Operation failed. 457 if (ec_ != boost::asio::error::would_block 458 && ec_ != boost::asio::error::try_again) 459 return traits_type::eof(); 460 461 // Wait for socket to become ready. 462 if (detail::socket_ops::poll_read( 463 socket().native_handle(), 0, timeout(), ec_) < 0) 464 return traits_type::eof(); 465 } 466 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) 467 } 468 overflow(int_type c)469 int_type overflow(int_type c) 470 { 471 #if defined(BOOST_ASIO_WINDOWS_RUNTIME) 472 ec_ = boost::asio::error::operation_not_supported; 473 return traits_type::eof(); 474 #else // defined(BOOST_ASIO_WINDOWS_RUNTIME) 475 char_type ch = traits_type::to_char_type(c); 476 477 // Determine what needs to be sent. 478 const_buffer output_buffer; 479 if (put_buffer_.empty()) 480 { 481 if (traits_type::eq_int_type(c, traits_type::eof())) 482 return traits_type::not_eof(c); // Nothing to do. 483 output_buffer = boost::asio::buffer(&ch, sizeof(char_type)); 484 } 485 else 486 { 487 output_buffer = boost::asio::buffer(pbase(), 488 (pptr() - pbase()) * sizeof(char_type)); 489 } 490 491 while (output_buffer.size() > 0) 492 { 493 // Check if we are past the expiry time. 494 if (traits_helper::less_than(expiry_time_, traits_helper::now())) 495 { 496 ec_ = boost::asio::error::timed_out; 497 return traits_type::eof(); 498 } 499 500 // Try to complete the operation without blocking. 501 if (!socket().native_non_blocking()) 502 socket().native_non_blocking(true, ec_); 503 detail::buffer_sequence_adapter< 504 const_buffer, const_buffer> bufs(output_buffer); 505 detail::signed_size_type bytes = detail::socket_ops::send( 506 socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_); 507 508 // Check if operation succeeded. 509 if (bytes > 0) 510 { 511 output_buffer += static_cast<std::size_t>(bytes); 512 continue; 513 } 514 515 // Operation failed. 516 if (ec_ != boost::asio::error::would_block 517 && ec_ != boost::asio::error::try_again) 518 return traits_type::eof(); 519 520 // Wait for socket to become ready. 521 if (detail::socket_ops::poll_write( 522 socket().native_handle(), 0, timeout(), ec_) < 0) 523 return traits_type::eof(); 524 } 525 526 if (!put_buffer_.empty()) 527 { 528 setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size()); 529 530 // If the new character is eof then our work here is done. 531 if (traits_type::eq_int_type(c, traits_type::eof())) 532 return traits_type::not_eof(c); 533 534 // Add the new character to the output buffer. 535 *pptr() = ch; 536 pbump(1); 537 } 538 539 return c; 540 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) 541 } 542 sync()543 int sync() 544 { 545 return overflow(traits_type::eof()); 546 } 547 setbuf(char_type * s,std::streamsize n)548 std::streambuf* setbuf(char_type* s, std::streamsize n) 549 { 550 if (pptr() == pbase() && s == 0 && n == 0) 551 { 552 put_buffer_.clear(); 553 setp(0, 0); 554 sync(); 555 return this; 556 } 557 558 return 0; 559 } 560 561 private: 562 // Disallow copying and assignment. 563 basic_socket_streambuf(const basic_socket_streambuf&) BOOST_ASIO_DELETED; 564 basic_socket_streambuf& operator=( 565 const basic_socket_streambuf&) BOOST_ASIO_DELETED; 566 init_buffers()567 void init_buffers() 568 { 569 setg(&get_buffer_[0], 570 &get_buffer_[0] + putback_max, 571 &get_buffer_[0] + putback_max); 572 573 if (put_buffer_.empty()) 574 setp(0, 0); 575 else 576 setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size()); 577 } 578 timeout() const579 int timeout() const 580 { 581 int64_t msec = traits_helper::to_posix_duration( 582 traits_helper::subtract(expiry_time_, 583 traits_helper::now())).total_milliseconds(); 584 if (msec > (std::numeric_limits<int>::max)()) 585 msec = (std::numeric_limits<int>::max)(); 586 else if (msec < 0) 587 msec = 0; 588 return static_cast<int>(msec); 589 } 590 591 template <typename EndpointSequence> connect_to_endpoints(const EndpointSequence & endpoints)592 void connect_to_endpoints(const EndpointSequence& endpoints) 593 { 594 this->connect_to_endpoints(endpoints.begin(), endpoints.end()); 595 } 596 597 template <typename EndpointIterator> connect_to_endpoints(EndpointIterator begin,EndpointIterator end)598 void connect_to_endpoints(EndpointIterator begin, EndpointIterator end) 599 { 600 #if defined(BOOST_ASIO_WINDOWS_RUNTIME) 601 ec_ = boost::asio::error::operation_not_supported; 602 #else // defined(BOOST_ASIO_WINDOWS_RUNTIME) 603 if (ec_) 604 return; 605 606 ec_ = boost::asio::error::not_found; 607 for (EndpointIterator i = begin; i != end; ++i) 608 { 609 // Check if we are past the expiry time. 610 if (traits_helper::less_than(expiry_time_, traits_helper::now())) 611 { 612 ec_ = boost::asio::error::timed_out; 613 return; 614 } 615 616 // Close and reopen the socket. 617 typename Protocol::endpoint ep(*i); 618 socket().close(ec_); 619 socket().open(ep.protocol(), ec_); 620 if (ec_) 621 continue; 622 623 // Try to complete the operation without blocking. 624 if (!socket().native_non_blocking()) 625 socket().native_non_blocking(true, ec_); 626 detail::socket_ops::connect(socket().native_handle(), 627 ep.data(), ep.size(), ec_); 628 629 // Check if operation succeeded. 630 if (!ec_) 631 return; 632 633 // Operation failed. 634 if (ec_ != boost::asio::error::in_progress 635 && ec_ != boost::asio::error::would_block) 636 continue; 637 638 // Wait for socket to become ready. 639 if (detail::socket_ops::poll_connect( 640 socket().native_handle(), timeout(), ec_) < 0) 641 continue; 642 643 // Get the error code from the connect operation. 644 int connect_error = 0; 645 size_t connect_error_len = sizeof(connect_error); 646 if (detail::socket_ops::getsockopt(socket().native_handle(), 0, 647 SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec_) 648 == detail::socket_error_retval) 649 return; 650 651 // Check the result of the connect operation. 652 ec_ = boost::system::error_code(connect_error, 653 boost::asio::error::get_system_category()); 654 if (!ec_) 655 return; 656 } 657 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) 658 } 659 660 // Helper function to get the maximum expiry time. max_expiry_time()661 static time_point max_expiry_time() 662 { 663 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ 664 && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 665 return boost::posix_time::pos_infin; 666 #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) 667 // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 668 return (time_point::max)(); 669 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) 670 // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) 671 } 672 673 enum { putback_max = 8 }; 674 boost::system::error_code ec_; 675 time_point expiry_time_; 676 }; 677 678 } // namespace asio 679 } // namespace boost 680 681 #include <boost/asio/detail/pop_options.hpp> 682 683 #if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 684 # undef BOOST_ASIO_PRIVATE_CONNECT_DEF 685 #endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) 686 687 #endif // !defined(BOOST_ASIO_NO_IOSTREAM) 688 689 #endif // BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP 690