Merge branches 'meta' and 'tlscrash' of https://github.com/CendioOssman/tigervnc
diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake
index 4b58b1d..a994309 100644
--- a/cmake/StaticBuild.cmake
+++ b/cmake/StaticBuild.cmake
@@ -19,10 +19,7 @@
set(BUILD_STATIC_GCC 1)
set(JPEG_LIBRARIES "-Wl,-Bstatic -ljpeg -Wl,-Bdynamic")
-
- if(WIN32)
- set(ZLIB_LIBRARIES "-Wl,-Bstatic -lz -Wl,-Bdynamic")
- endif()
+ set(ZLIB_LIBRARIES "-Wl,-Bstatic -lz -Wl,-Bdynamic")
# gettext is included in libc on many unix systems
if(NOT LIBC_HAS_DGETTEXT)
diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx
index ce489b1..fb95377 100644
--- a/common/rfb/CConnection.cxx
+++ b/common/rfb/CConnection.cxx
@@ -49,7 +49,8 @@
CConnection::~CConnection()
{
setFramebuffer(NULL);
- if (csecurity) csecurity->destroy();
+ if (csecurity)
+ delete csecurity;
delete reader_;
reader_ = 0;
delete writer_;
@@ -234,14 +235,14 @@
}
state_ = RFBSTATE_SECURITY;
- csecurity = security.GetCSecurity(secType);
+ csecurity = security.GetCSecurity(this, secType);
processSecurityMsg();
}
void CConnection::processSecurityMsg()
{
vlog.debug("processing security message");
- if (csecurity->processMsg(this)) {
+ if (csecurity->processMsg()) {
state_ = RFBSTATE_SECURITY_RESULT;
processSecurityResultMsg();
}
diff --git a/common/rfb/CSecurity.h b/common/rfb/CSecurity.h
index 3fedc50..2e703c6 100644
--- a/common/rfb/CSecurity.h
+++ b/common/rfb/CSecurity.h
@@ -44,9 +44,9 @@
class CConnection;
class CSecurity {
public:
+ CSecurity(CConnection* cc) { this->cc = cc; }
virtual ~CSecurity() {}
- virtual bool processMsg(CConnection* cc)=0;
- virtual void destroy() { delete this; }
+ virtual bool processMsg() = 0;
virtual int getType() const = 0;
virtual const char* description() const = 0;
virtual bool isSecure() const { return false; }
@@ -56,6 +56,9 @@
* It MUST be set by viewer.
*/
static UserPasswdGetter *upg;
+
+ protected:
+ CConnection* cc;
};
}
#endif
diff --git a/common/rfb/CSecurityNone.h b/common/rfb/CSecurityNone.h
index a7db6e0..d07815f 100644
--- a/common/rfb/CSecurityNone.h
+++ b/common/rfb/CSecurityNone.h
@@ -29,7 +29,8 @@
class CSecurityNone : public CSecurity {
public:
- virtual bool processMsg(CConnection* cc) { return true; }
+ CSecurityNone(CConnection* cc) : CSecurity(cc) {}
+ virtual bool processMsg() { return true; }
virtual int getType() const {return secTypeNone;}
virtual const char* description() const {return "No Encryption";}
};
diff --git a/common/rfb/CSecurityPlain.cxx b/common/rfb/CSecurityPlain.cxx
index 8e383c3..b2fb736 100644
--- a/common/rfb/CSecurityPlain.cxx
+++ b/common/rfb/CSecurityPlain.cxx
@@ -26,7 +26,7 @@
using namespace rfb;
-bool CSecurityPlain::processMsg(CConnection* cc)
+bool CSecurityPlain::processMsg()
{
rdr::OutStream* os = cc->getOutStream();
diff --git a/common/rfb/CSecurityPlain.h b/common/rfb/CSecurityPlain.h
index fb0d7a5..4ea8c9d 100644
--- a/common/rfb/CSecurityPlain.h
+++ b/common/rfb/CSecurityPlain.h
@@ -26,8 +26,8 @@
class CSecurityPlain : public CSecurity {
public:
- CSecurityPlain() {}
- virtual bool processMsg(CConnection* cc);
+ CSecurityPlain(CConnection* cc) : CSecurity(cc) {}
+ virtual bool processMsg();
virtual int getType() const { return secTypePlain; }
virtual const char* description() const { return "ask for username and password"; }
};
diff --git a/common/rfb/CSecurityStack.cxx b/common/rfb/CSecurityStack.cxx
index 47c3f6d..55f3133 100644
--- a/common/rfb/CSecurityStack.cxx
+++ b/common/rfb/CSecurityStack.cxx
@@ -21,9 +21,9 @@
using namespace rfb;
-CSecurityStack::CSecurityStack(int Type, const char*Name, CSecurity* s0,
- CSecurity* s1)
- :name(Name),type(Type)
+CSecurityStack::CSecurityStack(CConnection* cc, int Type, const char* Name,
+ CSecurity* s0, CSecurity* s1)
+ : CSecurity(cc), name(Name), type(Type)
{
state = 0;
state0 = s0;
@@ -38,12 +38,12 @@
delete state1;
}
-bool CSecurityStack::processMsg(CConnection* cc)
+bool CSecurityStack::processMsg()
{
bool res=true;
if (state == 0) {
if (state0)
- res = state0->processMsg(cc);
+ res = state0->processMsg();
if (!res)
return res;
@@ -53,7 +53,7 @@
if (state == 1) {
if(state1)
- res = state1->processMsg(cc);
+ res = state1->processMsg();
if(!res)
return res;
diff --git a/common/rfb/CSecurityStack.h b/common/rfb/CSecurityStack.h
index a16003f..4be507e 100644
--- a/common/rfb/CSecurityStack.h
+++ b/common/rfb/CSecurityStack.h
@@ -27,9 +27,10 @@
class CSecurityStack : public CSecurity {
public:
- CSecurityStack(int Type, const char *Name, CSecurity* s0 = 0, CSecurity* s1 = 0);
+ CSecurityStack(CConnection* cc, int Type, const char *Name,
+ CSecurity* s0 = NULL, CSecurity* s1 = NULL);
~CSecurityStack();
- virtual bool processMsg(CConnection* cc);
+ virtual bool processMsg();
virtual int getType() const {return type;};
virtual const char* description() const {return name;}
virtual bool isSecure() const;
diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx
index 9eeb76c..e1a31f7 100644
--- a/common/rfb/CSecurityTLS.cxx
+++ b/common/rfb/CSecurityTLS.cxx
@@ -67,8 +67,9 @@
static LogWriter vlog("TLS");
-CSecurityTLS::CSecurityTLS(bool _anon) : session(0), anon_cred(0),
- anon(_anon), fis(0), fos(0)
+CSecurityTLS::CSecurityTLS(CConnection* cc, bool _anon)
+ : CSecurity(cc), session(NULL), anon_cred(NULL), cert_cred(NULL),
+ anon(_anon), tlsis(NULL), tlsos(NULL), rawis(NULL), rawos(NULL)
{
cafile = X509CA.getData();
crlfile = X509CRL.getData();
@@ -115,6 +116,21 @@
cert_cred = 0;
}
+ if (rawis && rawos) {
+ cc->setStreams(rawis, rawos);
+ rawis = NULL;
+ rawos = NULL;
+ }
+
+ if (tlsis) {
+ delete tlsis;
+ tlsis = NULL;
+ }
+ if (tlsos) {
+ delete tlsos;
+ tlsos = NULL;
+ }
+
if (session) {
gnutls_deinit(session);
session = 0;
@@ -126,18 +142,13 @@
{
shutdown(true);
- if (fis)
- delete fis;
- if (fos)
- delete fos;
-
delete[] cafile;
delete[] crlfile;
gnutls_global_deinit();
}
-bool CSecurityTLS::processMsg(CConnection* cc)
+bool CSecurityTLS::processMsg()
{
rdr::InStream* is = cc->getInStream();
rdr::OutStream* os = cc->getOutStream();
@@ -164,17 +175,19 @@
throw AuthFailureException("gnutls_set_default_priority failed");
setParam();
- }
- rdr::TLSInStream *tlsis = new rdr::TLSInStream(is, session);
- rdr::TLSOutStream *tlsos = new rdr::TLSOutStream(os, session);
+ // Create these early as they set up the push/pull functions
+ // for GnuTLS
+ tlsis = new rdr::TLSInStream(is, session);
+ tlsos = new rdr::TLSOutStream(os, session);
+
+ rawis = is;
+ rawos = os;
+ }
int err;
err = gnutls_handshake(session);
if (err != GNUTLS_E_SUCCESS) {
- delete tlsis;
- delete tlsos;
-
if (!gnutls_error_is_fatal(err))
return false;
@@ -185,7 +198,7 @@
checkSession();
- cc->setStreams(fis = tlsis, fos = tlsos);
+ cc->setStreams(tlsis, tlsos);
return true;
}
diff --git a/common/rfb/CSecurityTLS.h b/common/rfb/CSecurityTLS.h
index e726d1e..4932c07 100644
--- a/common/rfb/CSecurityTLS.h
+++ b/common/rfb/CSecurityTLS.h
@@ -42,9 +42,9 @@
class UserMsgBox;
class CSecurityTLS : public CSecurity {
public:
- CSecurityTLS(bool _anon);
+ CSecurityTLS(CConnection* cc, bool _anon);
virtual ~CSecurityTLS();
- virtual bool processMsg(CConnection* cc);
+ virtual bool processMsg();
virtual int getType() const { return anon ? secTypeTLSNone : secTypeX509None; }
virtual const char* description() const
{ return anon ? "TLS Encryption without VncAuth" : "X509 Encryption without VncAuth"; }
@@ -69,8 +69,12 @@
bool anon;
char *cafile, *crlfile;
- rdr::InStream* fis;
- rdr::OutStream* fos;
+
+ rdr::InStream* tlsis;
+ rdr::OutStream* tlsos;
+
+ rdr::InStream* rawis;
+ rdr::OutStream* rawos;
};
}
diff --git a/common/rfb/CSecurityVeNCrypt.cxx b/common/rfb/CSecurityVeNCrypt.cxx
index f9597cc..22201dd 100644
--- a/common/rfb/CSecurityVeNCrypt.cxx
+++ b/common/rfb/CSecurityVeNCrypt.cxx
@@ -36,7 +36,8 @@
static LogWriter vlog("CVeNCrypt");
-CSecurityVeNCrypt::CSecurityVeNCrypt(SecurityClient* sec) : csecurity(NULL), security(sec)
+CSecurityVeNCrypt::CSecurityVeNCrypt(CConnection* cc, SecurityClient* sec)
+ : CSecurity(cc), csecurity(NULL), security(sec)
{
haveRecvdMajorVersion = false;
haveRecvdMinorVersion = false;
@@ -59,7 +60,7 @@
delete[] availableTypes;
}
-bool CSecurityVeNCrypt::processMsg(CConnection* cc)
+bool CSecurityVeNCrypt::processMsg()
{
InStream* is = cc->getInStream();
OutStream* os = cc->getOutStream();
@@ -171,7 +172,7 @@
if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt)
throw AuthFailureException("No valid VeNCrypt sub-type");
- csecurity = security->GetCSecurity(chosenType);
+ csecurity = security->GetCSecurity(cc, chosenType);
/* send chosen type to server */
os->writeU32(chosenType);
@@ -188,7 +189,7 @@
throw AuthFailureException("The server reported 0 VeNCrypt sub-types");
}
- return csecurity->processMsg(cc);
+ return csecurity->processMsg();
}
const char* CSecurityVeNCrypt::description() const
diff --git a/common/rfb/CSecurityVeNCrypt.h b/common/rfb/CSecurityVeNCrypt.h
index 6d978c7..d015e8f 100644
--- a/common/rfb/CSecurityVeNCrypt.h
+++ b/common/rfb/CSecurityVeNCrypt.h
@@ -34,9 +34,9 @@
class CSecurityVeNCrypt : public CSecurity {
public:
- CSecurityVeNCrypt(SecurityClient* sec);
+ CSecurityVeNCrypt(CConnection* cc, SecurityClient* sec);
~CSecurityVeNCrypt();
- virtual bool processMsg(CConnection* cc);// { return true; }
+ virtual bool processMsg();
int getType() const {return chosenType;}
virtual const char* description() const;
virtual bool isSecure() const;
diff --git a/common/rfb/CSecurityVncAuth.cxx b/common/rfb/CSecurityVncAuth.cxx
index 46463e0..6a87498 100644
--- a/common/rfb/CSecurityVncAuth.cxx
+++ b/common/rfb/CSecurityVncAuth.cxx
@@ -40,7 +40,7 @@
static const int vncAuthChallengeSize = 16;
-bool CSecurityVncAuth::processMsg(CConnection* cc)
+bool CSecurityVncAuth::processMsg()
{
rdr::InStream* is = cc->getInStream();
rdr::OutStream* os = cc->getOutStream();
diff --git a/common/rfb/CSecurityVncAuth.h b/common/rfb/CSecurityVncAuth.h
index 391ed23..2da9817 100644
--- a/common/rfb/CSecurityVncAuth.h
+++ b/common/rfb/CSecurityVncAuth.h
@@ -25,9 +25,9 @@
class CSecurityVncAuth : public CSecurity {
public:
- CSecurityVncAuth(void) {}
+ CSecurityVncAuth(CConnection* cc) : CSecurity(cc) {}
virtual ~CSecurityVncAuth() {}
- virtual bool processMsg(CConnection* cc);
+ virtual bool processMsg();
virtual int getType() const {return secTypeVncAuth;};
virtual const char* description() const {return "No Encryption";}
};
diff --git a/common/rfb/Congestion.cxx b/common/rfb/Congestion.cxx
index 8162808..4a78452 100644
--- a/common/rfb/Congestion.cxx
+++ b/common/rfb/Congestion.cxx
@@ -291,11 +291,20 @@
size_t Congestion::getBandwidth()
{
+ size_t bandwidth;
+
// No measurements yet? Guess RTT of 60 ms
if (safeBaseRTT == (unsigned)-1)
- return congWindow * 1000 / 60;
+ bandwidth = congWindow * 1000 / 60;
+ else
+ bandwidth = congWindow * 1000 / safeBaseRTT;
- return congWindow * 1000 / safeBaseRTT;
+ // We're still probing so guess actual bandwidth is halfway between
+ // the current guess and the next one (slow start doubles each time)
+ if (inSlowStart)
+ bandwidth = bandwidth + bandwidth / 2;
+
+ return bandwidth;
}
void Congestion::debugTrace(const char* filename, int fd)
diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx
index 53e0365..02128f7 100644
--- a/common/rfb/EncodeManager.cxx
+++ b/common/rfb/EncodeManager.cxx
@@ -1,6 +1,7 @@
/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
* Copyright 2014-2018 Pierre Ossman for Cendio AB
+ * Copyright 2018 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
@@ -50,6 +51,9 @@
// Don't bother with blocks smaller than this
static const int SolidBlockMinArea = 2048;
+// How long we consider a region recently changed (in ms)
+static const int RecentChangeTimeout = 50;
+
namespace rfb {
enum EncoderClass {
@@ -123,7 +127,8 @@
return "Unknown Encoder Type";
}
-EncodeManager::EncodeManager(SConnection* conn_) : conn(conn_)
+EncodeManager::EncodeManager(SConnection* conn_)
+ : conn(conn_), recentChangeTimer(this)
{
StatsVector::iterator iter;
@@ -253,23 +258,57 @@
return !lossyRegion.intersect(req).is_empty();
}
+int EncodeManager::getNextLosslessRefresh(const Region& req)
+{
+ // Do we have something we can send right away?
+ if (!pendingRefreshRegion.intersect(req).is_empty())
+ return 0;
+
+ assert(needsLosslessRefresh(req));
+ assert(recentChangeTimer.isStarted());
+
+ return recentChangeTimer.getNextTimeout();
+}
+
void EncodeManager::pruneLosslessRefresh(const Region& limits)
{
lossyRegion.assign_intersect(limits);
+ pendingRefreshRegion.assign_intersect(limits);
}
void EncodeManager::writeUpdate(const UpdateInfo& ui, const PixelBuffer* pb,
const RenderedCursor* renderedCursor)
{
- doUpdate(true, ui.changed, ui.copied, ui.copy_delta, pb, renderedCursor);
+ doUpdate(true, ui.changed, ui.copied, ui.copy_delta, pb, renderedCursor);
+
+ recentlyChangedRegion.assign_union(ui.changed);
+ recentlyChangedRegion.assign_union(ui.copied);
+ if (!recentChangeTimer.isStarted())
+ recentChangeTimer.start(RecentChangeTimeout);
}
void EncodeManager::writeLosslessRefresh(const Region& req, const PixelBuffer* pb,
const RenderedCursor* renderedCursor,
size_t maxUpdateSize)
{
- doUpdate(false, getLosslessRefresh(req, maxUpdateSize),
- Region(), Point(), pb, renderedCursor);
+ doUpdate(false, getLosslessRefresh(req, maxUpdateSize),
+ Region(), Point(), pb, renderedCursor);
+}
+
+bool EncodeManager::handleTimeout(Timer* t)
+{
+ if (t == &recentChangeTimer) {
+ // Any lossy region that wasn't recently updated can
+ // now be scheduled for a refresh
+ pendingRefreshRegion.assign_union(lossyRegion.subtract(recentlyChangedRegion));
+ recentlyChangedRegion.clear();
+
+ // Will there be more to do? (i.e. do we need another round)
+ if (!lossyRegion.subtract(pendingRefreshRegion).is_empty())
+ return true;
+ }
+
+ return false;
}
void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
@@ -325,6 +364,8 @@
enum EncoderClass solid, bitmap, bitmapRLE;
enum EncoderClass indexed, indexedRLE, fullColour;
+ bool allowJPEG;
+
rdr::S32 preferred;
std::vector<int>::iterator iter;
@@ -332,6 +373,12 @@
solid = bitmap = bitmapRLE = encoderRaw;
indexed = indexedRLE = fullColour = encoderRaw;
+ allowJPEG = conn->cp.pf().bpp >= 16;
+ if (!allowLossy) {
+ if (encoders[encoderTightJPEG]->losslessQuality == -1)
+ allowJPEG = false;
+ }
+
// Try to respect the client's wishes
preferred = conn->getPreferredEncoding();
switch (preferred) {
@@ -344,8 +391,7 @@
bitmapRLE = indexedRLE = fullColour = encoderHextile;
break;
case encodingTight:
- if (encoders[encoderTightJPEG]->isSupported() &&
- (conn->cp.pf().bpp >= 16) && allowLossy)
+ if (encoders[encoderTightJPEG]->isSupported() && allowJPEG)
fullColour = encoderTightJPEG;
else
fullColour = encoderTight;
@@ -362,8 +408,7 @@
// Any encoders still unassigned?
if (fullColour == encoderRaw) {
- if (encoders[encoderTightJPEG]->isSupported() &&
- (conn->cp.pf().bpp >= 16) && allowLossy)
+ if (encoders[encoderTightJPEG]->isSupported() && allowJPEG)
fullColour = encoderTightJPEG;
else if (encoders[encoderZRLE]->isSupported())
fullColour = encoderZRLE;
@@ -421,9 +466,17 @@
encoder = encoders[*iter];
encoder->setCompressLevel(conn->cp.compressLevel);
- encoder->setQualityLevel(conn->cp.qualityLevel);
- encoder->setFineQualityLevel(conn->cp.fineQualityLevel,
- conn->cp.subsampling);
+
+ if (allowLossy) {
+ encoder->setQualityLevel(conn->cp.qualityLevel);
+ encoder->setFineQualityLevel(conn->cp.fineQualityLevel,
+ conn->cp.subsampling);
+ } else {
+ int level = __rfbmax(conn->cp.qualityLevel,
+ encoder->losslessQuality);
+ encoder->setQualityLevel(level);
+ encoder->setFineQualityLevel(-1, subsampleUndefined);
+ }
}
}
@@ -437,8 +490,11 @@
// We make a conservative guess at the compression ratio at 2:1
maxUpdateSize *= 2;
+ // We will measure pixels, not bytes (assume 32 bpp)
+ maxUpdateSize /= 4;
+
area = 0;
- lossyRegion.intersect(req).get_rects(&rects);
+ pendingRefreshRegion.intersect(req).get_rects(&rects);
while (!rects.empty()) {
size_t idx;
Rect rect;
@@ -525,11 +581,17 @@
encoder = encoders[klass];
conn->writer()->startRect(rect, encoder->encoding);
- if (encoder->flags & EncoderLossy)
+ if ((encoder->flags & EncoderLossy) &&
+ ((encoder->losslessQuality == -1) ||
+ (encoder->getQualityLevel() < encoder->losslessQuality)))
lossyRegion.assign_union(Region(rect));
else
lossyRegion.assign_subtract(Region(rect));
+ // This was either a rect getting refreshed, or a rect that just got
+ // new content. Either way we should not try to refresh it anymore.
+ pendingRefreshRegion.assign_subtract(Region(rect));
+
return encoder;
}
@@ -574,6 +636,10 @@
lossyCopy.translate(delta);
lossyCopy.assign_intersect(copied);
lossyRegion.assign_union(lossyCopy);
+
+ // Stop any pending refresh as a copy is enough that we consider
+ // this region to be recently changed
+ pendingRefreshRegion.assign_subtract(copied);
}
void EncodeManager::writeSolidRects(Region *changed, const PixelBuffer* pb)
diff --git a/common/rfb/EncodeManager.h b/common/rfb/EncodeManager.h
index a91c544..bdae906 100644
--- a/common/rfb/EncodeManager.h
+++ b/common/rfb/EncodeManager.h
@@ -25,6 +25,7 @@
#include <rdr/types.h>
#include <rfb/PixelBuffer.h>
#include <rfb/Region.h>
+#include <rfb/Timer.h>
namespace rfb {
class SConnection;
@@ -36,7 +37,7 @@
struct RectInfo;
- class EncodeManager {
+ class EncodeManager : public Timer::Callback {
public:
EncodeManager(SConnection* conn);
~EncodeManager();
@@ -47,6 +48,8 @@
static bool supported(int encoding);
bool needsLosslessRefresh(const Region& req);
+ int getNextLosslessRefresh(const Region& req);
+
void pruneLosslessRefresh(const Region& limits);
void writeUpdate(const UpdateInfo& ui, const PixelBuffer* pb,
@@ -57,6 +60,8 @@
size_t maxUpdateSize);
protected:
+ virtual bool handleTimeout(Timer* t);
+
void doUpdate(bool allowLossy, const Region& changed,
const Region& copied, const Point& copy_delta,
const PixelBuffer* pb,
@@ -117,6 +122,10 @@
std::vector<int> activeEncoders;
Region lossyRegion;
+ Region recentlyChangedRegion;
+ Region pendingRefreshRegion;
+
+ Timer recentChangeTimer;
struct EncoderStats {
unsigned rects;
diff --git a/common/rfb/Encoder.cxx b/common/rfb/Encoder.cxx
index 18b6680..0e29f1d 100644
--- a/common/rfb/Encoder.cxx
+++ b/common/rfb/Encoder.cxx
@@ -24,9 +24,11 @@
using namespace rfb;
Encoder::Encoder(SConnection *conn_, int encoding_,
- enum EncoderFlags flags_, unsigned int maxPaletteSize_) :
+ enum EncoderFlags flags_,
+ unsigned int maxPaletteSize_, int losslessQuality_) :
encoding(encoding_), flags(flags_),
- maxPaletteSize(maxPaletteSize_), conn(conn_)
+ maxPaletteSize(maxPaletteSize_), losslessQuality(losslessQuality_),
+ conn(conn_)
{
}
diff --git a/common/rfb/Encoder.h b/common/rfb/Encoder.h
index 66a10d2..d5a0288 100644
--- a/common/rfb/Encoder.h
+++ b/common/rfb/Encoder.h
@@ -42,7 +42,8 @@
class Encoder {
public:
Encoder(SConnection* conn, int encoding,
- enum EncoderFlags flags, unsigned int maxPaletteSize);
+ enum EncoderFlags flags, unsigned int maxPaletteSize=-1,
+ int losslessQuality=-1);
virtual ~Encoder();
// isSupported() should return a boolean indicating if this encoder
@@ -54,6 +55,9 @@
virtual void setQualityLevel(int level) {};
virtual void setFineQualityLevel(int quality, int subsampling) {};
+ virtual int getCompressLevel() { return -1; };
+ virtual int getQualityLevel() { return -1; };
+
// writeRect() is the main interface that encodes the given rectangle
// with data from the PixelBuffer onto the SConnection given at
// encoder creation.
@@ -92,6 +96,10 @@
// Maximum size of the palette per rect
const unsigned int maxPaletteSize;
+ // Minimum level where the quality loss will not be noticed by
+ // most users (only relevant with EncoderLossy flag)
+ const int losslessQuality;
+
protected:
SConnection* conn;
};
diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx
index 418a440..47e5251 100644
--- a/common/rfb/HextileEncoder.cxx
+++ b/common/rfb/HextileEncoder.cxx
@@ -45,7 +45,7 @@
#undef BPP
HextileEncoder::HextileEncoder(SConnection* conn) :
- Encoder(conn, encodingHextile, EncoderPlain, -1)
+ Encoder(conn, encodingHextile, EncoderPlain)
{
}
diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx
index 60a0663..7287e7e 100644
--- a/common/rfb/RREEncoder.cxx
+++ b/common/rfb/RREEncoder.cxx
@@ -37,7 +37,7 @@
#undef BPP
RREEncoder::RREEncoder(SConnection* conn) :
- Encoder(conn, encodingRRE, EncoderPlain, -1)
+ Encoder(conn, encodingRRE, EncoderPlain)
{
}
diff --git a/common/rfb/RawEncoder.cxx b/common/rfb/RawEncoder.cxx
index 4090427..b12cf06 100644
--- a/common/rfb/RawEncoder.cxx
+++ b/common/rfb/RawEncoder.cxx
@@ -25,7 +25,7 @@
using namespace rfb;
RawEncoder::RawEncoder(SConnection* conn) :
- Encoder(conn, encodingRaw, EncoderPlain, -1)
+ Encoder(conn, encodingRaw, EncoderPlain)
{
}
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
index 6b81055..efc26ac 100644
--- a/common/rfb/SConnection.cxx
+++ b/common/rfb/SConnection.cxx
@@ -64,7 +64,8 @@
SConnection::~SConnection()
{
- if (ssecurity) ssecurity->destroy();
+ if (ssecurity)
+ delete ssecurity;
delete reader_;
reader_ = 0;
delete writer_;
@@ -155,7 +156,7 @@
os->writeU32(*i);
if (*i == secTypeNone) os->flush();
state_ = RFBSTATE_SECURITY;
- ssecurity = security.GetSSecurity(*i);
+ ssecurity = security.GetSSecurity(this, *i);
processSecurityMsg();
return;
}
@@ -198,7 +199,7 @@
try {
state_ = RFBSTATE_SECURITY;
- ssecurity = security.GetSSecurity(secType);
+ ssecurity = security.GetSSecurity(this, secType);
} catch (rdr::Exception& e) {
throwConnFailedException("%s", e.str());
}
@@ -210,7 +211,7 @@
{
vlog.debug("processing security message");
try {
- bool done = ssecurity->processMsg(this);
+ bool done = ssecurity->processMsg();
if (done) {
state_ = RFBSTATE_QUERYING;
setAccessRights(ssecurity->getAccessRights());
diff --git a/common/rfb/SSecurity.h b/common/rfb/SSecurity.h
index 6da63c3..8ae7902 100644
--- a/common/rfb/SSecurity.h
+++ b/common/rfb/SSecurity.h
@@ -52,9 +52,9 @@
class SSecurity {
public:
+ SSecurity(SConnection* sc) { this->sc = sc; }
virtual ~SSecurity() {}
- virtual bool processMsg(SConnection* sc)=0;
- virtual void destroy() { delete this; }
+ virtual bool processMsg() = 0;
virtual int getType() const = 0;
// getUserName() gets the name of the user attempting authentication. The
@@ -64,6 +64,9 @@
virtual const char* getUserName() const = 0;
virtual SConnection::AccessRights getAccessRights() const { return SConnection::AccessDefault; }
+
+ protected:
+ SConnection* sc;
};
}
diff --git a/common/rfb/SSecurityNone.h b/common/rfb/SSecurityNone.h
index 5c19f29..f14d83a 100644
--- a/common/rfb/SSecurityNone.h
+++ b/common/rfb/SSecurityNone.h
@@ -28,7 +28,8 @@
class SSecurityNone : public SSecurity {
public:
- virtual bool processMsg(SConnection* sc) { return true; }
+ SSecurityNone(SConnection* sc) : SSecurity(sc) {}
+ virtual bool processMsg() { return true; }
virtual int getType() const {return secTypeNone;}
virtual const char* getUserName() const {return 0;}
};
diff --git a/common/rfb/SSecurityPlain.cxx b/common/rfb/SSecurityPlain.cxx
index fc9dff2..6d48b65 100644
--- a/common/rfb/SSecurityPlain.cxx
+++ b/common/rfb/SSecurityPlain.cxx
@@ -60,7 +60,7 @@
return false;
}
-SSecurityPlain::SSecurityPlain()
+SSecurityPlain::SSecurityPlain(SConnection* sc) : SSecurity(sc)
{
#ifdef HAVE_PAM
valid = new UnixPasswordValidator();
@@ -73,7 +73,7 @@
state = 0;
}
-bool SSecurityPlain::processMsg(SConnection* sc)
+bool SSecurityPlain::processMsg()
{
rdr::InStream* is = sc->getInStream();
char* pw;
diff --git a/common/rfb/SSecurityPlain.h b/common/rfb/SSecurityPlain.h
index 4bf42b7..4b12da0 100644
--- a/common/rfb/SSecurityPlain.h
+++ b/common/rfb/SSecurityPlain.h
@@ -47,8 +47,8 @@
class SSecurityPlain : public SSecurity {
public:
- SSecurityPlain();
- virtual bool processMsg(SConnection* sc);
+ SSecurityPlain(SConnection* sc);
+ virtual bool processMsg();
virtual int getType() const { return secTypePlain; };
virtual const char* getUserName() const { return username.buf; }
diff --git a/common/rfb/SSecurityStack.cxx b/common/rfb/SSecurityStack.cxx
index 478ce4f..74509e7 100644
--- a/common/rfb/SSecurityStack.cxx
+++ b/common/rfb/SSecurityStack.cxx
@@ -20,8 +20,11 @@
using namespace rfb;
-SSecurityStack::SSecurityStack(int Type, SSecurity* s0, SSecurity* s1)
- :state(0), state0(s0), state1(s1), type(Type) {}
+SSecurityStack::SSecurityStack(SConnection* sc, int Type,
+ SSecurity* s0, SSecurity* s1)
+ : SSecurity(sc), state(0), state0(s0), state1(s1), type(Type)
+{
+}
SSecurityStack::~SSecurityStack()
{
@@ -31,13 +34,13 @@
delete state1;
}
-bool SSecurityStack::processMsg(SConnection* cc)
+bool SSecurityStack::processMsg()
{
bool res = true;
if (state == 0) {
if (state0)
- res = state0->processMsg(cc);
+ res = state0->processMsg();
if (!res)
return res;
state++;
@@ -45,7 +48,7 @@
if (state == 1) {
if (state1)
- res = state1->processMsg(cc);
+ res = state1->processMsg();
if (!res)
return res;
state++;
diff --git a/common/rfb/SSecurityStack.h b/common/rfb/SSecurityStack.h
index dd743d2..8b412bd 100644
--- a/common/rfb/SSecurityStack.h
+++ b/common/rfb/SSecurityStack.h
@@ -26,9 +26,10 @@
class SSecurityStack : public SSecurity {
public:
- SSecurityStack(int Type, SSecurity* s0 = 0, SSecurity* s1 = 0);
+ SSecurityStack(SConnection* sc, int Type,
+ SSecurity* s0 = NULL, SSecurity* s1 = NULL);
~SSecurityStack();
- virtual bool processMsg(SConnection* cc);
+ virtual bool processMsg();
virtual int getType() const { return type; };
virtual const char* getUserName() const;
virtual SConnection::AccessRights getAccessRights() const;
diff --git a/common/rfb/SSecurityTLS.cxx b/common/rfb/SSecurityTLS.cxx
index 5576a06..49532f5 100644
--- a/common/rfb/SSecurityTLS.cxx
+++ b/common/rfb/SSecurityTLS.cxx
@@ -49,9 +49,10 @@
static LogWriter vlog("TLS");
-SSecurityTLS::SSecurityTLS(bool _anon) : session(0), dh_params(0),
- anon_cred(0), cert_cred(0),
- anon(_anon), fis(0), fos(0)
+SSecurityTLS::SSecurityTLS(SConnection* sc, bool _anon)
+ : SSecurity(sc), session(NULL), dh_params(NULL), anon_cred(NULL),
+ cert_cred(NULL), anon(_anon), tlsis(NULL), tlsos(NULL),
+ rawis(NULL), rawos(NULL)
{
certfile = X509_CertFile.getData();
keyfile = X509_KeyFile.getData();
@@ -84,6 +85,21 @@
cert_cred = 0;
}
+ if (rawis && rawos) {
+ sc->setStreams(rawis, rawos);
+ rawis = NULL;
+ rawos = NULL;
+ }
+
+ if (tlsis) {
+ delete tlsis;
+ tlsis = NULL;
+ }
+ if (tlsos) {
+ delete tlsos;
+ tlsos = NULL;
+ }
+
if (session) {
gnutls_deinit(session);
session = 0;
@@ -95,25 +111,20 @@
{
shutdown();
- if (fis)
- delete fis;
- if (fos)
- delete fos;
-
delete[] keyfile;
delete[] certfile;
gnutls_global_deinit();
}
-bool SSecurityTLS::processMsg(SConnection *sc)
+bool SSecurityTLS::processMsg()
{
- rdr::InStream* is = sc->getInStream();
- rdr::OutStream* os = sc->getOutStream();
-
vlog.debug("Process security message (session %p)", session);
if (!session) {
+ rdr::InStream* is = sc->getInStream();
+ rdr::OutStream* os = sc->getOutStream();
+
if (gnutls_init(&session, GNUTLS_SERVER) != GNUTLS_E_SUCCESS)
throw AuthFailureException("gnutls_init failed");
@@ -130,17 +141,19 @@
os->writeU8(1);
os->flush();
- }
- rdr::TLSInStream *tlsis = new rdr::TLSInStream(is, session);
- rdr::TLSOutStream *tlsos = new rdr::TLSOutStream(os, session);
+ // Create these early as they set up the push/pull functions
+ // for GnuTLS
+ tlsis = new rdr::TLSInStream(is, session);
+ tlsos = new rdr::TLSOutStream(os, session);
+
+ rawis = is;
+ rawos = os;
+ }
int err;
err = gnutls_handshake(session);
if (err != GNUTLS_E_SUCCESS) {
- delete tlsis;
- delete tlsos;
-
if (!gnutls_error_is_fatal(err)) {
vlog.debug("Deferring completion of TLS handshake: %s", gnutls_strerror(err));
return false;
@@ -152,7 +165,7 @@
vlog.debug("Handshake completed");
- sc->setStreams(fis = tlsis, fos = tlsos);
+ sc->setStreams(tlsis, tlsos);
return true;
}
diff --git a/common/rfb/SSecurityTLS.h b/common/rfb/SSecurityTLS.h
index 30242a2..6f71182 100644
--- a/common/rfb/SSecurityTLS.h
+++ b/common/rfb/SSecurityTLS.h
@@ -40,9 +40,9 @@
class SSecurityTLS : public SSecurity {
public:
- SSecurityTLS(bool _anon);
+ SSecurityTLS(SConnection* sc, bool _anon);
virtual ~SSecurityTLS();
- virtual bool processMsg(SConnection* sc);
+ virtual bool processMsg();
virtual const char* getUserName() const {return 0;}
virtual int getType() const { return anon ? secTypeTLSNone : secTypeX509None;}
@@ -63,8 +63,11 @@
int type;
bool anon;
- rdr::InStream* fis;
- rdr::OutStream* fos;
+ rdr::InStream* tlsis;
+ rdr::OutStream* tlsos;
+
+ rdr::InStream* rawis;
+ rdr::OutStream* rawos;
};
}
diff --git a/common/rfb/SSecurityVeNCrypt.cxx b/common/rfb/SSecurityVeNCrypt.cxx
index ce6c71b..d522ef6 100644
--- a/common/rfb/SSecurityVeNCrypt.cxx
+++ b/common/rfb/SSecurityVeNCrypt.cxx
@@ -38,7 +38,8 @@
static LogWriter vlog("SVeNCrypt");
-SSecurityVeNCrypt::SSecurityVeNCrypt(SecurityServer *sec) : security(sec)
+SSecurityVeNCrypt::SSecurityVeNCrypt(SConnection* sc, SecurityServer *sec)
+ : SSecurity(sc), security(sec)
{
ssecurity = NULL;
haveSentVersion = false;
@@ -63,7 +64,7 @@
}
}
-bool SSecurityVeNCrypt::processMsg(SConnection* sc)
+bool SSecurityVeNCrypt::processMsg()
{
rdr::InStream* is = sc->getInStream();
rdr::OutStream* os = sc->getOutStream();
@@ -166,11 +167,11 @@
if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt)
throw AuthFailureException("No valid VeNCrypt sub-type");
- ssecurity = security->GetSSecurity(chosenType);
+ ssecurity = security->GetSSecurity(sc, chosenType);
}
/* continue processing the messages */
- return ssecurity->processMsg(sc);
+ return ssecurity->processMsg();
}
const char* SSecurityVeNCrypt::getUserName() const
diff --git a/common/rfb/SSecurityVeNCrypt.h b/common/rfb/SSecurityVeNCrypt.h
index f9c753f..06758b8 100644
--- a/common/rfb/SSecurityVeNCrypt.h
+++ b/common/rfb/SSecurityVeNCrypt.h
@@ -36,9 +36,9 @@
class SSecurityVeNCrypt : public SSecurity {
public:
- SSecurityVeNCrypt(SecurityServer *sec);
+ SSecurityVeNCrypt(SConnection* sc, SecurityServer *sec);
~SSecurityVeNCrypt();
- virtual bool processMsg(SConnection* sc);// { return true; }
+ virtual bool processMsg();
virtual int getType() const { return chosenType; }
virtual const char* getUserName() const;
virtual SConnection::AccessRights getAccessRights() const;
diff --git a/common/rfb/SSecurityVncAuth.cxx b/common/rfb/SSecurityVncAuth.cxx
index 05488f6..882f0b0 100644
--- a/common/rfb/SSecurityVncAuth.cxx
+++ b/common/rfb/SSecurityVncAuth.cxx
@@ -48,8 +48,9 @@
("Password", "Obfuscated binary encoding of the password which clients must supply to "
"access the server", &SSecurityVncAuth::vncAuthPasswdFile);
-SSecurityVncAuth::SSecurityVncAuth(void)
- : sentChallenge(false), responsePos(0), pg(&vncAuthPasswd), accessRights(0)
+SSecurityVncAuth::SSecurityVncAuth(SConnection* sc)
+ : SSecurity(sc), sentChallenge(false), responsePos(0),
+ pg(&vncAuthPasswd), accessRights(0)
{
}
@@ -70,7 +71,7 @@
return memcmp(response, expectedResponse, vncAuthChallengeSize) == 0;
}
-bool SSecurityVncAuth::processMsg(SConnection* sc)
+bool SSecurityVncAuth::processMsg()
{
rdr::InStream* is = sc->getInStream();
rdr::OutStream* os = sc->getOutStream();
diff --git a/common/rfb/SSecurityVncAuth.h b/common/rfb/SSecurityVncAuth.h
index a1d1747..fe00b03 100644
--- a/common/rfb/SSecurityVncAuth.h
+++ b/common/rfb/SSecurityVncAuth.h
@@ -51,8 +51,8 @@
class SSecurityVncAuth : public SSecurity {
public:
- SSecurityVncAuth(void);
- virtual bool processMsg(SConnection* sc);
+ SSecurityVncAuth(SConnection* sc);
+ virtual bool processMsg();
virtual int getType() const {return secTypeVncAuth;}
virtual const char* getUserName() const {return 0;}
virtual SConnection::AccessRights getAccessRights() const { return accessRights; }
diff --git a/common/rfb/SecurityClient.cxx b/common/rfb/SecurityClient.cxx
index 9bd780f..23c1d67 100644
--- a/common/rfb/SecurityClient.cxx
+++ b/common/rfb/SecurityClient.cxx
@@ -55,7 +55,7 @@
#endif
ConfViewer);
-CSecurity* SecurityClient::GetCSecurity(U32 secType)
+CSecurity* SecurityClient::GetCSecurity(CConnection* cc, U32 secType)
{
assert (CSecurity::upg != NULL); /* (upg == NULL) means bug in the viewer */
#ifdef HAVE_GNUTLS
@@ -66,29 +66,39 @@
goto bail;
switch (secType) {
- case secTypeNone: return new CSecurityNone();
- case secTypeVncAuth: return new CSecurityVncAuth();
- case secTypeVeNCrypt: return new CSecurityVeNCrypt(this);
- case secTypePlain: return new CSecurityPlain();
+ case secTypeNone: return new CSecurityNone(cc);
+ case secTypeVncAuth: return new CSecurityVncAuth(cc);
+ case secTypeVeNCrypt: return new CSecurityVeNCrypt(cc, this);
+ case secTypePlain: return new CSecurityPlain(cc);
#ifdef HAVE_GNUTLS
case secTypeTLSNone:
- return new CSecurityStack(secTypeTLSNone, "TLS with no password",
- new CSecurityTLS(true));
+ return new CSecurityStack(cc, secTypeTLSNone,
+ "TLS with no password",
+ new CSecurityTLS(cc, true));
case secTypeTLSVnc:
- return new CSecurityStack(secTypeTLSVnc, "TLS with VNCAuth",
- new CSecurityTLS(true), new CSecurityVncAuth());
+ return new CSecurityStack(cc, secTypeTLSVnc,
+ "TLS with VNCAuth",
+ new CSecurityTLS(cc, true),
+ new CSecurityVncAuth(cc));
case secTypeTLSPlain:
- return new CSecurityStack(secTypeTLSPlain, "TLS with Username/Password",
- new CSecurityTLS(true), new CSecurityPlain());
+ return new CSecurityStack(cc, secTypeTLSPlain,
+ "TLS with Username/Password",
+ new CSecurityTLS(cc, true),
+ new CSecurityPlain(cc));
case secTypeX509None:
- return new CSecurityStack(secTypeX509None, "X509 with no password",
- new CSecurityTLS(false));
+ return new CSecurityStack(cc, secTypeX509None,
+ "X509 with no password",
+ new CSecurityTLS(cc, false));
case secTypeX509Vnc:
- return new CSecurityStack(secTypeX509Vnc, "X509 with VNCAuth",
- new CSecurityTLS(false), new CSecurityVncAuth());
+ return new CSecurityStack(cc, secTypeX509Vnc,
+ "X509 with VNCAuth",
+ new CSecurityTLS(cc, false),
+ new CSecurityVncAuth(cc));
case secTypeX509Plain:
- return new CSecurityStack(secTypeX509Plain, "X509 with Username/Password",
- new CSecurityTLS(false), new CSecurityPlain());
+ return new CSecurityStack(cc, secTypeX509Plain,
+ "X509 with Username/Password",
+ new CSecurityTLS(cc, false),
+ new CSecurityPlain(cc));
#endif
}
diff --git a/common/rfb/SecurityClient.h b/common/rfb/SecurityClient.h
index b8ad831..3074a87 100644
--- a/common/rfb/SecurityClient.h
+++ b/common/rfb/SecurityClient.h
@@ -33,7 +33,7 @@
SecurityClient(void) : Security(secTypes) {}
/* Create client side CSecurity class instance */
- CSecurity* GetCSecurity(rdr::U32 secType);
+ CSecurity* GetCSecurity(CConnection* cc, rdr::U32 secType);
static void setDefaults(void);
diff --git a/common/rfb/SecurityServer.cxx b/common/rfb/SecurityServer.cxx
index e0aee13..97b133c 100644
--- a/common/rfb/SecurityServer.cxx
+++ b/common/rfb/SecurityServer.cxx
@@ -49,29 +49,29 @@
#endif
ConfServer);
-SSecurity* SecurityServer::GetSSecurity(U32 secType)
+SSecurity* SecurityServer::GetSSecurity(SConnection* sc, U32 secType)
{
if (!IsSupported(secType))
goto bail;
switch (secType) {
- case secTypeNone: return new SSecurityNone();
- case secTypeVncAuth: return new SSecurityVncAuth();
- case secTypeVeNCrypt: return new SSecurityVeNCrypt(this);
- case secTypePlain: return new SSecurityPlain();
+ case secTypeNone: return new SSecurityNone(sc);
+ case secTypeVncAuth: return new SSecurityVncAuth(sc);
+ case secTypeVeNCrypt: return new SSecurityVeNCrypt(sc, this);
+ case secTypePlain: return new SSecurityPlain(sc);
#ifdef HAVE_GNUTLS
case secTypeTLSNone:
- return new SSecurityStack(secTypeTLSNone, new SSecurityTLS(true));
+ return new SSecurityStack(sc, secTypeTLSNone, new SSecurityTLS(sc, true));
case secTypeTLSVnc:
- return new SSecurityStack(secTypeTLSVnc, new SSecurityTLS(true), new SSecurityVncAuth());
+ return new SSecurityStack(sc, secTypeTLSVnc, new SSecurityTLS(sc, true), new SSecurityVncAuth(sc));
case secTypeTLSPlain:
- return new SSecurityStack(secTypeTLSPlain, new SSecurityTLS(true), new SSecurityPlain());
+ return new SSecurityStack(sc, secTypeTLSPlain, new SSecurityTLS(sc, true), new SSecurityPlain(sc));
case secTypeX509None:
- return new SSecurityStack(secTypeX509None, new SSecurityTLS(false));
+ return new SSecurityStack(sc, secTypeX509None, new SSecurityTLS(sc, false));
case secTypeX509Vnc:
- return new SSecurityStack(secTypeX509None, new SSecurityTLS(false), new SSecurityVncAuth());
+ return new SSecurityStack(sc, secTypeX509None, new SSecurityTLS(sc, false), new SSecurityVncAuth(sc));
case secTypeX509Plain:
- return new SSecurityStack(secTypeX509Plain, new SSecurityTLS(false), new SSecurityPlain());
+ return new SSecurityStack(sc, secTypeX509Plain, new SSecurityTLS(sc, false), new SSecurityPlain(sc));
#endif
}
diff --git a/common/rfb/SecurityServer.h b/common/rfb/SecurityServer.h
index 019d67f..354f642 100644
--- a/common/rfb/SecurityServer.h
+++ b/common/rfb/SecurityServer.h
@@ -24,7 +24,8 @@
#include <rfb/Security.h>
namespace rfb {
-
+
+ class SConnection;
class SSecurity;
class SecurityServer : public Security {
@@ -32,7 +33,7 @@
SecurityServer(void) : Security(secTypes) {}
/* Create server side SSecurity class instance */
- SSecurity* GetSSecurity(rdr::U32 secType);
+ SSecurity* GetSSecurity(SConnection* sc, rdr::U32 secType);
static StringParameter secTypes;
};
diff --git a/common/rfb/TightJPEGEncoder.cxx b/common/rfb/TightJPEGEncoder.cxx
index 385207f..38cb4eb 100644
--- a/common/rfb/TightJPEGEncoder.cxx
+++ b/common/rfb/TightJPEGEncoder.cxx
@@ -64,7 +64,8 @@
TightJPEGEncoder::TightJPEGEncoder(SConnection* conn) :
- Encoder(conn, encodingTight, (EncoderFlags)(EncoderUseNativePF | EncoderLossy), -1),
+ Encoder(conn, encodingTight,
+ (EncoderFlags)(EncoderUseNativePF | EncoderLossy), -1, 9),
qualityLevel(-1), fineQuality(-1), fineSubsampling(subsampleUndefined)
{
}
@@ -101,6 +102,11 @@
fineSubsampling = subsampling;
}
+int TightJPEGEncoder::getQualityLevel()
+{
+ return qualityLevel;
+}
+
void TightJPEGEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
{
const rdr::U8* buffer;
diff --git a/common/rfb/TightJPEGEncoder.h b/common/rfb/TightJPEGEncoder.h
index 458c383..3d8fa8c 100644
--- a/common/rfb/TightJPEGEncoder.h
+++ b/common/rfb/TightJPEGEncoder.h
@@ -35,6 +35,8 @@
virtual void setQualityLevel(int level);
virtual void setFineQualityLevel(int quality, int subsampling);
+ virtual int getQualityLevel();
+
virtual void writeRect(const PixelBuffer* pb, const Palette& palette);
virtual void writeSolidRect(int width, int height,
const PixelFormat& pf,
diff --git a/common/rfb/Timer.cxx b/common/rfb/Timer.cxx
index fd1a87a..b9dd2f6 100644
--- a/common/rfb/Timer.cxx
+++ b/common/rfb/Timer.cxx
@@ -151,7 +151,7 @@
int Timer::getRemainingMs() {
timeval now;
gettimeofday(&now, 0);
- return __rfbmax(0, diffTimeMillis(pending.front()->dueTime, now));
+ return __rfbmax(0, diffTimeMillis(dueTime, now));
}
bool Timer::isBefore(timeval other) {
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index f22b993..f1591f4 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -1,5 +1,6 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2018 Pierre Ossman for Cendio AB
+ * Copyright 2018 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
@@ -48,7 +49,7 @@
inProcessMessages(false),
pendingSyncFence(false), syncFence(false), fenceFlags(0),
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
- server(server_), updates(false),
+ losslessTimer(this), server(server_), updates(false),
updateRenderedCursor(false), removeRenderedCursor(false),
continuousUpdates(false), encodeManager(this), pointerEventTime(0),
clientHasCursor(false),
@@ -839,7 +840,8 @@
bool VNCSConnectionST::handleTimeout(Timer* t)
{
try {
- if (t == &congestionTimer)
+ if ((t == &congestionTimer) ||
+ (t == &losslessTimer))
writeFramebufferUpdate();
} catch (rdr::Exception& e) {
close(e.str());
@@ -1065,28 +1067,46 @@
}
// Return if there is nothing to send the client.
+ if (ui.is_empty() && !writer()->needFakeUpdate()) {
+ int eta;
- if (ui.is_empty() && !writer()->needFakeUpdate() &&
- !encodeManager.needsLosslessRefresh(req))
- return;
+ // Any lossless refresh that needs handling?
+ if (!encodeManager.needsLosslessRefresh(req))
+ return;
+
+ // Now? Or later?
+ eta = encodeManager.getNextLosslessRefresh(req);
+ if (eta > 0) {
+ losslessTimer.start(eta);
+ return;
+ }
+ }
writeRTTPing();
if (!ui.is_empty())
encodeManager.writeUpdate(ui, server->getPixelBuffer(), cursor);
else {
- size_t maxUpdateSize;
+ int nextUpdate;
// FIXME: If continuous updates aren't used then the client might
// be slower than frameRate in its requests and we could
// afford a larger update size
+ nextUpdate = server->msToNextUpdate();
+ if (nextUpdate > 0) {
+ size_t bandwidth, maxUpdateSize;
- // FIXME: Bandwidth estimation without congestion control
- maxUpdateSize = congestion.getBandwidth() *
- server->msToNextUpdate() / 1000;
+ // FIXME: Bandwidth estimation without congestion control
+ bandwidth = congestion.getBandwidth();
- encodeManager.writeLosslessRefresh(req, server->getPixelBuffer(),
- cursor, maxUpdateSize);
+ // FIXME: Hard coded value for maximum CPU throughput
+ if (bandwidth > 5000000)
+ bandwidth = 5000000;
+
+ maxUpdateSize = bandwidth * nextUpdate / 1000;
+ encodeManager.writeLosslessRefresh(req, server->getPixelBuffer(),
+ cursor, maxUpdateSize);
+ }
}
writeRTTPing();
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 2f075a6..dfc8bcb 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -191,6 +191,7 @@
Congestion congestion;
Timer congestionTimer;
+ Timer losslessTimer;
VNCServerST* server;
SimpleUpdateTracker updates;