Main Page | Modules | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

basic_socketbuf.h

Go to the documentation of this file.
00001 // -*- Socket Streams -*-
00002 
00003 // Copyright (C) 2003, 2004, 2005 Pedro LamarĂ£o <pedro.lamarao@mndfck.org>
00004 
00005 // This file is part of the Socket Streams Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU Lesser General Public License as published by the
00008 // Free Software Foundation; either version 2.1 of the License
00009 // or (at your option) any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU Lesser General Public License for more details.
00015 
00016 // You should have received a copy of the GNU Lesser General Public License along
00017 // with this library; see the file COPYING. If not, write to the Free
00018 // Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
00019 // USA
00020 
00025 #ifndef SOCKETSTREAM_BASIC_SOCKETBUF_H
00026 #define SOCKETSTREAM_BASIC_SOCKETBUF_H 1
00027 
00028 #include <socketstream/config.h>
00029 
00030 #include <cerrno>
00031 #include <streambuf>
00032 #include <socketstream/basic_socket.h>
00033 #include <socketstream/address_factory.h>
00034 
00035 #ifdef WIN32
00036 # define EWOULDBLOCK WSAEWOULDBLOCK
00037 #endif
00038 
00039 #define SOCKETSTREAM_BUFSIZE 32
00040 
00041 namespace ss {
00042 
00049   template <typename _CharT, typename _Traits>
00050   class basic_socketbuf
00051   : public std::basic_streambuf<_CharT, _Traits>
00052   {
00053   public:
00054 
00056 
00063     typedef _CharT     char_type;
00064     typedef _Traits  traits_type;
00065     
00066     typedef typename traits_type::int_type  int_type;
00067     typedef typename traits_type::pos_type  pos_type;
00068     typedef typename traits_type::off_type  off_type;
00070 
00071     typedef std::basic_streambuf<char_type, traits_type> __streambuf_type;
00072     typedef basic_socketbuf<char_type, traits_type> __socketbuf_type;
00073     
00074     template <typename C, typename T>
00075     friend class basic_socketstream;
00076 
00082     basic_socketbuf()
00083     : __streambuf_type(), _M_socket(), _M_flags(sockets_base::def::flag),
00084       _M_buf(0), _M_buf_size(SOCKETSTREAM_BUFSIZE),
00085       _M_put_buf_size(), _M_get_buf_size(),
00086       _M_buf_allocated(false),
00087           _M_open(false)
00088     {}
00089 
00100     basic_socketbuf (sockets_base::family __f, sockets_base::style __s)
00101     : __streambuf_type(), _M_socket(__f, __s), _M_flags(sockets_base::def::flag),
00102       _M_buf(0), _M_buf_size(SOCKETSTREAM_BUFSIZE),
00103       _M_put_buf_size(), _M_get_buf_size(),
00104       _M_buf_allocated(false),
00105           _M_open(false)
00106     {}
00107 
00111     virtual
00112     ~basic_socketbuf()
00113     { _M_destroy_internal_buffer(); }
00114 
00123         template <typename AddressT>
00124     __socketbuf_type*
00125     connect (AddressT& __addr)
00126     {
00127       try
00128       {
00129         _M_socket.connect(&__addr, sizeof(__addr));
00130         _M_allocate_internal_buffer();
00131       }
00132       catch (const socket_exception& se)
00133       {
00134         switch (se.code())
00135         {
00136           case EWOULDBLOCK:
00137             // we can't return anything sensible anywhere else, be consistent
00138           default:
00139             throw;
00140         }
00141       }
00142 
00143       _M_open = true;
00144       return this;
00145     }
00146 
00150     bool
00151     is_open () const throw ()
00152     {
00153       return _M_open; // TODO: FIXME!
00154     }
00155 
00166     __socketbuf_type*
00167     shutdown (sockets_base::shutmode __mode = sockets_base::rw) throw ()
00168     {
00169       if (is_open())
00170         _M_socket.shutdown(__mode);
00171       _M_open = false;
00172       return this;      
00173     }
00174 
00180     basic_socket&
00181     socket ()
00182     {
00183       return _M_socket;
00184     }
00185 
00191     sockets_base::flag
00192     setf (sockets_base::flag __f)
00193     {
00194       sockets_base::flag __old = _M_flags;
00195       _M_flags = __f;
00196       return __old;
00197     }
00198 
00199   protected:
00200 
00208     basic_socketbuf(basic_socket::descriptor_t descriptor)
00209     : __streambuf_type(), _M_socket(descriptor),
00210       _M_flags(sockets_base::def::flag),
00211       _M_buf(0), _M_buf_size(SOCKETSTREAM_BUFSIZE),
00212       _M_put_buf_size(), _M_get_buf_size(),
00213       _M_buf_allocated(false),
00214           _M_open(false)
00215     {}
00216 
00228     virtual int_type
00229     underflow ()
00230     {
00231       int_type __ret = traits_type::eof();
00232       try
00233       {
00234         if (_M_get_buf_size > 0) // buffered input
00235         {
00236           const size_t __buflen = _M_get_buf_size;
00237           int __num = _M_socket.receive(this->eback(), __buflen, _M_flags);
00238           if (__num > 0)
00239           {
00240             this->setg(this->eback(), this->eback(), this->eback() + __num);
00241             __ret = traits_type::to_int_type(*this->gptr());
00242           }
00243         }
00244         else // unbuffered input
00245         {
00246           char_type c = __ret;
00247           if (_M_socket.receive(&c, 1, _M_flags) > 0)
00248           {
00249             __ret = traits_type::to_int_type(c);
00250           }
00251         }
00252       }
00253       catch (const socket_exception& e)
00254       {
00255         switch (e.code())
00256         {
00257           case EWOULDBLOCK:
00258             // we can't return anything sensible, can we?
00259           case EINTR:
00260           default:
00261             throw;
00262         }
00263       }
00264       return __ret;
00265     }
00266 
00277      virtual int_type
00278      uflow ()
00279      {
00280        int_type __ret = this->underflow();
00281        if (__ret != traits_type::eof() && _M_get_buf_size > 0)
00282        {
00283          this->gbump(1);
00284        }
00285        return __ret;
00286      }
00287      
00300     virtual int_type
00301     overflow (int_type __c = traits_type::eof())
00302     {
00303       int_type __ret = traits_type::eof();
00304       const bool __testeof = traits_type::eq_int_type(__c, __ret);
00305       try
00306       {
00307         if (!__testeof)
00308         {
00309           *this->pptr() = traits_type::to_char_type(__c);
00310           this->pbump(1);
00311         }
00312         int __num = _M_socket.send(this->pbase(), this->pptr() - this->pbase(), _M_flags);
00313         if (__num > 0)
00314         {
00315           this->pbump(-__num);
00316           __ret = __c;
00317         }
00318       }
00319       catch (const socket_exception& e)
00320       {
00321         switch (e.code())
00322         {
00323           case EPIPE:
00324             return traits_type::eof();
00325           case EWOULDBLOCK:
00326             // we can't return anything sensible, can we?
00327           case EINTR:
00328           default:
00329             throw;
00330         }
00331       }
00332       return __ret;
00333     }
00334 
00341     virtual __streambuf_type*
00342     setbuf (char_type *__s, std::streamsize __n)
00343     {
00344       if (!this->is_open() && __s == 0 && __n == 0)
00345       {
00346         _M_buf_size = 1;
00347       }
00348       else if (__s && __n > 0)
00349       {
00350         _M_destroy_internal_buffer();
00351         _M_buf = __s;
00352         _M_buf_size = __n;
00353         _M_get_buf_size = _M_buf_size / 2;
00354         _M_put_buf_size = _M_buf_size - _M_get_buf_size;
00355         this->setp(_M_buf, _M_buf + _M_put_buf_size - 1); // -1 for the overflow char
00356         this->setg(_M_buf + _M_put_buf_size,
00357                           _M_buf + _M_put_buf_size,
00358                           _M_buf + _M_put_buf_size);
00359       }
00360       return this;
00361     }
00362 
00366     virtual int
00367     sync ()
00368     {
00369       int __ret = 0;
00370       if (this->pbase() < this->pptr())
00371       {
00372         this->overflow();
00373       }
00374       return __ret;
00375     }
00376     
00383     virtual std::streamsize
00384     showmanyc ()
00385     {
00386       std::streamsize __ret = -1;
00387       if (this->is_open())
00388       {
00389         __ret = this->egptr() - this->gptr();
00390         char_type c;
00391         __ret += _M_socket.receive(&c, 1, sockets_base::peek);
00392       }
00393       return __ret;
00394     }
00395     
00405     virtual int_type
00406     pbackfail (int_type = traits_type::eof())
00407     {
00408       return traits_type::eof();
00409     }
00410   
00411   private:
00412   
00413     void
00414     _M_allocate_internal_buffer ()
00415     {
00416       if (!_M_buf_allocated && _M_buf_size)
00417       {
00418         _M_buf = new char_type[_M_buf_size];
00419         _M_buf_allocated = true;
00420       }
00421       _M_get_buf_size = _M_buf_size / 2;
00422       _M_put_buf_size = _M_buf_size - _M_get_buf_size;
00423       this->setp(_M_buf, _M_buf + _M_put_buf_size - 1); // -1 for the overflow char
00424       this->setg(_M_buf + _M_put_buf_size,
00425                         _M_buf + _M_put_buf_size,
00426                         _M_buf + _M_put_buf_size);
00427     }
00428 
00429     void
00430     _M_destroy_internal_buffer () throw ()
00431     {
00432       if (_M_buf_allocated)
00433       {
00434         delete [] _M_buf;
00435         _M_buf = 0;
00436         _M_buf_allocated = false;
00437       }
00438       this->setp(0, 0);
00439       this->setg(0, 0, 0);
00440     }
00441 
00442   private:
00443 
00444         basic_socketbuf (basic_socketbuf<char_type, traits_type> const&);
00445         basic_socketbuf<char_type, traits_type>&
00446         operator= (basic_socketbuf<char_type, traits_type> const&);
00447 
00448     basic_socket _M_socket;
00449   
00450     sockets_base::flag _M_flags;
00451   
00452     char_type* _M_buf;
00453     size_t     _M_buf_size;
00454     size_t     _M_put_buf_size;
00455     size_t     _M_get_buf_size;
00456     bool       _M_buf_allocated;
00457 
00458         bool       _M_open;
00459 
00460   };
00461 
00462   typedef basic_socketbuf<char, std::char_traits<char> > socketbuf;
00463 
00464 }
00465 
00466 #endif  // SOCKETSTREAM_BASIC_SOCKETBUF_H

Generated on Sat May 21 21:25:32 2005 for Socket Streams Library by  doxygen 1.4.3