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

Generated on Sun Aug 13 15:08:00 2006 for libassa by  doxygen 1.4.6