From e9425ac04d70481f7cb168a19bcbc47728f838c7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 15 May 2020 20:20:53 +0200 Subject: [PATCH] Create common base classes for buffered streams Most streams are backed by a memory buffer. Create common base classes for this functionality to avoid code duplication. --- common/rdr/BufferedInStream.cxx | 72 +++++++++++++++++++ common/rdr/BufferedInStream.h | 54 +++++++++++++++ common/rdr/BufferedOutStream.cxx | 115 +++++++++++++++++++++++++++++++ common/rdr/BufferedOutStream.h | 65 +++++++++++++++++ common/rdr/CMakeLists.txt | 2 + common/rdr/FdInStream.cxx | 65 ++++------------- common/rdr/FdInStream.h | 11 ++- common/rdr/FdOutStream.cxx | 91 +++++------------------- common/rdr/FdOutStream.h | 15 +--- common/rdr/FileInStream.cxx | 54 +++------------ common/rdr/FileInStream.h | 13 ++-- common/rdr/HexInStream.cxx | 56 +++++---------- common/rdr/HexInStream.h | 14 ++-- common/rdr/RandomStream.cxx | 44 +++--------- common/rdr/RandomStream.h | 13 ++-- common/rdr/TLSInStream.cxx | 46 +++---------- common/rdr/TLSInStream.h | 11 +-- common/rdr/ZlibInStream.cxx | 55 +++------------ common/rdr/ZlibInStream.h | 14 ++-- 19 files changed, 413 insertions(+), 397 deletions(-) create mode 100644 common/rdr/BufferedInStream.cxx create mode 100644 common/rdr/BufferedInStream.h create mode 100644 common/rdr/BufferedOutStream.cxx create mode 100644 common/rdr/BufferedOutStream.h diff --git a/common/rdr/BufferedInStream.cxx b/common/rdr/BufferedInStream.cxx new file mode 100644 index 00000000..5083eb2d --- /dev/null +++ b/common/rdr/BufferedInStream.cxx @@ -0,0 +1,72 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2020 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +using namespace rdr; + +static const size_t DEFAULT_BUF_SIZE = 8192; + +BufferedInStream::BufferedInStream(size_t bufSize_) + : bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0) +{ + ptr = end = start = new U8[bufSize]; +} + +BufferedInStream::~BufferedInStream() +{ + delete [] start; +} + +size_t BufferedInStream::pos() +{ + return offset + ptr - start; +} + +size_t BufferedInStream::overrun(size_t itemSize, size_t nItems, bool wait) +{ + if (itemSize > bufSize) + throw Exception("BufferedInStream overrun: " + "requested size of %lu bytes exceeds maximum of %lu bytes", + (long unsigned)itemSize, (long unsigned)bufSize); + + if (end - ptr != 0) + memmove(start, ptr, end - ptr); + + offset += ptr - start; + end -= ptr - start; + ptr = start; + + while (avail() < itemSize) { + if (!fillBuffer(start + bufSize - end, wait)) + return 0; + } + + size_t nAvail; + nAvail = avail() / itemSize; + if (nAvail < nItems) + return nAvail; + + return nItems; +} diff --git a/common/rdr/BufferedInStream.h b/common/rdr/BufferedInStream.h new file mode 100644 index 00000000..fc62133e --- /dev/null +++ b/common/rdr/BufferedInStream.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2020 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// +// Base class for input streams with a buffer +// + +#ifndef __RDR_BUFFEREDINSTREAM_H__ +#define __RDR_BUFFEREDINSTREAM_H__ + +#include + +namespace rdr { + + class BufferedInStream : public InStream { + + public: + virtual ~BufferedInStream(); + + virtual size_t pos(); + + private: + virtual bool fillBuffer(size_t maxSize, bool wait) = 0; + + virtual size_t overrun(size_t itemSize, size_t nItems, bool wait); + + private: + size_t bufSize; + size_t offset; + U8* start; + + protected: + BufferedInStream(size_t bufSize=0); + }; + +} // end of namespace rdr + +#endif diff --git a/common/rdr/BufferedOutStream.cxx b/common/rdr/BufferedOutStream.cxx new file mode 100644 index 00000000..76b0163b --- /dev/null +++ b/common/rdr/BufferedOutStream.cxx @@ -0,0 +1,115 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2011-2020 Pierre Ossman for Cendio AB + * Copyright 2017 Peter Astrand for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + + +using namespace rdr; + +static const size_t DEFAULT_BUF_SIZE = 16384; + +BufferedOutStream::BufferedOutStream(size_t bufSize_) + : bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0) +{ + ptr = start = sentUpTo = new U8[bufSize]; + end = start + bufSize; +} + +BufferedOutStream::~BufferedOutStream() +{ + // FIXME: Complain about non-flushed buffer? + delete [] start; +} + +size_t BufferedOutStream::length() +{ + return offset + ptr - sentUpTo; +} + +size_t BufferedOutStream::bufferUsage() +{ + return ptr - sentUpTo; +} + +void BufferedOutStream::flush() +{ + while (sentUpTo < ptr) { + size_t len; + + len = bufferUsage(); + + if (!flushBuffer(false)) + break; + + offset += len - bufferUsage(); + } + + // Managed to flush everything? + if (sentUpTo == ptr) + ptr = sentUpTo = start; +} + +size_t BufferedOutStream::overrun(size_t itemSize, size_t nItems) +{ + if (itemSize > bufSize) + throw Exception("BufferedOutStream overrun: " + "requested size of %lu bytes exceeds maximum of %lu bytes", + (long unsigned)itemSize, (long unsigned)bufSize); + + // First try to get rid of the data we have + flush(); + + // Still not enough space? + while (itemSize > avail()) { + // Can we shuffle things around? + // (don't do this if it gains us less than 25%) + if (((size_t)(sentUpTo - start) > bufSize / 4) && + (itemSize < bufSize - (ptr - sentUpTo))) { + memmove(start, sentUpTo, ptr - sentUpTo); + ptr = start + (ptr - sentUpTo); + sentUpTo = start; + } else { + size_t len; + + len = bufferUsage(); + + // Have to get rid of more data, so allow the flush to wait... + flushBuffer(true); + + offset += len - bufferUsage(); + + // Managed to flush everything? + if (sentUpTo == ptr) + ptr = sentUpTo = start; + } + } + + size_t nAvail; + nAvail = avail() / itemSize; + if (nAvail < nItems) + return nAvail; + + return nItems; +} diff --git a/common/rdr/BufferedOutStream.h b/common/rdr/BufferedOutStream.h new file mode 100644 index 00000000..092ea1f0 --- /dev/null +++ b/common/rdr/BufferedOutStream.h @@ -0,0 +1,65 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2011-2020 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// +// Base class for output streams with a buffer +// + +#ifndef __RDR_BUFFEREDOUTSTREAM_H__ +#define __RDR_BUFFEREDOUTSTREAM_H__ + +#include + +namespace rdr { + + class BufferedOutStream : public OutStream { + + public: + virtual ~BufferedOutStream(); + + virtual size_t length(); + virtual void flush(); + + size_t bufferUsage(); + + private: + // flushBuffer() requests that the stream be flushed. Returns true if it is + // able to progress the output (which might still not mean any bytes + // actually moved) and can be called again. If wait is true then it will + // block until all data has been written. + + virtual bool flushBuffer(bool wait) = 0; + + virtual size_t overrun(size_t itemSize, size_t nItems); + + private: + size_t bufSize; + size_t offset; + U8* start; + + protected: + U8* sentUpTo; + + protected: + BufferedOutStream(size_t bufSize=0); + }; + +} + +#endif diff --git a/common/rdr/CMakeLists.txt b/common/rdr/CMakeLists.txt index 989ba2f4..78778ddc 100644 --- a/common/rdr/CMakeLists.txt +++ b/common/rdr/CMakeLists.txt @@ -1,6 +1,8 @@ include_directories(${CMAKE_SOURCE_DIR}/common ${ZLIB_INCLUDE_DIRS}) add_library(rdr STATIC + BufferedInStream.cxx + BufferedOutStream.cxx Exception.cxx FdInStream.cxx FdOutStream.cxx diff --git a/common/rdr/FdInStream.cxx b/common/rdr/FdInStream.cxx index eb76ec06..c9d2241c 100644 --- a/common/rdr/FdInStream.cxx +++ b/common/rdr/FdInStream.cxx @@ -36,13 +36,6 @@ #include #endif -#ifndef vncmin -#define vncmin(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef vncmax -#define vncmax(a,b) (((a) > (b)) ? (a) : (b)) -#endif - /* Old systems have select() in sys/time.h */ #ifdef HAVE_SYS_SELECT_H #include @@ -57,26 +50,23 @@ enum { DEFAULT_BUF_SIZE = 8192 }; FdInStream::FdInStream(int fd_, int timeoutms_, size_t bufSize_, bool closeWhenDone_) - : fd(fd_), closeWhenDone(closeWhenDone_), + : BufferedInStream(bufSize_), + fd(fd_), closeWhenDone(closeWhenDone_), timeoutms(timeoutms_), blockCallback(0), - timing(false), timeWaitedIn100us(5), timedKbits(0), - bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0) + timing(false), timeWaitedIn100us(5), timedKbits(0) { - ptr = end = start = new U8[bufSize]; } FdInStream::FdInStream(int fd_, FdInStreamBlockCallback* blockCallback_, size_t bufSize_) - : fd(fd_), timeoutms(0), blockCallback(blockCallback_), - timing(false), timeWaitedIn100us(5), timedKbits(0), - bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0) + : BufferedInStream(bufSize_), + fd(fd_), timeoutms(0), blockCallback(blockCallback_), + timing(false), timeWaitedIn100us(5), timedKbits(0) { - ptr = end = start = new U8[bufSize]; } FdInStream::~FdInStream() { - delete [] start; if (closeWhenDone) close(fd); } @@ -91,46 +81,15 @@ void FdInStream::setBlockCallback(FdInStreamBlockCallback* blockCallback_) timeoutms = 0; } -size_t FdInStream::pos() -{ - return offset + ptr - start; -} -size_t FdInStream::overrun(size_t itemSize, size_t nItems, bool wait) +bool FdInStream::fillBuffer(size_t maxSize, bool wait) { - if (itemSize > bufSize) - throw Exception("FdInStream overrun: max itemSize exceeded"); - - if (end - ptr != 0) - memmove(start, ptr, end - ptr); - - offset += ptr - start; - end -= ptr - start; - ptr = start; - - size_t bytes_to_read; - while ((size_t)(end - start) < itemSize) { - bytes_to_read = start + bufSize - end; - if (!timing) { - // When not timing, we must be careful not to read too much - // extra data into the buffer. Otherwise, the line speed - // estimation might stay at zero for a long time: All reads - // during timing=1 can be satisfied without calling - // readWithTimeoutOrCallback. However, reading only 1 or 2 bytes - // bytes is ineffecient. - bytes_to_read = vncmin(bytes_to_read, vncmax(itemSize*nItems, 8)); - } - size_t n = readWithTimeoutOrCallback((U8*)end, bytes_to_read, wait); - if (n == 0) return 0; - end += n; - } - - size_t nAvail; - nAvail = avail() / itemSize; - if (nAvail < nItems) - return nAvail; + size_t n = readWithTimeoutOrCallback((U8*)end, maxSize, wait); + if (n == 0) + return false; + end += n; - return nItems; + return true; } // diff --git a/common/rdr/FdInStream.h b/common/rdr/FdInStream.h index 007f35ce..f7a52baf 100644 --- a/common/rdr/FdInStream.h +++ b/common/rdr/FdInStream.h @@ -23,7 +23,7 @@ #ifndef __RDR_FDINSTREAM_H__ #define __RDR_FDINSTREAM_H__ -#include +#include namespace rdr { @@ -33,7 +33,7 @@ namespace rdr { virtual ~FdInStreamBlockCallback() {} }; - class FdInStream : public InStream { + class FdInStream : public BufferedInStream { public: @@ -46,17 +46,15 @@ namespace rdr { void setTimeout(int timeoutms); void setBlockCallback(FdInStreamBlockCallback* blockCallback); int getFd() { return fd; } - size_t pos(); void startTiming(); void stopTiming(); unsigned int kbitsPerSecond(); unsigned int timeWaited() { return timeWaitedIn100us; } - protected: - size_t overrun(size_t itemSize, size_t nItems, bool wait); - private: + virtual bool fillBuffer(size_t maxSize, bool wait); + size_t readWithTimeoutOrCallback(void* buf, size_t len, bool wait=true); int fd; @@ -68,7 +66,6 @@ namespace rdr { unsigned int timeWaitedIn100us; unsigned int timedKbits; - size_t bufSize; size_t offset; U8* start; }; diff --git a/common/rdr/FdOutStream.cxx b/common/rdr/FdOutStream.cxx index 04c6851a..4fc74671 100644 --- a/common/rdr/FdOutStream.cxx +++ b/common/rdr/FdOutStream.cxx @@ -49,26 +49,20 @@ using namespace rdr; -enum { DEFAULT_BUF_SIZE = 16384 }; - FdOutStream::FdOutStream(int fd_, bool blocking_, int timeoutms_, size_t bufSize_) - : fd(fd_), blocking(blocking_), timeoutms(timeoutms_), - bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0) + : BufferedOutStream(bufSize_), + fd(fd_), blocking(blocking_), timeoutms(timeoutms_) { - ptr = start = sentUpTo = new U8[bufSize]; - end = start + bufSize; - gettimeofday(&lastWrite, NULL); } FdOutStream::~FdOutStream() { try { - blocking = true; - flush(); + while (sentUpTo != ptr) + flushBuffer(true); } catch (Exception&) { } - delete [] start; } void FdOutStream::setTimeout(int timeoutms_) { @@ -79,82 +73,29 @@ void FdOutStream::setBlocking(bool blocking_) { blocking = blocking_; } -size_t FdOutStream::length() -{ - return offset + ptr - sentUpTo; -} - -int FdOutStream::bufferUsage() -{ - return ptr - sentUpTo; -} - unsigned FdOutStream::getIdleTime() { return rfb::msSince(&lastWrite); } -void FdOutStream::flush() +bool FdOutStream::flushBuffer(bool wait) { - while (sentUpTo < ptr) { - size_t n = writeWithTimeout((const void*) sentUpTo, - ptr - sentUpTo, - blocking? timeoutms : 0); - - // Timeout? - if (n == 0) { - // If non-blocking then we're done here - if (!blocking) - break; - - throw TimedOut(); - } - - sentUpTo += n; - offset += n; - } - - // Managed to flush everything? - if (sentUpTo == ptr) - ptr = sentUpTo = start; -} + size_t n = writeWithTimeout((const void*) sentUpTo, + ptr - sentUpTo, + (blocking || wait)? timeoutms : 0); + // Timeout? + if (n == 0) { + // If non-blocking then we're done here + if (!blocking && !wait) + return false; -size_t FdOutStream::overrun(size_t itemSize, size_t nItems) -{ - if (itemSize > bufSize) - throw Exception("FdOutStream overrun: max itemSize exceeded"); - - // First try to get rid of the data we have - flush(); - - // Still not enough space? - if (itemSize > avail()) { - // Can we shuffle things around? - // (don't do this if it gains us less than 25%) - if (((size_t)(sentUpTo - start) > bufSize / 4) && - (itemSize < bufSize - (ptr - sentUpTo))) { - memmove(start, sentUpTo, ptr - sentUpTo); - ptr = start + (ptr - sentUpTo); - sentUpTo = start; - } else { - // Have to get rid of more data, so turn off non-blocking - // for a bit... - bool realBlocking; - - realBlocking = blocking; - blocking = true; - flush(); - blocking = realBlocking; - } + throw TimedOut(); } - size_t nAvail; - nAvail = avail() / itemSize; - if (nAvail < nItems) - return nAvail; + sentUpTo += n; - return nItems; + return true; } // diff --git a/common/rdr/FdOutStream.h b/common/rdr/FdOutStream.h index ed84fdb5..b1ecbd56 100644 --- a/common/rdr/FdOutStream.h +++ b/common/rdr/FdOutStream.h @@ -26,11 +26,11 @@ #include -#include +#include namespace rdr { - class FdOutStream : public OutStream { + class FdOutStream : public BufferedOutStream { public: @@ -41,23 +41,14 @@ namespace rdr { void setBlocking(bool blocking); int getFd() { return fd; } - void flush(); - size_t length(); - - int bufferUsage(); - unsigned getIdleTime(); private: - size_t overrun(size_t itemSize, size_t nItems); + virtual bool flushBuffer(bool wait); size_t writeWithTimeout(const void* data, size_t length, int timeoutms); int fd; bool blocking; int timeoutms; - size_t bufSize; - size_t offset; - U8* start; - U8* sentUpTo; struct timeval lastWrite; }; diff --git a/common/rdr/FileInStream.cxx b/common/rdr/FileInStream.cxx index 8344fcd1..66dfe766 100644 --- a/common/rdr/FileInStream.cxx +++ b/common/rdr/FileInStream.cxx @@ -30,7 +30,6 @@ FileInStream::FileInStream(const char *fileName) file = fopen(fileName, "rb"); if (!file) throw SystemException("fopen", errno); - ptr = end = b; } FileInStream::~FileInStream(void) { @@ -40,50 +39,17 @@ FileInStream::~FileInStream(void) { } } -void FileInStream::reset(void) { - if (!file) - throw Exception("File is not open"); - if (fseek(file, 0, SEEK_SET) != 0) - throw SystemException("fseek", errno); - ptr = end = b; -} - -size_t FileInStream::pos() +bool FileInStream::fillBuffer(size_t maxSize, bool wait) { - if (!file) - throw Exception("File is not open"); - - return ftell(file) + ptr - b; -} - -size_t FileInStream::overrun(size_t itemSize, size_t nItems, bool wait) -{ - if (itemSize > sizeof(b)) - throw Exception("FileInStream overrun: max itemSize exceeded"); - - if (end - ptr != 0) - memmove(b, ptr, end - ptr); - - end -= ptr - b; - ptr = b; - - - while ((size_t)(end - b) < itemSize) { - size_t n = fread((U8 *)end, b + sizeof(b) - end, 1, file); - if (n == 0) { - if (ferror(file)) - throw SystemException("fread", errno); - if (feof(file)) - throw EndOfStream(); - return 0; - } - end += b + sizeof(b) - end; + size_t n = fread((U8 *)end, 1, maxSize, file); + if (n == 0) { + if (ferror(file)) + throw SystemException("fread", errno); + if (feof(file)) + throw EndOfStream(); + return false; } + end += n; - size_t nAvail; - nAvail = avail() / itemSize; - if (nAvail < nItems) - return nAvail; - - return nItems; + return true; } diff --git a/common/rdr/FileInStream.h b/common/rdr/FileInStream.h index a33c765e..268f5375 100644 --- a/common/rdr/FileInStream.h +++ b/common/rdr/FileInStream.h @@ -22,26 +22,21 @@ #include -#include +#include namespace rdr { - class FileInStream : public InStream { + class FileInStream : public BufferedInStream { public: FileInStream(const char *fileName); ~FileInStream(void); - void reset(void); - - size_t pos(); - - protected: - size_t overrun(size_t itemSize, size_t nItems, bool wait = true); + private: + virtual bool fillBuffer(size_t maxSize, bool wait); private: - U8 b[131072]; FILE *file; }; diff --git a/common/rdr/HexInStream.cxx b/common/rdr/HexInStream.cxx index 787edc04..0901afee 100644 --- a/common/rdr/HexInStream.cxx +++ b/common/rdr/HexInStream.cxx @@ -24,18 +24,14 @@ using namespace rdr; -const int DEFAULT_BUF_LEN = 16384; - static inline int min(int a, int b) {return a bufSize) - throw Exception("HexInStream overrun: max itemSize exceeded"); - - if (end - ptr != 0) - memmove(start, ptr, end - ptr); - - end -= ptr - start; - offset += ptr - start; - ptr = start; - - while (avail() < itemSize) { - size_t n = in_stream.check(2, 1, wait); - if (n == 0) return 0; - const U8* iptr = in_stream.getptr(); - const U8* eptr = in_stream.getend(); - size_t length = min((eptr - iptr)/2, start + bufSize - end); +bool HexInStream::fillBuffer(size_t maxSize, bool wait) { + if (!in_stream.check(2, 1, wait)) + return false; - U8* optr = (U8*) end; - for (size_t i=0; i +#include namespace rdr { - class HexInStream : public InStream { + class HexInStream : public BufferedInStream { public: HexInStream(InStream& is, size_t bufSize=0); virtual ~HexInStream(); - size_t pos(); - static bool readHexAndShift(char c, int* v); static bool hexStrToBin(const char* s, char** data, size_t* length); - protected: - size_t overrun(size_t itemSize, size_t nItems, bool wait); - private: - size_t bufSize; - U8* start; - size_t offset; + virtual bool fillBuffer(size_t maxSize, bool wait); + private: InStream& in_stream; }; diff --git a/common/rdr/RandomStream.cxx b/common/rdr/RandomStream.cxx index 0290c24d..6333be3f 100644 --- a/common/rdr/RandomStream.cxx +++ b/common/rdr/RandomStream.cxx @@ -35,15 +35,10 @@ static rfb::LogWriter vlog("RandomStream"); using namespace rdr; -const size_t DEFAULT_BUF_LEN = 256; - unsigned int RandomStream::seed; RandomStream::RandomStream() - : offset(0) { - ptr = end = start = new U8[DEFAULT_BUF_LEN]; - #ifdef RFB_HAVE_WINCRYPT provider = 0; if (!CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, 0)) { @@ -75,8 +70,6 @@ RandomStream::RandomStream() } RandomStream::~RandomStream() { - delete [] start; - #ifdef RFB_HAVE_WINCRYPT if (provider) CryptReleaseContext(provider, 0); @@ -86,50 +79,29 @@ RandomStream::~RandomStream() { #endif } -size_t RandomStream::pos() { - return offset + ptr - start; -} - -size_t RandomStream::overrun(size_t itemSize, size_t nItems, bool wait) { - if (itemSize > DEFAULT_BUF_LEN) - throw Exception("RandomStream overrun: max itemSize exceeded"); - - if (end - ptr != 0) - memmove(start, ptr, end - ptr); - - end -= ptr - start; - offset += ptr - start; - ptr = start; - - size_t length = start + DEFAULT_BUF_LEN - end; - +bool RandomStream::fillBuffer(size_t maxSize, bool wait) { #ifdef RFB_HAVE_WINCRYPT if (provider) { - if (!CryptGenRandom(provider, length, (U8*)end)) + if (!CryptGenRandom(provider, maxSize, (U8*)end)) throw rdr::SystemException("unable to CryptGenRandom", GetLastError()); - end += length; + end += maxSize; } else { #else #ifndef WIN32 if (fp) { - size_t n = fread((U8*)end, length, 1, fp); - if (n != 1) + size_t n = fread((U8*)end, 1, maxSize, fp); + if (n <= 0) throw rdr::SystemException("reading /dev/urandom or /dev/random failed", errno); - end += length; + end += n; } else { #else { #endif #endif - for (size_t i=0; i -#include +#include #ifdef WIN32 #include @@ -32,22 +32,17 @@ namespace rdr { - class RandomStream : public InStream { + class RandomStream : public BufferedInStream { public: RandomStream(); virtual ~RandomStream(); - size_t pos(); - - protected: - size_t overrun(size_t itemSize, size_t nItems, bool wait); - private: - U8* start; - size_t offset; + virtual bool fillBuffer(size_t maxSize, bool wait); + private: static unsigned int seed; #ifdef RFB_HAVE_WINCRYPT HCRYPTPROV provider; diff --git a/common/rdr/TLSInStream.cxx b/common/rdr/TLSInStream.cxx index 15e2a471..92c2f0c6 100644 --- a/common/rdr/TLSInStream.cxx +++ b/common/rdr/TLSInStream.cxx @@ -30,8 +30,6 @@ #ifdef HAVE_GNUTLS using namespace rdr; -enum { DEFAULT_BUF_SIZE = 16384 }; - ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size) { TLSInStream* self= (TLSInStream*) str; @@ -43,8 +41,8 @@ ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size) return -1; } - if ((size_t)(in->getend() - in->getptr()) < size) - size = in->getend() - in->getptr(); + if (in->avail() < size) + size = in->avail(); in->readBytes(data, size); @@ -57,12 +55,10 @@ ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size) } TLSInStream::TLSInStream(InStream* _in, gnutls_session_t _session) - : session(_session), in(_in), bufSize(DEFAULT_BUF_SIZE), offset(0) + : session(_session), in(_in) { gnutls_transport_ptr_t recv, send; - ptr = end = start = new U8[bufSize]; - gnutls_transport_set_pull_function(session, pull); gnutls_transport_get_ptr2(session, &recv, &send); gnutls_transport_set_ptr2(session, this, send); @@ -71,40 +67,16 @@ TLSInStream::TLSInStream(InStream* _in, gnutls_session_t _session) TLSInStream::~TLSInStream() { gnutls_transport_set_pull_function(session, NULL); - - delete[] start; -} - -size_t TLSInStream::pos() -{ - return offset + ptr - start; } -size_t TLSInStream::overrun(size_t itemSize, size_t nItems, bool wait) +bool TLSInStream::fillBuffer(size_t maxSize, bool wait) { - if (itemSize > bufSize) - throw Exception("TLSInStream overrun: max itemSize exceeded"); - - if (end - ptr != 0) - memmove(start, ptr, end - ptr); - - offset += ptr - start; - end -= ptr - start; - ptr = start; - - while ((size_t)(end - start) < itemSize) { - size_t n = readTLS((U8*) end, start + bufSize - end, wait); - if (!wait && n == 0) - return 0; - end += n; - } - - size_t nAvail; - nAvail = avail() / itemSize; - if (nAvail < nItems) - return nAvail; + size_t n = readTLS((U8*) end, maxSize, wait); + if (!wait && n == 0) + return false; + end += n; - return nItems; + return true; } size_t TLSInStream::readTLS(U8* buf, size_t len, bool wait) diff --git a/common/rdr/TLSInStream.h b/common/rdr/TLSInStream.h index 5f9dee7f..9779c68e 100644 --- a/common/rdr/TLSInStream.h +++ b/common/rdr/TLSInStream.h @@ -27,27 +27,22 @@ #ifdef HAVE_GNUTLS #include -#include +#include namespace rdr { - class TLSInStream : public InStream { + class TLSInStream : public BufferedInStream { public: TLSInStream(InStream* in, gnutls_session_t session); virtual ~TLSInStream(); - size_t pos(); - private: - size_t overrun(size_t itemSize, size_t nItems, bool wait); + virtual bool fillBuffer(size_t maxSize, bool wait); size_t readTLS(U8* buf, size_t len, bool wait); static ssize_t pull(gnutls_transport_ptr_t str, void* data, size_t size); gnutls_session_t session; InStream* in; - size_t bufSize; - size_t offset; - U8* start; }; }; diff --git a/common/rdr/ZlibInStream.cxx b/common/rdr/ZlibInStream.cxx index 839cf0d0..675600d5 100644 --- a/common/rdr/ZlibInStream.cxx +++ b/common/rdr/ZlibInStream.cxx @@ -24,41 +24,31 @@ using namespace rdr; -enum { DEFAULT_BUF_SIZE = 16384 }; - ZlibInStream::ZlibInStream(size_t bufSize_) - : underlying(0), bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0), - zs(NULL), bytesIn(0) + : BufferedInStream(bufSize_), + underlying(0), zs(NULL), bytesIn(0) { - ptr = end = start = new U8[bufSize]; init(); } ZlibInStream::~ZlibInStream() { deinit(); - delete [] start; } void ZlibInStream::setUnderlying(InStream* is, size_t bytesIn_) { underlying = is; bytesIn = bytesIn_; - ptr = end = start; -} - -size_t ZlibInStream::pos() -{ - return offset + ptr - start; + skip(avail()); } void ZlibInStream::flushUnderlying() { - ptr = end = start; - while (bytesIn > 0) { - decompress(true); - end = start; // throw away any data + if (!check(1)) + throw Exception("ZlibInStream: failed to flush remaining stream data"); + skip(avail()); } setUnderlying(NULL, 0); @@ -96,42 +86,13 @@ void ZlibInStream::deinit() zs = NULL; } -size_t ZlibInStream::overrun(size_t itemSize, size_t nItems, bool wait) -{ - if (itemSize > bufSize) - throw Exception("ZlibInStream overrun: max itemSize exceeded"); - - if (end - ptr != 0) - memmove(start, ptr, end - ptr); - - offset += ptr - start; - end -= ptr - start; - ptr = start; - - while (avail() < itemSize) { - if (!decompress(wait)) - return 0; - } - - size_t nAvail; - nAvail = avail() / itemSize; - if (nAvail < nItems) - return nAvail; - - return nItems; -} - -// decompress() calls the decompressor once. Note that this won't necessarily -// generate any output data - it may just consume some input data. Returns -// false if wait is false and we would block on the underlying stream. - -bool ZlibInStream::decompress(bool wait) +bool ZlibInStream::fillBuffer(size_t maxSize, bool wait) { if (!underlying) throw Exception("ZlibInStream overrun: no underlying stream"); zs->next_out = (U8*)end; - zs->avail_out = start + bufSize - end; + zs->avail_out = maxSize; size_t n = underlying->check(1, 1, wait); if (n == 0) return false; diff --git a/common/rdr/ZlibInStream.h b/common/rdr/ZlibInStream.h index 08784b0f..04416756 100644 --- a/common/rdr/ZlibInStream.h +++ b/common/rdr/ZlibInStream.h @@ -24,38 +24,32 @@ #ifndef __RDR_ZLIBINSTREAM_H__ #define __RDR_ZLIBINSTREAM_H__ -#include +#include struct z_stream_s; namespace rdr { - class ZlibInStream : public InStream { + class ZlibInStream : public BufferedInStream { public: - ZlibInStream(size_t bufSize=0); virtual ~ZlibInStream(); void setUnderlying(InStream* is, size_t bytesIn); void flushUnderlying(); - size_t pos(); void reset(); private: - void init(); void deinit(); - size_t overrun(size_t itemSize, size_t nItems, bool wait); - bool decompress(bool wait); + virtual bool fillBuffer(size_t maxSize, bool wait); + private: InStream* underlying; - size_t bufSize; - size_t offset; z_stream_s* zs; size_t bytesIn; - U8* start; }; } // end of namespace rdr -- 2.39.5