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