2 // basic_socket_streambuf.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
12 #define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/push_options.hpp>
20 #include <boost/asio/detail/push_options.hpp>
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(
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;
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)) \
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; \
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
>
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
),
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
107 basic_socket_streambuf
<Protocol
, StreamSocketService
>* connect(
108 const endpoint_type
& endpoint
)
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
124 * @return \c this if a connection was successfully established, a null
127 template <typename T1
, ..., typename TN
>
128 basic_socket_streambuf
<Protocol
, StreamSocketService
>* connect(
131 BOOST_PP_REPEAT_FROM_TO(
132 1, BOOST_PP_INC(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY
),
133 BOOST_ASIO_PRIVATE_CONNECT_DEF
, _
)
136 /// Close the connection.
138 * @return \c this if a connection was successfully established, a null
141 basic_socket_streambuf
<Protocol
, StreamSocketService
>* close()
143 boost::system::error_code ec
;
145 this->basic_socket
<Protocol
, StreamSocketService
>::close(ec
);
148 return !ec
? this : 0;
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
),
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());
169 return traits_type::eof();
173 int_type
overflow(int_type c
)
177 if (traits_type::eq_int_type(c
, traits_type::eof()))
180 return traits_type::not_eof(c
);
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
);
190 return traits_type::eof();
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
),
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
);
224 return overflow(traits_type::eof());
227 std::streambuf
* setbuf(char_type
* s
, std::streamsize n
)
229 if (pptr() == pbase() && s
== 0 && n
== 0)
242 setg(get_buffer_
.begin(),
243 get_buffer_
.begin() + putback_max
,
244 get_buffer_
.begin() + putback_max
);
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
);
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
);
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_
;
283 #undef BOOST_ASIO_PRIVATE_CONNECT_DEF
285 #include <boost/asio/detail/pop_options.hpp>
287 #endif // BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP