diff options
Diffstat (limited to 'common/rfb')
129 files changed, 2155 insertions, 5410 deletions
diff --git a/common/rfb/Blacklist.cxx b/common/rfb/Blacklist.cxx index 68420ae2..19a9ed39 100644 --- a/common/rfb/Blacklist.cxx +++ b/common/rfb/Blacklist.cxx @@ -21,24 +21,26 @@ #endif #include <rfb/Blacklist.h> -#include <rfb/Configuration.h> +#include <core/Configuration.h> using namespace rfb; -BoolParameter enabled("UseBlacklist", - "Temporarily reject connections from a host if it " - "repeatedly fails to authenticate.", - true); -IntParameter threshold("BlacklistThreshold", - "The number of unauthenticated connection attempts " - "allowed from any individual host before that host " - "is black-listed", - 5); -IntParameter initialTimeout("BlacklistTimeout", - "The initial timeout applied when a host is " - "first black-listed. The host cannot re-attempt " - "a connection until the timeout expires.", - 10); +core::BoolParameter enabled("UseBlacklist", + "Temporarily reject connections from a " + "host if it repeatedly fails to " + "authenticate.", + true); +core::IntParameter threshold("BlacklistThreshold", + "The number of unauthenticated connection " + "attempts allowed from any individual " + "host before that host is black-listed", + 5, 0, INT_MAX); +core::IntParameter initialTimeout("BlacklistTimeout", + "The initial timeout applied when a " + "host is first black-listed. The " + "host cannot re-attempt a connection " + "until the timeout expires.", + 10, 0, INT_MAX); Blacklist::Blacklist() { diff --git a/common/rfb/Blacklist.h b/common/rfb/Blacklist.h index c1699f29..3c9660cc 100644 --- a/common/rfb/Blacklist.h +++ b/common/rfb/Blacklist.h @@ -27,13 +27,11 @@ #ifndef __RFB_BLACKLIST_H__ #define __RFB_BLACKLIST_H__ -#include <string.h> #include <time.h> + #include <map> #include <string> -#include <rfb/Configuration.h> - namespace rfb { // diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx index 5e7530c8..bbeef385 100644 --- a/common/rfb/CConnection.cxx +++ b/common/rfb/CConnection.cxx @@ -27,31 +27,34 @@ #include <algorithm> +#include <core/LogWriter.h> +#include <core/string.h> + #include <rfb/Exception.h> #include <rfb/clipboardTypes.h> #include <rfb/fenceTypes.h> +#include <rfb/screenTypes.h> #include <rfb/CMsgReader.h> #include <rfb/CMsgWriter.h> #include <rfb/CSecurity.h> +#include <rfb/Cursor.h> #include <rfb/Decoder.h> #include <rfb/KeysymStr.h> +#include <rfb/PixelBuffer.h> #include <rfb/Security.h> #include <rfb/SecurityClient.h> #include <rfb/CConnection.h> -#include <rfb/util.h> #define XK_MISCELLANY #define XK_XKB_KEYS #include <rfb/keysymdef.h> -#include <rfb/LogWriter.h> - #include <rdr/InStream.h> #include <rdr/OutStream.h> using namespace rfb; -static LogWriter vlog("CConnection"); +static core::LogWriter vlog("CConnection"); CConnection::CConnection() : csecurity(nullptr), @@ -98,7 +101,7 @@ void CConnection::setFramebuffer(ModifiablePixelBuffer* fb) } if ((framebuffer != nullptr) && (fb != nullptr)) { - Rect rect; + core::Rect rect; const uint8_t* data; int stride; @@ -107,9 +110,8 @@ void CConnection::setFramebuffer(ModifiablePixelBuffer* fb) // Copy still valid area - rect.setXYWH(0, 0, - __rfbmin(fb->width(), framebuffer->width()), - __rfbmin(fb->height(), framebuffer->height())); + rect = fb->getRect(); + rect = rect.intersect(framebuffer->getRect()); data = framebuffer->getBuffer(framebuffer->getRect(), &stride); fb->imageRect(rect, data, stride); @@ -189,10 +191,9 @@ bool CConnection::processVersionMsg() vlog.error("Server gave unsupported RFB protocol version %d.%d", server.majorVersion, server.minorVersion); state_ = RFBSTATE_INVALID; - throw protocol_error(format("Server gave unsupported RFB protocol " - "version %d.%d", - server.majorVersion, - server.minorVersion)); + throw protocol_error( + core::format("Server gave unsupported RFB protocol version %d.%d", + server.majorVersion, server.minorVersion)); } else if (server.beforeVersion(3,7)) { server.setVersion(3,3); } else if (server.afterVersion(3,8)) { @@ -379,7 +380,6 @@ void CConnection::securityCompleted() reader_ = new CMsgReader(this, is); writer_ = new CMsgWriter(&server, os); vlog.debug("Authentication success!"); - authSuccess(); writer_->writeClientInit(shared); } @@ -410,7 +410,7 @@ void CConnection::setDesktopSize(int w, int h) { decoder.flush(); - CMsgHandler::setDesktopSize(w,h); + server.setDimensions(w, h); if (continuousUpdates) writer()->writeEnableContinuousUpdates(true, 0, 0, @@ -430,7 +430,15 @@ void CConnection::setExtendedDesktopSize(unsigned reason, { decoder.flush(); - CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout); + server.supportsSetDesktopSize = true; + + if ((reason != reasonClient) || (result == resultSuccess)) + server.setDimensions(w, h, layout); + + if ((reason == reasonClient) && (result != resultSuccess)) { + vlog.error("SetDesktopSize failed: %d", result); + return; + } if (continuousUpdates) writer()->writeEnableContinuousUpdates(true, 0, 0, @@ -443,9 +451,41 @@ void CConnection::setExtendedDesktopSize(unsigned reason, assert(framebuffer->height() == server.height()); } +void CConnection::setCursor(int width, int height, + const core::Point& hotspot, + const uint8_t* data) +{ + Cursor cursor(width, height, hotspot, data); + server.setCursor(cursor); +} + +void CConnection::setCursorPos(const core::Point& /*pos*/) +{ +} + +void CConnection::setName(const char* name) +{ + server.setName(name); +} + +void CConnection::fence(uint32_t flags, unsigned len, const uint8_t data[]) +{ + server.supportsFence = true; + + if (flags & fenceFlagRequest) { + // FIXME: We handle everything synchronously, and we assume anything + // using us also does so, which means we automatically handle + // these flags + flags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter); + + writer()->writeFence(flags, len, data); + return; + } +} + void CConnection::endOfContinuousUpdates() { - CMsgHandler::endOfContinuousUpdates(); + server.supportsContinuousUpdates = true; // We've gotten the marker for a format change, so make the pending // one active @@ -459,11 +499,23 @@ void CConnection::endOfContinuousUpdates() } } +void CConnection::supportsQEMUKeyEvent() +{ + server.supportsQEMUKeyEvent = true; +} + +void CConnection::supportsExtendedMouseButtons() +{ + server.supportsExtendedMouseButtons = true; +} + void CConnection::serverInit(int width, int height, const PixelFormat& pf, const char* name) { - CMsgHandler::serverInit(width, height, pf, name); + server.setDimensions(width, height); + server.setPF(pf); + server.setName(name); state_ = RFBSTATE_NORMAL; vlog.debug("Initialisation done"); @@ -486,7 +538,7 @@ void CConnection::serverInit(int width, int height, } } -bool CConnection::readAndDecodeRect(const Rect& r, int encoding, +bool CConnection::readAndDecodeRect(const core::Rect& r, int encoding, ModifiablePixelBuffer* pb) { if (!decoder.decodeRect(r, encoding, pb)) @@ -497,8 +549,6 @@ bool CConnection::readAndDecodeRect(const Rect& r, int encoding, void CConnection::framebufferUpdateStart() { - CMsgHandler::framebufferUpdateStart(); - assert(framebuffer != nullptr); // Note: This might not be true if continuous updates are supported @@ -511,8 +561,6 @@ 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) { @@ -533,11 +581,18 @@ void CConnection::framebufferUpdateEnd() } } -bool CConnection::dataRect(const Rect& r, int encoding) +bool CConnection::dataRect(const core::Rect& r, int encoding) { return decoder.decodeRect(r, encoding, framebuffer); } +void CConnection::setColourMapEntries(int /*firstColour*/, + int /*nColours*/, + uint16_t* /*rgbs*/) +{ + vlog.error("Invalid SetColourMapEntries from server!"); +} + void CConnection::serverCutText(const char* str) { hasLocalClipboard = false; @@ -548,12 +603,53 @@ void CConnection::serverCutText(const char* str) handleClipboardAnnounce(true); } +void CConnection::setLEDState(unsigned int state) +{ + server.setLEDState(state); +} + void CConnection::handleClipboardCaps(uint32_t flags, const uint32_t* lengths) { + int i; uint32_t sizes[] = { 0 }; - CMsgHandler::handleClipboardCaps(flags, lengths); + vlog.debug("Got server clipboard capabilities:"); + for (i = 0;i < 16;i++) { + if (flags & (1 << i)) { + const char *type; + + switch (1 << i) { + case clipboardUTF8: + type = "Plain text"; + break; + case clipboardRTF: + type = "Rich text"; + break; + case clipboardHTML: + type = "HTML"; + break; + case clipboardDIB: + type = "Images"; + break; + case clipboardFiles: + type = "Files"; + break; + default: + vlog.debug(" Unknown format 0x%x", 1 << i); + continue; + } + + if (lengths[i] == 0) + vlog.debug(" %s (only notify)", type); + else { + vlog.debug(" %s (automatically send up to %s)", + type, core::iecPrefix(lengths[i], "B").c_str()); + } + } + } + + server.setClipboardCaps(flags, lengths); writer()->writeClipboardCaps(rfb::clipboardUTF8 | rfb::clipboardRequest | @@ -604,21 +700,17 @@ void CConnection::handleClipboardProvide(uint32_t flags, } // FIXME: This conversion magic should be in CMsgReader - if (!isValidUTF8((const char*)data[0], lengths[0])) { + if (!core::isValidUTF8((const char*)data[0], lengths[0])) { vlog.error("Invalid UTF-8 sequence in clipboard - ignoring"); return; } - serverClipboard = convertLF((const char*)data[0], lengths[0]); + serverClipboard = core::convertLF((const char*)data[0], lengths[0]); hasRemoteClipboard = true; // FIXME: Should probably verify that this data was actually requested handleClipboardData(serverClipboard.c_str()); } -void CConnection::authSuccess() -{ -} - void CConnection::initDone() { } @@ -679,7 +771,7 @@ void CConnection::sendClipboardData(const char* data) { if (server.clipboardFlags() & rfb::clipboardProvide) { // FIXME: This conversion magic should be in CMsgWriter - std::string filtered(convertCRLF(data)); + std::string filtered(core::convertCRLF(data)); size_t sizes[1] = { filtered.size() + 1 }; const uint8_t* datas[1] = { (const uint8_t*)filtered.c_str() }; @@ -815,6 +907,11 @@ void CConnection::setCompressLevel(int level) encodingChange = true; } +int CConnection::getCompressLevel() +{ + return compressLevel; +} + void CConnection::setQualityLevel(int level) { if (qualityLevel == level) @@ -824,6 +921,11 @@ void CConnection::setQualityLevel(int level) encodingChange = true; } +int CConnection::getQualityLevel() +{ + return qualityLevel; +} + void CConnection::setPF(const PixelFormat& pf) { if (server.pf() == pf && !formatChange) @@ -833,17 +935,9 @@ void CConnection::setPF(const PixelFormat& pf) formatChange = true; } -void CConnection::fence(uint32_t flags, unsigned len, const uint8_t data[]) +bool CConnection::isSecure() const { - CMsgHandler::fence(flags, len, data); - - if (!(flags & fenceFlagRequest)) - return; - - // We cannot guarantee any synchronisation at this level - flags = 0; - - writer()->writeFence(flags, len, data); + return csecurity ? csecurity->isSecure() : false; } // requestNewUpdate() requests an update from the server, having set the @@ -884,9 +978,9 @@ void CConnection::requestNewUpdate() if (forceNonincremental || !continuousUpdates) { pendingUpdate = true; - writer()->writeFramebufferUpdateRequest(Rect(0, 0, - server.width(), - server.height()), + writer()->writeFramebufferUpdateRequest({0, 0, + server.width(), + server.height()}, !forceNonincremental); } diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h index 07e47e39..b28c5aa9 100644 --- a/common/rfb/CConnection.h +++ b/common/rfb/CConnection.h @@ -29,8 +29,14 @@ #include <rfb/CMsgHandler.h> #include <rfb/DecodeManager.h> +#include <rfb/PixelFormat.h> #include <rfb/SecurityClient.h> +namespace rdr { + class InStream; + class OutStream; +} + namespace rfb { class CMsgReader; @@ -99,89 +105,6 @@ namespace rfb { // connection void close(); - - // Methods overridden from CMsgHandler - - // Note: These must be called by any deriving classes - - void setDesktopSize(int w, int h) override; - void setExtendedDesktopSize(unsigned reason, unsigned result, - int w, int h, - const ScreenSet& layout) override; - - void endOfContinuousUpdates() override; - - void serverInit(int width, int height, const PixelFormat& pf, - const char* name) override; - - bool readAndDecodeRect(const Rect& r, int encoding, - ModifiablePixelBuffer* pb) override; - - void framebufferUpdateStart() override; - void framebufferUpdateEnd() override; - bool dataRect(const Rect& r, int encoding) override; - - void serverCutText(const char* str) override; - - void handleClipboardCaps(uint32_t flags, - const uint32_t* lengths) override; - void handleClipboardRequest(uint32_t flags) override; - void handleClipboardPeek() override; - void handleClipboardNotify(uint32_t flags) override; - void handleClipboardProvide(uint32_t flags, const size_t* lengths, - const uint8_t* const* data) override; - - - // Methods to be overridden in a derived class - - // getUserPasswd() gets the username and password. This might - // involve a dialog, getpass(), etc. The user buffer pointer can be - // null, in which case no user name will be retrieved. - virtual void getUserPasswd(bool secure, std::string* user, - std::string* password) = 0; - - // showMsgBox() displays a message box with the specified style and - // contents. The return value is true if the user clicked OK/Yes. - virtual bool showMsgBox(MsgBoxFlags flags, const char *title, - const char *text) = 0; - - // authSuccess() is called when authentication has succeeded. - virtual void authSuccess(); - - // 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(); - - // handleClipboardRequest() is called whenever the server requests - // the client to send over its clipboard data. It will only be - // called after the client has first announced a clipboard change - // via announceClipboard(). - virtual void handleClipboardRequest(); - - // handleClipboardAnnounce() is called to indicate a change in the - // clipboard on the server. Call requestClipboard() to access the - // actual data. - virtual void handleClipboardAnnounce(bool available); - - // handleClipboardData() is called when the server has sent over - // the clipboard data as a result of a previous call to - // requestClipboard(). Note that this function might never be - // called if the clipboard data was no longer available when the - // server received the request. - virtual void handleClipboardData(const char* data); - - - // Other methods - // requestClipboard() will result in a request to the server to // transfer its clipboard data. A call to handleClipboardData() // will be made once the data is available. @@ -221,7 +144,9 @@ namespace rfb { // setCompressLevel()/setQualityLevel() controls the encoding hints // sent to the server void setCompressLevel(int level); + int getCompressLevel(); void setQualityLevel(int level); + int getQualityLevel(); // setPF() controls the pixel format requested from the server. // server.pf() will automatically be adjusted once the new format // is active. @@ -237,7 +162,7 @@ namespace rfb { // Identities, to determine the unique(ish) name of the server. const char* getServerName() const { return serverName.c_str(); } - bool isSecure() const { return csecurity ? csecurity->isSecure() : false; } + bool isSecure() const; enum stateEnum { RFBSTATE_UNINITIALISED, @@ -254,8 +179,107 @@ namespace rfb { stateEnum state() { return state_; } + // Methods used by SSecurity classes + + // getUserPasswd() gets the username and password. This might + // involve a dialog, getpass(), etc. The user buffer pointer can be + // null, in which case no user name will be retrieved. + virtual void getUserPasswd(bool secure, std::string* user, + std::string* password) = 0; + + // showMsgBox() displays a message box with the specified style and + // contents. The return value is true if the user clicked OK/Yes. + virtual bool showMsgBox(MsgBoxFlags flags, const char *title, + const char *text) = 0; + + protected: + + // Methods overridden from CMsgHandler + + // Note: These must be called by any deriving classes + + void setDesktopSize(int w, int h) override; + void setExtendedDesktopSize(unsigned reason, unsigned result, + int w, int h, + const ScreenSet& layout) override; + + void setCursor(int width, int height, const core::Point& hotspot, + const uint8_t* data) override; + void setCursorPos(const core::Point& pos) override; + + void setName(const char* name) override; + + void fence(uint32_t flags, unsigned len, const uint8_t data[]) override; + + void endOfContinuousUpdates() override; + + void supportsQEMUKeyEvent() override; + + void supportsExtendedMouseButtons() override; + + void serverInit(int width, int height, const PixelFormat& pf, + const char* name) override; + + bool readAndDecodeRect(const core::Rect& r, int encoding, + ModifiablePixelBuffer* pb) override; + + void framebufferUpdateStart() override; + void framebufferUpdateEnd() override; + bool dataRect(const core::Rect& r, int encoding) override; + + void setColourMapEntries(int firstColour, int nColours, + uint16_t* rgbs) override; + + void serverCutText(const char* str) override; + + void setLEDState(unsigned int state) override; + + void handleClipboardCaps(uint32_t flags, + const uint32_t* lengths) override; + void handleClipboardRequest(uint32_t flags) override; + void handleClipboardPeek() override; + void handleClipboardNotify(uint32_t flags) override; + void handleClipboardProvide(uint32_t flags, const size_t* lengths, + const uint8_t* const* data) override; + + + // Methods to be overridden in a derived class + + // 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(); + + // handleClipboardRequest() is called whenever the server requests + // the client to send over its clipboard data. It will only be + // called after the client has first announced a clipboard change + // via announceClipboard(). + virtual void handleClipboardRequest(); + + // handleClipboardAnnounce() is called to indicate a change in the + // clipboard on the server. Call requestClipboard() to access the + // actual data. + virtual void handleClipboardAnnounce(bool available); + + // handleClipboardData() is called when the server has sent over + // the clipboard data as a result of a previous call to + // requestClipboard(). Note that this function might never be + // called if the clipboard data was no longer available when the + // server received the request. + virtual void handleClipboardData(const char* data); + + protected: CSecurity *csecurity; SecurityClient security; + protected: void setState(stateEnum s) { state_ = s; } @@ -273,13 +297,6 @@ namespace rfb { bool supportsLEDState; private: - // This is a default implementation of fences that automatically - // responds to requests, stating no support for synchronisation. - // When overriding, call CMsgHandler::fence() directly in order to - // state correct support for fence flags. - void fence(uint32_t flags, unsigned len, const uint8_t data[]) override; - - private: bool processVersionMsg(); bool processSecurityTypesMsg(); bool processSecurityMsg(); diff --git a/common/rfb/CMakeLists.txt b/common/rfb/CMakeLists.txt index 36535448..d7467421 100644 --- a/common/rfb/CMakeLists.txt +++ b/common/rfb/CMakeLists.txt @@ -3,7 +3,6 @@ add_library(rfb STATIC Blacklist.cxx Congestion.cxx CConnection.cxx - CMsgHandler.cxx CMsgReader.cxx CMsgWriter.cxx CSecurityPlain.cxx @@ -12,7 +11,6 @@ add_library(rfb STATIC CSecurityVncAuth.cxx ClientParams.cxx ComparingUpdateTracker.cxx - Configuration.cxx CopyRectDecoder.cxx Cursor.cxx DecodeManager.cxx @@ -26,19 +24,13 @@ add_library(rfb STATIC JpegDecompressor.cxx KeyRemapper.cxx KeysymStr.c - LogWriter.cxx - Logger.cxx - Logger_file.cxx - Logger_stdio.cxx PixelBuffer.cxx PixelFormat.cxx RREEncoder.cxx RREDecoder.cxx RawDecoder.cxx RawEncoder.cxx - Region.cxx SConnection.cxx - SMsgHandler.cxx SMsgReader.cxx SMsgWriter.cxx ServerCore.cxx @@ -50,7 +42,6 @@ add_library(rfb STATIC SSecurityStack.cxx SSecurityVncAuth.cxx SSecurityVeNCrypt.cxx - Timer.cxx TightDecoder.cxx TightEncoder.cxx TightJPEGEncoder.cxx @@ -60,15 +51,12 @@ add_library(rfb STATIC ZRLEEncoder.cxx ZRLEDecoder.cxx encodings.cxx - obfuscate.cxx - util.cxx) + obfuscate.cxx) target_include_directories(rfb PUBLIC ${CMAKE_SOURCE_DIR}/common) target_include_directories(rfb SYSTEM PUBLIC ${JPEG_INCLUDE_DIR}) -target_include_directories(rfb SYSTEM PUBLIC ${PIXMAN_INCLUDE_DIRS}) -target_link_libraries(rfb os rdr network) +target_link_libraries(rfb core rdr network) target_link_libraries(rfb ${JPEG_LIBRARIES} ${PIXMAN_LIBRARIES}) -target_link_directories(rfb PUBLIC ${PIXMAN_LIBRARY_DIRS}) if(ENABLE_H264 AND NOT H264_LIBS STREQUAL "NONE") target_sources(rfb PRIVATE H264Decoder.cxx H264DecoderContext.cxx) @@ -79,11 +67,6 @@ if(ENABLE_H264 AND NOT H264_LIBS STREQUAL "NONE") endif() target_include_directories(rfb SYSTEM PUBLIC ${H264_INCLUDE_DIRS}) target_link_libraries(rfb ${H264_LIBRARIES}) - target_link_directories(rfb PUBLIC ${H264_LIBRARY_DIRS}) -endif() - -if(UNIX) - target_sources(rfb PRIVATE Logger_syslog.cxx) endif() if(WIN32) @@ -92,8 +75,9 @@ if(WIN32) endif(WIN32) if(UNIX AND NOT APPLE) - target_sources(rfb PRIVATE UnixPasswordValidator.cxx pam.c) - target_link_libraries(rfb ${PAM_LIBS}) + target_sources(rfb PRIVATE UnixPasswordValidator.cxx) + target_include_directories(rfb SYSTEM PRIVATE ${PAM_INCLUDE_DIRS}) + target_link_libraries(rfb ${PAM_LIBRARIES}) endif() if(GNUTLS_FOUND) @@ -109,12 +93,8 @@ endif() if (NETTLE_FOUND) target_sources(rfb PRIVATE CSecurityDH.cxx CSecurityMSLogonII.cxx CSecurityRSAAES.cxx SSecurityRSAAES.cxx) - target_include_directories(rfb SYSTEM PUBLIC ${NETTLE_INCLUDE_DIRS} - ${GMP_INCLUDE_DIRS}) - target_link_libraries(rfb ${HOGWEED_LIBRARIES} - ${NETTLE_LIBRARIES} ${GMP_LIBRARIES}) - target_link_directories(rfb PUBLIC ${HOGWEED_LIBRARY_DIRS} - ${NETTLE_LIBRARY_DIRS} ${GMP_LIBRARY_DIRS}) + target_include_directories(rfb SYSTEM PUBLIC ${NETTLE_INCLUDE_DIRS}) + target_link_libraries(rfb ${HOGWEED_LIBRARIES} ${NETTLE_LIBRARIES}) endif() if(UNIX) diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx deleted file mode 100644 index 0f3f6cd5..00000000 --- a/common/rfb/CMsgHandler.cxx +++ /dev/null @@ -1,168 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2019 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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> - -#include <rfb/Exception.h> -#include <rfb/LogWriter.h> -#include <rfb/CMsgHandler.h> -#include <rfb/clipboardTypes.h> -#include <rfb/screenTypes.h> -#include <rfb/util.h> - -static rfb::LogWriter vlog("CMsgHandler"); - -using namespace rfb; - -CMsgHandler::CMsgHandler() -{ -} - -CMsgHandler::~CMsgHandler() -{ -} - -void CMsgHandler::setDesktopSize(int width, int height) -{ - server.setDimensions(width, height); -} - -void CMsgHandler::setExtendedDesktopSize(unsigned reason, unsigned result, - int width, int height, - const ScreenSet& layout) -{ - server.supportsSetDesktopSize = true; - - if ((reason == reasonClient) && (result != resultSuccess)) - return; - - server.setDimensions(width, height, layout); -} - -void CMsgHandler::setName(const char* name) -{ - server.setName(name); -} - -void CMsgHandler::fence(uint32_t /*flags*/, unsigned /*len*/, - const uint8_t /*data*/ []) -{ - server.supportsFence = true; -} - -void CMsgHandler::endOfContinuousUpdates() -{ - server.supportsContinuousUpdates = true; -} - -void CMsgHandler::supportsExtendedMouseButtons() -{ - server.supportsExtendedMouseButtons = true; -} - -void CMsgHandler::supportsQEMUKeyEvent() -{ - 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() -{ -} - -void CMsgHandler::framebufferUpdateEnd() -{ -} - -void CMsgHandler::setLEDState(unsigned int state) -{ - server.setLEDState(state); -} - -void CMsgHandler::handleClipboardCaps(uint32_t flags, const uint32_t* lengths) -{ - int i; - - vlog.debug("Got server clipboard capabilities:"); - for (i = 0;i < 16;i++) { - if (flags & (1 << i)) { - const char *type; - - switch (1 << i) { - case clipboardUTF8: - type = "Plain text"; - break; - case clipboardRTF: - type = "Rich text"; - break; - case clipboardHTML: - type = "HTML"; - break; - case clipboardDIB: - type = "Images"; - break; - case clipboardFiles: - type = "Files"; - break; - default: - vlog.debug(" Unknown format 0x%x", 1 << i); - continue; - } - - if (lengths[i] == 0) - vlog.debug(" %s (only notify)", type); - else { - vlog.debug(" %s (automatically send up to %s)", - type, iecPrefix(lengths[i], "B").c_str()); - } - } - } - - server.setClipboardCaps(flags, lengths); -} - -void CMsgHandler::handleClipboardRequest(uint32_t /*flags*/) -{ -} - -void CMsgHandler::handleClipboardPeek() -{ -} - -void CMsgHandler::handleClipboardNotify(uint32_t /*flags*/) -{ -} - -void CMsgHandler::handleClipboardProvide(uint32_t /*flags*/, - const size_t* /*lengths*/, - const uint8_t* const* /*data*/) -{ -} diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h index b484b695..d267ae47 100644 --- a/common/rfb/CMsgHandler.h +++ b/common/rfb/CMsgHandler.h @@ -27,63 +27,62 @@ #include <stdint.h> #include <rfb/ServerParams.h> -#include <rfb/Rect.h> -#include <rfb/ScreenSet.h> -namespace rdr { class InStream; } +namespace core { + struct Point; + struct Rect; +} namespace rfb { + class ModifiablePixelBuffer; + struct ScreenSet; + class CMsgHandler { public: - CMsgHandler(); - virtual ~CMsgHandler(); - // 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(), - // setName(), serverInit() and handleClipboardCaps() methods, a - // derived class should call on to CMsgHandler's methods to set the - // members of "server" appropriately. + // read. A derived class must override these methods. - virtual void setDesktopSize(int w, int h); + virtual void setDesktopSize(int w, int h) = 0; virtual void setExtendedDesktopSize(unsigned reason, unsigned result, int w, int h, - const ScreenSet& layout); - virtual void setCursor(int width, int height, const Point& hotspot, + const ScreenSet& layout) = 0; + virtual void setCursor(int width, int height, const + core::Point& hotspot, const uint8_t* data) = 0; - virtual void setCursorPos(const Point& pos) = 0; - virtual void setName(const char* name); - virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]); - virtual void endOfContinuousUpdates(); - virtual void supportsQEMUKeyEvent(); - virtual void supportsExtendedMouseButtons(); + virtual void setCursorPos(const core::Point& pos) = 0; + virtual void setName(const char* name) = 0; + virtual void fence(uint32_t flags, unsigned len, + const uint8_t data[]) = 0; + virtual void endOfContinuousUpdates() = 0; + virtual void supportsQEMUKeyEvent() = 0; + virtual void supportsExtendedMouseButtons() = 0; virtual void serverInit(int width, int height, const PixelFormat& pf, const char* name) = 0; - virtual bool readAndDecodeRect(const Rect& r, int encoding, + virtual bool readAndDecodeRect(const core::Rect& r, int encoding, ModifiablePixelBuffer* pb) = 0; - virtual void framebufferUpdateStart(); - virtual void framebufferUpdateEnd(); - virtual bool dataRect(const Rect& r, int encoding) = 0; + virtual void framebufferUpdateStart() = 0; + virtual void framebufferUpdateEnd() = 0; + virtual bool dataRect(const core::Rect& r, int encoding) = 0; virtual void setColourMapEntries(int firstColour, int nColours, uint16_t* rgbs) = 0; virtual void bell() = 0; virtual void serverCutText(const char* str) = 0; - virtual void setLEDState(unsigned int state); + virtual void setLEDState(unsigned int state) = 0; virtual void handleClipboardCaps(uint32_t flags, - const uint32_t* lengths); - virtual void handleClipboardRequest(uint32_t flags); - virtual void handleClipboardPeek(); - virtual void handleClipboardNotify(uint32_t flags); + const uint32_t* lengths) = 0; + virtual void handleClipboardRequest(uint32_t flags) = 0; + virtual void handleClipboardPeek() = 0; + virtual void handleClipboardNotify(uint32_t flags) = 0; virtual void handleClipboardProvide(uint32_t flags, const size_t* lengths, - const uint8_t* const* data); + const uint8_t* const* data) = 0; ServerParams server; }; diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx index a10f7c47..a5e28ea5 100644 --- a/common/rfb/CMsgReader.cxx +++ b/common/rfb/CMsgReader.cxx @@ -26,20 +26,27 @@ #include <vector> +#include <core/LogWriter.h> +#include <core/string.h> + #include <rdr/InStream.h> #include <rdr/ZlibInStream.h> #include <rfb/msgTypes.h> #include <rfb/clipboardTypes.h> -#include <rfb/util.h> #include <rfb/Exception.h> -#include <rfb/LogWriter.h> #include <rfb/CMsgHandler.h> #include <rfb/CMsgReader.h> +#include <rfb/PixelBuffer.h> +#include <rfb/ScreenSet.h> +#include <rfb/encodings.h> -static rfb::LogWriter vlog("CMsgReader"); +static core::LogWriter vlog("CMsgReader"); -static rfb::IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024); +static core::IntParameter maxCutText("MaxCutText", + "Maximum permitted length of an " + "incoming clipboard update", + 256*1024, 0, INT_MAX); using namespace rfb; @@ -77,11 +84,11 @@ bool CMsgReader::readServerInit() is->readBytes((uint8_t*)name.data(), len); name[len] = '\0'; - if (isValidUTF8(name.data())) + if (core::isValidUTF8(name.data())) handler->serverInit(width, height, pf, name.data()); else handler->serverInit(width, height, pf, - latin1ToUTF8(name.data()).c_str()); + core::latin1ToUTF8(name.data()).c_str()); return true; } @@ -119,7 +126,7 @@ bool CMsgReader::readMsg() ret = readEndOfContinuousUpdates(); break; default: - throw protocol_error(format("Unknown message type %d", currentMsgType)); + throw protocol_error(core::format("Unknown message type %d", currentMsgType)); } if (ret) @@ -288,8 +295,8 @@ bool CMsgReader::readServerCutText() std::vector<char> ca(len); is->readBytes((uint8_t*)ca.data(), len); - std::string utf8(latin1ToUTF8(ca.data(), ca.size())); - std::string filtered(convertLF(utf8.data(), utf8.size())); + std::string utf8(core::latin1ToUTF8(ca.data(), ca.size())); + std::string filtered(core::convertLF(utf8.data(), utf8.size())); handler->serverCutText(filtered.c_str()); @@ -470,7 +477,7 @@ bool CMsgReader::readFramebufferUpdate() return true; } -bool CMsgReader::readRect(const Rect& r, int encoding) +bool CMsgReader::readRect(const core::Rect& r, int encoding) { if ((r.br.x > handler->server.width()) || (r.br.y > handler->server.height())) { @@ -486,7 +493,8 @@ bool CMsgReader::readRect(const Rect& r, int encoding) return handler->dataRect(r, encoding); } -bool CMsgReader::readSetXCursor(int width, int height, const Point& hotspot) +bool CMsgReader::readSetXCursor(int width, int height, + const core::Point& hotspot) { if (width > maxCursorSize || height > maxCursorSize) throw protocol_error("Too big cursor"); @@ -550,7 +558,8 @@ bool CMsgReader::readSetXCursor(int width, int height, const Point& hotspot) return true; } -bool CMsgReader::readSetCursor(int width, int height, const Point& hotspot) +bool CMsgReader::readSetCursor(int width, int height, + const core::Point& hotspot) { if (width > maxCursorSize || height > maxCursorSize) throw protocol_error("Too big cursor"); @@ -596,7 +605,8 @@ bool CMsgReader::readSetCursor(int width, int height, const Point& hotspot) return true; } -bool CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hotspot) +bool CMsgReader::readSetCursorWithAlpha(int width, int height, + const core::Point& hotspot) { if (width > maxCursorSize || height > maxCursorSize) throw protocol_error("Too big cursor"); @@ -657,7 +667,8 @@ bool CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hots return true; } -bool CMsgReader::readSetVMwareCursor(int width, int height, const Point& hotspot) +bool CMsgReader::readSetVMwareCursor(int width, int height, + const core::Point& hotspot) { if (width > maxCursorSize || height > maxCursorSize) throw protocol_error("Too big cursor"); @@ -784,7 +795,7 @@ bool CMsgReader::readSetDesktopName(int x, int y, int w, int h) return true; } - if (!isValidUTF8(name.data())) { + if (!core::isValidUTF8(name.data())) { vlog.error("Ignoring DesktopName rect with invalid UTF-8 sequence"); return true; } diff --git a/common/rfb/CMsgReader.h b/common/rfb/CMsgReader.h index 3b1c0ddb..e33f701d 100644 --- a/common/rfb/CMsgReader.h +++ b/common/rfb/CMsgReader.h @@ -26,14 +26,13 @@ #include <stdint.h> -#include <rfb/Rect.h> -#include <rfb/encodings.h> +#include <core/Rect.h> namespace rdr { class InStream; } namespace rfb { + class CMsgHandler; - struct Rect; class CMsgReader { public: @@ -59,12 +58,16 @@ namespace rfb { bool readFramebufferUpdate(); - bool readRect(const Rect& r, int encoding); + bool readRect(const core::Rect& r, int encoding); - bool readSetXCursor(int width, int height, const Point& hotspot); - bool readSetCursor(int width, int height, const Point& hotspot); - bool readSetCursorWithAlpha(int width, int height, const Point& hotspot); - bool readSetVMwareCursor(int width, int height, const Point& hotspot); + bool readSetXCursor(int width, int height, + const core::Point& hotspot); + bool readSetCursor(int width, int height, + const core::Point& hotspot); + bool readSetCursorWithAlpha(int width, int height, + const core::Point& hotspot); + bool readSetVMwareCursor(int width, int height, + const core::Point& hotspot); bool readSetDesktopName(int x, int y, int w, int h); bool readExtendedDesktopSize(int x, int y, int w, int h); bool readLEDState(); @@ -85,12 +88,14 @@ namespace rfb { uint8_t currentMsgType; int nUpdateRectsLeft; - Rect dataRect; + core::Rect dataRect; int rectEncoding; int cursorEncoding; static const int maxCursorSize = 256; }; + } + #endif diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx index 0128c431..c592a25e 100644 --- a/common/rfb/CMsgWriter.cxx +++ b/common/rfb/CMsgWriter.cxx @@ -24,6 +24,9 @@ #include <stdio.h> #include <assert.h> +#include <core/Rect.h> +#include <core/string.h> + #include <rdr/OutStream.h> #include <rdr/MemOutStream.h> #include <rdr/ZlibOutStream.h> @@ -33,10 +36,9 @@ #include <rfb/qemuTypes.h> #include <rfb/clipboardTypes.h> #include <rfb/PixelFormat.h> -#include <rfb/Rect.h> +#include <rfb/ScreenSet.h> #include <rfb/ServerParams.h> #include <rfb/CMsgWriter.h> -#include <rfb/util.h> using namespace rfb; @@ -101,7 +103,8 @@ void CMsgWriter::writeSetDesktopSize(int width, int height, endMsg(); } -void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental) +void CMsgWriter::writeFramebufferUpdateRequest(const core::Rect& r, + bool incremental) { startMsg(msgTypeFramebufferUpdateRequest); os->writeU8(incremental); @@ -173,9 +176,10 @@ void CMsgWriter::writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down) } -void CMsgWriter::writePointerEvent(const Point& pos, uint16_t buttonMask) +void CMsgWriter::writePointerEvent(const core::Point& pos, + uint16_t buttonMask) { - Point p(pos); + core::Point p(pos); bool extendedMouseButtons; if (p.x < 0) p.x = 0; @@ -223,7 +227,7 @@ void CMsgWriter::writeClientCutText(const char* str) if (strchr(str, '\r') != nullptr) throw std::invalid_argument("Invalid carriage return in clipboard data"); - std::string latin1(utf8ToLatin1(str)); + std::string latin1(core::utf8ToLatin1(str)); startMsg(msgTypeClientCutText); os->pad(3); diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h index 9cb4adec..d0378e62 100644 --- a/common/rfb/CMsgWriter.h +++ b/common/rfb/CMsgWriter.h @@ -27,6 +27,11 @@ #include <stdint.h> +namespace core { + struct Point; + struct Rect; +} + namespace rdr { class OutStream; } namespace rfb { @@ -34,8 +39,6 @@ namespace rfb { class PixelFormat; class ServerParams; struct ScreenSet; - struct Point; - struct Rect; class CMsgWriter { public: @@ -48,13 +51,14 @@ namespace rfb { void writeSetEncodings(const std::list<uint32_t> encodings); void writeSetDesktopSize(int width, int height, const ScreenSet& layout); - void writeFramebufferUpdateRequest(const Rect& r,bool incremental); + void writeFramebufferUpdateRequest(const core::Rect& r, + bool incremental); void writeEnableContinuousUpdates(bool enable, int x, int y, int w, int h); void writeFence(uint32_t flags, unsigned len, const uint8_t data[]); void writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down); - void writePointerEvent(const Point& pos, uint16_t buttonMask); + void writePointerEvent(const core::Point& pos, uint16_t buttonMask); void writeClientCutText(const char* str); diff --git a/common/rfb/CSecurityDH.cxx b/common/rfb/CSecurityDH.cxx index 2f0365a6..93cf6b26 100644 --- a/common/rfb/CSecurityDH.cxx +++ b/common/rfb/CSecurityDH.cxx @@ -40,7 +40,6 @@ #include <rdr/OutStream.h> #include <rdr/RandomStream.h> #include <rfb/Exception.h> -#include <os/os.h> using namespace rfb; diff --git a/common/rfb/CSecurityMSLogonII.cxx b/common/rfb/CSecurityMSLogonII.cxx index a5a99286..dfc0b658 100644 --- a/common/rfb/CSecurityMSLogonII.cxx +++ b/common/rfb/CSecurityMSLogonII.cxx @@ -39,7 +39,6 @@ #include <rdr/InStream.h> #include <rdr/OutStream.h> #include <rdr/RandomStream.h> -#include <os/os.h> using namespace rfb; diff --git a/common/rfb/CSecurityRSAAES.cxx b/common/rfb/CSecurityRSAAES.cxx index 0985d0f2..513d5605 100644 --- a/common/rfb/CSecurityRSAAES.cxx +++ b/common/rfb/CSecurityRSAAES.cxx @@ -34,14 +34,17 @@ #include <nettle/bignum.h> #include <nettle/sha1.h> #include <nettle/sha2.h> + +#include <core/LogWriter.h> +#include <core/string.h> + #include <rfb/CSecurityRSAAES.h> #include <rfb/CConnection.h> -#include <rfb/LogWriter.h> #include <rfb/Exception.h> -#include <rfb/util.h> + #include <rdr/AESInStream.h> #include <rdr/AESOutStream.h> -#include <os/os.h> +#include <rdr/RandomStream.h> enum { ReadPublicKey, @@ -55,7 +58,7 @@ const int MaxKeyLength = 8192; using namespace rfb; -static LogWriter vlog("CSecurityRSAAES"); +static core::LogWriter vlog("CSecurityRSAAES"); CSecurityRSAAES::CSecurityRSAAES(CConnection* cc_, uint32_t _secType, int _keySize, bool _isAllEncrypted) @@ -147,12 +150,12 @@ bool CSecurityRSAAES::processMsg() return false; } -static void random_func(void* ctx, size_t length, uint8_t* dst) +static void random_func(void*, size_t length, uint8_t* dst) { - rdr::RandomStream* rs = (rdr::RandomStream*)ctx; - if (!rs->hasData(length)) + rdr::RandomStream rs; + if (!rs.hasData(length)) throw std::runtime_error("Failed to generate random"); - rs->readBytes(dst, length); + rs.readBytes(dst, length); } void CSecurityRSAAES::writePublicKey() @@ -170,7 +173,7 @@ void CSecurityRSAAES::writePublicKey() // set e = 65537 mpz_set_ui(clientPublicKey.e, 65537); if (!rsa_generate_keypair(&clientPublicKey, &clientKey, - &rs, random_func, nullptr, nullptr, + nullptr, random_func, nullptr, nullptr, clientKeyLength, 0)) throw std::runtime_error("Failed to generate key"); clientKeyN = new uint8_t[rsaKeySize]; @@ -226,7 +229,7 @@ void CSecurityRSAAES::verifyServer() sha1_update(&ctx, serverKey.size, serverKeyE); sha1_digest(&ctx, sizeof(f), f); const char *title = "Server key fingerprint"; - std::string text = format( + std::string text = core::format( "The server has provided the following identifying information:\n" "Fingerprint: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n" "Please verify that the information is correct and press \"Yes\". " @@ -237,6 +240,7 @@ void CSecurityRSAAES::verifyServer() void CSecurityRSAAES::writeRandom() { + rdr::RandomStream rs; rdr::OutStream* os = cc->getOutStream(); if (!rs.hasData(keySize / 8)) throw std::runtime_error("Failed to generate random"); diff --git a/common/rfb/CSecurityRSAAES.h b/common/rfb/CSecurityRSAAES.h index af380bd3..ecbfdc4f 100644 --- a/common/rfb/CSecurityRSAAES.h +++ b/common/rfb/CSecurityRSAAES.h @@ -29,7 +29,7 @@ #include <rfb/CSecurity.h> #include <rfb/Security.h> -#include <rdr/RandomStream.h> +namespace core { class IntParameter; } namespace rdr { class InStream; @@ -39,6 +39,7 @@ namespace rdr { } namespace rfb { + class CSecurityRSAAES : public CSecurity { public: CSecurityRSAAES(CConnection* cc, uint32_t secType, @@ -48,7 +49,7 @@ namespace rfb { int getType() const override { return secType; } bool isSecure() const override { return secType == secTypeRA256; } - static IntParameter RSAKeyLength; + static core::IntParameter RSAKeyLength; private: void cleanup(); @@ -86,9 +87,8 @@ namespace rfb { rdr::InStream* rawis; rdr::OutStream* rawos; - - rdr::RandomStream rs; }; + } #endif diff --git a/common/rfb/CSecurityStack.h b/common/rfb/CSecurityStack.h index 521597ec..aec800f9 100644 --- a/common/rfb/CSecurityStack.h +++ b/common/rfb/CSecurityStack.h @@ -21,7 +21,6 @@ #define __RFB_CSECURITYSTACK_H__ #include <rfb/CSecurity.h> -#include <rfb/Security.h> namespace rfb { diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx index 0c10a85d..6eefe73b 100644 --- a/common/rfb/CSecurityTLS.cxx +++ b/common/rfb/CSecurityTLS.cxx @@ -3,7 +3,7 @@ * Copyright (C) 2005 Martin Koegler * Copyright (C) 2010 TigerVNC Team * Copyright (C) 2010 m-privacy GmbH - * Copyright (C) 2012-2021 Pierre Ossman for Cendio AB + * Copyright 2012-2025 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 @@ -34,15 +34,16 @@ #include <unistd.h> #endif +#include <core/LogWriter.h> +#include <core/string.h> +#include <core/xdgdirs.h> + #include <rfb/CSecurityTLS.h> #include <rfb/CConnection.h> -#include <rfb/LogWriter.h> #include <rfb/Exception.h> -#include <rfb/util.h> + #include <rdr/TLSException.h> -#include <rdr/TLSInStream.h> -#include <rdr/TLSOutStream.h> -#include <os/os.h> +#include <rdr/TLSSocket.h> #include <gnutls/x509.h> @@ -50,21 +51,19 @@ using namespace rfb; static const char* configdirfn(const char* fn); -StringParameter CSecurityTLS::X509CA("X509CA", "X509 CA certificate", - configdirfn("x509_ca.pem"), - ConfViewer); -StringParameter CSecurityTLS::X509CRL("X509CRL", "X509 CRL file", - configdirfn("x509_crl.pem"), - ConfViewer); +core::StringParameter CSecurityTLS::X509CA("X509CA", "X509 CA certificate", + configdirfn("x509_ca.pem")); +core::StringParameter CSecurityTLS::X509CRL("X509CRL", "X509 CRL file", + configdirfn("x509_crl.pem")); -static LogWriter vlog("TLS"); +static core::LogWriter vlog("TLS"); static const char* configdirfn(const char* fn) { static char full_path[PATH_MAX]; const char* configdir; - configdir = os::getvncconfigdir(); + configdir = core::getvncconfigdir(); if (configdir == nullptr) return ""; @@ -75,7 +74,7 @@ static const char* configdirfn(const char* fn) CSecurityTLS::CSecurityTLS(CConnection* cc_, bool _anon) : CSecurity(cc_), session(nullptr), anon_cred(nullptr), cert_cred(nullptr), - anon(_anon), tlsis(nullptr), tlsos(nullptr), + anon(_anon), tlssock(nullptr), rawis(nullptr), rawos(nullptr) { int err = gnutls_global_init(); @@ -85,27 +84,8 @@ CSecurityTLS::CSecurityTLS(CConnection* cc_, bool _anon) void CSecurityTLS::shutdown() { - if (tlsos) { - try { - if (tlsos->hasBufferedData()) { - tlsos->cork(false); - tlsos->flush(); - if (tlsos->hasBufferedData()) - vlog.error("Failed to flush remaining socket data on close"); - } - } catch (std::exception& e) { - vlog.error("Failed to flush remaining socket data on close: %s", e.what()); - } - } - - if (session) { - int ret; - // FIXME: We can't currently wait for the response, so we only send - // our close and hope for the best - ret = gnutls_bye(session, GNUTLS_SHUT_WR); - if ((ret != GNUTLS_E_SUCCESS) && (ret != GNUTLS_E_INVALID_SESSION)) - vlog.error("TLS shutdown failed: %s", gnutls_strerror(ret)); - } + if (tlssock) + tlssock->shutdown(); if (anon_cred) { gnutls_anon_free_client_credentials(anon_cred); @@ -123,13 +103,9 @@ void CSecurityTLS::shutdown() rawos = nullptr; } - if (tlsis) { - delete tlsis; - tlsis = nullptr; - } - if (tlsos) { - delete tlsos; - tlsos = nullptr; + if (tlssock) { + delete tlssock; + tlssock = nullptr; } if (session) { @@ -171,26 +147,18 @@ bool CSecurityTLS::processMsg() setParam(); - // Create these early as they set up the push/pull functions - // for GnuTLS - tlsis = new rdr::TLSInStream(is, session); - tlsos = new rdr::TLSOutStream(os, session); + tlssock = new rdr::TLSSocket(is, os, session); rawis = is; rawos = os; } - int err; - err = gnutls_handshake(session); - if (err != GNUTLS_E_SUCCESS) { - if (!gnutls_error_is_fatal(err)) { - vlog.debug("Deferring completion of TLS handshake: %s", gnutls_strerror(err)); + try { + if (!tlssock->handshake()) return false; - } - - vlog.error("TLS Handshake failed: %s\n", gnutls_strerror (err)); + } catch (std::exception&) { shutdown(); - throw rdr::tls_error("TLS Handshake failed", err); + throw; } vlog.debug("TLS handshake completed with %s", @@ -198,33 +166,29 @@ bool CSecurityTLS::processMsg() checkSession(); - cc->setStreams(tlsis, tlsos); + cc->setStreams(&tlssock->inStream(), &tlssock->outStream()); return true; } void CSecurityTLS::setParam() { - static const char kx_anon_priority[] = ":+ANON-ECDH:+ANON-DH"; + static const char kx_anon_priority[] = "+ANON-ECDH:+ANON-DH"; int ret; // Custom priority string specified? if (strcmp(Security::GnuTLSPriority, "") != 0) { - char *prio; + std::string prio; const char *err; - prio = new char[strlen(Security::GnuTLSPriority) + - strlen(kx_anon_priority) + 1]; - - strcpy(prio, Security::GnuTLSPriority); - if (anon) - strcat(prio, kx_anon_priority); - - ret = gnutls_priority_set_direct(session, prio, &err); - - delete [] prio; + prio = (const char*)Security::GnuTLSPriority; + if (anon) { + prio += ":"; + prio += kx_anon_priority; + } + ret = gnutls_priority_set_direct(session, prio.c_str(), &err); if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); @@ -234,30 +198,22 @@ void CSecurityTLS::setParam() const char *err; #if GNUTLS_VERSION_NUMBER >= 0x030603 - // gnutls_set_default_priority_appends() expects a normal priority string that - // doesn't start with ":". - ret = gnutls_set_default_priority_append(session, kx_anon_priority + 1, &err, 0); + ret = gnutls_set_default_priority_append(session, kx_anon_priority, &err, 0); if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); throw rdr::tls_error("gnutls_set_default_priority_append()", ret); } #else + std::string prio; + // We don't know what the system default priority is, so we guess // it's what upstream GnuTLS has - static const char gnutls_default_priority[] = "NORMAL"; - char *prio; - - prio = new char[malloc(strlen(gnutls_default_priority) + - strlen(kx_anon_priority) + 1]; - - strcpy(prio, gnutls_default_priority); - strcat(prio, kx_anon_priority); - - ret = gnutls_priority_set_direct(session, prio, &err); - - delete [] prio; + prio = "NORMAL"; + prio += ":"; + prio += kx_anon_priority; + ret = gnutls_priority_set_direct(session, prio.c_str(), &err); if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); @@ -277,6 +233,10 @@ void CSecurityTLS::setParam() vlog.debug("Anonymous session has been set"); } else { + const char* hostname; + size_t len; + bool valid; + ret = gnutls_certificate_allocate_credentials(&cert_cred); if (ret != GNUTLS_E_SUCCESS) throw rdr::tls_error("gnutls_certificate_allocate_credentials()", ret); @@ -294,10 +254,22 @@ void CSecurityTLS::setParam() if (ret != GNUTLS_E_SUCCESS) throw rdr::tls_error("gnutls_credentials_set()", ret); - if (gnutls_server_name_set(session, GNUTLS_NAME_DNS, - client->getServerName(), - strlen(client->getServerName())) != GNUTLS_E_SUCCESS) - vlog.error("Failed to configure the server name for TLS handshake"); + // Only DNS hostnames are allowed, and some servers will reject the + // connection if we provide anything else (e.g. an IPv6 address) + hostname = client->getServerName(); + len = strlen(hostname); + valid = true; + for (size_t i = 0; i < len; i++) { + if (!isalnum(hostname[i]) && hostname[i] != '.') + valid = false; + } + + if (valid) { + if (gnutls_server_name_set(session, GNUTLS_NAME_DNS, + client->getServerName(), + strlen(client->getServerName())) != GNUTLS_E_SUCCESS) + vlog.error("Failed to configure the server name for TLS handshake"); + } vlog.debug("X509 session has been set"); } @@ -324,12 +296,16 @@ void CSecurityTLS::checkSession() if (anon) return; - if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) + if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_UNSUPPORTED_CERTIFICATE); throw protocol_error("Unsupported certificate type"); + } err = gnutls_certificate_verify_peers2(session, &status); if (err != 0) { vlog.error("Server certificate verification failed: %s", gnutls_strerror(err)); + gnutls_alert_send_appropriate(session, err); throw rdr::tls_error("Server certificate verification()", err); } @@ -346,23 +322,29 @@ void CSecurityTLS::checkSession() GNUTLS_CRT_X509, &status_str, 0); - if (err != GNUTLS_E_SUCCESS) + if (err != GNUTLS_E_SUCCESS) { + gnutls_alert_send_appropriate(session, err); throw rdr::tls_error("Failed to get certificate error description", err); + } error = (const char*)status_str.data; gnutls_free(status_str.data); - throw protocol_error(format("Invalid server certificate: %s", - error.c_str())); + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); + throw protocol_error( + core::format("Invalid server certificate: %s", error.c_str())); } err = gnutls_certificate_verification_status_print(status, GNUTLS_CRT_X509, &status_str, 0); - if (err != GNUTLS_E_SUCCESS) + if (err != GNUTLS_E_SUCCESS) { + gnutls_alert_send_appropriate(session, err); throw rdr::tls_error("Failed to get certificate error description", err); + } vlog.info("Server certificate errors: %s", status_str.data); @@ -372,16 +354,21 @@ void CSecurityTLS::checkSession() /* Process overridable errors later */ cert_list = gnutls_certificate_get_peers(session, &cert_list_size); - if (!cert_list_size) + if (!cert_list_size) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_UNSUPPORTED_CERTIFICATE); throw protocol_error("Empty certificate chain"); + } /* Process only server's certificate, not issuer's certificate */ gnutls_x509_crt_t crt; gnutls_x509_crt_init(&crt); err = gnutls_x509_crt_import(crt, &cert_list[0], GNUTLS_X509_FMT_DER); - if (err != GNUTLS_E_SUCCESS) + if (err != GNUTLS_E_SUCCESS) { + gnutls_alert_send_appropriate(session, err); throw rdr::tls_error("Failed to decode server certificate", err); + } if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) { vlog.info("Server certificate doesn't match given server name"); @@ -398,7 +385,7 @@ void CSecurityTLS::checkSession() /* Certificate has some user overridable problems, so TOFU time */ - hostsDir = os::getvncstatedir(); + hostsDir = core::getvncstatedir(); if (hostsDir == nullptr) { throw std::runtime_error("Could not obtain VNC state directory " "path for known hosts storage"); @@ -420,12 +407,15 @@ void CSecurityTLS::checkSession() if ((known != GNUTLS_E_NO_CERTIFICATE_FOUND) && (known != GNUTLS_E_CERTIFICATE_KEY_MISMATCH)) { + gnutls_alert_send_appropriate(session, known); throw rdr::tls_error("Could not load known hosts database", known); } err = gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info); - if (err != GNUTLS_E_SUCCESS) + if (err != GNUTLS_E_SUCCESS) { + gnutls_alert_send_appropriate(session, known); throw rdr::tls_error("Could not find certificate to display", err); + } len = strlen((char*)info.data); for (size_t i = 0; i < len - 1; i++) { @@ -443,21 +433,24 @@ void CSecurityTLS::checkSession() if (status & (GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNER_NOT_CA)) { - text = format("This certificate has been signed by an unknown " - "authority:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site " - "and you should not continue.\n" - "\n" - "Do you want to make an exception for this " - "server?", info.data); + text = core::format( + "This certificate has been signed by an unknown authority:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unknown certificate issuer", - text.c_str())) + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_UNKNOWN_CA); throw auth_cancelled(); + } status &= ~(GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | @@ -465,82 +458,101 @@ void CSecurityTLS::checkSession() } if (status & GNUTLS_CERT_NOT_ACTIVATED) { - text = format("This certificate is not yet valid:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site " - "and you should not continue.\n" - "\n" - "Do you want to make an exception for this " - "server?", info.data); + text = core::format( + "This certificate is not yet valid:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); + if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Certificate is not yet valid", - text.c_str())) + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); throw auth_cancelled(); + } status &= ~GNUTLS_CERT_NOT_ACTIVATED; } if (status & GNUTLS_CERT_EXPIRED) { - text = format("This certificate has expired:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site " - "and you should not continue.\n" - "\n" - "Do you want to make an exception for this " - "server?", info.data); + text = core::format( + "This certificate has expired:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Expired certificate", - text.c_str())) + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); throw auth_cancelled(); + } status &= ~GNUTLS_CERT_EXPIRED; } if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { - text = format("This certificate uses an insecure algorithm:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site " - "and you should not continue.\n" - "\n" - "Do you want to make an exception for this " - "server?", info.data); + text = core::format( + "This certificate uses an insecure algorithm:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Insecure certificate algorithm", - text.c_str())) + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); throw auth_cancelled(); + } status &= ~GNUTLS_CERT_INSECURE_ALGORITHM; } if (status != 0) { vlog.error("Unhandled certificate problems: 0x%x", status); + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); throw std::logic_error("Unhandled certificate problems"); } if (!hostname_match) { - text = format("The specified hostname \"%s\" does not match the " - "certificate provided by the server:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site " - "and you should not continue.\n" - "\n" - "Do you want to make an exception for this " - "server?", client->getServerName(), info.data); + text = core::format( + "The specified hostname \"%s\" does not match the certificate " + "provided by the server:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + client->getServerName(), info.data); if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Certificate hostname mismatch", - text.c_str())) + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); throw auth_cancelled(); + } } } else if (known == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { std::string text; @@ -551,22 +563,26 @@ void CSecurityTLS::checkSession() if (status & (GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNER_NOT_CA)) { - text = format("This host is previously known with a different " - "certificate, and the new certificate has been " - "signed by an unknown authority:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site " - "and you should not continue.\n" - "\n" - "Do you want to make an exception for this " - "server?", info.data); + text = core::format( + "This host is previously known with a different certificate, " + "and the new certificate has been signed by an unknown " + "authority:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unexpected server certificate", - text.c_str())) + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_UNKNOWN_CA); throw auth_cancelled(); + } status &= ~(GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | @@ -574,91 +590,105 @@ void CSecurityTLS::checkSession() } if (status & GNUTLS_CERT_NOT_ACTIVATED) { - text = format("This host is previously known with a different " - "certificate, and the new certificate is not yet " - "valid:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site " - "and you should not continue.\n" - "\n" - "Do you want to make an exception for this " - "server?", info.data); + text = core::format( + "This host is previously known with a different certificate, " + "and the new certificate is not yet valid:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unexpected server certificate", - text.c_str())) + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); throw auth_cancelled(); + } status &= ~GNUTLS_CERT_NOT_ACTIVATED; } if (status & GNUTLS_CERT_EXPIRED) { - text = format("This host is previously known with a different " - "certificate, and the new certificate has " - "expired:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site " - "and you should not continue.\n" - "\n" - "Do you want to make an exception for this " - "server?", info.data); + text = core::format( + "This host is previously known with a different certificate, " + "and the new certificate has expired:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unexpected server certificate", - text.c_str())) + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); throw auth_cancelled(); + } status &= ~GNUTLS_CERT_EXPIRED; } if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { - text = format("This host is previously known with a different " - "certificate, and the new certificate uses an " - "insecure algorithm:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site " - "and you should not continue.\n" - "\n" - "Do you want to make an exception for this " - "server?", info.data); + text = core::format( + "This host is previously known with a different certificate, " + "and the new certificate uses an insecure algorithm:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + info.data); if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unexpected server certificate", - text.c_str())) + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); throw auth_cancelled(); + } status &= ~GNUTLS_CERT_INSECURE_ALGORITHM; } if (status != 0) { vlog.error("Unhandled certificate problems: 0x%x", status); + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); throw std::logic_error("Unhandled certificate problems"); } if (!hostname_match) { - text = format("This host is previously known with a different " - "certificate, and the specified hostname \"%s\" " - "does not match the new certificate provided by " - "the server:\n" - "\n" - "%s\n" - "\n" - "Someone could be trying to impersonate the site " - "and you should not continue.\n" - "\n" - "Do you want to make an exception for this " - "server?", client->getServerName(), info.data); + text = core::format( + "This host is previously known with a different certificate, " + "and the specified hostname \"%s\" does not match the new " + "certificate provided by the server:\n" + "\n" + "%s\n" + "\n" + "Someone could be trying to impersonate the site and you " + "should not continue.\n" + "\n" + "Do you want to make an exception for this server?", + client->getServerName(), info.data); if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unexpected server certificate", - text.c_str())) + text.c_str())) { + gnutls_alert_send(session, GNUTLS_AL_FATAL, + GNUTLS_A_BAD_CERTIFICATE); throw auth_cancelled(); + } } } diff --git a/common/rfb/CSecurityTLS.h b/common/rfb/CSecurityTLS.h index 2464cb6c..51b7dac1 100644 --- a/common/rfb/CSecurityTLS.h +++ b/common/rfb/CSecurityTLS.h @@ -2,6 +2,7 @@ * Copyright (C) 2004 Red Hat Inc. * Copyright (C) 2005 Martin Koegler * Copyright (C) 2010 TigerVNC Team + * Copyright 2012-2025 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 @@ -34,8 +35,7 @@ namespace rdr { class InStream; class OutStream; - class TLSInStream; - class TLSOutStream; + class TLSSocket; } namespace rfb { @@ -47,8 +47,8 @@ namespace rfb { int getType() const override { return anon ? secTypeTLSNone : secTypeX509None; } bool isSecure() const override { return !anon; } - static StringParameter X509CA; - static StringParameter X509CRL; + static core::StringParameter X509CA; + static core::StringParameter X509CRL; protected: void shutdown(); @@ -63,8 +63,7 @@ namespace rfb { gnutls_certificate_credentials_t cert_cred; bool anon; - rdr::TLSInStream* tlsis; - rdr::TLSOutStream* tlsos; + rdr::TLSSocket* tlssock; rdr::InStream* rawis; rdr::OutStream* rawos; diff --git a/common/rfb/CSecurityVeNCrypt.cxx b/common/rfb/CSecurityVeNCrypt.cxx index 1b6ecf22..a6e30947 100644 --- a/common/rfb/CSecurityVeNCrypt.cxx +++ b/common/rfb/CSecurityVeNCrypt.cxx @@ -29,16 +29,17 @@ #include <algorithm> #include <list> +#include <core/LogWriter.h> + #include <rfb/Exception.h> #include <rdr/InStream.h> #include <rdr/OutStream.h> #include <rfb/CConnection.h> #include <rfb/CSecurityVeNCrypt.h> -#include <rfb/LogWriter.h> using namespace rfb; -static LogWriter vlog("CVeNCrypt"); +static core::LogWriter vlog("CVeNCrypt"); CSecurityVeNCrypt::CSecurityVeNCrypt(CConnection* cc_, SecurityClient* sec) diff --git a/common/rfb/CSecurityVeNCrypt.h b/common/rfb/CSecurityVeNCrypt.h index f73e7927..8e2c6d5e 100644 --- a/common/rfb/CSecurityVeNCrypt.h +++ b/common/rfb/CSecurityVeNCrypt.h @@ -28,10 +28,11 @@ #include <stdint.h> #include <rfb/CSecurity.h> -#include <rfb/SecurityClient.h> namespace rfb { + class SecurityClient; + class CSecurityVeNCrypt : public CSecurity { public: diff --git a/common/rfb/ClientParams.cxx b/common/rfb/ClientParams.cxx index e5fd105e..514b0b4e 100644 --- a/common/rfb/ClientParams.cxx +++ b/common/rfb/ClientParams.cxx @@ -24,14 +24,20 @@ #include <stdexcept> +#include <core/LogWriter.h> +#include <core/string.h> + #include <rfb/encodings.h> #include <rfb/ledStates.h> #include <rfb/clipboardTypes.h> #include <rfb/ClientParams.h> -#include <rfb/util.h> +#include <rfb/Cursor.h> +#include <rfb/ScreenSet.h> using namespace rfb; +static core::LogWriter vlog("ClientParams"); + ClientParams::ClientParams() : majorVersion(0), minorVersion(0), compressLevel(2), qualityLevel(-1), fineQualityLevel(-1), @@ -41,7 +47,11 @@ ClientParams::ClientParams() { setName(""); - cursor_ = new Cursor(0, 0, Point(), nullptr); + screenLayout_ = new ScreenSet(); + + pf_ = new PixelFormat(); + + cursor_ = new Cursor(0, 0, {}, nullptr); clipFlags = clipboardUTF8 | clipboardRTF | clipboardHTML | clipboardRequest | clipboardNotify | clipboardProvide; @@ -51,7 +61,9 @@ ClientParams::ClientParams() ClientParams::~ClientParams() { + delete screenLayout_; delete cursor_; + delete pf_; } void ClientParams::setDimensions(int width, int height) @@ -63,17 +75,25 @@ void ClientParams::setDimensions(int width, int height) void ClientParams::setDimensions(int width, int height, const ScreenSet& layout) { - if (!layout.validate(width, height)) + if (!layout.validate(width, height)) { + char buffer[2048]; + vlog.debug("Invalid screen layout for %dx%d:", width, height); + layout.print(buffer, sizeof(buffer)); + vlog.debug("%s", buffer); + throw std::invalid_argument("Attempted to configure an invalid screen layout"); + } width_ = width; height_ = height; - screenLayout_ = layout; + delete screenLayout_; + screenLayout_ = new ScreenSet(layout); } void ClientParams::setPF(const PixelFormat& pf) { - pf_ = pf; + delete pf_; + pf_ = new PixelFormat(pf); if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32) throw std::invalid_argument("setPF: Not 8, 16 or 32 bpp?"); @@ -90,7 +110,7 @@ void ClientParams::setCursor(const Cursor& other) cursor_ = new Cursor(other); } -void ClientParams::setCursorPos(const Point& pos) +void ClientParams::setCursorPos(const core::Point& pos) { cursorPos_ = pos; } @@ -162,7 +182,7 @@ uint32_t ClientParams::clipboardSize(unsigned int format) const return clipSizes[i]; } - throw std::invalid_argument(rfb::format("Invalid clipboard format 0x%x", format)); + throw std::invalid_argument(core::format("Invalid clipboard format 0x%x", format)); } void ClientParams::setClipboardCaps(uint32_t flags, const uint32_t* lengths) @@ -236,4 +256,4 @@ bool ClientParams::supportsExtendedMouseButtons() const if (supportsEncoding(pseudoEncodingExtendedMouseButtons)) return true; return false; -}
\ No newline at end of file +} diff --git a/common/rfb/ClientParams.h b/common/rfb/ClientParams.h index f715c47f..0910181b 100644 --- a/common/rfb/ClientParams.h +++ b/common/rfb/ClientParams.h @@ -28,12 +28,14 @@ #include <stdint.h> -#include <rfb/Cursor.h> -#include <rfb/PixelFormat.h> -#include <rfb/ScreenSet.h> +#include <core/Rect.h> namespace rfb { + class Cursor; + class PixelFormat; + struct ScreenSet; + const int subsampleUndefined = -1; const int subsampleNone = 0; const int subsampleGray = 1; @@ -66,11 +68,11 @@ namespace rfb { int width() const { return width_; } int height() const { return height_; } - const ScreenSet& screenLayout() const { return screenLayout_; } + 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_; } + const PixelFormat& pf() const { return *pf_; } void setPF(const PixelFormat& pf); const char* name() const { return name_.c_str(); } @@ -79,8 +81,8 @@ namespace rfb { const Cursor& cursor() const { return *cursor_; } void setCursor(const Cursor& cursor); - const Point& cursorPos() const { return cursorPos_; } - void setCursorPos(const Point& pos); + const core::Point& cursorPos() const { return cursorPos_; } + void setCursorPos(const core::Point& pos); bool supportsEncoding(int32_t encoding) const; @@ -112,12 +114,12 @@ namespace rfb { int width_; int height_; - ScreenSet screenLayout_; + ScreenSet* screenLayout_; - PixelFormat pf_; + PixelFormat* pf_; std::string name_; Cursor* cursor_; - Point cursorPos_; + core::Point cursorPos_; std::set<int32_t> encodings_; unsigned int ledState_; uint32_t clipFlags; diff --git a/common/rfb/ComparingUpdateTracker.cxx b/common/rfb/ComparingUpdateTracker.cxx index dab5e6aa..a89c3ec3 100644 --- a/common/rfb/ComparingUpdateTracker.cxx +++ b/common/rfb/ComparingUpdateTracker.cxx @@ -22,17 +22,18 @@ #include <stdio.h> #include <string.h> + +#include <algorithm> #include <vector> -#include <rfb/Exception.h> -#include <rfb/LogWriter.h> -#include <rfb/util.h> +#include <core/LogWriter.h> +#include <core/string.h> #include <rfb/ComparingUpdateTracker.h> using namespace rfb; -static LogWriter vlog("ComparingUpdateTracker"); +static core::LogWriter vlog("ComparingUpdateTracker"); ComparingUpdateTracker::ComparingUpdateTracker(PixelBuffer* buffer) : fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true), @@ -50,8 +51,8 @@ ComparingUpdateTracker::~ComparingUpdateTracker() bool ComparingUpdateTracker::compare() { - std::vector<Rect> rects; - std::vector<Rect>::iterator i; + std::vector<core::Rect> rects; + std::vector<core::Rect>::iterator i; if (!enabled) return false; @@ -62,7 +63,7 @@ bool ComparingUpdateTracker::compare() oldFb.setSize(fb->width(), fb->height()); for (int y=0; y<fb->height(); y+=BLOCK_SIZE) { - Rect pos(0, y, fb->width(), __rfbmin(fb->height(), y+BLOCK_SIZE)); + core::Rect pos(0, y, fb->width(), std::min(fb->height(), y+BLOCK_SIZE)); int srcStride; const uint8_t* srcData = fb->getBuffer(pos, &srcStride); oldFb.imageRect(pos, srcData, srcStride); @@ -79,7 +80,7 @@ bool ComparingUpdateTracker::compare() changed.get_rects(&rects); - Region newChanged; + core::Region newChanged; for (i = rects.begin(); i != rects.end(); i++) compareRect(*i, &newChanged); @@ -111,10 +112,11 @@ void ComparingUpdateTracker::disable() firstCompare = true; } -void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged) +void ComparingUpdateTracker::compareRect(const core::Rect& r, + core::Region* newChanged) { if (!r.enclosed_by(fb->getRect())) { - Rect safe; + core::Rect safe; // Crop the rect and try again safe = r.intersect(fb->getRect()); if (!safe.is_empty()) @@ -134,20 +136,20 @@ void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged) for (int blockTop = r.tl.y; blockTop < r.br.y; blockTop += BLOCK_SIZE) { // Get a strip of the source buffer - Rect pos(r.tl.x, blockTop, r.br.x, __rfbmin(r.br.y, blockTop+BLOCK_SIZE)); + core::Rect pos(r.tl.x, blockTop, r.br.x, std::min(r.br.y, blockTop+BLOCK_SIZE)); int fbStride; const uint8_t* newBlockPtr = fb->getBuffer(pos, &fbStride); int newStrideBytes = fbStride * bytesPerPixel; uint8_t* oldBlockPtr = oldData; - int blockBottom = __rfbmin(blockTop+BLOCK_SIZE, r.br.y); + int blockBottom = std::min(blockTop+BLOCK_SIZE, r.br.y); for (int blockLeft = r.tl.x; blockLeft < r.br.x; blockLeft += BLOCK_SIZE) { const uint8_t* newPtr = newBlockPtr; uint8_t* oldPtr = oldBlockPtr; - int blockRight = __rfbmin(blockLeft+BLOCK_SIZE, r.br.x); + int blockRight = std::min(blockLeft+BLOCK_SIZE, r.br.x); int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel; // Scan the block top to bottom, to identify the first row of change @@ -223,8 +225,10 @@ void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged) } endOfChangeRight: - // Block change extends from (changeLeft, y) to (changeRight, y + changeHeight) - newChanged->assign_union(Region(Rect(changeLeft, y, changeRight, y + changeHeight))); + // Block change extends from (changeLeft, y) to (changeRight, + // y + changeHeight) + newChanged->assign_union({{changeLeft, y, + changeRight, y + changeHeight}}); // Copy the change from fb to oldFb to allow future changes to be identified for (int row = 0; row < changeHeight; row++) @@ -258,10 +262,12 @@ void ComparingUpdateTracker::logStats() ratio = (double)totalPixels / missedPixels; - vlog.info("%s in / %s out", - siPrefix(totalPixels, "pixels").c_str(), - siPrefix(missedPixels, "pixels").c_str()); - vlog.info("(1:%g ratio)", ratio); + // FIXME: This gets spammed on each session resize, so we'll have to + // keep it on a debug level for now + vlog.debug("%s in / %s out", + core::siPrefix(totalPixels, "pixels").c_str(), + core::siPrefix(missedPixels, "pixels").c_str()); + vlog.debug("(1:%g ratio)", ratio); totalPixels = missedPixels = 0; } diff --git a/common/rfb/ComparingUpdateTracker.h b/common/rfb/ComparingUpdateTracker.h index ca1dcc30..dbe7a4ef 100644 --- a/common/rfb/ComparingUpdateTracker.h +++ b/common/rfb/ComparingUpdateTracker.h @@ -19,6 +19,7 @@ #ifndef __RFB_COMPARINGUPDATETRACKER_H__ #define __RFB_COMPARINGUPDATETRACKER_H__ +#include <rfb/PixelBuffer.h> #include <rfb/UpdateTracker.h> namespace rfb { @@ -44,7 +45,7 @@ namespace rfb { void logStats(); private: - void compareRect(const Rect& r, Region* newchanged); + void compareRect(const core::Rect& r, core::Region* newchanged); PixelBuffer* fb; ManagedPixelBuffer oldFb; bool firstCompare; diff --git a/common/rfb/Configuration.cxx b/common/rfb/Configuration.cxx deleted file mode 100644 index 72947df1..00000000 --- a/common/rfb/Configuration.cxx +++ /dev/null @@ -1,469 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2004-2005 Cendio AB. - * Copyright 2017 Peter Astrand <astrand@cendio.se> for Cendio AB - * Copyright 2011-2022 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. - */ - -// -=- Configuration.cxx - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <stdlib.h> -#include <ctype.h> -#include <string.h> - -#include <stdexcept> - -#include <os/Mutex.h> - -#include <rfb/util.h> -#include <rfb/Configuration.h> -#include <rfb/LogWriter.h> - -#define LOCK_CONFIG os::AutoMutex a(mutex) - -#include <rdr/HexOutStream.h> -#include <rdr/HexInStream.h> - -using namespace rfb; - -static LogWriter vlog("Config"); - - -// -=- The Global/server/viewer Configuration objects -Configuration* Configuration::global_ = nullptr; -Configuration* Configuration::server_ = nullptr; -Configuration* Configuration::viewer_ = nullptr; - -Configuration* Configuration::global() { - if (!global_) - global_ = new Configuration("Global"); - return global_; -} - -Configuration* Configuration::server() { - if (!server_) - server_ = new Configuration("Server"); - return server_; -} - -Configuration* Configuration::viewer() { - if (!viewer_) - viewer_ = new Configuration("Viewer"); - return viewer_; -} - -// -=- Configuration implementation - -bool Configuration::set(const char* n, const char* v, bool immutable) { - return set(n, strlen(n), v, immutable); -} - -bool Configuration::set(const char* paramName, int len, - const char* val, bool immutable) -{ - VoidParameter* current = head; - while (current) { - if ((int)strlen(current->getName()) == len && - strncasecmp(current->getName(), paramName, len) == 0) - { - bool b = current->setParam(val); - if (b && immutable) - current->setImmutable(); - return b; - } - current = current->_next; - } - return _next ? _next->set(paramName, len, val, immutable) : false; -} - -bool Configuration::set(const char* config, bool immutable) { - bool hyphen = false; - if (config[0] == '-') { - hyphen = true; - config++; - if (config[0] == '-') config++; // allow gnu-style --<option> - } - const char* equal = strchr(config, '='); - if (equal) { - return set(config, equal-config, equal+1, immutable); - } else if (hyphen) { - VoidParameter* current = head; - while (current) { - if (strcasecmp(current->getName(), config) == 0) { - bool b = current->setParam(); - if (b && immutable) - current->setImmutable(); - return b; - } - current = current->_next; - } - } - return _next ? _next->set(config, immutable) : false; -} - -VoidParameter* Configuration::get(const char* param) -{ - VoidParameter* current = head; - while (current) { - if (strcasecmp(current->getName(), param) == 0) - return current; - current = current->_next; - } - return _next ? _next->get(param) : nullptr; -} - -void Configuration::list(int width, int nameWidth) { - VoidParameter* current = head; - - fprintf(stderr, "%s Parameters:\n", name.c_str()); - while (current) { - std::string def_str = current->getDefaultStr(); - const char* desc = current->getDescription(); - fprintf(stderr," %-*s -", nameWidth, current->getName()); - int column = strlen(current->getName()); - if (column < nameWidth) column = nameWidth; - column += 4; - while (true) { - const char* s = strchr(desc, ' '); - int wordLen; - if (s) wordLen = s-desc; - else wordLen = strlen(desc); - - if (column + wordLen + 1 > width) { - fprintf(stderr,"\n%*s",nameWidth+4,""); - column = nameWidth+4; - } - fprintf(stderr," %.*s",wordLen,desc); - column += wordLen + 1; - desc += wordLen + 1; - if (!s) break; - } - - if (!def_str.empty()) { - if (column + (int)def_str.size() + 11 > width) - fprintf(stderr,"\n%*s",nameWidth+4,""); - fprintf(stderr," (default=%s)\n",def_str.c_str()); - } else { - fprintf(stderr,"\n"); - } - current = current->_next; - } - - if (_next) - _next->list(width, nameWidth); -} - - -bool Configuration::remove(const char* param) { - VoidParameter *current = head; - VoidParameter **prevnext = &head; - - while (current) { - if (strcasecmp(current->getName(), param) == 0) { - *prevnext = current->_next; - return true; - } - prevnext = ¤t->_next; - current = current->_next; - } - - return false; -} - - -// -=- VoidParameter - -VoidParameter::VoidParameter(const char* name_, const char* desc_, - ConfigurationObject co) - : immutable(false), name(name_), description(desc_) -{ - Configuration *conf = nullptr; - - switch (co) { - case ConfGlobal: conf = Configuration::global(); - break; - case ConfServer: conf = Configuration::server(); - break; - case ConfViewer: conf = Configuration::viewer(); - break; - } - - _next = conf->head; - conf->head = this; - - mutex = new os::Mutex(); -} - -VoidParameter::~VoidParameter() { - delete mutex; -} - -const char* -VoidParameter::getName() const { - return name; -} - -const char* -VoidParameter::getDescription() const { - return description; -} - -bool VoidParameter::setParam() { - return false; -} - -bool VoidParameter::isBool() const { - return false; -} - -void -VoidParameter::setImmutable() { - vlog.debug("Set immutable %s", getName()); - immutable = true; -} - -// -=- AliasParameter - -AliasParameter::AliasParameter(const char* name_, const char* desc_, - VoidParameter* param_, ConfigurationObject co) - : VoidParameter(name_, desc_, co), param(param_) { -} - -bool -AliasParameter::setParam(const char* v) { - return param->setParam(v); -} - -bool AliasParameter::setParam() { - return param->setParam(); -} - -std::string AliasParameter::getDefaultStr() const { - return ""; -} - -std::string AliasParameter::getValueStr() const { - return param->getValueStr(); -} - -bool AliasParameter::isBool() const { - return param->isBool(); -} - -void -AliasParameter::setImmutable() { - vlog.debug("Set immutable %s (Alias)", getName()); - param->setImmutable(); -} - - -// -=- BoolParameter - -BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v, - ConfigurationObject co) -: VoidParameter(name_, desc_, co), value(v), def_value(v) { -} - -bool -BoolParameter::setParam(const char* v) { - if (immutable) return true; - - if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0 - || strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0) - setParam(true); - else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0 - || strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0) - setParam(false); - else { - vlog.error("Bool parameter %s: Invalid value '%s'", getName(), v); - return false; - } - - return true; -} - -bool BoolParameter::setParam() { - setParam(true); - return true; -} - -void BoolParameter::setParam(bool b) { - if (immutable) return; - value = b; - vlog.debug("Set %s(Bool) to %d", getName(), value); -} - -std::string BoolParameter::getDefaultStr() const { - return def_value ? "1" : "0"; -} - -std::string BoolParameter::getValueStr() const { - return value ? "1" : "0"; -} - -bool BoolParameter::isBool() const { - return true; -} - -BoolParameter::operator bool() const { - return value; -} - -// -=- IntParameter - -IntParameter::IntParameter(const char* name_, const char* desc_, int v, - int minValue_, int maxValue_, ConfigurationObject co) - : VoidParameter(name_, desc_, co), value(v), def_value(v), - minValue(minValue_), maxValue(maxValue_) -{ -} - -bool -IntParameter::setParam(const char* v) { - if (immutable) return true; - return setParam(strtol(v, nullptr, 0)); -} - -bool -IntParameter::setParam(int v) { - if (immutable) return true; - vlog.debug("Set %s(Int) to %d", getName(), v); - if (v < minValue || v > maxValue) - return false; - value = v; - return true; -} - -std::string IntParameter::getDefaultStr() const { - char result[16]; - sprintf(result, "%d", def_value); - return result; -} - -std::string IntParameter::getValueStr() const { - char result[16]; - sprintf(result, "%d", value); - return result; -} - -IntParameter::operator int() const { - return value; -} - -// -=- StringParameter - -StringParameter::StringParameter(const char* name_, const char* desc_, - const char* v, ConfigurationObject co) - : VoidParameter(name_, desc_, co), value(v), def_value(v) -{ - if (!v) { - vlog.error("Default value <null> for %s not allowed",name_); - throw std::invalid_argument("Default value <null> not allowed"); - } -} - -StringParameter::~StringParameter() { -} - -bool StringParameter::setParam(const char* v) { - LOCK_CONFIG; - if (immutable) return true; - if (!v) - throw std::invalid_argument("setParam(<null>) not allowed"); - vlog.debug("Set %s(String) to %s", getName(), v); - value = v; - return true; -} - -std::string StringParameter::getDefaultStr() const { - return def_value; -} - -std::string StringParameter::getValueStr() const { - LOCK_CONFIG; - return value; -} - -StringParameter::operator const char *() const { - return value.c_str(); -} - -// -=- BinaryParameter - -BinaryParameter::BinaryParameter(const char* name_, const char* desc_, - const uint8_t* v, size_t l, ConfigurationObject co) -: VoidParameter(name_, desc_, co), - value(nullptr), length(0), def_value(nullptr), def_length(0) { - if (l) { - assert(v); - value = new uint8_t[l]; - length = l; - memcpy(value, v, l); - def_value = new uint8_t[l]; - def_length = l; - memcpy(def_value, v, l); - } -} -BinaryParameter::~BinaryParameter() { - delete [] value; - delete [] def_value; -} - -bool BinaryParameter::setParam(const char* v) { - if (immutable) return true; - std::vector<uint8_t> newValue = hexToBin(v, strlen(v)); - if (newValue.empty() && strlen(v) > 0) - return false; - setParam(newValue.data(), newValue.size()); - return true; -} - -void BinaryParameter::setParam(const uint8_t* v, size_t len) { - LOCK_CONFIG; - if (immutable) return; - vlog.debug("Set %s(Binary)", getName()); - delete [] value; - value = nullptr; - length = 0; - if (len) { - assert(v); - value = new uint8_t[len]; - length = len; - memcpy(value, v, len); - } -} - -std::string BinaryParameter::getDefaultStr() const { - return binToHex(def_value, def_length); -} - -std::string BinaryParameter::getValueStr() const { - LOCK_CONFIG; - return binToHex(value, length); -} - -std::vector<uint8_t> BinaryParameter::getData() const { - LOCK_CONFIG; - std::vector<uint8_t> out(length); - memcpy(out.data(), value, length); - return out; -} diff --git a/common/rfb/Configuration.h b/common/rfb/Configuration.h deleted file mode 100644 index ec8d789a..00000000 --- a/common/rfb/Configuration.h +++ /dev/null @@ -1,300 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2011-2022 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. - */ - -// -=- Configuration.h -// -// This header defines a set of classes used to represent configuration -// parameters of different types. Instances of the different parameter -// types are associated with instances of the Configuration class, and -// are each given a unique name. The Configuration class provides a -// generic API through which parameters may be located by name and their -// value set, thus removing the need to write platform-specific code. -// Simply defining a new parameter and associating it with a Configuration -// will allow it to be configured by the user. -// -// If no Configuration is specified when creating a Parameter, then the -// global Configuration will be assumed. -// -// Configurations can be "chained" into groups. Each group has a root -// Configuration, a pointer to which should be passed to the constructors -// of the other group members. set() and get() operations called on the -// root will iterate through all of the group's members. -// -// NB: On platforms that support Threading, locking is performed to protect -// complex parameter types from concurrent access (e.g. strings). -// NB: NO LOCKING is performed when linking Configurations to groups -// or when adding Parameters to Configurations. - -#ifndef __RFB_CONFIGURATION_H__ -#define __RFB_CONFIGURATION_H__ - -#include <limits.h> -#include <stdint.h> - -#include <string> -#include <vector> - -namespace os { class Mutex; } - -namespace rfb { - class VoidParameter; - struct ParameterIterator; - - enum ConfigurationObject { ConfGlobal, ConfServer, ConfViewer }; - - // -=- Configuration - // Class used to access parameters. - - class Configuration { - public: - // - Create a new Configuration object - Configuration(const char* name_) - : name(name_), head(nullptr), _next(nullptr) {} - - // - Return the buffer containing the Configuration's name - const char* getName() const { return name.c_str(); } - - // - Set named parameter to value - bool set(const char* param, const char* value, bool immutable=false); - - // - Set parameter to value (separated by "=") - bool set(const char* config, bool immutable=false); - - // - Set named parameter to value, with name truncated at len - bool set(const char* name, int len, - const char* val, bool immutable); - - // - Get named parameter - VoidParameter* get(const char* param); - - // - List the parameters of this Configuration group - void list(int width=79, int nameWidth=10); - - // - Remove a parameter from this Configuration group - bool remove(const char* param); - - // - readFromFile - // Read configuration parameters from the specified file. - void readFromFile(const char* filename); - - // - writeConfigToFile - // Write a new configuration parameters file, then mv it - // over the old file. - void writeToFile(const char* filename); - - - // - Get the Global Configuration object - // NB: This call does NOT lock the Configuration system. - // ALWAYS ensure that if you have ANY global Parameters, - // then they are defined as global objects, to ensure that - // global() is called when only the main thread is running. - static Configuration* global(); - - // Enable server/viewer specific parameters - static void enableServerParams() { global()->appendConfiguration(server()); } - static void enableViewerParams() { global()->appendConfiguration(viewer()); } - - // - Container for process-wide Global parameters - static bool setParam(const char* param, const char* value, bool immutable=false) { - return global()->set(param, value, immutable); - } - static bool setParam(const char* config, bool immutable=false) { - return global()->set(config, immutable); - } - static bool setParam(const char* name, int len, - const char* val, bool immutable) { - return global()->set(name, len, val, immutable); - } - static VoidParameter* getParam(const char* param) { return global()->get(param); } - static void listParams(int width=79, int nameWidth=10) { - global()->list(width, nameWidth); - } - static bool removeParam(const char* param) { - return global()->remove(param); - } - - private: - friend class VoidParameter; - friend struct ParameterIterator; - - // Name for this Configuration - std::string name; - - // - Pointer to first Parameter in this group - VoidParameter* head; - - // Pointer to next Configuration in this group - Configuration* _next; - - // The process-wide, Global Configuration object - static Configuration* global_; - - // The server only Configuration object - static Configuration* server_; - - // The viewer only Configuration object - static Configuration* viewer_; - - // Get server/viewer specific configuration object - static Configuration* server(); - static Configuration* viewer(); - - // Append configuration object to this instance. - // NOTE: conf instance can be only one configuration object - void appendConfiguration(Configuration *conf) { - conf->_next = _next; _next = conf; - } - }; - - // -=- VoidParameter - // Configuration parameter base-class. - - class VoidParameter { - public: - VoidParameter(const char* name_, const char* desc_, ConfigurationObject co=ConfGlobal); - virtual ~VoidParameter(); - const char* getName() const; - const char* getDescription() const; - - virtual bool setParam(const char* value) = 0; - virtual bool setParam(); - virtual std::string getDefaultStr() const = 0; - virtual std::string getValueStr() const = 0; - virtual bool isBool() const; - - virtual void setImmutable(); - - protected: - friend class Configuration; - friend struct ParameterIterator; - - VoidParameter* _next; - bool immutable; - const char* name; - const char* description; - - os::Mutex* mutex; - }; - - class AliasParameter : public VoidParameter { - public: - AliasParameter(const char* name_, const char* desc_,VoidParameter* param_, - ConfigurationObject co=ConfGlobal); - bool setParam(const char* value) override; - bool setParam() override; - std::string getDefaultStr() const override; - std::string getValueStr() const override; - bool isBool() const override; - void setImmutable() override; - private: - VoidParameter* param; - }; - - class BoolParameter : public VoidParameter { - public: - BoolParameter(const char* name_, const char* desc_, bool v, - ConfigurationObject co=ConfGlobal); - bool setParam(const char* value) override; - bool setParam() override; - virtual void setParam(bool b); - std::string getDefaultStr() const override; - std::string getValueStr() const override; - bool isBool() const override; - operator bool() const; - protected: - bool value; - bool def_value; - }; - - class IntParameter : public VoidParameter { - public: - IntParameter(const char* name_, const char* desc_, int v, - int minValue=INT_MIN, int maxValue=INT_MAX, - ConfigurationObject co=ConfGlobal); - using VoidParameter::setParam; - bool setParam(const char* value) override; - virtual bool setParam(int v); - std::string getDefaultStr() const override; - std::string getValueStr() const override; - operator int() const; - protected: - int value; - int def_value; - int minValue, maxValue; - }; - - class StringParameter : public VoidParameter { - public: - // StringParameter contains a null-terminated string, which CANNOT - // be Null, and so neither can the default value! - StringParameter(const char* name_, const char* desc_, const char* v, - ConfigurationObject co=ConfGlobal); - ~StringParameter() override; - bool setParam(const char* value) override; - std::string getDefaultStr() const override; - std::string getValueStr() const override; - operator const char*() const; - protected: - std::string value; - std::string def_value; - }; - - class BinaryParameter : public VoidParameter { - public: - BinaryParameter(const char* name_, const char* desc_, - const uint8_t* v, size_t l, - ConfigurationObject co=ConfGlobal); - using VoidParameter::setParam; - ~BinaryParameter() override; - bool setParam(const char* value) override; - virtual void setParam(const uint8_t* v, size_t l); - std::string getDefaultStr() const override; - std::string getValueStr() const override; - - std::vector<uint8_t> getData() const; - - protected: - uint8_t* value; - size_t length; - uint8_t* def_value; - size_t def_length; - }; - - // -=- ParameterIterator - // Iterates over all enabled parameters (global + server/viewer). - // Current Parameter is accessed via param, the current Configuration - // via config. The next() method moves on to the next Parameter. - - struct ParameterIterator { - ParameterIterator() : config(Configuration::global()), param(config->head) {} - void next() { - param = param->_next; - while (!param) { - config = config->_next; - if (!config) break; - param = config->head; - } - } - Configuration* config; - VoidParameter* param; - }; - -}; - -#endif // __RFB_CONFIGURATION_H__ diff --git a/common/rfb/Congestion.cxx b/common/rfb/Congestion.cxx index 94f07055..46bae00d 100644 --- a/common/rfb/Congestion.cxx +++ b/common/rfb/Congestion.cxx @@ -49,9 +49,10 @@ #include <linux/sockios.h> #endif +#include <core/LogWriter.h> +#include <core/time.h> + #include <rfb/Congestion.h> -#include <rfb/LogWriter.h> -#include <rfb/util.h> // Debug output on what the congestion control is up to #undef CONGESTION_DEBUG @@ -78,7 +79,7 @@ static inline bool isAfter(unsigned a, unsigned b) { return a != b && a - b <= UINT_MAX / 2; } -static LogWriter vlog("Congestion"); +static core::LogWriter vlog("Congestion"); Congestion::Congestion() : lastPosition(0), extraBuffer(0), @@ -99,7 +100,7 @@ Congestion::~Congestion() void Congestion::updatePosition(unsigned pos) { struct timeval now; - unsigned delta, consumed; + unsigned idle, delta, consumed; gettimeofday(&now, nullptr); @@ -110,15 +111,17 @@ void Congestion::updatePosition(unsigned pos) // Idle for too long? // We use a very crude RTO calculation in order to keep things simple // FIXME: should implement RFC 2861 - if (msBetween(&lastSent, &now) > __rfbmax(baseRTT*2, 100)) { + idle = core::msBetween(&lastSent, &now); + if (idle > 100 && idle > baseRTT*2) { #ifdef CONGESTION_DEBUG vlog.debug("Connection idle for %d ms, resetting congestion control", - msBetween(&lastSent, &now)); + idle); #endif // Close congestion window and redo wire latency measurement - congWindow = __rfbmin(INITIAL_WINDOW, congWindow); + if (congWindow > INITIAL_WINDOW) + congWindow = INITIAL_WINDOW; baseRTT = -1; measurements = 0; gettimeofday(&lastAdjustment, nullptr); @@ -132,7 +135,7 @@ void Congestion::updatePosition(unsigned pos) // (we cannot do this until we have a RTT measurement though) if (baseRTT != (unsigned)-1) { extraBuffer += delta; - consumed = msBetween(&lastUpdate, &now) * congWindow / baseRTT; + consumed = core::msBetween(&lastUpdate, &now) * congWindow / baseRTT; if (extraBuffer < consumed) extraBuffer = 0; else @@ -174,7 +177,7 @@ void Congestion::gotPong() lastPong = rttInfo; lastPongArrival = now; - rtt = msBetween(&rttInfo.tv, &now); + rtt = core::msBetween(&rttInfo.tv, &now); if (rtt < 1) rtt = 1; @@ -184,7 +187,7 @@ void Congestion::gotPong() // Pings sent before the last adjustment aren't interesting as they // aren't a measurement of the current congestion window - if (isBefore(&rttInfo.tv, &lastAdjustment)) + if (core::isBefore(&rttInfo.tv, &lastAdjustment)) return; // Estimate added delay because of overtaxed buffers (see above) @@ -249,7 +252,7 @@ int Congestion::getUncongestedETA() prevPing = &lastPong; eta = 0; - elapsed = msSince(&lastPongArrival); + elapsed = core::msSince(&lastPongArrival); // Walk the ping queue and figure out which one we are waiting for to // get to an uncongested state @@ -268,7 +271,7 @@ int Congestion::getUncongestedETA() curPing = *iter; } - etaNext = msBetween(&prevPing->tv, &curPing.tv); + etaNext = core::msBetween(&prevPing->tv, &curPing.tv); // Compensate for buffering delays delay = curPing.extra * baseRTT / congWindow; etaNext += delay; @@ -349,7 +352,7 @@ unsigned Congestion::getExtraBuffer() if (baseRTT == (unsigned)-1) return 0; - elapsed = msSince(&lastUpdate); + elapsed = core::msSince(&lastUpdate); consumed = elapsed * congWindow / baseRTT; if (consumed >= extraBuffer) @@ -389,7 +392,7 @@ unsigned Congestion::getInFlight() // completely. Look at the next ping that should arrive and figure // out how far behind it should be and interpolate the positions. - etaNext = msBetween(&lastPong.tv, &nextPong.tv); + etaNext = core::msBetween(&lastPong.tv, &nextPong.tv); // Compensate for buffering delays delay = nextPong.extra * baseRTT / congWindow; etaNext += delay; @@ -399,7 +402,7 @@ unsigned Congestion::getInFlight() else etaNext -= delay; - elapsed = msSince(&lastPongArrival); + elapsed = core::msSince(&lastPongArrival); // The pong should be here any second. Be optimistic and assume // we can already use its value. @@ -430,7 +433,7 @@ void Congestion::updateCongestion() diff = minRTT - baseRTT; - if (diff > __rfbmax(100, baseRTT/2)) { + if (diff > 100 && diff > baseRTT/2) { // We have no way of detecting loss, so assume massive latency // spike means packet loss. Adjust the window and go directly // to congestion avoidance. diff --git a/common/rfb/CopyRectDecoder.cxx b/common/rfb/CopyRectDecoder.cxx index a7383881..efc77c99 100644 --- a/common/rfb/CopyRectDecoder.cxx +++ b/common/rfb/CopyRectDecoder.cxx @@ -20,10 +20,12 @@ #include <config.h> #endif +#include <core/Region.h> + #include <rdr/MemInStream.h> #include <rdr/OutStream.h> + #include <rfb/PixelBuffer.h> -#include <rfb/Region.h> #include <rfb/CopyRectDecoder.h> using namespace rfb; @@ -36,7 +38,7 @@ CopyRectDecoder::~CopyRectDecoder() { } -bool CopyRectDecoder::readRect(const Rect& /*r*/, +bool CopyRectDecoder::readRect(const core::Rect& /*r*/, rdr::InStream* is, const ServerParams& /*server*/, rdr::OutStream* os) @@ -48,11 +50,11 @@ bool CopyRectDecoder::readRect(const Rect& /*r*/, } -void CopyRectDecoder::getAffectedRegion(const Rect& rect, +void CopyRectDecoder::getAffectedRegion(const core::Rect& rect, const uint8_t* buffer, size_t buflen, const ServerParams& server, - Region* region) + core::Region* region) { rdr::MemInStream is(buffer, buflen); int srcX = is.readU16(); @@ -60,11 +62,12 @@ void CopyRectDecoder::getAffectedRegion(const Rect& rect, Decoder::getAffectedRegion(rect, buffer, buflen, server, region); - region->assign_union(Region(rect.translate(Point(srcX-rect.tl.x, - srcY-rect.tl.y)))); + region->assign_union(rect.translate({srcX-rect.tl.x, + srcY-rect.tl.y})); } -void CopyRectDecoder::decodeRect(const Rect& r, const uint8_t* buffer, +void CopyRectDecoder::decodeRect(const core::Rect& r, + const uint8_t* buffer, size_t buflen, const ServerParams& /*server*/, ModifiablePixelBuffer* pb) @@ -72,5 +75,5 @@ void CopyRectDecoder::decodeRect(const Rect& r, const uint8_t* buffer, rdr::MemInStream is(buffer, buflen); int srcX = is.readU16(); int srcY = is.readU16(); - pb->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY)); + pb->copyRect(r, {r.tl.x-srcX, r.tl.y-srcY}); } diff --git a/common/rfb/CopyRectDecoder.h b/common/rfb/CopyRectDecoder.h index 51651196..b1d0d38d 100644 --- a/common/rfb/CopyRectDecoder.h +++ b/common/rfb/CopyRectDecoder.h @@ -26,13 +26,13 @@ namespace rfb { public: CopyRectDecoder(); virtual ~CopyRectDecoder(); - bool readRect(const Rect& r, rdr::InStream* is, + bool readRect(const core::Rect& r, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os) override; - void getAffectedRegion(const Rect& rect, const uint8_t* buffer, + void getAffectedRegion(const core::Rect& rect, const uint8_t* buffer, size_t buflen, const ServerParams& server, - Region* region) override; - void decodeRect(const Rect& r, const uint8_t* buffer, + core::Region* region) override; + void decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) override; }; diff --git a/common/rfb/Cursor.cxx b/common/rfb/Cursor.cxx index 94844144..e094e4ed 100644 --- a/common/rfb/Cursor.cxx +++ b/common/rfb/Cursor.cxx @@ -26,14 +26,15 @@ #include <stdexcept> +#include <core/LogWriter.h> + #include <rfb/Cursor.h> -#include <rfb/LogWriter.h> using namespace rfb; -static LogWriter vlog("Cursor"); +static core::LogWriter vlog("Cursor"); -Cursor::Cursor(int width, int height, const Point& hotspot, +Cursor::Cursor(int width, int height, const core::Point& hotspot, const uint8_t* data_) : width_(width), height_(height), hotspot_(hotspot) { @@ -215,9 +216,9 @@ std::vector<uint8_t> Cursor::getMask() const void Cursor::crop() { - Rect busy = Rect(0, 0, width_, height_); - busy = busy.intersect(Rect(hotspot_.x, hotspot_.y, - hotspot_.x+1, hotspot_.y+1)); + core::Rect busy(0, 0, width_, height_); + busy = busy.intersect({hotspot_.x, hotspot_.y, + hotspot_.x+1, hotspot_.y+1}); int x, y; uint8_t *data_ptr = data; for (y = 0; y < height(); y++) { @@ -255,9 +256,10 @@ RenderedCursor::RenderedCursor() { } -const uint8_t* RenderedCursor::getBuffer(const Rect& _r, int* stride) const +const uint8_t* RenderedCursor::getBuffer(const core::Rect& _r, + int* stride) const { - Rect r; + core::Rect r; r = _r.translate(offset.negate()); if (!r.enclosed_by(buffer.getRect())) @@ -267,10 +269,10 @@ const uint8_t* RenderedCursor::getBuffer(const Rect& _r, int* stride) const } void RenderedCursor::update(PixelBuffer* framebuffer, - Cursor* cursor, const Point& pos) + Cursor* cursor, const core::Point& pos) { - Point rawOffset, diff; - Rect clippedRect; + core::Point rawOffset, diff; + core::Rect clippedRect; const uint8_t* data; int stride; @@ -282,7 +284,7 @@ void RenderedCursor::update(PixelBuffer* framebuffer, setSize(framebuffer->width(), framebuffer->height()); rawOffset = pos.subtract(cursor->hotspot()); - clippedRect = Rect(0, 0, cursor->width(), cursor->height()) + clippedRect = core::Rect(0, 0, cursor->width(), cursor->height()) .translate(rawOffset) .intersect(framebuffer->getRect()); offset = clippedRect.tl; @@ -313,7 +315,7 @@ void RenderedCursor::update(PixelBuffer* framebuffer, else if (fg[3] == 0xff) { memcpy(rgb, fg, 3); } else { - buffer.getImage(bg, Rect(x, y, x+1, y+1)); + buffer.getImage(bg, {x, y, x+1, y+1}); format.rgbFromBuffer(rgb, bg, 1); // FIXME: Gamma aware blending for (int i = 0;i < 3;i++) { @@ -323,7 +325,7 @@ void RenderedCursor::update(PixelBuffer* framebuffer, } format.bufferFromRGB(bg, rgb, 1); - buffer.imageRect(Rect(x, y, x+1, y+1), bg); + buffer.imageRect({x, y, x+1, y+1}, bg); } } } diff --git a/common/rfb/Cursor.h b/common/rfb/Cursor.h index c71f5a77..ef3c1b80 100644 --- a/common/rfb/Cursor.h +++ b/common/rfb/Cursor.h @@ -26,19 +26,22 @@ #include <vector> +#include <core/Rect.h> + #include <rfb/PixelBuffer.h> namespace rfb { class Cursor { public: - Cursor(int width, int height, const Point& hotspot, const uint8_t* data); + Cursor(int width, int height, const core::Point& hotspot, + const uint8_t* data); Cursor(const Cursor& other); ~Cursor(); int width() const { return width_; }; int height() const { return height_; }; - const Point& hotspot() const { return hotspot_; }; + const core::Point& hotspot() const { return hotspot_; }; const uint8_t* getBuffer() const { return data; }; // getBitmap() returns a monochrome version of the cursor @@ -52,7 +55,7 @@ namespace rfb { protected: int width_, height_; - Point hotspot_; + core::Point hotspot_; uint8_t* data; }; @@ -60,15 +63,16 @@ namespace rfb { public: RenderedCursor(); - Rect getEffectiveRect() const { return buffer.getRect(offset); } + core::Rect getEffectiveRect() const { return buffer.getRect(offset); } - const uint8_t* getBuffer(const Rect& r, int* stride) const override; + const uint8_t* getBuffer(const core::Rect& r, int* stride) const override; - void update(PixelBuffer* framebuffer, Cursor* cursor, const Point& pos); + void update(PixelBuffer* framebuffer, Cursor* cursor, + const core::Point& pos); protected: ManagedPixelBuffer buffer; - Point offset; + core::Point offset; }; } diff --git a/common/rfb/DecodeManager.cxx b/common/rfb/DecodeManager.cxx index 4effe985..48181f94 100644 --- a/common/rfb/DecodeManager.cxx +++ b/common/rfb/DecodeManager.cxx @@ -23,22 +23,20 @@ #include <assert.h> #include <string.h> +#include <core/LogWriter.h> +#include <core/Region.h> +#include <core/string.h> + #include <rfb/CConnection.h> #include <rfb/DecodeManager.h> #include <rfb/Decoder.h> #include <rfb/Exception.h> -#include <rfb/Region.h> -#include <rfb/LogWriter.h> -#include <rfb/util.h> -#include <rdr/Exception.h> #include <rdr/MemOutStream.h> -#include <os/Mutex.h> - using namespace rfb; -static LogWriter vlog("DecodeManager"); +static core::LogWriter vlog("DecodeManager"); DecodeManager::DecodeManager(CConnection *conn_) : conn(conn_), threadException(nullptr) @@ -49,11 +47,7 @@ DecodeManager::DecodeManager(CConnection *conn_) : memset(stats, 0, sizeof(stats)); - queueMutex = new os::Mutex(); - producerCond = new os::Condition(queueMutex); - consumerCond = new os::Condition(queueMutex); - - cpuCount = os::Thread::getSystemCPUCount(); + cpuCount = std::thread::hardware_concurrency(); if (cpuCount == 0) { vlog.error("Unable to determine the number of CPU cores on this system"); cpuCount = 1; @@ -86,22 +80,16 @@ DecodeManager::~DecodeManager() threads.pop_back(); } - delete threadException; - while (!freeBuffers.empty()) { delete freeBuffers.back(); freeBuffers.pop_back(); } - delete consumerCond; - delete producerCond; - delete queueMutex; - for (Decoder* decoder : decoders) delete decoder; } -bool DecodeManager::decodeRect(const Rect& r, int encoding, +bool DecodeManager::decodeRect(const core::Rect& r, int encoding, ModifiablePixelBuffer* pb) { Decoder *decoder; @@ -128,29 +116,25 @@ bool DecodeManager::decodeRect(const Rect& r, int encoding, decoder = decoders[encoding]; // Wait for an available memory buffer - queueMutex->lock(); + std::unique_lock<std::mutex> lock(queueMutex); // FIXME: Should we return and let other things run here? while (freeBuffers.empty()) - producerCond->wait(); + producerCond.wait(lock); // Don't pop the buffer in case we throw an exception // whilst reading bufferStream = freeBuffers.front(); - queueMutex->unlock(); + lock.unlock(); // First check if any thread has encountered a problem throwThreadException(); // Read the rect bufferStream->clear(); - try { - if (!decoder->readRect(r, conn->getInStream(), conn->server, bufferStream)) - return false; - } catch (std::exception& e) { - throw std::runtime_error(format("Error reading rect: %s", e.what())); - } + if (!decoder->readRect(r, conn->getInStream(), conn->server, bufferStream)) + return false; stats[encoding].rects++; stats[encoding].bytes += 12 + bufferStream->length(); @@ -173,7 +157,7 @@ bool DecodeManager::decodeRect(const Rect& r, int encoding, bufferStream->length(), conn->server, &entry->affectedRegion); - queueMutex->lock(); + lock.lock(); // The workers add buffers to the end so it's safe to assume // the front is still the same buffer @@ -183,21 +167,21 @@ bool DecodeManager::decodeRect(const Rect& r, int encoding, // We only put a single entry on the queue so waking a single // thread is sufficient - consumerCond->signal(); + consumerCond.notify_one(); - queueMutex->unlock(); + lock.unlock(); return true; } void DecodeManager::flush() { - queueMutex->lock(); + std::unique_lock<std::mutex> lock(queueMutex); while (!workQueue.empty()) - producerCond->wait(); + producerCond.wait(lock); - queueMutex->unlock(); + lock.unlock(); throwThreadException(); } @@ -227,49 +211,49 @@ void DecodeManager::logStats() ratio = (double)stats[i].equivalent / stats[i].bytes; vlog.info(" %s: %s, %s", encodingName(i), - siPrefix(stats[i].rects, "rects").c_str(), - siPrefix(stats[i].pixels, "pixels").c_str()); + core::siPrefix(stats[i].rects, "rects").c_str(), + core::siPrefix(stats[i].pixels, "pixels").c_str()); vlog.info(" %*s %s (1:%g ratio)", (int)strlen(encodingName(i)), "", - iecPrefix(stats[i].bytes, "B").c_str(), ratio); + core::iecPrefix(stats[i].bytes, "B").c_str(), ratio); } ratio = (double)equivalent / bytes; vlog.info(" Total: %s, %s", - siPrefix(rects, "rects").c_str(), - siPrefix(pixels, "pixels").c_str()); + core::siPrefix(rects, "rects").c_str(), + core::siPrefix(pixels, "pixels").c_str()); vlog.info(" %s (1:%g ratio)", - iecPrefix(bytes, "B").c_str(), ratio); + core::iecPrefix(bytes, "B").c_str(), ratio); } -void DecodeManager::setThreadException(const std::exception& e) +void DecodeManager::setThreadException() { - os::AutoMutex a(queueMutex); + const std::lock_guard<std::mutex> lock(queueMutex); - if (threadException != nullptr) + if (threadException) return; - threadException = new std::runtime_error(format("Exception on worker thread: %s", e.what())); + threadException = std::current_exception(); } void DecodeManager::throwThreadException() { - os::AutoMutex a(queueMutex); + const std::lock_guard<std::mutex> lock(queueMutex); - if (threadException == nullptr) + if (!threadException) return; - std::runtime_error e(threadException->what()); - - delete threadException; - threadException = nullptr; - - throw e; + try { + std::rethrow_exception(threadException); + } catch (...) { + threadException = nullptr; + throw; + } } DecodeManager::DecodeThread::DecodeThread(DecodeManager* manager_) - : manager(manager_), stopRequested(false) + : manager(manager_), thread(nullptr), stopRequested(false) { start(); } @@ -277,25 +261,35 @@ DecodeManager::DecodeThread::DecodeThread(DecodeManager* manager_) DecodeManager::DecodeThread::~DecodeThread() { stop(); - wait(); + if (thread != nullptr) { + thread->join(); + delete thread; + } +} + +void DecodeManager::DecodeThread::start() +{ + assert(thread == nullptr); + + thread = new std::thread(&DecodeThread::worker, this); } void DecodeManager::DecodeThread::stop() { - os::AutoMutex a(manager->queueMutex); + const std::lock_guard<std::mutex> lock(manager->queueMutex); - if (!isRunning()) + if (thread == nullptr) return; stopRequested = true; // We can't wake just this thread, so wake everyone - manager->consumerCond->broadcast(); + manager->consumerCond.notify_all(); } void DecodeManager::DecodeThread::worker() { - manager->queueMutex->lock(); + std::unique_lock<std::mutex> lock(manager->queueMutex); while (!stopRequested) { DecodeManager::QueueEntry *entry; @@ -304,14 +298,14 @@ void DecodeManager::DecodeThread::worker() entry = findEntry(); if (entry == nullptr) { // Wait and try again - manager->consumerCond->wait(); + manager->consumerCond.wait(lock); continue; } // This is ours now entry->active = true; - manager->queueMutex->unlock(); + lock.unlock(); // Do the actual decoding try { @@ -319,12 +313,12 @@ void DecodeManager::DecodeThread::worker() entry->bufferStream->length(), *entry->server, entry->pb); } catch (std::exception& e) { - manager->setThreadException(e); + manager->setThreadException(); } catch(...) { assert(false); } - manager->queueMutex->lock(); + lock.lock(); // Remove the entry from the queue and give back the memory buffer manager->freeBuffers.push_back(entry->bufferStream); @@ -332,19 +326,17 @@ void DecodeManager::DecodeThread::worker() delete entry; // Wake the main thread in case it is waiting for a memory buffer - manager->producerCond->signal(); + manager->producerCond.notify_one(); // This rect might have been blocking multiple other rects, so // wake up every worker thread if (manager->workQueue.size() > 1) - manager->consumerCond->broadcast(); + manager->consumerCond.notify_all(); } - - manager->queueMutex->unlock(); } DecodeManager::QueueEntry* DecodeManager::DecodeThread::findEntry() { - Region lockedRegion; + core::Region lockedRegion; if (manager->workQueue.empty()) return nullptr; diff --git a/common/rfb/DecodeManager.h b/common/rfb/DecodeManager.h index b11b7044..146bf8ae 100644 --- a/common/rfb/DecodeManager.h +++ b/common/rfb/DecodeManager.h @@ -19,16 +19,18 @@ #ifndef __RFB_DECODEMANAGER_H__ #define __RFB_DECODEMANAGER_H__ +#include <condition_variable> +#include <exception> #include <list> +#include <mutex> +#include <thread> -#include <os/Thread.h> +#include <core/Region.h> -#include <rfb/Region.h> #include <rfb/encodings.h> -namespace os { - class Condition; - class Mutex; +namespace core { + struct Rect; } namespace rdr { @@ -36,17 +38,17 @@ namespace rdr { } namespace rfb { + class CConnection; class Decoder; class ModifiablePixelBuffer; - struct Rect; class DecodeManager { public: DecodeManager(CConnection *conn); ~DecodeManager(); - bool decodeRect(const Rect& r, int encoding, + bool decodeRect(const core::Rect& r, int encoding, ModifiablePixelBuffer* pb); void flush(); @@ -54,7 +56,7 @@ namespace rfb { private: void logStats(); - void setThreadException(const std::exception& e); + void setThreadException(); void throwThreadException(); private: @@ -72,43 +74,46 @@ namespace rfb { struct QueueEntry { bool active; - Rect rect; + core::Rect rect; int encoding; Decoder* decoder; const ServerParams* server; ModifiablePixelBuffer* pb; rdr::MemOutStream* bufferStream; - Region affectedRegion; + core::Region affectedRegion; }; std::list<rdr::MemOutStream*> freeBuffers; std::list<QueueEntry*> workQueue; - os::Mutex* queueMutex; - os::Condition* producerCond; - os::Condition* consumerCond; + std::mutex queueMutex; + std::condition_variable producerCond; + std::condition_variable consumerCond; private: - class DecodeThread : public os::Thread { + class DecodeThread { public: DecodeThread(DecodeManager* manager); ~DecodeThread(); + void start(); void stop(); protected: - void worker() override; + void worker(); DecodeManager::QueueEntry* findEntry(); private: DecodeManager* manager; + std::thread* thread; bool stopRequested; }; std::list<DecodeThread*> threads; - std::exception *threadException; + std::exception_ptr threadException; }; + } #endif diff --git a/common/rfb/Decoder.cxx b/common/rfb/Decoder.cxx index e9bc9a4f..0f1cde89 100644 --- a/common/rfb/Decoder.cxx +++ b/common/rfb/Decoder.cxx @@ -22,8 +22,10 @@ #endif #include <stdio.h> + +#include <core/Region.h> + #include <rfb/encodings.h> -#include <rfb/Region.h> #include <rfb/Decoder.h> #include <rfb/RawDecoder.h> #include <rfb/CopyRectDecoder.h> @@ -45,19 +47,19 @@ Decoder::~Decoder() { } -void Decoder::getAffectedRegion(const Rect& rect, +void Decoder::getAffectedRegion(const core::Rect& rect, const uint8_t* /*buffer*/, size_t /*buflen*/, const ServerParams& /*server*/, - Region* region) + core::Region* region) { region->reset(rect); } -bool Decoder::doRectsConflict(const Rect& /*rectA*/, +bool Decoder::doRectsConflict(const core::Rect& /*rectA*/, const uint8_t* /*bufferA*/, size_t /*buflenA*/, - const Rect& /*rectB*/, + const core::Rect& /*rectB*/, const uint8_t* /*bufferB*/, size_t /*buflenB*/, const ServerParams& /*server*/) diff --git a/common/rfb/Decoder.h b/common/rfb/Decoder.h index 77987737..17d5296b 100644 --- a/common/rfb/Decoder.h +++ b/common/rfb/Decoder.h @@ -19,19 +19,23 @@ #ifndef __RFB_DECODER_H__ #define __RFB_DECODER_H__ +#include <stddef.h> #include <stdint.h> +namespace core { + class Region; + struct Rect; +} + namespace rdr { class InStream; class OutStream; } namespace rfb { + class ServerParams; class ModifiablePixelBuffer; - class Region; - - struct Rect; enum DecoderFlags { // A constant for decoders that don't need anything special @@ -54,7 +58,7 @@ namespace rfb { // InStream to the OutStream, possibly changing it along the way to // make it easier to decode. This function will always be called in // a serial manner on the main thread. - virtual bool readRect(const Rect& r, rdr::InStream* is, + virtual bool readRect(const core::Rect& r, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os)=0; // These functions will be called from any of the worker threads. @@ -64,17 +68,17 @@ namespace rfb { // getAffectedRegion() returns the parts of the frame buffer will // 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 uint8_t* buffer, + virtual void getAffectedRegion(const core::Rect& rect, const uint8_t* buffer, size_t buflen, const ServerParams& server, - Region* region); + core::Region* region); // doesRectsConflict() determines if two rectangles must be decoded // in the order they were received. This will only be called if the // DecoderPartiallyOrdered flag has been set. - virtual bool doRectsConflict(const Rect& rectA, + virtual bool doRectsConflict(const core::Rect& rectA, const uint8_t* bufferA, size_t buflenA, - const Rect& rectB, + const core::Rect& rectB, const uint8_t* bufferB, size_t buflenB, const ServerParams& server); @@ -83,7 +87,7 @@ namespace rfb { // 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 uint8_t* buffer, + virtual void decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb)=0; @@ -94,6 +98,7 @@ namespace rfb { public: const enum DecoderFlags flags; }; + } #endif diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx index 67a32f5b..6a63fa6f 100644 --- a/common/rfb/EncodeManager.cxx +++ b/common/rfb/EncodeManager.cxx @@ -25,14 +25,17 @@ #include <stdlib.h> +#include <core/LogWriter.h> +#include <core/string.h> + +#include <rfb/Cursor.h> #include <rfb/EncodeManager.h> #include <rfb/Encoder.h> #include <rfb/Palette.h> #include <rfb/SConnection.h> #include <rfb/SMsgWriter.h> #include <rfb/UpdateTracker.h> -#include <rfb/LogWriter.h> -#include <rfb/util.h> +#include <rfb/encodings.h> #include <rfb/RawEncoder.h> #include <rfb/RREEncoder.h> @@ -43,7 +46,7 @@ using namespace rfb; -static LogWriter vlog("EncodeManager"); +static core::LogWriter vlog("EncodeManager"); // Split each rectangle into smaller ones no larger than this area, // and no wider than this width. @@ -191,11 +194,11 @@ void EncodeManager::logStats() ratio = (double)copyStats.equivalent / copyStats.bytes; vlog.info(" %s: %s, %s", "Copies", - siPrefix(copyStats.rects, "rects").c_str(), - siPrefix(copyStats.pixels, "pixels").c_str()); + core::siPrefix(copyStats.rects, "rects").c_str(), + core::siPrefix(copyStats.pixels, "pixels").c_str()); vlog.info(" %*s %s (1:%g ratio)", (int)strlen("Copies"), "", - iecPrefix(copyStats.bytes, "B").c_str(), ratio); + core::iecPrefix(copyStats.bytes, "B").c_str(), ratio); } for (i = 0;i < stats.size();i++) { @@ -221,21 +224,21 @@ void EncodeManager::logStats() ratio = (double)stats[i][j].equivalent / stats[i][j].bytes; vlog.info(" %s: %s, %s", encoderTypeName((EncoderType)j), - siPrefix(stats[i][j].rects, "rects").c_str(), - siPrefix(stats[i][j].pixels, "pixels").c_str()); + core::siPrefix(stats[i][j].rects, "rects").c_str(), + core::siPrefix(stats[i][j].pixels, "pixels").c_str()); vlog.info(" %*s %s (1:%g ratio)", (int)strlen(encoderTypeName((EncoderType)j)), "", - iecPrefix(stats[i][j].bytes, "B").c_str(), ratio); + core::iecPrefix(stats[i][j].bytes, "B").c_str(), ratio); } } ratio = (double)equivalent / bytes; vlog.info(" Total: %s, %s", - siPrefix(rects, "rects").c_str(), - siPrefix(pixels, "pixels").c_str()); + core::siPrefix(rects, "rects").c_str(), + core::siPrefix(pixels, "pixels").c_str()); vlog.info(" %s (1:%g ratio)", - iecPrefix(bytes, "B").c_str(), ratio); + core::iecPrefix(bytes, "B").c_str(), ratio); } bool EncodeManager::supported(int encoding) @@ -252,12 +255,12 @@ bool EncodeManager::supported(int encoding) } } -bool EncodeManager::needsLosslessRefresh(const Region& req) +bool EncodeManager::needsLosslessRefresh(const core::Region& req) { return !lossyRegion.intersect(req).is_empty(); } -int EncodeManager::getNextLosslessRefresh(const Region& req) +int EncodeManager::getNextLosslessRefresh(const core::Region& req) { // Do we have something we can send right away? if (!pendingRefreshRegion.intersect(req).is_empty()) @@ -269,12 +272,19 @@ int EncodeManager::getNextLosslessRefresh(const Region& req) return recentChangeTimer.getNextTimeout(); } -void EncodeManager::pruneLosslessRefresh(const Region& limits) +void EncodeManager::pruneLosslessRefresh(const core::Region& limits) { lossyRegion.assign_intersect(limits); pendingRefreshRegion.assign_intersect(limits); } +void EncodeManager::forceRefresh(const core::Region& req) +{ + lossyRegion.assign_union(req); + if (!recentChangeTimer.isStarted()) + pendingRefreshRegion.assign_union(req); +} + void EncodeManager::writeUpdate(const UpdateInfo& ui, const PixelBuffer* pb, const RenderedCursor* renderedCursor) { @@ -286,15 +296,16 @@ void EncodeManager::writeUpdate(const UpdateInfo& ui, const PixelBuffer* pb, recentChangeTimer.start(RecentChangeTimeout); } -void EncodeManager::writeLosslessRefresh(const Region& req, const PixelBuffer* pb, +void EncodeManager::writeLosslessRefresh(const core::Region& req, + const PixelBuffer* pb, const RenderedCursor* renderedCursor, size_t maxUpdateSize) { doUpdate(false, getLosslessRefresh(req, maxUpdateSize), - Region(), Point(), pb, renderedCursor); + {}, {}, pb, renderedCursor); } -void EncodeManager::handleTimeout(Timer* t) +void EncodeManager::handleTimeout(core::Timer* t) { if (t == &recentChangeTimer) { // Any lossy region that wasn't recently updated can @@ -308,13 +319,15 @@ void EncodeManager::handleTimeout(Timer* t) } } -void EncodeManager::doUpdate(bool allowLossy, const Region& changed_, - const Region& copied, const Point& copyDelta, +void EncodeManager::doUpdate(bool allowLossy, const + core::Region& changed_, + const core::Region& copied, + const core::Point& copyDelta, const PixelBuffer* pb, const RenderedCursor* renderedCursor) { int nRects; - Region changed, cursorRegion; + core::Region changed, cursorRegion; updates++; @@ -475,19 +488,20 @@ void EncodeManager::prepareEncoders(bool allowLossy) encoder->setFineQualityLevel(conn->client.fineQualityLevel, conn->client.subsampling); } else { - int level = __rfbmax(conn->client.qualityLevel, - encoder->losslessQuality); - encoder->setQualityLevel(level); + if (conn->client.qualityLevel < encoder->losslessQuality) + encoder->setQualityLevel(encoder->losslessQuality); + else + encoder->setQualityLevel(conn->client.qualityLevel); encoder->setFineQualityLevel(-1, subsampleUndefined); } } } -Region EncodeManager::getLosslessRefresh(const Region& req, - size_t maxUpdateSize) +core::Region EncodeManager::getLosslessRefresh(const core::Region& req, + size_t maxUpdateSize) { - std::vector<Rect> rects; - Region refresh; + std::vector<core::Rect> rects; + core::Region refresh; size_t area; // We make a conservative guess at the compression ratio at 2:1 @@ -500,7 +514,7 @@ Region EncodeManager::getLosslessRefresh(const Region& req, pendingRefreshRegion.intersect(req).get_rects(&rects); while (!rects.empty()) { size_t idx; - Rect rect; + core::Rect rect; // Grab a random rect so we don't keep damaging and restoring the // same rect over and over @@ -514,17 +528,21 @@ Region EncodeManager::getLosslessRefresh(const Region& req, // Use the narrowest axis to avoid getting to thin rects if (rect.width() > rect.height()) { int width = (maxUpdateSize - area) / rect.height(); - rect.br.x = rect.tl.x + __rfbmax(1, width); + if (width < 1) + width = 1; + rect.br.x = rect.tl.x + width; } else { int height = (maxUpdateSize - area) / rect.width(); - rect.br.y = rect.tl.y + __rfbmax(1, height); + if (height < 1) + height = 1; + rect.br.y = rect.tl.y + height; } - refresh.assign_union(Region(rect)); + refresh.assign_union(rect); break; } area += rect.area(); - refresh.assign_union(Region(rect)); + refresh.assign_union(rect); rects.erase(rects.begin() + idx); } @@ -532,11 +550,11 @@ Region EncodeManager::getLosslessRefresh(const Region& req, return refresh; } -int EncodeManager::computeNumRects(const Region& changed) +int EncodeManager::computeNumRects(const core::Region& changed) { int numRects; - std::vector<Rect> rects; - std::vector<Rect>::const_iterator rect; + std::vector<core::Rect> rects; + std::vector<core::Rect>::const_iterator rect; numRects = 0; changed.get_rects(&rects); @@ -566,7 +584,7 @@ int EncodeManager::computeNumRects(const Region& changed) return numRects; } -Encoder *EncodeManager::startRect(const Rect& rect, int type) +Encoder* EncodeManager::startRect(const core::Rect& rect, int type) { Encoder *encoder; int klass, equiv; @@ -587,13 +605,13 @@ Encoder *EncodeManager::startRect(const Rect& rect, int type) if ((encoder->flags & EncoderLossy) && ((encoder->losslessQuality == -1) || (encoder->getQualityLevel() < encoder->losslessQuality))) - lossyRegion.assign_union(Region(rect)); + lossyRegion.assign_union(rect); else - lossyRegion.assign_subtract(Region(rect)); + lossyRegion.assign_subtract(rect); // This was either a rect getting refreshed, or a rect that just got // new content. Either way we should not try to refresh it anymore. - pendingRefreshRegion.assign_subtract(Region(rect)); + pendingRefreshRegion.assign_subtract(rect); return encoder; } @@ -611,12 +629,13 @@ void EncodeManager::endRect() stats[klass][activeType].bytes += length; } -void EncodeManager::writeCopyRects(const Region& copied, const Point& delta) +void EncodeManager::writeCopyRects(const core::Region& copied, + const core::Point& delta) { - std::vector<Rect> rects; - std::vector<Rect>::const_iterator rect; + std::vector<core::Rect> rects; + std::vector<core::Rect>::const_iterator rect; - Region lossyCopy; + core::Region lossyCopy; beforeLength = conn->getOutStream()->length(); @@ -645,20 +664,22 @@ void EncodeManager::writeCopyRects(const Region& copied, const Point& delta) pendingRefreshRegion.assign_subtract(copied); } -void EncodeManager::writeSolidRects(Region *changed, const PixelBuffer* pb) +void EncodeManager::writeSolidRects(core::Region* changed, + const PixelBuffer* pb) { - std::vector<Rect> rects; - std::vector<Rect>::const_iterator rect; + std::vector<core::Rect> rects; + std::vector<core::Rect>::const_iterator rect; changed->get_rects(&rects); for (rect = rects.begin(); rect != rects.end(); ++rect) findSolidRect(*rect, changed, pb); } -void EncodeManager::findSolidRect(const Rect& rect, Region *changed, +void EncodeManager::findSolidRect(const core::Rect& rect, + core::Region* changed, const PixelBuffer* pb) { - Rect sr; + core::Rect sr; int dx, dy, dw, dh; // We start by finding a solid 16x16 block @@ -677,11 +698,11 @@ void EncodeManager::findSolidRect(const Rect& rect, Region *changed, if (dx + dw > rect.br.x) dw = rect.br.x - dx; - pb->getImage(colourValue, Rect(dx, dy, dx+1, dy+1)); + pb->getImage(colourValue, {dx, dy, dx+1, dy+1}); sr.setXYWH(dx, dy, dw, dh); if (checkSolidTile(sr, colourValue, pb)) { - Rect erb, erp; + core::Rect erb, erp; Encoder *encoder; @@ -721,7 +742,7 @@ void EncodeManager::findSolidRect(const Rect& rect, Region *changed, } endRect(); - changed->assign_subtract(Region(erp)); + changed->assign_subtract(erp); // Search remaining areas by recursion // FIXME: Is this the best way to divide things up? @@ -752,15 +773,16 @@ void EncodeManager::findSolidRect(const Rect& rect, Region *changed, } } -void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb) +void EncodeManager::writeRects(const core::Region& changed, + const PixelBuffer* pb) { - std::vector<Rect> rects; - std::vector<Rect>::const_iterator rect; + std::vector<core::Rect> rects; + std::vector<core::Rect>::const_iterator rect; changed.get_rects(&rects); for (rect = rects.begin(); rect != rects.end(); ++rect) { int w, h, sw, sh; - Rect sr; + core::Rect sr; w = rect->width(); h = rect->height(); @@ -794,7 +816,8 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb) } } -void EncodeManager::writeSubRect(const Rect& rect, const PixelBuffer *pb) +void EncodeManager::writeSubRect(const core::Rect& rect, + const PixelBuffer* pb) { PixelBuffer *ppb; @@ -878,7 +901,8 @@ void EncodeManager::writeSubRect(const Rect& rect, const PixelBuffer *pb) endRect(); } -bool EncodeManager::checkSolidTile(const Rect& r, const uint8_t* colourValue, +bool EncodeManager::checkSolidTile(const core::Rect& r, + const uint8_t* colourValue, const PixelBuffer *pb) { const uint8_t* buffer; @@ -902,13 +926,14 @@ bool EncodeManager::checkSolidTile(const Rect& r, const uint8_t* colourValue, } } -void EncodeManager::extendSolidAreaByBlock(const Rect& r, +void EncodeManager::extendSolidAreaByBlock(const core::Rect& r, const uint8_t* colourValue, - const PixelBuffer *pb, Rect* er) + const PixelBuffer* pb, + core::Rect* er) { int dx, dy, dw, dh; int w_prev; - Rect sr; + core::Rect sr; int w_best = 0, h_best = 0; w_prev = r.width(); @@ -958,12 +983,14 @@ void EncodeManager::extendSolidAreaByBlock(const Rect& r, er->br.y = er->tl.y + h_best; } -void EncodeManager::extendSolidAreaByPixel(const Rect& r, const Rect& sr, +void EncodeManager::extendSolidAreaByPixel(const core::Rect& r, + const core::Rect& sr, const uint8_t* colourValue, - const PixelBuffer *pb, Rect* er) + const PixelBuffer* pb, + core::Rect* er) { int cx, cy; - Rect tr; + core::Rect tr; // Try to extend the area upwards. for (cy = sr.tl.y - 1; cy >= r.tl.y; cy--) { @@ -998,7 +1025,7 @@ void EncodeManager::extendSolidAreaByPixel(const Rect& r, const Rect& sr, er->br.x = cx; } -PixelBuffer* EncodeManager::preparePixelBuffer(const Rect& rect, +PixelBuffer* EncodeManager::preparePixelBuffer(const core::Rect& rect, const PixelBuffer *pb, bool convert) { @@ -1063,7 +1090,7 @@ void EncodeManager::OffsetPixelBuffer::update(const PixelFormat& pf, setBuffer(width, height, (uint8_t*)data_, stride_); } -uint8_t* EncodeManager::OffsetPixelBuffer::getBufferRW(const Rect& /*r*/, int* /*stride*/) +uint8_t* EncodeManager::OffsetPixelBuffer::getBufferRW(const core::Rect& /*r*/, int* /*stride*/) { throw std::logic_error("Invalid write attempt to OffsetPixelBuffer"); } diff --git a/common/rfb/EncodeManager.h b/common/rfb/EncodeManager.h index 7ae9b5b8..4ce6d0ce 100644 --- a/common/rfb/EncodeManager.h +++ b/common/rfb/EncodeManager.h @@ -24,21 +24,22 @@ #include <stdint.h> +#include <core/Region.h> +#include <core/Timer.h> + #include <rfb/PixelBuffer.h> -#include <rfb/Region.h> -#include <rfb/Timer.h> namespace rfb { + class SConnection; class Encoder; class UpdateInfo; class PixelBuffer; class RenderedCursor; - struct Rect; struct RectInfo; - class EncodeManager : public Timer::Callback { + class EncodeManager : public core::Timer::Callback { public: EncodeManager(SConnection* conn); ~EncodeManager(); @@ -48,51 +49,60 @@ namespace rfb { // Hack to let ConnParams calculate the client's preferred encoding static bool supported(int encoding); - bool needsLosslessRefresh(const Region& req); - int getNextLosslessRefresh(const Region& req); + bool needsLosslessRefresh(const core::Region& req); + int getNextLosslessRefresh(const core::Region& req); + + void pruneLosslessRefresh(const core::Region& limits); - void pruneLosslessRefresh(const Region& limits); + void forceRefresh(const core::Region& req); void writeUpdate(const UpdateInfo& ui, const PixelBuffer* pb, const RenderedCursor* renderedCursor); - void writeLosslessRefresh(const Region& req, const PixelBuffer* pb, + void writeLosslessRefresh(const core::Region& req, + const PixelBuffer* pb, const RenderedCursor* renderedCursor, size_t maxUpdateSize); protected: - void handleTimeout(Timer* t) override; + void handleTimeout(core::Timer* t) override; - void doUpdate(bool allowLossy, const Region& changed, - const Region& copied, const Point& copy_delta, + void doUpdate(bool allowLossy, const core::Region& changed, + const core::Region& copied, + const core::Point& copy_delta, const PixelBuffer* pb, const RenderedCursor* renderedCursor); void prepareEncoders(bool allowLossy); - Region getLosslessRefresh(const Region& req, size_t maxUpdateSize); + core::Region getLosslessRefresh(const core::Region& req, + size_t maxUpdateSize); - int computeNumRects(const Region& changed); + int computeNumRects(const core::Region& changed); - Encoder *startRect(const Rect& rect, int type); + Encoder* startRect(const core::Rect& rect, int type); void endRect(); - void writeCopyRects(const Region& copied, const Point& delta); - void writeSolidRects(Region *changed, const PixelBuffer* pb); - void findSolidRect(const Rect& rect, Region *changed, const PixelBuffer* pb); - void writeRects(const Region& changed, const PixelBuffer* pb); + void writeCopyRects(const core::Region& copied, + const core::Point& delta); + void writeSolidRects(core::Region* changed, const PixelBuffer* pb); + void findSolidRect(const core::Rect& rect, core::Region* changed, + const PixelBuffer* pb); + void writeRects(const core::Region& changed, const PixelBuffer* pb); - void writeSubRect(const Rect& rect, const PixelBuffer *pb); + void writeSubRect(const core::Rect& rect, const PixelBuffer* pb); - bool checkSolidTile(const Rect& r, const uint8_t* colourValue, + bool checkSolidTile(const core::Rect& r, const uint8_t* colourValue, const PixelBuffer *pb); - void extendSolidAreaByBlock(const Rect& r, const uint8_t* colourValue, - const PixelBuffer *pb, Rect* er); - void extendSolidAreaByPixel(const Rect& r, const Rect& sr, + void extendSolidAreaByBlock(const core::Rect& r, const uint8_t* colourValue, - const PixelBuffer *pb, Rect* er); + const PixelBuffer* pb, core::Rect* er); + void extendSolidAreaByPixel(const core::Rect& r, + const core::Rect& sr, + const uint8_t* colourValue, + const PixelBuffer* pb, core::Rect* er); - PixelBuffer* preparePixelBuffer(const Rect& rect, - const PixelBuffer *pb, bool convert); + PixelBuffer* preparePixelBuffer(const core::Rect& rect, + const PixelBuffer* pb, bool convert); bool analyseRect(const PixelBuffer *pb, struct RectInfo *info, int maxColours); @@ -114,11 +124,11 @@ namespace rfb { std::vector<Encoder*> encoders; std::vector<int> activeEncoders; - Region lossyRegion; - Region recentlyChangedRegion; - Region pendingRefreshRegion; + core::Region lossyRegion; + core::Region recentlyChangedRegion; + core::Region pendingRefreshRegion; - Timer recentChangeTimer; + core::Timer recentChangeTimer; struct EncoderStats { unsigned rects; @@ -143,12 +153,13 @@ namespace rfb { const uint8_t* data_, int stride); private: - uint8_t* getBufferRW(const Rect& r, int* stride) override; + uint8_t* getBufferRW(const core::Rect& r, int* stride) override; }; OffsetPixelBuffer offsetPixelBuffer; ManagedPixelBuffer convertedPixelBuffer; }; + } #endif diff --git a/common/rfb/Encoder.h b/common/rfb/Encoder.h index 5e066323..7fa2cc75 100644 --- a/common/rfb/Encoder.h +++ b/common/rfb/Encoder.h @@ -22,8 +22,6 @@ #include <stdint.h> -#include <rfb/Rect.h> - namespace rfb { class SConnection; class PixelBuffer; diff --git a/common/rfb/H264Decoder.cxx b/common/rfb/H264Decoder.cxx index 89850ba4..d0d9b4df 100644 --- a/common/rfb/H264Decoder.cxx +++ b/common/rfb/H264Decoder.cxx @@ -29,14 +29,11 @@ #include <rdr/MemInStream.h> #include <rdr/InStream.h> #include <rdr/OutStream.h> -#include <rfb/LogWriter.h> #include <rfb/H264Decoder.h> #include <rfb/H264DecoderContext.h> using namespace rfb; -static LogWriter vlog("H264Decoder"); - enum rectFlags { resetContext = 0x1, resetAllContexts = 0x2, @@ -53,22 +50,20 @@ H264Decoder::~H264Decoder() void H264Decoder::resetContexts() { - os::AutoMutex lock(&mutex); for (H264DecoderContext* context : contexts) delete context; contexts.clear(); } -H264DecoderContext* H264Decoder::findContext(const Rect& r) +H264DecoderContext* H264Decoder::findContext(const core::Rect& r) { - os::AutoMutex m(&mutex); for (H264DecoderContext* context : contexts) if (context->isEqualRect(r)) return context; return nullptr; } -bool H264Decoder::readRect(const Rect& /*r*/, +bool H264Decoder::readRect(const core::Rect& /*r*/, rdr::InStream* is, const ServerParams& /*server*/, rdr::OutStream* os) @@ -96,7 +91,7 @@ bool H264Decoder::readRect(const Rect& /*r*/, return true; } -void H264Decoder::decodeRect(const Rect& r, const uint8_t* buffer, +void H264Decoder::decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& /*server*/, ModifiablePixelBuffer* pb) @@ -116,9 +111,14 @@ void H264Decoder::decodeRect(const Rect& r, const uint8_t* buffer, ctx = findContext(r); } + if (ctx && (reset & resetContext)) { + contexts.remove(ctx); + delete ctx; + ctx = nullptr; + } + if (!ctx) { - os::AutoMutex lock(&mutex); if (contexts.size() >= MAX_H264_INSTANCES) { H264DecoderContext* excess_ctx = contexts.front(); @@ -131,12 +131,6 @@ void H264Decoder::decodeRect(const Rect& r, const uint8_t* buffer, contexts.push_back(ctx); } - if (!ctx->isReady()) - throw std::runtime_error("H264Decoder: Context is not ready"); - - if (reset & resetContext) - ctx->reset(); - if (!len) return; diff --git a/common/rfb/H264Decoder.h b/common/rfb/H264Decoder.h index 8ba47799..bc1b9281 100644 --- a/common/rfb/H264Decoder.h +++ b/common/rfb/H264Decoder.h @@ -21,9 +21,8 @@ #ifndef __RFB_H264DECODER_H__ #define __RFB_H264DECODER_H__ -#include <deque> +#include <list> -#include <os/Mutex.h> #include <rfb/Decoder.h> namespace rfb { @@ -33,19 +32,18 @@ namespace rfb { public: H264Decoder(); virtual ~H264Decoder(); - bool readRect(const Rect& r, rdr::InStream* is, + bool readRect(const core::Rect& r, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os) override; - void decodeRect(const Rect& r, const uint8_t* buffer, + void decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) override; private: void resetContexts(); - H264DecoderContext* findContext(const Rect& r); + H264DecoderContext* findContext(const core::Rect& r); - os::Mutex mutex; - std::deque<H264DecoderContext*> contexts; + std::list<H264DecoderContext*> contexts; }; } diff --git a/common/rfb/H264DecoderContext.cxx b/common/rfb/H264DecoderContext.cxx index b2054554..3ad8c343 100644 --- a/common/rfb/H264DecoderContext.cxx +++ b/common/rfb/H264DecoderContext.cxx @@ -22,11 +22,6 @@ #include <config.h> #endif -#include <stdexcept> - -#include <os/Mutex.h> -#include <rfb/LogWriter.h> - #include <rfb/H264DecoderContext.h> #ifdef H264_LIBAV @@ -39,31 +34,11 @@ using namespace rfb; -static LogWriter vlog("H264DecoderContext"); - -H264DecoderContext *H264DecoderContext::createContext(const Rect &r) +H264DecoderContext *H264DecoderContext::createContext(const core::Rect &r) { - H264DecoderContext *ret = new H264DecoderContextType(r); - if (!ret->initCodec()) - { - throw std::runtime_error("H264DecoderContext: Unable to create context"); - } - - return ret; + return new H264DecoderContextType(r); } H264DecoderContext::~H264DecoderContext() { } - -bool H264DecoderContext::isReady() -{ - os::AutoMutex lock(&mutex); - return initialized; -} - -void H264DecoderContext::reset() -{ - freeCodec(); - initCodec(); -} diff --git a/common/rfb/H264DecoderContext.h b/common/rfb/H264DecoderContext.h index 88c2396c..5ef46662 100644 --- a/common/rfb/H264DecoderContext.h +++ b/common/rfb/H264DecoderContext.h @@ -23,35 +23,30 @@ #include <stdint.h> -#include <os/Mutex.h> -#include <rfb/Rect.h> -#include <rfb/Decoder.h> +#include <core/Rect.h> namespace rfb { + + class ModifiablePixelBuffer; + class H264DecoderContext { public: - static H264DecoderContext *createContext(const Rect &r); + static H264DecoderContext* createContext(const core::Rect& r); virtual ~H264DecoderContext() = 0; virtual void decode(const uint8_t* /*h264_buffer*/, uint32_t /*len*/, ModifiablePixelBuffer* /*pb*/) {} - void reset(); - inline bool isEqualRect(const Rect &r) const { return r == rect; } - bool isReady(); + inline bool isEqualRect(const core::Rect &r) const { return r == rect; } protected: - os::Mutex mutex; - rfb::Rect rect; - bool initialized; + core::Rect rect; - H264DecoderContext(const Rect &r) : rect(r) { initialized = false; } - - virtual bool initCodec() { return false; } - virtual void freeCodec() {} + H264DecoderContext(const core::Rect &r) : rect(r) {} }; + } #endif diff --git a/common/rfb/H264LibavDecoderContext.cxx b/common/rfb/H264LibavDecoderContext.cxx index 2d8d03e7..ba1b1b6d 100644 --- a/common/rfb/H264LibavDecoderContext.cxx +++ b/common/rfb/H264LibavDecoderContext.cxx @@ -22,6 +22,9 @@ #include <config.h> #endif +#include <new> +#include <stdexcept> + extern "C" { #include <libavutil/imgutils.h> #include <libavcodec/version.h> @@ -33,41 +36,31 @@ extern "C" { #define FFMPEG_INIT_PACKET_DEPRECATED #endif -#include <rfb/LogWriter.h> #include <rfb/PixelBuffer.h> #include <rfb/H264LibavDecoderContext.h> using namespace rfb; -static LogWriter vlog("H264LibavDecoderContext"); - -bool H264LibavDecoderContext::initCodec() { - os::AutoMutex lock(&mutex); - +H264LibavDecoderContext::H264LibavDecoderContext(const core::Rect& r) + : H264DecoderContext(r) +{ sws = nullptr; h264WorkBuffer = nullptr; h264WorkBufferLength = 0; const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264); if (!codec) - { - vlog.error("Codec not found"); - return false; - } + throw std::runtime_error("Codec not found"); parser = av_parser_init(codec->id); if (!parser) - { - vlog.error("Could not create H264 parser"); - return false; - } + throw std::runtime_error("Could not create H264 parser"); avctx = avcodec_alloc_context3(codec); if (!avctx) { av_parser_close(parser); - vlog.error("Could not allocate video codec context"); - return false; + throw std::runtime_error("Could not allocate video codec context"); } frame = av_frame_alloc(); @@ -75,8 +68,7 @@ bool H264LibavDecoderContext::initCodec() { { av_parser_close(parser); avcodec_free_context(&avctx); - vlog.error("Could not allocate video frame"); - return false; + throw std::runtime_error("Could not allocate video frame"); } if (avcodec_open2(avctx, codec, nullptr) < 0) @@ -84,26 +76,18 @@ bool H264LibavDecoderContext::initCodec() { av_parser_close(parser); avcodec_free_context(&avctx); av_frame_free(&frame); - vlog.error("Could not open codec"); - return false; + throw std::runtime_error("Could not open video codec"); } - - initialized = true; - return true; } -void H264LibavDecoderContext::freeCodec() { - os::AutoMutex lock(&mutex); - - if (!initialized) - return; +H264LibavDecoderContext::~H264LibavDecoderContext() +{ av_parser_close(parser); avcodec_free_context(&avctx); av_frame_free(&rgbFrame); av_frame_free(&frame); sws_freeContext(sws); free(h264WorkBuffer); - initialized = false; } // We need to reallocate buffer because AVPacket uses non-const pointer. @@ -130,9 +114,6 @@ uint8_t* H264LibavDecoderContext::makeH264WorkBuffer(const uint8_t* buffer, uint void H264LibavDecoderContext::decode(const uint8_t* h264_in_buffer, uint32_t len, ModifiablePixelBuffer* pb) { - os::AutoMutex lock(&mutex); - if (!initialized) - return; uint8_t* h264_work_buffer = makeH264WorkBuffer(h264_in_buffer, len); #ifdef FFMPEG_INIT_PACKET_DEPRECATED @@ -147,19 +128,15 @@ void H264LibavDecoderContext::decode(const uint8_t* h264_in_buffer, while (len) { ret = av_parser_parse2(parser, avctx, &packet->data, &packet->size, h264_work_buffer, len, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); + // Silently ignore errors, hoping its a temporary encoding glitch if (ret < 0) - { - vlog.error("Error while parsing"); break; - } // We need to slap on tv to make it work here (don't ask me why) if (!packet->size && len == static_cast<uint32_t>(ret)) ret = av_parser_parse2(parser, avctx, &packet->data, &packet->size, h264_work_buffer, len, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); + // Silently ignore errors, hoping its a temporary encoding glitch if (ret < 0) - { - vlog.error("Error while parsing"); break; - } h264_work_buffer += ret; len -= ret; @@ -176,27 +153,21 @@ void H264LibavDecoderContext::decode(const uint8_t* h264_in_buffer, #ifndef FFMPEG_DECODE_VIDEO2_DEPRECATED int got_frame; ret = avcodec_decode_video2(avctx, frame, &got_frame, packet); + // Silently ignore errors, hoping its a temporary encoding glitch if (ret < 0 || !got_frame) - { - vlog.error("Error during decoding"); break; - } #else ret = avcodec_send_packet(avctx, packet); + // Silently ignore errors, hoping its a temporary encoding glitch if (ret < 0) - { - vlog.error("Error sending a packet to decoding"); break; - } ret = avcodec_receive_frame(avctx, frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; - else if (ret < 0) - { - vlog.error("Error during decoding"); + // Silently ignore errors, hoping its a temporary encoding glitch + if (ret < 0) break; - } #endif frames_received++; } diff --git a/common/rfb/H264LibavDecoderContext.h b/common/rfb/H264LibavDecoderContext.h index 96558bee..c23fdf79 100644 --- a/common/rfb/H264LibavDecoderContext.h +++ b/common/rfb/H264LibavDecoderContext.h @@ -31,16 +31,12 @@ extern "C" { namespace rfb { class H264LibavDecoderContext : public H264DecoderContext { public: - H264LibavDecoderContext(const Rect &r) : H264DecoderContext(r) {} - ~H264LibavDecoderContext() { freeCodec(); } + H264LibavDecoderContext(const core::Rect &r); + ~H264LibavDecoderContext(); void decode(const uint8_t* h264_buffer, uint32_t len, ModifiablePixelBuffer* pb) override; - protected: - bool initCodec() override; - void freeCodec() override; - private: uint8_t* makeH264WorkBuffer(const uint8_t* buffer, uint32_t len); diff --git a/common/rfb/H264WinDecoderContext.cxx b/common/rfb/H264WinDecoderContext.cxx index a9b13942..71086fad 100644 --- a/common/rfb/H264WinDecoderContext.cxx +++ b/common/rfb/H264WinDecoderContext.cxx @@ -22,48 +22,38 @@ #include <config.h> #endif +#include <stdexcept> + #include <mfapi.h> #include <mferror.h> #include <wmcodecdsp.h> #define SAFE_RELEASE(obj) if (obj) { obj->Release(); obj = nullptr; } -#include <os/Mutex.h> -#include <rfb/LogWriter.h> #include <rfb/PixelBuffer.h> #include <rfb/H264WinDecoderContext.h> using namespace rfb; -static LogWriter vlog("H264WinDecoderContext"); - // Older MinGW lacks this definition #ifndef HAVE_VIDEO_PROCESSOR_MFT static GUID CLSID_VideoProcessorMFT = { 0x88753b26, 0x5b24, 0x49bd, { 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82 } }; #endif -bool H264WinDecoderContext::initCodec() { - os::AutoMutex lock(&mutex); - +H264WinDecoderContext::H264WinDecoderContext(const core::Rect &r) + : H264DecoderContext(r) +{ if (FAILED(MFStartup(MF_VERSION, MFSTARTUP_LITE))) - { - vlog.error("Could not initialize MediaFoundation"); - return false; - } + throw std::runtime_error("Could not initialize MediaFoundation"); if (FAILED(CoCreateInstance(CLSID_CMSH264DecoderMFT, nullptr, CLSCTX_INPROC_SERVER, IID_IMFTransform, (LPVOID*)&decoder))) - { - vlog.error("MediaFoundation H264 codec not found"); - return false; - } + throw std::runtime_error("MediaFoundation H264 codec not found"); if (FAILED(CoCreateInstance(CLSID_VideoProcessorMFT, nullptr, CLSCTX_INPROC_SERVER, IID_IMFTransform, (LPVOID*)&converter))) { - vlog.error("Cannot create MediaFoundation Video Processor (available only on Windows 8+). Trying ColorConvert DMO."); if (FAILED(CoCreateInstance(CLSID_CColorConvertDMO, nullptr, CLSCTX_INPROC_SERVER, IID_IMFTransform, (LPVOID*)&converter))) { decoder->Release(); - vlog.error("ColorConvert DMO not found"); - return false; + throw std::runtime_error("MediaFoundation H264 codec not found"); } } @@ -72,10 +62,7 @@ bool H264WinDecoderContext::initCodec() { if (SUCCEEDED(decoder->GetAttributes(&attributes))) { GUID MF_LOW_LATENCY = { 0x9c27891a, 0xed7a, 0x40e1, { 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee } }; - if (SUCCEEDED(attributes->SetUINT32(MF_LOW_LATENCY, TRUE))) - { - vlog.info("Enabled low latency mode"); - } + attributes->SetUINT32(MF_LOW_LATENCY, TRUE); attributes->Release(); } @@ -85,8 +72,7 @@ bool H264WinDecoderContext::initCodec() { { decoder->Release(); converter->Release(); - vlog.error("Could not create MF MediaType"); - return false; + throw std::runtime_error("Could not create MF MediaType"); } input_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); input_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); @@ -113,8 +99,7 @@ bool H264WinDecoderContext::initCodec() { decoder->Release(); converter->Release(); input_type->Release(); - vlog.error("Could not start H264 decoder"); - return false; + throw std::runtime_error("Could not start H264 decoder"); } MFT_OUTPUT_STREAM_INFO info; @@ -134,22 +119,14 @@ bool H264WinDecoderContext::initCodec() { SAFE_RELEASE(converted_sample); SAFE_RELEASE(input_buffer); SAFE_RELEASE(decoded_buffer); - vlog.error("Could not allocate media samples/buffers"); - return false; + throw std::runtime_error("Could not allocate media samples/buffers"); } input_sample->AddBuffer(input_buffer); decoded_sample->AddBuffer(decoded_buffer); - - initialized = true; - return true; } -void H264WinDecoderContext::freeCodec() { - os::AutoMutex lock(&mutex); - - if (!initialized) - return; +H264WinDecoderContext::~H264WinDecoderContext() { SAFE_RELEASE(decoder) SAFE_RELEASE(converter) SAFE_RELEASE(input_sample) @@ -159,24 +136,16 @@ void H264WinDecoderContext::freeCodec() { SAFE_RELEASE(decoded_buffer) SAFE_RELEASE(converted_buffer) MFShutdown(); - initialized = false; } void H264WinDecoderContext::decode(const uint8_t* h264_buffer, uint32_t len, ModifiablePixelBuffer* pb) { - os::AutoMutex lock(&mutex); - if (!initialized) - return; - if (FAILED(input_buffer->SetCurrentLength(len))) { input_buffer->Release(); if (FAILED(MFCreateMemoryBuffer(len, &input_buffer))) - { - vlog.error("Could not allocate media buffer"); - return; - } + throw std::runtime_error("Could not allocate media buffer"); input_buffer->SetCurrentLength(len); input_sample->RemoveAllBuffers(); input_sample->AddBuffer(input_buffer); @@ -187,14 +156,12 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer, memcpy(locked, h264_buffer, len); input_buffer->Unlock(); - vlog.debug("Received %u bytes, decoding", len); - // extract actual size, including possible cropping ParseSPS(h264_buffer, len); if (FAILED(decoder->ProcessInput(0, input_sample, 0))) { - vlog.error("Error sending a packet to decoding"); + // Silently ignore errors, hoping its a temporary encoding glitch return; } @@ -219,7 +186,6 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer, if (SUCCEEDED(hr)) { - vlog.debug("Frame decoded"); // successfully decoded next frame // but do not exit loop, try again if there is next frame decoded = true; @@ -259,7 +225,7 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer, UINT32 width, height; if FAILED(MFGetAttributeSize(output_type, MF_MT_FRAME_SIZE, &width, &height)) { - vlog.error("Error getting output type size"); + // Silently ignore errors, hoping its a temporary encoding glitch output_type->Release(); break; } @@ -279,13 +245,11 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer, crop_height = height; } - vlog.debug("Setting up decoded output with %ux%u size", crop_width, crop_height); - // input type to converter, BGRX pixel format IMFMediaType* converted_type; if (FAILED(MFCreateMediaType(&converted_type))) { - vlog.error("Error creating media type"); + // Silently ignore errors, hoping its a temporary encoding glitch } else { @@ -310,7 +274,7 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer, if (FAILED(MFCreateMemoryBuffer(info.cbSize, &converted_buffer))) { - vlog.error("Error creating media buffer"); + // Silently ignore errors, hoping its a temporary encoding glitch } else { @@ -327,7 +291,7 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer, { if (FAILED(converter->ProcessInput(0, decoded_sample, 0))) { - vlog.error("Error sending a packet to converter"); + // Silently ignore errors, hoping its a temporary encoding glitch return; } @@ -343,12 +307,10 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer, if (FAILED(hr)) { - vlog.error("Error converting to RGB"); + // Silently ignore errors, hoping its a temporary encoding glitch } else { - vlog.debug("Frame converted to RGB"); - BYTE* out; DWORD buflen; converted_buffer->Lock(&out, nullptr, &buflen); @@ -528,8 +490,6 @@ void H264WinDecoderContext::ParseSPS(const uint8_t* buffer, int length) offset_x = frame_crop_left_offset; offset_y = frame_crop_bottom_offset; - vlog.debug("SPS parsing - full=%dx%d, cropped=%dx%d, offset=%d,%d", full_width, full_height, crop_width, crop_height, offset_x, offset_y); - #undef SKIP_BITS #undef SKIP_UE #undef GET_BITS diff --git a/common/rfb/H264WinDecoderContext.h b/common/rfb/H264WinDecoderContext.h index 92041781..b1dbf0e1 100644 --- a/common/rfb/H264WinDecoderContext.h +++ b/common/rfb/H264WinDecoderContext.h @@ -30,16 +30,12 @@ namespace rfb { class H264WinDecoderContext : public H264DecoderContext { public: - H264WinDecoderContext(const Rect &r) : H264DecoderContext(r) {}; - ~H264WinDecoderContext() { freeCodec(); } + H264WinDecoderContext(const core::Rect &r); + ~H264WinDecoderContext(); void decode(const uint8_t* h264_buffer, uint32_t len, ModifiablePixelBuffer* pb) override; - protected: - bool initCodec() override; - void freeCodec() override; - private: LONG stride; uint32_t full_width = 0; diff --git a/common/rfb/HextileDecoder.cxx b/common/rfb/HextileDecoder.cxx index 35ec7928..c6eb428b 100644 --- a/common/rfb/HextileDecoder.cxx +++ b/common/rfb/HextileDecoder.cxx @@ -21,6 +21,8 @@ #include <config.h> #endif +#include <algorithm> + #include <rdr/InStream.h> #include <rdr/MemInStream.h> #include <rdr/OutStream.h> @@ -41,10 +43,10 @@ HextileDecoder::~HextileDecoder() { } -bool HextileDecoder::readRect(const Rect& r, rdr::InStream* is, +bool HextileDecoder::readRect(const core::Rect& r, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os) { - Rect t; + core::Rect t; size_t bytesPerPixel; is->setRestorePoint(); @@ -53,12 +55,12 @@ bool HextileDecoder::readRect(const Rect& r, rdr::InStream* is, for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) { - t.br.y = __rfbmin(r.br.y, t.tl.y + 16); + t.br.y = std::min(r.br.y, t.tl.y + 16); for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) { uint8_t tileType; - t.br.x = __rfbmin(r.br.x, t.tl.x + 16); + t.br.x = std::min(r.br.x, t.tl.x + 16); if (!is->hasDataOrRestore(1)) return false; @@ -113,7 +115,7 @@ bool HextileDecoder::readRect(const Rect& r, rdr::InStream* is, return true; } -void HextileDecoder::decodeRect(const Rect& r, const uint8_t* buffer, +void HextileDecoder::decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) { @@ -138,22 +140,22 @@ inline T HextileDecoder::readPixel(rdr::InStream* is) } template<class T> -void HextileDecoder::hextileDecode(const Rect& r, rdr::InStream* is, +void HextileDecoder::hextileDecode(const core::Rect& r, rdr::InStream* is, const PixelFormat& pf, ModifiablePixelBuffer* pb) { - Rect t; + core::Rect t; T bg = 0; T fg = 0; T buf[16 * 16]; for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) { - t.br.y = __rfbmin(r.br.y, t.tl.y + 16); + t.br.y = std::min(r.br.y, t.tl.y + 16); for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) { - t.br.x = __rfbmin(r.br.x, t.tl.x + 16); + t.br.x = std::min(r.br.x, t.tl.x + 16); int tileType = is->readU8(); diff --git a/common/rfb/HextileDecoder.h b/common/rfb/HextileDecoder.h index 38e8b776..6ff94a1f 100644 --- a/common/rfb/HextileDecoder.h +++ b/common/rfb/HextileDecoder.h @@ -29,17 +29,17 @@ namespace rfb { public: HextileDecoder(); virtual ~HextileDecoder(); - bool readRect(const Rect& r, rdr::InStream* is, + bool readRect(const core::Rect& r, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os) override; - void decodeRect(const Rect& r, const uint8_t* buffer, + void decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) override; private: template<class T> inline T readPixel(rdr::InStream* is); template<class T> - void hextileDecode(const Rect& r, rdr::InStream* is, + void hextileDecode(const core::Rect& r, rdr::InStream* is, const PixelFormat& pf, ModifiablePixelBuffer* pb); }; diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx index 0666d02d..5ee07a2d 100644 --- a/common/rfb/HextileEncoder.cxx +++ b/common/rfb/HextileEncoder.cxx @@ -22,21 +22,28 @@ #include <config.h> #endif +#include <algorithm> + +#include <core/Configuration.h> + +#include <rdr/OutStream.h> + #include <rfb/encodings.h> #include <rfb/SConnection.h> #include <rfb/HextileEncoder.h> #include <rfb/Palette.h> #include <rfb/PixelBuffer.h> -#include <rfb/Configuration.h> #include <rfb/hextileConstants.h> using namespace rfb; -BoolParameter improvedHextile("ImprovedHextile", - "Use improved compression algorithm for Hextile " - "encoding which achieves better compression " - "ratios by the cost of using more CPU time", - true); +core::BoolParameter improvedHextile("ImprovedHextile", + "Use improved compression " + "algorithm for Hextile encoding " + "which achieves better compression " + "ratios by the cost of using more " + "CPU time", + true); HextileEncoder::HextileEncoder(SConnection* conn_) : Encoder(conn_, encodingHextile, EncoderPlain) @@ -115,7 +122,7 @@ template<class T> void HextileEncoder::hextileEncode(rdr::OutStream* os, const PixelBuffer* pb) { - Rect t; + core::Rect t; T buf[256]; T oldBg = 0, oldFg = 0; bool oldBgValid = false; @@ -124,11 +131,11 @@ void HextileEncoder::hextileEncode(rdr::OutStream* os, for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) { - t.br.y = __rfbmin(pb->height(), t.tl.y + 16); + t.br.y = std::min(pb->height(), t.tl.y + 16); for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) { - t.br.x = __rfbmin(pb->width(), t.tl.x + 16); + t.br.x = std::min(pb->width(), t.tl.x + 16); pb->getImage(buf, t); @@ -532,7 +539,7 @@ template<class T> void HextileEncoder::hextileEncodeBetter(rdr::OutStream* os, const PixelBuffer* pb) { - Rect t; + core::Rect t; T buf[256]; T oldBg = 0, oldFg = 0; bool oldBgValid = false; @@ -543,11 +550,11 @@ void HextileEncoder::hextileEncodeBetter(rdr::OutStream* os, for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) { - t.br.y = __rfbmin(pb->height(), t.tl.y + 16); + t.br.y = std::min(pb->height(), t.tl.y + 16); for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) { - t.br.x = __rfbmin(pb->width(), t.tl.x + 16); + t.br.x = std::min(pb->width(), t.tl.x + 16); pb->getImage(buf, t); diff --git a/common/rfb/Hostname.h b/common/rfb/Hostname.h deleted file mode 100644 index f43e5067..00000000 --- a/common/rfb/Hostname.h +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * 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. - */ - -#ifndef __RFB_HOSTNAME_H__ -#define __RFB_HOSTNAME_H__ - -#include <assert.h> -#include <ctype.h> -#include <stdlib.h> -#include <string.h> - -#include <stdexcept> - -#include <rfb/util.h> - -namespace rfb { - - static bool isAllSpace(const char *string) { - if (string == nullptr) - return false; - while(*string != '\0') { - if (! isspace(*string)) - return false; - string++; - } - return true; - } - - static inline void getHostAndPort(const char* hi, std::string* host, - int* port, int basePort=5900) - { - const char* hostStart; - const char* hostEnd; - const char* portStart; - - if (hi == nullptr) - throw std::invalid_argument("NULL host specified"); - - // Trim leading whitespace - while(isspace(*hi)) - hi++; - - assert(host); - assert(port); - - if (hi[0] == '[') { - hostStart = &hi[1]; - hostEnd = strchr(hostStart, ']'); - if (hostEnd == nullptr) - throw std::invalid_argument("Unmatched [ in host"); - - portStart = hostEnd + 1; - if (isAllSpace(portStart)) - portStart = nullptr; - } else { - hostStart = &hi[0]; - hostEnd = strrchr(hostStart, ':'); - - if (hostEnd == nullptr) { - hostEnd = hostStart + strlen(hostStart); - portStart = nullptr; - } else { - if ((hostEnd > hostStart) && (hostEnd[-1] == ':')) - hostEnd--; - portStart = strchr(hostStart, ':'); - if (portStart != hostEnd) { - // We found more : in the host. This is probably an IPv6 address - hostEnd = hostStart + strlen(hostStart); - portStart = nullptr; - } - } - } - - // Back up past trailing space - while(isspace(*(hostEnd - 1)) && hostEnd > hostStart) - hostEnd--; - - if (hostStart == hostEnd) - *host = "localhost"; - else - *host = std::string(hostStart, hostEnd - hostStart); - - if (portStart == nullptr) - *port = basePort; - else { - char* end; - - if (portStart[0] != ':') - throw std::invalid_argument("Invalid port specified"); - - if (portStart[1] != ':') - *port = strtol(portStart + 1, &end, 10); - else - *port = strtol(portStart + 2, &end, 10); - if (*end != '\0' && ! isAllSpace(end)) - throw std::invalid_argument("Invalid port specified"); - - if ((portStart[1] != ':') && (*port < 100)) - *port += basePort; - } - } - -}; - -#endif // __RFB_HOSTNAME_H__ diff --git a/common/rfb/JpegCompressor.cxx b/common/rfb/JpegCompressor.cxx index 67a86cd9..d8216c99 100644 --- a/common/rfb/JpegCompressor.cxx +++ b/common/rfb/JpegCompressor.cxx @@ -24,8 +24,9 @@ #include <stdexcept> +#include <core/Rect.h> + #include <rfb/JpegCompressor.h> -#include <rfb/Rect.h> #include <rfb/PixelFormat.h> #include <rfb/ClientParams.h> @@ -157,7 +158,8 @@ JpegCompressor::~JpegCompressor(void) } void JpegCompressor::compress(const uint8_t *buf, volatile int stride, - const Rect& r, const PixelFormat& pf, + const core::Rect& r, + const PixelFormat& pf, int quality, int subsamp) { int w = r.width(); diff --git a/common/rfb/JpegCompressor.h b/common/rfb/JpegCompressor.h index 26194204..2460f62b 100644 --- a/common/rfb/JpegCompressor.h +++ b/common/rfb/JpegCompressor.h @@ -25,9 +25,9 @@ #ifndef __RFB_JPEGCOMPRESSOR_H__ #define __RFB_JPEGCOMPRESSOR_H__ +#include <core/Rect.h> + #include <rdr/MemOutStream.h> -#include <rfb/PixelFormat.h> -#include <rfb/Rect.h> struct jpeg_compress_struct; @@ -36,6 +36,9 @@ struct JPEG_DEST_MGR; namespace rfb { + class PixelFormat; + struct Rect; + class JpegCompressor : public rdr::MemOutStream { public: @@ -43,7 +46,8 @@ namespace rfb { JpegCompressor(int bufferLen = 128*1024); virtual ~JpegCompressor(); - void compress(const uint8_t *, int, const Rect&, const PixelFormat&, int, int); + void compress(const uint8_t*, int, const core::Rect&, + const PixelFormat&, int, int); void writeBytes(const uint8_t*, int); diff --git a/common/rfb/JpegDecompressor.cxx b/common/rfb/JpegDecompressor.cxx index 10c9e49c..ef548be0 100644 --- a/common/rfb/JpegDecompressor.cxx +++ b/common/rfb/JpegDecompressor.cxx @@ -23,9 +23,10 @@ #include <config.h> #endif +#include <core/Rect.h> + #include <rfb/JpegDecompressor.h> #include <rfb/Exception.h> -#include <rfb/Rect.h> #include <rfb/PixelFormat.h> #include <stdio.h> @@ -153,7 +154,8 @@ JpegDecompressor::~JpegDecompressor(void) void JpegDecompressor::decompress(const uint8_t *jpegBuf, int jpegBufLen, uint8_t *buf, volatile int stride, - const Rect& r, const PixelFormat& pf) + const core::Rect& r, + const PixelFormat& pf) { int w = r.width(); int h = r.height(); diff --git a/common/rfb/JpegDecompressor.h b/common/rfb/JpegDecompressor.h index 5d4f0c21..8e651b1c 100644 --- a/common/rfb/JpegDecompressor.h +++ b/common/rfb/JpegDecompressor.h @@ -26,16 +26,19 @@ #ifndef __RFB_JPEGDECOMPRESSOR_H__ #define __RFB_JPEGDECOMPRESSOR_H__ -#include <rfb/PixelFormat.h> -#include <rfb/Rect.h> +#include <stdint.h> struct jpeg_decompress_struct; struct JPEG_ERROR_MGR; struct JPEG_SRC_MGR; +namespace core { struct Rect; } + namespace rfb { + class PixelFormat; + class JpegDecompressor { public: @@ -43,8 +46,8 @@ namespace rfb { JpegDecompressor(void); virtual ~JpegDecompressor(); - void decompress(const uint8_t *, int, uint8_t *, int, const Rect&, - const PixelFormat&); + void decompress(const uint8_t*, int, uint8_t*, int, + const core::Rect&, const PixelFormat&); private: diff --git a/common/rfb/KeyRemapper.cxx b/common/rfb/KeyRemapper.cxx index 1c478178..24740321 100644 --- a/common/rfb/KeyRemapper.cxx +++ b/common/rfb/KeyRemapper.cxx @@ -23,59 +23,31 @@ #include <stdio.h> #include <string.h> -#include <os/Mutex.h> +#include <core/Configuration.h> +#include <core/LogWriter.h> #include <rfb/KeyRemapper.h> -#include <rfb/Configuration.h> -#include <rfb/LogWriter.h> using namespace rfb; -static LogWriter vlog("KeyRemapper"); +static core::LogWriter vlog("KeyRemapper"); KeyRemapper KeyRemapper::defInstance; -KeyRemapper::KeyRemapper(const char* m) +KeyRemapper::KeyRemapper() { - mutex = new os::Mutex; - - setMapping(m); } KeyRemapper::~KeyRemapper() { - delete mutex; } -void KeyRemapper::setMapping(const char* m) { - os::AutoMutex a(mutex); - - mapping.clear(); - while (m[0]) { - int from, to; - char bidi; - const char* nextComma = strchr(m, ','); - if (!nextComma) - nextComma = m + strlen(m); - if (sscanf(m, "0x%x%c>0x%x", &from, - &bidi, &to) == 3) { - if (bidi != '-' && bidi != '<') - vlog.error("Warning: Unknown operation %c>, assuming ->", bidi); - mapping[from] = to; - if (bidi == '<') - mapping[to] = from; - } else { - vlog.error("Warning: Bad mapping %.*s", (int)(nextComma-m), m); - } - m = nextComma; - if (nextComma[0]) - m++; - } +void KeyRemapper::setMapping(const std::map<uint32_t,uint32_t>& m) +{ + mapping = m; } uint32_t KeyRemapper::remapKey(uint32_t key) const { - os::AutoMutex a(mutex); - std::map<uint32_t,uint32_t>::const_iterator i = mapping.find(key); if (i != mapping.end()) return i->second; @@ -83,15 +55,41 @@ uint32_t KeyRemapper::remapKey(uint32_t key) const { } -class KeyMapParameter : public StringParameter { +class KeyMapParameter : public core::StringListParameter { public: KeyMapParameter() - : StringParameter("RemapKeys", "Comma-separated list of incoming keysyms to remap. Mappings are expressed as two hex values, prefixed by 0x, and separated by ->", "") { - KeyRemapper::defInstance.setMapping(""); + : core::StringListParameter("RemapKeys", + "Comma-separated list of incoming " + "keysyms to remap. Mappings are " + "expressed as two hex values, prefixed " + "by 0x, and separated by ->", + {}) { + KeyRemapper::defInstance.setMapping({}); } bool setParam(const char* v) override { - KeyRemapper::defInstance.setMapping(v); - return StringParameter::setParam(v); + std::map<uint32_t,uint32_t> mapping; + + if (!core::StringListParameter::setParam(v)) + return false; + + for (const char* m : *this) { + int from, to; + char bidi; + if (sscanf(m, "0x%x%c>0x%x", &from, + &bidi, &to) == 3) { + if (bidi != '-' && bidi != '<') + vlog.error("Warning: Unknown operation %c>, assuming ->", bidi); + mapping[from] = to; + if (bidi == '<') + mapping[to] = from; + } else { + vlog.error("Warning: Bad mapping %s", m); + } + } + + KeyRemapper::defInstance.setMapping(mapping); + + return true; } } defaultParam; diff --git a/common/rfb/KeyRemapper.h b/common/rfb/KeyRemapper.h index 89853721..71ef0a87 100644 --- a/common/rfb/KeyRemapper.h +++ b/common/rfb/KeyRemapper.h @@ -23,20 +23,17 @@ #include <stdint.h> -namespace os { class Mutex; } - namespace rfb { class KeyRemapper { public: - KeyRemapper(const char* m=""); + KeyRemapper(); ~KeyRemapper(); - void setMapping(const char* m); + void setMapping(const std::map<uint32_t,uint32_t>& m); uint32_t remapKey(uint32_t key) const; static KeyRemapper defInstance; private: std::map<uint32_t,uint32_t> mapping; - os::Mutex* mutex; }; }; diff --git a/common/rfb/LogWriter.cxx b/common/rfb/LogWriter.cxx deleted file mode 100644 index 8e39d544..00000000 --- a/common/rfb/LogWriter.cxx +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * 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. - */ - -// -=- LogWriter.cxx - client-side logging interface - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> - -#include <rfb/LogWriter.h> -#include <rfb/Configuration.h> -#include <rfb/util.h> -#include <stdlib.h> - -rfb::LogParameter rfb::logParams; - -using namespace rfb; - - -LogWriter::LogWriter(const char* name) - : m_name(name), m_level(0), m_log(nullptr), m_next(log_writers) { - log_writers = this; -} - -LogWriter::~LogWriter() { - // *** Should remove this logger here! -} - -void LogWriter::setLog(Logger *logger) { - m_log = logger; -} - -void LogWriter::setLevel(int level) { - m_level = level; -} - -void -LogWriter::listLogWriters(int /*width*/) { - // *** make this respect width... - LogWriter* current = log_writers; - fprintf(stderr, " "); - while (current) { - fprintf(stderr, "%s", current->m_name); - current = current->m_next; - if (current) fprintf(stderr, ", "); - } - fprintf(stderr, "\n"); -} - -LogWriter* LogWriter::log_writers; - -LogWriter* -LogWriter::getLogWriter(const char* name) { - LogWriter* current = log_writers; - while (current) { - if (strcasecmp(name, current->m_name) == 0) return current; - current = current->m_next; - } - return nullptr; -} - -bool LogWriter::setLogParams(const char* params) { - std::vector<std::string> parts; - parts = split(params, ':'); - if (parts.size() != 3) { - fprintf(stderr, "Failed to parse log params:%s\n",params); - return false; - } - int level = atoi(parts[2].c_str()); - Logger* logger = nullptr; - if (!parts[1].empty()) { - logger = Logger::getLogger(parts[1].c_str()); - if (!logger) - fprintf(stderr, "No logger found! %s\n", parts[1].c_str()); - } - if (parts[0] == "*") { - LogWriter* current = log_writers; - while (current) { - current->setLog(logger); - current->setLevel(level); - current = current->m_next; - } - return true; - } else { - LogWriter* logwriter = getLogWriter(parts[0].c_str()); - if (!logwriter) { - fprintf(stderr, "No logwriter found! %s\n", parts[0].c_str()); - } else { - logwriter->setLog(logger); - logwriter->setLevel(level); - return true; - } - } - return false; -} - - -LogParameter::LogParameter() - : StringParameter("Log", - "Specifies which log output should be directed to " - "which target logger, and the level of output to log. " - "Format is <log>:<target>:<level>[, ...].", - "") { -} - -bool LogParameter::setParam(const char* v) { - if (immutable) return true; - LogWriter::setLogParams("*::0"); - StringParameter::setParam(v); - std::vector<std::string> parts; - parts = split(v, ','); - for (size_t i = 0; i < parts.size(); i++) { - if (parts[i].empty()) - continue; - if (!LogWriter::setLogParams(parts[i].c_str())) - return false; - } - return true; -} diff --git a/common/rfb/LogWriter.h b/common/rfb/LogWriter.h deleted file mode 100644 index d1fd4990..00000000 --- a/common/rfb/LogWriter.h +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * 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. - */ - -// -=- LogWriter.h - The Log writer class. - -#ifndef __RFB_LOG_WRITER_H__ -#define __RFB_LOG_WRITER_H__ - -#include <stdarg.h> -#include <rfb/Logger.h> -#include <rfb/Configuration.h> - -// Each log writer instance has a unique textual name, -// and is attached to a particular Log instance and -// is assigned a particular log level. - -#define DEF_LOGFUNCTION(name, level) \ - inline void v##name(const char* fmt, va_list ap) \ - __attribute__((__format__ (__printf__, 2, 0))) \ - { \ - if (m_log && (level <= m_level)) \ - m_log->write(level, m_name, fmt, ap); \ - } \ - inline void name(const char* fmt, ...) \ - __attribute__((__format__ (__printf__, 2, 3))) \ - { \ - if (m_log && (level <= m_level)) { \ - va_list ap; va_start(ap, fmt); \ - m_log->write(level, m_name, fmt, ap);\ - va_end(ap); \ - } \ - } - -namespace rfb { - - class LogWriter; - - class LogWriter { - public: - LogWriter(const char* name); - ~LogWriter(); - - const char *getName() {return m_name;} - - void setLog(Logger *logger); - void setLevel(int level); - int getLevel(void) { return m_level; } - - inline void write(int level, const char* format, ...) - __attribute__((__format__ (__printf__, 3, 4))) - { - if (m_log && (level <= m_level)) { - va_list ap; - va_start(ap, format); - m_log->write(level, m_name, format, ap); - va_end(ap); - } - } - - static const int LEVEL_ERROR = 0; - static const int LEVEL_STATUS = 10; - static const int LEVEL_INFO = 30; - static const int LEVEL_DEBUG = 100; - - DEF_LOGFUNCTION(error, LEVEL_ERROR) - DEF_LOGFUNCTION(status, LEVEL_STATUS) - DEF_LOGFUNCTION(info, LEVEL_INFO) - DEF_LOGFUNCTION(debug, LEVEL_DEBUG) - - // -=- DIAGNOSTIC & HELPER ROUTINES - - static void listLogWriters(int width=79); - - // -=- CLASS FIELDS & FUNCTIONS - - static LogWriter* log_writers; - - static LogWriter* getLogWriter(const char* name); - - static bool setLogParams(const char* params); - - private: - const char* m_name; - int m_level; - Logger* m_log; - LogWriter* m_next; - }; - - class LogParameter : public StringParameter { - public: - LogParameter(); - bool setParam(const char* v) override; - }; - extern LogParameter logParams; - -}; - -#endif // __RFB_LOG_WRITER_H__ diff --git a/common/rfb/Logger.cxx b/common/rfb/Logger.cxx deleted file mode 100644 index 25f7ccb7..00000000 --- a/common/rfb/Logger.cxx +++ /dev/null @@ -1,95 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * 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. - */ - -// -=- Logger.cxx - support for the Logger and LogWriter classes - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#include <rfb/Logger.h> -#include <rfb/LogWriter.h> - -using namespace rfb; - -Logger* Logger::loggers = nullptr; - -Logger::Logger(const char* name) - : registered(false), m_name(name), m_next(nullptr) -{ -} - -Logger::~Logger() { - // *** Should remove this logger here! -} - -void Logger::write(int level, const char *logname, const char* format, - va_list ap) -{ - // - Format the supplied data, and pass it to the - // actual log_message function - // The log level is included as a hint for loggers capable of representing - // different log levels in some way. - char buf1[4096]; - vsnprintf(buf1, sizeof(buf1)-1, format, ap); - buf1[sizeof(buf1)-1] = 0; - 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 -Logger::registerLogger() { - if (!registered) { - registered = true; - m_next = loggers; - loggers=this; - } -} - -Logger* -Logger::getLogger(const char* name) { - Logger* current = loggers; - while (current) { - if (strcasecmp(name, current->m_name) == 0) return current; - current = current->m_next; - } - return nullptr; -} - -void -Logger::listLoggers() { - Logger* current = loggers; - while (current) { - printf(" %s\n", current->m_name); - current = current->m_next; - } -} - - diff --git a/common/rfb/Logger.h b/common/rfb/Logger.h deleted file mode 100644 index 76f03535..00000000 --- a/common/rfb/Logger.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * 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. - */ - -// -=- Logger.h - The Logger class. - -#ifndef __RFB_LOGGER_H__ -#define __RFB_LOGGER_H__ - -#include <stdarg.h> -#include <stdio.h> - -// Each log writer instance has a unique textual name, -// and is attached to a particular Logger instance and -// is assigned a particular log level. - -namespace rfb { - - class Logger { - public: - - // -=- Create / Destroy a logger - - Logger(const char* name); - virtual ~Logger(); - - // -=- Get the name of a logger - - const char *getName() {return m_name;} - - // -=- Write data to a log - - virtual void write(int level, const char *logname, const char *text) = 0; - void write(int level, const char *logname, const char* format, va_list ap) - __attribute__((__format__ (__printf__, 4, 0))); - - // -=- Register a logger - - void registerLogger(); - - // -=- CLASS FIELDS & FUNCTIONS - - static Logger* loggers; - - static Logger* getLogger(const char* name); - - static void listLoggers(); - - private: - bool registered; - const char *m_name; - Logger *m_next; - }; - -}; - -#endif // __RFB_LOGGER_H__ diff --git a/common/rfb/Logger_file.cxx b/common/rfb/Logger_file.cxx deleted file mode 100644 index eabe420a..00000000 --- a/common/rfb/Logger_file.cxx +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * 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. - */ - -// -=- Logger_file.cxx - Logger instance for a file - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <limits.h> -#include <stdlib.h> -#include <string.h> - -#include <os/Mutex.h> - -#include <rfb/Logger_file.h> - -using namespace rfb; - -Logger_File::Logger_File(const char* loggerName) - : Logger(loggerName), indent(13), width(79), m_file(nullptr), - m_lastLogTime(0) -{ - m_filename[0] = '\0'; - mutex = new os::Mutex(); -} - -Logger_File::~Logger_File() -{ - closeFile(); - delete mutex; -} - -void Logger_File::write(int /*level*/, const char *logname, const char *message) -{ - os::AutoMutex a(mutex); - - if (!m_file) { - if (m_filename[0] == '\0') - return; - char bakFilename[PATH_MAX]; - if (snprintf(bakFilename, sizeof(bakFilename), - "%s.bak", m_filename) >= (int)sizeof(bakFilename)) { - remove(m_filename); - } else { - remove(bakFilename); - rename(m_filename, bakFilename); - } - m_file = fopen(m_filename, "w+"); - if (!m_file) return; - } - - time_t current = time(nullptr); - if (current != m_lastLogTime) { - m_lastLogTime = current; - fprintf(m_file, "\n%s", ctime(&m_lastLogTime)); - } - - fprintf(m_file," %s:", logname); - int column = strlen(logname) + 2; - if (column < indent) { - fprintf(m_file,"%*s",indent-column,""); - column = indent; - } - while (true) { - const char* s = strchr(message, ' '); - int wordLen; - if (s) wordLen = s-message; - else wordLen = strlen(message); - - if (column + wordLen + 1 > width) { - fprintf(m_file,"\n%*s",indent,""); - column = indent; - } - fprintf(m_file," %.*s",wordLen,message); - column += wordLen + 1; - message += wordLen + 1; - if (!s) break; - } - fprintf(m_file,"\n"); - fflush(m_file); -} - -void Logger_File::setFilename(const char* filename) -{ - closeFile(); - m_filename[0] = '\0'; - if (strlen(filename) >= sizeof(m_filename)) - return; - strcpy(m_filename, filename); -} - -void Logger_File::setFile(FILE* file) -{ - closeFile(); - m_file = file; -} - -void Logger_File::closeFile() -{ - if (m_file) { - fclose(m_file); - m_file = nullptr; - } -} - -static Logger_File logger("file"); - -bool rfb::initFileLogger(const char* filename) { - logger.setFilename(filename); - logger.registerLogger(); - return true; -} diff --git a/common/rfb/Logger_file.h b/common/rfb/Logger_file.h deleted file mode 100644 index 6f2a4ef6..00000000 --- a/common/rfb/Logger_file.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * 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. - */ - -// -=- Logger_file - log to a file - -#ifndef __RFB_LOGGER_FILE_H__ -#define __RFB_LOGGER_FILE_H__ - -#include <time.h> -#include <limits.h> - -#include <rfb/Logger.h> - -namespace os { class Mutex; } - -namespace rfb { - - class Logger_File : public Logger { - public: - Logger_File(const char* loggerName); - ~Logger_File(); - - void write(int level, const char *logname, const char *message) override; - void setFilename(const char* filename); - void setFile(FILE* file); - - int indent; - int width; - - protected: - void closeFile(); - char m_filename[PATH_MAX]; - FILE* m_file; - time_t m_lastLogTime; - os::Mutex* mutex; - }; - - bool initFileLogger(const char* filename); -}; - -#endif diff --git a/common/rfb/Logger_stdio.cxx b/common/rfb/Logger_stdio.cxx deleted file mode 100644 index 5e5c6dea..00000000 --- a/common/rfb/Logger_stdio.cxx +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * 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. - */ - -// -=- Logger_stdio.cxx - Logger instances for stderr and stdout - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <rfb/Logger_stdio.h> - -using namespace rfb; - -static Logger_StdIO logStdErr("stderr", stderr); -static Logger_StdIO logStdOut("stdout", stdout); - -bool rfb::initStdIOLoggers() { - logStdErr.registerLogger(); - logStdOut.registerLogger(); - return true; -} diff --git a/common/rfb/Logger_stdio.h b/common/rfb/Logger_stdio.h deleted file mode 100644 index a1d17a0f..00000000 --- a/common/rfb/Logger_stdio.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * 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. - */ - -// -=- Logger_stdio - standard output logger instances - -#ifndef __RFB_LOGGER_STDIO_H__ -#define __RFB_LOGGER_STDIO_H__ - -#include <rfb/Logger_file.h> - -namespace rfb { - - class Logger_StdIO : public Logger_File { - public: - Logger_StdIO(const char *name, FILE* file) : Logger_File(name) { - setFile(file); - } - }; - - bool initStdIOLoggers(); - -}; - -#endif diff --git a/common/rfb/Logger_syslog.cxx b/common/rfb/Logger_syslog.cxx deleted file mode 100644 index de9e425e..00000000 --- a/common/rfb/Logger_syslog.cxx +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright (C) 2015 TigerVNC - * - * 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. - */ - -// -=- Logger_syslog.cxx - Logger instance for a syslog - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <string.h> -#include <syslog.h> - -#include <rfb/Logger_syslog.h> -#include <rfb/LogWriter.h> - -using namespace rfb; - - -Logger_Syslog::Logger_Syslog(const char* loggerName) - : Logger(loggerName) -{ - openlog(nullptr, LOG_CONS | LOG_PID, LOG_USER); -} - -Logger_Syslog::~Logger_Syslog() -{ - closelog(); -} - -void Logger_Syslog::write(int level, const char *logname, const char *message) -{ - // Convert our priority level into syslog level - int priority; - if (level >= LogWriter::LEVEL_DEBUG) { - priority = LOG_DEBUG; - } else if (level >= LogWriter::LEVEL_INFO) { - priority = LOG_INFO; - } else if (level >= LogWriter::LEVEL_STATUS) { - priority = LOG_NOTICE; - } else { - priority = LOG_ERR; - } - - syslog(priority, "%s: %s", logname, message); -} - -static Logger_Syslog logger("syslog"); - -void rfb::initSyslogLogger() { - logger.registerLogger(); -} diff --git a/common/rfb/Logger_syslog.h b/common/rfb/Logger_syslog.h deleted file mode 100644 index 20c46a5f..00000000 --- a/common/rfb/Logger_syslog.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2015 TigerVNC - * - * 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. - */ - -// -=- Logger_syslog - log to syslog - -#ifndef __RFB_LOGGER_SYSLOG_H__ -#define __RFB_LOGGER_SYSLOG_H__ - -#include <time.h> -#include <rfb/Logger.h> - -namespace rfb { - - class Logger_Syslog : public Logger { - public: - Logger_Syslog(const char* loggerName); - virtual ~Logger_Syslog(); - - void write(int level, const char *logname, const char *message) override; - }; - - void initSyslogLogger(); -}; - -#endif diff --git a/common/rfb/PixelBuffer.cxx b/common/rfb/PixelBuffer.cxx index 5590c214..32b0ce2f 100644 --- a/common/rfb/PixelBuffer.cxx +++ b/common/rfb/PixelBuffer.cxx @@ -30,13 +30,14 @@ #include <stdexcept> -#include <rfb/LogWriter.h> +#include <core/LogWriter.h> +#include <core/string.h> + #include <rfb/PixelBuffer.h> -#include <rfb/util.h> using namespace rfb; -static LogWriter vlog("PixelBuffer"); +static core::LogWriter vlog("PixelBuffer"); // We do a lot of byte offset calculations that assume the result fits // inside a signed 32 bit integer. Limit the maximum size of pixel @@ -63,7 +64,8 @@ PixelBuffer::~PixelBuffer() {} void -PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) const +PixelBuffer::getImage(void* imageBuf, const core::Rect& r, + int outStride) const { int inStride; const uint8_t* data; @@ -72,10 +74,9 @@ PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) const const uint8_t* end; if (!r.enclosed_by(getRect())) - throw std::out_of_range(rfb::format("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d", - r.width(), r.height(), - r.tl.x, r.tl.y, - width(), height())); + throw std::out_of_range(core::format( + "Source rect %dx%d at %d,%d exceeds framebuffer %dx%d", + r.width(), r.height(), r.tl.x, r.tl.y, width(), height())); data = getBuffer(r, &inStride); @@ -98,7 +99,7 @@ PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) const } void PixelBuffer::getImage(const PixelFormat& pf, void* imageBuf, - const Rect& r, int stride) const + const core::Rect& r, int stride) const { const uint8_t* srcBuffer; int srcStride; @@ -109,10 +110,9 @@ void PixelBuffer::getImage(const PixelFormat& pf, void* imageBuf, } if (!r.enclosed_by(getRect())) - throw std::out_of_range(rfb::format("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d", - r.width(), r.height(), - r.tl.x, r.tl.y, - width(), height())); + throw std::out_of_range(core::format( + "Source rect %dx%d at %d,%d exceeds framebuffer %dx%d", + r.width(), r.height(), r.tl.x, r.tl.y, width(), height())); if (stride == 0) stride = r.width(); @@ -126,9 +126,11 @@ void PixelBuffer::getImage(const PixelFormat& pf, void* imageBuf, void PixelBuffer::setSize(int width, int height) { if ((width < 0) || (width > maxPixelBufferWidth)) - throw std::out_of_range(rfb::format("Invalid PixelBuffer width of %d pixels requested", width)); + throw std::out_of_range(core::format( + "Invalid PixelBuffer width of %d pixels requested", width)); if ((height < 0) || (height > maxPixelBufferHeight)) - throw std::out_of_range(rfb::format("Invalid PixelBuffer height of %d pixels requested", height)); + throw std::out_of_range(core::format( + "Invalid PixelBuffer height of %d pixels requested", height)); width_ = width; height_ = height; @@ -150,17 +152,17 @@ ModifiablePixelBuffer::~ModifiablePixelBuffer() { } -void ModifiablePixelBuffer::fillRect(const Rect& r, const void* pix) +void ModifiablePixelBuffer::fillRect(const core::Rect& r, + const void* pix) { int stride; uint8_t *buf; int w, h, b; if (!r.enclosed_by(getRect())) - throw std::out_of_range(rfb::format("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", - r.width(), r.height(), - r.tl.x, r.tl.y, - width(), height())); + throw std::out_of_range(core::format( + "Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", + r.width(), r.height(), r.tl.x, r.tl.y, width(), height())); w = r.width(); h = r.height(); @@ -199,7 +201,7 @@ void ModifiablePixelBuffer::fillRect(const Rect& r, const void* pix) commitBufferRW(r); } -void ModifiablePixelBuffer::imageRect(const Rect& r, +void ModifiablePixelBuffer::imageRect(const core::Rect& r, const void* pixels, int srcStride) { uint8_t* dest; @@ -209,10 +211,9 @@ void ModifiablePixelBuffer::imageRect(const Rect& r, uint8_t* end; if (!r.enclosed_by(getRect())) - throw std::out_of_range(rfb::format("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", - r.width(), r.height(), - r.tl.x, r.tl.y, - width(), height())); + throw std::out_of_range(core::format( + "Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", + r.width(), r.height(), r.tl.x, r.tl.y, width(), height())); bytesPerPixel = getPF().bpp/8; @@ -237,29 +238,29 @@ void ModifiablePixelBuffer::imageRect(const Rect& r, commitBufferRW(r); } -void ModifiablePixelBuffer::copyRect(const Rect &rect, - const Point &move_by_delta) +void ModifiablePixelBuffer::copyRect(const core::Rect& rect, + const core::Point& move_by_delta) { int srcStride, dstStride; int bytesPerPixel; const uint8_t* srcData; uint8_t* dstData; - Rect drect, srect; + core::Rect drect, srect; drect = rect; if (!drect.enclosed_by(getRect())) - throw std::out_of_range(rfb::format("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", - drect.width(), drect.height(), - drect.tl.x, drect.tl.y, - width(), height())); + throw std::out_of_range(core::format( + "Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", + drect.width(), drect.height(), drect.tl.x, drect.tl.y, + width(), height())); srect = drect.translate(move_by_delta.negate()); if (!srect.enclosed_by(getRect())) - throw std::out_of_range(rfb::format("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d", - srect.width(), srect.height(), - srect.tl.x, srect.tl.y, - width(), height())); + throw std::out_of_range(core::format( + "Source rect %dx%d at %d,%d exceeds framebuffer %dx%d", + srect.width(), srect.height(), srect.tl.x, srect.tl.y, + width(), height())); bytesPerPixel = format.bpp/8; @@ -297,7 +298,8 @@ void ModifiablePixelBuffer::copyRect(const Rect &rect, commitBufferRW(drect); } -void ModifiablePixelBuffer::fillRect(const PixelFormat& pf, const Rect &dest, +void ModifiablePixelBuffer::fillRect(const PixelFormat& pf, + const core::Rect& dest, const void* pix) { uint8_t buf[4]; @@ -305,17 +307,18 @@ void ModifiablePixelBuffer::fillRect(const PixelFormat& pf, const Rect &dest, fillRect(dest, buf); } -void ModifiablePixelBuffer::imageRect(const PixelFormat& pf, const Rect &dest, +void ModifiablePixelBuffer::imageRect(const PixelFormat& pf, + const core::Rect& dest, const void* pixels, int stride) { uint8_t* dstBuffer; int dstStride; if (!dest.enclosed_by(getRect())) - throw std::out_of_range(rfb::format("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", - dest.width(), dest.height(), - dest.tl.x, dest.tl.y, - width(), height())); + throw std::out_of_range(core::format( + "Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d", + dest.width(), dest.height(), dest.tl.x, dest.tl.y, + width(), height())); if (stride == 0) stride = dest.width(); @@ -339,29 +342,29 @@ FullFramePixelBuffer::FullFramePixelBuffer() : data(nullptr) {} FullFramePixelBuffer::~FullFramePixelBuffer() {} -uint8_t* FullFramePixelBuffer::getBufferRW(const Rect& r, int* stride_) +uint8_t* FullFramePixelBuffer::getBufferRW(const core::Rect& r, + int* stride_) { if (!r.enclosed_by(getRect())) - throw std::out_of_range(rfb::format("Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d", - r.width(), r.height(), - r.tl.x, r.tl.y, - width(), height())); + throw std::out_of_range(core::format( + "Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d", + r.width(), r.height(), r.tl.x, r.tl.y, width(), height())); *stride_ = stride; return &data[(r.tl.x + (r.tl.y * stride)) * (format.bpp/8)]; } -void FullFramePixelBuffer::commitBufferRW(const Rect& /*r*/) +void FullFramePixelBuffer::commitBufferRW(const core::Rect& /*r*/) { } -const uint8_t* FullFramePixelBuffer::getBuffer(const Rect& r, int* stride_) const +const uint8_t* FullFramePixelBuffer::getBuffer(const core::Rect& r, + int* stride_) const { if (!r.enclosed_by(getRect())) - throw std::out_of_range(rfb::format("Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d", - r.width(), r.height(), - r.tl.x, r.tl.y, - width(), height())); + throw std::out_of_range(core::format( + "Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d", + r.width(), r.height(), r.tl.x, r.tl.y, width(), height())); *stride_ = stride; return &data[(r.tl.x + (r.tl.y * stride)) * (format.bpp/8)]; @@ -371,13 +374,17 @@ void FullFramePixelBuffer::setBuffer(int width, int height, uint8_t* data_, int stride_) { if ((width < 0) || (width > maxPixelBufferWidth)) - throw std::out_of_range(rfb::format("Invalid PixelBuffer width of %d pixels requested", width)); + throw std::out_of_range(core::format( + "Invalid PixelBuffer width of %d pixels requested", width)); if ((height < 0) || (height > maxPixelBufferHeight)) - throw std::out_of_range(rfb::format("Invalid PixelBuffer height of %d pixels requested", height)); + throw std::out_of_range(core::format( + "Invalid PixelBuffer height of %d pixels requested", height)); if ((stride_ < 0) || (stride_ > maxPixelBufferStride) || (stride_ < width)) - throw std::invalid_argument(rfb::format("Invalid PixelBuffer stride of %d pixels requested", stride_)); + throw std::invalid_argument(core::format( + "Invalid PixelBuffer stride of %d pixels requested", stride_)); if ((width != 0) && (height != 0) && (data_ == nullptr)) - throw std::logic_error(rfb::format("PixelBuffer requested without a valid memory area")); + throw std::logic_error(core::format( + "PixelBuffer requested without a valid memory area")); ModifiablePixelBuffer::setSize(width, height); stride = stride_; diff --git a/common/rfb/PixelBuffer.h b/common/rfb/PixelBuffer.h index 963fbbf6..9fbea611 100644 --- a/common/rfb/PixelBuffer.h +++ b/common/rfb/PixelBuffer.h @@ -25,12 +25,13 @@ #ifndef __RFB_PIXEL_BUFFER_H__ #define __RFB_PIXEL_BUFFER_H__ +#include <core/Rect.h> + #include <rfb/PixelFormat.h> -#include <rfb/Rect.h> -namespace rfb { +namespace core { class Region; } - class Region; +namespace rfb { class PixelBuffer { public: @@ -52,9 +53,9 @@ namespace rfb { // Get rectangle encompassing this buffer // Top-left of rectangle is either at (0,0), or the specified point. - Rect getRect() const { return Rect(0, 0, width_, height_); } - Rect getRect(const Point& pos) const { - return Rect(pos, pos.translate(Point(width_, height_))); + core::Rect getRect() const { return {0, 0, width_, height_}; } + core::Rect getRect(const core::Point& pos) const { + return {pos, pos.translate({width_, height_})}; } /////////////////////////////////////////////// @@ -64,18 +65,20 @@ namespace rfb { // Get a pointer into the buffer // The pointer is to the top-left pixel of the specified Rect. // The buffer stride (in pixels) is returned. - virtual const uint8_t* getBuffer(const Rect& r, int* stride) const = 0; + virtual const uint8_t* getBuffer(const core::Rect& r, + int* stride) const = 0; // Get pixel data for a given part of the buffer // Data is copied into the supplied buffer, with the specified // stride. Try to avoid using this though as getBuffer() will in // most cases avoid the extra memory copy. - void getImage(void* imageBuf, const Rect& r, int stride=0) const; + void getImage(void* imageBuf, const core::Rect& r, + int stride=0) const; // Get pixel data in a given format // Works just the same as getImage(), but guaranteed to be in a // specific format. void getImage(const PixelFormat& pf, void* imageBuf, - const Rect& r, int stride=0) const; + const core::Rect& r, int stride=0) const; /////////////////////////////////////////////// // Framebuffer update methods @@ -84,7 +87,7 @@ namespace rfb { // Ensure that the specified rectangle of buffer is up to date. // Overridden by derived classes implementing framebuffer access // to copy the required display data into place. - virtual void grabRegion(const Region& /*region*/) {} + virtual void grabRegion(const core::Region& /*region*/) {} protected: PixelBuffer(); @@ -110,32 +113,35 @@ namespace rfb { // Get a writeable pointer into the buffer // Like getBuffer(), the pointer is to the top-left pixel of the // specified Rect and the stride in pixels is returned. - virtual uint8_t* getBufferRW(const Rect& r, int* stride) = 0; + virtual uint8_t* getBufferRW(const core::Rect& r, int* stride) = 0; // Commit the modified contents // Ensures that the changes to the specified Rect is properly // stored away and any temporary buffers are freed. The Rect given // here needs to match the Rect given to the earlier call to // getBufferRW(). - virtual void commitBufferRW(const Rect& r) = 0; + virtual void commitBufferRW(const core::Rect& r) = 0; /////////////////////////////////////////////// // Basic rendering operations // These operations DO NOT clip to the pixelbuffer area, or trap overruns. // Fill a rectangle - void fillRect(const Rect &dest, const void* pix); + void fillRect(const core::Rect& dest, const void* pix); // Copy pixel data to the buffer - void imageRect(const Rect &dest, const void* pixels, int stride=0); + void imageRect(const core::Rect& dest, const void* pixels, + int stride=0); // Copy pixel data from one PixelBuffer location to another - void copyRect(const Rect &dest, const Point& move_by_delta); + void copyRect(const core::Rect& dest, + const core::Point& move_by_delta); // Render in a specific format // Does the exact same thing as the above methods, but the given // pixel values are defined by the given PixelFormat. - void fillRect(const PixelFormat& pf, const Rect &dest, const void* pix); - void imageRect(const PixelFormat& pf, const Rect &dest, + void fillRect(const PixelFormat& pf, const core::Rect& dest, + const void* pix); + void imageRect(const PixelFormat& pf, const core::Rect& dest, const void* pixels, int stride=0); protected: @@ -151,9 +157,10 @@ namespace rfb { virtual ~FullFramePixelBuffer(); public: - const uint8_t* getBuffer(const Rect& r, int* stride) const override; - uint8_t* getBufferRW(const Rect& r, int* stride) override; - void commitBufferRW(const Rect& r) override; + const uint8_t* getBuffer(const core::Rect& r, + int* stride) const override; + uint8_t* getBufferRW(const core::Rect& r, int* stride) override; + void commitBufferRW(const core::Rect& r) override; protected: FullFramePixelBuffer(); diff --git a/common/rfb/PixelFormat.h b/common/rfb/PixelFormat.h index f0a16767..7b754da8 100644 --- a/common/rfb/PixelFormat.h +++ b/common/rfb/PixelFormat.h @@ -136,7 +136,7 @@ namespace rfb { /* Only for testing this class */ friend void makePixel(const rfb::PixelFormat &, uint8_t *); - friend bool verifyPixel(const rfb::PixelFormat &, + friend void verifyPixel(const rfb::PixelFormat &, const rfb::PixelFormat &, const uint8_t *); }; diff --git a/common/rfb/RREDecoder.cxx b/common/rfb/RREDecoder.cxx index 53ddc2da..d2c3d3e6 100644 --- a/common/rfb/RREDecoder.cxx +++ b/common/rfb/RREDecoder.cxx @@ -40,7 +40,7 @@ RREDecoder::~RREDecoder() { } -bool RREDecoder::readRect(const Rect& /*r*/, rdr::InStream* is, +bool RREDecoder::readRect(const core::Rect& /*r*/, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os) { uint32_t numRects; @@ -66,7 +66,7 @@ bool RREDecoder::readRect(const Rect& /*r*/, rdr::InStream* is, return true; } -void RREDecoder::decodeRect(const Rect& r, const uint8_t* buffer, +void RREDecoder::decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) { @@ -91,7 +91,7 @@ inline T RREDecoder::readPixel(rdr::InStream* is) } template<class T> -void RREDecoder::rreDecode(const Rect& r, rdr::InStream* is, +void RREDecoder::rreDecode(const core::Rect& r, rdr::InStream* is, const PixelFormat& pf, ModifiablePixelBuffer* pb) { @@ -109,6 +109,6 @@ void RREDecoder::rreDecode(const Rect& r, rdr::InStream* is, if (((x+w) > r.width()) || ((y+h) > r.height())) throw protocol_error("RRE decode error"); - pb->fillRect(pf, Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), &pix); + pb->fillRect(pf, {r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h}, &pix); } } diff --git a/common/rfb/RREDecoder.h b/common/rfb/RREDecoder.h index 8490146c..3fdcdd85 100644 --- a/common/rfb/RREDecoder.h +++ b/common/rfb/RREDecoder.h @@ -29,17 +29,17 @@ namespace rfb { public: RREDecoder(); virtual ~RREDecoder(); - bool readRect(const Rect& r, rdr::InStream* is, + bool readRect(const core::Rect& r, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os) override; - void decodeRect(const Rect& r, const uint8_t* buffer, + void decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) override; private: template<class T> inline T readPixel(rdr::InStream* is); template<class T> - void rreDecode(const Rect& r, rdr::InStream* is, + void rreDecode(const core::Rect& r, rdr::InStream* is, const PixelFormat& pf, ModifiablePixelBuffer* pb); }; } diff --git a/common/rfb/RawDecoder.cxx b/common/rfb/RawDecoder.cxx index f2ea586b..43ce15a4 100644 --- a/common/rfb/RawDecoder.cxx +++ b/common/rfb/RawDecoder.cxx @@ -37,7 +37,7 @@ RawDecoder::~RawDecoder() { } -bool RawDecoder::readRect(const Rect& r, rdr::InStream* is, +bool RawDecoder::readRect(const core::Rect& r, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os) { if (!is->hasData(r.area() * (server.pf().bpp/8))) @@ -46,7 +46,7 @@ bool RawDecoder::readRect(const Rect& r, rdr::InStream* is, return true; } -void RawDecoder::decodeRect(const Rect& r, const uint8_t* buffer, +void RawDecoder::decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) { diff --git a/common/rfb/RawDecoder.h b/common/rfb/RawDecoder.h index 2ac8b0bd..6c3a6357 100644 --- a/common/rfb/RawDecoder.h +++ b/common/rfb/RawDecoder.h @@ -25,10 +25,10 @@ namespace rfb { public: RawDecoder(); virtual ~RawDecoder(); - bool readRect(const Rect& r, rdr::InStream* is, + bool readRect(const core::Rect& r, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os) override; - void decodeRect(const Rect& r, const uint8_t* buffer, + void decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) override; }; diff --git a/common/rfb/Rect.h b/common/rfb/Rect.h deleted file mode 100644 index b82ed274..00000000 --- a/common/rfb/Rect.h +++ /dev/null @@ -1,130 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * 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. - */ - -// rfb::Rect and rfb::Point structures - -#ifndef __RFB_RECT_INCLUDED__ -#define __RFB_RECT_INCLUDED__ - -// Some platforms (e.g. Windows) include max() and min() macros in their -// standard headers, but they are also standard C++ template functions, so some -// C++ headers will undefine them. So we steer clear of the names min and max -// and define __rfbmin and __rfbmax instead. - -#ifndef __rfbmax -#define __rfbmax(a,b) (((a) > (b)) ? (a) : (b)) -#endif -#ifndef __rfbmin -#define __rfbmin(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -namespace rfb { - - // rfb::Point - // - // Represents a point in 2D space, by X and Y coordinates. - // Can also be used to represent a delta, or offset, between - // two Points. - // Functions are provided to allow Points to be compared for - // equality and translated by a supplied offset. - // Functions are also provided to negate offset Points. - - struct Point { - Point() : x(0), y(0) {} - Point(int x_, int y_) : x(x_), y(y_) {} - inline Point negate() const - __attribute__ ((warn_unused_result)) - {return Point(-x, -y);} - inline bool operator==(const Point &p) const {return x==p.x && y==p.y;} - inline bool operator!=(const Point &p) const {return x!=p.x || y!=p.y;} - inline Point translate(const Point &p) const - __attribute__ ((warn_unused_result)) - {return Point(x+p.x, y+p.y);} - inline Point subtract(const Point &p) const - __attribute__ ((warn_unused_result)) - {return Point(x-p.x, y-p.y);} - int x, y; - }; - - // rfb::Rect - // - // Represents a rectangular region defined by its top-left (tl) - // and bottom-right (br) Points. - // Rects may be compared for equality, checked to determine whether - // or not they are empty, cleared (made empty), or intersected with - // one another. The bounding rectangle of two existing Rects - // may be calculated, as may the area of a Rect. - // Rects may also be translated, in the same way as Points, by - // an offset specified in a Point structure. - - struct Rect { - Rect() {} - Rect(Point tl_, Point br_) : tl(tl_), br(br_) {} - Rect(int x1, int y1, int x2, int y2) : tl(x1, y1), br(x2, y2) {} - inline void setXYWH(int x, int y, int w, int h) { - tl.x = x; tl.y = y; br.x = x+w; br.y = y+h; - } - inline Rect intersect(const Rect &r) const - __attribute__ ((warn_unused_result)) - { - Rect result; - result.tl.x = __rfbmax(tl.x, r.tl.x); - result.tl.y = __rfbmax(tl.y, r.tl.y); - result.br.x = __rfbmax(__rfbmin(br.x, r.br.x), result.tl.x); - result.br.y = __rfbmax(__rfbmin(br.y, r.br.y), result.tl.y); - return result; - } - inline Rect union_boundary(const Rect &r) const - __attribute__ ((warn_unused_result)) - { - if (r.is_empty()) return *this; - if (is_empty()) return r; - Rect result; - result.tl.x = __rfbmin(tl.x, r.tl.x); - result.tl.y = __rfbmin(tl.y, r.tl.y); - result.br.x = __rfbmax(br.x, r.br.x); - result.br.y = __rfbmax(br.y, r.br.y); - return result; - } - inline Rect translate(const Point &p) const - __attribute__ ((warn_unused_result)) - { - return Rect(tl.translate(p), br.translate(p)); - } - inline bool operator==(const Rect &r) const {return r.tl == tl && r.br == br;} - inline bool operator!=(const Rect &r) const {return r.tl != tl || r.br != br;} - inline bool is_empty() const {return (tl.x >= br.x) || (tl.y >= br.y);} - inline void clear() {tl = Point(); br = Point();} - inline bool enclosed_by(const Rect &r) const { - return (tl.x>=r.tl.x) && (tl.y>=r.tl.y) && (br.x<=r.br.x) && (br.y<=r.br.y); - } - inline bool overlaps(const Rect &r) const { - return tl.x < r.br.x && tl.y < r.br.y && br.x > r.tl.x && br.y > r.tl.y; - } - inline int area() const {return is_empty() ? 0 : (br.x-tl.x)*(br.y-tl.y);} - inline Point dimensions() const {return Point(width(), height());} - inline int width() const {return br.x-tl.x;} - inline int height() const {return br.y-tl.y;} - inline bool contains(const Point &p) const { - return (tl.x<=p.x) && (tl.y<=p.y) && (br.x>p.x) && (br.y>p.y); - } - Point tl; - Point br; - }; -} -#endif // __RFB_RECT_INCLUDED__ diff --git a/common/rfb/Region.cxx b/common/rfb/Region.cxx deleted file mode 100644 index cfdf0ca2..00000000 --- a/common/rfb/Region.cxx +++ /dev/null @@ -1,183 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2016-2020 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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <rfb/Region.h> -#include <rfb/LogWriter.h> - -extern "C" { -#include <pixman.h> -} - -static rfb::LogWriter vlog("Region"); - -rfb::Region::Region() { - rgn = new struct pixman_region16; - pixman_region_init(rgn); -} - -rfb::Region::Region(const Rect& r) { - rgn = new struct pixman_region16; - pixman_region_init_rect(rgn, r.tl.x, r.tl.y, r.width(), r.height()); -} - -rfb::Region::Region(const rfb::Region& r) { - rgn = new struct pixman_region16; - pixman_region_init(rgn); - pixman_region_copy(rgn, r.rgn); -} - -rfb::Region::~Region() { - pixman_region_fini(rgn); - delete rgn; -} - -rfb::Region& rfb::Region::operator=(const rfb::Region& r) { - pixman_region_copy(rgn, r.rgn); - return *this; -} - -void rfb::Region::clear() { - // pixman_region_clear() isn't available on some older systems - pixman_region_fini(rgn); - pixman_region_init(rgn); -} - -void rfb::Region::reset(const Rect& r) { - pixman_region_fini(rgn); - pixman_region_init_rect(rgn, r.tl.x, r.tl.y, r.width(), r.height()); -} - -void rfb::Region::translate(const Point& delta) { - pixman_region_translate(rgn, delta.x, delta.y); -} - -void rfb::Region::assign_intersect(const rfb::Region& r) { - pixman_region_intersect(rgn, rgn, r.rgn); -} - -void rfb::Region::assign_union(const rfb::Region& r) { - pixman_region_union(rgn, rgn, r.rgn); -} - -void rfb::Region::assign_subtract(const rfb::Region& r) { - pixman_region_subtract(rgn, rgn, r.rgn); -} - -rfb::Region rfb::Region::intersect(const rfb::Region& r) const { - rfb::Region ret; - pixman_region_intersect(ret.rgn, rgn, r.rgn); - return ret; -} - -rfb::Region rfb::Region::union_(const rfb::Region& r) const { - rfb::Region ret; - pixman_region_union(ret.rgn, rgn, r.rgn); - return ret; -} - -rfb::Region rfb::Region::subtract(const rfb::Region& r) const { - rfb::Region ret; - pixman_region_subtract(ret.rgn, rgn, r.rgn); - return ret; -} - -bool rfb::Region::operator==(const rfb::Region& r) const { - return pixman_region_equal(rgn, r.rgn); -} - -bool rfb::Region::operator!=(const rfb::Region& r) const { - return !pixman_region_equal(rgn, r.rgn); -} - -int rfb::Region::numRects() const { - return pixman_region_n_rects(rgn); -} - -bool rfb::Region::get_rects(std::vector<Rect>* rects, - bool left2right, bool topdown) const -{ - int nRects; - const pixman_box16_t* boxes; - int xInc, yInc, i; - - boxes = pixman_region_rectangles(rgn, &nRects); - - rects->clear(); - rects->reserve(nRects); - - xInc = left2right ? 1 : -1; - yInc = topdown ? 1 : -1; - i = topdown ? 0 : nRects-1; - - while (nRects > 0) { - int firstInNextBand = i; - int nRectsInBand = 0; - - while (nRects > 0 && boxes[firstInNextBand].y1 == boxes[i].y1) - { - firstInNextBand += yInc; - nRects--; - nRectsInBand++; - } - - if (xInc != yInc) - i = firstInNextBand - yInc; - - while (nRectsInBand > 0) { - Rect r(boxes[i].x1, boxes[i].y1, boxes[i].x2, boxes[i].y2); - rects->push_back(r); - i += xInc; - nRectsInBand--; - } - - i = firstInNextBand; - } - - return !rects->empty(); -} - -rfb::Rect rfb::Region::get_bounding_rect() const { - const pixman_box16_t* extents; - extents = pixman_region_extents(rgn); - return Rect(extents->x1, extents->y1, extents->x2, extents->y2); -} - - -void rfb::Region::debug_print(const char* prefix) const -{ - Rect extents; - std::vector<Rect> rects; - std::vector<Rect>::const_iterator iter; - - extents = get_bounding_rect(); - get_rects(&rects); - - vlog.debug("%s num rects %3ld extents %3d,%3d %3dx%3d", - prefix, (long)rects.size(), extents.tl.x, extents.tl.y, - extents.width(), extents.height()); - - for (iter = rects.begin(); iter != rects.end(); ++iter) { - vlog.debug(" rect %3d,%3d %3dx%3d", - iter->tl.x, iter->tl.y, iter->width(), iter->height()); - } -} diff --git a/common/rfb/Region.h b/common/rfb/Region.h deleted file mode 100644 index 38de67ce..00000000 --- a/common/rfb/Region.h +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2016-2020 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. - */ - -// Region class wrapper around pixman's region operations - -#ifndef __RFB_REGION_INCLUDED__ -#define __RFB_REGION_INCLUDED__ - -#include <rfb/Rect.h> -#include <vector> - -struct pixman_region16; - -namespace rfb { - - class Region { - public: - // Create an empty region - Region(); - // Create a rectangular region - Region(const Rect& r); - - Region(const Region& r); - Region &operator=(const Region& src); - - ~Region(); - - // the following methods alter the region in place: - - void clear(); - void reset(const Rect& r); - void translate(const rfb::Point& delta); - - void assign_intersect(const Region& r); - void assign_union(const Region& r); - void assign_subtract(const Region& r); - - // the following three operations return a new region: - - Region intersect(const Region& r) const - __attribute__ ((warn_unused_result)); - Region union_(const Region& r) const - __attribute__ ((warn_unused_result)); - Region subtract(const Region& r) const - __attribute__ ((warn_unused_result)); - - bool operator==(const Region& b) const; - bool operator!=(const Region& b) const; - int numRects() const; - bool is_empty() const { return numRects() == 0; } - - bool get_rects(std::vector<Rect>* rects, bool left2right=true, - bool topdown=true) const; - Rect get_bounding_rect() const; - - void debug_print(const char *prefix) const; - - protected: - - struct pixman_region16* rgn; - }; - -}; - -#endif // __RFB_REGION_INCLUDED__ diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx index a0a1c373..c698b991 100644 --- a/common/rfb/SConnection.cxx +++ b/common/rfb/SConnection.cxx @@ -26,6 +26,11 @@ #include <algorithm> +#include <core/LogWriter.h> +#include <core/string.h> + +#include <rdr/OutStream.h> + #include <rfb/Exception.h> #include <rfb/Security.h> #include <rfb/clipboardTypes.h> @@ -38,13 +43,10 @@ #include <rfb/encodings.h> #include <rfb/EncodeManager.h> #include <rfb/SSecurity.h> -#include <rfb/util.h> - -#include <rfb/LogWriter.h> using namespace rfb; -static LogWriter vlog("SConnection"); +static core::LogWriter vlog("SConnection"); SConnection::SConnection(AccessRights accessRights_) : readyForSetColourMapEntries(false), is(nullptr), os(nullptr), @@ -133,10 +135,10 @@ bool SConnection::processVersionMsg() if (client.majorVersion != 3) { // unknown protocol version - failConnection(format("Client needs protocol version %d.%d, " - "server has %d.%d", - client.majorVersion, client.minorVersion, - defaultMajorVersion, defaultMinorVersion)); + failConnection(core::format( + "Client needs protocol version %d.%d, server has %d.%d", + client.majorVersion, client.minorVersion, + defaultMajorVersion, defaultMinorVersion)); } if (client.minorVersion != 3 && client.minorVersion != 7 && client.minorVersion != 8) { @@ -152,8 +154,6 @@ bool SConnection::processVersionMsg() client.majorVersion,client.minorVersion); } - versionReceived(); - std::list<uint8_t> secTypes; std::list<uint8_t>::iterator i; secTypes = security.GetEnabledSecTypes(); @@ -166,9 +166,9 @@ bool SConnection::processVersionMsg() if (*i == secTypeNone || *i == secTypeVncAuth) break; } if (i == secTypes.end()) { - failConnection(format("No supported security type for " - "%d.%d client", - client.majorVersion, client.minorVersion)); + failConnection( + core::format("No supported security type for %d.%d client", + client.majorVersion, client.minorVersion)); } os->writeU32(*i); @@ -278,7 +278,7 @@ bool SConnection::processInitMsg() return reader_->readClientInit(); } -void SConnection::handleAuthFailureTimeout(Timer* /*t*/) +void SConnection::handleAuthFailureTimeout(core::Timer* /*t*/) { if (state_ != RFBSTATE_SECURITY_FAILURE) { close("SConnection::handleAuthFailureTimeout: Invalid state"); @@ -344,6 +344,8 @@ bool SConnection::accessCheck(AccessRights ar) const void SConnection::setEncodings(int nEncodings, const int32_t* encodings) { int i; + bool firstFence, firstContinuousUpdates, firstLEDState, + firstQEMUKeyEvent, firstExtMouseButtonsEvent; preferredEncoding = encodingRaw; for (i = 0;i < nEncodings;i++) { @@ -353,7 +355,26 @@ void SConnection::setEncodings(int nEncodings, const int32_t* encodings) } } - SMsgHandler::setEncodings(nEncodings, encodings); + firstFence = !client.supportsFence(); + firstContinuousUpdates = !client.supportsContinuousUpdates(); + firstLEDState = !client.supportsLEDState(); + firstQEMUKeyEvent = !client.supportsEncoding(pseudoEncodingQEMUKeyEvent); + firstExtMouseButtonsEvent = !client.supportsEncoding(pseudoEncodingExtendedMouseButtons); + + client.setEncodings(nEncodings, encodings); + + supportsLocalCursor(); + + if (client.supportsFence() && firstFence) + supportsFence(); + if (client.supportsContinuousUpdates() && firstContinuousUpdates) + supportsContinuousUpdates(); + if (client.supportsLEDState() && firstLEDState) + supportsLEDState(); + if (client.supportsEncoding(pseudoEncodingQEMUKeyEvent) && firstQEMUKeyEvent) + writer()->writeQEMUKeyEvent(); + if (client.supportsEncoding(pseudoEncodingExtendedMouseButtons) && firstExtMouseButtonsEvent) + writer()->writeExtendedMouseButtonsSupport(); if (client.supportsEncoding(pseudoEncodingExtendedClipboard)) { uint32_t sizes[] = { 0 }; @@ -373,9 +394,54 @@ void SConnection::clientCutText(const char* str) clientClipboard = str; hasRemoteClipboard = true; + if (!accessCheck(AccessCutText)) + return; + handleClipboardAnnounce(true); } +void SConnection::handleClipboardCaps(uint32_t flags, const uint32_t* lengths) +{ + int i; + + vlog.debug("Got client clipboard capabilities:"); + for (i = 0;i < 16;i++) { + if (flags & (1 << i)) { + const char *type; + + switch (1 << i) { + case clipboardUTF8: + type = "Plain text"; + break; + case clipboardRTF: + type = "Rich text"; + break; + case clipboardHTML: + type = "HTML"; + break; + case clipboardDIB: + type = "Images"; + break; + case clipboardFiles: + type = "Files"; + break; + default: + vlog.debug(" Unknown format 0x%x", 1 << i); + continue; + } + + if (lengths[i] == 0) + vlog.debug(" %s (only notify)", type); + else { + vlog.debug(" %s (automatically send up to %s)", + type, core::iecPrefix(lengths[i], "B").c_str()); + } + } + } + + client.setClipboardCaps(flags, lengths); +} + void SConnection::handleClipboardRequest(uint32_t flags) { if (!(flags & rfb::clipboardUTF8)) { @@ -386,6 +452,8 @@ void SConnection::handleClipboardRequest(uint32_t flags) vlog.debug("Ignoring unexpected clipboard request"); return; } + if (!accessCheck(AccessCutText)) + return; handleClipboardRequest(); } @@ -401,10 +469,15 @@ void SConnection::handleClipboardNotify(uint32_t flags) if (flags & rfb::clipboardUTF8) { hasLocalClipboard = false; + if (!accessCheck(AccessCutText)) + return; handleClipboardAnnounce(true); } else { + if (!accessCheck(AccessCutText)) + return; handleClipboardAnnounce(false); } + } void SConnection::handleClipboardProvide(uint32_t flags, @@ -417,28 +490,33 @@ void SConnection::handleClipboardProvide(uint32_t flags, } // FIXME: This conversion magic should be in SMsgReader - if (!isValidUTF8((const char*)data[0], lengths[0])) { + if (!core::isValidUTF8((const char*)data[0], lengths[0])) { vlog.error("Invalid UTF-8 sequence in clipboard - ignoring"); return; } - clientClipboard = convertLF((const char*)data[0], lengths[0]); + clientClipboard = core::convertLF((const char*)data[0], lengths[0]); hasRemoteClipboard = true; + if (!accessCheck(AccessCutText)) + return; + // FIXME: Should probably verify that this data was actually requested handleClipboardData(clientClipboard.c_str()); } -void SConnection::supportsQEMUKeyEvent() +void SConnection::supportsLocalCursor() { - writer()->writeQEMUKeyEvent(); } -void SConnection::supportsExtendedMouseButtons() +void SConnection::supportsFence() { - writer()->writeExtendedMouseButtonsSupport(); } -void SConnection::versionReceived() +void SConnection::supportsContinuousUpdates() +{ +} + +void SConnection::supportsLEDState() { } @@ -500,13 +578,13 @@ void SConnection::close(const char* /*reason*/) void SConnection::setPixelFormat(const PixelFormat& pf) { - SMsgHandler::setPixelFormat(pf); + client.setPF(pf); readyForSetColourMapEntries = true; if (!pf.trueColour) writeFakeColourMap(); } -void SConnection::framebufferUpdateRequest(const Rect& /*r*/, +void SConnection::framebufferUpdateRequest(const core::Rect& /*r*/, bool /*incremental*/) { if (!readyForSetColourMapEntries) { @@ -549,6 +627,9 @@ void SConnection::handleClipboardData(const char* /*data*/) void SConnection::requestClipboard() { + if (!accessCheck(AccessCutText)) + return; + if (hasRemoteClipboard) { handleClipboardData(clientClipboard.c_str()); return; @@ -561,6 +642,9 @@ void SConnection::requestClipboard() void SConnection::announceClipboard(bool available) { + if (!accessCheck(AccessCutText)) + return; + hasLocalClipboard = available; unsolicitedClipboardAttempt = false; @@ -587,10 +671,13 @@ void SConnection::announceClipboard(bool available) void SConnection::sendClipboardData(const char* data) { + if (!accessCheck(AccessCutText)) + return; + if (client.supportsEncoding(pseudoEncodingExtendedClipboard) && (client.clipboardFlags() & rfb::clipboardProvide)) { // FIXME: This conversion magic should be in SMsgWriter - std::string filtered(convertCRLF(data)); + std::string filtered(core::convertCRLF(data)); size_t sizes[1] = { filtered.size() + 1 }; const uint8_t* datas[1] = { (const uint8_t*)filtered.c_str() }; diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h index f030ae05..a90b37ca 100644 --- a/common/rfb/SConnection.h +++ b/common/rfb/SConnection.h @@ -26,13 +26,16 @@ #include <string> -#include <rdr/InStream.h> -#include <rdr/OutStream.h> +#include <core/Timer.h> #include <rfb/AccessRights.h> #include <rfb/SMsgHandler.h> #include <rfb/SecurityServer.h> -#include <rfb/Timer.h> + +namespace rdr { + class InStream; + class OutStream; +} namespace rfb { @@ -84,6 +87,59 @@ namespace rfb { // cleanup of the SConnection object by the server virtual void close(const char* reason); + // requestClipboard() will result in a request to the client to + // transfer its clipboard data. A call to handleClipboardData() + // will be made once the data is available. + virtual void requestClipboard(); + + // announceClipboard() informs the client of changes to the + // clipboard on the server. The client may later request the + // clipboard data via handleClipboardRequest(). + virtual void announceClipboard(bool available); + + // sendClipboardData() transfers the clipboard data to the client + // and should be called whenever the client has requested the + // clipboard via handleClipboardRequest(). + virtual void sendClipboardData(const char* data); + + // getAccessRights() returns the access rights of a SConnection to the server. + AccessRights getAccessRights() { return accessRights; } + + // setAccessRights() allows a security package to limit the access rights + // of a SConnection to the server. How the access rights are treated + // is up to the derived class. + virtual void setAccessRights(AccessRights ar); + virtual bool accessCheck(AccessRights ar) const; + + // authenticated() returns true if the client has authenticated + // successfully. + bool authenticated() { return (state_ == RFBSTATE_INITIALISATION || + state_ == RFBSTATE_NORMAL); } + + SMsgReader* reader() { return reader_; } + SMsgWriter* writer() { return writer_; } + + rdr::InStream* getInStream() { return is; } + rdr::OutStream* getOutStream() { return os; } + + enum stateEnum { + RFBSTATE_UNINITIALISED, + RFBSTATE_PROTOCOL_VERSION, + RFBSTATE_SECURITY_TYPE, + RFBSTATE_SECURITY, + RFBSTATE_SECURITY_FAILURE, + RFBSTATE_QUERYING, + RFBSTATE_INITIALISATION, + RFBSTATE_NORMAL, + RFBSTATE_CLOSING, + RFBSTATE_INVALID + }; + + stateEnum state() { return state_; } + + int32_t getPreferredEncoding() { return preferredEncoding; } + + protected: // Overridden from SMsgHandler @@ -91,23 +147,38 @@ namespace rfb { void clientCutText(const char* str) override; + void handleClipboardCaps(uint32_t flags, + const uint32_t* lengths) override; void handleClipboardRequest(uint32_t flags) override; void handleClipboardPeek() override; void handleClipboardNotify(uint32_t flags) override; void handleClipboardProvide(uint32_t flags, const size_t* lengths, const uint8_t* const* data) override; - void supportsQEMUKeyEvent() override; - - virtual void supportsExtendedMouseButtons() override; - - // Methods to be overridden in a derived class - // versionReceived() indicates that the version number has just been read - // from the client. The version will already have been "cooked" - // to deal with unknown/bogus viewer protocol numbers. - virtual void versionReceived(); + // supportsLocalCursor() is called whenever the status of + // cp.supportsLocalCursor has changed. At the moment this happens on a + // setEncodings message, but in the future this may be due to a message + // specially for this purpose. + virtual void supportsLocalCursor(); + + // supportsFence() is called the first time we detect support for fences + // in the client. A fence message should be sent at this point to notify + // the client of server support. + virtual void supportsFence(); + + // supportsContinuousUpdates() is called the first time we detect that + // the client wants the continuous updates extension. A + // EndOfContinuousUpdates message should be sent back to the client at + // this point if it is supported. + virtual void supportsContinuousUpdates(); + + // supportsLEDState() is called the first time we detect that the + // client supports the LED state extension. A LEDState message + // should be sent back to the client to inform it of the current + // server state. + virtual void supportsLEDState(); // authSuccess() is called when authentication has succeeded. virtual void authSuccess(); @@ -132,7 +203,7 @@ namespace rfb { // framebufferUpdateRequest() is called when a FramebufferUpdateRequest // message is received. The derived class must call on to // SConnection::framebufferUpdateRequest(). - void framebufferUpdateRequest(const Rect& r, bool incremental) override; + void framebufferUpdateRequest(const core::Rect& r, bool incremental) override; // fence() is called when we get a fence request or response. By default // it responds directly to requests (stating it doesn't support any @@ -163,62 +234,6 @@ namespace rfb { // client received the request. virtual void handleClipboardData(const char* data); - - // Other methods - - // requestClipboard() will result in a request to the client to - // transfer its clipboard data. A call to handleClipboardData() - // will be made once the data is available. - virtual void requestClipboard(); - - // announceClipboard() informs the client of changes to the - // clipboard on the server. The client may later request the - // clipboard data via handleClipboardRequest(). - virtual void announceClipboard(bool available); - - // sendClipboardData() transfers the clipboard data to the client - // and should be called whenever the client has requested the - // clipboard via handleClipboardRequest(). - virtual void sendClipboardData(const char* data); - - // getAccessRights() returns the access rights of a SConnection to the server. - AccessRights getAccessRights() { return accessRights; } - - // setAccessRights() allows a security package to limit the access rights - // of a SConnection to the server. How the access rights are treated - // is up to the derived class. - virtual void setAccessRights(AccessRights ar); - virtual bool accessCheck(AccessRights ar) const; - - // authenticated() returns true if the client has authenticated - // successfully. - bool authenticated() { return (state_ == RFBSTATE_INITIALISATION || - state_ == RFBSTATE_NORMAL); } - - SMsgReader* reader() { return reader_; } - SMsgWriter* writer() { return writer_; } - - rdr::InStream* getInStream() { return is; } - rdr::OutStream* getOutStream() { return os; } - - enum stateEnum { - RFBSTATE_UNINITIALISED, - RFBSTATE_PROTOCOL_VERSION, - RFBSTATE_SECURITY_TYPE, - RFBSTATE_SECURITY, - RFBSTATE_SECURITY_FAILURE, - RFBSTATE_QUERYING, - RFBSTATE_INITIALISATION, - RFBSTATE_NORMAL, - RFBSTATE_CLOSING, - RFBSTATE_INVALID - }; - - stateEnum state() { return state_; } - - int32_t getPreferredEncoding() { return preferredEncoding; } - - protected: // failConnection() prints a message to the log, sends a connection // failed message to the client (if possible) and throws an // Exception. @@ -243,7 +258,7 @@ namespace rfb { bool processSecurityFailure(); bool processInitMsg(); - void handleAuthFailureTimeout(Timer* t); + void handleAuthFailureTimeout(core::Timer* t); int defaultMajorVersion, defaultMinorVersion; @@ -256,7 +271,7 @@ namespace rfb { SecurityServer security; SSecurity* ssecurity; - MethodTimer<SConnection> authFailureTimer; + core::MethodTimer<SConnection> authFailureTimer; std::string authFailureMsg; stateEnum state_; diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h index c97e788a..402a13af 100644 --- a/common/rfb/SDesktop.h +++ b/common/rfb/SDesktop.h @@ -38,14 +38,19 @@ #ifndef __RFB_SDESKTOP_H__ #define __RFB_SDESKTOP_H__ -#include <rfb/PixelBuffer.h> -#include <rfb/VNCServer.h> +#include <stdint.h> + #include <rfb/screenTypes.h> +namespace core { struct Point; } + namespace network { class Socket; } namespace rfb { + struct ScreenSet; + class VNCServer; + class SDesktop { public: // init() is called immediately when the VNCServer gets a reference @@ -97,7 +102,7 @@ namespace rfb { // pointerEvent() is called whenever a client sends an event that // the pointer moved, or a button was pressed or released. - virtual void pointerEvent(const Point& /*pos*/, + virtual void pointerEvent(const core::Point& /*pos*/, uint16_t /*buttonMask*/) {}; // handleClipboardRequest() is called whenever a client requests @@ -122,47 +127,6 @@ namespace rfb { virtual ~SDesktop() {} }; - // -=- SStaticDesktop - // Trivial implementation of the SDesktop interface, which provides - // dummy input handlers and event processing routine, and exports - // a plain black desktop of the specified format. - class SStaticDesktop : public SDesktop { - public: - SStaticDesktop(const Point& size) - : server(nullptr), buffer(nullptr) - { - PixelFormat pf; - const uint8_t black[4] = { 0, 0, 0, 0 }; - buffer = new ManagedPixelBuffer(pf, size.x, size.y); - if (buffer) - buffer->fillRect(buffer->getRect(), black); - } - SStaticDesktop(const Point& size, const PixelFormat& pf) - : buffer(nullptr) - { - const uint8_t black[4] = { 0, 0, 0, 0 }; - buffer = new ManagedPixelBuffer(pf, size.x, size.y); - if (buffer) - buffer->fillRect(buffer->getRect(), black); - } - virtual ~SStaticDesktop() { - if (buffer) delete buffer; - } - - void init(VNCServer* vs) override { - server = vs; - server->setPixelBuffer(buffer); - } - void queryConnection(network::Socket* sock, - const char* /*userName*/) override { - server->approveConnection(sock, true, nullptr); - } - - protected: - VNCServer* server; - ManagedPixelBuffer* buffer; - }; - }; #endif // __RFB_SDESKTOP_H__ diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx deleted file mode 100644 index 1dce634d..00000000 --- a/common/rfb/SMsgHandler.cxx +++ /dev/null @@ -1,176 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2019 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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <rfb/Exception.h> -#include <rfb/LogWriter.h> -#include <rfb/SMsgHandler.h> -#include <rfb/ScreenSet.h> -#include <rfb/clipboardTypes.h> -#include <rfb/encodings.h> -#include <rfb/util.h> - -using namespace rfb; - -static LogWriter vlog("SMsgHandler"); - -SMsgHandler::SMsgHandler() -{ -} - -SMsgHandler::~SMsgHandler() -{ -} - -void SMsgHandler::clientInit(bool /*shared*/) -{ -} - -void SMsgHandler::setPixelFormat(const PixelFormat& pf) -{ - client.setPF(pf); -} - -void SMsgHandler::setEncodings(int nEncodings, const int32_t* encodings) -{ - bool firstFence, firstContinuousUpdates, firstLEDState, - firstQEMUKeyEvent, firstExtMouseButtonsEvent; - - firstFence = !client.supportsFence(); - firstContinuousUpdates = !client.supportsContinuousUpdates(); - firstLEDState = !client.supportsLEDState(); - firstQEMUKeyEvent = !client.supportsEncoding(pseudoEncodingQEMUKeyEvent); - firstExtMouseButtonsEvent = !client.supportsEncoding(pseudoEncodingExtendedMouseButtons); - - client.setEncodings(nEncodings, encodings); - - supportsLocalCursor(); - - if (client.supportsFence() && firstFence) - supportsFence(); - if (client.supportsContinuousUpdates() && firstContinuousUpdates) - supportsContinuousUpdates(); - if (client.supportsLEDState() && firstLEDState) - supportsLEDState(); - if (client.supportsEncoding(pseudoEncodingQEMUKeyEvent) && firstQEMUKeyEvent) - supportsQEMUKeyEvent(); - if (client.supportsEncoding(pseudoEncodingExtendedMouseButtons) && firstExtMouseButtonsEvent) - supportsExtendedMouseButtons(); -} - -void SMsgHandler::keyEvent(uint32_t /*keysym*/, uint32_t /*keycode*/, - bool /*down*/) -{ -} - -void SMsgHandler::pointerEvent(const Point& /*pos*/, - uint16_t /*buttonMask*/) -{ -} - -void SMsgHandler::clientCutText(const char* /*str*/) -{ -} - -void SMsgHandler::handleClipboardCaps(uint32_t flags, const uint32_t* lengths) -{ - int i; - - vlog.debug("Got client clipboard capabilities:"); - for (i = 0;i < 16;i++) { - if (flags & (1 << i)) { - const char *type; - - switch (1 << i) { - case clipboardUTF8: - type = "Plain text"; - break; - case clipboardRTF: - type = "Rich text"; - break; - case clipboardHTML: - type = "HTML"; - break; - case clipboardDIB: - type = "Images"; - break; - case clipboardFiles: - type = "Files"; - break; - default: - vlog.debug(" Unknown format 0x%x", 1 << i); - continue; - } - - if (lengths[i] == 0) - vlog.debug(" %s (only notify)", type); - else { - vlog.debug(" %s (automatically send up to %s)", - type, iecPrefix(lengths[i], "B").c_str()); - } - } - } - - client.setClipboardCaps(flags, lengths); -} - -void SMsgHandler::handleClipboardRequest(uint32_t /*flags*/) -{ -} - -void SMsgHandler::handleClipboardPeek() -{ -} - -void SMsgHandler::handleClipboardNotify(uint32_t /*flags*/) -{ -} - -void SMsgHandler::handleClipboardProvide(uint32_t /*flags*/, - const size_t* /*lengths*/, - const uint8_t* const* /*data*/) -{ -} - -void SMsgHandler::supportsLocalCursor() -{ -} - -void SMsgHandler::supportsFence() -{ -} - -void SMsgHandler::supportsContinuousUpdates() -{ -} - -void SMsgHandler::supportsLEDState() -{ -} - -void SMsgHandler::supportsQEMUKeyEvent() -{ -} - -void SMsgHandler::supportsExtendedMouseButtons() -{ -}
\ No newline at end of file diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h index c5d13d78..d14a21c0 100644 --- a/common/rfb/SMsgHandler.h +++ b/common/rfb/SMsgHandler.h @@ -25,83 +25,47 @@ #include <stdint.h> -#include <rfb/PixelFormat.h> #include <rfb/ClientParams.h> -#include <rfb/ScreenSet.h> - -namespace rdr { class InStream; } namespace rfb { class SMsgHandler { public: - SMsgHandler(); - virtual ~SMsgHandler(); + virtual ~SMsgHandler() {} - // 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 clipboardCaps() methods, a - // derived class must call on to SMsgHandler's methods. + // The following methods are called as corresponding messages are + // read. A derived class must override these methods. - virtual void clientInit(bool shared); + virtual void clientInit(bool shared) = 0; - virtual void setPixelFormat(const PixelFormat& pf); - virtual void setEncodings(int nEncodings, const int32_t* encodings); - virtual void framebufferUpdateRequest(const Rect& r, bool incremental) = 0; + virtual void setPixelFormat(const PixelFormat& pf) = 0; + virtual void setEncodings(int nEncodings, + const int32_t* encodings) = 0; + virtual void framebufferUpdateRequest(const core::Rect& r, + bool incremental) = 0; virtual void setDesktopSize(int fb_width, int fb_height, const ScreenSet& layout) = 0; - virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]) = 0; + virtual void fence(uint32_t flags, unsigned len, + const uint8_t data[]) = 0; virtual void enableContinuousUpdates(bool enable, - int x, int y, int w, int h) = 0; + int x, int y, + int w, int h) = 0; virtual void keyEvent(uint32_t keysym, uint32_t keycode, - bool down); - virtual void pointerEvent(const Point& pos, - uint16_t buttonMask); + bool down) = 0; + virtual void pointerEvent(const core::Point& pos, + uint16_t buttonMask) = 0; - virtual void clientCutText(const char* str); + virtual void clientCutText(const char* str) = 0; virtual void handleClipboardCaps(uint32_t flags, - const uint32_t* lengths); - virtual void handleClipboardRequest(uint32_t flags); - virtual void handleClipboardPeek(); - virtual void handleClipboardNotify(uint32_t flags); + const uint32_t* lengths) = 0; + virtual void handleClipboardRequest(uint32_t flags) = 0; + virtual void handleClipboardPeek() = 0; + virtual void handleClipboardNotify(uint32_t flags) = 0; virtual void handleClipboardProvide(uint32_t flags, const size_t* lengths, - const uint8_t* const* data); - - // supportsLocalCursor() is called whenever the status of - // cp.supportsLocalCursor has changed. At the moment this happens on a - // setEncodings message, but in the future this may be due to a message - // specially for this purpose. - virtual void supportsLocalCursor(); - - // supportsFence() is called the first time we detect support for fences - // in the client. A fence message should be sent at this point to notify - // the client of server support. - virtual void supportsFence(); - - // supportsContinuousUpdates() is called the first time we detect that - // the client wants the continuous updates extension. A - // EndOfContinuousUpdates message should be sent back to the client at - // this point if it is supported. - virtual void supportsContinuousUpdates(); - - // supportsLEDState() is called the first time we detect that the - // client supports the LED state extension. A LEDState message - // should be sent back to the client to inform it of the current - // server state. - virtual void supportsLEDState(); - - // supportsQEMUKeyEvent() is called the first time we detect that the - // client wants the QEMU Extended Key Event extension. The default - // handler will send a pseudo-rect back, signalling server support. - virtual void supportsQEMUKeyEvent(); - - // supportsExtendedMouseButtons() is called the first time we detect that the - // client supports sending 16 bit mouse button state. This lets us pass more button - // states between server and client. - virtual void supportsExtendedMouseButtons(); + const uint8_t* const* data) = 0; ClientParams client; }; diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx index 5df11153..9054bcc3 100644 --- a/common/rfb/SMsgReader.cxx +++ b/common/rfb/SMsgReader.cxx @@ -25,6 +25,10 @@ #include <vector> +#include <core/Configuration.h> +#include <core/LogWriter.h> +#include <core/string.h> + #include <rdr/InStream.h> #include <rdr/ZlibInStream.h> @@ -32,17 +36,19 @@ #include <rfb/qemuTypes.h> #include <rfb/clipboardTypes.h> #include <rfb/Exception.h> +#include <rfb/PixelFormat.h> +#include <rfb/ScreenSet.h> #include <rfb/SMsgHandler.h> #include <rfb/SMsgReader.h> -#include <rfb/Configuration.h> -#include <rfb/LogWriter.h> -#include <rfb/util.h> using namespace rfb; -static LogWriter vlog("SMsgReader"); +static core::LogWriter vlog("SMsgReader"); -static IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024); +static core::IntParameter maxCutText("MaxCutText", + "Maximum permitted length of an " + "incoming clipboard update", + 256*1024, 0, INT_MAX); SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_) : handler(handler_), is(is_), state(MSGSTATE_IDLE) @@ -201,7 +207,7 @@ bool SMsgReader::readFramebufferUpdateRequest() int y = is->readU16(); int w = is->readU16(); int h = is->readU16(); - handler->framebufferUpdateRequest(Rect(x, y, x+w, y+h), inc); + handler->framebufferUpdateRequest({x, y, x+w, y+h}, inc); return true; } @@ -298,7 +304,7 @@ bool SMsgReader::readPointerEvent() } is->clearRestorePoint(); - handler->pointerEvent(Point(x, y), mask); + handler->pointerEvent({x, y}, mask); return true; } @@ -338,8 +344,8 @@ bool SMsgReader::readClientCutText() std::vector<char> ca(len); is->readBytes((uint8_t*)ca.data(), len); - std::string utf8(latin1ToUTF8(ca.data(), ca.size())); - std::string filtered(convertLF(utf8.data(), utf8.size())); + std::string utf8(core::latin1ToUTF8(ca.data(), ca.size())); + std::string filtered(core::convertLF(utf8.data(), utf8.size())); handler->clientCutText(filtered.c_str()); @@ -485,7 +491,7 @@ bool SMsgReader::readQEMUMessage() ret = readQEMUKeyEvent(); break; default: - throw protocol_error(format("Unknown QEMU submessage type %d", subType)); + throw protocol_error(core::format("Unknown QEMU submessage type %d", subType)); } if (!ret) { diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx index 5ee0905b..d52df511 100644 --- a/common/rfb/SMsgWriter.cxx +++ b/common/rfb/SMsgWriter.cxx @@ -24,6 +24,9 @@ #include <stdio.h> +#include <core/LogWriter.h> +#include <core/string.h> + #include <rdr/OutStream.h> #include <rdr/MemOutStream.h> #include <rdr/ZlibOutStream.h> @@ -32,16 +35,17 @@ #include <rfb/fenceTypes.h> #include <rfb/clipboardTypes.h> #include <rfb/ClientParams.h> +#include <rfb/Cursor.h> #include <rfb/UpdateTracker.h> #include <rfb/Encoder.h> +#include <rfb/ScreenSet.h> #include <rfb/SMsgWriter.h> -#include <rfb/LogWriter.h> +#include <rfb/encodings.h> #include <rfb/ledStates.h> -#include <rfb/util.h> using namespace rfb; -static LogWriter vlog("SMsgWriter"); +static core::LogWriter vlog("SMsgWriter"); SMsgWriter::SMsgWriter(ClientParams* client_, rdr::OutStream* os_) : client(client_), os(os_), @@ -95,7 +99,7 @@ void SMsgWriter::writeServerCutText(const char* str) if (strchr(str, '\r') != nullptr) throw std::invalid_argument("Invalid carriage return in clipboard data"); - std::string latin1(utf8ToLatin1(str)); + std::string latin1(core::utf8ToLatin1(str)); startMsg(msgTypeServerCutText); os->pad(3); @@ -405,7 +409,7 @@ void SMsgWriter::writeFramebufferUpdateEnd() endMsg(); } -void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY) +void SMsgWriter::writeCopyRect(const core::Rect& r, int srcX, int srcY) { startRect(r,encodingCopyRect); os->writeU16(srcX); @@ -413,7 +417,7 @@ void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY) endRect(); } -void SMsgWriter::startRect(const Rect& r, int encoding) +void SMsgWriter::startRect(const core::Rect& r, int encoding) { if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) throw std::logic_error("SMsgWriter::startRect: nRects out of sync"); @@ -488,7 +492,7 @@ void SMsgWriter::writePseudoRects() } if (needCursorPos) { - const Point& cursorPos = client->cursorPos(); + const core::Point& cursorPos = client->cursorPos(); if (client->supportsEncoding(pseudoEncodingVMwareCursorPosition)) { writeSetVMwareCursorPositionRect(cursorPos.x, cursorPos.y); diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h index 7bc0ed6a..113a9370 100644 --- a/common/rfb/SMsgWriter.h +++ b/common/rfb/SMsgWriter.h @@ -25,8 +25,7 @@ #include <stdint.h> -#include <rfb/encodings.h> -#include <rfb/ScreenSet.h> +namespace core { struct Rect; } namespace rdr { class OutStream; } @@ -117,11 +116,11 @@ namespace rfb { void writeFramebufferUpdateEnd(); // There is no explicit encoder for CopyRect rects. - void writeCopyRect(const Rect& r, int srcX, int srcY); + void writeCopyRect(const core::Rect& r, int srcX, int srcY); // Encoders should call these to mark the start and stop of individual // rects. - void startRect(const Rect& r, int enc); + void startRect(const core::Rect& r, int enc); void endRect(); protected: diff --git a/common/rfb/SSecurity.h b/common/rfb/SSecurity.h index 0911ecd8..edbe8185 100644 --- a/common/rfb/SSecurity.h +++ b/common/rfb/SSecurity.h @@ -44,12 +44,12 @@ #ifndef __RFB_SSECURITY_H__ #define __RFB_SSECURITY_H__ -#include <rfb/SConnection.h> - -#include <list> +#include <rfb/AccessRights.h> namespace rfb { + class SConnection; + class SSecurity { public: SSecurity(SConnection* sc_) : sc(sc_) {} diff --git a/common/rfb/SSecurityPlain.cxx b/common/rfb/SSecurityPlain.cxx index e62e6d60..4fa63250 100644 --- a/common/rfb/SSecurityPlain.cxx +++ b/common/rfb/SSecurityPlain.cxx @@ -21,10 +21,12 @@ #include <config.h> #endif +#include <core/Configuration.h> +#include <core/string.h> + #include <rfb/SSecurityPlain.h> #include <rfb/SConnection.h> #include <rfb/Exception.h> -#include <rfb/util.h> #include <rdr/InStream.h> #if !defined(WIN32) && !defined(__APPLE__) #include <rfb/UnixPasswordValidator.h> @@ -37,32 +39,30 @@ using namespace rfb; -StringParameter PasswordValidator::plainUsers +core::StringListParameter PasswordValidator::plainUsers ("PlainUsers", "Users permitted to access via Plain security type (including TLSPlain, X509Plain etc.)" #ifdef HAVE_NETTLE " or RSA-AES security types (RA2, RA2ne, RA2_256, RA2ne_256)" #endif , - ""); + {}); bool PasswordValidator::validUser(const char* username) { - std::vector<std::string> users; - - users = split(plainUsers, ','); - - for (size_t i = 0; i < users.size(); i++) { - if (users[i] == "*") + for (const char* user : plainUsers) { + if (strcmp(user, "*") == 0) return true; #if !defined(WIN32) && !defined(__APPLE__) - if (users[i] == "%u") { + if (strcmp(user, "%u") == 0) { struct passwd *pw = getpwnam(username); if (pw && pw->pw_uid == getuid()) return true; } #endif - if (users[i] == username) + // FIXME: We should compare uid, as the usernames might not be case + // sensitive, or have other normalisation + if (strcmp(user, username) == 0) return true; } return false; @@ -113,8 +113,9 @@ bool SSecurityPlain::processMsg() password[plen] = 0; username[ulen] = 0; plen = 0; - if (!valid->validate(sc, username, password)) - throw auth_error("Authentication failed"); + std::string msg = "Authentication failed"; + if (!valid->validate(sc, username, password, msg)) + throw auth_error(msg); } return true; diff --git a/common/rfb/SSecurityPlain.h b/common/rfb/SSecurityPlain.h index c0ac049b..4c030455 100644 --- a/common/rfb/SSecurityPlain.h +++ b/common/rfb/SSecurityPlain.h @@ -20,23 +20,29 @@ #ifndef __RFB_SSECURITYPLAIN_H__ #define __RFB_SSECURITYPLAIN_H__ -#include <rfb/SConnection.h> +#include <rfb/Security.h> #include <rfb/SSecurity.h> -#include <rfb/SSecurityVeNCrypt.h> -#include <rfb/Configuration.h> + +namespace core { class StringListParameter; } namespace rfb { class PasswordValidator { public: - bool validate(SConnection* sc, const char *username, const char *password) - { return validUser(username) ? validateInternal(sc, username, password) : false; } - static StringParameter plainUsers; + bool validate(SConnection* sc, + const char *username, + const char *password, + std::string &msg) + { return validUser(username) ? validateInternal(sc, username, password, msg) : false; } + static core::StringListParameter plainUsers; virtual ~PasswordValidator() { } protected: - virtual bool validateInternal(SConnection* sc, const char *username, const char *password)=0; + virtual bool validateInternal(SConnection* sc, + const char *username, + const char *password, + std::string &msg) = 0; static bool validUser(const char* username); }; diff --git a/common/rfb/SSecurityRSAAES.cxx b/common/rfb/SSecurityRSAAES.cxx index fed213ad..405005ab 100644 --- a/common/rfb/SSecurityRSAAES.cxx +++ b/common/rfb/SSecurityRSAAES.cxx @@ -37,13 +37,15 @@ #include <nettle/base64.h> #include <nettle/asn1.h> +#include <core/Exception.h> +#include <core/LogWriter.h> + #include <rdr/AESInStream.h> #include <rdr/AESOutStream.h> -#include <rdr/Exception.h> +#include <rdr/RandomStream.h> #include <rfb/SSecurityRSAAES.h> #include <rfb/SConnection.h> -#include <rfb/LogWriter.h> #include <rfb/Exception.h> #if !defined(WIN32) && !defined(__APPLE__) #include <rfb/UnixPasswordValidator.h> @@ -67,14 +69,14 @@ const size_t MaxKeyFileSize = 32 * 1024; using namespace rfb; -StringParameter SSecurityRSAAES::keyFile +core::StringParameter SSecurityRSAAES::keyFile ("RSAKey", "Path to the RSA key for the RSA-AES security types in " - "PEM format", "", ConfServer); -BoolParameter SSecurityRSAAES::requireUsername + "PEM format", ""); +core::BoolParameter SSecurityRSAAES::requireUsername ("RequireUsername", "Require username for the RSA-AES security types", - false, ConfServer); + false); -static LogWriter vlog("CSecurityRSAAES"); +static core::LogWriter vlog("SSecurityRSAAES"); SSecurityRSAAES::SSecurityRSAAES(SConnection* sc_, uint32_t _secType, int _keySize, bool _isAllEncrypted) @@ -174,7 +176,7 @@ void SSecurityRSAAES::loadPrivateKey() { FILE* file = fopen(keyFile, "rb"); if (!file) - throw rdr::posix_error("Failed to open key file", errno); + throw core::posix_error("Failed to open key file", errno); fseek(file, 0, SEEK_END); size_t size = ftell(file); if (size == 0 || size > MaxKeyFileSize) { @@ -185,7 +187,7 @@ void SSecurityRSAAES::loadPrivateKey() std::vector<uint8_t> data(size); if (fread(data.data(), 1, data.size(), file) != size) { fclose(file); - throw rdr::posix_error("Failed to read key", errno); + throw core::posix_error("Failed to read key", errno); } fclose(file); @@ -345,6 +347,7 @@ static void random_func(void* ctx, size_t length, uint8_t* dst) void SSecurityRSAAES::writeRandom() { + rdr::RandomStream rs; rdr::OutStream* os = sc->getOutStream(); if (!rs.hasData(keySize / 8)) throw std::runtime_error("Failed to generate random"); @@ -580,9 +583,10 @@ void SSecurityRSAAES::verifyUserPass() #elif !defined(__APPLE__) UnixPasswordValidator *valid = new UnixPasswordValidator(); #endif - if (!valid->validate(sc, username, password)) { + std::string msg = "Authentication failed"; + if (!valid->validate(sc, username, password, msg)) { delete valid; - throw auth_error("Authentication failed"); + throw auth_error(msg); } delete valid; #else diff --git a/common/rfb/SSecurityRSAAES.h b/common/rfb/SSecurityRSAAES.h index e3300cb7..283134db 100644 --- a/common/rfb/SSecurityRSAAES.h +++ b/common/rfb/SSecurityRSAAES.h @@ -27,7 +27,10 @@ #include <rfb/SSecurity.h> -#include <rdr/RandomStream.h> +namespace core { + class BoolParameter; + class StringParameter; +} namespace rdr { class InStream; @@ -51,8 +54,8 @@ namespace rfb { return accessRights; } - static StringParameter keyFile; - static BoolParameter requireUsername; + static core::StringParameter keyFile; + static core::BoolParameter requireUsername; private: void cleanup(); @@ -96,8 +99,6 @@ namespace rfb { rdr::InStream* rawis; rdr::OutStream* rawos; - - rdr::RandomStream rs; }; } diff --git a/common/rfb/SSecurityTLS.cxx b/common/rfb/SSecurityTLS.cxx index b297242b..17497b8e 100644 --- a/common/rfb/SSecurityTLS.cxx +++ b/common/rfb/SSecurityTLS.cxx @@ -2,7 +2,7 @@ * Copyright (C) 2004 Red Hat Inc. * Copyright (C) 2005 Martin Koegler * Copyright (C) 2010 TigerVNC Team - * Copyright (C) 2012-2021 Pierre Ossman for Cendio AB + * Copyright 2012-2025 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 @@ -30,13 +30,15 @@ #include <stdlib.h> +#include <core/LogWriter.h> + #include <rfb/SSecurityTLS.h> #include <rfb/SConnection.h> -#include <rfb/LogWriter.h> #include <rfb/Exception.h> + #include <rdr/TLSException.h> -#include <rdr/TLSInStream.h> -#include <rdr/TLSOutStream.h> +#include <rdr/TLSSocket.h> + #include <gnutls/x509.h> #if defined (SSECURITYTLS__USE_DEPRECATED_DH) @@ -59,17 +61,17 @@ static const gnutls_datum_t ffdhe_pkcs3_param = { using namespace rfb; -StringParameter SSecurityTLS::X509_CertFile -("X509Cert", "Path to the X509 certificate in PEM format", "", ConfServer); +core::StringParameter SSecurityTLS::X509_CertFile +("X509Cert", "Path to the X509 certificate in PEM format", ""); -StringParameter SSecurityTLS::X509_KeyFile -("X509Key", "Path to the key of the X509 certificate in PEM format", "", ConfServer); +core::StringParameter SSecurityTLS::X509_KeyFile +("X509Key", "Path to the key of the X509 certificate in PEM format", ""); -static LogWriter vlog("TLS"); +static core::LogWriter vlog("TLS"); SSecurityTLS::SSecurityTLS(SConnection* sc_, bool _anon) : SSecurity(sc_), session(nullptr), anon_cred(nullptr), - cert_cred(nullptr), anon(_anon), tlsis(nullptr), tlsos(nullptr), + cert_cred(nullptr), anon(_anon), tlssock(nullptr), rawis(nullptr), rawos(nullptr) { int ret; @@ -85,32 +87,13 @@ SSecurityTLS::SSecurityTLS(SConnection* sc_, bool _anon) void SSecurityTLS::shutdown() { - if (tlsos) { - try { - if (tlsos->hasBufferedData()) { - tlsos->cork(false); - tlsos->flush(); - if (tlsos->hasBufferedData()) - vlog.error("Failed to flush remaining socket data on close"); - } - } catch (std::exception& e) { - vlog.error("Failed to flush remaining socket data on close: %s", e.what()); - } - } - - if (session) { - int ret; - // FIXME: We can't currently wait for the response, so we only send - // our close and hope for the best - ret = gnutls_bye(session, GNUTLS_SHUT_WR); - if ((ret != GNUTLS_E_SUCCESS) && (ret != GNUTLS_E_INVALID_SESSION)) - vlog.error("TLS shutdown failed: %s", gnutls_strerror(ret)); - } + if (tlssock) + tlssock->shutdown(); #if defined (SSECURITYTLS__USE_DEPRECATED_DH) if (dh_params) { gnutls_dh_params_deinit(dh_params); - dh_params = 0; + dh_params = nullptr; } #endif @@ -130,13 +113,9 @@ void SSecurityTLS::shutdown() rawos = nullptr; } - if (tlsis) { - delete tlsis; - tlsis = nullptr; - } - if (tlsos) { - delete tlsos; - tlsos = nullptr; + if (tlssock) { + delete tlssock; + tlssock = nullptr; } if (session) { @@ -182,56 +161,46 @@ bool SSecurityTLS::processMsg() os->writeU8(1); os->flush(); - // Create these early as they set up the push/pull functions - // for GnuTLS - tlsis = new rdr::TLSInStream(is, session); - tlsos = new rdr::TLSOutStream(os, session); + tlssock = new rdr::TLSSocket(is, os, session); rawis = is; rawos = os; } - err = gnutls_handshake(session); - if (err != GNUTLS_E_SUCCESS) { - if (!gnutls_error_is_fatal(err)) { - vlog.debug("Deferring completion of TLS handshake: %s", gnutls_strerror(err)); + try { + if (!tlssock->handshake()) return false; - } - vlog.error("TLS Handshake failed: %s", gnutls_strerror (err)); + } catch (std::exception&) { shutdown(); - throw rdr::tls_error("TLS Handshake failed", err); + throw; } vlog.debug("TLS handshake completed with %s", gnutls_session_get_desc(session)); - sc->setStreams(tlsis, tlsos); + sc->setStreams(&tlssock->inStream(), &tlssock->outStream()); return true; } void SSecurityTLS::setParams() { - static const char kx_anon_priority[] = ":+ANON-ECDH:+ANON-DH"; + static const char kx_anon_priority[] = "+ANON-ECDH:+ANON-DH"; int ret; // Custom priority string specified? if (strcmp(Security::GnuTLSPriority, "") != 0) { - char *prio; + std::string prio; const char *err; - prio = new char[strlen(Security::GnuTLSPriority) + - strlen(kx_anon_priority) + 1]; - - strcpy(prio, Security::GnuTLSPriority); - if (anon) - strcat(prio, kx_anon_priority); - - ret = gnutls_priority_set_direct(session, prio, &err); - - delete [] prio; + prio = (const char*)Security::GnuTLSPriority; + if (anon) { + prio += ":"; + prio += kx_anon_priority; + } + ret = gnutls_priority_set_direct(session, prio.c_str(), &err); if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); @@ -241,30 +210,22 @@ void SSecurityTLS::setParams() const char *err; #if GNUTLS_VERSION_NUMBER >= 0x030603 - // gnutls_set_default_priority_appends() expects a normal priority string that - // doesn't start with ":". - ret = gnutls_set_default_priority_append(session, kx_anon_priority + 1, &err, 0); + ret = gnutls_set_default_priority_append(session, kx_anon_priority, &err, 0); if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); throw rdr::tls_error("gnutls_set_default_priority_append()", ret); } #else + std::string prio; + // We don't know what the system default priority is, so we guess // it's what upstream GnuTLS has - static const char gnutls_default_priority[] = "NORMAL"; - char *prio; - - prio = new char[strlen(gnutls_default_priority) + - strlen(kx_anon_priority) + 1]; - - strcpy(prio, gnutls_default_priority); - strcat(prio, kx_anon_priority); - - ret = gnutls_priority_set_direct(session, prio, &err); - - delete [] prio; + prio = "NORMAL"; + prio += ":"; + prio += kx_anon_priority; + ret = gnutls_priority_set_direct(session, prio.c_str(), &err); if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); diff --git a/common/rfb/SSecurityTLS.h b/common/rfb/SSecurityTLS.h index 1dc33cfd..61eec2a8 100644 --- a/common/rfb/SSecurityTLS.h +++ b/common/rfb/SSecurityTLS.h @@ -2,6 +2,7 @@ * Copyright (C) 2004 Red Hat Inc. * Copyright (C) 2005 Martin Koegler * Copyright (C) 2010 TigerVNC Team + * Copyright 2012-2025 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 @@ -26,6 +27,7 @@ #error "This header should not be included without HAVE_GNUTLS defined" #endif +#include <rfb/Security.h> #include <rfb/SSecurity.h> #include <gnutls/gnutls.h> @@ -40,8 +42,7 @@ namespace rdr { class InStream; class OutStream; - class TLSInStream; - class TLSOutStream; + class TLSSocket; } namespace rfb { @@ -54,8 +55,8 @@ namespace rfb { const char* getUserName() const override {return nullptr;} int getType() const override { return anon ? secTypeTLSNone : secTypeX509None;} - static StringParameter X509_CertFile; - static StringParameter X509_KeyFile; + static core::StringParameter X509_CertFile; + static core::StringParameter X509_KeyFile; protected: void shutdown(); @@ -71,8 +72,7 @@ namespace rfb { bool anon; - rdr::TLSInStream* tlsis; - rdr::TLSOutStream* tlsos; + rdr::TLSSocket* tlssock; rdr::InStream* rawis; rdr::OutStream* rawos; diff --git a/common/rfb/SSecurityVeNCrypt.cxx b/common/rfb/SSecurityVeNCrypt.cxx index 4617fddb..757acc06 100644 --- a/common/rfb/SSecurityVeNCrypt.cxx +++ b/common/rfb/SSecurityVeNCrypt.cxx @@ -26,15 +26,20 @@ #include <config.h> #endif +#include <core/LogWriter.h> + +#include <rfb/SConnection.h> +#include <rfb/SecurityServer.h> #include <rfb/SSecurityVeNCrypt.h> #include <rfb/Exception.h> -#include <rfb/LogWriter.h> +#include <rfb/Security.h> + #include <rdr/InStream.h> #include <rdr/OutStream.h> using namespace rfb; -static LogWriter vlog("SVeNCrypt"); +static core::LogWriter vlog("SVeNCrypt"); SSecurityVeNCrypt::SSecurityVeNCrypt(SConnection* sc_, SecurityServer *sec) diff --git a/common/rfb/SSecurityVeNCrypt.h b/common/rfb/SSecurityVeNCrypt.h index ea2bb6fb..534f94a6 100644 --- a/common/rfb/SSecurityVeNCrypt.h +++ b/common/rfb/SSecurityVeNCrypt.h @@ -25,11 +25,13 @@ #ifndef __SSECURITYVENCRYPT_H__ #define __SSECURITYVENCRYPT_H__ -#include <rfb/SSecurityStack.h> -#include <rfb/SConnection.h> +#include <rfb/SSecurity.h> namespace rfb { + class SConnection; + class SecurityServer; + class SSecurityVeNCrypt : public SSecurity { public: SSecurityVeNCrypt(SConnection* sc, SecurityServer *sec); diff --git a/common/rfb/SSecurityVncAuth.cxx b/common/rfb/SSecurityVncAuth.cxx index 22d88079..b267d5a0 100644 --- a/common/rfb/SSecurityVncAuth.cxx +++ b/common/rfb/SSecurityVncAuth.cxx @@ -25,13 +25,17 @@ #include <config.h> #endif +#include <core/Configuration.h> +#include <core/LogWriter.h> + +#include <rdr/OutStream.h> + #include <rfb/SSecurityVncAuth.h> #include <rdr/RandomStream.h> #include <rfb/SConnection.h> -#include <rfb/Configuration.h> -#include <rfb/LogWriter.h> #include <rfb/Exception.h> #include <rfb/obfuscate.h> + #include <assert.h> #include <string.h> #include <stdio.h> @@ -42,12 +46,12 @@ extern "C" { using namespace rfb; -static LogWriter vlog("SVncAuth"); +static core::LogWriter vlog("SVncAuth"); -StringParameter SSecurityVncAuth::vncAuthPasswdFile -("PasswordFile", "Password file for VNC authentication", "", ConfServer); -AliasParameter rfbauth("rfbauth", "Alias for PasswordFile", - &SSecurityVncAuth::vncAuthPasswdFile, ConfServer); +core::StringParameter SSecurityVncAuth::vncAuthPasswdFile +("PasswordFile", "Password file for VNC authentication", ""); +core::AliasParameter rfbauth("rfbauth", "Alias for PasswordFile", + &SSecurityVncAuth::vncAuthPasswdFile); VncAuthPasswdParameter SSecurityVncAuth::vncAuthPasswd ("Password", "Obfuscated binary encoding of the password which clients must supply to " "access the server", &SSecurityVncAuth::vncAuthPasswdFile); @@ -118,8 +122,8 @@ bool SSecurityVncAuth::processMsg() VncAuthPasswdParameter::VncAuthPasswdParameter(const char* name_, const char* desc, - StringParameter* passwdFile_) -: BinaryParameter(name_, desc, nullptr, 0, ConfServer), + core::StringParameter* passwdFile_) +: core::BinaryParameter(name_, desc, nullptr, 0), passwdFile(passwdFile_) { } diff --git a/common/rfb/SSecurityVncAuth.h b/common/rfb/SSecurityVncAuth.h index 532abe0a..e2845337 100644 --- a/common/rfb/SSecurityVncAuth.h +++ b/common/rfb/SSecurityVncAuth.h @@ -26,7 +26,8 @@ #include <stdint.h> -#include <rfb/Configuration.h> +#include <core/Configuration.h> + #include <rfb/SSecurity.h> #include <rfb/Security.h> @@ -41,12 +42,12 @@ namespace rfb { virtual ~VncAuthPasswdGetter() { } }; - class VncAuthPasswdParameter : public VncAuthPasswdGetter, BinaryParameter { + class VncAuthPasswdParameter : public VncAuthPasswdGetter, core::BinaryParameter { public: - VncAuthPasswdParameter(const char* name, const char* desc, StringParameter* passwdFile_); + VncAuthPasswdParameter(const char* name, const char* desc, core::StringParameter* passwdFile_); void getVncAuthPasswd(std::string *password, std::string *readOnlyPassword) override; protected: - StringParameter* passwdFile; + core::StringParameter* passwdFile; }; class SSecurityVncAuth : public SSecurity { @@ -56,7 +57,7 @@ namespace rfb { int getType() const override {return secTypeVncAuth;} const char* getUserName() const override {return nullptr;} AccessRights getAccessRights() const override { return accessRights; } - static StringParameter vncAuthPasswdFile; + static core::StringParameter vncAuthPasswdFile; static VncAuthPasswdParameter vncAuthPasswd; private: bool verifyResponse(const char* password); diff --git a/common/rfb/ScreenSet.h b/common/rfb/ScreenSet.h index fb93e5c2..10753b17 100644 --- a/common/rfb/ScreenSet.h +++ b/common/rfb/ScreenSet.h @@ -25,10 +25,11 @@ #include <string.h> #include <stdint.h> -#include <rfb/Rect.h> #include <list> #include <set> +#include <core/Rect.h> + namespace rfb { // rfb::Screen @@ -52,7 +53,7 @@ namespace rfb { } uint32_t id; - Rect dimensions; + core::Rect dimensions; uint32_t flags; }; @@ -87,7 +88,7 @@ namespace rfb { inline bool validate(int fb_width, int fb_height) const { std::list<Screen>::const_iterator iter; std::set<uint32_t> seen_ids; - Rect fb_rect; + core::Rect fb_rect; if (screens.empty()) return false; diff --git a/common/rfb/Security.cxx b/common/rfb/Security.cxx index 3b0d95bf..1d4124f9 100644 --- a/common/rfb/Security.cxx +++ b/common/rfb/Security.cxx @@ -24,17 +24,19 @@ #include <string.h> #include <algorithm> +#include <stdexcept> + +#include <core/LogWriter.h> +#include <core/string.h> -#include <rfb/LogWriter.h> #include <rfb/Security.h> -#include <rfb/util.h> using namespace rfb; -static LogWriter vlog("Security"); +static core::LogWriter vlog("Security"); #ifdef HAVE_GNUTLS -StringParameter Security::GnuTLSPriority("GnuTLSPriority", +core::StringParameter Security::GnuTLSPriority("GnuTLSPriority", "GnuTLS priority string that controls the TLS session’s handshake algorithms", ""); #endif @@ -43,9 +45,16 @@ Security::Security() { } -Security::Security(StringParameter &secTypes) +Security::Security(core::EnumListParameter &secTypes) { - enabledSecTypes = parseSecTypes(secTypes); + for (core::EnumListEntry type : secTypes) { + uint32_t typeNum = secTypeNum(type.getValueStr().c_str()); + // Should have been filtered by EnumListParameter, but let's have + // a safety net + if (typeNum == secTypeInvalid) + throw std::logic_error("Unknown security type"); + enabledSecTypes.push_back(typeNum); + } } const std::list<uint8_t> Security::GetEnabledSecTypes(void) @@ -179,16 +188,3 @@ const char* rfb::secTypeName(uint32_t num) default: return "[unknown secType]"; } } - -std::list<uint32_t> rfb::parseSecTypes(const char* types_) -{ - std::list<uint32_t> result; - std::vector<std::string> types; - types = split(types_, ','); - for (size_t i = 0; i < types.size(); i++) { - uint32_t typeNum = secTypeNum(types[i].c_str()); - if (typeNum != secTypeInvalid) - result.push_back(typeNum); - } - return result; -} diff --git a/common/rfb/Security.h b/common/rfb/Security.h index 430a1d89..40f54c36 100644 --- a/common/rfb/Security.h +++ b/common/rfb/Security.h @@ -24,11 +24,15 @@ #include <stdint.h> -#include <rfb/Configuration.h> - #include <list> +namespace core { + class EnumListParameter; + class StringParameter; +} + namespace rfb { + const uint8_t secTypeInvalid = 0; const uint8_t secTypeNone = 1; const uint8_t secTypeVncAuth = 2; @@ -76,7 +80,7 @@ namespace rfb { * Create Security instance. */ Security(); - Security(StringParameter &secTypes); + Security(core::EnumListParameter& secTypes); /* * Note about security types. @@ -105,7 +109,7 @@ namespace rfb { char *ToString(void); #ifdef HAVE_GNUTLS - static StringParameter GnuTLSPriority; + static core::StringParameter GnuTLSPriority; #endif private: @@ -114,7 +118,7 @@ namespace rfb { const char* secTypeName(uint32_t num); uint32_t secTypeNum(const char* name); - std::list<uint32_t> parseSecTypes(const char* types); + } #endif diff --git a/common/rfb/SecurityClient.cxx b/common/rfb/SecurityClient.cxx index 027d47df..d71941b5 100644 --- a/common/rfb/SecurityClient.cxx +++ b/common/rfb/SecurityClient.cxx @@ -25,12 +25,15 @@ #include <stdexcept> +#include <core/Configuration.h> + #include <rfb/CSecurityNone.h> #include <rfb/CSecurityStack.h> #include <rfb/CSecurityVeNCrypt.h> #include <rfb/CSecurityVncAuth.h> #include <rfb/CSecurityPlain.h> #include <rfb/Security.h> +#include <rfb/SecurityClient.h> #ifdef HAVE_GNUTLS #include <rfb/CSecurityTLS.h> #endif @@ -42,7 +45,7 @@ using namespace rfb; -StringParameter SecurityClient::secTypes +core::EnumListParameter SecurityClient::secTypes ("SecurityTypes", "Specify which security scheme to use (None, VncAuth, Plain" #ifdef HAVE_GNUTLS @@ -52,14 +55,22 @@ StringParameter SecurityClient::secTypes ", RA2, RA2ne, RA2_256, RA2ne_256, DH, MSLogonII" #endif ")", + { "None", "VncAuth", "Plain", +#ifdef HAVE_GNUTLS + "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain", +#endif +#ifdef HAVE_NETTLE + "RA2", "RA2ne", "RA2_256", "RA2ne_256", "DH", "MSLogonII", +#endif + }, + { "None", "VncAuth", "Plain", #ifdef HAVE_GNUTLS - "X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone," + "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain", #endif #ifdef HAVE_NETTLE - "RA2,RA2_256,RA2ne,RA2ne_256,DH,MSLogonII," + "RA2", "RA2ne", "RA2_256", "RA2ne_256", "DH", "MSLogonII", #endif - "VncAuth,None", -ConfViewer); + }); CSecurity* SecurityClient::GetCSecurity(CConnection* cc, uint32_t secType) { diff --git a/common/rfb/SecurityClient.h b/common/rfb/SecurityClient.h index b86fcb35..11fea417 100644 --- a/common/rfb/SecurityClient.h +++ b/common/rfb/SecurityClient.h @@ -22,12 +22,13 @@ #ifndef __RFB_SECURITYCLIENT_H__ #define __RFB_SECURITYCLIENT_H__ -#include <rfb/Configuration.h> #include <rfb/Security.h> -#include <rfb/CSecurity.h> namespace rfb { + class CConnection; + class CSecurity; + class SecurityClient : public Security { public: SecurityClient(void) : Security(secTypes) {} @@ -35,7 +36,7 @@ namespace rfb { /* Create client side CSecurity class instance */ CSecurity* GetCSecurity(CConnection* cc, uint32_t secType); - static StringParameter secTypes; + static core::EnumListParameter secTypes; }; } diff --git a/common/rfb/SecurityServer.cxx b/common/rfb/SecurityServer.cxx index d692f4fc..207e70f8 100644 --- a/common/rfb/SecurityServer.cxx +++ b/common/rfb/SecurityServer.cxx @@ -21,7 +21,11 @@ #include <config.h> #endif +#include <stdexcept> + #include <rfb/Security.h> +#include <rfb/SecurityServer.h> + #include <rfb/SSecurityNone.h> #include <rfb/SSecurityStack.h> #include <rfb/SSecurityPlain.h> @@ -36,7 +40,7 @@ using namespace rfb; -StringParameter SecurityServer::secTypes +core::EnumListParameter SecurityServer::secTypes ("SecurityTypes", "Specify which security scheme to use (None, VncAuth, Plain" #ifdef HAVE_GNUTLS @@ -46,11 +50,19 @@ StringParameter SecurityServer::secTypes ", RA2, RA2ne, RA2_256, RA2ne_256" #endif ")", + { "None", "VncAuth", "Plain", +#ifdef HAVE_GNUTLS + "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain", +#endif +#ifdef HAVE_NETTLE + "RA2", "RA2ne", "RA2_256", "RA2ne_256", +#endif + }, + { #ifdef HAVE_GNUTLS - "TLSVnc," + "TLSVnc", #endif - "VncAuth", -ConfServer); + "VncAuth"}); SSecurity* SecurityServer::GetSSecurity(SConnection* sc, uint32_t secType) { diff --git a/common/rfb/SecurityServer.h b/common/rfb/SecurityServer.h index a51ee23c..0239b36d 100644 --- a/common/rfb/SecurityServer.h +++ b/common/rfb/SecurityServer.h @@ -20,7 +20,6 @@ #ifndef __RFB_SECURITYSERVER_H__ #define __RFB_SECURITYSERVER_H__ -#include <rfb/Configuration.h> #include <rfb/Security.h> namespace rfb { @@ -35,7 +34,7 @@ namespace rfb { /* Create server side SSecurity class instance */ SSecurity* GetSSecurity(SConnection* sc, uint32_t secType); - static StringParameter secTypes; + static core::EnumListParameter secTypes; }; } diff --git a/common/rfb/ServerCore.cxx b/common/rfb/ServerCore.cxx index 1a80dc0c..302dad71 100644 --- a/common/rfb/ServerCore.cxx +++ b/common/rfb/ServerCore.cxx @@ -28,74 +28,74 @@ #include <string.h> #include <rfb/ServerCore.h> -rfb::IntParameter rfb::Server::idleTimeout +core::IntParameter rfb::Server::idleTimeout ("IdleTimeout", "The number of seconds after which an idle VNC connection will be dropped " "(zero means no timeout)", - 0, 0); -rfb::IntParameter rfb::Server::maxDisconnectionTime + 0, 0, INT_MAX); +core::IntParameter rfb::Server::maxDisconnectionTime ("MaxDisconnectionTime", "Terminate when no client has been connected for s seconds", - 0, 0); -rfb::IntParameter rfb::Server::maxConnectionTime + 0, 0, INT_MAX); +core::IntParameter rfb::Server::maxConnectionTime ("MaxConnectionTime", "Terminate when a client has been connected for s seconds", - 0, 0); -rfb::IntParameter rfb::Server::maxIdleTime + 0, 0, INT_MAX); +core::IntParameter rfb::Server::maxIdleTime ("MaxIdleTime", "Terminate after s seconds of user inactivity", - 0, 0); -rfb::IntParameter rfb::Server::compareFB + 0, 0, INT_MAX); +core::IntParameter rfb::Server::compareFB ("CompareFB", "Perform pixel comparison on framebuffer to reduce unnecessary updates " "(0: never, 1: always, 2: auto)", - 2); -rfb::IntParameter rfb::Server::frameRate + 2, 0, 2); +core::IntParameter rfb::Server::frameRate ("FrameRate", "The maximum number of updates per second sent to each client", - 60); -rfb::BoolParameter rfb::Server::protocol3_3 + 60, 0, INT_MAX); +core::BoolParameter rfb::Server::protocol3_3 ("Protocol3.3", "Always use protocol version 3.3 for backwards compatibility with " "badly-behaved clients", false); -rfb::BoolParameter rfb::Server::alwaysShared +core::BoolParameter rfb::Server::alwaysShared ("AlwaysShared", "Always treat incoming connections as shared, regardless of the client-" "specified setting", false); -rfb::BoolParameter rfb::Server::neverShared +core::BoolParameter rfb::Server::neverShared ("NeverShared", "Never treat incoming connections as shared, regardless of the client-" "specified setting", false); -rfb::BoolParameter rfb::Server::disconnectClients +core::BoolParameter rfb::Server::disconnectClients ("DisconnectClients", "Disconnect existing clients if an incoming connection is non-shared. " "If combined with NeverShared then new connections will be refused " "while there is a client active", true); -rfb::BoolParameter rfb::Server::acceptKeyEvents +core::BoolParameter rfb::Server::acceptKeyEvents ("AcceptKeyEvents", "Accept key press and release events from clients.", true); -rfb::BoolParameter rfb::Server::acceptPointerEvents +core::BoolParameter rfb::Server::acceptPointerEvents ("AcceptPointerEvents", "Accept pointer movement and button events from clients.", true); -rfb::BoolParameter rfb::Server::acceptCutText +core::BoolParameter rfb::Server::acceptCutText ("AcceptCutText", "Accept clipboard updates from clients.", true); -rfb::BoolParameter rfb::Server::sendCutText +core::BoolParameter rfb::Server::sendCutText ("SendCutText", "Send clipboard changes to clients.", true); -rfb::BoolParameter rfb::Server::acceptSetDesktopSize +core::BoolParameter rfb::Server::acceptSetDesktopSize ("AcceptSetDesktopSize", "Accept set desktop size events from clients.", true); -rfb::BoolParameter rfb::Server::queryConnect +core::BoolParameter rfb::Server::queryConnect ("QueryConnect", "Prompt the local user to accept or reject incoming connections.", false); diff --git a/common/rfb/ServerCore.h b/common/rfb/ServerCore.h index 69cad39f..a7c7f309 100644 --- a/common/rfb/ServerCore.h +++ b/common/rfb/ServerCore.h @@ -24,29 +24,29 @@ #ifndef __RFB_SERVER_CORE_H__ #define __RFB_SERVER_CORE_H__ -#include <rfb/Configuration.h> +#include <core/Configuration.h> namespace rfb { class Server { public: - static IntParameter idleTimeout; - static IntParameter maxDisconnectionTime; - static IntParameter maxConnectionTime; - static IntParameter maxIdleTime; - static IntParameter compareFB; - static IntParameter frameRate; - static BoolParameter protocol3_3; - static BoolParameter alwaysShared; - static BoolParameter neverShared; - static BoolParameter disconnectClients; - static BoolParameter acceptKeyEvents; - static BoolParameter acceptPointerEvents; - static BoolParameter acceptCutText; - static BoolParameter sendCutText; - static BoolParameter acceptSetDesktopSize; - static BoolParameter queryConnect; + static core::IntParameter idleTimeout; + static core::IntParameter maxDisconnectionTime; + static core::IntParameter maxConnectionTime; + static core::IntParameter maxIdleTime; + static core::IntParameter compareFB; + static core::IntParameter frameRate; + static core::BoolParameter protocol3_3; + static core::BoolParameter alwaysShared; + static core::BoolParameter neverShared; + static core::BoolParameter disconnectClients; + static core::BoolParameter acceptKeyEvents; + static core::BoolParameter acceptPointerEvents; + static core::BoolParameter acceptCutText; + static core::BoolParameter sendCutText; + static core::BoolParameter acceptSetDesktopSize; + static core::BoolParameter queryConnect; }; diff --git a/common/rfb/ServerParams.cxx b/common/rfb/ServerParams.cxx index b7432b8f..4b8f6136 100644 --- a/common/rfb/ServerParams.cxx +++ b/common/rfb/ServerParams.cxx @@ -24,12 +24,18 @@ #include <stdexcept> +#include <core/LogWriter.h> +#include <core/string.h> + #include <rfb/ledStates.h> +#include <rfb/Cursor.h> +#include <rfb/ScreenSet.h> #include <rfb/ServerParams.h> -#include <rfb/util.h> using namespace rfb; +static core::LogWriter vlog("ServerParams"); + ServerParams::ServerParams() : majorVersion(0), minorVersion(0), supportsQEMUKeyEvent(false), @@ -40,7 +46,11 @@ ServerParams::ServerParams() { setName(""); - cursor_ = new Cursor(0, 0, Point(), nullptr); + screenLayout_ = new ScreenSet(); + + pf_ = new PixelFormat(); + + cursor_ = new Cursor(0, 0, {}, nullptr); clipFlags = 0; memset(clipSizes, 0, sizeof(clipSizes)); @@ -60,17 +70,25 @@ void ServerParams::setDimensions(int width, int height) void ServerParams::setDimensions(int width, int height, const ScreenSet& layout) { - if (!layout.validate(width, height)) + if (!layout.validate(width, height)) { + char buffer[2048]; + vlog.debug("Invalid screen layout for %dx%d:", width, height); + layout.print(buffer, sizeof(buffer)); + vlog.debug("%s", buffer); + throw std::invalid_argument("Attempted to configure an invalid screen layout"); + } width_ = width; height_ = height; - screenLayout_ = layout; + delete screenLayout_; + screenLayout_ = new ScreenSet(layout); } void ServerParams::setPF(const PixelFormat& pf) { - pf_ = pf; + delete pf_; + pf_ = new PixelFormat(pf); if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32) throw std::invalid_argument("setPF: Not 8, 16 or 32 bpp?"); @@ -101,7 +119,8 @@ uint32_t ServerParams::clipboardSize(unsigned int format) const return clipSizes[i]; } - throw std::invalid_argument(rfb::format("Invalid clipboard format 0x%x", format)); + throw std::invalid_argument( + core::format("Invalid clipboard format 0x%x", format)); } void ServerParams::setClipboardCaps(uint32_t flags, const uint32_t* lengths) diff --git a/common/rfb/ServerParams.h b/common/rfb/ServerParams.h index d730b891..6be9acd6 100644 --- a/common/rfb/ServerParams.h +++ b/common/rfb/ServerParams.h @@ -25,12 +25,12 @@ #include <string> -#include <rfb/Cursor.h> -#include <rfb/PixelFormat.h> -#include <rfb/ScreenSet.h> - namespace rfb { + class Cursor; + class PixelFormat; + struct ScreenSet; + class ServerParams { public: ServerParams(); @@ -55,11 +55,11 @@ namespace rfb { int width() const { return width_; } int height() const { return height_; } - const ScreenSet& screenLayout() const { return screenLayout_; } + 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_; } + const PixelFormat& pf() const { return *pf_; } void setPF(const PixelFormat& pf); const char* name() const { return name_.c_str(); } @@ -85,9 +85,9 @@ namespace rfb { int width_; int height_; - ScreenSet screenLayout_; + ScreenSet* screenLayout_; - PixelFormat pf_; + PixelFormat* pf_; std::string name_; Cursor* cursor_; unsigned int ledState_; diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx index a26c0bfe..da0d5865 100644 --- a/common/rfb/TightDecoder.cxx +++ b/common/rfb/TightDecoder.cxx @@ -27,16 +27,18 @@ #include <vector> +#include <core/string.h> + #include <rdr/InStream.h> #include <rdr/MemInStream.h> #include <rdr/OutStream.h> #include <rfb/ServerParams.h> #include <rfb/Exception.h> +#include <rfb/JpegDecompressor.h> #include <rfb/PixelBuffer.h> #include <rfb/TightConstants.h> #include <rfb/TightDecoder.h> -#include <rfb/util.h> using namespace rfb; @@ -51,7 +53,7 @@ TightDecoder::~TightDecoder() { } -bool TightDecoder::readRect(const Rect& r, rdr::InStream* is, +bool TightDecoder::readRect(const core::Rect& r, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os) { uint8_t comp_ctl; @@ -111,7 +113,8 @@ bool TightDecoder::readRect(const Rect& r, rdr::InStream* is, int palSize = 0; if (r.width() > TIGHT_MAX_WIDTH) - throw protocol_error(format("TightDecoder: Too large rectangle (%d pixels)", r.width())); + throw protocol_error(core::format( + "TightDecoder: Too large rectangle (%d pixels)", r.width())); // Possible palette if ((comp_ctl & tightExplicitFilter) != 0) { @@ -192,10 +195,10 @@ bool TightDecoder::readRect(const Rect& r, rdr::InStream* is, return true; } -bool TightDecoder::doRectsConflict(const Rect& /*rectA*/, +bool TightDecoder::doRectsConflict(const core::Rect& /*rectA*/, const uint8_t* bufferA, size_t buflenA, - const Rect& /*rectB*/, + const core::Rect& /*rectB*/, const uint8_t* bufferB, size_t buflenB, const ServerParams& /*server*/) @@ -220,7 +223,7 @@ bool TightDecoder::doRectsConflict(const Rect& /*rectA*/, return false; } -void TightDecoder::decodeRect(const Rect& r, const uint8_t* buffer, +void TightDecoder::decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) { @@ -506,7 +509,7 @@ uint32_t TightDecoder::readCompact(rdr::InStream* is) void TightDecoder::FilterGradient24(const uint8_t *inbuf, const PixelFormat& pf, uint32_t* outbuf, - int stride, const Rect& r) + int stride, const core::Rect& r) { int x, y, c; uint8_t prevRow[TIGHT_MAX_WIDTH*3]; @@ -552,7 +555,7 @@ TightDecoder::FilterGradient24(const uint8_t *inbuf, template<class T> void TightDecoder::FilterGradient(const uint8_t* inbuf, const PixelFormat& pf, T* outbuf, - int stride, const Rect& r) + int stride, const core::Rect& r) { int x, y, c; static uint8_t prevRow[TIGHT_MAX_WIDTH*3]; @@ -606,7 +609,7 @@ void TightDecoder::FilterGradient(const uint8_t* inbuf, template<class T> void TightDecoder::FilterPalette(const T* palette, int palSize, const uint8_t* inbuf, T* outbuf, - int stride, const Rect& r) + int stride, const core::Rect& r) { // Indexed color int x, h = r.height(), w = r.width(), b, pad = stride - w; diff --git a/common/rfb/TightDecoder.h b/common/rfb/TightDecoder.h index d569a7fd..a75fc7da 100644 --- a/common/rfb/TightDecoder.h +++ b/common/rfb/TightDecoder.h @@ -22,7 +22,6 @@ #include <rdr/ZlibInStream.h> #include <rfb/Decoder.h> -#include <rfb/JpegDecompressor.h> namespace rfb { @@ -31,15 +30,15 @@ namespace rfb { public: TightDecoder(); virtual ~TightDecoder(); - bool readRect(const Rect& r, rdr::InStream* is, + bool readRect(const core::Rect& r, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os) override; - bool doRectsConflict(const Rect& rectA, + bool doRectsConflict(const core::Rect& rectA, const uint8_t* bufferA, size_t buflenA, - const Rect& rectB, + const core::Rect& rectB, const uint8_t* bufferB, size_t buflenB, const ServerParams& server) override; - void decodeRect(const Rect& r, const uint8_t* buffer, + void decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) override; @@ -47,16 +46,16 @@ namespace rfb { uint32_t readCompact(rdr::InStream* is); void FilterGradient24(const uint8_t* inbuf, const PixelFormat& pf, - uint32_t* outbuf, int stride, const Rect& r); + uint32_t* outbuf, int stride, const core::Rect& r); template<class T> void FilterGradient(const uint8_t* inbuf, const PixelFormat& pf, - T* outbuf, int stride, const Rect& r); + T* outbuf, int stride, const core::Rect& r); template<class T> void FilterPalette(const T* palette, int palSize, const uint8_t* inbuf, T* outbuf, - int stride, const Rect& r); + int stride, const core::Rect& r); private: rdr::ZlibInStream zis[4]; diff --git a/common/rfb/Timer.cxx b/common/rfb/Timer.cxx deleted file mode 100644 index 6f7ec7ba..00000000 --- a/common/rfb/Timer.cxx +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2016-2024 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. - */ - -// -=- Timer.cxx - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <sys/time.h> - -#include <algorithm> - -#include <rfb/Timer.h> -#include <rfb/util.h> -#include <rfb/LogWriter.h> - -using namespace rfb; - -#ifndef __NO_DEFINE_VLOG__ -static LogWriter vlog("Timer"); -#endif - - -// Millisecond timeout processing helper functions - -inline static timeval addMillis(timeval inTime, int millis) { - int secs = millis / 1000; - millis = millis % 1000; - inTime.tv_sec += secs; - inTime.tv_usec += millis * 1000; - if (inTime.tv_usec >= 1000000) { - inTime.tv_sec++; - inTime.tv_usec -= 1000000; - } - return inTime; -} - -inline static int diffTimeMillis(timeval later, timeval earlier) { - long udiff; - udiff = ((later.tv_sec - earlier.tv_sec) * 1000000) + - (later.tv_usec - earlier.tv_usec); - return (udiff + 999) / 1000; -} - -std::list<Timer*> Timer::pending; - -int Timer::checkTimeouts() { - timeval start; - - if (pending.empty()) - return -1; - - gettimeofday(&start, nullptr); - while (pending.front()->isBefore(start)) { - Timer* timer; - - timer = pending.front(); - pending.pop_front(); - - timer->lastDueTime = timer->dueTime; - timer->cb->handleTimeout(timer); - - if (pending.empty()) - return -1; - } - return getNextTimeout(); -} - -int Timer::getNextTimeout() { - timeval now; - gettimeofday(&now, nullptr); - - if (pending.empty()) - return -1; - - int toWait = pending.front()->getRemainingMs(); - - if (toWait > pending.front()->timeoutMs) { - if (toWait - pending.front()->timeoutMs < 1000) { - vlog.info("gettimeofday is broken..."); - return toWait; - } - // Time has jumped backwards! - vlog.info("Time has moved backwards!"); - pending.front()->dueTime = now; - toWait = 0; - } - - return toWait; -} - -void Timer::insertTimer(Timer* t) { - std::list<Timer*>::iterator i; - for (i=pending.begin(); i!=pending.end(); i++) { - if (t->isBefore((*i)->dueTime)) { - pending.insert(i, t); - return; - } - } - pending.push_back(t); -} - -void Timer::start(int timeoutMs_) { - timeval now; - gettimeofday(&now, nullptr); - stop(); - timeoutMs = timeoutMs_; - dueTime = addMillis(now, timeoutMs); - insertTimer(this); -} - -void Timer::repeat(int timeoutMs_) { - timeval now; - - gettimeofday(&now, nullptr); - - if (isStarted()) { - vlog.error("Incorrectly repeating already running timer"); - stop(); - } - - if (msBetween(&lastDueTime, &dueTime) != 0) - vlog.error("Timer incorrectly modified whilst repeating"); - - if (timeoutMs_ != -1) - timeoutMs = timeoutMs_; - - dueTime = addMillis(lastDueTime, timeoutMs); - if (isBefore(now)) { - // Time has jumped forwards, or we're not getting enough - // CPU time for the timers - dueTime = now; - } - - insertTimer(this); -} - -void Timer::stop() { - pending.remove(this); -} - -bool Timer::isStarted() { - return std::find(pending.begin(), pending.end(), - this) != pending.end(); -} - -int Timer::getTimeoutMs() { - return timeoutMs; -} - -int Timer::getRemainingMs() { - timeval now; - gettimeofday(&now, nullptr); - return __rfbmax(0, diffTimeMillis(dueTime, now)); -} - -bool Timer::isBefore(timeval other) { - return (dueTime.tv_sec < other.tv_sec) || - ((dueTime.tv_sec == other.tv_sec) && - (dueTime.tv_usec < other.tv_usec)); -} diff --git a/common/rfb/Timer.h b/common/rfb/Timer.h deleted file mode 100644 index 362cb84e..00000000 --- a/common/rfb/Timer.h +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2018-2024 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. - */ - -#ifndef __RFB_TIMER_H__ -#define __RFB_TIMER_H__ - -#include <list> -#include <sys/time.h> - -namespace rfb { - - /* Timer - - Cross-platform timeout handling. The caller creates instances of - Timer and passes a Callback implementation to each. The Callback - will then be called with a pointer to the Timer instance that - timed-out when the timeout occurs. - - The static methods of Timer are used by the main loop of the - application both to dispatch elapsed Timer callbacks and to - determine how long to wait in select() for the next timeout to - occur. - - For classes that can be derived it's best to use MethodTimer which - can call a specific method on the class, thus avoiding conflicts - when subclassing. - */ - - struct Timer { - - struct Callback { - // handleTimeout - // Passed a pointer to the Timer that has timed out. If the - // handler returns true then the Timer is reset and left - // running, causing another timeout after the appropriate - // interval. - // If the handler returns false then the Timer is cancelled. - virtual void handleTimeout(Timer* t) = 0; - - virtual ~Callback() {} - }; - - // checkTimeouts() - // Dispatches any elapsed Timers, and returns the number of - // milliseconds until the next Timer will timeout. - static int checkTimeouts(); - - // getNextTimeout() - // Returns the number of milliseconds until the next timeout, - // without dispatching any elapsed Timers. - static int getNextTimeout(); - - // Create a Timer with the specified callback handler - Timer(Callback* cb_) {cb = cb_;} - ~Timer() {stop();} - - // start() - // Starts the timer, causing a timeout after the specified number - // of milliseconds. If the timer is already active then it will - // be implicitly cancelled and re-started. - void start(int timeoutMs_); - - // repeat() - // Restarts the timer in a way that repeats that last timeout. - // This allows you to have a periodic timer without the risk of - // accumulating drift caused by processing delays. - // A new interval can be specified, otherwise the previous - // interval is reused. - void repeat(int timeoutMs_=-1); - - // stop() - // Cancels the timer. - void stop(); - - // isStarted() - // Determines whether the timer is started. - bool isStarted(); - - // getTimeoutMs() - // Determines the previously used timeout value, if any. - // Usually used with isStarted() to get the _current_ timeout. - int getTimeoutMs(); - - // getRemainingMs() - // Determines how many milliseconds are left before the Timer - // will timeout. Only valid for an active timer. - int getRemainingMs(); - - // isBefore() - // Determine whether the Timer will timeout before the specified - // time. - bool isBefore(timeval other); - - protected: - timeval dueTime, lastDueTime; - int timeoutMs; - Callback* cb; - - static void insertTimer(Timer* t); - // The list of currently active Timers, ordered by time left until - // timeout. - static std::list<Timer*> pending; - }; - - template<class T> class MethodTimer - : public Timer, public Timer::Callback { - public: - MethodTimer(T* obj_, void (T::*cb_)(Timer*)) - : Timer(this), obj(obj_), cb(cb_) {} - - void handleTimeout(Timer* t) override { return (obj->*cb)(t); } - - private: - T* obj; - void (T::*cb)(Timer*); - }; - -}; - -#endif diff --git a/common/rfb/UnixPasswordValidator.cxx b/common/rfb/UnixPasswordValidator.cxx index 57fa9b39..8239463a 100644 --- a/common/rfb/UnixPasswordValidator.cxx +++ b/common/rfb/UnixPasswordValidator.cxx @@ -22,24 +22,119 @@ #include <config.h> #endif -#include <rfb/Configuration.h> -#include <rfb/Exception.h> +#include <assert.h> +#include <string.h> +#include <security/pam_appl.h> + +#include <core/Configuration.h> +#include <core/LogWriter.h> + #include <rfb/UnixPasswordValidator.h> -#include <rfb/pam.h> using namespace rfb; -static StringParameter pamService +static core::LogWriter vlog("UnixPasswordValidator"); + +static core::StringParameter pamService ("PAMService", "Service name for PAM password validation", "vnc"); -AliasParameter pam_service("pam_service", "Alias for PAMService", - &pamService); +core::AliasParameter pam_service("pam_service", "Alias for PAMService", + &pamService); -int do_pam_auth(const char *service, const char *username, - const char *password); +std::string UnixPasswordValidator::displayName; -bool UnixPasswordValidator::validateInternal(SConnection * /*sc*/, +typedef struct +{ + const char *username; + const char *password; + std::string &msg; +} AuthData; + +#if defined(__sun) +static int pam_callback(int count, struct pam_message **in, + struct pam_response **out, void *ptr) +#else +static int pam_callback(int count, const struct pam_message **in, + struct pam_response **out, void *ptr) +#endif +{ + int i; + AuthData *auth = (AuthData *) ptr; + struct pam_response *resp = + (struct pam_response *) malloc (sizeof (struct pam_response) * count); + + if (!resp && count) + return PAM_CONV_ERR; + + for (i = 0; i < count; i++) { + resp[i].resp_retcode = PAM_SUCCESS; + switch (in[i]->msg_style) { + case PAM_TEXT_INFO: + vlog.info("%s info: %s", (const char *) pamService, in[i]->msg); + auth->msg = in[i]->msg; + resp[i].resp = nullptr; + break; + case PAM_ERROR_MSG: + vlog.error("%s error: %s", (const char *) pamService, in[i]->msg); + auth->msg = in[i]->msg; + resp[i].resp = nullptr; + break; + case PAM_PROMPT_ECHO_ON: /* Send Username */ + resp[i].resp = strdup(auth->username); + break; + case PAM_PROMPT_ECHO_OFF: /* Send Password */ + resp[i].resp = strdup(auth->password); + break; + default: + free(resp); + return PAM_CONV_ERR; + } + } + + *out = resp; + return PAM_SUCCESS; +} + +bool UnixPasswordValidator::validateInternal(SConnection * /* sc */, const char *username, - const char *password) + const char *password, + std::string &msg) { - return do_pam_auth(pamService, username, password); + int ret; + AuthData auth = { username, password, msg }; + struct pam_conv conv = { + pam_callback, + &auth + }; + pam_handle_t *pamh = nullptr; + ret = pam_start(pamService, username, &conv, &pamh); + if (ret != PAM_SUCCESS) { + /* Can't call pam_strerror() here because the content of pamh undefined */ + vlog.error("pam_start(%s) failed: %d", (const char *) pamService, ret); + return false; + } +#ifdef PAM_XDISPLAY + /* At this point, displayName should never be empty */ + assert(displayName.length() > 0); + /* Pass the display name to PAM modules but PAM_XDISPLAY may not be + * recognized by modules built with old versions of PAM */ + ret = pam_set_item(pamh, PAM_XDISPLAY, displayName.c_str()); + if (ret != PAM_SUCCESS && ret != PAM_BAD_ITEM) { + vlog.error("pam_set_item(PAM_XDISPLAY) failed: %d (%s)", ret, pam_strerror(pamh, ret)); + goto error; + } +#endif + ret = pam_authenticate(pamh, 0); + if (ret != PAM_SUCCESS) { + vlog.error("pam_authenticate() failed: %d (%s)", ret, pam_strerror(pamh, ret)); + goto error; + } + ret = pam_acct_mgmt(pamh, 0); + if (ret != PAM_SUCCESS) { + vlog.error("pam_acct_mgmt() failed: %d (%s)", ret, pam_strerror(pamh, ret)); + goto error; + } + return true; +error: + pam_end(pamh, ret); + return false; } diff --git a/common/rfb/UnixPasswordValidator.h b/common/rfb/UnixPasswordValidator.h index 4d623d6c..a2cc89c5 100644 --- a/common/rfb/UnixPasswordValidator.h +++ b/common/rfb/UnixPasswordValidator.h @@ -26,9 +26,19 @@ namespace rfb { class UnixPasswordValidator: public PasswordValidator { + public: + static void setDisplayName(const std::string& display) { + displayName = display; + } + protected: - bool validateInternal(SConnection * sc, const char *username, - const char *password) override; + bool validateInternal(SConnection *sc, + const char *username, + const char *password, + std::string &msg) override; + + private: + static std::string displayName; }; } diff --git a/common/rfb/UpdateTracker.cxx b/common/rfb/UpdateTracker.cxx index 7c97a6b8..1aedf491 100644 --- a/common/rfb/UpdateTracker.cxx +++ b/common/rfb/UpdateTracker.cxx @@ -25,27 +25,31 @@ #include <config.h> #endif +#include <core/LogWriter.h> + #include <rfb/UpdateTracker.h> -#include <rfb/LogWriter.h> using namespace rfb; -static LogWriter vlog("UpdateTracker"); +static core::LogWriter vlog("UpdateTracker"); // -=- ClippingUpdateTracker -void ClippingUpdateTracker::add_changed(const Region ®ion) { +void ClippingUpdateTracker::add_changed(const core::Region& region) +{ ut->add_changed(region.intersect(clipRect)); } -void ClippingUpdateTracker::add_copied(const Region &dest, const Point &delta) { +void ClippingUpdateTracker::add_copied(const core::Region& dest, + const core::Point& delta) +{ // Clip the destination to the display area - Region clipdest = dest.intersect(clipRect); + core::Region clipdest = dest.intersect(clipRect); if (clipdest.is_empty()) return; // Clip the source to the screen - Region tmp = clipdest; + core::Region tmp = clipdest; tmp.translate(delta.negate()); tmp.assign_intersect(clipRect); if (!tmp.is_empty()) { @@ -70,25 +74,28 @@ SimpleUpdateTracker::SimpleUpdateTracker() { SimpleUpdateTracker::~SimpleUpdateTracker() { } -void SimpleUpdateTracker::add_changed(const Region ®ion) { +void SimpleUpdateTracker::add_changed(const core::Region& region) +{ changed.assign_union(region); } -void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) { +void SimpleUpdateTracker::add_copied(const core::Region& dest, + const core::Point& delta) +{ // Is there anything to do? if (dest.is_empty()) return; // Calculate whether any of this copy can be treated as a continuation // of an earlier one - Region src = dest; + core::Region src = dest; src.translate(delta.negate()); - Region overlap = src.intersect(copied); + core::Region overlap = src.intersect(copied); if (overlap.is_empty()) { // There is no overlap - Rect newbr = dest.get_bounding_rect(); - Rect oldbr = copied.get_bounding_rect(); + core::Rect newbr = dest.get_bounding_rect(); + core::Rect oldbr = copied.get_bounding_rect(); if (oldbr.area() > newbr.area()) { // Old copyrect is (probably) bigger - use it changed.assign_union(dest); @@ -97,7 +104,7 @@ void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) { // Use the new one // But be careful not to copy stuff that still needs // to be updated. - Region invalid_src = src.intersect(changed); + core::Region invalid_src = src.intersect(changed); invalid_src.translate(delta); changed.assign_union(invalid_src); changed.assign_union(copied); @@ -107,13 +114,13 @@ void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) { return; } - Region invalid_src = overlap.intersect(changed); + core::Region invalid_src = overlap.intersect(changed); invalid_src.translate(delta); changed.assign_union(invalid_src); overlap.translate(delta); - Region nonoverlapped_copied = dest.union_(copied).subtract(overlap); + core::Region nonoverlapped_copied = dest.union_(copied).subtract(overlap); changed.assign_union(nonoverlapped_copied); copied = overlap; @@ -122,12 +129,14 @@ void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) { return; } -void SimpleUpdateTracker::subtract(const Region& region) { +void SimpleUpdateTracker::subtract(const core::Region& region) +{ copied.assign_subtract(region); changed.assign_subtract(region); } -void SimpleUpdateTracker::getUpdateInfo(UpdateInfo* info, const Region& clip) +void SimpleUpdateTracker::getUpdateInfo(UpdateInfo* info, + const core::Region& clip) { copied.assign_subtract(changed); info->changed = changed.intersect(clip); diff --git a/common/rfb/UpdateTracker.h b/common/rfb/UpdateTracker.h index e91b9621..3d7a2fcd 100644 --- a/common/rfb/UpdateTracker.h +++ b/common/rfb/UpdateTracker.h @@ -19,17 +19,16 @@ #ifndef __RFB_UPDATETRACKER_INCLUDED__ #define __RFB_UPDATETRACKER_INCLUDED__ -#include <rfb/Rect.h> -#include <rfb/Region.h> -#include <rfb/PixelBuffer.h> +#include <core/Rect.h> +#include <core/Region.h> namespace rfb { class UpdateInfo { public: - Region changed; - Region copied; - Point copy_delta; + core::Region changed; + core::Region copied; + core::Point copy_delta; bool is_empty() const { return copied.is_empty() && changed.is_empty(); } @@ -47,23 +46,25 @@ namespace rfb { UpdateTracker() {}; virtual ~UpdateTracker() {}; - virtual void add_changed(const Region ®ion) = 0; - virtual void add_copied(const Region &dest, const Point &delta) = 0; + virtual void add_changed(const core::Region& region) = 0; + virtual void add_copied(const core::Region& dest, + const core::Point& delta) = 0; }; class ClippingUpdateTracker : public UpdateTracker { public: ClippingUpdateTracker() : ut(nullptr) {} - ClippingUpdateTracker(UpdateTracker* ut_, const Rect& r=Rect()) : ut(ut_), clipRect(r) {} + ClippingUpdateTracker(UpdateTracker* ut_, const core::Rect& r={}) : ut(ut_), clipRect(r) {} void setUpdateTracker(UpdateTracker* ut_) {ut = ut_;} - void setClipRect(const Rect& cr) {clipRect = cr;} + void setClipRect(const core::Rect& cr) {clipRect = cr;} - void add_changed(const Region ®ion) override; - void add_copied(const Region &dest, const Point &delta) override; + void add_changed(const core::Region& region) override; + void add_copied(const core::Region& dest, + const core::Point& delta) override; protected: UpdateTracker* ut; - Rect clipRect; + core::Rect clipRect; }; class SimpleUpdateTracker : public UpdateTracker { @@ -71,27 +72,29 @@ namespace rfb { SimpleUpdateTracker(); virtual ~SimpleUpdateTracker(); - void add_changed(const Region ®ion) override; - void add_copied(const Region &dest, const Point &delta) override; - virtual void subtract(const Region& region); + void add_changed(const core::Region& region) override; + void add_copied(const core::Region& dest, + const core::Point& delta) override; + virtual void subtract(const core::Region& region); // Fill the supplied UpdateInfo structure with update information // FIXME: Provide getUpdateInfo() with no clipping, for better efficiency. - virtual void getUpdateInfo(UpdateInfo* info, const Region& cliprgn); + virtual void getUpdateInfo(UpdateInfo* info, + const core::Region& cliprgn); // Copy the contained updates to another tracker virtual void copyTo(UpdateTracker* to) const; // Move the entire update region by an offset - void translate(const Point& p) {changed.translate(p); copied.translate(p);} + void translate(const core::Point& p) {changed.translate(p); copied.translate(p);} virtual bool is_empty() const {return changed.is_empty() && copied.is_empty();} virtual void clear() {changed.clear(); copied.clear();}; protected: - Region changed; - Region copied; - Point copy_delta; + core::Region changed; + core::Region copied; + core::Point copy_delta; }; } diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index a354f636..2d77fae6 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -22,7 +22,12 @@ #include <config.h> #endif -#include <rdr/Exception.h> +#include <core/LogWriter.h> +#include <core/string.h> +#include <core/time.h> + +#include <rdr/FdInStream.h> +#include <rdr/FdOutStream.h> #include <network/TcpSocket.h> @@ -31,12 +36,12 @@ #include <rfb/Exception.h> #include <rfb/KeyRemapper.h> #include <rfb/KeysymStr.h> -#include <rfb/LogWriter.h> #include <rfb/Security.h> #include <rfb/ServerCore.h> #include <rfb/SMsgWriter.h> #include <rfb/VNCServerST.h> #include <rfb/VNCSConnectionST.h> +#include <rfb/encodings.h> #include <rfb/screenTypes.h> #include <rfb/fenceTypes.h> #include <rfb/ledStates.h> @@ -44,13 +49,12 @@ #define XK_MISCELLANY #define XK_XKB_KEYS #include <rfb/keysymdef.h> -#include <rfb/util.h> using namespace rfb; -static LogWriter vlog("VNCSConnST"); +static core::LogWriter vlog("VNCSConnST"); -static Cursor emptyCursor(0, 0, Point(0, 0), nullptr); +static Cursor emptyCursor(0, 0, {0, 0}, nullptr); VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s, bool reverse, AccessRights ar) @@ -71,9 +75,9 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s, if (rfb::Server::idleTimeout) { // minimum of 15 seconds while authenticating if (rfb::Server::idleTimeout < 15) - idleTimer.start(secsToMillis(15)); + idleTimer.start(core::secsToMillis(15)); else - idleTimer.start(secsToMillis(rfb::Server::idleTimeout)); + idleTimer.start(core::secsToMillis(rfb::Server::idleTimeout)); } } @@ -216,11 +220,11 @@ void VNCSConnectionST::pixelBufferChange() //updates.intersect(server->pb->getRect()); // //if (server->pb->width() > client.width()) - // updates.add_changed(Rect(client.width(), 0, server->pb->width(), - // server->pb->height())); + // updates.add_changed({client.width(), 0, server->pb->width(), + // server->pb->height()}); //if (server->pb->height() > client.height()) - // updates.add_changed(Rect(0, client.height(), client.width(), - // server->pb->height())); + // updates.add_changed({0, client.height(), client.width(), + // server->pb->height()}); damagedCursorRegion.assign_intersect(server->getPixelBuffer()->getRect()); @@ -236,7 +240,7 @@ void VNCSConnectionST::pixelBufferChange() } // Drop any lossy tracking that is now outside the framebuffer - encodeManager.pruneLosslessRefresh(Region(server->getPixelBuffer()->getRect())); + encodeManager.pruneLosslessRefresh(server->getPixelBuffer()->getRect()); } // Just update the whole screen at the moment because we're too lazy to // work out what's actually changed. @@ -310,8 +314,6 @@ void VNCSConnectionST::requestClipboardOrClose() { try { if (state() != RFBSTATE_NORMAL) return; - if (!accessCheck(AccessCutText)) return; - if (!rfb::Server::acceptCutText) return; requestClipboard(); } catch(std::exception& e) { close(e.what()); @@ -322,8 +324,6 @@ void VNCSConnectionST::announceClipboardOrClose(bool available) { try { if (state() != RFBSTATE_NORMAL) return; - if (!accessCheck(AccessCutText)) return; - if (!rfb::Server::sendCutText) return; announceClipboard(available); } catch(std::exception& e) { close(e.what()); @@ -334,8 +334,6 @@ void VNCSConnectionST::sendClipboardDataOrClose(const char* data) { try { if (state() != RFBSTATE_NORMAL) return; - if (!accessCheck(AccessCutText)) return; - if (!rfb::Server::sendCutText) return; sendClipboardData(data); } catch(std::exception& e) { close(e.what()); @@ -421,7 +419,7 @@ void VNCSConnectionST::approveConnectionOrClose(bool accept, void VNCSConnectionST::authSuccess() { if (rfb::Server::idleTimeout) - idleTimer.start(secsToMillis(rfb::Server::idleTimeout)); + idleTimer.start(core::secsToMillis(rfb::Server::idleTimeout)); // - Set the connection parameters appropriately client.setDimensions(server->getPixelBuffer()->width(), @@ -448,7 +446,7 @@ void VNCSConnectionST::queryConnection(const char* userName) void VNCSConnectionST::clientInit(bool shared) { if (rfb::Server::idleTimeout) - idleTimer.start(secsToMillis(rfb::Server::idleTimeout)); + idleTimer.start(core::secsToMillis(rfb::Server::idleTimeout)); if (rfb::Server::alwaysShared || reverseConnection) shared = true; if (!accessCheck(AccessNonShared)) shared = true; if (rfb::Server::neverShared) shared = false; @@ -463,15 +461,16 @@ void VNCSConnectionST::setPixelFormat(const PixelFormat& pf) pf.print(buffer, 256); vlog.info("Client pixel format %s", buffer); setCursor(); + encodeManager.forceRefresh(server->getPixelBuffer()->getRect()); } -void VNCSConnectionST::pointerEvent(const Point& pos, uint16_t buttonMask) +void VNCSConnectionST::pointerEvent(const core::Point& pos, + uint16_t buttonMask) { if (rfb::Server::idleTimeout) - idleTimer.start(secsToMillis(rfb::Server::idleTimeout)); + idleTimer.start(core::secsToMillis(rfb::Server::idleTimeout)); pointerEventTime = time(nullptr); if (!accessCheck(AccessPtrEvents)) return; - if (!rfb::Server::acceptPointerEvents) return; pointerEventPos = pos; server->pointerEvent(this, pointerEventPos, buttonMask); } @@ -502,8 +501,10 @@ void VNCSConnectionST::keyEvent(uint32_t keysym, uint32_t keycode, bool down) { uint32_t lookup; if (rfb::Server::idleTimeout) - idleTimer.start(secsToMillis(rfb::Server::idleTimeout)); + idleTimer.start(core::secsToMillis(rfb::Server::idleTimeout)); if (!accessCheck(AccessKeyEvents)) return; + // FIXME: This check isn't strictly needed, but we get a lot of + // confusing debug logging without it if (!rfb::Server::acceptKeyEvents) return; if (down) @@ -605,27 +606,28 @@ void VNCSConnectionST::keyEvent(uint32_t keysym, uint32_t keycode, bool down) { server->keyEvent(keysym, keycode, down); } -void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental) +void VNCSConnectionST::framebufferUpdateRequest(const core::Rect& r, + bool incremental) { - Rect safeRect; + core::Rect safeRect; if (!accessCheck(AccessView)) return; SConnection::framebufferUpdateRequest(r, incremental); // Check that the client isn't sending crappy requests - if (!r.enclosed_by(Rect(0, 0, client.width(), client.height()))) { + if (!r.enclosed_by({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, client.width(), client.height()); - safeRect = r.intersect(Rect(0, 0, client.width(), client.height())); + safeRect = r.intersect({0, 0, client.width(), client.height()}); } else { safeRect = r; } // Just update the requested region. // Framebuffer update will be sent a bit later, see processMessages(). - Region reqRgn(safeRect); + core::Region reqRgn(safeRect); if (!incremental || !continuousUpdates) requested.assign_union(reqRgn); @@ -656,8 +658,7 @@ void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height, layout.print(buffer, sizeof(buffer)); vlog.debug("%s", buffer); - if (!accessCheck(AccessSetDesktopSize) || - !rfb::Server::acceptSetDesktopSize) { + if (!accessCheck(AccessSetDesktopSize)) { vlog.debug("Rejecting unauthorized framebuffer resize request"); result = resultProhibited; } else { @@ -716,7 +717,10 @@ void VNCSConnectionST::fence(uint32_t flags, unsigned len, const uint8_t data[]) void VNCSConnectionST::enableContinuousUpdates(bool enable, int x, int y, int w, int h) { - Rect rect; + core::Rect rect; + + if (!accessCheck(AccessView)) + return; if (!client.supportsFence() || !client.supportsContinuousUpdates()) throw protocol_error("Client tried to enable continuous updates when not allowed"); @@ -735,21 +739,16 @@ void VNCSConnectionST::enableContinuousUpdates(bool enable, void VNCSConnectionST::handleClipboardRequest() { - if (!accessCheck(AccessCutText)) return; server->handleClipboardRequest(this); } void VNCSConnectionST::handleClipboardAnnounce(bool available) { - if (!accessCheck(AccessCutText)) return; - if (!rfb::Server::acceptCutText) return; server->handleClipboardAnnounce(this, available); } void VNCSConnectionST::handleClipboardData(const char* data) { - if (!accessCheck(AccessCutText)) return; - if (!rfb::Server::acceptCutText) return; server->handleClipboardData(this, data); } @@ -790,7 +789,7 @@ void VNCSConnectionST::supportsLEDState() writer()->writeLEDState(); } -void VNCSConnectionST::handleTimeout(Timer* t) +void VNCSConnectionST::handleTimeout(core::Timer* t) { try { if ((t == &congestionTimer) || @@ -921,7 +920,7 @@ void VNCSConnectionST::writeNoDataUpdate() void VNCSConnectionST::writeDataUpdate() { - Region req; + core::Region req; UpdateInfo ui; bool needNewUpdateInfo; const RenderedCursor *cursor; @@ -946,7 +945,7 @@ void VNCSConnectionST::writeDataUpdate() // destination will be wrong, so add it to the changed region. if (!ui.copied.is_empty() && !damagedCursorRegion.is_empty()) { - Region bogusCopiedCursor; + core::Region bogusCopiedCursor; bogusCopiedCursor = damagedCursorRegion; bogusCopiedCursor.translate(ui.copy_delta); @@ -993,7 +992,7 @@ void VNCSConnectionST::writeDataUpdate() cursor = nullptr; if (needRenderedCursor()) { - Rect renderedCursorRect; + core::Rect renderedCursorRect; cursor = server->getRenderedCursor(); renderedCursorRect = cursor->getEffectiveRect(); @@ -1033,7 +1032,7 @@ void VNCSConnectionST::writeDataUpdate() void VNCSConnectionST::writeLosslessRefresh() { - Region req, pending; + core::Region req, pending; const RenderedCursor *cursor; int nextRefresh, nextUpdate; diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index 17de9d01..b618923f 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -29,16 +29,17 @@ #include <map> +#include <core/Timer.h> + #include <rfb/Congestion.h> #include <rfb/EncodeManager.h> #include <rfb/SConnection.h> -#include <rfb/Timer.h> namespace rfb { class VNCServerST; class VNCSConnectionST : private SConnection, - public Timer::Callback { + public core::Timer::Callback { public: VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse, AccessRights ar); @@ -108,8 +109,8 @@ namespace rfb { // Change tracking - void add_changed(const Region& region) { updates.add_changed(region); } - void add_copied(const Region& dest, const Point& delta) { + void add_changed(const core::Region& region) { updates.add_changed(region); } + void add_copied(const core::Region& dest, const core::Point& delta) { updates.add_copied(dest, delta); } @@ -123,10 +124,11 @@ namespace rfb { void queryConnection(const char* userName) override; void clientInit(bool shared) override; void setPixelFormat(const PixelFormat& pf) override; - void pointerEvent(const Point& pos, uint16_t buttonMask) override; + void pointerEvent(const core::Point& pos, + uint16_t buttonMask) override; void keyEvent(uint32_t keysym, uint32_t keycode, bool down) override; - void framebufferUpdateRequest(const Rect& r, + void framebufferUpdateRequest(const core::Rect& r, bool incremental) override; void setDesktopSize(int fb_width, int fb_height, const ScreenSet& layout) override; @@ -143,7 +145,7 @@ namespace rfb { void supportsLEDState() override; // Timer callbacks - void handleTimeout(Timer* t) override; + void handleTimeout(core::Timer* t) override; // Internal methods @@ -180,24 +182,24 @@ namespace rfb { uint8_t *fenceData; Congestion congestion; - Timer congestionTimer; - Timer losslessTimer; + core::Timer congestionTimer; + core::Timer losslessTimer; VNCServerST* server; SimpleUpdateTracker updates; - Region requested; + core::Region requested; bool updateRenderedCursor, removeRenderedCursor; - Region damagedCursorRegion; + core::Region damagedCursorRegion; bool continuousUpdates; - Region cuRegion; + core::Region cuRegion; EncodeManager encodeManager; std::map<uint32_t, uint32_t> pressedKeys; - Timer idleTimer; + core::Timer idleTimer; time_t pointerEventTime; - Point pointerEventPos; + core::Point pointerEventPos; bool clientHasCursor; std::string closeReason; diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h index 4e3a5b23..4d9b31ed 100644 --- a/common/rfb/VNCServer.h +++ b/common/rfb/VNCServer.h @@ -23,14 +23,19 @@ #ifndef __RFB_VNCSERVER_H__ #define __RFB_VNCSERVER_H__ +#include <list> + +#include <rfb/AccessRights.h> #include <rfb/UpdateTracker.h> -#include <rfb/SSecurity.h> -#include <rfb/ScreenSet.h> namespace network { class Socket; } namespace rfb { + class PixelBuffer; + class SConnection; + struct ScreenSet; + class VNCServer : public UpdateTracker { public: // addSocket() tells the server to serve the Socket. The caller @@ -128,13 +133,14 @@ namespace rfb { // setCursor() tells the server that the cursor has changed. The // cursorData argument contains width*height rgba quadruplets with // non-premultiplied alpha. - virtual void setCursor(int width, int height, const Point& hotspot, + virtual void setCursor(int width, int height, + const core::Point& hotspot, const uint8_t* cursorData) = 0; // setCursorPos() tells the server the current position of the cursor, and // whether the server initiated that change (e.g. through another X11 // client calling XWarpPointer()). - virtual void setCursorPos(const Point& p, bool warped) = 0; + virtual void setCursorPos(const core::Point& p, bool warped) = 0; // setName() tells the server what desktop title to supply to clients virtual void setName(const char* name) = 0; diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index b99d33b0..77d652b9 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -55,24 +55,28 @@ #include <assert.h> #include <stdlib.h> +#include <core/LogWriter.h> +#include <core/time.h> + +#include <rdr/FdOutStream.h> + #include <network/Socket.h> #include <rfb/ComparingUpdateTracker.h> #include <rfb/KeyRemapper.h> #include <rfb/KeysymStr.h> -#include <rfb/LogWriter.h> +#include <rfb/SDesktop.h> #include <rfb/Security.h> #include <rfb/ServerCore.h> #include <rfb/VNCServerST.h> #include <rfb/VNCSConnectionST.h> -#include <rfb/util.h> #include <rfb/ledStates.h> using namespace rfb; -static LogWriter slog("VNCServerST"); -static LogWriter connectionsLog("Connections"); +static core::LogWriter slog("VNCServerST"); +static core::LogWriter connectionsLog("Connections"); // // -=- VNCServerST Implementation @@ -85,7 +89,7 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) blockCounter(0), pb(nullptr), ledState(ledUnknown), name(name_), pointerClient(nullptr), clipboardClient(nullptr), pointerClientTime(0), - comparer(nullptr), cursor(new Cursor(0, 0, Point(), nullptr)), + comparer(nullptr), cursor(new Cursor(0, 0, {}, nullptr)), renderedCursorInvalid(false), keyRemapper(&KeyRemapper::defInstance), idleTimer(this), disconnectTimer(this), connectTimer(this), @@ -97,9 +101,9 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) // FIXME: Do we really want to kick off these right away? if (rfb::Server::maxIdleTime) - idleTimer.start(secsToMillis(rfb::Server::maxIdleTime)); + idleTimer.start(core::secsToMillis(rfb::Server::maxIdleTime)); if (rfb::Server::maxDisconnectionTime) - disconnectTimer.start(secsToMillis(rfb::Server::maxDisconnectionTime)); + disconnectTimer.start(core::secsToMillis(rfb::Server::maxDisconnectionTime)); } VNCServerST::~VNCServerST() @@ -161,12 +165,18 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing, AccessRights a // Adjust the exit timers if (rfb::Server::maxConnectionTime && clients.empty()) - connectTimer.start(secsToMillis(rfb::Server::maxConnectionTime)); + connectTimer.start(core::secsToMillis(rfb::Server::maxConnectionTime)); disconnectTimer.stop(); - VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing, accessRights); - clients.push_front(client); - client->init(); + try { + VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing, accessRights); + clients.push_front(client); + client->init(); + } catch (std::exception& e) { + connectionsLog.error("Error accepting client: %s", e.what()); + sock->shutdown(); + closingSockets.push_back(sock); + } } void VNCServerST::removeSocket(network::Socket* sock) { @@ -203,7 +213,7 @@ void VNCServerST::removeSocket(network::Socket* sock) { // Adjust the exit timers connectTimer.stop(); if (rfb::Server::maxDisconnectionTime && clients.empty()) - disconnectTimer.start(secsToMillis(rfb::Server::maxDisconnectionTime)); + disconnectTimer.start(core::secsToMillis(rfb::Server::maxDisconnectionTime)); return; } @@ -313,7 +323,7 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_) // Check that the screen layout is still valid if (pb_ && !layout.validate(pb_->width(), pb_->height())) { - Rect fbRect; + core::Rect fbRect; ScreenSet::iterator iter, iter_next; fbRect.setXYWH(0, 0, pb_->width(), pb_->height()); @@ -354,6 +364,9 @@ void VNCServerST::setScreenLayout(const ScreenSet& layout) void VNCServerST::requestClipboard() { + if (!rfb::Server::acceptCutText) + return; + if (clipboardClient == nullptr) { slog.debug("Got request for client clipboard but no client currently owns the clipboard"); return; @@ -368,6 +381,9 @@ void VNCServerST::announceClipboard(bool available) clipboardRequestors.clear(); + if (!rfb::Server::sendCutText) + return; + for (ci = clients.begin(); ci != clients.end(); ++ci) (*ci)->announceClipboardOrClose(available); } @@ -376,6 +392,9 @@ void VNCServerST::sendClipboardData(const char* data) { std::list<VNCSConnectionST*>::iterator ci; + if (!rfb::Server::sendCutText) + return; + if (strchr(data, '\r') != nullptr) throw std::invalid_argument("Invalid carriage return in clipboard data"); @@ -401,7 +420,7 @@ void VNCServerST::setName(const char* name_) (*ci)->setDesktopNameOrClose(name_); } -void VNCServerST::add_changed(const Region& region) +void VNCServerST::add_changed(const core::Region& region) { if (comparer == nullptr) return; @@ -410,7 +429,8 @@ void VNCServerST::add_changed(const Region& region) startFrameClock(); } -void VNCServerST::add_copied(const Region& dest, const Point& delta) +void VNCServerST::add_copied(const core::Region& dest, + const core::Point& delta) { if (comparer == nullptr) return; @@ -419,7 +439,8 @@ void VNCServerST::add_copied(const Region& dest, const Point& delta) startFrameClock(); } -void VNCServerST::setCursor(int width, int height, const Point& newHotspot, +void VNCServerST::setCursor(int width, int height, + const core::Point& newHotspot, const uint8_t* data) { delete cursor; @@ -435,7 +456,7 @@ void VNCServerST::setCursor(int width, int height, const Point& newHotspot, } } -void VNCServerST::setCursorPos(const Point& pos, bool warped) +void VNCServerST::setCursorPos(const core::Point& pos, bool warped) { if (cursorPos != pos) { cursorPos = pos; @@ -466,8 +487,11 @@ void VNCServerST::setLEDState(unsigned int state) void VNCServerST::keyEvent(uint32_t keysym, uint32_t keycode, bool down) { + if (!rfb::Server::acceptKeyEvents) + return; + if (rfb::Server::maxIdleTime) - idleTimer.start(secsToMillis(rfb::Server::maxIdleTime)); + idleTimer.start(core::secsToMillis(rfb::Server::maxIdleTime)); // Remap the key if required if (keyRemapper) { @@ -484,11 +508,16 @@ void VNCServerST::keyEvent(uint32_t keysym, uint32_t keycode, bool down) } void VNCServerST::pointerEvent(VNCSConnectionST* client, - const Point& pos, uint16_t buttonMask) + const core::Point& pos, + uint16_t buttonMask) { time_t now = time(nullptr); + + if (!rfb::Server::acceptPointerEvents) + return; + if (rfb::Server::maxIdleTime) - idleTimer.start(secsToMillis(rfb::Server::maxIdleTime)); + idleTimer.start(core::secsToMillis(rfb::Server::maxIdleTime)); // Let one client own the cursor whilst buttons are pressed in order // to provide a bit more sane user experience. But limit the time to @@ -516,9 +545,11 @@ void VNCServerST::handleClipboardRequest(VNCSConnectionST* client) void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client, bool available) { - if (available) + if (available) { + if (!rfb::Server::acceptCutText) + return; clipboardClient = client; - else { + } else { if (client != clipboardClient) return; clipboardClient = nullptr; @@ -529,6 +560,8 @@ void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client, void VNCServerST::handleClipboardData(VNCSConnectionST* client, const char* data) { + if (!rfb::Server::acceptCutText) + return; if (client != clipboardClient) { slog.debug("Ignoring unexpected clipboard data"); return; @@ -543,6 +576,11 @@ unsigned int VNCServerST::setDesktopSize(VNCSConnectionST* requester, unsigned int result; std::list<VNCSConnectionST*>::iterator ci; + if (!rfb::Server::acceptSetDesktopSize) { + slog.debug("Rejecting unauthorized framebuffer resize request"); + return resultProhibited; + } + // We can't handle a framebuffer larger than this, so don't let a // client set one (see PixelBuffer.cxx) if ((fb_width > 16384) || (fb_height > 16384)) { @@ -622,7 +660,7 @@ SConnection* VNCServerST::getConnection(network::Socket* sock) { return nullptr; } -void VNCServerST::handleTimeout(Timer* t) +void VNCServerST::handleTimeout(core::Timer* t) { if (t == &frameTimer) { int timeout; @@ -822,7 +860,7 @@ int VNCServerST::msToNextUpdate() void VNCServerST::writeUpdate() { UpdateInfo ui; - Region toCheck; + core::Region toCheck; std::list<VNCSConnectionST*>::iterator ci; @@ -834,9 +872,9 @@ void VNCServerST::writeUpdate() toCheck = ui.changed.union_(ui.copied); if (needRenderedCursor()) { - Rect clippedCursorRect = Rect(0, 0, cursor->width(), cursor->height()) - .translate(cursorPos.subtract(cursor->hotspot())) - .intersect(pb->getRect()); + core::Rect clippedCursorRect = core::Rect(0, 0, cursor->width(), cursor->height()) + .translate(cursorPos.subtract(cursor->hotspot())) + .intersect(pb->getRect()); if (!toCheck.intersect(clippedCursorRect).is_empty()) renderedCursorInvalid = true; @@ -864,7 +902,7 @@ void VNCServerST::writeUpdate() // checkUpdate() is called by clients to see if it is safe to read from // the framebuffer at this time. -Region VNCServerST::getPendingRegion() +core::Region VNCServerST::getPendingRegion() { UpdateInfo ui; @@ -876,7 +914,7 @@ Region VNCServerST::getPendingRegion() // Block client from updating if there are pending updates if (comparer->is_empty()) - return Region(); + return {}; comparer->getUpdateInfo(&ui, pb->getRect()); diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index dc4f9aad..5db4513a 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -26,11 +26,11 @@ #include <sys/time.h> -#include <rfb/SDesktop.h> +#include <core/Timer.h> + #include <rfb/VNCServer.h> #include <rfb/Blacklist.h> #include <rfb/Cursor.h> -#include <rfb/Timer.h> #include <rfb/ScreenSet.h> namespace rfb { @@ -40,9 +40,10 @@ namespace rfb { class ListConnInfo; class PixelBuffer; class KeyRemapper; + class SDesktop; class VNCServerST : public VNCServer, - public Timer::Callback { + public core::Timer::Callback { public: // -=- Constructors @@ -95,11 +96,12 @@ namespace rfb { void closeClients(const char* reason) override {closeClients(reason, nullptr);} SConnection* getConnection(network::Socket* sock) override; - void add_changed(const Region ®ion) override; - void add_copied(const Region &dest, const Point &delta) override; - void setCursor(int width, int height, const Point& hotspot, + void add_changed(const core::Region& region) override; + void add_copied(const core::Region& dest, + const core::Point& delta) override; + void setCursor(int width, int height, const core::Point& hotspot, const uint8_t* data) override; - void setCursorPos(const Point& p, bool warped) override; + void setCursorPos(const core::Point& p, bool warped) override; void setName(const char* name_) override; void setLEDState(unsigned state) override; @@ -111,13 +113,14 @@ namespace rfb { const ScreenSet& getScreenLayout() const { return screenLayout; } const Cursor* getCursor() const { return cursor; } - const Point& getCursorPos() const { return cursorPos; } + const core::Point& getCursorPos() const { return cursorPos; } const char* getName() const { return name.c_str(); } unsigned getLEDState() const { return ledState; } // Event handlers void keyEvent(uint32_t keysym, uint32_t keycode, bool down); - void pointerEvent(VNCSConnectionST* client, const Point& pos, uint16_t buttonMask); + void pointerEvent(VNCSConnectionST* client, + const core::Point& pos, uint16_t buttonMask); void handleClipboardRequest(VNCSConnectionST* client); void handleClipboardAnnounce(VNCSConnectionST* client, bool available); @@ -146,7 +149,7 @@ namespace rfb { // Part of the framebuffer that has been modified but is not yet // ready to be sent to clients - Region getPendingRegion(); + core::Region getPendingRegion(); // getRenderedCursor() returns an up to date version of the server // side rendered cursor buffer @@ -155,7 +158,7 @@ namespace rfb { protected: // Timer callbacks - void handleTimeout(Timer* t) override; + void handleTimeout(core::Timer* t) override; // - Internal methods @@ -195,19 +198,19 @@ namespace rfb { ComparingUpdateTracker* comparer; - Point cursorPos; + core::Point cursorPos; Cursor* cursor; RenderedCursor renderedCursor; bool renderedCursorInvalid; KeyRemapper* keyRemapper; - Timer idleTimer; - Timer disconnectTimer; - Timer connectTimer; + core::Timer idleTimer; + core::Timer disconnectTimer; + core::Timer connectTimer; uint64_t msc, queuedMsc; - Timer frameTimer; + core::Timer frameTimer; }; }; diff --git a/common/rfb/WinPasswdValidator.cxx b/common/rfb/WinPasswdValidator.cxx index 84832e81..a6281950 100644 --- a/common/rfb/WinPasswdValidator.cxx +++ b/common/rfb/WinPasswdValidator.cxx @@ -30,7 +30,8 @@ using namespace rfb; // This method will only work for Windows NT, 2000, and XP (and possibly Vista) bool WinPasswdValidator::validateInternal(rfb::SConnection* /*sc*/, const char* username, - const char* password) + const char* password, + std::string & /* msg */) { HANDLE handle; diff --git a/common/rfb/WinPasswdValidator.h b/common/rfb/WinPasswdValidator.h index 340a6234..993cafea 100644 --- a/common/rfb/WinPasswdValidator.h +++ b/common/rfb/WinPasswdValidator.h @@ -21,6 +21,7 @@ #ifndef __RFB_WINPASSWDVALIDATOR_H__ #define __RFB_WINPASSWDVALIDATOR_H__ +#include <string> #include <rfb/SSecurityPlain.h> namespace rfb @@ -30,7 +31,10 @@ namespace rfb WinPasswdValidator() {}; virtual ~WinPasswdValidator() {}; protected: - bool validateInternal(SConnection *sc, const char* username, const char* password) override; + bool validateInternal(SConnection *sc, + const char *username, + const char *password, + std::string &msg) override; }; } diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx index 633d1c36..845bf4dc 100644 --- a/common/rfb/ZRLEDecoder.cxx +++ b/common/rfb/ZRLEDecoder.cxx @@ -21,6 +21,8 @@ #include <config.h> #endif +#include <algorithm> + #include <rdr/InStream.h> #include <rdr/MemInStream.h> #include <rdr/OutStream.h> @@ -75,7 +77,7 @@ ZRLEDecoder::~ZRLEDecoder() { } -bool ZRLEDecoder::readRect(const Rect& /*r*/, rdr::InStream* is, +bool ZRLEDecoder::readRect(const core::Rect& /*r*/, rdr::InStream* is, const ServerParams& /*server*/, rdr::OutStream* os) { @@ -99,7 +101,7 @@ bool ZRLEDecoder::readRect(const Rect& /*r*/, rdr::InStream* is, return true; } -void ZRLEDecoder::decodeRect(const Rect& r, const uint8_t* buffer, +void ZRLEDecoder::decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) { @@ -113,13 +115,13 @@ void ZRLEDecoder::decodeRect(const Rect& r, const uint8_t* buffer, } template<class T> -void ZRLEDecoder::zrleDecode(const Rect& r, rdr::InStream* is, +void ZRLEDecoder::zrleDecode(const core::Rect& r, rdr::InStream* is, const PixelFormat& pf, ModifiablePixelBuffer* pb) { int length = is->readU32(); zis.setUnderlying(is, length); - Rect t; + core::Rect t; T buf[64 * 64]; Pixel maxPixel = pf.pixelFromRGB((uint16_t)-1, (uint16_t)-1, (uint16_t)-1); @@ -134,11 +136,11 @@ void ZRLEDecoder::zrleDecode(const Rect& r, rdr::InStream* is, for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) { - t.br.y = __rfbmin(r.br.y, t.tl.y + 64); + t.br.y = std::min(r.br.y, t.tl.y + 64); for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) { - t.br.x = __rfbmin(r.br.x, t.tl.x + 64); + t.br.x = std::min(r.br.x, t.tl.x + 64); zlibHasData(&zis, 1); int mode = zis.readU8(); diff --git a/common/rfb/ZRLEDecoder.h b/common/rfb/ZRLEDecoder.h index facf0adc..b9ebf771 100644 --- a/common/rfb/ZRLEDecoder.h +++ b/common/rfb/ZRLEDecoder.h @@ -30,16 +30,16 @@ namespace rfb { public: ZRLEDecoder(); virtual ~ZRLEDecoder(); - bool readRect(const Rect& r, rdr::InStream* is, + bool readRect(const core::Rect& r, rdr::InStream* is, const ServerParams& server, rdr::OutStream* os) override; - void decodeRect(const Rect& r, const uint8_t* buffer, + void decodeRect(const core::Rect& r, const uint8_t* buffer, size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) override; private: template<class T> - void zrleDecode(const Rect& r, rdr::InStream* is, + void zrleDecode(const core::Rect& r, rdr::InStream* is, const PixelFormat& pf, ModifiablePixelBuffer* pb); private: diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx index 1e2c6ef4..1908d7e3 100644 --- a/common/rfb/ZRLEEncoder.cxx +++ b/common/rfb/ZRLEEncoder.cxx @@ -21,20 +21,23 @@ #include <config.h> #endif +#include <core/Configuration.h> +#include <core/LogWriter.h> + #include <rdr/OutStream.h> -#include <rfb/Exception.h> #include <rfb/encodings.h> #include <rfb/Palette.h> +#include <rfb/PixelBuffer.h> #include <rfb/SConnection.h> #include <rfb/ZRLEEncoder.h> -#include <rfb/Configuration.h> -#include <rfb/LogWriter.h> using namespace rfb; -static LogWriter vlog("ZRLEEncoder"); +static core::LogWriter vlog("ZRLEEncoder"); -IntParameter zlibLevel("ZlibLevel","[DEPRECATED] Zlib compression level",-1); +core::IntParameter zlibLevel("ZlibLevel", + "[DEPRECATED] Zlib compression level", + -1, -1, -1); ZRLEEncoder::ZRLEEncoder(SConnection* conn_) : Encoder(conn_, encodingZRLE, EncoderPlain, 127), @@ -66,7 +69,7 @@ void ZRLEEncoder::setCompressLevel(int level) void ZRLEEncoder::writeRect(const PixelBuffer* pb, const Palette& palette) { int x, y; - Rect tile; + core::Rect tile; rdr::OutStream* os; @@ -132,7 +135,8 @@ void ZRLEEncoder::writeSolidRect(int width, int height, mos.clear(); } -void ZRLEEncoder::writePaletteTile(const Rect& tile, const PixelBuffer* pb, +void ZRLEEncoder::writePaletteTile(const core::Rect& tile, + const PixelBuffer* pb, const Palette& palette) { const uint8_t* buffer; @@ -158,7 +162,8 @@ void ZRLEEncoder::writePaletteTile(const Rect& tile, const PixelBuffer* pb, } } -void ZRLEEncoder::writePaletteRLETile(const Rect& tile, const PixelBuffer* pb, +void ZRLEEncoder::writePaletteRLETile(const core::Rect& tile, + const PixelBuffer* pb, const Palette& palette) { const uint8_t* buffer; @@ -184,7 +189,8 @@ void ZRLEEncoder::writePaletteRLETile(const Rect& tile, const PixelBuffer* pb, } } -void ZRLEEncoder::writeRawTile(const Rect& tile, const PixelBuffer* pb) +void ZRLEEncoder::writeRawTile(const core::Rect& tile, + const PixelBuffer* pb) { const uint8_t* buffer; int stride; diff --git a/common/rfb/ZRLEEncoder.h b/common/rfb/ZRLEEncoder.h index 87d87e94..3be81ba3 100644 --- a/common/rfb/ZRLEEncoder.h +++ b/common/rfb/ZRLEEncoder.h @@ -40,11 +40,13 @@ namespace rfb { const uint8_t* colour) override; protected: - void writePaletteTile(const Rect& tile, const PixelBuffer* pb, + void writePaletteTile(const core::Rect& tile, + const PixelBuffer* pb, const Palette& palette); - void writePaletteRLETile(const Rect& tile, const PixelBuffer* pb, + void writePaletteRLETile(const core::Rect& tile, + const PixelBuffer* pb, const Palette& palette); - void writeRawTile(const Rect& tile, const PixelBuffer* pb); + void writeRawTile(const core::Rect& tile, const PixelBuffer* pb); void writePalette(const PixelFormat& pf, const Palette& palette); diff --git a/common/rfb/pam.c b/common/rfb/pam.c deleted file mode 100644 index f9e5ce74..00000000 --- a/common/rfb/pam.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2006 Martin Koegler - * Copyright (C) 2010 TigerVNC Team - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <string.h> -#include <security/pam_appl.h> - -#include <rfb/pam.h> - -typedef struct -{ - const char *username; - const char *password; -} AuthData; - -#if defined(__sun) -static int pam_callback(int count, struct pam_message **in, - struct pam_response **out, void *ptr) -#else -static int pam_callback(int count, const struct pam_message **in, - struct pam_response **out, void *ptr) -#endif -{ - int i; - AuthData *auth = (AuthData *) ptr; - struct pam_response *resp = - (struct pam_response *) malloc (sizeof (struct pam_response) * count); - - if (!resp && count) - return PAM_CONV_ERR; - - for (i = 0; i < count; i++) { - resp[i].resp_retcode = PAM_SUCCESS; - switch (in[i]->msg_style) { - case PAM_TEXT_INFO: - case PAM_ERROR_MSG: - resp[i].resp = 0; - break; - case PAM_PROMPT_ECHO_ON: /* Send Username */ - resp[i].resp = strdup(auth->username); - break; - case PAM_PROMPT_ECHO_OFF: /* Send Password */ - resp[i].resp = strdup(auth->password); - break; - default: - free(resp); - return PAM_CONV_ERR; - } - } - - *out = resp; - return PAM_SUCCESS; -} - - -int do_pam_auth(const char *service, const char *username, const char *password) -{ - int ret; - AuthData auth = { username, password }; - struct pam_conv conv = { - pam_callback, - &auth - }; - pam_handle_t *h = 0; - ret = pam_start(service, username, &conv, &h); - if (ret == PAM_SUCCESS) - ret = pam_authenticate(h, 0); - if (ret == PAM_SUCCESS) - ret = pam_acct_mgmt(h, 0); - pam_end(h, ret); - - return ret == PAM_SUCCESS ? 1 : 0; -} - diff --git a/common/rfb/pam.h b/common/rfb/pam.h deleted file mode 100644 index d378d19c..00000000 --- a/common/rfb/pam.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2006 Martin Koegler - * Copyright (C) 2010 TigerVNC Team - * - * 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. - */ - -#ifndef __RFB_PAM_H__ -#define __RFB_PAM_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -int do_pam_auth(const char *service, const char *username, const char *password); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/common/rfb/util.cxx b/common/rfb/util.cxx deleted file mode 100644 index 3c62b1df..00000000 --- a/common/rfb/util.cxx +++ /dev/null @@ -1,682 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2011-2023 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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <ctype.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <sys/time.h> - -#include <rfb/util.h> - -namespace rfb { - - std::string format(const char *fmt, ...) - { - va_list ap; - int len; - char *buf; - std::string out; - - va_start(ap, fmt); - len = vsnprintf(nullptr, 0, fmt, ap); - va_end(ap); - - if (len < 0) - return ""; - - buf = new char[len+1]; - - va_start(ap, fmt); - vsnprintf(buf, len+1, fmt, ap); - va_end(ap); - - out = buf; - - delete [] buf; - - return out; - } - - std::vector<std::string> split(const char* src, - const char delimiter) - { - std::vector<std::string> out; - const char *start, *stop; - - start = src; - do { - stop = strchr(start, delimiter); - if (stop == nullptr) { - out.push_back(start); - } else { - out.push_back(std::string(start, stop-start)); - start = stop + 1; - } - } while (stop != nullptr); - - return out; - } - - static char intToHex(uint8_t i) { - if (i<=9) - return '0'+i; - else if ((i>=10) && (i<=15)) - return 'a'+(i-10); - assert(false); - return '\0'; - } - - void binToHex(const uint8_t* in, size_t inlen, - char* out, size_t outlen) { - if (inlen > outlen/2) - inlen = outlen/2; - - if (inlen > 0) { - assert(in); - assert(out); - } - - for (size_t i=0; i<inlen; i++) { - out[i*2] = intToHex((in[i] >> 4) & 15); - out[i*2+1] = intToHex((in[i] & 15)); - } - } - - std::string binToHex(const uint8_t* in, size_t inlen) { - char* buffer = new char[inlen*2+1](); - std::string out; - binToHex(in, inlen, buffer, inlen*2); - out = buffer; - delete [] buffer; - return out; - } - - static bool readHexAndShift(char c, uint8_t* v) { - c=tolower(c); - if ((c >= '0') && (c <= '9')) - *v = (*v << 4) + (c - '0'); - else if ((c >= 'a') && (c <= 'f')) - *v = (*v << 4) + (c - 'a' + 10); - else - return false; - return true; - } - - bool hexToBin(const char* in, size_t inlen, - uint8_t* out, size_t outlen) { - assert(in || inlen == 0); - assert(out || outlen == 0); - - if (inlen & 1) - return false; - - if (inlen > outlen*2) - inlen = outlen*2; - - for(size_t i=0; i<inlen; i+=2) { - uint8_t byte = 0; - if (!readHexAndShift(in[i], &byte) || - !readHexAndShift(in[i+1], &byte)) - return false; - out[i/2] = byte; - } - - return true; - } - - std::vector<uint8_t> hexToBin(const char* in, size_t inlen) { - std::vector<uint8_t> out(inlen/2); - if (!hexToBin(in, inlen, out.data(), inlen/2)) - return std::vector<uint8_t>(); - return out; - } - - std::string convertLF(const char* src, size_t bytes) - { - size_t sz; - std::string out; - - const char* in; - size_t in_len; - - // Compute output size - sz = 0; - in = src; - in_len = bytes; - while ((in_len > 0) && (*in != '\0')) { - if (*in != '\r') { - sz++; - in++; - in_len--; - continue; - } - - if ((in_len < 2) || (*(in+1) != '\n')) - sz++; - - in++; - in_len--; - } - - // Reserve space - out.reserve(sz); - - // And convert - in = src; - in_len = bytes; - while ((in_len > 0) && (*in != '\0')) { - if (*in != '\r') { - out += *in++; - in_len--; - continue; - } - - if ((in_len < 2) || (*(in+1) != '\n')) - out += '\n'; - - in++; - in_len--; - } - - return out; - } - - std::string convertCRLF(const char* src, size_t bytes) - { - std::string out; - size_t sz; - - const char* in; - size_t in_len; - - // Compute output size - sz = 0; - in = src; - in_len = bytes; - while ((in_len > 0) && (*in != '\0')) { - sz++; - - if (*in == '\r') { - if ((in_len < 2) || (*(in+1) != '\n')) - sz++; - } else if (*in == '\n') { - if ((in == src) || (*(in-1) != '\r')) - sz++; - } - - in++; - in_len--; - } - - // Reserve space - out.reserve(sz); - - // And convert - in = src; - in_len = bytes; - while ((in_len > 0) && (*in != '\0')) { - if (*in == '\n') { - if ((in == src) || (*(in-1) != '\r')) - out += '\r'; - } - - out += *in; - - if (*in == '\r') { - if ((in_len < 2) || (*(in+1) != '\n')) - out += '\n'; - } - - in++; - in_len--; - } - - return out; - } - - size_t ucs4ToUTF8(unsigned src, char dst[5]) { - if (src < 0x80) { - *dst++ = src; - *dst++ = '\0'; - return 1; - } else if (src < 0x800) { - *dst++ = 0xc0 | (src >> 6); - *dst++ = 0x80 | (src & 0x3f); - *dst++ = '\0'; - return 2; - } else if ((src >= 0xd800) && (src < 0xe000)) { - return ucs4ToUTF8(0xfffd, dst); - } else if (src < 0x10000) { - *dst++ = 0xe0 | (src >> 12); - *dst++ = 0x80 | ((src >> 6) & 0x3f); - *dst++ = 0x80 | (src & 0x3f); - *dst++ = '\0'; - return 3; - } else if (src < 0x110000) { - *dst++ = 0xf0 | (src >> 18); - *dst++ = 0x80 | ((src >> 12) & 0x3f); - *dst++ = 0x80 | ((src >> 6) & 0x3f); - *dst++ = 0x80 | (src & 0x3f); - *dst++ = '\0'; - return 4; - } else { - return ucs4ToUTF8(0xfffd, dst); - } - } - - size_t utf8ToUCS4(const char* src, size_t max, unsigned* dst) { - size_t count, consumed; - - *dst = 0xfffd; - - if (max == 0) - return 0; - - consumed = 1; - - if ((*src & 0x80) == 0) { - *dst = *src; - count = 0; - } else if ((*src & 0xe0) == 0xc0) { - *dst = *src & 0x1f; - count = 1; - } else if ((*src & 0xf0) == 0xe0) { - *dst = *src & 0x0f; - count = 2; - } else if ((*src & 0xf8) == 0xf0) { - *dst = *src & 0x07; - count = 3; - } else { - // Invalid sequence, consume all continuation characters - src++; - max--; - while ((max-- > 0) && ((*src++ & 0xc0) == 0x80)) - consumed++; - return consumed; - } - - src++; - max--; - - while (count--) { - consumed++; - - // Invalid or truncated sequence? - if ((max == 0) || ((*src & 0xc0) != 0x80)) { - *dst = 0xfffd; - return consumed; - } - - *dst <<= 6; - *dst |= *src & 0x3f; - - src++; - max--; - } - - // UTF-16 surrogate code point? - if ((*dst >= 0xd800) && (*dst < 0xe000)) - *dst = 0xfffd; - - return consumed; - } - - size_t ucs4ToUTF16(unsigned src, wchar_t dst[3]) { - if ((src < 0xd800) || ((src >= 0xe000) && (src < 0x10000))) { - *dst++ = src; - *dst++ = L'\0'; - return 1; - } else if ((src >= 0x10000) && (src < 0x110000)) { - src -= 0x10000; - *dst++ = 0xd800 | ((src >> 10) & 0x03ff); - *dst++ = 0xdc00 | (src & 0x03ff); - *dst++ = L'\0'; - return 2; - } else { - return ucs4ToUTF16(0xfffd, dst); - } - } - - size_t utf16ToUCS4(const wchar_t* src, size_t max, unsigned* dst) { - *dst = 0xfffd; - - if (max == 0) - return 0; - - if ((*src < 0xd800) || (*src >= 0xe000)) { - *dst = *src; - return 1; - } - - if (*src & 0x0400) { - size_t consumed; - - // Invalid sequence, consume all continuation characters - consumed = 0; - while ((max > 0) && (*src & 0x0400)) { - src++; - max--; - consumed++; - } - - return consumed; - } - - *dst = *src++; - max--; - - // Invalid or truncated sequence? - if ((max == 0) || ((*src & 0xfc00) != 0xdc00)) { - *dst = 0xfffd; - return 1; - } - - *dst = 0x10000 + ((*dst & 0x03ff) << 10); - *dst |= *src & 0x3ff; - - return 2; - } - - std::string latin1ToUTF8(const char* src, size_t bytes) { - std::string out; - size_t sz; - - const char* in; - size_t in_len; - - // Compute output size - sz = 0; - in = src; - in_len = bytes; - while ((in_len > 0) && (*in != '\0')) { - char buf[5]; - sz += ucs4ToUTF8(*(const unsigned char*)in, buf); - in++; - in_len--; - } - - // Reserve space - out.reserve(sz); - - // And convert - in = src; - in_len = bytes; - while ((in_len > 0) && (*in != '\0')) { - char buf[5]; - ucs4ToUTF8(*(const unsigned char*)in, buf); - out += buf; - in++; - in_len--; - } - - return out; - } - - std::string utf8ToLatin1(const char* src, size_t bytes) { - std::string out; - size_t sz; - - const char* in; - size_t in_len; - - // Compute output size - sz = 0; - in = src; - in_len = bytes; - while ((in_len > 0) && (*in != '\0')) { - size_t len; - unsigned ucs; - - len = utf8ToUCS4(in, in_len, &ucs); - in += len; - in_len -= len; - sz++; - } - - // Reserve space - out.reserve(sz); - - // And convert - in = src; - in_len = bytes; - while ((in_len > 0) && (*in != '\0')) { - size_t len; - unsigned ucs; - - len = utf8ToUCS4(in, in_len, &ucs); - in += len; - in_len -= len; - - if (ucs > 0xff) - out += '?'; - else - out += (unsigned char)ucs; - } - - return out; - } - - std::string utf16ToUTF8(const wchar_t* src, size_t units) - { - std::string out; - size_t sz; - - const wchar_t* in; - size_t in_len; - - // Compute output size - sz = 0; - in = src; - in_len = units; - while ((in_len > 0) && (*in != '\0')) { - size_t len; - unsigned ucs; - char buf[5]; - - len = utf16ToUCS4(in, in_len, &ucs); - in += len; - in_len -= len; - - sz += ucs4ToUTF8(ucs, buf); - } - - // Reserve space - out.reserve(sz); - - // And convert - in = src; - in_len = units; - while ((in_len > 0) && (*in != '\0')) { - size_t len; - unsigned ucs; - char buf[5]; - - len = utf16ToUCS4(in, in_len, &ucs); - in += len; - in_len -= len; - - ucs4ToUTF8(ucs, buf); - out += buf; - } - - return out; - } - - std::wstring utf8ToUTF16(const char* src, size_t bytes) - { - std::wstring out; - size_t sz; - - const char* in; - size_t in_len; - - // Compute output size - sz = 0; - in = src; - in_len = bytes; - while ((in_len > 0) && (*in != '\0')) { - size_t len; - unsigned ucs; - wchar_t buf[3]; - - len = utf8ToUCS4(in, in_len, &ucs); - in += len; - in_len -= len; - - sz += ucs4ToUTF16(ucs, buf); - } - - // Reserve space - out.reserve(sz); - - // And convert - in = src; - in_len = bytes; - while ((in_len > 0) && (*in != '\0')) { - size_t len; - unsigned ucs; - wchar_t buf[3]; - - len = utf8ToUCS4(in, in_len, &ucs); - in += len; - in_len -= len; - - ucs4ToUTF16(ucs, buf); - out += buf; - } - - return out; - } - - bool isValidUTF8(const char* str, size_t bytes) - { - while ((bytes > 0) && (*str != '\0')) { - size_t len; - unsigned ucs; - - len = utf8ToUCS4(str, bytes, &ucs); - str += len; - bytes -= len; - - if (ucs == 0xfffd) - return false; - } - - return true; - } - - bool isValidUTF16(const wchar_t* wstr, size_t units) - { - while ((units > 0) && (*wstr != '\0')) { - size_t len; - unsigned ucs; - - len = utf16ToUCS4(wstr, units, &ucs); - wstr += len; - units -= len; - - if (ucs == 0xfffd) - return false; - } - - return true; - } - - unsigned msBetween(const struct timeval *first, - const struct timeval *second) - { - unsigned diff; - - diff = (second->tv_sec - first->tv_sec) * 1000; - - diff += second->tv_usec / 1000; - diff -= first->tv_usec / 1000; - - return diff; - } - - unsigned msSince(const struct timeval *then) - { - struct timeval now; - - gettimeofday(&now, nullptr); - - return msBetween(then, &now); - } - - bool isBefore(const struct timeval *first, - const struct timeval *second) - { - if (first->tv_sec < second->tv_sec) - return true; - if (first->tv_sec > second->tv_sec) - return false; - if (first->tv_usec < second->tv_usec) - return true; - return false; - } - - static std::string doPrefix(long long value, const char *unit, - unsigned divisor, const char **prefixes, - size_t prefixCount, int precision) { - char buffer[256]; - double newValue; - size_t prefix; - - newValue = value; - prefix = 0; - while (newValue >= divisor) { - if (prefix >= prefixCount) - break; - newValue /= divisor; - prefix++; - } - - snprintf(buffer, sizeof(buffer), "%.*g %s%s", precision, newValue, - (prefix == 0) ? "" : prefixes[prefix-1], unit); - buffer[sizeof(buffer)-1] = '\0'; - - return buffer; - } - - static const char *siPrefixes[] = - { "k", "M", "G", "T", "P", "E", "Z", "Y" }; - static const char *iecPrefixes[] = - { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" }; - - std::string siPrefix(long long value, const char *unit, - int precision) { - return doPrefix(value, unit, 1000, siPrefixes, - sizeof(siPrefixes)/sizeof(*siPrefixes), - precision); - } - - std::string iecPrefix(long long value, const char *unit, - int precision) { - return doPrefix(value, unit, 1024, iecPrefixes, - sizeof(iecPrefixes)/sizeof(*iecPrefixes), - precision); - } -}; diff --git a/common/rfb/util.h b/common/rfb/util.h deleted file mode 100644 index b47ac4c9..00000000 --- a/common/rfb/util.h +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2011-2023 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. - */ - -// -// util.h - miscellaneous useful bits -// - -#ifndef __RFB_UTIL_H__ -#define __RFB_UTIL_H__ - -#include <limits.h> -#include <stdint.h> - -#include <string> -#include <vector> - -struct timeval; - -namespace rfb { - - // Formats according to printf(), with a dynamic allocation - std::string format(const char *fmt, ...) - __attribute__((__format__ (__printf__, 1, 2))); - - // Splits a string with the specified delimiter - std::vector<std::string> split(const char* src, - const char delimiter); - - // Conversion to and from a hex string - - void binToHex(const uint8_t* in, size_t inlen, char* out, size_t outlen); - std::string binToHex(const uint8_t* in, size_t inlen); - bool hexToBin(const char* in, size_t inlen, uint8_t* out, size_t outlen); - std::vector<uint8_t> hexToBin(const char* in, size_t inlen); - - // Makes sure line endings are in a certain format - - std::string convertLF(const char* src, size_t bytes = (size_t)-1); - std::string convertCRLF(const char* src, size_t bytes = (size_t)-1); - - // Convertions between various Unicode formats - - size_t ucs4ToUTF8(unsigned src, char dst[5]); - size_t utf8ToUCS4(const char* src, size_t max, unsigned* dst); - - size_t ucs4ToUTF16(unsigned src, wchar_t dst[3]); - size_t utf16ToUCS4(const wchar_t* src, size_t max, unsigned* dst); - - std::string latin1ToUTF8(const char* src, size_t bytes = (size_t)-1); - std::string utf8ToLatin1(const char* src, size_t bytes = (size_t)-1); - - std::string utf16ToUTF8(const wchar_t* src, size_t units = (size_t)-1); - std::wstring utf8ToUTF16(const char* src, size_t bytes = (size_t)-1); - - bool isValidUTF8(const char* str, size_t bytes = (size_t)-1); - bool isValidUTF16(const wchar_t* wstr, size_t units = (size_t)-1); - - // HELPER functions for timeout handling - - // secsToMillis() turns seconds into milliseconds, capping the value so it - // can't wrap round and become -ve - inline int secsToMillis(int secs) { - return (secs < 0 || secs > (INT_MAX/1000) ? INT_MAX : secs * 1000); - } - - // Returns time elapsed between two moments in milliseconds. - unsigned msBetween(const struct timeval *first, - const struct timeval *second); - - // Returns time elapsed since given moment in milliseconds. - unsigned msSince(const struct timeval *then); - - // Returns true if first happened before seconds - bool isBefore(const struct timeval *first, - const struct timeval *second); - - std::string siPrefix(long long value, const char *unit, - int precision=6); - std::string iecPrefix(long long value, const char *unit, - int precision=6); -} - -// Some platforms (e.g. Windows) include max() and min() macros in their -// standard headers, but they are also standard C++ template functions, so some -// C++ headers will undefine them. So we steer clear of the names min and max -// and define __rfbmin and __rfbmax instead. - -#ifndef __rfbmax -#define __rfbmax(a,b) (((a) > (b)) ? (a) : (b)) -#endif -#ifndef __rfbmin -#define __rfbmin(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -#endif |