Browse Source

Merge branch 'connparams' of https://github.com/CendioOssman/tigervnc

tags/v1.9.90
Pierre Ossman 5 years ago
parent
commit
d8bbbeb3b3
55 changed files with 1234 additions and 1084 deletions
  1. 286
    21
      common/rfb/CConnection.cxx
  2. 63
    7
      common/rfb/CConnection.h
  3. 2
    1
      common/rfb/CMakeLists.txt
  4. 18
    15
      common/rfb/CMsgHandler.cxx
  5. 8
    6
      common/rfb/CMsgHandler.h
  6. 10
    12
      common/rfb/CMsgReader.cxx
  7. 14
    91
      common/rfb/CMsgWriter.cxx
  8. 6
    5
      common/rfb/CMsgWriter.h
  9. 0
    1
      common/rfb/CSecurityTLS.cxx
  10. 0
    1
      common/rfb/CSecurityTLS.h
  11. 178
    0
      common/rfb/ClientParams.cxx
  12. 23
    32
      common/rfb/ClientParams.h
  13. 0
    200
      common/rfb/ConnParams.cxx
  14. 4
    4
      common/rfb/CopyRectDecoder.cxx
  15. 3
    3
      common/rfb/CopyRectDecoder.h
  16. 7
    7
      common/rfb/DecodeManager.cxx
  17. 1
    1
      common/rfb/DecodeManager.h
  18. 2
    2
      common/rfb/Decoder.cxx
  19. 5
    5
      common/rfb/Decoder.h
  20. 23
    19
      common/rfb/EncodeManager.cxx
  21. 5
    5
      common/rfb/HextileDecoder.cxx
  22. 2
    2
      common/rfb/HextileDecoder.h
  23. 1
    1
      common/rfb/HextileEncoder.cxx
  24. 1
    1
      common/rfb/JpegCompressor.cxx
  25. 10
    1
      common/rfb/Logger.cxx
  26. 5
    5
      common/rfb/RREDecoder.cxx
  27. 2
    2
      common/rfb/RREDecoder.h
  28. 1
    1
      common/rfb/RREEncoder.cxx
  29. 6
    6
      common/rfb/RawDecoder.cxx
  30. 2
    2
      common/rfb/RawDecoder.h
  31. 44
    26
      common/rfb/SConnection.cxx
  32. 11
    19
      common/rfb/SMsgHandler.cxx
  33. 4
    4
      common/rfb/SMsgHandler.h
  34. 105
    170
      common/rfb/SMsgWriter.cxx
  35. 13
    26
      common/rfb/SMsgWriter.h
  36. 84
    0
      common/rfb/ServerParams.cxx
  37. 89
    0
      common/rfb/ServerParams.h
  38. 12
    12
      common/rfb/TightDecoder.cxx
  39. 3
    3
      common/rfb/TightDecoder.h
  40. 1
    2
      common/rfb/TightEncoder.cxx
  41. 4
    4
      common/rfb/TightJPEGEncoder.cxx
  42. 1
    16
      common/rfb/UpdateTracker.cxx
  43. 1
    4
      common/rfb/UpdateTracker.h
  44. 53
    61
      common/rfb/VNCSConnectionST.cxx
  45. 9
    6
      common/rfb/VNCServerST.cxx
  46. 4
    4
      common/rfb/ZRLEDecoder.cxx
  47. 2
    2
      common/rfb/ZRLEDecoder.h
  48. 1
    2
      common/rfb/ZRLEEncoder.cxx
  49. 5
    5
      tests/decperf.cxx
  50. 6
    8
      tests/encperf.cxx
  51. 19
    0
      unix/x0vncserver/XDesktop.cxx
  52. 53
    212
      vncviewer/CConn.cxx
  53. 3
    20
      vncviewer/CConn.h
  54. 14
    14
      vncviewer/DesktopWindow.cxx
  55. 5
    5
      vncviewer/Viewport.cxx

+ 286
- 21
common/rfb/CConnection.cxx View File

@@ -16,6 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>

@@ -24,6 +25,7 @@
#include <rfb/CMsgReader.h>
#include <rfb/CMsgWriter.h>
#include <rfb/CSecurity.h>
#include <rfb/Decoder.h>
#include <rfb/Security.h>
#include <rfb/SecurityClient.h>
#include <rfb/CConnection.h>
@@ -39,9 +41,17 @@ using namespace rfb;
static LogWriter vlog("CConnection");

