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