sockbuf.h

Go to the documentation of this file.
00001 /*
00002     socklibpp library
00003     Copyright (C) 2005  Daniel K. O. <danielosmari at users.sf.net>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Lesser General Public
00007     License as published by the Free Software Foundation; either
00008     version 2.1 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Lesser General Public License for more details.
00014 
00015     You should have received a copy of the GNU Lesser General Public
00016     License along with this library; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 */
00019 
00020 
00021 
00022 #ifndef SOCKBUF_H
00023 #define SOCKBUF_H
00024 
00025 
00029 #include <new>
00030 #include <streambuf>
00031 #include <memory>
00032 
00033 #include "sockbase.h"
00034 
00035 namespace socklibpp {
00036 
00037 
00038 /* TODO (DanielKO#1#): Replace the exceptions by socket-specific ones */
00039 
00040 
00041 
00052 template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
00053 class basic_sockbuf : public std::basic_streambuf<_CharT, _Traits>
00054 {
00055 public:
00056         // Types:
00057         typedef _CharT                          char_type;
00058         typedef _Traits                         traits_type;
00059         typedef typename traits_type::int_type  int_type;
00060         typedef typename traits_type::pos_type  pos_type;
00061         typedef typename traits_type::off_type  off_type;
00062 
00063         typedef std::basic_streambuf<char_type, traits_type> __streambuf_type;
00064 
00065 protected:
00066 
00068         sock _M_socket;
00069 
00071         char *_M_ibuffer, *_M_obuffer;
00072 
00074         int _M_buf_size;
00075 
00076 
00077 public:
00079         basic_sockbuf() :
00080                 _M_socket(sock::invalid_socket)
00081         {
00082                 _M_buffer_init();
00083         }
00084 
00090         explicit
00091         basic_sockbuf(sock sock_)
00092         :       _M_socket(sock_)
00093         {
00094                 _M_buffer_init();
00095         }
00096         
00097 
00099         explicit
00100         basic_sockbuf(const addr_in& _sin)
00101         :       _M_socket(sock::invalid_socket)
00102         {
00103                 _M_buffer_init();
00104                 connect(_sin);
00105         }
00106         
00107 
00109         virtual
00110         ~basic_sockbuf()
00111         {
00112                 sync();
00113                 close();
00114                 _M_buffer_delete();
00115         }
00116 
00118         sock
00119         socket() const
00120         throw()
00121         {
00122                return _M_socket;
00123         }
00124 
00125 
00127         void
00128         socket(sock sock_)
00129         throw()
00130         {
00131                 _M_socket = sock_;
00132         }
00133         
00134         
00138         bool
00139         connect(const addr_in& _sin)
00140         throw ()
00141         {
00142                 if (_M_socket.fd == sock::invalid_socket)
00143                         if (!_M_socket.create(  sock::pf_inet,
00144                                                 sock::sock_stream,
00145                                                 sock::proto_ip))
00146                                 return false;
00147                                                 
00148                 return _M_socket.connect(_sin);
00149         }
00150         
00151         
00157         bool
00158         connect(const std::string& _addr, uint16_t _port)
00159         throw()
00160         {
00161                 addr_in _sin;
00162 
00163                 if (!_sin.ip(_addr))
00164                         if (!_sin.resolve(_addr))
00165                                 return false;
00166 
00167                 _sin.port(_port);
00168 
00169                 return connect(_sin);
00170         }
00171 
00172 
00174         basic_sockbuf*
00175         close()
00176         throw()
00177         {
00178                 bool _s = _M_socket.close();
00179                 _M_socket.fd = sock::invalid_socket;
00180 
00181                 return  _s ? 0 : this;
00182         }
00183         
00184 
00193         bool can_read(uint32_t usec_=0, uint32_t sec_ = 0)
00194         throw (std::ios_base::failure)
00195         {
00196                 if (_M_socket.can_read(usec_, sec_))
00197                         return true;
00198                 if (_M_socket.error)
00199                         throw std::ios_base::failure("basic_sockbuf::can_read()");
00200                 return false;
00201         }
00202         
00203 
00212         bool can_write(uint32_t _usec=0, uint32_t _sec = 0)
00213         throw (std::ios_base::failure)
00214         {
00215                 if (_M_socket.can_write(_usec, _sec))
00216                         return true;
00217                 if (_M_socket.error)
00218                         throw std::ios_base::failure("basic_sockbuf::can_write");
00219                 return false;
00220         }
00221         
00222 
00224         bool is_connected() const
00225         throw()
00226         {
00227                 addr_in _sin;
00228                 if (!_M_socket.peername(_sin))
00229                         return false;
00230                 return true;
00231         }
00232 
00233 protected:
00234         // Common initialization code for both ctors goes here.
00235         void _M_buffer_init(int _sz = 1024)
00236         {
00237                 _M_buf_size = _sz;
00238                 _M_ibuffer = new char_type[ (_M_buf_size+1) * 2 ];
00239                 _M_obuffer = _M_ibuffer + _M_buf_size + 1;
00240 
00241                 this->setg(_M_ibuffer, _M_ibuffer + 1, _M_ibuffer + 1);
00242                 this->setp(_M_obuffer, _M_obuffer + _M_buf_size);
00243         }
00244         
00245         void _M_buffer_delete()
00246         {
00247                 delete[] _M_ibuffer;
00248         }
00249 
00250 
00252         virtual int_type
00253         underflow()
00254         {
00255                 *this->eback() = -1[this->gptr()];  // to allow putback operations
00256 
00257                 int result = _M_socket.recv(this->eback() + 1 , _M_buf_size);
00258 
00259                 if (result < 1)
00260                         return traits_type::eof();
00261 
00262                 this->setg(this->eback(), this->eback()+1, this->eback() + result + 1);
00263                 
00264                 return traits_type::to_int_type(*this->gptr());
00265         }
00266         
00267 
00269         virtual int
00270         showmanyc()
00271         {
00272                 unsigned long data;
00273                 if (!_M_socket.ioctl(sock::fionread, data))
00274                         return -1;
00275                 return data;
00276         }
00277         
00278 
00280         virtual int_type
00281         overflow(int_type __c = traits_type::eof())
00282         {
00283                 char *s1 = this->pbase();
00284                 char *s2 = this->pptr();
00285                 
00286                 int num = s2-s1;
00287 
00288                 /* TODO (DanielKO#2#): Make overflow use socklibpp::sock::sendall() */
00289                 if (__c != traits_type::eof()) {
00290                         *this->pptr() = __c;
00291                         ++num;
00292                 }
00293                 
00294                 if (!num)
00295                         return traits_type::eof();
00296 
00297                 int result = _M_socket.send(s1, num);
00298 
00299                 if (_M_socket.error)
00300                         return traits_type::eof();
00301 
00302                 if (result != num)      // didn't write everything
00303                         std::memmove(
00304                                 s1,
00305                                 s1 + result,
00306                                 num - result);
00307 
00308                 this->setp(_M_obuffer, _M_obuffer + _M_buf_size);
00309 
00310                 return traits_type::to_int_type(num);
00311         }
00312 
00313 
00315         virtual int
00316         sync()
00317         {
00318                 while (this->pptr() > this->pbase())
00319                         if (overflow(traits_type::eof()) == traits_type::eof())
00320                                 return -1;
00321                                 
00322                 return 0;
00323         }
00324 
00325 
00335         /* TODO (DanielKO#2#): Improve setbuf */
00336         virtual __streambuf_type*
00337         setbuf(char_type*, std::streamsize _n)
00338         {
00339                 if (_n<2)
00340                         return 0;
00341                 try {
00342                         _M_buffer_delete();
00343                         _M_buffer_init(_n);
00344                         return this;
00345                 }
00346                 catch(...)
00347                 {
00348                         return 0;
00349                 }
00350         }
00351 
00352 /* TODO (DanielKO#4#): Implement xsputn if the current default 
00353                        inherited implementation is slow. (Need to make some 
00354                        performance tests) */
00355 
00356 
00357 
00358 };
00359 
00360 
00362 typedef basic_sockbuf<char>     sockbuf;
00363 
00364 }
00365 
00366 #endif

Generated on Thu Jan 18 19:26:35 2007 for socklib++ by  doxygen 1.5.1