$search
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