00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef ASIO_BASIC_SOCKET_STREAMBUF_HPP
00012 #define ASIO_BASIC_SOCKET_STREAMBUF_HPP
00013
00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
00015 # pragma once
00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
00017
00018 #include "asio/detail/push_options.hpp"
00019
00020 #include "asio/detail/push_options.hpp"
00021 #include <streambuf>
00022 #include <boost/array.hpp>
00023 #include <boost/preprocessor/arithmetic/inc.hpp>
00024 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
00025 #include <boost/preprocessor/repetition/enum_params.hpp>
00026 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
00027 #include <boost/utility/base_from_member.hpp>
00028 #include "asio/detail/pop_options.hpp"
00029
00030 #include "asio/basic_socket.hpp"
00031 #include "asio/io_service.hpp"
00032 #include "asio/stream_socket_service.hpp"
00033 #include "asio/detail/throw_error.hpp"
00034
00035 #if !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY)
00036 #define ASIO_SOCKET_STREAMBUF_MAX_ARITY 5
00037 #endif // !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY)
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 #define ASIO_PRIVATE_CONNECT_DEF( z, n, data ) \
00055 template <BOOST_PP_ENUM_PARAMS(n, typename T)> \
00056 basic_socket_streambuf<Protocol, StreamSocketService>* connect( \
00057 BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \
00058 { \
00059 init_buffers(); \
00060 asio::error_code ec; \
00061 this->basic_socket<Protocol, StreamSocketService>::close(ec); \
00062 typedef typename Protocol::resolver_query resolver_query; \
00063 resolver_query query(BOOST_PP_ENUM_PARAMS(n, x)); \
00064 resolve_and_connect(query, ec); \
00065 return !ec ? this : 0; \
00066 } \
00067
00068
00069 namespace asio {
00070
00072 template <typename Protocol,
00073 typename StreamSocketService = stream_socket_service<Protocol> >
00074 class basic_socket_streambuf
00075 : public std::streambuf,
00076 private boost::base_from_member<io_service>,
00077 public basic_socket<Protocol, StreamSocketService>
00078 {
00079 public:
00081 typedef typename Protocol::endpoint endpoint_type;
00082
00084 basic_socket_streambuf()
00085 : basic_socket<Protocol, StreamSocketService>(
00086 boost::base_from_member<asio::io_service>::member),
00087 unbuffered_(false)
00088 {
00089 init_buffers();
00090 }
00091
00093 virtual ~basic_socket_streambuf()
00094 {
00095 if (pptr() != pbase())
00096 overflow(traits_type::eof());
00097 }
00098
00100
00106 basic_socket_streambuf<Protocol, StreamSocketService>* connect(
00107 const endpoint_type& endpoint)
00108 {
00109 init_buffers();
00110 asio::error_code ec;
00111 this->basic_socket<Protocol, StreamSocketService>::close(ec);
00112 this->basic_socket<Protocol, StreamSocketService>::connect(endpoint, ec);
00113 return !ec ? this : 0;
00114 }
00115
00116 #if defined(GENERATING_DOCUMENTATION)
00117
00118
00126 template <typename T1, ..., typename TN>
00127 basic_socket_streambuf<Protocol, StreamSocketService>* connect(
00128 T1 t1, ..., TN tn);
00129 #else
00130 BOOST_PP_REPEAT_FROM_TO(
00131 1, BOOST_PP_INC(ASIO_SOCKET_STREAMBUF_MAX_ARITY),
00132 ASIO_PRIVATE_CONNECT_DEF, _ )
00133 #endif
00134
00136
00140 basic_socket_streambuf<Protocol, StreamSocketService>* close()
00141 {
00142 asio::error_code ec;
00143 sync();
00144 this->basic_socket<Protocol, StreamSocketService>::close(ec);
00145 if (!ec)
00146 init_buffers();
00147 return !ec ? this : 0;
00148 }
00149
00150 protected:
00151 int_type underflow()
00152 {
00153 if (gptr() == egptr())
00154 {
00155 asio::error_code ec;
00156 std::size_t bytes_transferred = this->service.receive(
00157 this->implementation,
00158 asio::buffer(asio::buffer(get_buffer_) + putback_max),
00159 0, ec);
00160 if (ec)
00161 return traits_type::eof();
00162 setg(get_buffer_.begin(), get_buffer_.begin() + putback_max,
00163 get_buffer_.begin() + putback_max + bytes_transferred);
00164 return traits_type::to_int_type(*gptr());
00165 }
00166 else
00167 {
00168 return traits_type::eof();
00169 }
00170 }
00171
00172 int_type overflow(int_type c)
00173 {
00174 if (unbuffered_)
00175 {
00176 if (traits_type::eq_int_type(c, traits_type::eof()))
00177 {
00178
00179 return traits_type::not_eof(c);
00180 }
00181 else
00182 {
00183
00184 asio::error_code ec;
00185 char_type ch = traits_type::to_char_type(c);
00186 this->service.send(this->implementation,
00187 asio::buffer(&ch, sizeof(char_type)), 0, ec);
00188 if (ec)
00189 return traits_type::eof();
00190 return c;
00191 }
00192 }
00193 else
00194 {
00195
00196 asio::const_buffer buffer =
00197 asio::buffer(pbase(), pptr() - pbase());
00198 while (asio::buffer_size(buffer) > 0)
00199 {
00200 asio::error_code ec;
00201 std::size_t bytes_transferred = this->service.send(
00202 this->implementation, asio::buffer(buffer),
00203 0, ec);
00204 if (ec)
00205 return traits_type::eof();
00206 buffer = buffer + bytes_transferred;
00207 }
00208 setp(put_buffer_.begin(), put_buffer_.end());
00209
00210
00211 if (traits_type::eq_int_type(c, traits_type::eof()))
00212 return traits_type::not_eof(c);
00213
00214
00215 *pptr() = traits_type::to_char_type(c);
00216 pbump(1);
00217 return c;
00218 }
00219 }
00220
00221 int sync()
00222 {
00223 return overflow(traits_type::eof());
00224 }
00225
00226 std::streambuf* setbuf(char_type* s, std::streamsize n)
00227 {
00228 if (pptr() == pbase() && s == 0 && n == 0)
00229 {
00230 unbuffered_ = true;
00231 setp(0, 0);
00232 return this;
00233 }
00234
00235 return 0;
00236 }
00237
00238 private:
00239 void init_buffers()
00240 {
00241 setg(get_buffer_.begin(),
00242 get_buffer_.begin() + putback_max,
00243 get_buffer_.begin() + putback_max);
00244 if (unbuffered_)
00245 setp(0, 0);
00246 else
00247 setp(put_buffer_.begin(), put_buffer_.end());
00248 }
00249
00250 void resolve_and_connect(const typename Protocol::resolver_query& query,
00251 asio::error_code& ec)
00252 {
00253 typedef typename Protocol::resolver resolver_type;
00254 typedef typename Protocol::resolver_iterator iterator_type;
00255 resolver_type resolver(
00256 boost::base_from_member<asio::io_service>::member);
00257 iterator_type i = resolver.resolve(query, ec);
00258 if (!ec)
00259 {
00260 iterator_type end;
00261 ec = asio::error::host_not_found;
00262 while (ec && i != end)
00263 {
00264 this->basic_socket<Protocol, StreamSocketService>::close();
00265 this->basic_socket<Protocol, StreamSocketService>::connect(*i, ec);
00266 ++i;
00267 }
00268 }
00269 }
00270
00271 enum { putback_max = 8 };
00272 enum { buffer_size = 512 };
00273 boost::array<char, buffer_size> get_buffer_;
00274 boost::array<char, buffer_size> put_buffer_;
00275 bool unbuffered_;
00276 };
00277
00278 }
00279
00280 #undef ASIO_PRIVATE_CONNECT_DEF
00281
00282 #include "asio/detail/pop_options.hpp"
00283
00284 #endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP