Socketbuf.cpp

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 //------------------------------------------------------------------------------
00003 //                             Socketbuf.cpp
00004 //------------------------------------------------------------------------------
00005 //  Copyright (C) 1997-2002,2005  Vladislav Grinchenko
00006 //
00007 //  This library is free software; you can redistribute it and/or
00008 //  modify it under the terms of the GNU Library General Public
00009 //  License as published by the Free Software Foundation; either
00010 //  version 2 of the License, or (at your option) any later version.
00011 //------------------------------------------------------------------------------
00012 //  Created: 12/03/99
00013 //------------------------------------------------------------------------------
00014 
00015 #include "assa/Socket.h"
00016 #include "assa/Socketbuf.h"
00017 #include "assa/MemDump.h"
00018 
00019 using namespace ASSA;
00020 
00021 Socketbuf::
00022 Socketbuf (Socket* s_) 
00023     : m_s (s_) 
00024 {
00025     trace_with_mask("Socketbuf::Socketbuf",STRMBUFTRACE);
00026     // By default, I am doing buffering IO
00027     unbuffered (0);
00028 }
00029 
00030 int  
00031 Socketbuf::
00032 sync () 
00033 { 
00034     trace_with_mask("Socketbuf::sync",STRMBUFTRACE);
00035     return flush_output (); 
00036 }
00037 
00038 int  
00039 Socketbuf::
00040 showmanyc () 
00041 { 
00042     trace_with_mask("Socketbuf::showmanyc",STRMBUFTRACE);
00043     return m_s->getBytesAvail (); 
00044 }
00045 
00046 void
00047 Socketbuf::
00048 xput_char (char c_) 
00049 { 
00050     trace_with_mask("Socketbuf::xput_char",STRMBUFTRACE);
00051     *pptr() = c_; 
00052     pbump (1); 
00053 }
00054 
00055 Socketbuf::
00056 ~Socketbuf ()
00057 {
00058     trace_with_mask("Socketbuf::~Socketbuf",STRMBUFTRACE);
00059     overflow (EOF);     // flush put area
00060 }
00061 
00062 int  
00063 Socketbuf::
00064 sys_read  (char* b_, int len_) 
00065 { 
00066     trace_with_mask("Socketbuf::sys_read",STRMBUFTRACE);
00067     
00068     int ret = ::read (m_s->getHandler (), b_, len_);
00069 
00070     DL((STRMBUFTRACE,"Tried to read %d bytes from OS::socket\n", len_));
00071     DL((STRMBUFTRACE,"::read () returned %d\n", ret));
00072 
00073     if (ret == -1) {
00074         DL((STRMBUFTRACE,"::read () error: %d\n",errno));
00075     }
00076     return (ret);
00077 }
00078 
00079 int  
00080 Socketbuf::
00081 sys_write (char* b_, int len_) 
00082 { 
00083     trace_with_mask("Socketbuf::sys_write",STRMBUFTRACE);
00084 
00085     int ret = ::write (m_s->getHandler (), b_, len_);
00086 
00087     DL((STRMBUFTRACE,"Tried to write %d bytes to OS::socket\n", len_));
00088     DL((STRMBUFTRACE,"::write () returned %d\n", ret));
00089 
00090     if (ret == -1) {
00091         DL((STRMBUFTRACE,"::write () error: %d\n",errno));
00092     }
00093 
00094     return (ret);
00095 }
00096 
00097 int  
00098 Socketbuf::
00099 underflow ()
00100 {
00101     /*
00102       The important thing to note is that this function
00103       returns:
00104         a) pointer to the first character in buffer available.
00105         b) EOF if sys_read () failed.
00106         
00107       In case of peer closing its connection, a) will be true.
00108       Caller can always find out number of bytes in buffer
00109       and determine if peer indeed closed connection.
00110     */
00111     trace_with_mask("Socketbuf::underflow",STRMBUFTRACE);
00112 
00113     if (gptr () < egptr ())                   // The get area is not empty,
00114         return *(unsigned char*) gptr (); //  return 1st character
00115 
00116     if (base () == 0 &&    // If buffer isn't established,
00117         doallocate () == EOF)  // allocate buffer (both buff & unbuff IO)
00118         return EOF;
00119 
00120     int bufsz = unbuffered () ? 1 : MAXTCPFRAMESZ;
00121 
00122     /*
00123       Read as much as I can up to the allocated buffer size.
00124       EOF = (-1).
00125     */
00126     int rval = sys_read (base (), bufsz); 
00127 
00128     DL((STRMBUF,"Socketbuf::sys_read() returned %d bytes\n", rval));
00129 
00130     if (rval == EOF) {
00131 
00132         if (errno != EWOULDBLOCK) {
00133             m_flags |= EOF_SEEN;
00134         }
00135         return EOF;
00136     }
00137 
00138     DL((STRMBUF,"Having read %d bytes from socket\n",rval));
00139     MemDump::dump_to_log (STRMBUF, "Data received:", base (), rval);
00140 
00141     // Set get area pointers according to the data just read
00142 
00143     setg (base (), base (), base () + rval); 
00144 
00145     dump ();
00146 
00147     return *(unsigned char*) gptr (); // Return front character
00148 }
00149 
00150 int
00151 Socketbuf::
00152 overflow (int c_)
00153 {
00154     trace_with_mask("Socketbuf::overflow",STRMBUFTRACE);
00155 
00156     // If c == EOF, return flush_output()
00157     // Otherwise, insert c into the buffer
00158 
00159     if (c_ == EOF)
00160         return flush_output ();
00161 
00162     if (pbase () == 0 && doallocate () == EOF)
00163         return EOF;
00164 
00165     if (pptr () >= epptr() && flush_output () == EOF)
00166         return EOF;
00167 
00168     xput_char (c_);
00169 
00170     dump ();
00171 
00172     if ((unbuffered () || pptr () >= epptr ()) && flush_output () == EOF) 
00173         return EOF;
00174 
00175     dump ();
00176 
00177     return c_;
00178 }
00179 
00180 int
00181 Socketbuf::
00182 flush_output ()
00183 {
00184     trace_with_mask("Socketbuf::flush_output",STRMBUFTRACE);
00185 
00186     if (pptr () <= pbase ()) {  // Nothing to flush
00187         return 0;
00188     }
00189 
00190     int requested;
00191     int xmitted;
00192 
00193     requested = pptr () - pbase ();
00194 
00195     if ((xmitted = sys_write (pbase (), requested)) < 0) {
00196         return EOF;
00197     }
00198 
00199     if (unbuffered ()) {
00200         setp (pbase (), epptr ());
00201         return 0;
00202     }
00203 
00204     requested -= xmitted;
00205     setp (pbase (), pbase () + MAXTCPFRAMESZ);
00206     pbump (requested);
00207 
00208     if (requested > 0) {
00209         ::memmove (pbase (), pbase () + xmitted, requested);
00210     }
00211 
00212     return 0;
00213 }
00214 
00215 int
00216 Socketbuf::doallocate ()
00217 {
00218     trace_with_mask("Socketbuf::doallocate",STRMBUFTRACE);
00219 
00220     // Get area comes first and matches entier buffer area.
00221     // Put area comes right after it. They are two equally-sized
00222     // separate buffers.
00223     //
00224     // ------------ -
00225     // |          | ^
00226     // | get area | | buffer area
00227     // |          | v
00228     // ------------ -
00229     // | put area |
00230     // |          |
00231     // ------------
00232     //
00233     // Return 1 on allocation and 0 if there is no need
00234 
00235     if (m_buf_base)
00236         return 0;
00237 
00238     if ( ! (m_flags & UNBUFFERED) ) {
00239         DL((STRMBUF,"Buffered IO - allocating %d bytes\n",
00240             2 * MAXTCPFRAMESZ));
00241         char* buf = new char [2 * MAXTCPFRAMESZ];
00242 
00243         setg (buf, buf + MAXTCPFRAMESZ, buf + MAXTCPFRAMESZ);
00244         setb (buf, buf + MAXTCPFRAMESZ, 1);
00245    
00246         buf += MAXTCPFRAMESZ;
00247         setp (buf, buf+MAXTCPFRAMESZ);
00248     }
00249     else {
00250         DL((STRMBUF,"Unbuffered IO - same 1 byte array\n"));
00251         setb (m_shortbuf, m_shortbuf+1, 0);
00252 
00253         // read_base is pointing to the begining,  and
00254         // read_end to one past end of the buffer.
00255         // Because buffer is empty, read_ptr should point
00256         // to the end (same as read_end). This way, calling
00257         // routines will detect that get area needs data from sync.
00258         //
00259         // +- read_base   +- read_ptr 
00260         // |              |- read_end 
00261         // |              |+----- one past end-of-block
00262         // v              vv
00263         // +--------------+-+
00264         // | get area     | |
00265         // +--------------+-+
00266         setg (m_shortbuf, m_shortbuf+1, m_shortbuf+1);
00267 
00268         // write_base  & write_ptr are pointing to the begining, 
00269         // and write_end to one past end of the buffer.
00270         // Because buffer is empty, read_ptr should point
00271         // to the beginning (same as write_base). This way, calling
00272         // routines will detect that put area needs data from sync.
00273         //
00274         // +- write_base   +- write_end points one past 
00275         // |- write_ptr    |    end-of-block
00276         // v               v
00277         // +--------------+-+
00278         // | put area     | |
00279         // +--------------+-+
00280 
00281         setp (m_shortbuf, m_shortbuf+1);
00282     }
00283     dump ();
00284     return 1;
00285 }
00286 
00287 

Generated on Mon Dec 19 15:59:01 2005 for libassa by  doxygen 1.4.5