bincimap

Log | Files | Refs | LICENSE

io.cc (10005B)


      1 /* -*- Mode: c++; -*- */
      2 /*  --------------------------------------------------------------------
      3  *  Filename:
      4  *    src/io/io.h
      5  *  
      6  *  Description:
      7  *    Implementation of the IO class.
      8  *
      9  *  Authors:
     10  *    Andreas Aardal Hanssen <andreas-binc curly bincimap spot org>
     11  *
     12  *  Bugs:
     13  *
     14  *  ChangeLog:
     15  *
     16  *  --------------------------------------------------------------------
     17  *  Copyright 2002-2005 Andreas Aardal Hanssen
     18  *
     19  *  This program is free software; you can redistribute it and/or modify
     20  *  it under the terms of the GNU General Public License as published by
     21  *  the Free Software Foundation; either version 2 of the License, or
     22  *  (at your option) any later version.
     23  *
     24  *  This program is distributed in the hope that it will be useful,
     25  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     26  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     27  *  GNU General Public License for more details.
     28  *
     29  *  You should have received a copy of the GNU General Public License
     30  *  along with this program; if not, write to the Free Software
     31  *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
     32  *  --------------------------------------------------------------------
     33  */
     34 #ifdef HAVE_CONFIG_H
     35 #include <config.h>
     36 #endif
     37 
     38 #include <string>
     39 
     40 #include "session.h"
     41 #include "io.h"
     42 
     43 
     44 using namespace ::std;
     45 using namespace Binc;
     46 
     47 //------------------------------------------------------------------------
     48 IO::IO()
     49 {
     50   pid = getpid();
     51   enabled = true;
     52   flushesOnEndl = true;
     53   mode = MODE_PLAIN;
     54   useLogPrefix = false;
     55   seqnr = 0;
     56   buffersize = 8192;
     57   transfertimeout = 0;
     58   inputsize = 0;
     59   inputlimit = true;
     60 }
     61 
     62 //------------------------------------------------------------------------
     63 IO::IO(FILE *fp)
     64 {
     65   pid = getpid();
     66   setFd(fp);
     67   enabled = true;
     68   flushesOnEndl = true;
     69   mode = MODE_PLAIN;
     70   useLogPrefix = false;
     71   seqnr = 0;
     72   buffersize = 8192;
     73   transfertimeout = 0;
     74   inputsize = 0;
     75   inputlimit = true;
     76 }
     77 
     78 //------------------------------------------------------------------------
     79 IO::~IO(void)
     80 {
     81   switch (mode) {
     82   case MODE_SYSLOG:
     83     closelog();
     84     break;
     85   default:
     86     break;
     87   }
     88 }
     89 
     90 //------------------------------------------------------------------------
     91 void IO::enable(void)
     92 {
     93   enabled = true;
     94 }
     95 
     96 //------------------------------------------------------------------------
     97 void IO::enableLogPrefix(void)
     98 {
     99   useLogPrefix = true;
    100 }
    101 
    102 //------------------------------------------------------------------------
    103 void IO::disable(void)
    104 {
    105   enabled = false;
    106 }
    107 
    108 //------------------------------------------------------------------------
    109 void IO::flushContent(void)
    110 {
    111   if (!enabled) return;
    112 
    113   string s = outputBuffer.str();
    114   string tmpstr;
    115   if (mode == MODE_SYSLOG) {
    116     tmpstr = "";
    117     for (string::iterator i = s.begin(); i != s.end(); ++i)
    118       if (*i != '\r' && *i != '\n') {
    119 	tmpstr += *i;
    120       } else {
    121 	writeStr(tmpstr);
    122 	tmpstr = "";
    123       }
    124 
    125     if (tmpstr != "")
    126       writeStr(tmpstr);
    127   } else
    128     writeStr(s);
    129 
    130 
    131   outputBuffer.clear();
    132 }
    133 
    134 //------------------------------------------------------------------------
    135 void IO::flushOnEndl(void)
    136 {
    137   flushesOnEndl = true;
    138 }
    139 
    140 //------------------------------------------------------------------------
    141 void IO::noFlushOnEndl(void)
    142 {
    143   flushesOnEndl = false;
    144 }
    145 
    146 //------------------------------------------------------------------------
    147 void IO::clear(void)
    148 {
    149   if (!enabled) return;
    150 
    151   outputBuffer.clear();
    152 }
    153 
    154 //------------------------------------------------------------------------
    155 void IO::setModeSyslog(const string &servicename, int facility = LOG_DAEMON)
    156 {
    157   static string sname;
    158   sname = servicename;
    159   if (mode != MODE_SYSLOG) {
    160     openlog(sname.c_str(), LOG_PID, facility);
    161     mode = MODE_SYSLOG;
    162   }
    163 }
    164 
    165 //------------------------------------------------------------------------
    166 void IO::setFd(FILE *fp)
    167 {
    168   fpout = fp;
    169 }
    170 
    171 //------------------------------------------------------------------------
    172 void IO::resetInput(void)
    173 {
    174   inputsize = 0;
    175 }
    176 
    177 //------------------------------------------------------------------------
    178 void IO::enableInputLimit(void)
    179 {
    180   inputlimit = true;
    181 }
    182 
    183 //------------------------------------------------------------------------
    184 void IO::disableInputLimit(void)
    185 {
    186   inputlimit = false;
    187 }
    188 
    189 //------------------------------------------------------------------------
    190 IO &IO::operator << (std::ostream &(*man)(std::ostream &))
    191 { 
    192   if (!enabled) return *this;
    193   
    194   if (useLogPrefix && outputBuffer.getSize() == 0) {
    195     outputBuffer << pid;
    196     outputBuffer << " ";
    197     outputBuffer << seqnr++;
    198     if (logprefix != "")
    199       outputBuffer << " [" << logprefix << "]";
    200     outputBuffer << " ";
    201   }
    202 
    203   static std::ostream &(*endl_funcpt)(std::ostream&) = std::endl;
    204   
    205   if (man == endl_funcpt) {
    206     outputBuffer << "\r\n";
    207     
    208     if (flushesOnEndl)
    209       flushContent();
    210   } else
    211     outputBuffer << man;
    212   
    213   if ((int) outputBuffer.getSize() >= buffersize)
    214     flushContent();
    215 
    216   return *this;
    217 }
    218 
    219 //------------------------------------------------------------------------
    220 int IO::select(int maxfd,
    221 	       fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
    222 	       int &timeout)
    223 {
    224   if (timeout == -1) return 1;
    225   struct timeval t1;
    226   struct timeval t2;
    227   int res;
    228 
    229   if (gettimeofday(&t1, 0) == -1) {
    230     setLastError("Failure in select: gettimeofday failed.");
    231     return -1;
    232   }
    233 
    234   do {
    235     struct timeval t;
    236     t.tv_sec = timeout;
    237     t.tv_usec = 0;
    238     res = ::select(maxfd, readfds, writefds, exceptfds, timeout ? &t : 0);
    239 
    240     if (gettimeofday(&t2, 0) == -1) {
    241       setLastError("Failure in select: gettimeofday failed.");
    242       return -1;
    243     }
    244 
    245     timeout = 1000*(t2.tv_sec - t1.tv_sec) + (t2.tv_usec - t1.tv_usec)/1000;
    246 
    247     if (timeout < 0) timeout = 0;
    248     if (res == 0) return 0;
    249     if (res > 0) return res;
    250   } while (res == -1 && errno == EINTR);
    251   return -1;
    252 }
    253 
    254 //------------------------------------------------------------------------
    255 void IO::writeStr(const string s)
    256 {
    257   if (s == "")
    258     return;
    259   
    260   if (mode == MODE_PLAIN) {
    261     alarm(transfertimeout);
    262     int n = fwrite(s.c_str(), 1, s.length(), fpout);
    263     fflush(fpout);
    264     alarm(0);
    265     
    266     if (n != (int) s.length()) {
    267       // ignore error
    268       return;
    269     }
    270 
    271     Session::getInstance().addWriteBytes(n);
    272 
    273   } else if (mode == MODE_SYSLOG) {
    274     alarm(transfertimeout);
    275     syslog(LOG_INFO, "%s", s.c_str());
    276     alarm(0);
    277   } else {
    278     // ignore error
    279     return;
    280   }
    281 }
    282 
    283 //------------------------------------------------------------------------
    284 int IO::readChar(int timeout, bool retry)
    285 {
    286   string s;
    287   int ret = readStr(s, 1, timeout, retry);
    288   if (ret == 1)
    289     return s[0];
    290 
    291   return ret;
    292 }
    293 
    294 //------------------------------------------------------------------------
    295 int IO::fillBuffer(int timeout, bool retry)
    296 {
    297   // Fill the input buffer with data
    298   fd_set rfds;
    299   FD_ZERO(&rfds);
    300   FD_SET(0, &rfds);
    301 
    302   int r = select(fileno(stdin) + 1, &rfds, 0, 0, timeout);
    303   if (r == 0) {
    304     setLastError("client timed out");
    305     return -2;
    306   } else if (r == -1) {
    307     setLastError("error reading from client");
    308     return -1;
    309   }
    310   
    311   char buf[1024];
    312   int readBytes = read(fileno(stdin), buf, sizeof(buf));
    313   if (readBytes <= 0) {
    314     setLastError("client disconnected");
    315     return -1;
    316   }
    317 
    318   Session::getInstance().addReadBytes(readBytes);
    319   
    320   for (int i = 0; i < readBytes; ++i)
    321     inputBuffer.push_front(buf[i]);
    322   
    323   return readBytes;
    324 }
    325 
    326 //------------------------------------------------------------------------
    327 int IO::readStr(string &data, int bytes, int timeout, bool retry)
    328 {
    329   data = "";
    330 
    331   bool second = false;
    332   for (;;) {
    333     // First, empty data from the input buffer
    334     while (inputBuffer.size() > 0) {
    335       if (bytes != -1 && data.length() == (unsigned int) bytes)
    336 	break;
    337 
    338       data += inputBuffer.back();
    339       inputBuffer.pop_back();
    340     }
    341 
    342     // If bytes == -1, this means we want to fill the buffer once
    343     // more, then empty this over in data, then finally return.
    344     if (bytes == -1 && second)
    345       return data.length();
    346 
    347     // If we got as much as we wanted, return.
    348     if (bytes != -1 && data.length() == (unsigned int) bytes)
    349       return bytes;
    350 
    351     // If we reached the input limit, abort.
    352     if (inputlimit && data.length() >= 8192) {
    353       setLastError("input limit is 8192 characters.");
    354       return -1;
    355     }
    356 
    357     // Fill the buffer with data, 
    358     int ret = fillBuffer(timeout, retry);
    359     if (ret < 0)
    360       return ret;
    361 
    362     second = true;
    363   }
    364 
    365   return data.length();
    366 }
    367 
    368 //------------------------------------------------------------------------
    369 void IO::unReadChar(int c_in) 
    370 {
    371   inputBuffer.push_back(c_in);
    372 }
    373 
    374 //------------------------------------------------------------------------
    375 void IO::unReadChar(const string &s_in)
    376 {
    377   if (s_in.length() != 0) {
    378     int c = s_in.length() - 1;
    379     while (c >= 0) {
    380       unReadChar(s_in[c]);
    381       --c;
    382     }
    383   }
    384 }
    385 
    386 //------------------------------------------------------------------------
    387 int IO::pending(void) const
    388 {
    389   return 0;
    390 }
    391 
    392 //------------------------------------------------------------------------
    393 const string &IO::getLastError(void) const
    394 {
    395   return lastError;
    396 }
    397 
    398 //------------------------------------------------------------------------
    399 void IO::setLastError(const string &e)
    400 {
    401   lastError = e;
    402 }
    403 
    404 //------------------------------------------------------------------------
    405 IOFactory::IOFactory(void)
    406 {
    407 }
    408 
    409 //------------------------------------------------------------------------
    410 IOFactory::~IOFactory(void)
    411 {
    412 }
    413 
    414 //------------------------------------------------------------------------
    415 IOFactory &IOFactory::getInstance(void)
    416 {
    417   static IOFactory iofactory;
    418   return iofactory;
    419 }
    420 
    421 //------------------------------------------------------------------------
    422 void IOFactory::assign(int id, IO *io)
    423 {
    424   ioers[id] = io;
    425 }
    426 
    427 //------------------------------------------------------------------------
    428 IO &IOFactory::get(int id)
    429 {
    430   if (ioers.find(id) == ioers.end()) {
    431     static IO NIL;
    432     return NIL;
    433   }
    434 
    435   return *ioers[id];
    436 }