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 }