Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

basic_socket_streambuf.hpp 21KB

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