CConnection::CConnection()
: csecurity(0), is(0), os(0), reader_(0), writer_(0),
: csecurity(0),
supportsLocalCursor(false), supportsDesktopResize(false),
supportsLEDState(false),
is(0), os(0), reader_(0), writer_(0),
shared(false),
state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false),
pendingPFChange(false), preferredEncoding(encodingTight),
compressLevel(2), qualityLevel(-1),
formatChange(false), encodingChange(false),
firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
forceNonincremental(true),
framebuffer(NULL), decoder(this)
{
}
@@ -67,6 +77,11 @@ void CConnection::setFramebuffer(ModifiablePixelBuffer* fb)
{
decoder.flush();

if (fb) {
assert(fb->width() == server.width());
assert(fb->height() == server.height());
}

if ((framebuffer != NULL) && (fb != NULL)) {
Rect rect;

@@ -128,35 +143,51 @@ void CConnection::processMsg()

void CConnection::processVersionMsg()
{
char verStr[13];
int majorVersion;
int minorVersion;

vlog.debug("reading protocol version");
bool done;
if (!cp.readVersion(is, &done)) {

if (!is->checkNoWait(12))
return;

is->readBytes(verStr, 12);
verStr[12] = '\0';

if (sscanf(verStr, "RFB %03d.%03d\n",
&majorVersion, &minorVersion) != 2) {
state_ = RFBSTATE_INVALID;
throw Exception("reading version failed: not an RFB server?");
}
if (!done) return;

server.setVersion(majorVersion, minorVersion);

vlog.info("Server supports RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
server.majorVersion, server.minorVersion);

// The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
if (cp.beforeVersion(3,3)) {
if (server.beforeVersion(3,3)) {
vlog.error("Server gave unsupported RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
server.majorVersion, server.minorVersion);
state_ = RFBSTATE_INVALID;
throw Exception("Server gave unsupported RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
} else if (useProtocol3_3 || cp.beforeVersion(3,7)) {
cp.setVersion(3,3);
} else if (cp.afterVersion(3,8)) {
cp.setVersion(3,8);
server.majorVersion, server.minorVersion);
} else if (useProtocol3_3 || server.beforeVersion(3,7)) {
server.setVersion(3,3);
} else if (server.afterVersion(3,8)) {
server.setVersion(3,8);
}

cp.writeVersion(os);
sprintf(verStr, "RFB %03d.%03d\n",
server.majorVersion, server.minorVersion);
os->writeBytes(verStr, 12);
os->flush();

state_ = RFBSTATE_SECURITY_TYPES;

vlog.info("Using RFB protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
server.majorVersion, server.minorVersion);
}


@@ -169,7 +200,7 @@ void CConnection::processSecurityTypesMsg()
std::list<rdr::U8> secTypes;
secTypes = security.GetEnabledSecTypes();

if (cp.isVersion(3,3)) {
if (server.isVersion(3,3)) {

// legacy 3.3 server may only offer "vnc authentication" or "none"

@@ -252,7 +283,7 @@ void CConnection::processSecurityResultMsg()
{
vlog.debug("processing security result message");
int result;
if (cp.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
if (server.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
result = secResultOK;
} else {
if (!is->checkNoWait(1)) return;
@@ -272,7 +303,7 @@ void CConnection::processSecurityResultMsg()
throw Exception("Unknown security result from server");
}
state_ = RFBSTATE_INVALID;
if (cp.beforeVersion(3,8))
if (server.beforeVersion(3,8))
throw AuthFailureException();
CharArray reason(is->readString());
throw AuthFailureException(reason.buf);
@@ -296,7 +327,7 @@ void CConnection::securityCompleted()
{
state_ = RFBSTATE_INITIALISATION;
reader_ = new CMsgReader(this, is);
writer_ = new CMsgWriter(&cp, os);
writer_ = new CMsgWriter(&server, os);
vlog.debug("Authentication success!");
authSuccess();
writer_->writeClientInit(shared);
@@ -307,6 +338,16 @@ void CConnection::setDesktopSize(int w, int h)
decoder.flush();

CMsgHandler::setDesktopSize(w,h);

if (continuousUpdates)
writer()->writeEnableContinuousUpdates(true, 0, 0,
server.width(),
server.height());

resizeFramebuffer();
assert(framebuffer != NULL);
assert(framebuffer->width() == server.width());
assert(framebuffer->height() == server.height());
}

void CConnection::setExtendedDesktopSize(unsigned reason,
@@ -317,6 +358,59 @@ void CConnection::setExtendedDesktopSize(unsigned reason,
decoder.flush();

CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout);

if (continuousUpdates)
writer()->writeEnableContinuousUpdates(true, 0, 0,
server.width(),
server.height());

resizeFramebuffer();
assert(framebuffer != NULL);
assert(framebuffer->width() == server.width());
assert(framebuffer->height() == server.height());
}

void CConnection::endOfContinuousUpdates()
{
CMsgHandler::endOfContinuousUpdates();

// We've gotten the marker for a format change, so make the pending
// one active
if (pendingPFChange) {
server.setPF(pendingPF);
pendingPFChange = false;

// We might have another change pending
if (formatChange)
requestNewUpdate();
}
}

void CConnection::serverInit(int width, int height,
const PixelFormat& pf,
const char* name)
{
CMsgHandler::serverInit(width, height, pf, name);

state_ = RFBSTATE_NORMAL;
vlog.debug("initialisation done");

initDone();
assert(framebuffer != NULL);
assert(framebuffer->width() == server.width());
assert(framebuffer->height() == server.height());

// We want to make sure we call SetEncodings at least once
encodingChange = true;

requestNewUpdate();

// This initial update request is a bit of a corner case, so we need
// to help out setting the correct format here.
if (pendingPFChange) {
server.setPF(pendingPF);
pendingPFChange = false;
}
}

void CConnection::readAndDecodeRect(const Rect& r, int encoding,
@@ -329,6 +423,13 @@ void CConnection::readAndDecodeRect(const Rect& r, int encoding,
void CConnection::framebufferUpdateStart()
{
CMsgHandler::framebufferUpdateStart();

assert(framebuffer != NULL);

// Note: This might not be true if continuous updates are supported
pendingUpdate = false;

requestNewUpdate();
}

void CConnection::framebufferUpdateEnd()
@@ -336,6 +437,25 @@ void CConnection::framebufferUpdateEnd()
decoder.flush();

CMsgHandler::framebufferUpdateEnd();

// A format change has been scheduled and we are now past the update
// with the old format. Time to active the new one.
if (pendingPFChange && !continuousUpdates) {
server.setPF(pendingPF);
pendingPFChange = false;
}

if (firstUpdate) {
if (server.supportsContinuousUpdates) {
vlog.info("Enabling continuous updates");
continuousUpdates = true;
writer()->writeEnableContinuousUpdates(true, 0, 0,
server.width(),
server.height());
}

firstUpdate = false;
}
}

void CConnection::dataRect(const Rect& r, int encoding)
@@ -347,10 +467,64 @@ void CConnection::authSuccess()
{
}

void CConnection::serverInit()
void CConnection::initDone()
{
state_ = RFBSTATE_NORMAL;
vlog.debug("initialisation done");
}

void CConnection::resizeFramebuffer()
{
assert(false);
}

void CConnection::refreshFramebuffer()
{
forceNonincremental = true;

// Without continuous updates we have to make sure we only have a
// single update in flight, so we'll have to wait to do the refresh
if (continuousUpdates)
requestNewUpdate();
}

void CConnection::setPreferredEncoding(int encoding)
{
if (preferredEncoding == encoding)
return;

preferredEncoding = encoding;
encodingChange = true;
}

int CConnection::getPreferredEncoding()
{
return preferredEncoding;
}

void CConnection::setCompressLevel(int level)
{
if (compressLevel == level)
return;

compressLevel = level;
encodingChange = true;
}

void CConnection::setQualityLevel(int level)
{
if (qualityLevel == level)
return;

qualityLevel = level;
encodingChange = true;
}

void CConnection::setPF(const PixelFormat& pf)
{
if (server.pf().equal(pf) && !formatChange)
return;

nextPF = pf;
formatChange = true;
}

void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
@@ -365,3 +539,94 @@ void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])

writer()->writeFence(flags, len, data);
}

// requestNewUpdate() requests an update from the server, having set the
// format and encoding appropriately.
void CConnection::requestNewUpdate()
{
if (formatChange && !pendingPFChange) {
/* Catch incorrect requestNewUpdate calls */
assert(!pendingUpdate || continuousUpdates);

// We have to make sure we switch the internal format at a safe
// time. For continuous updates we temporarily disable updates and
// look for a EndOfContinuousUpdates message to see when to switch.
// For classical updates we just got a new update right before this
// function was called, so we need to make sure we finish that
// update before we can switch.

pendingPFChange = true;
pendingPF = nextPF;

if (continuousUpdates)
writer()->writeEnableContinuousUpdates(false, 0, 0, 0, 0);

writer()->writeSetPixelFormat(pendingPF);

if (continuousUpdates)
writer()->writeEnableContinuousUpdates(true, 0, 0,
server.width(),
server.height());

formatChange = false;
}

if (encodingChange) {
updateEncodings();
encodingChange = false;
}

if (forceNonincremental || !continuousUpdates) {
pendingUpdate = true;
writer()->writeFramebufferUpdateRequest(Rect(0, 0,
server.width(),
server.height()),
!forceNonincremental);
}

forceNonincremental = false;
}

// Ask for encodings based on which decoders are supported. Assumes higher
// encoding numbers are more desirable.

void CConnection::updateEncodings()
{
std::list<rdr::U32> encodings;

if (supportsLocalCursor) {
encodings.push_back(pseudoEncodingCursorWithAlpha);
encodings.push_back(pseudoEncodingCursor);
encodings.push_back(pseudoEncodingXCursor);
}
if (supportsDesktopResize) {
encodings.push_back(pseudoEncodingDesktopSize);
encodings.push_back(pseudoEncodingExtendedDesktopSize);
}
if (supportsLEDState)
encodings.push_back(pseudoEncodingLEDState);

encodings.push_back(pseudoEncodingDesktopName);
encodings.push_back(pseudoEncodingLastRect);
encodings.push_back(pseudoEncodingContinuousUpdates);
encodings.push_back(pseudoEncodingFence);
encodings.push_back(pseudoEncodingQEMUKeyEvent);

if (Decoder::supported(preferredEncoding)) {
encodings.push_back(preferredEncoding);
}

encodings.push_back(encodingCopyRect);

for (int i = encodingMax; i >= 0; i--) {
if ((i != preferredEncoding) && Decoder::supported(i))
encodings.push_back(i);
}

if (compressLevel >= 0 && compressLevel <= 9)
encodings.push_back(pseudoEncodingCompressLevel0 + compressLevel);
if (qualityLevel >= 0 && qualityLevel <= 9)
encodings.push_back(pseudoEncodingQualityLevel0 + qualityLevel);

writer()->writeSetEncodings(encodings);
}

+ 63
- 7
common/rfb/CConnection.h View File

@@ -100,6 +100,12 @@ namespace rfb {
int w, int h,
const ScreenSet& layout);

virtual void endOfContinuousUpdates();

virtual void serverInit(int width, int height,
const PixelFormat& pf,
const char* name);

virtual void readAndDecodeRect(const Rect& r, int encoding,
ModifiablePixelBuffer* pb);

@@ -110,20 +116,43 @@ namespace rfb {

// Methods to be overridden in a derived class

// getIdVerifier() returns the identity verifier associated with the connection.
// Ownership of the IdentityVerifier is retained by the CConnection instance.
virtual IdentityVerifier* getIdentityVerifier() {return 0;}

// authSuccess() is called when authentication has succeeded.
virtual void authSuccess();

// serverInit() is called when the ServerInit message is received. The
// derived class must call on to CConnection::serverInit().
virtual void serverInit();
// initDone() is called when the connection is fully established
// and standard messages can be sent. This is called before the
// initial FramebufferUpdateRequest giving a derived class the
// chance to modify pixel format and settings. The derived class
// must also make sure it has provided a valid framebuffer before
// returning.
virtual void initDone() = 0;

// resizeFramebuffer() is called whenever the framebuffer
// dimensions or the screen layout changes. A subclass must make
// sure the pixel buffer has been updated once this call returns.
virtual void resizeFramebuffer();


// Other methods

// refreshFramebuffer() forces a complete refresh of the entire
// framebuffer
void refreshFramebuffer();

// setPreferredEncoding()/getPreferredEncoding() adjusts which
// encoding is listed first as a hint to the server that it is the
// preferred one
void setPreferredEncoding(int encoding);
int getPreferredEncoding();
// setCompressLevel()/setQualityLevel() controls the encoding hints
// sent to the server
void setCompressLevel(int level);
void setQualityLevel(int level);
// setPF() controls the pixel format requested from the server.
// server.pf() will automatically be adjusted once the new format
// is active.
void setPF(const PixelFormat& pf);

CMsgReader* reader() { return reader_; }
CMsgWriter* writer() { return writer_; }

@@ -159,6 +188,13 @@ namespace rfb {

ModifiablePixelBuffer* getFramebuffer() { return framebuffer; }

protected:
// Optional capabilities that a subclass is expected to set to true
// if supported
bool supportsLocalCursor;
bool supportsDesktopResize;
bool supportsLEDState;

private:
// This is a default implementation of fences that automatically
// responds to requests, stating no support for synchronisation.
@@ -176,6 +212,9 @@ namespace rfb {
void throwConnFailedException();
void securityCompleted();

void requestNewUpdate();
void updateEncodings();

rdr::InStream* is;
rdr::OutStream* os;
CMsgReader* reader_;
@@ -188,6 +227,23 @@ namespace rfb {

bool useProtocol3_3;

bool pendingPFChange;
rfb::PixelFormat pendingPF;

int preferredEncoding;
int compressLevel;
int qualityLevel;

bool formatChange;
rfb::PixelFormat nextPF;
bool encodingChange;

bool firstUpdate;
bool pendingUpdate;
bool continuousUpdates;

bool forceNonincremental;

ModifiablePixelBuffer* framebuffer;
DecodeManager decoder;
};

+ 2
- 1
common/rfb/CMakeLists.txt View File

@@ -11,9 +11,9 @@ set(RFB_SOURCES
CSecurityStack.cxx
CSecurityVeNCrypt.cxx
CSecurityVncAuth.cxx
ClientParams.cxx
ComparingUpdateTracker.cxx
Configuration.cxx
ConnParams.cxx
CopyRectDecoder.cxx
Cursor.cxx
DecodeManager.cxx
@@ -43,6 +43,7 @@ set(RFB_SOURCES
SMsgReader.cxx
SMsgWriter.cxx
ServerCore.cxx
ServerParams.cxx
Security.cxx
SecurityServer.cxx
SecurityClient.cxx

+ 18
- 15
common/rfb/CMsgHandler.cxx View File

@@ -34,50 +34,53 @@ CMsgHandler::~CMsgHandler()

void CMsgHandler::setDesktopSize(int width, int height)
{
cp.width = width;
cp.height = height;
server.setDimensions(width, height);
}

void CMsgHandler::setExtendedDesktopSize(unsigned reason, unsigned result,
int width, int height,
const ScreenSet& layout)
{
cp.supportsSetDesktopSize = true;
server.supportsSetDesktopSize = true;

if ((reason == reasonClient) && (result != resultSuccess))
return;

if (!layout.validate(width, height))
fprintf(stderr, "Server sent us an invalid screen layout\n");

cp.width = width;
cp.height = height;
cp.screenLayout = layout;
server.setDimensions(width, height, layout);
}

void CMsgHandler::setPixelFormat(const PixelFormat& pf)
{
cp.setPF(pf);
server.setPF(pf);
}

void CMsgHandler::setName(const char* name)
{
cp.setName(name);
server.setName(name);
}

void CMsgHandler::fence(rdr::U32 flags, unsigned len, const char data[])
{
cp.supportsFence = true;
server.supportsFence = true;
}

void CMsgHandler::endOfContinuousUpdates()
{
cp.supportsContinuousUpdates = true;
server.supportsContinuousUpdates = true;
}

void CMsgHandler::supportsQEMUKeyEvent()
{
cp.supportsQEMUKeyEvent = true;
server.supportsQEMUKeyEvent = true;
}

void CMsgHandler::serverInit(int width, int height,
const PixelFormat& pf,
const char* name)
{
server.setDimensions(width, height);
server.setPF(pf);
server.setName(name);
}

void CMsgHandler::framebufferUpdateStart()
@@ -90,5 +93,5 @@ void CMsgHandler::framebufferUpdateEnd()

void CMsgHandler::setLEDState(unsigned int state)
{
cp.setLEDState(state);
server.setLEDState(state);
}

+ 8
- 6
common/rfb/CMsgHandler.h View File

@@ -26,7 +26,7 @@

#include <rdr/types.h>
#include <rfb/Pixel.h>
#include <rfb/ConnParams.h>
#include <rfb/ServerParams.h>
#include <rfb/Rect.h>
#include <rfb/ScreenSet.h>

@@ -41,9 +41,9 @@ namespace rfb {

// The following methods are called as corresponding messages are read. A
// derived class should override these methods as desired. Note that for
// the setDesktopSize(), setExtendedDesktopSize(), setPixelFormat() and
// setName() methods, a derived class should call on to CMsgHandler's
// methods to set the members of cp appropriately.
// the setDesktopSize(), setExtendedDesktopSize(), setPixelFormat(),
// setName() and serverInit() methods, a derived class should call on to
// CMsgHandler's methods to set the members of "server" appropriately.

virtual void setDesktopSize(int w, int h);
virtual void setExtendedDesktopSize(unsigned reason, unsigned result,
@@ -56,7 +56,9 @@ namespace rfb {
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
virtual void endOfContinuousUpdates();
virtual void supportsQEMUKeyEvent();
virtual void serverInit() = 0;
virtual void serverInit(int width, int height,
const PixelFormat& pf,
const char* name) = 0;

virtual void readAndDecodeRect(const Rect& r, int encoding,
ModifiablePixelBuffer* pb) = 0;
@@ -72,7 +74,7 @@ namespace rfb {

virtual void setLEDState(unsigned int state);

ConnParams cp;
ServerParams server;
};
}
#endif

+ 10
- 12
common/rfb/CMsgReader.cxx View File

@@ -43,13 +43,10 @@ void CMsgReader::readServerInit()
{
int width = is->readU16();
int height = is->readU16();
handler->setDesktopSize(width, height);
PixelFormat pf;
pf.read(is);
handler->setPixelFormat(pf);
CharArray name(is->readString());
handler->setName(name.buf);
handler->serverInit();
handler->serverInit(width, height, pf, name.buf);
}

void CMsgReader::readMsg()
@@ -192,10 +189,11 @@ void CMsgReader::readFramebufferUpdate()

void CMsgReader::readRect(const Rect& r, int encoding)
{
if ((r.br.x > handler->cp.width) || (r.br.y > handler->cp.height)) {
if ((r.br.x > handler->server.width()) ||
(r.br.y > handler->server.height())) {
fprintf(stderr, "Rect too big: %dx%d at %d,%d exceeds %dx%d\n",
r.width(), r.height(), r.tl.x, r.tl.y,
handler->cp.width, handler->cp.height);
handler->server.width(), handler->server.height());
throw Exception("Rect too big");
}

@@ -269,7 +267,7 @@ void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
if (width > maxCursorSize || height > maxCursorSize)
throw Exception("Too big cursor");

int data_len = width * height * (handler->cp.pf().bpp/8);
int data_len = width * height * (handler->server.pf().bpp/8);
int mask_len = ((width+7)/8) * height;
rdr::U8Array data(data_len);
rdr::U8Array mask(mask_len);
@@ -290,14 +288,14 @@ void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
int byte = y * maskBytesPerRow + x / 8;
int bit = 7 - x % 8;

handler->cp.pf().rgbFromBuffer(out, in, 1);
handler->server.pf().rgbFromBuffer(out, in, 1);

if (mask.buf[byte] & (1 << bit))
out[3] = 255;
else
out[3] = 0;

in += handler->cp.pf().bpp/8;
in += handler->server.pf().bpp/8;
out += 4;
}
}
@@ -321,10 +319,10 @@ void CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hots

encoding = is->readS32();

origPF = handler->cp.pf();
handler->cp.setPF(rgbaPF);
origPF = handler->server.pf();
handler->server.setPF(rgbaPF);
handler->readAndDecodeRect(pb.getRect(), encoding, &pb);
handler->cp.setPF(origPF);
handler->server.setPF(origPF);

// On-wire data has pre-multiplied alpha, but we store it
// non-pre-multiplied

+ 14
- 91
common/rfb/CMsgWriter.cxx View File

@@ -20,19 +20,17 @@
#include <rdr/OutStream.h>
#include <rfb/msgTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/encodings.h>
#include <rfb/qemuTypes.h>
#include <rfb/Exception.h>
#include <rfb/PixelFormat.h>
#include <rfb/Rect.h>
#include <rfb/ConnParams.h>
#include <rfb/Decoder.h>
#include <rfb/ServerParams.h>
#include <rfb/CMsgWriter.h>

using namespace rfb;

CMsgWriter::CMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
: cp(cp_), os(os_)
CMsgWriter::CMsgWriter(ServerParams* server_, rdr::OutStream* os_)
: server(server_), os(os_)
{
}

@@ -54,96 +52,21 @@ void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf)
endMsg();
}

void CMsgWriter::writeSetEncodings(int nEncodings, rdr::U32* encodings)
void CMsgWriter::writeSetEncodings(const std::list<rdr::U32> encodings)
{
std::list<rdr::U32>::const_iterator iter;
startMsg(msgTypeSetEncodings);
os->skip(1);
os->writeU16(nEncodings);
for (int i = 0; i < nEncodings; i++)
os->writeU32(encodings[i]);
os->writeU16(encodings.size());
for (iter = encodings.begin(); iter != encodings.end(); ++iter)
os->writeU32(*iter);
endMsg();
}

// Ask for encodings based on which decoders are supported. Assumes higher
// encoding numbers are more desirable.

void CMsgWriter::writeSetEncodings(int preferredEncoding, bool useCopyRect)
{
int nEncodings = 0;
rdr::U32 encodings[encodingMax+3];

if (cp->supportsLocalCursor) {
encodings[nEncodings++] = pseudoEncodingCursorWithAlpha;
encodings[nEncodings++] = pseudoEncodingCursor;
encodings[nEncodings++] = pseudoEncodingXCursor;
}
if (cp->supportsDesktopResize)
encodings[nEncodings++] = pseudoEncodingDesktopSize;
if (cp->supportsExtendedDesktopSize)
encodings[nEncodings++] = pseudoEncodingExtendedDesktopSize;
if (cp->supportsDesktopRename)
encodings[nEncodings++] = pseudoEncodingDesktopName;
if (cp->supportsLEDState)
encodings[nEncodings++] = pseudoEncodingLEDState;

encodings[nEncodings++] = pseudoEncodingLastRect;
encodings[nEncodings++] = pseudoEncodingContinuousUpdates;
encodings[nEncodings++] = pseudoEncodingFence;
encodings[nEncodings++] = pseudoEncodingQEMUKeyEvent;

if (Decoder::supported(preferredEncoding)) {
encodings[nEncodings++] = preferredEncoding;
}

if (useCopyRect) {
encodings[nEncodings++] = encodingCopyRect;
}

/*
* Prefer encodings in this order:
*
* Tight, ZRLE, Hextile, *
*/

if ((preferredEncoding != encodingTight) &&
Decoder::supported(encodingTight))
encodings[nEncodings++] = encodingTight;

if ((preferredEncoding != encodingZRLE) &&
Decoder::supported(encodingZRLE))
encodings[nEncodings++] = encodingZRLE;

if ((preferredEncoding != encodingHextile) &&
Decoder::supported(encodingHextile))
encodings[nEncodings++] = encodingHextile;

// Remaining encodings
for (int i = encodingMax; i >= 0; i--) {
switch (i) {
case encodingCopyRect:
case encodingTight:
case encodingZRLE:
case encodingHextile:
/* These have already been sent earlier */
break;
default:
if ((i != preferredEncoding) && Decoder::supported(i))
encodings[nEncodings++] = i;
}
}

if (cp->compressLevel >= 0 && cp->compressLevel <= 9)
encodings[nEncodings++] = pseudoEncodingCompressLevel0 + cp->compressLevel;
if (cp->qualityLevel >= 0 && cp->qualityLevel <= 9)
encodings[nEncodings++] = pseudoEncodingQualityLevel0 + cp->qualityLevel;

writeSetEncodings(nEncodings, encodings);
}

void CMsgWriter::writeSetDesktopSize(int width, int height,
const ScreenSet& layout)
{
if (!cp->supportsSetDesktopSize)
if (!server->supportsSetDesktopSize)
throw Exception("Server does not support SetDesktopSize");

startMsg(msgTypeSetDesktopSize);
@@ -182,7 +105,7 @@ void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
void CMsgWriter::writeEnableContinuousUpdates(bool enable,
int x, int y, int w, int h)
{
if (!cp->supportsContinuousUpdates)
if (!server->supportsContinuousUpdates)
throw Exception("Server does not support continuous updates");

startMsg(msgTypeEnableContinuousUpdates);
@@ -199,7 +122,7 @@ void CMsgWriter::writeEnableContinuousUpdates(bool enable,

void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
{
if (!cp->supportsFence)
if (!server->supportsFence)
throw Exception("Server does not support fences");
if (len > 64)
throw Exception("Too large fence payload");
@@ -219,7 +142,7 @@ void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])

void CMsgWriter::writeKeyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
{
if (!cp->supportsQEMUKeyEvent || !keycode) {
if (!server->supportsQEMUKeyEvent || !keycode) {
/* This event isn't meaningful without a valid keysym */
if (!keysym)
return;
@@ -245,8 +168,8 @@ void CMsgWriter::writePointerEvent(const Point& pos, int buttonMask)
Point p(pos);
if (p.x < 0) p.x = 0;
if (p.y < 0) p.y = 0;
if (p.x >= cp->width) p.x = cp->width - 1;
if (p.y >= cp->height) p.y = cp->height - 1;
if (p.x >= server->width()) p.x = server->width() - 1;
if (p.y >= server->height()) p.y = server->height() - 1;

startMsg(msgTypePointerEvent);
os->writeU8(buttonMask);

+ 6
- 5
common/rfb/CMsgWriter.h View File

@@ -23,6 +23,8 @@
#ifndef __RFB_CMSGWRITER_H__
#define __RFB_CMSGWRITER_H__

#include <list>

#include <rdr/types.h>

namespace rdr { class OutStream; }
@@ -30,21 +32,20 @@ namespace rdr { class OutStream; }
namespace rfb {

class PixelFormat;
class ConnParams;
class ServerParams;
struct ScreenSet;
struct Point;
struct Rect;

class CMsgWriter {
public:
CMsgWriter(ConnParams* cp, rdr::OutStream* os);
CMsgWriter(ServerParams* server, rdr::OutStream* os);
virtual ~CMsgWriter();

void writeClientInit(bool shared);

void writeSetPixelFormat(const PixelFormat& pf);
void writeSetEncodings(int nEncodings, rdr::U32* encodings);
void writeSetEncodings(int preferredEncoding, bool useCopyRect);
void writeSetEncodings(const std::list<rdr::U32> encodings);
void writeSetDesktopSize(int width, int height, const ScreenSet& layout);

void writeFramebufferUpdateRequest(const Rect& r,bool incremental);
@@ -60,7 +61,7 @@ namespace rfb {
void startMsg(int type);
void endMsg();

ConnParams* cp;
ServerParams* server;
rdr::OutStream* os;
};
}

+ 0
- 1
common/rfb/CSecurityTLS.cxx View File

@@ -34,7 +34,6 @@
#endif

#include <rfb/CSecurityTLS.h>
#include <rfb/SSecurityVeNCrypt.h>
#include <rfb/CConnection.h>
#include <rfb/LogWriter.h>
#include <rfb/Exception.h>

+ 0
- 1
common/rfb/CSecurityTLS.h View File

@@ -31,7 +31,6 @@
#endif

#include <rfb/CSecurity.h>
#include <rfb/SSecurityVeNCrypt.h>
#include <rfb/Security.h>
#include <rfb/UserMsgBox.h>
#include <rdr/InStream.h>

+ 178
- 0
common/rfb/ClientParams.cxx View File

@@ -0,0 +1,178 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
* Copyright 2014-2018 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.
*/
#include <rfb/Exception.h>
#include <rfb/encodings.h>
#include <rfb/ledStates.h>
#include <rfb/ClientParams.h>

using namespace rfb;

ClientParams::ClientParams()
: majorVersion(0), minorVersion(0),
compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
subsampling(subsampleUndefined),
width_(0), height_(0), name_(0),
ledState_(ledUnknown)
{
setName("");
cursor_ = new Cursor(0, 0, Point(), NULL);
}

ClientParams::~ClientParams()
{
delete [] name_;
delete cursor_;
}

void ClientParams::setDimensions(int width, int height)
{
ScreenSet layout;
layout.add_screen(rfb::Screen(0, 0, 0, width, height, 0));
setDimensions(width, height, layout);
}

void ClientParams::setDimensions(int width, int height, const ScreenSet& layout)
{
if (!layout.validate(width, height))
throw Exception("Attempted to configure an invalid screen layout");

width_ = width;
height_ = height;
screenLayout_ = layout;
}

void ClientParams::setPF(const PixelFormat& pf)
{
pf_ = pf;

if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32)
throw Exception("setPF: not 8, 16 or 32 bpp?");
}

void ClientParams::setName(const char* name)
{
delete [] name_;
name_ = strDup(name);
}

void ClientParams::setCursor(const Cursor& other)
{
delete cursor_;
cursor_ = new Cursor(other);
}

bool ClientParams::supportsEncoding(rdr::S32 encoding) const
{
return encodings_.count(encoding) != 0;
}

void ClientParams::setEncodings(int nEncodings, const rdr::S32* encodings)
{
compressLevel = -1;
qualityLevel = -1;
fineQualityLevel = -1;
subsampling = subsampleUndefined;

encodings_.clear();
encodings_.insert(encodingRaw);

for (int i = nEncodings-1; i >= 0; i--) {
switch (encodings[i]) {
case pseudoEncodingSubsamp1X:
subsampling = subsampleNone;
break;
case pseudoEncodingSubsampGray:
subsampling = subsampleGray;
break;
case pseudoEncodingSubsamp2X:
subsampling = subsample2X;
break;
case pseudoEncodingSubsamp4X:
subsampling = subsample4X;
break;
case pseudoEncodingSubsamp8X:
subsampling = subsample8X;
break;
case pseudoEncodingSubsamp16X:
subsampling = subsample16X;
break;
}

if (encodings[i] >= pseudoEncodingCompressLevel0 &&
encodings[i] <= pseudoEncodingCompressLevel9)
compressLevel = encodings[i] - pseudoEncodingCompressLevel0;

if (encodings[i] >= pseudoEncodingQualityLevel0 &&
encodings[i] <= pseudoEncodingQualityLevel9)
qualityLevel = encodings[i] - pseudoEncodingQualityLevel0;

if (encodings[i] >= pseudoEncodingFineQualityLevel0 &&
encodings[i] <= pseudoEncodingFineQualityLevel100)
fineQualityLevel = encodings[i] - pseudoEncodingFineQualityLevel0;

encodings_.insert(encodings[i]);
}
}

void ClientParams::setLEDState(unsigned int state)
{
ledState_ = state;
}

bool ClientParams::supportsLocalCursor() const
{
if (supportsEncoding(pseudoEncodingCursorWithAlpha))
return true;
if (supportsEncoding(pseudoEncodingCursor))
return true;
if (supportsEncoding(pseudoEncodingXCursor))
return true;
return false;
}

bool ClientParams::supportsDesktopSize() const
{
if (supportsEncoding(pseudoEncodingExtendedDesktopSize))
return true;
if (supportsEncoding(pseudoEncodingDesktopSize))
return true;
return false;
}

bool ClientParams::supportsLEDState() const
{
if (supportsEncoding(pseudoEncodingLEDState))
return true;
return false;
}

bool ClientParams::supportsFence() const
{
if (supportsEncoding(pseudoEncodingFence))
return true;
return false;
}

bool ClientParams::supportsContinuousUpdates() const
{
if (supportsEncoding(pseudoEncodingContinuousUpdates))
return true;
return false;
}

common/rfb/ConnParams.h → common/rfb/ClientParams.h View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2014 Pierre Ossman for Cendio AB
* Copyright 2014-2018 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
@@ -17,11 +17,11 @@
* USA.
*/
//
// ConnParams - structure containing the connection parameters.
// ClientParams - structure describing the current state of the remote client
//

#ifndef __RFB_CONNPARAMS_H__
#define __RFB_CONNPARAMS_H__
#ifndef __RFB_CLIENTPARAMS_H__
#define __RFB_CLIENTPARAMS_H__

#include <set>

@@ -30,8 +30,6 @@
#include <rfb/PixelFormat.h>
#include <rfb/ScreenSet.h>

namespace rdr { class InStream; }

namespace rfb {

const int subsampleUndefined = -1;
@@ -42,13 +40,10 @@ namespace rfb {
const int subsample8X = 4;
const int subsample16X = 5;

class ConnParams {
class ClientParams {
public:
ConnParams();
~ConnParams();

bool readVersion(rdr::InStream* is, bool* done);
void writeVersion(rdr::OutStream* os);
ClientParams();
~ClientParams();

int majorVersion;
int minorVersion;
@@ -67,9 +62,11 @@ namespace rfb {
return !beforeVersion(major,minor+1);
}

int width;
int height;
ScreenSet screenLayout;
const int width() const { return width_; }
const int height() const { return height_; }
const ScreenSet& screenLayout() const { return screenLayout_; }
void setDimensions(int width, int height);
void setDimensions(int width, int height, const ScreenSet& layout);

const PixelFormat& pf() const { return pf_; }
void setPF(const PixelFormat& pf);
@@ -87,21 +84,13 @@ namespace rfb {
unsigned int ledState() { return ledState_; }
void setLEDState(unsigned int state);

bool useCopyRect;

bool supportsLocalCursor;
bool supportsLocalXCursor;
bool supportsLocalCursorWithAlpha;
bool supportsDesktopResize;
bool supportsExtendedDesktopSize;
bool supportsDesktopRename;
bool supportsLastRect;
bool supportsLEDState;
bool supportsQEMUKeyEvent;

bool supportsSetDesktopSize;
bool supportsFence;
bool supportsContinuousUpdates;
// Wrappers to check for functionality rather than specific
// encodings
bool supportsLocalCursor() const;
bool supportsDesktopSize() const;
bool supportsLEDState() const;
bool supportsFence() const;
bool supportsContinuousUpdates() const;

int compressLevel;
int qualityLevel;
@@ -110,12 +99,14 @@ namespace rfb {

private:

int width_;
int height_;
ScreenSet screenLayout_;

PixelFormat pf_;
char* name_;
Cursor* cursor_;
std::set<rdr::S32> encodings_;
char verStr[13];
int verStrPos;
unsigned int ledState_;
};
}

+ 0
- 200
common/rfb/ConnParams.cxx View File

@@ -1,200 +0,0 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
* Copyright 2014 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.
*/
#include <stdio.h>
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
#include <rfb/Exception.h>
#include <rfb/encodings.h>
#include <rfb/ledStates.h>
#include <rfb/ConnParams.h>
#include <rfb/util.h>

using namespace rfb;

ConnParams::ConnParams()
: majorVersion(0), minorVersion(0),
width(0), height(0), useCopyRect(false),
supportsLocalCursor(false), supportsLocalXCursor(false),
supportsLocalCursorWithAlpha(false),
supportsDesktopResize(false), supportsExtendedDesktopSize(false),
supportsDesktopRename(false), supportsLastRect(false),
supportsLEDState(false), supportsQEMUKeyEvent(false),
supportsSetDesktopSize(false), supportsFence(false),
supportsContinuousUpdates(false),
compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
subsampling(subsampleUndefined), name_(0), verStrPos(0),
ledState_(ledUnknown)
{
setName("");
cursor_ = new Cursor(0, 0, Point(), NULL);
}

ConnParams::~ConnParams()
{
delete [] name_;
delete cursor_;
}

bool ConnParams::readVersion(rdr::InStream* is, bool* done)
{
if (verStrPos >= 12) return false;
while (is->checkNoWait(1) && verStrPos < 12) {
verStr[verStrPos++] = is->readU8();
}

if (verStrPos < 12) {
*done = false;
return true;
}
*done = true;
verStr[12] = 0;
return (sscanf(verStr, "RFB %03d.%03d\n", &majorVersion,&minorVersion) == 2);
}

void ConnParams::writeVersion(rdr::OutStream* os)
{
char str[13];
sprintf(str, "RFB %03d.%03d\n", majorVersion, minorVersion);
os->writeBytes(str, 12);
os->flush();
}

void ConnParams::setPF(const PixelFormat& pf)
{
pf_ = pf;

if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32)
throw Exception("setPF: not 8, 16 or 32 bpp?");
}

void ConnParams::setName(const char* name)
{
delete [] name_;
name_ = strDup(name);
}

void ConnParams::setCursor(const Cursor& other)
{
delete cursor_;
cursor_ = new Cursor(other);
}

bool ConnParams::supportsEncoding(rdr::S32 encoding) const
{
return encodings_.count(encoding) != 0;
}

void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings)
{
useCopyRect = false;
supportsLocalCursor = false;
supportsLocalCursorWithAlpha = false;
supportsDesktopResize = false;
supportsExtendedDesktopSize = false;
supportsLocalXCursor = false;
supportsLastRect = false;
supportsQEMUKeyEvent = false;
compressLevel = -1;
qualityLevel = -1;
fineQualityLevel = -1;
subsampling = subsampleUndefined;

encodings_.clear();
encodings_.insert(encodingRaw);

for (int i = nEncodings-1; i >= 0; i--) {
switch (encodings[i]) {
case encodingCopyRect:
useCopyRect = true;
break;
case pseudoEncodingCursor:
supportsLocalCursor = true;
break;
case pseudoEncodingXCursor:
supportsLocalXCursor = true;
break;
case pseudoEncodingCursorWithAlpha:
supportsLocalCursorWithAlpha = true;
break;
case pseudoEncodingDesktopSize:
supportsDesktopResize = true;
break;
case pseudoEncodingExtendedDesktopSize:
supportsExtendedDesktopSize = true;
break;
case pseudoEncodingDesktopName:
supportsDesktopRename = true;
break;
case pseudoEncodingLastRect:
supportsLastRect = true;
break;
case pseudoEncodingLEDState:
supportsLEDState = true;
break;
case pseudoEncodingQEMUKeyEvent:
supportsQEMUKeyEvent = true;
break;
case pseudoEncodingFence:
supportsFence = true;
break;
case pseudoEncodingContinuousUpdates:
supportsContinuousUpdates = true;
break;
case pseudoEncodingSubsamp1X:
subsampling = subsampleNone;
break;
case pseudoEncodingSubsampGray:
subsampling = subsampleGray;
break;
case pseudoEncodingSubsamp2X:
subsampling = subsample2X;
break;
case pseudoEncodingSubsamp4X:
subsampling = subsample4X;
break;
case pseudoEncodingSubsamp8X:
subsampling = subsample8X;
break;
case pseudoEncodingSubsamp16X:
subsampling = subsample16X;
break;
}

if (encodings[i] >= pseudoEncodingCompressLevel0 &&
encodings[i] <= pseudoEncodingCompressLevel9)
compressLevel = encodings[i] - pseudoEncodingCompressLevel0;

if (encodings[i] >= pseudoEncodingQualityLevel0 &&
encodings[i] <= pseudoEncodingQualityLevel9)
qualityLevel = encodings[i] - pseudoEncodingQualityLevel0;

if (encodings[i] >= pseudoEncodingFineQualityLevel0 &&
encodings[i] <= pseudoEncodingFineQualityLevel100)
fineQualityLevel = encodings[i] - pseudoEncodingFineQualityLevel0;

if (encodings[i] > 0)
encodings_.insert(encodings[i]);
}
}

void ConnParams::setLEDState(unsigned int state)
{
ledState_ = state;
}

+ 4
- 4
common/rfb/CopyRectDecoder.cxx View File

@@ -32,7 +32,7 @@ CopyRectDecoder::~CopyRectDecoder()
}

void CopyRectDecoder::readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os)
const ServerParams& server, rdr::OutStream* os)
{
os->copyBytes(is, 4);
}
@@ -41,21 +41,21 @@ void CopyRectDecoder::readRect(const Rect& r, rdr::InStream* is,
void CopyRectDecoder::getAffectedRegion(const Rect& rect,
const void* buffer,
size_t buflen,
const ConnParams& cp,
const ServerParams& server,
Region* region)
{
rdr::MemInStream is(buffer, buflen);
int srcX = is.readU16();
int srcY = is.readU16();

Decoder::getAffectedRegion(rect, buffer, buflen, cp, region);
Decoder::getAffectedRegion(rect, buffer, buflen, server, region);

region->assign_union(Region(rect.translate(Point(srcX-rect.tl.x,
srcY-rect.tl.y))));
}

void CopyRectDecoder::decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)
{
rdr::MemInStream is(buffer, buflen);

+ 3
- 3
common/rfb/CopyRectDecoder.h View File

@@ -27,12 +27,12 @@ namespace rfb {
CopyRectDecoder();
virtual ~CopyRectDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os);
const ServerParams& server, rdr::OutStream* os);
virtual void getAffectedRegion(const Rect& rect, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
Region* region);
virtual void decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb);
};
}

+ 7
- 7
common/rfb/DecodeManager.cxx View File

@@ -132,9 +132,9 @@ void DecodeManager::decodeRect(const Rect& r, int encoding,
if (threads.empty()) {
bufferStream = freeBuffers.front();
bufferStream->clear();
decoder->readRect(r, conn->getInStream(), conn->cp, bufferStream);
decoder->readRect(r, conn->getInStream(), conn->server, bufferStream);
decoder->decodeRect(r, bufferStream->data(), bufferStream->length(),
conn->cp, pb);
conn->server, pb);
return;
}

@@ -155,7 +155,7 @@ void DecodeManager::decodeRect(const Rect& r, int encoding,

// Read the rect
bufferStream->clear();
decoder->readRect(r, conn->getInStream(), conn->cp, bufferStream);
decoder->readRect(r, conn->getInStream(), conn->server, bufferStream);

// Then try to put it on the queue
entry = new QueueEntry;
@@ -164,12 +164,12 @@ void DecodeManager::decodeRect(const Rect& r, int encoding,
entry->rect = r;
entry->encoding = encoding;
entry->decoder = decoder;
entry->cp = &conn->cp;
entry->server = &conn->server;
entry->pb = pb;
entry->bufferStream = bufferStream;

decoder->getAffectedRegion(r, bufferStream->data(),
bufferStream->length(), conn->cp,
bufferStream->length(), conn->server,
&entry->affectedRegion);

queueMutex->lock();
@@ -276,7 +276,7 @@ void DecodeManager::DecodeThread::worker()
try {
entry->decoder->decodeRect(entry->rect, entry->bufferStream->data(),
entry->bufferStream->length(),
*entry->cp, entry->pb);
*entry->server, entry->pb);
} catch (rdr::Exception& e) {
manager->setThreadException(e);
} catch(...) {
@@ -346,7 +346,7 @@ DecodeManager::QueueEntry* DecodeManager::DecodeThread::findEntry()
(*iter2)->rect,
(*iter2)->bufferStream->data(),
(*iter2)->bufferStream->length(),
*entry->cp))
*entry->server))
goto next;
}
}

+ 1
- 1
common/rfb/DecodeManager.h View File

@@ -65,7 +65,7 @@ namespace rfb {
Rect rect;
int encoding;
Decoder* decoder;
const ConnParams* cp;
const ServerParams* server;
ModifiablePixelBuffer* pb;
rdr::MemOutStream* bufferStream;
Region affectedRegion;

+ 2
- 2
common/rfb/Decoder.cxx View File

@@ -38,7 +38,7 @@ Decoder::~Decoder()
}

void Decoder::getAffectedRegion(const Rect& rect, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
Region* region)
{
region->reset(rect);
@@ -47,7 +47,7 @@ void Decoder::getAffectedRegion(const Rect& rect, const void* buffer,
bool Decoder::doRectsConflict(const Rect& rectA, const void* bufferA,
size_t buflenA, const Rect& rectB,
const void* bufferB, size_t buflenB,
const ConnParams& cp)
const ServerParams& server)
{
return false;
}

+ 5
- 5
common/rfb/Decoder.h View File

@@ -25,7 +25,7 @@ namespace rdr {
}

namespace rfb {
class ConnParams;
class ServerParams;
class ModifiablePixelBuffer;
class Region;

@@ -53,7 +53,7 @@ namespace rfb {
// make it easier to decode. This function will always be called in
// a serial manner on the main thread.
virtual void readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os)=0;
const ServerParams& server, rdr::OutStream* os)=0;

// These functions will be called from any of the worker threads.
// A lock will be held whilst these are called so it is safe to
@@ -63,7 +63,7 @@ namespace rfb {
// be either read from or written do when decoding this rect. The
// default implementation simply returns the given rectangle.
virtual void getAffectedRegion(const Rect& rect, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
Region* region);

// doesRectsConflict() determines if two rectangles must be decoded
@@ -75,14 +75,14 @@ namespace rfb {
const Rect& rectB,
const void* bufferB,
size_t buflenB,
const ConnParams& cp);
const ServerParams& server);

// decodeRect() decodes the given rectangle with data from the
// given buffer, onto the ModifiablePixelBuffer. The PixelFormat of
// the PixelBuffer might not match the ConnParams and it is up to
// the decoder to do any necessary conversion.
virtual void decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)=0;

public:

+ 23
- 19
common/rfb/EncodeManager.cxx View File

@@ -325,6 +325,9 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,

changed = changed_;

if (!conn->client.supportsEncoding(encodingCopyRect))
changed.assign_union(copied);

/*
* We need to render the cursor seperately as it has its own
* magical pixel buffer, so split it out from the changed region.
@@ -334,7 +337,7 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
changed.assign_subtract(renderedCursor->getEffectiveRect());
}

if (conn->cp.supportsLastRect)
if (conn->client.supportsEncoding(pseudoEncodingLastRect))
nRects = 0xFFFF;
else {
nRects = copied.numRects();
@@ -344,13 +347,14 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,

conn->writer()->writeFramebufferUpdateStart(nRects);

writeCopyRects(copied, copyDelta);
if (conn->client.supportsEncoding(encodingCopyRect))
writeCopyRects(copied, copyDelta);

/*
* We start by searching for solid rects, which are then removed
* from the changed region.
*/
if (conn->cp.supportsLastRect)
if (conn->client.supportsEncoding(pseudoEncodingLastRect))
writeSolidRects(&changed, pb);

writeRects(changed, pb);
@@ -373,7 +377,7 @@ void EncodeManager::prepareEncoders(bool allowLossy)
solid = bitmap = bitmapRLE = encoderRaw;
indexed = indexedRLE = fullColour = encoderRaw;

allowJPEG = conn->cp.pf().bpp >= 16;
allowJPEG = conn->client.pf().bpp >= 16;
if (!allowLossy) {
if (encoders[encoderTightJPEG]->losslessQuality == -1)
allowJPEG = false;
@@ -447,7 +451,7 @@ void EncodeManager::prepareEncoders(bool allowLossy)
}

// JPEG is the only encoder that can reduce things to grayscale
if ((conn->cp.subsampling == subsampleGray) &&
if ((conn->client.subsampling == subsampleGray) &&
encoders[encoderTightJPEG]->isSupported() && allowLossy) {
solid = bitmap = bitmapRLE = encoderTightJPEG;
indexed = indexedRLE = fullColour = encoderTightJPEG;
@@ -465,14 +469,14 @@ void EncodeManager::prepareEncoders(bool allowLossy)

encoder = encoders[*iter];

encoder->setCompressLevel(conn->cp.compressLevel);
encoder->setCompressLevel(conn->client.compressLevel);

if (allowLossy) {
encoder->setQualityLevel(conn->cp.qualityLevel);
encoder->setFineQualityLevel(conn->cp.fineQualityLevel,
conn->cp.subsampling);
encoder->setQualityLevel(conn->client.qualityLevel);
encoder->setFineQualityLevel(conn->client.fineQualityLevel,
conn->client.subsampling);
} else {
int level = __rfbmax(conn->cp.qualityLevel,
int level = __rfbmax(conn->client.qualityLevel,
encoder->losslessQuality);
encoder->setQualityLevel(level);
encoder->setFineQualityLevel(-1, subsampleUndefined);
@@ -575,7 +579,7 @@ Encoder *EncodeManager::startRect(const Rect& rect, int type)

stats[klass][activeType].rects++;
stats[klass][activeType].pixels += rect.area();
equiv = 12 + rect.area() * (conn->cp.pf().bpp/8);
equiv = 12 + rect.area() * (conn->client.pf().bpp/8);
stats[klass][activeType].equivalent += equiv;

encoder = encoders[klass];
@@ -623,7 +627,7 @@ void EncodeManager::writeCopyRects(const Region& copied, const Point& delta)

copyStats.rects++;
copyStats.pixels += rect->area();
equiv = 12 + rect->area() * (conn->cp.pf().bpp/8);
equiv = 12 + rect->area() * (conn->client.pf().bpp/8);
copyStats.equivalent += equiv;

conn->writer()->writeCopyRect(*rect, rect->tl.x - delta.x,
@@ -710,11 +714,11 @@ void EncodeManager::findSolidRect(const Rect& rect, Region *changed,
rdr::U32 _buffer2;
rdr::U8* converted = (rdr::U8*)&_buffer2;

conn->cp.pf().bufferFromBuffer(converted, pb->getPF(),
conn->client.pf().bufferFromBuffer(converted, pb->getPF(),
colourValue, 1);

encoder->writeSolidRect(erp.width(), erp.height(),
conn->cp.pf(), converted);
conn->client.pf(), converted);
}
endRect();

@@ -808,10 +812,10 @@ void EncodeManager::writeSubRect(const Rect& rect, const PixelBuffer *pb)
// compression setting means spending less effort in building
// a palette. It might be that they figured the increase in
// zlib setting compensated for the loss.
if (conn->cp.compressLevel == -1)
if (conn->client.compressLevel == -1)
divisor = 2 * 8;
else
divisor = conn->cp.compressLevel * 8;
divisor = conn->client.compressLevel * 8;
if (divisor < 4)
divisor = 4;

@@ -819,7 +823,7 @@ void EncodeManager::writeSubRect(const Rect& rect, const PixelBuffer *pb)

// Special exception inherited from the Tight encoder
if (activeEncoders[encoderFullColour] == encoderTightJPEG) {
if ((conn->cp.compressLevel != -1) && (conn->cp.compressLevel < 2))
if ((conn->client.compressLevel != -1) && (conn->client.compressLevel < 2))
maxColours = 24;
else
maxColours = 96;
@@ -992,8 +996,8 @@ PixelBuffer* EncodeManager::preparePixelBuffer(const Rect& rect,
int stride;

// Do wo need to convert the data?
if (convert && !conn->cp.pf().equal(pb->getPF())) {
convertedPixelBuffer.setPF(conn->cp.pf());
if (convert && !conn->client.pf().equal(pb->getPF())) {
convertedPixelBuffer.setPF(conn->client.pf());
convertedPixelBuffer.setSize(rect.width(), rect.height());

buffer = pb->getBuffer(rect, &stride);

+ 5
- 5
common/rfb/HextileDecoder.cxx View File

@@ -20,7 +20,7 @@
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>

#include <rfb/ConnParams.h>
#include <rfb/ServerParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/HextileDecoder.h>

@@ -45,12 +45,12 @@ HextileDecoder::~HextileDecoder()
}

void HextileDecoder::readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os)
const ServerParams& server, rdr::OutStream* os)
{
Rect t;
size_t bytesPerPixel;

bytesPerPixel = cp.pf().bpp/8;
bytesPerPixel = server.pf().bpp/8;

for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {

@@ -91,11 +91,11 @@ void HextileDecoder::readRect(const Rect& r, rdr::InStream* is,
}

void HextileDecoder::decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)
{
rdr::MemInStream is(buffer, buflen);
const PixelFormat& pf = cp.pf();
const PixelFormat& pf = server.pf();
switch (pf.bpp) {
case 8: hextileDecode8 (r, &is, pf, pb); break;
case 16: hextileDecode16(r, &is, pf, pb); break;

+ 2
- 2
common/rfb/HextileDecoder.h View File

@@ -27,9 +27,9 @@ namespace rfb {
HextileDecoder();
virtual ~HextileDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os);
const ServerParams& server, rdr::OutStream* os);
virtual void decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb);
};
}

+ 1
- 1
common/rfb/HextileEncoder.cxx View File

@@ -55,7 +55,7 @@ HextileEncoder::~HextileEncoder()

bool HextileEncoder::isSupported()
{
return conn->cp.supportsEncoding(encodingHextile);
return conn->client.supportsEncoding(encodingHextile);
}

void HextileEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)

+ 1
- 1
common/rfb/JpegCompressor.cxx View File

@@ -22,7 +22,7 @@
#include <rdr/Exception.h>
#include <rfb/Rect.h>
#include <rfb/PixelFormat.h>
#include <rfb/ConnParams.h>
#include <rfb/ClientParams.h>

#include <stdio.h>
extern "C" {

+ 10
- 1
common/rfb/Logger.cxx View File

@@ -47,7 +47,16 @@ void Logger::write(int level, const char *logname, const char* format,
char buf1[4096];
vsnprintf(buf1, sizeof(buf1)-1, format, ap);
buf1[sizeof(buf1)-1] = 0;
write(level, logname, buf1);
char *buf = buf1;
while (true) {
char *end = strchr(buf, '\n');
if (end)
*end = '\0';
write(level, logname, buf);
if (!end)
break;
buf = end + 1;
}
}

void

+ 5
- 5
common/rfb/RREDecoder.cxx View File

@@ -20,7 +20,7 @@
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>

#include <rfb/ConnParams.h>
#include <rfb/ServerParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/RREDecoder.h>

@@ -45,22 +45,22 @@ RREDecoder::~RREDecoder()
}

void RREDecoder::readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os)
const ServerParams& server, rdr::OutStream* os)
{
rdr::U32 numRects;

numRects = is->readU32();
os->writeU32(numRects);

os->copyBytes(is, cp.pf().bpp/8 + numRects * (cp.pf().bpp/8 + 8));
os->copyBytes(is, server.pf().bpp/8 + numRects * (server.pf().bpp/8 + 8));
}

void RREDecoder::decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)
{
rdr::MemInStream is(buffer, buflen);
const PixelFormat& pf = cp.pf();
const PixelFormat& pf = server.pf();
switch (pf.bpp) {
case 8: rreDecode8 (r, &is, pf, pb); break;
case 16: rreDecode16(r, &is, pf, pb); break;

+ 2
- 2
common/rfb/RREDecoder.h View File

@@ -27,9 +27,9 @@ namespace rfb {
RREDecoder();
virtual ~RREDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os);
const ServerParams& server, rdr::OutStream* os);
virtual void decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb);
};
}

+ 1
- 1
common/rfb/RREEncoder.cxx View File

@@ -47,7 +47,7 @@ RREEncoder::~RREEncoder()

bool RREEncoder::isSupported()
{
return conn->cp.supportsEncoding(encodingRRE);
return conn->client.supportsEncoding(encodingRRE);
}

void RREEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)

+ 6
- 6
common/rfb/RawDecoder.cxx View File

@@ -19,7 +19,7 @@
#include <assert.h>

#include <rdr/OutStream.h>
#include <rfb/ConnParams.h>
#include <rfb/ServerParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/RawDecoder.h>

@@ -34,15 +34,15 @@ RawDecoder::~RawDecoder()
}

void RawDecoder::readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os)
const ServerParams& server, rdr::OutStream* os)
{
os->copyBytes(is, r.area() * (cp.pf().bpp/8));
os->copyBytes(is, r.area() * (server.pf().bpp/8));
}

void RawDecoder::decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)
{
assert(buflen >= (size_t)r.area() * (cp.pf().bpp/8));
pb->imageRect(cp.pf(), r, buffer);
assert(buflen >= (size_t)r.area() * (server.pf().bpp/8));
pb->imageRect(server.pf(), r, buffer);
}

+ 2
- 2
common/rfb/RawDecoder.h View File

@@ -26,9 +26,9 @@ namespace rfb {
RawDecoder();
virtual ~RawDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os);
const ServerParams& server, rdr::OutStream* os);
virtual void decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb);
};
}

