basic_socket_streambuf.hpp
Go to the documentation of this file.
00001 //
00002 // basic_socket_streambuf.hpp
00003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
00004 //
00005 // Copyright (c) 2003-2008 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 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 // A macro that should expand to:
00040 //   template <typename T1, ..., typename Tn>
00041 //   basic_socket_streambuf<Protocol, StreamSocketService>* connect(
00042 //       T1 x1, ..., Tn xn)
00043 //   {
00044 //     init_buffers();
00045 //     asio::error_code ec;
00046 //     this->basic_socket<Protocol, StreamSocketService>::close(ec);
00047 //     typedef typename Protocol::resolver_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 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         // Nothing to do.
00179         return traits_type::not_eof(c);
00180       }
00181       else
00182       {
00183         // Send the single character immediately.
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       // Send all data in the output buffer.
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       // If the new character is eof then our work here is done.
00211       if (traits_type::eq_int_type(c, traits_type::eof()))
00212         return traits_type::not_eof(c);
00213 
00214       // Add the new character to the output buffer.
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 } // namespace asio
00279 
00280 #undef ASIO_PRIVATE_CONNECT_DEF
00281 
00282 #include "asio/detail/pop_options.hpp"
00283 
00284 #endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines


Castor
Author(s): Carpe Noctem
autogenerated on Fri Nov 8 2013 11:05:39