summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/rfb/SMsgWriter.cxx22
-rw-r--r--common/rfb/SMsgWriter.h13
-rw-r--r--common/rfb/SMsgWriterV3.cxx184
-rw-r--r--common/rfb/SMsgWriterV3.h8
-rw-r--r--common/rfb/VNCSConnectionST.cxx24
5 files changed, 167 insertions, 84 deletions
diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
index f3079eed..1695161f 100644
--- a/common/rfb/SMsgWriter.cxx
+++ b/common/rfb/SMsgWriter.cxx
@@ -114,6 +114,11 @@ int SMsgWriter::getNumRects(const Rect &r)
return encoders[encoding]->getNumRects(r);
}
+bool SMsgWriter::needFakeUpdate()
+{
+ return false;
+}
+
// FIXME: This functions is not used because it incorrectly computes
// the number of rectangles if the Tight encoder is used.
/*
@@ -126,6 +131,17 @@ void SMsgWriter::writeFramebufferUpdate(const UpdateInfo& ui, ImageGetter* ig,
}
*/
+bool SMsgWriter::needNoDataUpdate()
+{
+ return false;
+}
+
+void SMsgWriter::writeNoDataUpdate()
+{
+ // This class has no pseudo-rectangles so there is nothing to do here
+ vlog.error("writeNoDataUpdate() called");
+}
+
void SMsgWriter::writeRects(const UpdateInfo& ui, ImageGetter* ig,
Region* updatedRegion)
{
@@ -148,12 +164,6 @@ void SMsgWriter::writeRects(const UpdateInfo& ui, ImageGetter* ig,
}
}
-
-bool SMsgWriter::needFakeUpdate()
-{
- return false;
-}
-
bool SMsgWriter::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
{
return writeRect(r, cp->currentEncoding(), ig, actual);
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
index 5df72704..44a39158 100644
--- a/common/rfb/SMsgWriter.h
+++ b/common/rfb/SMsgWriter.h
@@ -98,8 +98,7 @@ namespace rfb {
int hotspotY, void* data, void* mask)=0;
// needFakeUpdate() returns true when an immediate update is needed in
- // order to flush out setDesktopSize or setCursor pseudo-rectangles to the
- // client.
+ // order to flush out pseudo-rectangles to the client.
virtual bool needFakeUpdate();
// writeFramebufferUpdate() writes a framebuffer update using the given
@@ -114,6 +113,16 @@ namespace rfb {
Region* updatedRegion);
*/
+ // needNoDataUpdate() returns true when an update without any
+ // framebuffer changes need to be sent (using writeNoDataUpdate()).
+ // Commonly this is an update that modifies the size of the framebuffer
+ // or the screen layout.
+ virtual bool needNoDataUpdate();
+
+ // writeNoDataUpdate() write a framebuffer update containing only
+ // pseudo-rectangles.
+ virtual void writeNoDataUpdate();
+
// writeRects() accepts an UpdateInfo (changed & copied regions) and an
// ImageGetter to fetch pixels from. It then calls writeCopyRect() and
// writeRect() as appropriate. writeFramebufferUpdateStart() must be used
diff --git a/common/rfb/SMsgWriterV3.cxx b/common/rfb/SMsgWriterV3.cxx
index a11579b6..6f0aed0a 100644
--- a/common/rfb/SMsgWriterV3.cxx
+++ b/common/rfb/SMsgWriterV3.cxx
@@ -144,35 +144,135 @@ void SMsgWriterV3::writeSetXCursor(int width, int height, int hotspotX,
}
}
+bool SMsgWriterV3::needFakeUpdate()
+{
+ return wsccb || needSetDesktopName || needNoDataUpdate();
+}
+
+bool SMsgWriterV3::needNoDataUpdate()
+{
+ return needSetDesktopSize || needExtendedDesktopSize ||
+ !extendedDesktopSizeMsgs.empty();
+}
+
+void SMsgWriterV3::writeNoDataUpdate()
+{
+ int nRects;
+
+ nRects = 0;
+
+ if (needSetDesktopSize)
+ nRects++;
+ if (needExtendedDesktopSize)
+ nRects++;
+ if (!extendedDesktopSizeMsgs.empty())
+ nRects += extendedDesktopSizeMsgs.size();
+
+ writeFramebufferUpdateStart(nRects);
+ writeNoDataRects();
+ writeFramebufferUpdateEnd();
+}
+
void SMsgWriterV3::writeFramebufferUpdateStart(int nRects)
{
startMsg(msgTypeFramebufferUpdate);
os->pad(1);
- if (wsccb) nRects++;
- if (needSetDesktopSize) nRects++;
- if (needExtendedDesktopSize) nRects++;
- if (!extendedDesktopSizeMsgs.empty()) nRects += extendedDesktopSizeMsgs.size();
- if (needSetDesktopName) nRects++;
+
+ if (wsccb)
+ nRects++;
+ if (needSetDesktopName)
+ nRects++;
+
os->writeU16(nRects);
+
nRectsInUpdate = 0;
nRectsInHeader = nRects;
- if (wsccb) {
- wsccb->writeSetCursorCallback();
- wsccb = 0;
- }
+
+ writePseudoRects();
}
void SMsgWriterV3::writeFramebufferUpdateStart()
{
nRectsInUpdate = nRectsInHeader = 0;
+
if (!updateOS)
updateOS = new rdr::MemOutStream;
os = updateOS;
+
+ writePseudoRects();
}
void SMsgWriterV3::writeFramebufferUpdateEnd()
{
- /* Start with specific ExtendedDesktopSize messages */
+ if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
+ "nRects out of sync");
+
+ if (os == updateOS) {
+ os = realOS;
+ startMsg(msgTypeFramebufferUpdate);
+ os->pad(1);
+ os->writeU16(nRectsInUpdate);
+ os->writeBytes(updateOS->data(), updateOS->length());
+ updateOS->clear();
+ }
+
+ updatesSent++;
+ endMsg();
+}
+
+void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
+{
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3::startRect: nRects out of sync");
+
+ currentEncoding = encoding;
+ lenBeforeRect = os->length();
+ if (encoding != encodingCopyRect)
+ rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
+
+ os->writeS16(r.tl.x);
+ os->writeS16(r.tl.y);
+ os->writeU16(r.width());
+ os->writeU16(r.height());
+ os->writeU32(encoding);
+}
+
+void SMsgWriterV3::endRect()
+{
+ if (currentEncoding <= encodingMax) {
+ bytesSent[currentEncoding] += os->length() - lenBeforeRect;
+ rectsSent[currentEncoding]++;
+ }
+}
+
+void SMsgWriterV3::writePseudoRects()
+{
+ if (wsccb) {
+ wsccb->writeSetCursorCallback();
+ wsccb = 0;
+ }
+
+ if (needSetDesktopName) {
+ if (!cp->supportsDesktopRename)
+ throw Exception("Client does not support desktop rename");
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3 setDesktopName: nRects out of sync");
+
+ os->writeS16(0);
+ os->writeS16(0);
+ os->writeU16(0);
+ os->writeU16(0);
+ os->writeU32(pseudoEncodingDesktopName);
+ os->writeString(cp->name());
+
+ needSetDesktopName = false;
+ }
+}
+
+void SMsgWriterV3::writeNoDataRects()
+{
+ // Start with specific ExtendedDesktopSize messages
if (!extendedDesktopSizeMsgs.empty()) {
std::list<ExtendedDesktopSizeMsg>::const_iterator ri;
ScreenSet::const_iterator si;
@@ -205,12 +305,13 @@ void SMsgWriterV3::writeFramebufferUpdateEnd()
extendedDesktopSizeMsgs.clear();
}
- /* Send this before SetDesktopSize to make life easier on the clients */
+ // Send this before SetDesktopSize to make life easier on the clients
if (needExtendedDesktopSize) {
if (!cp->supportsExtendedDesktopSize)
throw Exception("Client does not support extended desktop resize");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriterV3 setExtendedDesktopSize: nRects out of sync");
+
os->writeU16(0);
os->writeU16(0);
os->writeU16(cp->width);
@@ -233,74 +334,21 @@ void SMsgWriterV3::writeFramebufferUpdateEnd()
needExtendedDesktopSize = false;
}
+ // Some clients assume this is the last rectangle so don't send anything
+ // more after this
if (needSetDesktopSize) {
if (!cp->supportsDesktopResize)
throw Exception("Client does not support desktop resize");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriterV3 setDesktopSize: nRects out of sync");
+
os->writeS16(0);
os->writeS16(0);
os->writeU16(cp->width);
os->writeU16(cp->height);
os->writeU32(pseudoEncodingDesktopSize);
- needSetDesktopSize = false;
- }
- if (needSetDesktopName) {
- if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
- throw Exception("SMsgWriterV3 setDesktopName: nRects out of sync");
- os->writeS16(0);
- os->writeS16(0);
- os->writeU16(0);
- os->writeU16(0);
- os->writeU32(pseudoEncodingDesktopName);
- os->writeString(cp->name());
- needSetDesktopName = false;
- }
-
- if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
- throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
- "nRects out of sync");
- if (os == updateOS) {
- os = realOS;
- startMsg(msgTypeFramebufferUpdate);
- os->pad(1);
- os->writeU16(nRectsInUpdate);
- os->writeBytes(updateOS->data(), updateOS->length());
- updateOS->clear();
+ needSetDesktopSize = false;
}
-
- updatesSent++;
- endMsg();
-}
-
-bool SMsgWriterV3::needFakeUpdate()
-{
- return wsccb || needSetDesktopSize || needExtendedDesktopSize ||
- !extendedDesktopSizeMsgs.empty() || needSetDesktopName;
-}
-
-void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
-{
- if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
- throw Exception("SMsgWriterV3::startRect: nRects out of sync");
-
- currentEncoding = encoding;
- lenBeforeRect = os->length();
- if (encoding != encodingCopyRect)
- rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
-
- os->writeS16(r.tl.x);
- os->writeS16(r.tl.y);
- os->writeU16(r.width());
- os->writeU16(r.height());
- os->writeU32(encoding);
}
-void SMsgWriterV3::endRect()
-{
- if (currentEncoding <= encodingMax) {
- bytesSent[currentEncoding] += os->length() - lenBeforeRect;
- rectsSent[currentEncoding]++;
- }
-}
diff --git a/common/rfb/SMsgWriterV3.h b/common/rfb/SMsgWriterV3.h
index e86c828c..5e0a3f1b 100644
--- a/common/rfb/SMsgWriterV3.h
+++ b/common/rfb/SMsgWriterV3.h
@@ -46,13 +46,19 @@ namespace rfb {
void* data, void* mask);
virtual void writeSetXCursor(int width, int height, int hotspotX,
int hotspotY, void* data, void* mask);
+ virtual bool needFakeUpdate();
+ virtual bool needNoDataUpdate();
+ virtual void writeNoDataUpdate();
virtual void writeFramebufferUpdateStart(int nRects);
virtual void writeFramebufferUpdateStart();
virtual void writeFramebufferUpdateEnd();
- virtual bool needFakeUpdate();
virtual void startRect(const Rect& r, unsigned int encoding);
virtual void endRect();
+ protected:
+ virtual void writePseudoRects();
+ virtual void writeNoDataRects();
+
private:
rdr::MemOutStream* updateOS;
rdr::OutStream* realOS;
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index cc7c9e8e..9b4d38ef 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -501,16 +501,22 @@ void VNCSConnectionST::clientCutText(const char* str, int len)
void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
{
+ Rect safeRect;
+
if (!(accessRights & AccessView)) return;
SConnection::framebufferUpdateRequest(r, incremental);
+ vlog.info("FramebufferUpdateRequest %dx%d at %d,%d %sincr",
+ r.width(), r.height(), r.tl.x, r.tl.y, incremental ? "" : "non-");
+
// Check that the client isn't sending crappy requests
if (!r.enclosed_by(Rect(0, 0, cp.width, cp.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);
- // We crop the size later in writeFramebufferUpdate() so no need to
- // do so now.
+ safeRect = r.intersect(Rect(0, 0, cp.width, cp.height));
+ } else {
+ safeRect = r;
}
// Just update the requested region.
@@ -623,12 +629,16 @@ void VNCSConnectionST::writeSetCursorCallback()
void VNCSConnectionST::writeFramebufferUpdate()
{
- // The framebuffer might have changed size since the
- // FramebufferUpdateRequest message was received. Clip it to the current
- // size of the framebuffer.
- requested = requested.intersect(Region(Rect(0, 0, cp.width, cp.height)));
+ if (state() != RFBSTATE_NORMAL || requested.is_empty())
+ return;
- if (state() != RFBSTATE_NORMAL || requested.is_empty()) return;
+ // First take care of any updates that cannot contain framebuffer data
+ // changes.
+ if (writer()->needNoDataUpdate()) {
+ writer()->writeNoDataUpdate();
+ requested.clear();
+ return;
+ }
updates.enable_copyrect(cp.useCopyRect);