/** * @file iodevice.cc * @brief Implementation of the IODevice class. * @author Andreas Aardal Hanssen * @date 2002, 2003 */ #include "iodevice.h" #include "convert.h" // BincStream #include "session.h" // getEnv/hasEnv #include #include using namespace Binc; using std::ostream; IODevice::IODevice(int f) : flags(f | IsEnabled) , maxInputBufferSize(0) , maxOutputBufferSize(0) , timeout(0) , readCount(0) , writeCount(0) , outputLevel(LogLevel::ErrorLevel) , outputLevelLimit(LogLevel::ErrorLevel) , error(Error::Unknown) , errorString("Unknown device error") , dumpfd(0) {} IODevice::~IODevice() {} IODevice &IODevice::operator<<(ostream &(*source)(ostream &)) { if (!(flags & IsEnabled) || outputLevel > outputLevelLimit) return *this; static ostream &(*endl_funcptr)(ostream &) = std::endl; if (source != endl_funcptr) return *this; outputBuffer << "\r\n"; if (dumpfd) ::write(dumpfd, "\r\n", 2); if (flags & FlushesOnEndl) { flush(); } else if (flags & HasOutputLimit) { if (outputBuffer.getSize() > maxOutputBufferSize) flush(); } return *this; } bool IODevice::canRead() const { return false; } void IODevice::clear() { if (!(flags & IsEnabled)) return; inputBuffer.clear(); outputBuffer.clear(); } bool IODevice::flush() { if (!(flags & IsEnabled)) return true; WriteResult writeResult = WriteWait; do { unsigned int s = outputBuffer.getSize(); if (s == 0) break; if (!waitForWrite()) return false; writeResult = write(); if (writeResult == WriteError) return false; writeCount += s - outputBuffer.getSize(); } while (outputBuffer.getSize() > 0 && writeResult == WriteWait); outputBuffer.clear(); return true; } void IODevice::setFlags(unsigned int f) { flags |= f; } void IODevice::clearFlags(unsigned int f) { flags &= ~f; } void IODevice::setMaxInputBufferSize(unsigned int max) { maxInputBufferSize = max; } void IODevice::setMaxOutputBufferSize(unsigned int max) { maxOutputBufferSize = max; } void IODevice::setTimeout(unsigned int t) { timeout = t; if (t) flags |= HasTimeout; else flags &= ~HasTimeout; } unsigned int IODevice::getTimeout() const { return timeout; } void IODevice::setOutputLevel(LogLevel level) { outputLevel = level; } IODevice::LogLevel IODevice::getOutputLevel() const { return outputLevel; } void IODevice::setOutputLevelLimit(LogLevel level) { outputLevelLimit = level; } IODevice::LogLevel IODevice::getOutputLevelLimit() const { return outputLevelLimit; } bool IODevice::readStr(std::string *dest, unsigned int max) { // If max is 0, fill the input buffer once only if it's empty. if (!max && inputBuffer.getSize() == 0 && !fillInputBuffer()) return false; // If max is != 0, wait until we have max. while (max && inputBuffer.getSize() < max) if (!fillInputBuffer()) return false; unsigned int bytesToRead = max ? max : inputBuffer.getSize(); *dest += inputBuffer.str().substr(0, bytesToRead); if (dumpfd) ::write(dumpfd, inputBuffer.str().substr(0, bytesToRead).c_str(), bytesToRead); inputBuffer.popString(bytesToRead); readCount += bytesToRead; return true; } bool IODevice::readChar(char *dest) { if (inputBuffer.getSize() == 0 && !fillInputBuffer()) return false; char c = inputBuffer.popChar(); if (dest) *dest = c; if (dumpfd) ::write(dumpfd, &c, 1); ++readCount; return true; } void IODevice::unreadChar(char c) { inputBuffer.unpopChar(c); } void IODevice::unreadStr(const std::string &s) { inputBuffer.unpopStr(s); } bool IODevice::skipTo(char c) { char dest = '\0'; do { if (!readChar(&dest)) return false; if (dumpfd) ::write(dumpfd, &dest, 1); } while (c != dest); return true; } std::string IODevice::service() const { return "nul"; } bool IODevice::waitForWrite() const { return false; } bool IODevice::waitForRead() const { return false; } IODevice::WriteResult IODevice::write() { return WriteError; } bool IODevice::fillInputBuffer() { return false; } IODevice::Error IODevice::getLastError() const { return error; } std::string IODevice::getLastErrorString() const { return errorString; } unsigned int IODevice::getReadCount() const { return readCount; } unsigned int IODevice::getWriteCount() const { return writeCount; } void IODevice::enableProtocolDumping() { BincStream ss; ss << "/tmp/bincimap-dump-" << static_cast(time(nullptr)) << "-" << Session::getInstance().getIP() << "-XXXXXX"; std::string safename = ss.str(); dumpfd = mkstemp(safename.data()); if (dumpfd == -1) dumpfd = 0; }