+ 44
- 26
common/rfb/SConnection.cxx View File

@@ -59,7 +59,7 @@ SConnection::SConnection()
if (rfb::Server::protocol3_3)
defaultMinorVersion = 3;

cp.setVersion(defaultMajorVersion, defaultMinorVersion);
client.setVersion(defaultMajorVersion, defaultMinorVersion);
}

SConnection::~SConnection()
@@ -80,7 +80,12 @@ void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)

void SConnection::initialiseProtocol()
{
cp.writeVersion(os);
char str[13];

sprintf(str, "RFB %03d.%03d\n", defaultMajorVersion, defaultMinorVersion);
os->writeBytes(str, 12);
os->flush();

state_ = RFBSTATE_PROTOCOL_VERSION;
}

@@ -104,35 +109,47 @@ void SConnection::processMsg()

void SConnection::processVersionMsg()
{
char verStr[13];
int majorVersion;
int minorVersion;

vlog.debug("reading protocol version");
bool done;
if (!cp.readVersion(is, &done)) {

if (!is->checkNoWait(12))
return;

is->readBytes(verStr, 12);
verStr[12] = '\0';

if (sscanf(verStr, "RFB %03d.%03d\n",
&majorVersion, &minorVersion) != 2) {
state_ = RFBSTATE_INVALID;
throw Exception("reading version failed: not an RFB client?");
}
if (!done) return;

client.setVersion(majorVersion, minorVersion);

vlog.info("Client needs protocol version %d.%d",
cp.majorVersion, cp.minorVersion);
client.majorVersion, client.minorVersion);

if (cp.majorVersion != 3) {
if (client.majorVersion != 3) {
// unknown protocol version
throwConnFailedException("Client needs protocol version %d.%d, server has %d.%d",
cp.majorVersion, cp.minorVersion,
client.majorVersion, client.minorVersion,
defaultMajorVersion, defaultMinorVersion);
}

if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) {
if (client.minorVersion != 3 && client.minorVersion != 7 && client.minorVersion != 8) {
vlog.error("Client uses unofficial protocol version %d.%d",
cp.majorVersion,cp.minorVersion);
if (cp.minorVersion >= 8)
cp.minorVersion = 8;
else if (cp.minorVersion == 7)
cp.minorVersion = 7;
client.majorVersion,client.minorVersion);
if (client.minorVersion >= 8)
client.minorVersion = 8;
else if (client.minorVersion == 7)
client.minorVersion = 7;
else
cp.minorVersion = 3;
client.minorVersion = 3;
vlog.error("Assuming compatibility with version %d.%d",
cp.majorVersion,cp.minorVersion);
client.majorVersion,client.minorVersion);
}

