basic_socket_streambuf.hpp 22 KB

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