Simplify stream availability handling

Just have a simply number of bytes argument to avoid a lot of
complexity.
This commit is contained in:
Pierre Ossman 2020-05-19 21:07:05 +02:00 committed by Lauri Kasanen
parent 92c7695981
commit 57a3c3bba8
20 changed files with 67 additions and 132 deletions

View File

@ -44,12 +44,12 @@ size_t BufferedInStream::pos()
return offset + ptr - start; return offset + ptr - start;
} }
size_t BufferedInStream::overrun(size_t itemSize, size_t nItems, bool wait) bool BufferedInStream::overrun(size_t needed, bool wait)
{ {
if (itemSize > bufSize) if (needed > bufSize)
throw Exception("BufferedInStream overrun: " throw Exception("BufferedInStream overrun: "
"requested size of %lu bytes exceeds maximum of %lu bytes", "requested size of %lu bytes exceeds maximum of %lu bytes",
(long unsigned)itemSize, (long unsigned)bufSize); (long unsigned)needed, (long unsigned)bufSize);
if (end - ptr != 0) if (end - ptr != 0)
memmove(start, ptr, end - ptr); memmove(start, ptr, end - ptr);
@ -58,15 +58,10 @@ size_t BufferedInStream::overrun(size_t itemSize, size_t nItems, bool wait)
end -= ptr - start; end -= ptr - start;
ptr = start; ptr = start;
while (avail() < itemSize) { while (avail() < needed) {
if (!fillBuffer(start + bufSize - end, wait)) if (!fillBuffer(start + bufSize - end, wait))
return 0; return false;
} }
size_t nAvail; return true;
nAvail = avail() / itemSize;
if (nAvail < nItems)
return nAvail;
return nItems;
} }

View File

@ -38,7 +38,7 @@ namespace rdr {
private: private:
virtual bool fillBuffer(size_t maxSize, bool wait) = 0; virtual bool fillBuffer(size_t maxSize, bool wait) = 0;
virtual size_t overrun(size_t itemSize, size_t nItems, bool wait); virtual bool overrun(size_t needed, bool wait);
private: private:
size_t bufSize; size_t bufSize;

View File

@ -71,22 +71,22 @@ void BufferedOutStream::flush()
ptr = sentUpTo = start; ptr = sentUpTo = start;
} }
size_t BufferedOutStream::overrun(size_t itemSize, size_t nItems) void BufferedOutStream::overrun(size_t needed)
{ {
if (itemSize > bufSize) if (needed > bufSize)
throw Exception("BufferedOutStream overrun: " throw Exception("BufferedOutStream overrun: "
"requested size of %lu bytes exceeds maximum of %lu bytes", "requested size of %lu bytes exceeds maximum of %lu bytes",
(long unsigned)itemSize, (long unsigned)bufSize); (long unsigned)needed, (long unsigned)bufSize);
// First try to get rid of the data we have // First try to get rid of the data we have
flush(); flush();
// Still not enough space? // Still not enough space?
while (itemSize > avail()) { while (needed > avail()) {
// Can we shuffle things around? // Can we shuffle things around?
// (don't do this if it gains us less than 25%) // (don't do this if it gains us less than 25%)
if (((size_t)(sentUpTo - start) > bufSize / 4) && if (((size_t)(sentUpTo - start) > bufSize / 4) &&
(itemSize < bufSize - (ptr - sentUpTo))) { (needed < bufSize - (ptr - sentUpTo))) {
memmove(start, sentUpTo, ptr - sentUpTo); memmove(start, sentUpTo, ptr - sentUpTo);
ptr = start + (ptr - sentUpTo); ptr = start + (ptr - sentUpTo);
sentUpTo = start; sentUpTo = start;
@ -105,11 +105,4 @@ size_t BufferedOutStream::overrun(size_t itemSize, size_t nItems)
ptr = sentUpTo = start; ptr = sentUpTo = start;
} }
} }
size_t nAvail;
nAvail = avail() / itemSize;
if (nAvail < nItems)
return nAvail;
return nItems;
} }

View File

