basic_socket_streambuf.hpp 20 KB

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