diff options
-rw-r--r-- | common/rfb/SMsgWriter.cxx | 22 | ||||
-rw-r--r-- | common/rfb/SMsgWriter.h | 13 | ||||
-rw-r--r-- | common/rfb/SMsgWriterV3.cxx | 184 | ||||
-rw-r--r-- | common/rfb/SMsgWriterV3.h | 8 | ||||
-rw-r--r-- | common/rfb/VNCSConnectionST.cxx | 24 |
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); |