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