basic_socket_iostream.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. //
  2. // basic_socket_iostream.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_IOSTREAM_HPP
  11. #define BOOST_ASIO_BASIC_SOCKET_IOSTREAM_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 <istream>
  18. #include <ostream>
  19. #include <boost/asio/basic_socket_streambuf.hpp>
  20. #if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
  21. # include <boost/asio/stream_socket_service.hpp>
  22. #endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
  23. #if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
  24. # include <boost/asio/detail/variadic_templates.hpp>
  25. // A macro that should expand to:
  26. // template <typename T1, ..., typename Tn>
  27. // explicit basic_socket_iostream(T1 x1, ..., Tn xn)
  28. // : std::basic_iostream<char>(
  29. // &this->detail::socket_iostream_base<
  30. // Protocol BOOST_ASIO_SVC_TARG, Clock,
  31. // WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_)
  32. // {
  33. // if (rdbuf()->connect(x1, ..., xn) == 0)
  34. // this->setstate(std::ios_base::failbit);
  35. // }
  36. // This macro should only persist within this file.
  37. # define BOOST_ASIO_PRIVATE_CTR_DEF(n) \
  38. template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
  39. explicit basic_socket_iostream(BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n)) \
  40. : std::basic_iostream<char>( \
  41. &this->detail::socket_iostream_base< \
  42. Protocol BOOST_ASIO_SVC_TARG, Clock, \
  43. WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_) \
  44. { \
  45. this->setf(std::ios_base::unitbuf); \
  46. if (rdbuf()->connect(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \
  47. this->setstate(std::ios_base::failbit); \
  48. } \
  49. /**/
  50. // A macro that should expand to:
  51. // template <typename T1, ..., typename Tn>
  52. // void connect(T1 x1, ..., Tn xn)
  53. // {
  54. // if (rdbuf()->connect(x1, ..., xn) == 0)
  55. // this->setstate(std::ios_base::failbit);
  56. // }
  57. // This macro should only persist within this file.
  58. # define BOOST_ASIO_PRIVATE_CONNECT_DEF(n) \
  59. template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
  60. void connect(BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n)) \
  61. { \
  62. if (rdbuf()->connect(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \
  63. this->setstate(std::ios_base::failbit); \
  64. } \
  65. /**/
  66. #endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
  67. #include <boost/asio/detail/push_options.hpp>
  68. namespace boost {
  69. namespace asio {
  70. namespace detail {
  71. // A separate base class is used to ensure that the streambuf is initialised
  72. // prior to the basic_socket_iostream's basic_iostream base class.
  73. template <typename Protocol BOOST_ASIO_SVC_TPARAM,
  74. typename Clock, typename WaitTraits BOOST_ASIO_SVC_TPARAM1>
  75. class socket_iostream_base
  76. {
  77. protected:
  78. socket_iostream_base()
  79. {
  80. }
  81. #if defined(BOOST_ASIO_HAS_MOVE)
  82. socket_iostream_base(socket_iostream_base&& other)
  83. : streambuf_(std::move(other.streambuf_))
  84. {
  85. }
  86. socket_iostream_base(basic_stream_socket<Protocol> s)
  87. : streambuf_(std::move(s))
  88. {
  89. }
  90. socket_iostream_base& operator=(socket_iostream_base&& other)
  91. {
  92. streambuf_ = std::move(other.streambuf_);
  93. return *this;
  94. }
  95. #endif // defined(BOOST_ASIO_HAS_MOVE)
  96. basic_socket_streambuf<Protocol BOOST_ASIO_SVC_TARG,
  97. Clock, WaitTraits BOOST_ASIO_SVC_TARG1> streambuf_;
  98. };
  99. } // namespace detail
  100. #if !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)
  101. #define BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL
  102. // Forward declaration with defaulted arguments.
  103. template <typename Protocol
  104. BOOST_ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>),
  105. #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
  106. && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
  107. typename Clock = boost::posix_time::ptime,
  108. typename WaitTraits = time_traits<Clock>
  109. BOOST_ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)>
  110. #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
  111. // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
  112. typename Clock = chrono::steady_clock,
  113. typename WaitTraits = wait_traits<Clock>
  114. BOOST_ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)>
  115. #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
  116. // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
  117. class basic_socket_iostream;
  118. #endif // !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)
  119. /// Iostream interface for a socket.
  120. #if defined(GENERATING_DOCUMENTATION)
  121. template <typename Protocol,
  122. typename Clock = chrono::steady_clock,
  123. typename WaitTraits = wait_traits<Clock> >
  124. #else // defined(GENERATING_DOCUMENTATION)
  125. template <typename Protocol BOOST_ASIO_SVC_TPARAM,
  126. typename Clock, typename WaitTraits BOOST_ASIO_SVC_TPARAM1>
  127. #endif // defined(GENERATING_DOCUMENTATION)
  128. class basic_socket_iostream
  129. : private detail::socket_iostream_base<Protocol
  130. BOOST_ASIO_SVC_TARG, Clock, WaitTraits BOOST_ASIO_SVC_TARG1>,
  131. public std::basic_iostream<char>
  132. {
  133. private:
  134. // These typedefs are intended keep this class's implementation independent
  135. // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.
  136. #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
  137. && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
  138. typedef WaitTraits traits_helper;
  139. #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
  140. // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
  141. typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
  142. #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
  143. // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
  144. public:
  145. /// The protocol type.
  146. typedef Protocol protocol_type;
  147. /// The endpoint type.
  148. typedef typename Protocol::endpoint endpoint_type;
  149. /// The clock type.
  150. typedef Clock clock_type;
  151. #if defined(GENERATING_DOCUMENTATION)
  152. /// (Deprecated: Use time_point.) The time type.
  153. typedef typename WaitTraits::time_type time_type;
  154. /// The time type.
  155. typedef typename WaitTraits::time_point time_point;
  156. /// (Deprecated: Use duration.) The duration type.
  157. typedef typename WaitTraits::duration_type duration_type;
  158. /// The duration type.
  159. typedef typename WaitTraits::duration duration;
  160. #else
  161. # if !defined(BOOST_ASIO_NO_DEPRECATED)
  162. typedef typename traits_helper::time_type time_type;
  163. typedef typename traits_helper::duration_type duration_type;
  164. # endif // !defined(BOOST_ASIO_NO_DEPRECATED)
  165. typedef typename traits_helper::time_type time_point;
  166. typedef typename traits_helper::duration_type duration;
  167. #endif
  168. /// Construct a basic_socket_iostream without establishing a connection.
  169. basic_socket_iostream()
  170. : std::basic_iostream<char>(
  171. &this->detail::socket_iostream_base<
  172. Protocol BOOST_ASIO_SVC_TARG, Clock,
  173. WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_)
  174. {
  175. this->setf(std::ios_base::unitbuf);
  176. }
  177. #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  178. /// Construct a basic_socket_iostream from the supplied socket.
  179. explicit basic_socket_iostream(basic_stream_socket<protocol_type> s)
  180. : detail::socket_iostream_base<
  181. Protocol BOOST_ASIO_SVC_TARG, Clock,
  182. WaitTraits BOOST_ASIO_SVC_TARG1>(std::move(s)),
  183. std::basic_iostream<char>(
  184. &this->detail::socket_iostream_base<
  185. Protocol BOOST_ASIO_SVC_TARG, Clock,
  186. WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_)
  187. {
  188. this->setf(std::ios_base::unitbuf);
  189. }
  190. #if defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) \
  191. || defined(GENERATING_DOCUMENTATION)
  192. /// Move-construct a basic_socket_iostream from another.
  193. basic_socket_iostream(basic_socket_iostream&& other)
  194. : detail::socket_iostream_base<
  195. Protocol BOOST_ASIO_SVC_TARG, Clock,
  196. WaitTraits BOOST_ASIO_SVC_TARG1>(std::move(other)),
  197. std::basic_iostream<char>(std::move(other))
  198. {
  199. this->set_rdbuf(&this->detail::socket_iostream_base<
  200. Protocol BOOST_ASIO_SVC_TARG, Clock,
  201. WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_);
  202. }
  203. /// Move-assign a basic_socket_iostream from another.
  204. basic_socket_iostream& operator=(basic_socket_iostream&& other)
  205. {
  206. std::basic_iostream<char>::operator=(std::move(other));
  207. detail::socket_iostream_base<
  208. Protocol BOOST_ASIO_SVC_TARG, Clock,
  209. WaitTraits BOOST_ASIO_SVC_TARG1>::operator=(std::move(other));
  210. return *this;
  211. }
  212. #endif // defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE)
  213. // || defined(GENERATING_DOCUMENTATION)
  214. #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  215. #if defined(GENERATING_DOCUMENTATION)
  216. /// Establish a connection to an endpoint corresponding to a resolver query.
  217. /**
  218. * This constructor automatically establishes a connection based on the
  219. * supplied resolver query parameters. The arguments are used to construct
  220. * a resolver query object.
  221. */
  222. template <typename T1, ..., typename TN>
  223. explicit basic_socket_iostream(T1 t1, ..., TN tn);
  224. #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
  225. template <typename... T>
  226. explicit basic_socket_iostream(T... x)
  227. : std::basic_iostream<char>(
  228. &this->detail::socket_iostream_base<
  229. Protocol BOOST_ASIO_SVC_TARG, Clock,
  230. WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_)
  231. {
  232. this->setf(std::ios_base::unitbuf);
  233. if (rdbuf()->connect(x...) == 0)
  234. this->setstate(std::ios_base::failbit);
  235. }
  236. #else
  237. BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CTR_DEF)
  238. #endif
  239. #if defined(GENERATING_DOCUMENTATION)
  240. /// Establish a connection to an endpoint corresponding to a resolver query.
  241. /**
  242. * This function automatically establishes a connection based on the supplied
  243. * resolver query parameters. The arguments are used to construct a resolver
  244. * query object.
  245. */
  246. template <typename T1, ..., typename TN>
  247. void connect(T1 t1, ..., TN tn);
  248. #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
  249. template <typename... T>
  250. void connect(T... x)
  251. {
  252. if (rdbuf()->connect(x...) == 0)
  253. this->setstate(std::ios_base::failbit);
  254. }
  255. #else
  256. BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CONNECT_DEF)
  257. #endif
  258. /// Close the connection.
  259. void close()
  260. {
  261. if (rdbuf()->close() == 0)
  262. this->setstate(std::ios_base::failbit);
  263. }
  264. /// Return a pointer to the underlying streambuf.
  265. basic_socket_streambuf<Protocol BOOST_ASIO_SVC_TARG,
  266. Clock, WaitTraits BOOST_ASIO_SVC_TARG1>* rdbuf() const
  267. {
  268. return const_cast<basic_socket_streambuf<Protocol BOOST_ASIO_SVC_TARG,
  269. Clock, WaitTraits BOOST_ASIO_SVC_TARG1>*>(
  270. &this->detail::socket_iostream_base<
  271. Protocol BOOST_ASIO_SVC_TARG, Clock,
  272. WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_);
  273. }
  274. /// Get a reference to the underlying socket.
  275. basic_socket<Protocol BOOST_ASIO_SVC_TARG>& socket()
  276. {
  277. return rdbuf()->socket();
  278. }
  279. /// Get the last error associated with the stream.
  280. /**
  281. * @return An \c error_code corresponding to the last error from the stream.
  282. *
  283. * @par Example
  284. * To print the error associated with a failure to establish a connection:
  285. * @code tcp::iostream s("www.boost.org", "http");
  286. * if (!s)
  287. * {
  288. * std::cout << "Error: " << s.error().message() << std::endl;
  289. * } @endcode
  290. */
  291. const boost::system::error_code& error() const
  292. {
  293. return rdbuf()->error();
  294. }
  295. #if !defined(BOOST_ASIO_NO_DEPRECATED)
  296. /// (Deprecated: Use expiry().) Get the stream's expiry time as an absolute
  297. /// time.
  298. /**
  299. * @return An absolute time value representing the stream's expiry time.
  300. */
  301. time_point expires_at() const
  302. {
  303. return rdbuf()->expires_at();
  304. }
  305. #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
  306. /// Get the stream's expiry time as an absolute time.
  307. /**
  308. * @return An absolute time value representing the stream's expiry time.
  309. */
  310. time_point expiry() const
  311. {
  312. return rdbuf()->expiry();
  313. }
  314. /// Set the stream's expiry time as an absolute time.
  315. /**
  316. * This function sets the expiry time associated with the stream. Stream
  317. * operations performed after this time (where the operations cannot be
  318. * completed using the internal buffers) will fail with the error
  319. * boost::asio::error::operation_aborted.
  320. *
  321. * @param expiry_time The expiry time to be used for the stream.
  322. */
  323. void expires_at(const time_point& expiry_time)
  324. {
  325. rdbuf()->expires_at(expiry_time);
  326. }
  327. /// Set the stream's expiry time relative to now.
  328. /**
  329. * This function sets the expiry time associated with the stream. Stream
  330. * operations performed after this time (where the operations cannot be
  331. * completed using the internal buffers) will fail with the error
  332. * boost::asio::error::operation_aborted.
  333. *
  334. * @param expiry_time The expiry time to be used for the timer.
  335. */
  336. void expires_after(const duration& expiry_time)
  337. {
  338. rdbuf()->expires_after(expiry_time);
  339. }
  340. #if !defined(BOOST_ASIO_NO_DEPRECATED)
  341. /// (Deprecated: Use expiry().) Get the stream's expiry time relative to now.
  342. /**
  343. * @return A relative time value representing the stream's expiry time.
  344. */
  345. duration expires_from_now() const
  346. {
  347. return rdbuf()->expires_from_now();
  348. }
  349. /// (Deprecated: Use expires_after().) Set the stream's expiry time relative
  350. /// to now.
  351. /**
  352. * This function sets the expiry time associated with the stream. Stream
  353. * operations performed after this time (where the operations cannot be
  354. * completed using the internal buffers) will fail with the error
  355. * boost::asio::error::operation_aborted.
  356. *
  357. * @param expiry_time The expiry time to be used for the timer.
  358. */
  359. void expires_from_now(const duration& expiry_time)
  360. {
  361. rdbuf()->expires_from_now(expiry_time);
  362. }
  363. #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
  364. private:
  365. // Disallow copying and assignment.
  366. basic_socket_iostream(const basic_socket_iostream&) BOOST_ASIO_DELETED;
  367. basic_socket_iostream& operator=(
  368. const basic_socket_iostream&) BOOST_ASIO_DELETED;
  369. };
  370. } // namespace asio
  371. } // namespace boost
  372. #include <boost/asio/detail/pop_options.hpp>
  373. #if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
  374. # undef BOOST_ASIO_PRIVATE_CTR_DEF
  375. # undef BOOST_ASIO_PRIVATE_CONNECT_DEF
  376. #endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
  377. #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
  378. #endif // BOOST_ASIO_BASIC_SOCKET_IOSTREAM_HPP