@ -46,7 +46,7 @@ namespace rdr {
virtual bool flushBuffer(bool wait) = 0; virtual bool flushBuffer(bool wait) = 0;
virtual size_t overrun(size_t itemSize, size_t nItems); virtual void overrun(size_t needed);
private: private:
size_t bufSize; size_t bufSize;

View File

@ -73,7 +73,7 @@ decodeError:
bool HexInStream::fillBuffer(size_t maxSize, bool wait) { bool HexInStream::fillBuffer(size_t maxSize, bool wait) {
if (!in_stream.check(2, 1, wait)) if (!in_stream.check(2, wait))
return false; return false;
const U8* iptr = in_stream.getptr(); const U8* iptr = in_stream.getptr();

View File

@ -95,18 +95,10 @@ HexOutStream::flush() {
out_stream.flush(); out_stream.flush();
} }
size_t void HexOutStream::overrun(size_t needed) {
HexOutStream::overrun(size_t itemSize, size_t nItems) { if (needed > bufSize)
if (itemSize > bufSize) throw Exception("HexOutStream overrun: buffer size exceeded");
throw Exception("HexOutStream overrun: max itemSize exceeded");
writeBuffer(); writeBuffer();
size_t nAvail;
nAvail = avail() / itemSize;
if (nAvail < nItems)
return nAvail;
return nItems;
} }

View File

@ -37,7 +37,7 @@ namespace rdr {
private: private:
void writeBuffer(); void writeBuffer();
size_t overrun(size_t itemSize, size_t nItems); virtual void overrun(size_t needed);
OutStream& out_stream; OutStream& out_stream;

View File

@ -43,28 +43,17 @@ namespace rdr {
return end - ptr; return end - ptr;
} }
// check() ensures there is buffer data for at least one item of size // check() ensures there is buffer data for at least needed bytes. Returns
// itemSize bytes. Returns the number of items in the buffer (up to a // true once the data is available. If wait is false, then instead of
// maximum of nItems). If wait is false, then instead of blocking to wait // blocking to wait for the bytes, false is returned if the bytes are not
// for the bytes, zero is returned if the bytes are not immediately // immediately available.
// available. If itemSize or nItems is zero, check() will return zero.
inline size_t check(size_t itemSize, size_t nItems=1, bool wait=true) inline size_t check(size_t needed, bool wait=true)
{ {
size_t nAvail; if (needed > avail())
return overrun(needed, wait);
if (itemSize == 0 || nItems == 0) return true;
return 0;
if (itemSize > avail())
return overrun(itemSize, nItems, wait);
// itemSize cannot be zero at this point
nAvail = avail() / itemSize;
if (nAvail < nItems)
return nAvail;
return nItems;
} }
// checkNoWait() tries to make sure that the given number of bytes can // checkNoWait() tries to make sure that the given number of bytes can
@ -72,10 +61,7 @@ namespace rdr {
// otherwise. The length must be "small" (less than the buffer size). // otherwise. The length must be "small" (less than the buffer size).
// If length is zero, checkNoWait() will return true. // If length is zero, checkNoWait() will return true.
inline bool checkNoWait(size_t length) inline bool checkNoWait(size_t length) { return check(length, false); }
{
return length == 0 || check(length, 1, false) > 0;
}
// readU/SN() methods read unsigned and signed N-bit integers. // readU/SN() methods read unsigned and signed N-bit integers.
@ -146,13 +132,12 @@ namespace rdr {
private: private:
// overrun() is implemented by a derived class to cope with buffer overrun. // overrun() is implemented by a derived class to cope with buffer overrun.
// It ensures there are at least itemSize bytes of buffer data. Returns // It ensures there are at least needed bytes of buffer data. Returns true
// the number of items in the buffer (up to a maximum of nItems). itemSize // once the data is available. If wait is false, then instead of blocking
// is supposed to be "small" (a few bytes). If wait is false, then // to wait for the bytes, false is returned if the bytes are not
// instead of blocking to wait for the bytes, zero is returned if the bytes // immediately available.
// are not immediately available.
virtual size_t overrun(size_t itemSize, size_t nItems, bool wait=true) = 0; virtual bool overrun(size_t needed, bool wait=true) = 0;
protected: protected:

View File

@ -53,7 +53,7 @@ namespace rdr {
private: private:
size_t overrun(size_t itemSize, size_t nItems, bool wait) { throw EndOfStream(); } bool overrun(size_t needed, bool wait) { throw EndOfStream(); }
const U8* start; const U8* start;
bool deleteWhenDone; bool deleteWhenDone;
}; };

View File

@ -52,11 +52,11 @@ namespace rdr {
protected: protected:
// overrun() either doubles the buffer or adds enough space for nItems of // overrun() either doubles the buffer or adds enough space for
// size itemSize bytes. // needed bytes.
size_t overrun(size_t itemSize, size_t nItems) { virtual void overrun(size_t needed) {
size_t len = ptr - start + itemSize * nItems; size_t len = ptr - start + needed;
if (len < (size_t)(end - start) * 2) if (len < (size_t)(end - start) * 2)
len = (end - start) * 2; len = (end - start) * 2;
@ -69,8 +69,6 @@ namespace rdr {
delete [] start; delete [] start;
start = newStart; start = newStart;
end = newStart + len; end = newStart + len;
return nItems;
} }
U8* start; U8* start;

View File

@ -48,22 +48,12 @@ namespace rdr {
return end - ptr; return end - ptr;
} }
// check() ensures there is buffer space for at least one item of size // check() ensures there is buffer space for at least needed bytes.
// itemSize bytes. Returns the number of items which fit (up to a maximum
// of nItems).
inline size_t check(size_t itemSize, size_t nItems=1) inline void check(size_t needed)
{ {
size_t nAvail; if (needed > avail())
overrun(needed);
if (itemSize > avail())
return overrun(itemSize, nItems);
nAvail = avail() / itemSize;
if (nAvail < nItems)
return nAvail;
return nItems;
} }
// writeU/SN() methods write unsigned and signed N-bit integers. // writeU/SN() methods write unsigned and signed N-bit integers.
@ -91,19 +81,14 @@ namespace rdr {
while (bytes-- > 0) writeU8(0); while (bytes-- > 0) writeU8(0);
} }
inline void skip(size_t bytes) {
while (bytes > 0) {
size_t n = check(1, bytes);
ptr += n;
bytes -= n;
}
}
// writeBytes() writes an exact number of bytes. // writeBytes() writes an exact number of bytes.
void writeBytes(const void* data, size_t length) { void writeBytes(const void* data, size_t length) {
while (length > 0) { while (length > 0) {
size_t n = check(1, length); check(1);
size_t n = length;
if (length > avail())
n = avail();
memcpy(ptr, data, n); memcpy(ptr, data, n);
ptr += n; ptr += n;
data = (U8*)data + n; data = (U8*)data + n;
@ -115,7 +100,10 @@ namespace rdr {
void copyBytes(InStream* is, size_t length) { void copyBytes(InStream* is, size_t length) {
while (length > 0) { while (length > 0) {
size_t n = check(1, length); check(1);
size_t n = length;
if (length > avail())
n = avail();
is->readBytes(ptr, n); is->readBytes(ptr, n);
ptr += n; ptr += n;
length -= n; length -= n;
@ -151,11 +139,9 @@ namespace rdr {
private: private:
// overrun() is implemented by a derived class to cope with buffer overrun. // overrun() is implemented by a derived class to cope with buffer overrun.
// It ensures there are at least itemSize bytes of buffer space. Returns // It ensures there are at least needed bytes of buffer space.
// the number of items which fit (up to a maximum of nItems). itemSize is
// supposed to be "small" (a few bytes).
virtual size_t overrun(size_t itemSize, size_t nItems) = 0; virtual void overrun(size_t needed) = 0;
protected: protected:

View File

@ -36,7 +36,7 @@ ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size)
InStream *in = self->in; InStream *in = self->in;
try { try {
if (!in->check(1, 1, false)) { if (!in->check(1, false)) {
gnutls_transport_set_errno(self->session, EAGAIN); gnutls_transport_set_errno(self->session, EAGAIN);
return -1; return -1;
} }
@ -84,7 +84,7 @@ size_t TLSInStream::readTLS(U8* buf, size_t len, bool wait)
int n; int n;
if (gnutls_record_check_pending(session) == 0) { if (gnutls_record_check_pending(session) == 0) {
n = in->check(1, 1, wait); n = in->check(1, wait);
if (n == 0) if (n == 0)
return 0; return 0;
} }

View File

@ -93,19 +93,12 @@ void TLSOutStream::flush()
out->flush(); out->flush();
} }
size_t TLSOutStream::overrun(size_t itemSize, size_t nItems) void TLSOutStream::overrun(size_t needed)
{ {
if (itemSize > bufSize) if (needed > bufSize)
throw Exception("TLSOutStream overrun: max itemSize exceeded"); throw Exception("TLSOutStream overrun: buffer size exceeded");
flush(); flush();
size_t nAvail;
nAvail = avail() / itemSize;
if (nAvail < nItems)
return nAvail;
return nItems;
} }
size_t TLSOutStream::writeTLS(const U8* data, size_t length) size_t TLSOutStream::writeTLS(const U8* data, size_t length)

View File

@ -39,7 +39,7 @@ namespace rdr {
size_t length(); size_t length();
protected: protected:
size_t overrun(size_t itemSize, size_t nItems); virtual void overrun(size_t needed);
private: private:
size_t writeTLS(const U8* data, size_t length); size_t writeTLS(const U8* data, size_t length);

View File

@ -94,7 +94,7 @@ bool ZlibInStream::fillBuffer(size_t maxSize, bool wait)
zs->next_out = (U8*)end; zs->next_out = (U8*)end;
zs->avail_out = maxSize; zs->avail_out = maxSize;
size_t n = underlying->check(1, 1, wait); size_t n = underlying->check(1, wait);
if (n == 0) return false; if (n == 0) return false;
zs->next_in = (U8*)underlying->getptr(); zs->next_in = (U8*)underlying->getptr();
zs->avail_in = underlying->avail(); zs->avail_in = underlying->avail();

View File

@ -95,18 +95,18 @@ void ZlibOutStream::flush()
ptr = start; ptr = start;
} }
size_t ZlibOutStream::overrun(size_t itemSize, size_t nItems) void ZlibOutStream::overrun(size_t needed)
{ {
#ifdef ZLIBOUT_DEBUG #ifdef ZLIBOUT_DEBUG
fprintf(stderr,"zos overrun\n"); fprintf(stderr,"zos overrun\n");
#endif #endif
if (itemSize > bufSize) if (needed > bufSize)
throw Exception("ZlibOutStream overrun: max itemSize exceeded"); throw Exception("ZlibOutStream overrun: buffer size exceeded");
checkCompressionLevel(); checkCompressionLevel();
while (avail() < itemSize) { while (avail() < needed) {
zs->next_in = start; zs->next_in = start;
zs->avail_in = ptr - start; zs->avail_in = ptr - start;
@ -126,13 +126,6 @@ size_t ZlibOutStream::overrun(size_t itemSize, size_t nItems)
ptr -= zs->next_in - start; ptr -= zs->next_in - start;
} }
} }
size_t nAvail;
nAvail = avail() / itemSize;
if (nAvail < nItems)
return nAvail;
return nItems;
} }
void ZlibOutStream::deflate(int flush) void ZlibOutStream::deflate(int flush)

View File

@ -45,7 +45,7 @@ namespace rdr {
private: private:
size_t overrun(size_t itemSize, size_t nItems); virtual void overrun(size_t needed);
void deflate(int flush); void deflate(int flush);
void checkCompressionLevel(); void checkCompressionLevel();

View File

@ -57,7 +57,7 @@ void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf)
void CMsgWriter::writeSetEncodings(int nEncodings, rdr::U32* encodings) void CMsgWriter::writeSetEncodings(int nEncodings, rdr::U32* encodings)
{ {
startMsg(msgTypeSetEncodings); startMsg(msgTypeSetEncodings);
os->skip(1); os->pad(1);
os->writeU16(nEncodings); os->writeU16(nEncodings);
for (int i = 0; i < nEncodings; i++) for (int i = 0; i < nEncodings; i++)
os->writeU32(encodings[i]); os->writeU32(encodings[i]);

View File

@ -95,7 +95,7 @@ JpegEmptyOutputBuffer(j_compress_ptr cinfo)
JpegCompressor *jc = dest->instance; JpegCompressor *jc = dest->instance;
jc->setptr(jc->getend()); jc->setptr(jc->getend());
jc->overrun(jc->getend() - jc->getstart(), 1); jc->overrun(jc->getend() - jc->getstart());
dest->pub.next_output_byte = jc->getptr(); dest->pub.next_output_byte = jc->getptr();
dest->pub.free_in_buffer = jc->avail(); dest->pub.free_in_buffer = jc->avail();

View File

@ -49,8 +49,8 @@ namespace rfb {
inline rdr::U8* getstart() { return start; } inline rdr::U8* getstart() { return start; }
virtual inline size_t overrun(size_t itemSize, size_t nItems) { inline virtual void overrun(int needed) {
return MemOutStream::overrun(itemSize, nItems); return MemOutStream::overrun(needed);
} }
private: private: