00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef BOOST_CMT_ASIO_BASIC_SOCKET_STREAMBUF_HPP
00012 #define BOOST_CMT_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 <boost/asio/detail/config.hpp>
00019
00020 #if !defined(BOOST_NO_IOSTREAM)
00021
00022 #include <streambuf>
00023 #include <boost/array.hpp>
00024 #include <boost/preprocessor/arithmetic/inc.hpp>
00025 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
00026 #include <boost/preprocessor/repetition/enum_params.hpp>
00027 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
00028 #include <boost/asio/basic_socket.hpp>
00029 #include <boost/asio/detail/throw_error.hpp>
00030 #include <boost/asio/io_service.hpp>
00031 #include <boost/asio/stream_socket_service.hpp>
00032 #include <boost/cmt/asio.hpp>
00033
00034 #if !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY)
00035 #define BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY 5
00036 #endif // !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY)
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 #define BOOST_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 boost::system::error_code ec; \
00061 this->basic_socket<Protocol, StreamSocketService>::close(ec); \
00062 typedef typename Protocol::resolver resolver_type; \
00063 typedef typename resolver_type::query resolver_query; \
00064 resolver_query query(BOOST_PP_ENUM_PARAMS(n, x)); \
00065 resolve_and_connect(query, ec); \
00066 return !ec ? this : 0; \
00067 } \
00068
00069
00070 #include <boost/asio/detail/push_options.hpp>
00071
00072
00073 namespace boost {
00074 namespace cmt {
00075 namespace asio {
00076
00077 using namespace boost::asio;
00078
00080 template <typename Protocol,
00081 typename StreamSocketService = stream_socket_service<Protocol> >
00082 class basic_socket_streambuf
00083 : public std::streambuf,
00084 public basic_socket<Protocol, StreamSocketService>
00085 {
00086 public:
00088 typedef typename Protocol::endpoint endpoint_type;
00089
00091 basic_socket_streambuf()
00092 : basic_socket<Protocol, StreamSocketService>(
00093 boost::cmt::asio::default_io_service() ),
00094 unbuffered_(false)
00095 {
00096 init_buffers();
00097 }
00098
00100 virtual ~basic_socket_streambuf()
00101 {
00102 if (pptr() != pbase())
00103 overflow(traits_type::eof());
00104 }
00105
00107
00113 basic_socket_streambuf<Protocol, StreamSocketService>* connect(
00114 const endpoint_type& endpoint)
00115 {
00116 init_buffers();
00117 boost::system::error_code ec;
00118 this->basic_socket<Protocol, StreamSocketService>::close(ec);
00119
00120 stack_retainable<promise<boost::system::error_code> > p;
00121 this->basic_socket<Protocol, StreamSocketService>::async_connect(endpoint,
00122 boost::bind( boost::cmt::asio::detail::error_handler_ec, &p, _1 ));
00123 return !p.wait() ? this : 0;
00124 }
00125
00126 #if defined(GENERATING_DOCUMENTATION)
00127
00128
00136 template <typename T1, ..., typename TN>
00137 basic_socket_streambuf<Protocol, StreamSocketService>* connect(
00138 T1 t1, ..., TN tn);
00139 #else
00140 BOOST_PP_REPEAT_FROM_TO(
00141 1, BOOST_PP_INC(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY),
00142 BOOST_ASIO_PRIVATE_CONNECT_DEF, _ )
00143 #endif
00144
00146
00150 basic_socket_streambuf<Protocol, StreamSocketService>* close()
00151 {
00152 boost::system::error_code ec;
00153 sync();
00154 this->basic_socket<Protocol, StreamSocketService>::close(ec);
00155 if (!ec)
00156 init_buffers();
00157 return !ec ? this : 0;
00158 }
00159
00160 protected:
00161 int_type underflow()
00162 {
00163 if (gptr() == egptr())
00164 {
00165 boost::system::error_code ec;
00166 stack_retainable<promise<size_t> > p;
00167 this->service.async_receive(
00168 this->implementation,
00169 boost::asio::buffer(boost::asio::buffer(get_buffer_) + putback_max),
00170 0, boost::bind( boost::cmt::asio::detail::read_write_handler_ec, &p, &ec, _1, _2 ));
00171 std::size_t bytes_transferred = p.wait();
00172 if (ec)
00173 return traits_type::eof();
00174 setg(get_buffer_.begin(), get_buffer_.begin() + putback_max,
00175 get_buffer_.begin() + putback_max + bytes_transferred);
00176 return traits_type::to_int_type(*gptr());
00177 }
00178 else
00179 {
00180 return traits_type::eof();
00181 }
00182 }
00183
00184 int_type overflow(int_type c)
00185 {
00186 if (unbuffered_)
00187 {
00188 if (traits_type::eq_int_type(c, traits_type::eof()))
00189 {
00190
00191 return traits_type::not_eof(c);
00192 }
00193 else
00194 {
00195
00196 boost::system::error_code ec;
00197 char_type ch = traits_type::to_char_type(c);
00198
00199
00200
00201
00202
00203
00204 stack_retainable<promise<size_t> > p;
00205 this->service.async_send(
00206 this->implementation,
00207 boost::asio::buffer(&ch, sizeof(char_type)),
00208 0, boost::bind( boost::cmt::asio::detail::read_write_handler_ec, &p, &ec, _1, _2 ));
00209 std::size_t bytes_transferred = p.wait();
00210 if (ec)
00211 return traits_type::eof();
00212 return c;
00213 }
00214 }
00215 else
00216 {
00217
00218 boost::asio::const_buffer buffer =
00219 boost::asio::buffer(pbase(), pptr() - pbase());
00220 while (boost::asio::buffer_size(buffer) > 0)
00221 {
00222 boost::system::error_code ec;
00223
00224
00225
00226 stack_retainable<promise<size_t> > p;
00227 this->service.async_send(
00228 this->implementation, boost::asio::buffer(buffer),
00229 0, boost::bind( boost::cmt::asio::detail::read_write_handler_ec, &p, &ec, _1, _2 ));
00230 std::size_t bytes_transferred = p.wait();
00231 if (ec)
00232 return traits_type::eof();
00233 buffer = buffer + bytes_transferred;
00234 }
00235 setp(put_buffer_.begin(), put_buffer_.end());
00236
00237
00238 if (traits_type::eq_int_type(c, traits_type::eof()))
00239 return traits_type::not_eof(c);
00240
00241
00242 *pptr() = traits_type::to_char_type(c);
00243 pbump(1);
00244 return c;
00245 }
00246 }
00247
00248 int sync()
00249 {
00250 return overflow(traits_type::eof());
00251 }
00252
00253 std::streambuf* setbuf(char_type* s, std::streamsize n)
00254 {
00255 if (pptr() == pbase() && s == 0 && n == 0)
00256 {
00257 unbuffered_ = true;
00258 setp(0, 0);
00259 return this;
00260 }
00261
00262 return 0;
00263 }
00264
00265 private:
00266
00267 void init_buffers()
00268 {
00269 setg(get_buffer_.begin(),
00270 get_buffer_.begin() + putback_max,
00271 get_buffer_.begin() + putback_max);
00272 if (unbuffered_)
00273 setp(0, 0);
00274 else
00275 setp(put_buffer_.begin(), put_buffer_.end());
00276 }
00277
00278 template <typename ResolverQuery>
00279 void resolve_and_connect(const ResolverQuery& query,
00280 boost::system::error_code& ec)
00281 {
00282 typedef typename Protocol::resolver resolver_type;
00283 typedef typename resolver_type::iterator iterator_type;
00284 resolver_type resolver(
00285 boost::cmt::asio::default_io_service() );
00286 iterator_type i = resolver.resolve(query, ec);
00287 if (!ec)
00288 {
00289 iterator_type end;
00290 ec = boost::asio::error::host_not_found;
00291 while (ec && i != end)
00292 {
00293 this->basic_socket<Protocol, StreamSocketService>::close();
00294 this->basic_socket<Protocol, StreamSocketService>::connect(*i, ec);
00295 ++i;
00296 }
00297 }
00298 }
00299
00300 enum { putback_max = 8 };
00301 enum { buffer_size = 512 };
00302 boost::array<char, buffer_size> get_buffer_;
00303 boost::array<char, buffer_size> put_buffer_;
00304 bool unbuffered_;
00305 };
00306 }
00307 }
00308 }
00309
00310 #include <boost/asio/detail/pop_options.hpp>
00311
00312 #undef BOOST_ASIO_PRIVATE_CONNECT_DEF
00313
00314 #endif // !defined(BOOST_NO_IOSTREAM)
00315
00316 #endif // BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP