fix doc example typo
[boost.git] / boost / asio / basic_socket_streambuf.hpp
blob9977be687d8fd8ccb70e08944ef64688b3d331b4
1 //
2 // basic_socket_streambuf.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2008 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 //
11 #ifndef BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
12 #define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/push_options.hpp>
20 #include <boost/asio/detail/push_options.hpp>
21 #include <streambuf>
22 #include <boost/array.hpp>
23 #include <boost/preprocessor/arithmetic/inc.hpp>
24 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
25 #include <boost/preprocessor/repetition/enum_params.hpp>
26 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
27 #include <boost/utility/base_from_member.hpp>
28 #include <boost/asio/detail/pop_options.hpp>
30 #include <boost/asio/basic_socket.hpp>
31 #include <boost/asio/io_service.hpp>
32 #include <boost/asio/stream_socket_service.hpp>
33 #include <boost/asio/detail/throw_error.hpp>
35 #if !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY)
36 #define BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY 5
37 #endif // !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY)
39 // A macro that should expand to:
40 // template <typename T1, ..., typename Tn>
41 // basic_socket_streambuf<Protocol, StreamSocketService>* connect(
42 // T1 x1, ..., Tn xn)
43 // {
44 // init_buffers();
45 // boost::system::error_code ec;
46 // this->basic_socket<Protocol, StreamSocketService>::close(ec);
47 // typedef typename Protocol::resolver_query resolver_query;
48 // resolver_query query(x1, ..., xn);
49 // resolve_and_connect(query, ec);
50 // return !ec ? this : 0;
51 // }
52 // This macro should only persist within this file.
54 #define BOOST_ASIO_PRIVATE_CONNECT_DEF( z, n, data ) \
55 template <BOOST_PP_ENUM_PARAMS(n, typename T)> \
56 basic_socket_streambuf<Protocol, StreamSocketService>* connect( \
57 BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \
58 { \
59 init_buffers(); \
60 boost::system::error_code ec; \
61 this->basic_socket<Protocol, StreamSocketService>::close(ec); \
62 typedef typename Protocol::resolver_query resolver_query; \
63 resolver_query query(BOOST_PP_ENUM_PARAMS(n, x)); \
64 resolve_and_connect(query, ec); \
65 return !ec ? this : 0; \
66 } \
67 /**/
69 namespace boost {
70 namespace asio {
72 /// Iostream streambuf for a socket.
73 template <typename Protocol,
74 typename StreamSocketService = stream_socket_service<Protocol> >
75 class basic_socket_streambuf
76 : public std::streambuf,
77 private boost::base_from_member<io_service>,
78 public basic_socket<Protocol, StreamSocketService>
80 public:
81 /// The endpoint type.
82 typedef typename Protocol::endpoint endpoint_type;
84 /// Construct a basic_socket_streambuf without establishing a connection.
85 basic_socket_streambuf()
86 : basic_socket<Protocol, StreamSocketService>(
87 boost::base_from_member<boost::asio::io_service>::member),
88 unbuffered_(false)
90 init_buffers();
93 /// Destructor flushes buffered data.
94 virtual ~basic_socket_streambuf()
96 if (pptr() != pbase())
97 overflow(traits_type::eof());
100 /// Establish a connection.
102 * This function establishes a connection to the specified endpoint.
104 * @return \c this if a connection was successfully established, a null
105 * pointer otherwise.
107 basic_socket_streambuf<Protocol, StreamSocketService>* connect(
108 const endpoint_type& endpoint)
110 init_buffers();
111 boost::system::error_code ec;
112 this->basic_socket<Protocol, StreamSocketService>::close(ec);
113 this->basic_socket<Protocol, StreamSocketService>::connect(endpoint, ec);
114 return !ec ? this : 0;
117 #if defined(GENERATING_DOCUMENTATION)
118 /// Establish a connection.
120 * This function automatically establishes a connection based on the supplied
121 * resolver query parameters. The arguments are used to construct a resolver
122 * query object.
124 * @return \c this if a connection was successfully established, a null
125 * pointer otherwise.
127 template <typename T1, ..., typename TN>
128 basic_socket_streambuf<Protocol, StreamSocketService>* connect(
129 T1 t1, ..., TN tn);
130 #else
131 BOOST_PP_REPEAT_FROM_TO(
132 1, BOOST_PP_INC(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY),
133 BOOST_ASIO_PRIVATE_CONNECT_DEF, _ )
134 #endif
136 /// Close the connection.
138 * @return \c this if a connection was successfully established, a null
139 * pointer otherwise.
141 basic_socket_streambuf<Protocol, StreamSocketService>* close()
143 boost::system::error_code ec;
144 sync();
145 this->basic_socket<Protocol, StreamSocketService>::close(ec);
146 if (!ec)
147 init_buffers();
148 return !ec ? this : 0;
151 protected:
152 int_type underflow()
154 if (gptr() == egptr())
156 boost::system::error_code ec;
157 std::size_t bytes_transferred = this->service.receive(
158 this->implementation,
159 boost::asio::buffer(boost::asio::buffer(get_buffer_) + putback_max),
160 0, ec);
161 if (ec)
162 return traits_type::eof();
163 setg(get_buffer_.begin(), get_buffer_.begin() + putback_max,
164 get_buffer_.begin() + putback_max + bytes_transferred);
165 return traits_type::to_int_type(*gptr());
167 else
169 return traits_type::eof();
173 int_type overflow(int_type c)
175 if (unbuffered_)
177 if (traits_type::eq_int_type(c, traits_type::eof()))
179 // Nothing to do.
180 return traits_type::not_eof(c);
182 else
184 // Send the single character immediately.
185 boost::system::error_code ec;
186 char_type ch = traits_type::to_char_type(c);
187 this->service.send(this->implementation,
188 boost::asio::buffer(&ch, sizeof(char_type)), 0, ec);
189 if (ec)
190 return traits_type::eof();
191 return c;
194 else
196 // Send all data in the output buffer.
197 boost::asio::const_buffer buffer =
198 boost::asio::buffer(pbase(), pptr() - pbase());
199 while (boost::asio::buffer_size(buffer) > 0)
201 boost::system::error_code ec;
202 std::size_t bytes_transferred = this->service.send(
203 this->implementation, boost::asio::buffer(buffer),
204 0, ec);
205 if (ec)
206 return traits_type::eof();
207 buffer = buffer + bytes_transferred;
209 setp(put_buffer_.begin(), put_buffer_.end());
211 // If the new character is eof then our work here is done.
212 if (traits_type::eq_int_type(c, traits_type::eof()))
213 return traits_type::not_eof(c);
215 // Add the new character to the output buffer.
216 *pptr() = traits_type::to_char_type(c);
217 pbump(1);
218 return c;
222 int sync()
224 return overflow(traits_type::eof());
227 std::streambuf* setbuf(char_type* s, std::streamsize n)
229 if (pptr() == pbase() && s == 0 && n == 0)
231 unbuffered_ = true;
232 setp(0, 0);
233 return this;
236 return 0;
239 private:
240 void init_buffers()
242 setg(get_buffer_.begin(),
243 get_buffer_.begin() + putback_max,
244 get_buffer_.begin() + putback_max);
245 if (unbuffered_)
246 setp(0, 0);
247 else
248 setp(put_buffer_.begin(), put_buffer_.end());
251 template <typename ResolverQuery>
252 void resolve_and_connect(const ResolverQuery& query,
253 boost::system::error_code& ec)
255 typedef typename Protocol::resolver resolver_type;
256 typedef typename Protocol::resolver_iterator iterator_type;
257 resolver_type resolver(
258 boost::base_from_member<boost::asio::io_service>::member);
259 iterator_type i = resolver.resolve(query, ec);
260 if (!ec)
262 iterator_type end;
263 ec = boost::asio::error::host_not_found;
264 while (ec && i != end)
266 this->basic_socket<Protocol, StreamSocketService>::close();
267 this->basic_socket<Protocol, StreamSocketService>::connect(*i, ec);
268 ++i;
273 enum { putback_max = 8 };
274 enum { buffer_size = 512 };
275 boost::array<char, buffer_size> get_buffer_;
276 boost::array<char, buffer_size> put_buffer_;
277 bool unbuffered_;
280 } // namespace asio
281 } // namespace boost
283 #undef BOOST_ASIO_PRIVATE_CONNECT_DEF
285 #include <boost/asio/detail/pop_options.hpp>
287 #endif // BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP