Bytemaster's Boost Libraries
/Users/dlarimer/dev/libs/cmt/include/boost/cmt/asio/basic_socket_streambuf.hpp
00001 //
00002 // basic_socket_streambuf.hpp
00003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
00004 //
00005 // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
00006 //
00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 // A macro that should expand to:
00039 //   template <typename T1, ..., typename Tn>
00040 //   basic_socket_streambuf<Protocol, StreamSocketService>* connect(
00041 //       T1 x1, ..., Tn xn)
00042 //   {
00043 //     init_buffers();
00044 //     boost::system::error_code ec;
00045 //     this->basic_socket<Protocol, StreamSocketService>::close(ec);
00046 //     typedef typename Protocol::resolver resolver_type;
00047 //     typedef typename resolver_type::query resolver_query;
00048 //     resolver_query query(x1, ..., xn);
00049 //     resolve_and_connect(query, ec);
00050 //     return !ec ? this : 0;
00051 //   }
00052 // This macro should only persist within this file.
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     //TODO: MAKE ASYNC
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         // Nothing to do.
00191         return traits_type::not_eof(c);
00192       }
00193       else
00194       {
00195         // Send the single character immediately.
00196         boost::system::error_code ec;
00197         char_type ch = traits_type::to_char_type(c);
00198 
00199      //   boost::cmt::asio::write( *this, 
00200      //           boost::asio::buffer(&ch, sizeof(char_type)), ec);
00201 
00202       //      this->service.send(this->implementation,
00203       //          boost::asio::buffer(&ch, sizeof(char_type)), 0, ec);
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       // Send all data in the output buffer.
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  //       std::size_t bytes_transferred = boost::cmt::asio::write_some( this->implementation, 
00224   //                                      boost::asio::buffer(buffer), ec);
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       // If the new character is eof then our work here is done.
00238       if (traits_type::eq_int_type(c, traits_type::eof()))
00239         return traits_type::not_eof(c);
00240 
00241       // Add the new character to the output buffer.
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 } // namespace asio
00307 } // namespace cmt
00308 } // namespace boost
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
 All Classes Namespaces Files Functions Variables Typedefs Defines