versionReceived();
@@ -141,7 +158,7 @@ void SConnection::processVersionMsg()
std::list<rdr::U8>::iterator i;
secTypes = security.GetEnabledSecTypes();

if (cp.isVersion(3,3)) {
if (client.isVersion(3,3)) {

// cope with legacy 3.3 client only if "no authentication" or "vnc
// authentication" is supported.
@@ -150,7 +167,7 @@ void SConnection::processVersionMsg()
}
if (i == secTypes.end()) {
throwConnFailedException("No supported security type for %d.%d client",
cp.majorVersion, cp.minorVersion);
client.majorVersion, client.minorVersion);
}

os->writeU32(*i);
@@ -220,7 +237,7 @@ void SConnection::processSecurityMsg()
} catch (AuthFailureException& e) {
vlog.error("AuthFailureException: %s", e.str());
os->writeU32(secResultFailed);
if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
if (!client.beforeVersion(3,8)) // 3.8 onwards have failure message
os->writeString(e.str());
os->flush();
throw;
@@ -245,7 +262,7 @@ void SConnection::throwConnFailedException(const char* format, ...)
vlog.info("Connection failed: %s", str);

if (state_ == RFBSTATE_PROTOCOL_VERSION) {
if (cp.majorVersion == 3 && cp.minorVersion == 3) {
if (client.majorVersion == 3 && client.minorVersion == 3) {
os->writeU32(0);
os->writeString(str);
os->flush();
@@ -308,12 +325,12 @@ void SConnection::approveConnection(bool accept, const char* reason)
if (state_ != RFBSTATE_QUERYING)
throw Exception("SConnection::approveConnection: invalid state");

if (!cp.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) {
if (!client.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) {
if (accept) {
os->writeU32(secResultOK);
} else {
os->writeU32(secResultFailed);
if (!cp.beforeVersion(3,8)) { // 3.8 onwards have failure message
if (!client.beforeVersion(3,8)) { // 3.8 onwards have failure message
if (reason)
os->writeString(reason);
else
@@ -326,7 +343,7 @@ void SConnection::approveConnection(bool accept, const char* reason)
if (accept) {
state_ = RFBSTATE_INITIALISATION;
reader_ = new SMsgReader(this, is);
writer_ = new SMsgWriter(&cp, os);
writer_ = new SMsgWriter(&client, os);
authSuccess();
} else {
state_ = RFBSTATE_INVALID;
@@ -339,7 +356,8 @@ void SConnection::approveConnection(bool accept, const char* reason)

void SConnection::clientInit(bool shared)
{
writer_->writeServerInit();
writer_->writeServerInit(client.width(), client.height(),
client.pf(), client.name());
state_ = RFBSTATE_NORMAL;
}

@@ -360,7 +378,7 @@ void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
{
if (!readyForSetColourMapEntries) {
readyForSetColourMapEntries = true;
if (!cp.pf().trueColour) {
if (!client.pf().trueColour) {
writeFakeColourMap();
}
}
@@ -388,7 +406,7 @@ void SConnection::writeFakeColourMap(void)
rdr::U16 red[256], green[256], blue[256];

for (i = 0;i < 256;i++)
cp.pf().rgbFromPixel(i, &red[i], &green[i], &blue[i]);
client.pf().rgbFromPixel(i, &red[i], &green[i], &blue[i]);

writer()->writeSetColourMapEntries(0, 256, red, green, blue);
}

+ 11
- 19
common/rfb/SMsgHandler.cxx View File

@@ -19,6 +19,7 @@
#include <rfb/Exception.h>
#include <rfb/SMsgHandler.h>
#include <rfb/ScreenSet.h>
#include <rfb/encodings.h>

using namespace rfb;

@@ -36,7 +37,7 @@ void SMsgHandler::clientInit(bool shared)

void SMsgHandler::setPixelFormat(const PixelFormat& pf)
{
cp.setPF(pf);
client.setPF(pf);
}

void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings)
@@ -44,22 +45,22 @@ void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings)
bool firstFence, firstContinuousUpdates, firstLEDState,
firstQEMUKeyEvent;

firstFence = !cp.supportsFence;
firstContinuousUpdates = !cp.supportsContinuousUpdates;
firstLEDState = !cp.supportsLEDState;
firstQEMUKeyEvent = !cp.supportsQEMUKeyEvent;
firstFence = !client.supportsFence();
firstContinuousUpdates = !client.supportsContinuousUpdates();
firstLEDState = !client.supportsLEDState();
firstQEMUKeyEvent = !client.supportsEncoding(pseudoEncodingQEMUKeyEvent);

cp.setEncodings(nEncodings, encodings);
client.setEncodings(nEncodings, encodings);

supportsLocalCursor();

if (cp.supportsFence && firstFence)
if (client.supportsFence() && firstFence)
supportsFence();
if (cp.supportsContinuousUpdates && firstContinuousUpdates)
if (client.supportsContinuousUpdates() && firstContinuousUpdates)
supportsContinuousUpdates();
if (cp.supportsLEDState && firstLEDState)
if (client.supportsLEDState() && firstLEDState)
supportsLEDState();
if (cp.supportsQEMUKeyEvent && firstQEMUKeyEvent)
if (client.supportsEncoding(pseudoEncodingQEMUKeyEvent) && firstQEMUKeyEvent)
supportsQEMUKeyEvent();
}

@@ -82,12 +83,3 @@ void SMsgHandler::supportsLEDState()
void SMsgHandler::supportsQEMUKeyEvent()
{
}

void SMsgHandler::setDesktopSize(int fb_width, int fb_height,
const ScreenSet& layout)
{
cp.width = fb_width;
cp.height = fb_height;
cp.screenLayout = layout;
}


+ 4
- 4
common/rfb/SMsgHandler.h View File

@@ -25,7 +25,7 @@

#include <rdr/types.h>
#include <rfb/PixelFormat.h>
#include <rfb/ConnParams.h>
#include <rfb/ClientParams.h>
#include <rfb/InputHandler.h>
#include <rfb/ScreenSet.h>

@@ -40,8 +40,8 @@ namespace rfb {

// The following methods are called as corresponding messages are read. A
// derived class should override these methods as desired. Note that for
// the setPixelFormat(), setEncodings() and setDesktopSize() methods, a
// derived class must call on to SMsgHandler's methods.
// the setPixelFormat(), and setEncodings() methods, a derived class must
// call on to SMsgHandler's methods.

virtual void clientInit(bool shared);

@@ -85,7 +85,7 @@ namespace rfb {
// handler will send a pseudo-rect back, signalling server support.
virtual void supportsQEMUKeyEvent();

ConnParams cp;
ClientParams client;
};
}
#endif

+ 105
- 170
common/rfb/SMsgWriter.cxx View File

@@ -22,7 +22,7 @@
#include <rfb/msgTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/Exception.h>
#include <rfb/ConnParams.h>
#include <rfb/ClientParams.h>
#include <rfb/UpdateTracker.h>
#include <rfb/Encoder.h>
#include <rfb/SMsgWriter.h>
@@ -33,12 +33,10 @@ using namespace rfb;

static LogWriter vlog("SMsgWriter");

SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
: cp(cp_), os(os_),
SMsgWriter::SMsgWriter(ClientParams* client_, rdr::OutStream* os_)
: client(client_), os(os_),
nRectsInUpdate(0), nRectsInHeader(0),
needSetDesktopSize(false), needExtendedDesktopSize(false),
needSetDesktopName(false), needSetCursor(false),
needSetXCursor(false), needSetCursorWithAlpha(false),
needSetDesktopName(false), needCursor(false),
needLEDState(false), needQEMUKeyEvent(false)
{
}
@@ -47,12 +45,13 @@ SMsgWriter::~SMsgWriter()
{
}

void SMsgWriter::writeServerInit()
void SMsgWriter::writeServerInit(rdr::U16 width, rdr::U16 height,
const PixelFormat& pf, const char* name)
{
os->writeU16(cp->width);
os->writeU16(cp->height);
cp->pf().write(os);
os->writeString(cp->name());
os->writeU16(width);
os->writeU16(height);
pf.write(os);
os->writeString(name);
endMsg();
}

@@ -90,7 +89,7 @@ void SMsgWriter::writeServerCutText(const char* str, int len)

void SMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
{
if (!cp->supportsFence)
if (!client->supportsEncoding(pseudoEncodingFence))
throw Exception("Client does not support fences");
if (len > 64)
throw Exception("Too large fence payload");
@@ -112,116 +111,68 @@ void SMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])

void SMsgWriter::writeEndOfContinuousUpdates()
{
if (!cp->supportsContinuousUpdates)
if (!client->supportsEncoding(pseudoEncodingContinuousUpdates))
throw Exception("Client does not support continuous updates");

startMsg(msgTypeEndOfContinuousUpdates);
endMsg();
}

bool SMsgWriter::writeSetDesktopSize() {
if (!cp->supportsDesktopResize)
return false;

needSetDesktopSize = true;

return true;
}

bool SMsgWriter::writeExtendedDesktopSize() {
if (!cp->supportsExtendedDesktopSize)
return false;

needExtendedDesktopSize = true;

return true;
}

bool SMsgWriter::writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result,
int fb_width, int fb_height,
const ScreenSet& layout) {
void SMsgWriter::writeDesktopSize(rdr::U16 reason, rdr::U16 result)
{
ExtendedDesktopSizeMsg msg;

if (!cp->supportsExtendedDesktopSize)
return false;
if (!client->supportsEncoding(pseudoEncodingDesktopSize) &&
!client->supportsEncoding(pseudoEncodingExtendedDesktopSize))
throw Exception("Client does not support desktop size changes");

msg.reason = reason;
msg.result = result;
msg.fb_width = fb_width;
msg.fb_height = fb_height;
msg.layout = layout;

extendedDesktopSizeMsgs.push_back(msg);

return true;
}

bool SMsgWriter::writeSetDesktopName() {
if (!cp->supportsDesktopRename)
return false;

needSetDesktopName = true;

return true;
}

bool SMsgWriter::writeSetCursor()
{
if (!cp->supportsLocalCursor)
return false;

needSetCursor = true;

return true;
}

bool SMsgWriter::writeSetXCursor()
void SMsgWriter::writeSetDesktopName()
{
if (!cp->supportsLocalXCursor)
return false;

needSetXCursor = true;
if (!client->supportsEncoding(pseudoEncodingDesktopName))
throw Exception("Client does not support desktop name changes");

return true;
needSetDesktopName = true;
}

bool SMsgWriter::writeSetCursorWithAlpha()
void SMsgWriter::writeCursor()
{
if (!cp->supportsLocalCursorWithAlpha)
return false;
if (!client->supportsEncoding(pseudoEncodingCursor) &&
!client->supportsEncoding(pseudoEncodingXCursor) &&
!client->supportsEncoding(pseudoEncodingCursorWithAlpha))
throw Exception("Client does not support local cursor");

needSetCursorWithAlpha = true;

return true;
needCursor = true;
}

bool SMsgWriter::writeLEDState()
void SMsgWriter::writeLEDState()
{
if (!cp->supportsLEDState)
return false;
if (cp->ledState() == ledUnknown)
return false;
if (!client->supportsEncoding(pseudoEncodingLEDState))
throw Exception("Client does not support LED state");
if (client->ledState() == ledUnknown)
throw Exception("Server has not specified LED state");

needLEDState = true;

return true;
}

bool SMsgWriter::writeQEMUKeyEvent()
void SMsgWriter::writeQEMUKeyEvent()
{
if (!cp->supportsQEMUKeyEvent)
return false;
if (!client->supportsEncoding(pseudoEncodingQEMUKeyEvent))
throw Exception("Client does not support QEMU key events");

needQEMUKeyEvent = true;

return true;
}

bool SMsgWriter::needFakeUpdate()
{
if (needSetDesktopName)
return true;
if (needSetCursor || needSetXCursor || needSetCursorWithAlpha)
if (needCursor)
return true;
if (needLEDState)
return true;
@@ -235,9 +186,7 @@ bool SMsgWriter::needFakeUpdate()

bool SMsgWriter::needNoDataUpdate()
{
if (needSetDesktopSize)
return true;
if (needExtendedDesktopSize || !extendedDesktopSizeMsgs.empty())
if (!extendedDesktopSizeMsgs.empty())
return true;

return false;
@@ -249,12 +198,12 @@ void SMsgWriter::writeNoDataUpdate()

nRects = 0;

if (needSetDesktopSize)
nRects++;
if (needExtendedDesktopSize)
nRects++;
if (!extendedDesktopSizeMsgs.empty())
nRects += extendedDesktopSizeMsgs.size();
if (!extendedDesktopSizeMsgs.empty()) {
if (client->supportsEncoding(pseudoEncodingExtendedDesktopSize))
nRects += extendedDesktopSizeMsgs.size();
else
nRects++;
}

writeFramebufferUpdateStart(nRects);
writeNoDataRects();
@@ -269,11 +218,7 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects)
if (nRects != 0xFFFF) {
if (needSetDesktopName)
nRects++;
if (needSetCursor)
nRects++;
if (needSetXCursor)
nRects++;
if (needSetCursorWithAlpha)
if (needCursor)
nRects++;
if (needLEDState)
nRects++;
@@ -347,56 +292,52 @@ void SMsgWriter::endMsg()

void SMsgWriter::writePseudoRects()
{
if (needSetCursor) {
const Cursor& cursor = cp->cursor();

rdr::U8Array data(cursor.width()*cursor.height() * (cp->pf().bpp/8));
rdr::U8Array mask(cursor.getMask());

const rdr::U8* in;
rdr::U8* out;

in = cursor.getBuffer();
out = data.buf;
for (int i = 0;i < cursor.width()*cursor.height();i++) {
cp->pf().bufferFromRGB(out, in, 1);
in += 4;
out += cp->pf().bpp/8;
if (needCursor) {
const Cursor& cursor = client->cursor();

if (client->supportsEncoding(pseudoEncodingCursorWithAlpha)) {
writeSetCursorWithAlphaRect(cursor.width(), cursor.height(),
cursor.hotspot().x, cursor.hotspot().y,
cursor.getBuffer());
} else if (client->supportsEncoding(pseudoEncodingCursor)) {
rdr::U8Array data(cursor.width()*cursor.height() * (client->pf().bpp/8));
rdr::U8Array mask(cursor.getMask());

const rdr::U8* in;
rdr::U8* out;

in = cursor.getBuffer();
out = data.buf;
for (int i = 0;i < cursor.width()*cursor.height();i++) {
client->pf().bufferFromRGB(out, in, 1);
in += 4;
out += client->pf().bpp/8;
}

writeSetCursorRect(cursor.width(), cursor.height(),
cursor.hotspot().x, cursor.hotspot().y,
data.buf, mask.buf);
} else if (client->supportsEncoding(pseudoEncodingXCursor)) {
rdr::U8Array bitmap(cursor.getBitmap());
rdr::U8Array mask(cursor.getMask());

writeSetXCursorRect(cursor.width(), cursor.height(),
cursor.hotspot().x, cursor.hotspot().y,
bitmap.buf, mask.buf);
} else {
throw Exception("Client does not support local cursor");
}

writeSetCursorRect(cursor.width(), cursor.height(),
cursor.hotspot().x, cursor.hotspot().y,
data.buf, mask.buf);
needSetCursor = false;
}

if (needSetXCursor) {
const Cursor& cursor = cp->cursor();
rdr::U8Array bitmap(cursor.getBitmap());
rdr::U8Array mask(cursor.getMask());

writeSetXCursorRect(cursor.width(), cursor.height(),
cursor.hotspot().x, cursor.hotspot().y,
bitmap.buf, mask.buf);
needSetXCursor = false;
}

if (needSetCursorWithAlpha) {
const Cursor& cursor = cp->cursor();

writeSetCursorWithAlphaRect(cursor.width(), cursor.height(),
cursor.hotspot().x, cursor.hotspot().y,
cursor.getBuffer());
needSetCursorWithAlpha = false;
needCursor = false;
}

if (needSetDesktopName) {
writeSetDesktopNameRect(cp->name());
writeSetDesktopNameRect(client->name());
needSetDesktopName = false;
}

if (needLEDState) {
writeLEDStateRect(cp->ledState());
writeLEDStateRect(client->ledState());
needLEDState = false;
}

@@ -408,36 +349,30 @@ void SMsgWriter::writePseudoRects()

void SMsgWriter::writeNoDataRects()
{
// Start with specific ExtendedDesktopSize messages
if (!extendedDesktopSizeMsgs.empty()) {
std::list<ExtendedDesktopSizeMsg>::const_iterator ri;

for (ri = extendedDesktopSizeMsgs.begin();ri != extendedDesktopSizeMsgs.end();++ri) {
writeExtendedDesktopSizeRect(ri->reason, ri->result,
ri->fb_width, ri->fb_height, ri->layout);
if (client->supportsEncoding(pseudoEncodingExtendedDesktopSize)) {
std::list<ExtendedDesktopSizeMsg>::const_iterator ri;
for (ri = extendedDesktopSizeMsgs.begin();ri != extendedDesktopSizeMsgs.end();++ri) {
// FIXME: We can probably skip multiple reasonServer entries
writeExtendedDesktopSizeRect(ri->reason, ri->result,
client->width(), client->height(),
client->screenLayout());
}
} else if (client->supportsEncoding(pseudoEncodingDesktopSize)) {
// Some clients assume this is the last rectangle so don't send anything
// more after this
writeSetDesktopSizeRect(client->width(), client->height());
} else {
throw Exception("Client does not support desktop size changes");
}

extendedDesktopSizeMsgs.clear();
}

// Send this before SetDesktopSize to make life easier on the clients
if (needExtendedDesktopSize) {
writeExtendedDesktopSizeRect(0, 0, cp->width, cp->height,
cp->screenLayout);
needExtendedDesktopSize = false;
}

// Some clients assume this is the last rectangle so don't send anything
// more after this
if (needSetDesktopSize) {
writeSetDesktopSizeRect(cp->width, cp->height);
needSetDesktopSize = false;
}
}

void SMsgWriter::writeSetDesktopSizeRect(int width, int height)
{
if (!cp->supportsDesktopResize)
if (!client->supportsEncoding(pseudoEncodingDesktopSize))
throw Exception("Client does not support desktop resize");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriter::writeSetDesktopSizeRect: nRects out of sync");
@@ -457,7 +392,7 @@ void SMsgWriter::writeExtendedDesktopSizeRect(rdr::U16 reason,
{
ScreenSet::const_iterator si;

if (!cp->supportsExtendedDesktopSize)
if (!client->supportsEncoding(pseudoEncodingExtendedDesktopSize))
throw Exception("Client does not support extended desktop resize");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriter::writeExtendedDesktopSizeRect: nRects out of sync");
@@ -483,7 +418,7 @@ void SMsgWriter::writeExtendedDesktopSizeRect(rdr::U16 reason,

void SMsgWriter::writeSetDesktopNameRect(const char *name)
{
if (!cp->supportsDesktopRename)
if (!client->supportsEncoding(pseudoEncodingDesktopName))
throw Exception("Client does not support desktop rename");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriter::writeSetDesktopNameRect: nRects out of sync");
@@ -500,7 +435,7 @@ void SMsgWriter::writeSetCursorRect(int width, int height,
int hotspotX, int hotspotY,
const void* data, const void* mask)
{
if (!cp->supportsLocalCursor)
if (!client->supportsEncoding(pseudoEncodingCursor))
throw Exception("Client does not support local cursors");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriter::writeSetCursorRect: nRects out of sync");
@@ -510,7 +445,7 @@ void SMsgWriter::writeSetCursorRect(int width, int height,
os->writeU16(width);
os->writeU16(height);
os->writeU32(pseudoEncodingCursor);
os->writeBytes(data, width * height * (cp->pf().bpp/8));
os->writeBytes(data, width * height * (client->pf().bpp/8));
os->writeBytes(mask, (width+7)/8 * height);
}

@@ -518,7 +453,7 @@ void SMsgWriter::writeSetXCursorRect(int width, int height,
int hotspotX, int hotspotY,
const void* data, const void* mask)
{
if (!cp->supportsLocalXCursor)
if (!client->supportsEncoding(pseudoEncodingXCursor))
throw Exception("Client does not support local cursors");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriter::writeSetXCursorRect: nRects out of sync");
@@ -544,7 +479,7 @@ void SMsgWriter::writeSetCursorWithAlphaRect(int width, int height,
int hotspotX, int hotspotY,
const rdr::U8* data)
{
if (!cp->supportsLocalCursorWithAlpha)
if (!client->supportsEncoding(pseudoEncodingCursorWithAlpha))
throw Exception("Client does not support local cursors");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriter::writeSetCursorWithAlphaRect: nRects out of sync");
@@ -570,9 +505,9 @@ void SMsgWriter::writeSetCursorWithAlphaRect(int width, int height,

void SMsgWriter::writeLEDStateRect(rdr::U8 state)
{
if (!cp->supportsLEDState)
if (!client->supportsEncoding(pseudoEncodingLEDState))
throw Exception("Client does not support LED state updates");
if (cp->ledState() == ledUnknown)
if (client->ledState() == ledUnknown)
throw Exception("Server does not support LED state updates");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriter::writeLEDStateRect: nRects out of sync");
@@ -587,7 +522,7 @@ void SMsgWriter::writeLEDStateRect(rdr::U8 state)

void SMsgWriter::writeQEMUKeyEventRect()
{
if (!cp->supportsQEMUKeyEvent)
if (!client->supportsEncoding(pseudoEncodingQEMUKeyEvent))
throw Exception("Client does not support QEMU extended key events");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriter::writeQEMUKeyEventRect: nRects out of sync");

+ 13
- 26
common/rfb/SMsgWriter.h View File

@@ -31,17 +31,19 @@ namespace rdr { class OutStream; }

namespace rfb {

class ConnParams;
class ClientParams;
class PixelFormat;
struct ScreenSet;

class SMsgWriter {
public:
SMsgWriter(ConnParams* cp, rdr::OutStream* os);
SMsgWriter(ClientParams* client, rdr::OutStream* os);
virtual ~SMsgWriter();

// writeServerInit() must only be called at the appropriate time in the
// protocol initialisation.
void writeServerInit();
void writeServerInit(rdr::U16 width, rdr::U16 height,
const PixelFormat& pf, const char* name);

// Methods to write normal protocol messages

@@ -63,30 +65,21 @@ namespace rfb {
// updates mode.
void writeEndOfContinuousUpdates();

// writeSetDesktopSize() won't actually write immediately, but will
// writeDesktopSize() won't actually write immediately, but will
// write the relevant pseudo-rectangle as part of the next update.
bool writeSetDesktopSize();
// Same thing for the extended version. The first version queues up a
// generic update of the current server state, but the second queues a
// specific message.
bool writeExtendedDesktopSize();
bool writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result,
int fb_width, int fb_height,
const ScreenSet& layout);
void writeDesktopSize(rdr::U16 reason, rdr::U16 result=0);

bool writeSetDesktopName();
void writeSetDesktopName();

// Like setDesktopSize, we can't just write out a cursor message
// immediately.
bool writeSetCursor();
bool writeSetXCursor();
bool writeSetCursorWithAlpha();
void writeCursor();

// Same for LED state message
bool writeLEDState();
void writeLEDState();

// And QEMU keyboard event handshake
bool writeQEMUKeyEvent();
void writeQEMUKeyEvent();

// needFakeUpdate() returns true when an immediate update is needed in
// order to flush out pseudo-rectangles to the client.
@@ -140,25 +133,19 @@ namespace rfb {
void writeLEDStateRect(rdr::U8 state);
void writeQEMUKeyEventRect();

ConnParams* cp;
ClientParams* client;
rdr::OutStream* os;

int nRectsInUpdate;
int nRectsInHeader;

bool needSetDesktopSize;
bool needExtendedDesktopSize;
bool needSetDesktopName;
bool needSetCursor;
bool needSetXCursor;
bool needSetCursorWithAlpha;
bool needCursor;
bool needLEDState;
bool needQEMUKeyEvent;

typedef struct {
rdr::U16 reason, result;
int fb_width, fb_height;
ScreenSet layout;
} ExtendedDesktopSizeMsg;

std::list<ExtendedDesktopSizeMsg> extendedDesktopSizeMsgs;

+ 84
- 0
common/rfb/ServerParams.cxx View File

@@ -0,0 +1,84 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
* Copyright 2014-2018 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.
*/
#include <rfb/Exception.h>
#include <rfb/ledStates.h>
#include <rfb/ServerParams.h>

using namespace rfb;

ServerParams::ServerParams()
: majorVersion(0), minorVersion(0),
supportsQEMUKeyEvent(false),
supportsSetDesktopSize(false), supportsFence(false),
supportsContinuousUpdates(false),
width_(0), height_(0), name_(0),
ledState_(ledUnknown)
{
setName("");
cursor_ = new Cursor(0, 0, Point(), NULL);
}

ServerParams::~ServerParams()
{
delete [] name_;
delete cursor_;
}

void ServerParams::setDimensions(int width, int height)
{
ScreenSet layout;
layout.add_screen(rfb::Screen(0, 0, 0, width, height, 0));
setDimensions(width, height, layout);
}

void ServerParams::setDimensions(int width, int height, const ScreenSet& layout)
{
if (!layout.validate(width, height))
throw Exception("Attempted to configure an invalid screen layout");

width_ = width;
height_ = height;
screenLayout_ = layout;
}

void ServerParams::setPF(const PixelFormat& pf)
{
pf_ = pf;

if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32)
throw Exception("setPF: not 8, 16 or 32 bpp?");
}

void ServerParams::setName(const char* name)
{
delete [] name_;
name_ = strDup(name);
}

void ServerParams::setCursor(const Cursor& other)
{
delete cursor_;
cursor_ = new Cursor(other);
}

void ServerParams::setLEDState(unsigned int state)
{
ledState_ = state;
}

+ 89
- 0
common/rfb/ServerParams.h View File

@@ -0,0 +1,89 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2014-2018 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.
*/
//
// ServerParams - structure describing the current state of the remote server
//

#ifndef __RFB_SERVERPARAMS_H__
#define __RFB_SERVERPARAMS_H__

#include <rfb/Cursor.h>
#include <rfb/PixelFormat.h>
#include <rfb/ScreenSet.h>

namespace rfb {

class ServerParams {
public:
ServerParams();
~ServerParams();

int majorVersion;
int minorVersion;

void setVersion(int major, int minor) {
majorVersion = major; minorVersion = minor;
}
bool isVersion(int major, int minor) const {
return majorVersion == major && minorVersion == minor;
}
bool beforeVersion(int major, int minor) const {
return (majorVersion < major ||
(majorVersion == major && minorVersion < minor));
}
bool afterVersion(int major, int minor) const {
return !beforeVersion(major,minor+1);
}

const int width() const { return width_; }
const int height() const { return height_; }
const ScreenSet& screenLayout() const { return screenLayout_; }
void setDimensions(int width, int height);
void setDimensions(int width, int height, const ScreenSet& layout);

const PixelFormat& pf() const { return pf_; }
void setPF(const PixelFormat& pf);

const char* name() const { return name_; }
void setName(const char* name);

const Cursor& cursor() const { return *cursor_; }
void setCursor(const Cursor& cursor);

unsigned int ledState() { return ledState_; }
void setLEDState(unsigned int state);

bool supportsQEMUKeyEvent;
bool supportsSetDesktopSize;
bool supportsFence;
bool supportsContinuousUpdates;

private:

int width_;
int height_;
ScreenSet screenLayout_;

PixelFormat pf_;
char* name_;
Cursor* cursor_;
unsigned int ledState_;
};
}
#endif

+ 12
- 12
common/rfb/TightDecoder.cxx View File

@@ -25,7 +25,7 @@
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>

#include <rfb/ConnParams.h>
#include <rfb/ServerParams.h>
#include <rfb/Exception.h>
#include <rfb/PixelBuffer.h>
#include <rfb/TightConstants.h>
@@ -55,7 +55,7 @@ TightDecoder::~TightDecoder()
}

void TightDecoder::readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os)
const ServerParams& server, rdr::OutStream* os)
{
rdr::U8 comp_ctl;

@@ -66,10 +66,10 @@ void TightDecoder::readRect(const Rect& r, rdr::InStream* is,

// "Fill" compression type.
if (comp_ctl == tightFill) {
if (cp.pf().is888())
if (server.pf().is888())
os->copyBytes(is, 3);
else
os->copyBytes(is, cp.pf().bpp/8);
os->copyBytes(is, server.pf().bpp/8);
return;
}

@@ -106,13 +106,13 @@ void TightDecoder::readRect(const Rect& r, rdr::InStream* is,
palSize = is->readU8() + 1;
os->writeU8(palSize - 1);

if (cp.pf().is888())
if (server.pf().is888())
os->copyBytes(is, palSize * 3);
else
os->copyBytes(is, palSize * cp.pf().bpp/8);
os->copyBytes(is, palSize * server.pf().bpp/8);
break;
case tightFilterGradient:
if (cp.pf().bpp == 8)
if (server.pf().bpp == 8)
throw Exception("TightDecoder: invalid BPP for gradient filter");
break;
case tightFilterCopy:
@@ -129,10 +129,10 @@ void TightDecoder::readRect(const Rect& r, rdr::InStream* is,
rowSize = (r.width() + 7) / 8;
else
rowSize = r.width();
} else if (cp.pf().is888()) {
} else if (server.pf().is888()) {
rowSize = r.width() * 3;
} else {
rowSize = r.width() * cp.pf().bpp/8;
rowSize = r.width() * server.pf().bpp/8;
}

dataSize = r.height() * rowSize;
@@ -154,7 +154,7 @@ bool TightDecoder::doRectsConflict(const Rect& rectA,
const Rect& rectB,
const void* bufferB,
size_t buflenB,
const ConnParams& cp)
const ServerParams& server)
{
rdr::U8 comp_ctl_a, comp_ctl_b;

@@ -177,11 +177,11 @@ bool TightDecoder::doRectsConflict(const Rect& rectA,
}

void TightDecoder::decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)
{
const rdr::U8* bufptr;
const PixelFormat& pf = cp.pf();
const PixelFormat& pf = server.pf();

rdr::U8 comp_ctl;


+ 3
- 3
common/rfb/TightDecoder.h View File

@@ -32,16 +32,16 @@ namespace rfb {
TightDecoder();
virtual ~TightDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os);
const ServerParams& server, rdr::OutStream* os);
virtual bool doRectsConflict(const Rect& rectA,
const void* bufferA,
size_t buflenA,
const Rect& rectB,
const void* bufferB,
size_t buflenB,
const ConnParams& cp);
const ServerParams& server);
virtual void decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb);

private:

+ 1
- 2
common/rfb/TightEncoder.cxx View File

@@ -23,7 +23,6 @@
#include <rfb/PixelBuffer.h>
#include <rfb/Palette.h>
#include <rfb/encodings.h>
#include <rfb/ConnParams.h>
#include <rfb/SConnection.h>
#include <rfb/TightEncoder.h>
#include <rfb/TightConstants.h>
@@ -68,7 +67,7 @@ TightEncoder::~TightEncoder()

bool TightEncoder::isSupported()
{
return conn->cp.supportsEncoding(encodingTight);
return conn->client.supportsEncoding(encodingTight);
}

void TightEncoder::setCompressLevel(int level)

+ 4
- 4
common/rfb/TightJPEGEncoder.cxx View File

@@ -76,15 +76,15 @@ TightJPEGEncoder::~TightJPEGEncoder()

bool TightJPEGEncoder::isSupported()
{
if (!conn->cp.supportsEncoding(encodingTight))
if (!conn->client.supportsEncoding(encodingTight))
return false;

// Any one of these indicates support for JPEG
if (conn->cp.qualityLevel != -1)
if (conn->client.qualityLevel != -1)
return true;
if (conn->cp.fineQualityLevel != -1)
if (conn->client.fineQualityLevel != -1)
return true;
if (conn->cp.subsampling != -1)
if (conn->client.subsampling != -1)
return true;

// Tight support, but not JPEG

+ 1
- 16
common/rfb/UpdateTracker.cxx View File

@@ -60,32 +60,17 @@ void ClippingUpdateTracker::add_copied(const Region &dest, const Point &delta) {

// SimpleUpdateTracker

SimpleUpdateTracker::SimpleUpdateTracker(bool use_copyrect) {
copy_enabled = use_copyrect;
SimpleUpdateTracker::SimpleUpdateTracker() {
}

SimpleUpdateTracker::~SimpleUpdateTracker() {
}

void SimpleUpdateTracker::enable_copyrect(bool enable) {
if (!enable && copy_enabled) {
add_changed(copied);
copied.clear();
}
copy_enabled=enable;
}

void SimpleUpdateTracker::add_changed(const Region &region) {
changed.assign_union(region);
}

void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) {
// Do we support copyrect?
if (!copy_enabled) {
add_changed(dest);
return;
}

// Is there anything to do?
if (dest.is_empty()) return;


+ 1
- 4
common/rfb/UpdateTracker.h View File

@@ -68,11 +68,9 @@ namespace rfb {

class SimpleUpdateTracker : public UpdateTracker {
public:
SimpleUpdateTracker(bool use_copyrect=true);
SimpleUpdateTracker();
virtual ~SimpleUpdateTracker();

virtual void enable_copyrect(bool enable);

virtual void add_changed(const Region &region);
virtual void add_copied(const Region &dest, const Point &delta);
virtual void subtract(const Region& region);
@@ -94,7 +92,6 @@ namespace rfb {
Region changed;
Region copied;
Point copy_delta;
bool copy_enabled;
};

}

+ 53
- 61
common/rfb/VNCSConnectionST.cxx View File

@@ -49,7 +49,7 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
inProcessMessages(false),
pendingSyncFence(false), syncFence(false), fenceFlags(0),
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
losslessTimer(this), server(server_), updates(false),
losslessTimer(this), server(server_),
updateRenderedCursor(false), removeRenderedCursor(false),
continuousUpdates(false), encodeManager(this), idleTimer(this),
pointerEventTime(0), clientHasCursor(false)
@@ -199,9 +199,9 @@ void VNCSConnectionST::pixelBufferChange()
{
try {
if (!authenticated()) return;
if (cp.width && cp.height &&
(server->getPixelBuffer()->width() != cp.width ||
server->getPixelBuffer()->height() != cp.height))
if (client.width() && client.height() &&
(server->getPixelBuffer()->width() != client.width() ||
server->getPixelBuffer()->height() != client.height()))
{
// We need to clip the next update to the new size, but also add any
// extra bits if it's bigger. If we wanted to do this exactly, something
@@ -211,26 +211,24 @@ void VNCSConnectionST::pixelBufferChange()

//updates.intersect(server->pb->getRect());
//
//if (server->pb->width() > cp.width)
// updates.add_changed(Rect(cp.width, 0, server->pb->width(),
//if (server->pb->width() > client.width())
// updates.add_changed(Rect(client.width(), 0, server->pb->width(),
// server->pb->height()));
//if (server->pb->height() > cp.height)
// updates.add_changed(Rect(0, cp.height, cp.width,
//if (server->pb->height() > client.height())
// updates.add_changed(Rect(0, client.height(), client.width(),
// server->pb->height()));

damagedCursorRegion.assign_intersect(server->getPixelBuffer()->getRect());

cp.width = server->getPixelBuffer()->width();
cp.height = server->getPixelBuffer()->height();
cp.screenLayout = server->getScreenLayout();
client.setDimensions(server->getPixelBuffer()->width(),
server->getPixelBuffer()->height(),
server->getScreenLayout());
if (state() == RFBSTATE_NORMAL) {
// We should only send EDS to client asking for both
if (!writer()->writeExtendedDesktopSize()) {
if (!writer()->writeSetDesktopSize()) {
close("Client does not support desktop resize");
return;
}
if (!client.supportsDesktopSize()) {
close("Client does not support desktop resize");
return;
}
writer()->writeDesktopSize(reasonServer);
}

// Drop any lossy tracking that is now outside the framebuffer
@@ -325,7 +323,7 @@ bool VNCSConnectionST::getComparerState()
// We interpret a low compression level as an indication that the client
// wants to prioritise CPU usage over bandwidth, and hence disable the
// comparing update tracker.
return (cp.compressLevel == -1) || (cp.compressLevel > 1);
return (client.compressLevel == -1) || (client.compressLevel > 1);
}


@@ -363,8 +361,7 @@ bool VNCSConnectionST::needRenderedCursor()
if (state() != RFBSTATE_NORMAL)
return false;

if (!cp.supportsLocalCursorWithAlpha &&
!cp.supportsLocalCursor && !cp.supportsLocalXCursor)
if (!client.supportsLocalCursor())
return true;
if (!server->getCursorPos().equals(pointerEventPos) &&
(time(0) - pointerEventTime) > 0)
@@ -394,16 +391,16 @@ void VNCSConnectionST::authSuccess()
idleTimer.start(secsToMillis(rfb::Server::idleTimeout));

// - Set the connection parameters appropriately
cp.width = server->getPixelBuffer()->width();
cp.height = server->getPixelBuffer()->height();
cp.screenLayout = server->getScreenLayout();
cp.setName(server->getName());
cp.setLEDState(server->getLEDState());
client.setDimensions(server->getPixelBuffer()->width(),
server->getPixelBuffer()->height(),
server->getScreenLayout());
client.setName(server->getName());
client.setLEDState(server->getLEDState());
// - Set the default pixel format
cp.setPF(server->getPixelBuffer()->getPF());
client.setPF(server->getPixelBuffer()->getPF());
char buffer[256];
cp.pf().print(buffer, 256);
client.pf().print(buffer, 256);
vlog.info("Server default pixel format %s", buffer);

// - Mark the entire display as "dirty"
@@ -492,7 +489,7 @@ void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {

// Lock key heuristics
// (only for clients that do not support the LED state extension)
if (!cp.supportsLEDState) {
if (!client.supportsLEDState()) {
// Always ignore ScrollLock as we don't have a heuristic
// for that
if (keysym == XK_Scroll_Lock) {
@@ -597,10 +594,11 @@ void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
SConnection::framebufferUpdateRequest(r, incremental);

// Check that the client isn't sending crappy requests
if (!r.enclosed_by(Rect(0, 0, cp.width, cp.height))) {
if (!r.enclosed_by(Rect(0, 0, client.width(), client.height()))) {
vlog.error("FramebufferUpdateRequest %dx%d at %d,%d exceeds framebuffer %dx%d",
r.width(), r.height(), r.tl.x, r.tl.y, cp.width, cp.height);
safeRect = r.intersect(Rect(0, 0, cp.width, cp.height));
r.width(), r.height(), r.tl.x, r.tl.y,
client.width(), client.height());
safeRect = r.intersect(Rect(0, 0, client.width(), client.height()));
} else {
safeRect = r;
}
@@ -617,7 +615,8 @@ void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)

// And send the screen layout to the client (which, unlike the
// framebuffer dimensions, the client doesn't get during init)
writer()->writeExtendedDesktopSize();
if (client.supportsEncoding(pseudoEncodingExtendedDesktopSize))
writer()->writeDesktopSize(reasonServer);

// We do not send a DesktopSize since it only contains the
// framebuffer size (which the client already should know) and
@@ -635,8 +634,7 @@ void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height,
if (!rfb::Server::acceptSetDesktopSize) return;

result = server->setDesktopSize(this, fb_width, fb_height, layout);
writer()->writeExtendedDesktopSize(reasonClient, result,
fb_width, fb_height, layout);
writer()->writeDesktopSize(reasonClient, result);
}

void VNCSConnectionST::fence(rdr::U32 flags, unsigned len, const char data[])
@@ -688,7 +686,7 @@ void VNCSConnectionST::enableContinuousUpdates(bool enable,
{
Rect rect;

if (!cp.supportsFence || !cp.supportsContinuousUpdates)
if (!client.supportsFence() || !client.supportsContinuousUpdates())
throw Exception("Client tried to enable continuous updates when not allowed");

continuousUpdates = enable;
@@ -704,7 +702,7 @@ void VNCSConnectionST::enableContinuousUpdates(bool enable,
}

// supportsLocalCursor() is called whenever the status of
// cp.supportsLocalCursor has changed. If the client does now support local
// client.supportsLocalCursor() has changed. If the client does now support local
// cursor, we make sure that the old server-side rendered cursor is cleaned up
// and the cursor is sent to the client.

@@ -726,7 +724,7 @@ void VNCSConnectionST::supportsContinuousUpdates()
{
// We refuse to use continuous updates if we cannot monitor the buffer
// usage using fences.
if (!cp.supportsFence)
if (!client.supportsFence())
return;

writer()->writeEndOfContinuousUpdates();
@@ -734,6 +732,9 @@ void VNCSConnectionST::supportsContinuousUpdates()

void VNCSConnectionST::supportsLEDState()
{
if (client.ledState() == ledUnknown)
return;

writer()->writeLEDState();
}

@@ -772,7 +773,7 @@ void VNCSConnectionST::writeRTTPing()
{
char type;

if (!cp.supportsFence)
if (!client.supportsFence())
return;

congestion.updatePosition(sock->outStream().length());
@@ -799,7 +800,7 @@ bool VNCSConnectionST::isCongested()
if (sock->outStream().bufferUsage() > 0)
return true;

if (!cp.supportsFence)
if (!client.supportsFence())
return false;

congestion.updatePosition(sock->outStream().length());
@@ -876,8 +877,6 @@ void VNCSConnectionST::writeDataUpdate()
bool needNewUpdateInfo;
const RenderedCursor *cursor;

updates.enable_copyrect(cp.useCopyRect);

// See what the client has requested (if anything)
if (continuousUpdates)
req = cuRegion.union_(requested);
@@ -1063,13 +1062,13 @@ void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
if (!authenticated())
return;

cp.screenLayout = server->getScreenLayout();
client.setDimensions(client.width(), client.height(),
server->getScreenLayout());

if (state() != RFBSTATE_NORMAL)
return;

writer()->writeExtendedDesktopSize(reason, 0, cp.width, cp.height,
cp.screenLayout);
writer()->writeDesktopSize(reason);
}


@@ -1084,34 +1083,26 @@ void VNCSConnectionST::setCursor()

// We need to blank out the client's cursor or there will be two
if (needRenderedCursor()) {
cp.setCursor(emptyCursor);
client.setCursor(emptyCursor);
clientHasCursor = false;
} else {
cp.setCursor(*server->getCursor());
client.setCursor(*server->getCursor());
clientHasCursor = true;
}

if (!writer()->writeSetCursorWithAlpha()) {
if (!writer()->writeSetCursor()) {
if (!writer()->writeSetXCursor()) {
// No client support
return;
}
}
}
if (client.supportsLocalCursor())
writer()->writeCursor();
}

void VNCSConnectionST::setDesktopName(const char *name)
{
cp.setName(name);
client.setName(name);

if (state() != RFBSTATE_NORMAL)
return;

if (!writer()->writeSetDesktopName()) {
fprintf(stderr, "Client does not support desktop rename\n");
return;
}
if (client.supportsEncoding(pseudoEncodingDesktopName))
writer()->writeSetDesktopName();
}

void VNCSConnectionST::setLEDState(unsigned int ledstate)
@@ -1119,9 +1110,10 @@ void VNCSConnectionST::setLEDState(unsigned int ledstate)
if (state() != RFBSTATE_NORMAL)
return;

cp.setLEDState(ledstate);
client.setLEDState(ledstate);

writer()->writeLEDState();
if (client.supportsLEDState())
writer()->writeLEDState();
}

void VNCSConnectionST::setSocketTimeouts()

+ 9
- 6
common/rfb/VNCServerST.cxx View File

@@ -255,8 +255,6 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_, const ScreenSet& layout)
delete comparer;
comparer = 0;

screenLayout = layout;

if (!pb) {
screenLayout = ScreenSet();

@@ -266,16 +264,17 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_, const ScreenSet& layout)
return;
}

if (!layout.validate(pb->width(), pb->height()))
throw Exception("setPixelBuffer: invalid screen layout");

screenLayout = layout;

// Assume the framebuffer contents wasn't saved and reset everything
// that tracks its contents
comparer = new ComparingUpdateTracker(pb);
renderedCursorInvalid = true;
add_changed(pb->getRect());

// Make sure that we have at least one screen
if (screenLayout.num_screens() == 0)
screenLayout.add_screen(Screen(0, 0, 0, pb->width(), pb->height(), 0));

std::list<VNCSConnectionST*>::iterator ci, ci_next;
for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
ci_next = ci; ci_next++;
@@ -309,6 +308,10 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_)
}
}

// Make sure that we have at least one screen
if (layout.num_screens() == 0)
layout.add_screen(Screen(0, 0, 0, pb->width(), pb->height(), 0));

setPixelBuffer(pb_, layout);
}


+ 4
- 4
common/rfb/ZRLEDecoder.cxx View File

@@ -21,7 +21,7 @@
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>

#include <rfb/ConnParams.h>
#include <rfb/ServerParams.h>
#include <rfb/PixelBuffer.h>
#include <rfb/ZRLEDecoder.h>

@@ -72,7 +72,7 @@ ZRLEDecoder::~ZRLEDecoder()
}

void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os)
const ServerParams& server, rdr::OutStream* os)
{
rdr::U32 len;

@@ -82,11 +82,11 @@ void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is,
}

void ZRLEDecoder::decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)
{
rdr::MemInStream is(buffer, buflen);
const rfb::PixelFormat& pf = cp.pf();
const rfb::PixelFormat& pf = server.pf();
switch (pf.bpp) {
case 8: zrleDecode8 (r, &is, &zis, pf, pb); break;
case 16: zrleDecode16(r, &is, &zis, pf, pb); break;

+ 2
- 2
common/rfb/ZRLEDecoder.h View File

@@ -28,9 +28,9 @@ namespace rfb {
ZRLEDecoder();
virtual ~ZRLEDecoder();
virtual void readRect(const Rect& r, rdr::InStream* is,
const ConnParams& cp, rdr::OutStream* os);
const ServerParams& server, rdr::OutStream* os);
virtual void decodeRect(const Rect& r, const void* buffer,
size_t buflen, const ConnParams& cp,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb);
private:
rdr::ZlibInStream zis;

+ 1
- 2
common/rfb/ZRLEEncoder.cxx View File

@@ -19,7 +19,6 @@
#include <rdr/OutStream.h>
#include <rfb/Exception.h>
#include <rfb/encodings.h>
#include <rfb/ConnParams.h>
#include <rfb/Palette.h>
#include <rfb/SConnection.h>
#include <rfb/ZRLEEncoder.h>
@@ -43,7 +42,7 @@ ZRLEEncoder::~ZRLEEncoder()

bool ZRLEEncoder::isSupported()
{
return conn->cp.supportsEncoding(encodingZRLE);
return conn->client.supportsEncoding(encodingZRLE);
}

void ZRLEEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)

+ 5
- 5
tests/decperf.cxx View File

@@ -47,7 +47,7 @@ public:
CConn(const char *filename);
~CConn();

virtual void setDesktopSize(int w, int h);
virtual void initDone();
virtual void setPixelFormat(const rfb::PixelFormat& pf);
virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*);
virtual void framebufferUpdateStart();
@@ -81,11 +81,11 @@ CConn::~CConn()
delete in;
}

void CConn::setDesktopSize(int w, int h)
void CConn::initDone()
{
CConnection::setDesktopSize(w, h);
setFramebuffer(new rfb::ManagedPixelBuffer(filePF, cp.width, cp.height));
setFramebuffer(new rfb::ManagedPixelBuffer(filePF,
server.width(),
server.height()));
}

void CConn::setPixelFormat(const rfb::PixelFormat& pf)

+ 6
- 8
tests/encperf.cxx View File

@@ -89,7 +89,7 @@ public:
void getStats(double& ratio, unsigned long long& bytes,
unsigned long long& rawEquivalent);

virtual void setDesktopSize(int w, int h);
virtual void initDone();
virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*);
virtual void framebufferUpdateStart();
virtual void framebufferUpdateEnd();
@@ -180,7 +180,7 @@ CConn::CConn(const char *filename)
setDesktopSize(width, height);

sc = new SConn();
sc->cp.setPF((bool)translate ? fbPF : pf);
sc->client.setPF((bool)translate ? fbPF : pf);
sc->setEncodings(sizeof(encodings) / sizeof(*encodings), encodings);
}

@@ -196,14 +196,12 @@ void CConn::getStats(double& ratio, unsigned long long& bytes,
sc->getStats(ratio, bytes, rawEquivalent);
}

void CConn::setDesktopSize(int w, int h)
void CConn::initDone()
{
rfb::ModifiablePixelBuffer *pb;

CConnection::setDesktopSize(w, h);

pb = new rfb::ManagedPixelBuffer((bool)translate ? fbPF : cp.pf(),
cp.width, cp.height);
pb = new rfb::ManagedPixelBuffer((bool)translate ? fbPF : server.pf(),
server.width(), server.height());
setFramebuffer(pb);
}

@@ -290,7 +288,7 @@ SConn::SConn()
out = new DummyOutStream;
setStreams(NULL, out);

setWriter(new rfb::SMsgWriter(&cp, out));
setWriter(new rfb::SMsgWriter(&client, out));

manager = new Manager(this);
}

+ 19
- 0
unix/x0vncserver/XDesktop.cxx View File

@@ -423,8 +423,27 @@ ScreenSet XDesktop::computeScreenLayout()

layout = ::computeScreenLayout(&outputIdMap);
XRRFreeScreenResources(res);

// Adjust the layout relative to the geometry
ScreenSet::iterator iter, iter_next;
Point offset(-geometry->offsetLeft(), -geometry->offsetTop());
for (iter = layout.begin();iter != layout.end();iter = iter_next) {
iter_next = iter; ++iter_next;
iter->dimensions = iter->dimensions.translate(offset);
if (iter->dimensions.enclosed_by(geometry->getRect()))
continue;
iter->dimensions = iter->dimensions.intersect(geometry->getRect());
if (iter->dimensions.is_empty()) {
layout.remove_screen(iter->id);
}
}
#endif

// Make sure that we have at least one screen
if (layout.num_screens() == 0)
layout.add_screen(rfb::Screen(0, 0, 0, geometry->width(),
geometry->height(), 0));

return layout;
}


+ 53
- 212
vncviewer/CConn.cxx View File

@@ -36,8 +36,6 @@
#include <rfb/screenTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/Timer.h>
#include <rdr/MemInStream.h>
#include <rdr/MemOutStream.h>
#include <network/TcpSocket.h>
#ifndef WIN32
#include <network/UnixSocket.h>
@@ -76,36 +74,21 @@ static const PixelFormat mediumColourPF(8, 8, false, true,

CConn::CConn(const char* vncServerName, network::Socket* socket=NULL)
: serverHost(0), serverPort(0), desktop(NULL),
updateCount(0), pixelCount(0), pendingPFChange(false),
currentEncoding(encodingTight), lastServerEncoding((unsigned int)-1),
formatChange(false), encodingChange(false),
firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
forceNonincremental(true), supportsSyncFence(false)
updateCount(0), pixelCount(0),
lastServerEncoding((unsigned int)-1)
{
setShared(::shared);
sock = socket;

int encNum = encodingNum(preferredEncoding);
if (encNum != -1)
currentEncoding = encNum;

cp.supportsLocalCursor = true;

cp.supportsDesktopResize = true;
cp.supportsExtendedDesktopSize = true;
cp.supportsDesktopRename = true;

cp.supportsLEDState = true;
supportsLocalCursor = true;
supportsDesktopResize = true;
supportsLEDState = true;

if (customCompressLevel)
cp.compressLevel = compressLevel;
else
cp.compressLevel = -1;
setCompressLevel(::compressLevel);

if (!noJpeg)
cp.qualityLevel = qualityLevel;
else
cp.qualityLevel = -1;
setQualityLevel(::qualityLevel);

if(sock == NULL) {
try {
@@ -158,16 +141,6 @@ CConn::~CConn()
delete sock;
}

void CConn::refreshFramebuffer()
{
forceNonincremental = true;

// Without fences, we cannot safely trigger an update request directly
// but must wait for the next update to arrive.
if (supportsSyncFence)
requestNewUpdate();
}

const char *CConn::connectionInfo()
{
static char infoText[1024] = "";
@@ -181,7 +154,7 @@ const char *CConn::connectionInfo()
infoText[0] = '\0';

snprintf(scratch, sizeof(scratch),
_("Desktop name: %.80s"), cp.name());
_("Desktop name: %.80s"), server.name());
strcat(infoText, scratch);
strcat(infoText, "\n");

@@ -191,13 +164,13 @@ const char *CConn::connectionInfo()
strcat(infoText, "\n");

snprintf(scratch, sizeof(scratch),
_("Size: %d x %d"), cp.width, cp.height);
_("Size: %d x %d"), server.width(), server.height());
strcat(infoText, scratch);
strcat(infoText, "\n");

// TRANSLATORS: Will be filled in with a string describing the
// protocol pixel format in a fairly language neutral way
cp.pf().print(pfStr, 100);
server.pf().print(pfStr, 100);
snprintf(scratch, sizeof(scratch),
_("Pixel format: %s"), pfStr);
strcat(infoText, scratch);
@@ -211,7 +184,7 @@ const char *CConn::connectionInfo()
strcat(infoText, "\n");

snprintf(scratch, sizeof(scratch),
_("Requested encoding: %s"), encodingName(currentEncoding));
_("Requested encoding: %s"), encodingName(getPreferredEncoding()));
strcat(infoText, scratch);
strcat(infoText, "\n");

@@ -226,7 +199,7 @@ const char *CConn::connectionInfo()
strcat(infoText, "\n");

snprintf(scratch, sizeof(scratch),
_("Protocol version: %d.%d"), cp.majorVersion, cp.minorVersion);
_("Protocol version: %d.%d"), server.majorVersion, server.minorVersion);
strcat(infoText, scratch);
strcat(infoText, "\n");

@@ -310,34 +283,27 @@ void CConn::socketEvent(FL_SOCKET fd, void *data)

////////////////////// CConnection callback methods //////////////////////

// serverInit() is called when the serverInit message has been received. At
// initDone() is called when the serverInit message has been received. At
// this point we create the desktop window and display it. We also tell the
// server the pixel format and encodings to use and request the first update.
void CConn::serverInit()
void CConn::initDone()
{
CConnection::serverInit();

// If using AutoSelect with old servers, start in FullColor
// mode. See comment in autoSelectFormatAndEncoding.
if (cp.beforeVersion(3, 8) && autoSelect)
if (server.beforeVersion(3, 8) && autoSelect)
fullColour.setParam(true);

serverPF = cp.pf();
serverPF = server.pf();

desktop = new DesktopWindow(cp.width, cp.height, cp.name(), serverPF, this);
desktop = new DesktopWindow(server.width(), server.height(),
server.name(), serverPF, this);
fullColourPF = desktop->getPreferredPF();

// Force a switch to the format and encoding we'd like
formatChange = encodingChange = true;

// And kick off the update cycle
requestNewUpdate();

// This initial update request is a bit of a corner case, so we need
// to help out setting the correct format here.
assert(pendingPFChange);
cp.setPF(pendingPF);
pendingPFChange = false;
updatePixelFormat();
int encNum = encodingNum(::preferredEncoding);
if (encNum != -1)
setPreferredEncoding(encNum);
}

// setDesktopSize() is called when the desktop size changes (including when
@@ -366,8 +332,7 @@ void CConn::setExtendedDesktopSize(unsigned reason, unsigned result,
void CConn::setName(const char* name)
{
CConnection::setName(name);
if (desktop)
desktop->setName(name);
desktop->setName(name);
}

// framebufferUpdateStart() is called at the beginning of an update.
@@ -378,11 +343,6 @@ void CConn::framebufferUpdateStart()
{
CConnection::framebufferUpdateStart();

// Note: This might not be true if sync fences are supported
pendingUpdate = false;

requestNewUpdate();

// Update the screen prematurely for very slow updates
Fl::add_timeout(1.0, handleUpdateTimeout, this);
}
@@ -400,22 +360,6 @@ void CConn::framebufferUpdateEnd()
Fl::remove_timeout(handleUpdateTimeout, this);
desktop->updateWindow();

if (firstUpdate) {
// We need fences to make extra update requests and continuous
// updates "safe". See fence() for the next step.
if (cp.supportsFence)
writer()->writeFence(fenceFlagRequest | fenceFlagSyncNext, 0, NULL);

firstUpdate = false;
}

// A format change has been scheduled and we are now past the update
// with the old format. Time to active the new one.
if (pendingPFChange) {
cp.setPF(pendingPF);
pendingPFChange = false;
}

// Compute new settings based on updated bandwidth values
if (autoSelect)
autoSelectFormatAndEncoding();
@@ -469,27 +413,6 @@ void CConn::fence(rdr::U32 flags, unsigned len, const char data[])
writer()->writeFence(flags, len, data);
return;
}

if (len == 0) {
// Initial probe
if (flags & fenceFlagSyncNext) {
supportsSyncFence = true;

if (cp.supportsContinuousUpdates) {
vlog.info(_("Enabling continuous updates"));
continuousUpdates = true;
writer()->writeEnableContinuousUpdates(true, 0, 0, cp.width, cp.height);
}
}
} else {
// Pixel format change
rdr::MemInStream memStream(data, len);
PixelFormat pf;

pf.read(&memStream);

cp.setPF(pf);
}
}

void CConn::setLEDState(unsigned int state)
@@ -504,13 +427,7 @@ void CConn::setLEDState(unsigned int state)

void CConn::resizeFramebuffer()
{
if (!desktop)
return;

if (continuousUpdates)
writer()->writeEnableContinuousUpdates(true, 0, 0, cp.width, cp.height);

desktop->resizeFramebuffer(cp.width, cp.height);
desktop->resizeFramebuffer(server.width(), server.height());
}

// autoSelectFormatAndEncoding() chooses the format and encoding appropriate
@@ -533,13 +450,10 @@ void CConn::autoSelectFormatAndEncoding()
int kbitsPerSecond = sock->inStream().kbitsPerSecond();
unsigned int timeWaited = sock->inStream().timeWaited();
bool newFullColour = fullColour;
int newQualityLevel = qualityLevel;
int newQualityLevel = ::qualityLevel;

// Always use Tight
if (currentEncoding != encodingTight) {
currentEncoding = encodingTight;
encodingChange = true;
}
setPreferredEncoding(encodingTight);

// Check that we have a decent bandwidth measurement
if ((kbitsPerSecond == 0) || (timeWaited < 10000))
@@ -552,16 +466,15 @@ void CConn::autoSelectFormatAndEncoding()
else
newQualityLevel = 6;

if (newQualityLevel != qualityLevel) {
if (newQualityLevel != ::qualityLevel) {
vlog.info(_("Throughput %d kbit/s - changing to quality %d"),
kbitsPerSecond, newQualityLevel);
cp.qualityLevel = newQualityLevel;
qualityLevel.setParam(newQualityLevel);
encodingChange = true;
::qualityLevel.setParam(newQualityLevel);
setQualityLevel(newQualityLevel);
}
}

if (cp.beforeVersion(3, 8)) {
if (server.beforeVersion(3, 8)) {
// Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
// cursors "asynchronously". If this happens in the middle of a
// pixel format change, the server will encode the cursor with
@@ -582,76 +495,31 @@ void CConn::autoSelectFormatAndEncoding()
vlog.info(_("Throughput %d kbit/s - full color is now disabled"),
kbitsPerSecond);
fullColour.setParam(newFullColour);
formatChange = true;
updatePixelFormat();
}
}

// checkEncodings() sends a setEncodings message if one is needed.
void CConn::checkEncodings()
{
if (encodingChange && writer()) {
vlog.info(_("Using %s encoding"),encodingName(currentEncoding));
writer()->writeSetEncodings(currentEncoding, true);
encodingChange = false;
}
}

// requestNewUpdate() requests an update from the server, having set the
// format and encoding appropriately.
void CConn::requestNewUpdate()
void CConn::updatePixelFormat()
{
if (formatChange) {
PixelFormat pf;

/* Catch incorrect requestNewUpdate calls */
assert(!pendingUpdate || supportsSyncFence);

if (fullColour) {
pf = fullColourPF;
} else {
if (lowColourLevel == 0)
pf = verylowColourPF;
else if (lowColourLevel == 1)
pf = lowColourPF;
else
pf = mediumColourPF;
}

if (supportsSyncFence) {
// We let the fence carry the pixel format and switch once we
// get the response back. That way we will be synchronised with
// when the server switches.
rdr::MemOutStream memStream;

pf.write(&memStream);

writer()->writeFence(fenceFlagRequest | fenceFlagSyncNext,
memStream.length(), (const char*)memStream.data());
} else {
// New requests are sent out at the start of processing the last
// one, so we cannot switch our internal format right now (doing so
// would mean misdecoding the current update).
pendingPFChange = true;
pendingPF = pf;
}

char str[256];
pf.print(str, 256);
vlog.info(_("Using pixel format %s"),str);
writer()->writeSetPixelFormat(pf);
PixelFormat pf;

formatChange = false;
if (fullColour) {
pf = fullColourPF;
} else {
if (lowColourLevel == 0)
pf = verylowColourPF;
else if (lowColourLevel == 1)
pf = lowColourPF;
else
pf = mediumColourPF;
}

checkEncodings();

if (forceNonincremental || !continuousUpdates) {
pendingUpdate = true;
writer()->writeFramebufferUpdateRequest(Rect(0, 0, cp.width, cp.height),
!forceNonincremental);
}
forceNonincremental = false;
char str[256];
pf.print(str, 256);
vlog.info(_("Using pixel format %s"),str);
setPF(pf);
}

void CConn::handleOptions(void *data)
@@ -663,50 +531,23 @@ void CConn::handleOptions(void *data)
// list is cheap. Avoid overriding what the auto logic has selected
// though.
if (!autoSelect) {
int encNum = encodingNum(preferredEncoding);
int encNum = encodingNum(::preferredEncoding);

if (encNum != -1)
self->currentEncoding = encNum;
self->setPreferredEncoding(encNum);
}

self->cp.supportsLocalCursor = true;

if (customCompressLevel)
self->cp.compressLevel = compressLevel;
self->setCompressLevel(::compressLevel);
else
self->cp.compressLevel = -1;
self->setCompressLevel(-1);

if (!noJpeg && !autoSelect)
self->cp.qualityLevel = qualityLevel;
self->setQualityLevel(::qualityLevel);
else
self->cp.qualityLevel = -1;

self->encodingChange = true;

// Format changes refreshes the entire screen though and are therefore
// very costly. It's probably worth the effort to see if it is necessary
// here.
PixelFormat pf;
self->setQualityLevel(-1);

if (fullColour) {
pf = self->fullColourPF;
} else {
if (lowColourLevel == 0)
pf = verylowColourPF;
else if (lowColourLevel == 1)
pf = lowColourPF;
else
pf = mediumColourPF;
}

if (!pf.equal(self->cp.pf())) {
self->formatChange = true;

// Without fences, we cannot safely trigger an update request directly
// but must wait for the next update to arrive.
if (self->supportsSyncFence)
self->requestNewUpdate();
}
self->updatePixelFormat();
}

void CConn::handleUpdateTimeout(void *data)

+ 3
- 20
vncviewer/CConn.h View File

@@ -36,8 +36,6 @@ public:
CConn(const char* vncServerName, network::Socket* sock);
~CConn();

void refreshFramebuffer();

const char *connectionInfo();

unsigned getUpdateCount();
@@ -51,7 +49,7 @@ public:
static void socketEvent(FL_SOCKET fd, void *data);

// CConnection callback methods
void serverInit();
void initDone();

void setDesktopSize(int w, int h);
void setExtendedDesktopSize(unsigned reason, unsigned result,
@@ -81,8 +79,7 @@ private:
void resizeFramebuffer();

void autoSelectFormatAndEncoding();
void checkEncodings();
void requestNewUpdate();
void updatePixelFormat();

static void handleOptions(void *data);

@@ -101,21 +98,7 @@ private:
rfb::PixelFormat serverPF;
rfb::PixelFormat fullColourPF;

bool pendingPFChange;
rfb::PixelFormat pendingPF;

int currentEncoding, lastServerEncoding;

bool formatChange;
bool encodingChange;

bool firstUpdate;
bool pendingUpdate;
bool continuousUpdates;

bool forceNonincremental;

bool supportsSyncFence;
int lastServerEncoding;
};

#endif

+ 14
- 14
vncviewer/DesktopWindow.cxx View File

@@ -235,7 +235,7 @@ void DesktopWindow::setName(const char *name)
void DesktopWindow::updateWindow()
{
if (firstUpdate) {
if (cc->cp.supportsSetDesktopSize) {
if (cc->server.supportsSetDesktopSize) {
// Hack: Wait until we're in the proper mode and position until
// resizing things, otherwise we might send the wrong thing.
if (delayedFullscreen)
@@ -487,7 +487,7 @@ void DesktopWindow::resize(int x, int y, int w, int h)
// d) We're not still waiting for startup fullscreen to kick in
//
if (not firstUpdate and not delayedFullscreen and
::remoteResize and cc->cp.supportsSetDesktopSize) {
::remoteResize and cc->server.supportsSetDesktopSize) {
// We delay updating the remote desktop as we tend to get a flood
// of resize events as the user is dragging the window.
Fl::remove_timeout(handleResizeTimeout, this);
@@ -1014,14 +1014,14 @@ void DesktopWindow::handleResizeTimeout(void *data)
void DesktopWindow::remoteResize(int width, int height)
{
ScreenSet layout;
ScreenSet::iterator iter;
ScreenSet::const_iterator iter;

if (!fullscreen_active() || (width > w()) || (height > h())) {
// In windowed mode (or the framebuffer is so large that we need
// to scroll) we just report a single virtual screen that covers
// the entire framebuffer.

layout = cc->cp.screenLayout;
layout = cc->server.screenLayout();

// Not sure why we have no screens, but adding a new one should be
// safe as there is nothing to conflict with...
@@ -1077,8 +1077,8 @@ void DesktopWindow::remoteResize(int width, int height)
sy -= viewport_rect.tl.y;

// Look for perfectly matching existing screen...
for (iter = cc->cp.screenLayout.begin();
iter != cc->cp.screenLayout.end(); ++iter) {
for (iter = cc->server.screenLayout().begin();
iter != cc->server.screenLayout().end(); ++iter) {
if ((iter->dimensions.tl.x == sx) &&
(iter->dimensions.tl.y == sy) &&
(iter->dimensions.width() == sw) &&
@@ -1087,7 +1087,7 @@ void DesktopWindow::remoteResize(int width, int height)
}

// Found it?
if (iter != cc->cp.screenLayout.end()) {
if (iter != cc->server.screenLayout().end()) {
layout.add_screen(*iter);
continue;
}
@@ -1095,13 +1095,13 @@ void DesktopWindow::remoteResize(int width, int height)
// Need to add a new one, which means we need to find an unused id
while (true) {
id = rand();
for (iter = cc->cp.screenLayout.begin();
iter != cc->cp.screenLayout.end(); ++iter) {
for (iter = cc->server.screenLayout().begin();
iter != cc->server.screenLayout().end(); ++iter) {
if (iter->id == id)
break;
}

if (iter == cc->cp.screenLayout.end())
if (iter == cc->server.screenLayout().end())
break;
}

@@ -1115,14 +1115,14 @@ void DesktopWindow::remoteResize(int width, int height)
}

// Do we actually change anything?
if ((width == cc->cp.width) &&
(height == cc->cp.height) &&
(layout == cc->cp.screenLayout))
if ((width == cc->server.width()) &&
(height == cc->server.height()) &&
(layout == cc->server.screenLayout()))
return;

char buffer[2048];
vlog.debug("Requesting framebuffer resize from %dx%d to %dx%d",
cc->cp.width, cc->cp.height, width, height);
cc->server.width(), cc->server.height(), width, height);
layout.print(buffer, sizeof(buffer));
vlog.debug("%s", buffer);


+ 5
- 5
vncviewer/Viewport.cxx View File

@@ -425,7 +425,7 @@ void Viewport::pushLEDState()
unsigned int state;

// Server support?
if (cc->cp.ledState() == ledUnknown)
if (cc->server.ledState() == ledUnknown)
return;

state = 0;
@@ -458,7 +458,7 @@ void Viewport::pushLEDState()
state |= ledNumLock;

// No support for Scroll Lock //
state |= (cc->cp.ledState() & ledScrollLock);
state |= (cc->server.ledState() & ledScrollLock);

#else
unsigned int mask;
@@ -484,17 +484,17 @@ void Viewport::pushLEDState()
state |= ledScrollLock;
#endif

if ((state & ledCapsLock) != (cc->cp.ledState() & ledCapsLock)) {
if ((state & ledCapsLock) != (cc->server.ledState() & ledCapsLock)) {
vlog.debug("Inserting fake CapsLock to get in sync with server");
handleKeyPress(0x3a, XK_Caps_Lock);
handleKeyRelease(0x3a);
}
if ((state & ledNumLock) != (cc->cp.ledState() & ledNumLock)) {
if ((state & ledNumLock) != (cc->server.ledState() & ledNumLock)) {
vlog.debug("Inserting fake NumLock to get in sync with server");
handleKeyPress(0x45, XK_Num_Lock);
handleKeyRelease(0x45);
}
if ((state & ledScrollLock) != (cc->cp.ledState() & ledScrollLock)) {
if ((state & ledScrollLock) != (cc->server.ledState() & ledScrollLock)) {
vlog.debug("Inserting fake ScrollLock to get in sync with server");
handleKeyPress(0x46, XK_Scroll_Lock);
handleKeyRelease(0x46);

Loading…
Cancel
Save