aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/CMakeLists.txt4
-rw-r--r--common/core/CMakeLists.txt32
-rw-r--r--common/core/Configuration.cxx857
-rw-r--r--common/core/Configuration.h (renamed from common/rfb/Configuration.h)250
-rw-r--r--common/core/Exception.cxx (renamed from common/rdr/Exception.cxx)31
-rw-r--r--common/core/Exception.h (renamed from common/rdr/Exception.h)11
-rw-r--r--common/core/LogWriter.cxx (renamed from common/rfb/LogWriter.cxx)29
-rw-r--r--common/core/LogWriter.h (renamed from common/rfb/LogWriter.h)19
-rw-r--r--common/core/Logger.cxx (renamed from common/rfb/Logger.cxx)6
-rw-r--r--common/core/Logger.h (renamed from common/rfb/Logger.h)8
-rw-r--r--common/core/Logger_file.cxx (renamed from common/rfb/Logger_file.cxx)13
-rw-r--r--common/core/Logger_file.h (renamed from common/rfb/Logger_file.h)11
-rw-r--r--common/core/Logger_stdio.cxx (renamed from common/rfb/Logger_stdio.cxx)7
-rw-r--r--common/core/Logger_stdio.h (renamed from common/rfb/Logger_stdio.h)8
-rw-r--r--common/core/Logger_syslog.cxx (renamed from common/rfb/Logger_syslog.cxx)9
-rw-r--r--common/core/Logger_syslog.h (renamed from common/rfb/Logger_syslog.h)9
-rw-r--r--common/core/Rect.h (renamed from common/rfb/Rect.h)42
-rw-r--r--common/core/Region.cxx (renamed from common/rfb/Region.cxx)74
-rw-r--r--common/core/Region.h (renamed from common/rfb/Region.h)16
-rw-r--r--common/core/Timer.cxx (renamed from common/rfb/Timer.cxx)34
-rw-r--r--common/core/Timer.h (renamed from common/rfb/Timer.h)6
-rw-r--r--common/core/string.cxx (renamed from common/rfb/util.cxx)42
-rw-r--r--common/core/string.h (renamed from common/rfb/util.h)43
-rw-r--r--common/core/time.cxx88
-rw-r--r--common/core/time.h58
-rw-r--r--common/core/winerrno.h (renamed from common/os/winerrno.h)0
-rw-r--r--common/core/xdgdirs.cxx (renamed from common/os/os.cxx)14
-rw-r--r--common/core/xdgdirs.h (renamed from common/os/os.h)8
-rw-r--r--common/network/CMakeLists.txt2
-rw-r--r--common/network/Socket.cxx31
-rw-r--r--common/network/Socket.h11
-rw-r--r--common/network/TcpSocket.cxx144
-rw-r--r--common/network/TcpSocket.h3
-rw-r--r--common/network/UnixSocket.cxx23
-rw-r--r--common/os/CMakeLists.txt15
-rw-r--r--common/os/Mutex.cxx158
-rw-r--r--common/os/Mutex.h64
-rw-r--r--common/os/Thread.cxx173
-rw-r--r--common/os/Thread.h58
-rw-r--r--common/rdr/BufferedInStream.cxx14
-rw-r--r--common/rdr/BufferedOutStream.cxx13
-rw-r--r--common/rdr/CMakeLists.txt11
-rw-r--r--common/rdr/FdInStream.cxx9
-rw-r--r--common/rdr/FdOutStream.cxx14
-rw-r--r--common/rdr/FileInStream.cxx7
-rw-r--r--common/rdr/HexInStream.cxx6
-rw-r--r--common/rdr/HexOutStream.cxx7
-rw-r--r--common/rdr/InStream.h13
-rw-r--r--common/rdr/MemInStream.h1
-rw-r--r--common/rdr/RandomStream.cxx14
-rw-r--r--common/rdr/TLSException.cxx29
-rw-r--r--common/rdr/TLSException.h8
-rw-r--r--common/rdr/TLSInStream.cxx98
-rw-r--r--common/rdr/TLSInStream.h18
-rw-r--r--common/rdr/TLSOutStream.cxx82
-rw-r--r--common/rdr/TLSOutStream.h17
-rw-r--r--common/rdr/TLSSocket.cxx228
-rw-r--r--common/rdr/TLSSocket.h81
-rw-r--r--common/rdr/ZlibOutStream.cxx5
-rw-r--r--common/rfb/Blacklist.cxx32
-rw-r--r--common/rfb/Blacklist.h4
-rw-r--r--common/rfb/CConnection.cxx182
-rw-r--r--common/rfb/CConnection.h199
-rw-r--r--common/rfb/CMakeLists.txt34
-rw-r--r--common/rfb/CMsgHandler.cxx168
-rw-r--r--common/rfb/CMsgHandler.h59
-rw-r--r--common/rfb/CMsgReader.cxx41
-rw-r--r--common/rfb/CMsgReader.h23
-rw-r--r--common/rfb/CMsgWriter.cxx16
-rw-r--r--common/rfb/CMsgWriter.h12
-rw-r--r--common/rfb/CSecurityDH.cxx1
-rw-r--r--common/rfb/CSecurityMSLogonII.cxx1
-rw-r--r--common/rfb/CSecurityRSAAES.cxx24
-rw-r--r--common/rfb/CSecurityRSAAES.h8
-rw-r--r--common/rfb/CSecurityStack.h1
-rw-r--r--common/rfb/CSecurityTLS.cxx450
-rw-r--r--common/rfb/CSecurityTLS.h11
-rw-r--r--common/rfb/CSecurityVeNCrypt.cxx5
-rw-r--r--common/rfb/CSecurityVeNCrypt.h3
-rw-r--r--common/rfb/ClientParams.cxx36
-rw-r--r--common/rfb/ClientParams.h22
-rw-r--r--common/rfb/ComparingUpdateTracker.cxx44
-rw-r--r--common/rfb/ComparingUpdateTracker.h3
-rw-r--r--common/rfb/Configuration.cxx469
-rw-r--r--common/rfb/Congestion.cxx35
-rw-r--r--common/rfb/CopyRectDecoder.cxx19
-rw-r--r--common/rfb/CopyRectDecoder.h8
-rw-r--r--common/rfb/Cursor.cxx30
-rw-r--r--common/rfb/Cursor.h18
-rw-r--r--common/rfb/DecodeManager.cxx126
-rw-r--r--common/rfb/DecodeManager.h37
-rw-r--r--common/rfb/Decoder.cxx12
-rw-r--r--common/rfb/Decoder.h23
-rw-r--r--common/rfb/EncodeManager.cxx159
-rw-r--r--common/rfb/EncodeManager.h73
-rw-r--r--common/rfb/Encoder.h2
-rw-r--r--common/rfb/H264Decoder.cxx24
-rw-r--r--common/rfb/H264Decoder.h12
-rw-r--r--common/rfb/H264DecoderContext.cxx29
-rw-r--r--common/rfb/H264DecoderContext.h23
-rw-r--r--common/rfb/H264LibavDecoderContext.cxx67
-rw-r--r--common/rfb/H264LibavDecoderContext.h8
-rw-r--r--common/rfb/H264WinDecoderContext.cxx80
-rw-r--r--common/rfb/H264WinDecoderContext.h8
-rw-r--r--common/rfb/HextileDecoder.cxx20
-rw-r--r--common/rfb/HextileDecoder.h6
-rw-r--r--common/rfb/HextileEncoder.cxx31
-rw-r--r--common/rfb/Hostname.h120
-rw-r--r--common/rfb/JpegCompressor.cxx6
-rw-r--r--common/rfb/JpegCompressor.h10
-rw-r--r--common/rfb/JpegDecompressor.cxx6
-rw-r--r--common/rfb/JpegDecompressor.h11
-rw-r--r--common/rfb/KeyRemapper.cxx78
-rw-r--r--common/rfb/KeyRemapper.h7
-rw-r--r--common/rfb/PixelBuffer.cxx121
-rw-r--r--common/rfb/PixelBuffer.h47
-rw-r--r--common/rfb/PixelFormat.h2
-rw-r--r--common/rfb/RREDecoder.cxx8
-rw-r--r--common/rfb/RREDecoder.h6
-rw-r--r--common/rfb/RawDecoder.cxx4
-rw-r--r--common/rfb/RawDecoder.h4
-rw-r--r--common/rfb/SConnection.cxx137
-rw-r--r--common/rfb/SConnection.h157
-rw-r--r--common/rfb/SDesktop.h52
-rw-r--r--common/rfb/SMsgHandler.cxx176
-rw-r--r--common/rfb/SMsgHandler.h80
-rw-r--r--common/rfb/SMsgReader.cxx26
-rw-r--r--common/rfb/SMsgWriter.cxx18
-rw-r--r--common/rfb/SMsgWriter.h7
-rw-r--r--common/rfb/SSecurity.h6
-rw-r--r--common/rfb/SSecurityPlain.cxx27
-rw-r--r--common/rfb/SSecurityPlain.h20
-rw-r--r--common/rfb/SSecurityRSAAES.cxx26
-rw-r--r--common/rfb/SSecurityRSAAES.h11
-rw-r--r--common/rfb/SSecurityTLS.cxx117
-rw-r--r--common/rfb/SSecurityTLS.h12
-rw-r--r--common/rfb/SSecurityVeNCrypt.cxx9
-rw-r--r--common/rfb/SSecurityVeNCrypt.h6
-rw-r--r--common/rfb/SSecurityVncAuth.cxx22
-rw-r--r--common/rfb/SSecurityVncAuth.h11
-rw-r--r--common/rfb/ScreenSet.h7
-rw-r--r--common/rfb/Security.cxx34
-rw-r--r--common/rfb/Security.h14
-rw-r--r--common/rfb/SecurityClient.cxx21
-rw-r--r--common/rfb/SecurityClient.h7
-rw-r--r--common/rfb/SecurityServer.cxx20
-rw-r--r--common/rfb/SecurityServer.h3
-rw-r--r--common/rfb/ServerCore.cxx44
-rw-r--r--common/rfb/ServerCore.h34
-rw-r--r--common/rfb/ServerParams.cxx31
-rw-r--r--common/rfb/ServerParams.h16
-rw-r--r--common/rfb/TightDecoder.cxx21
-rw-r--r--common/rfb/TightDecoder.h15
-rw-r--r--common/rfb/UnixPasswordValidator.cxx117
-rw-r--r--common/rfb/UnixPasswordValidator.h14
-rw-r--r--common/rfb/UpdateTracker.cxx43
-rw-r--r--common/rfb/UpdateTracker.h45
-rw-r--r--common/rfb/VNCSConnectionST.cxx83
-rw-r--r--common/rfb/VNCSConnectionST.h30
-rw-r--r--common/rfb/VNCServer.h14
-rw-r--r--common/rfb/VNCServerST.cxx96
-rw-r--r--common/rfb/VNCServerST.h35
-rw-r--r--common/rfb/WinPasswdValidator.cxx3
-rw-r--r--common/rfb/WinPasswdValidator.h6
-rw-r--r--common/rfb/ZRLEDecoder.cxx14
-rw-r--r--common/rfb/ZRLEDecoder.h6
-rw-r--r--common/rfb/ZRLEEncoder.cxx24
-rw-r--r--common/rfb/ZRLEEncoder.h8
-rw-r--r--common/rfb/pam.c95
-rw-r--r--common/rfb/pam.h34
170 files changed, 4102 insertions, 3966 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 6fd1e106..96b4e6b7 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_subdirectory(os)
+add_subdirectory(core)
add_subdirectory(rdr)
add_subdirectory(network)
add_subdirectory(rfb)
@@ -9,6 +9,6 @@ add_subdirectory(rfb)
# is passed (additionally, libvnc is not used on Windows.)
if(NOT WIN32)
- set_target_properties(os rdr network rfb
+ set_target_properties(core rdr network rfb
PROPERTIES COMPILE_FLAGS -fPIC)
endif()
diff --git a/common/core/CMakeLists.txt b/common/core/CMakeLists.txt
new file mode 100644
index 00000000..7e58acc0
--- /dev/null
+++ b/common/core/CMakeLists.txt
@@ -0,0 +1,32 @@
+add_library(core STATIC
+ Configuration.cxx
+ Exception.cxx
+ Logger.cxx
+ Logger_file.cxx
+ Logger_stdio.cxx
+ LogWriter.cxx
+ Region.cxx
+ Timer.cxx
+ string.cxx
+ time.cxx
+ xdgdirs.cxx)
+
+target_include_directories(core PUBLIC ${CMAKE_SOURCE_DIR}/common)
+target_include_directories(core SYSTEM PUBLIC ${PIXMAN_INCLUDE_DIRS})
+target_link_libraries(core ${PIXMAN_LIBRARIES})
+
+if(UNIX)
+ target_sources(core PRIVATE Logger_syslog.cxx)
+endif()
+
+if(WIN32)
+ target_link_libraries(core ws2_32)
+endif()
+
+if(UNIX)
+ target_sources(core PRIVATE Logger_syslog.cxx)
+endif()
+
+if(UNIX)
+ libtool_create_control_file(core)
+endif()
diff --git a/common/core/Configuration.cxx b/common/core/Configuration.cxx
new file mode 100644
index 00000000..e6affb06
--- /dev/null
+++ b/common/core/Configuration.cxx
@@ -0,0 +1,857 @@
+/* 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-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
+ * 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 <algorithm>
+#include <stdexcept>
+
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
+#include <rdr/HexOutStream.h>
+#include <rdr/HexInStream.h>
+
+using namespace core;
+
+static LogWriter vlog("Config");
+
+
+// -=- The Global Configuration object
+Configuration* Configuration::global_ = nullptr;
+
+Configuration* Configuration::global() {
+ if (!global_)
+ global_ = new Configuration();
+ return global_;
+}
+
+// -=- Configuration implementation
+
+bool Configuration::set(const char* paramName, const char* val,
+ bool immutable)
+{
+ for (VoidParameter* current: params) {
+ if (strcasecmp(current->getName(), paramName) == 0) {
+ bool b = current->setParam(val);
+ if (b && immutable)
+ current->setImmutable();
+ return b;
+ }
+ }
+ return false;
+}
+
+VoidParameter* Configuration::get(const char* param)
+{
+ for (VoidParameter* current: params) {
+ if (strcasecmp(current->getName(), param) == 0)
+ return current;
+ }
+ return nullptr;
+}
+
+void Configuration::list(int width, int nameWidth) {
+ for (VoidParameter* current: params) {
+ std::string def_str = current->getDefaultStr();
+ std::string desc_str = current->getDescription();
+ if (!def_str.empty())
+ desc_str += " (default=" + def_str + ")";
+ const char* desc = desc_str.c_str();
+ fprintf(stderr," %-*s -", nameWidth, current->getName());
+ int column = strlen(current->getName());
+ if (column < nameWidth) column = nameWidth;
+ column += 4;
+ while (true) {
+ if (desc[0] == '\0')
+ break;
+
+ int wordLen = strcspn(desc, " \f\n\r\t\v,");
+ if (wordLen == 0) {
+ desc++;
+ continue;
+ }
+
+ if (desc[wordLen] == ',')
+ wordLen++;
+
+ if (column + wordLen + 1 > width) {
+ fprintf(stderr,"\n%*s",nameWidth+4,"");
+ column = nameWidth+4;
+ }
+ fprintf(stderr, " ");
+ column++;
+
+ fprintf(stderr, "%.*s", wordLen, desc);
+ column += wordLen;
+ desc += wordLen;
+ }
+ fprintf(stderr,"\n");
+ }
+}
+
+
+bool Configuration::remove(const char* param) {
+ std::list<VoidParameter*>::iterator iter;
+
+ iter = std::find_if(params.begin(), params.end(),
+ [param](VoidParameter* p) {
+ return strcasecmp(p->getName(), param) == 0;
+ });
+ if (iter == params.end())
+ return false;
+
+ params.erase(iter);
+ return true;
+}
+
+int Configuration::handleArg(int argc, char* argv[], int index)
+{
+ std::string param, val;
+ const char* equal = strchr(argv[index], '=');
+
+ if (equal == argv[index])
+ return 0;
+
+ if (equal) {
+ param.assign(argv[index], equal-argv[index]);
+ val.assign(equal+1);
+ } else {
+ param.assign(argv[index]);
+ }
+
+ if ((param.length() > 0) && (param[0] == '-')) {
+ // allow gnu-style --<option>
+ if ((param.length() > 1) && (param[1] == '-'))
+ param = param.substr(2);
+ else
+ param = param.substr(1);
+ } else {
+ // All command line arguments need either an initial '-', or an '='
+ if (!equal)
+ return 0;
+ }
+
+ if (equal)
+ return set(param.c_str(), val.c_str()) ? 1 : 0;
+
+ for (VoidParameter* current: params) {
+ if (strcasecmp(current->getName(), param.c_str()) != 0)
+ continue;
+
+ // We need to resolve an ambiguity for booleans
+ if (dynamic_cast<BoolParameter*>(current) != nullptr) {
+ if (index+1 < argc) {
+ // FIXME: Should not duplicate the list of values here
+ if ((strcasecmp(argv[index+1], "0") == 0) ||
+ (strcasecmp(argv[index+1], "1") == 0) ||
+ (strcasecmp(argv[index+1], "on") == 0) ||
+ (strcasecmp(argv[index+1], "off") == 0) ||
+ (strcasecmp(argv[index+1], "true") == 0) ||
+ (strcasecmp(argv[index+1], "false") == 0) ||
+ (strcasecmp(argv[index+1], "yes") == 0) ||
+ (strcasecmp(argv[index+1], "no") == 0)) {
+ return current->setParam(argv[index+1]) ? 2 : 0;
+ }
+ }
+ }
+
+ if (current->setParam())
+ return 1;
+
+ if (index+1 >= argc)
+ return 0;
+
+ return current->setParam(argv[index+1]) ? 2 : 0;
+ }
+
+ return 0;
+}
+
+
+// -=- VoidParameter
+
+VoidParameter::VoidParameter(const char* name_, const char* desc_)
+ : immutable(false), name(name_), description(desc_)
+{
+ Configuration *conf;
+
+ conf = Configuration::global();
+ conf->params.push_back(this);
+ conf->params.sort([](const VoidParameter* a, const VoidParameter* b) {
+ return strcasecmp(a->getName(), b->getName()) < 0;
+ });
+}
+
+VoidParameter::~VoidParameter() {
+ Configuration *conf;
+
+ conf = Configuration::global();
+ conf->params.remove(this);
+}
+
+const char*
+VoidParameter::getName() const {
+ return name;
+}
+
+const char*
+VoidParameter::getDescription() const {
+ return description;
+}
+
+bool VoidParameter::setParam() {
+ return false;
+}
+
+bool VoidParameter::isDefault() const {
+ return getDefaultStr() == getValueStr();
+}
+
+void
+VoidParameter::setImmutable() {
+ vlog.debug("Set immutable %s", getName());
+ immutable = true;
+}
+
+// -=- AliasParameter
+
+AliasParameter::AliasParameter(const char* name_, const char* desc_,
+ VoidParameter* param_)
+ : VoidParameter(name_, desc_), 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();
+}
+
+void
+AliasParameter::setImmutable() {
+ vlog.debug("Set immutable %s (Alias)", getName());
+ param->setImmutable();
+}
+
+
+// -=- BoolParameter
+
+BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v)
+: VoidParameter(name_, desc_), 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 %s", getName(), getValueStr().c_str());
+}
+
+std::string BoolParameter::getDefaultStr() const {
+ return def_value ? "on" : "off";
+}
+
+std::string BoolParameter::getValueStr() const {
+ return value ? "on" : "off";
+}
+
+BoolParameter::operator bool() const {
+ return value;
+}
+
+// -=- IntParameter
+
+IntParameter::IntParameter(const char* name_, const char* desc_, int v,
+ int minValue_, int maxValue_)
+ : VoidParameter(name_, desc_), value(v), def_value(v),
+ minValue(minValue_), maxValue(maxValue_)
+{
+ if (v < minValue || v > maxValue) {
+ vlog.error("Invalid default value %d for %s", v, getName());
+ throw std::invalid_argument("Invalid default value");
+ }
+}
+
+bool
+IntParameter::setParam(const char* v) {
+ char* end;
+ long n;
+ if (immutable) return true;
+ n = strtol(v, &end, 0);
+ if ((*end != 0) || (n < INT_MIN) || (n > INT_MAX)) {
+ vlog.error("Int parameter %s: Invalid value '%s'", getName(), v);
+ return false;
+ }
+ return setParam(n);
+}
+
+bool
+IntParameter::setParam(int v) {
+ if (immutable) return true;
+ if (v < minValue || v > maxValue) {
+ vlog.error("Int parameter %s: Invalid value '%d'", getName(), v);
+ return false;
+ }
+ vlog.debug("Set %s(Int) to %d", getName(), v);
+ 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)
+ : VoidParameter(name_, desc_), value(v?v:""), def_value(v?v:"")
+{
+ if (!v) {
+ vlog.error("Default value <null> for %s not allowed",name_);
+ throw std::invalid_argument("Default value <null> not allowed");
+ }
+}
+
+bool StringParameter::setParam(const char* v) {
+ 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 {
+ return value;
+}
+
+StringParameter::operator const char *() const {
+ return value.c_str();
+}
+
+// -=- EnumParameter
+
+EnumParameter::EnumParameter(const char* name_, const char* desc_,
+ const std::set<const char*>& enums_,
+ const char* v)
+ : VoidParameter(name_, desc_), value(v?v:""), def_value(v?v:"")
+{
+ if (!v) {
+ vlog.error("Default value <null> for %s not allowed", name_);
+ throw std::invalid_argument("Default value <null> not allowed");
+ }
+
+ for (const char* e: enums_) {
+ if (!e) {
+ vlog.error("Enumeration <null> for %s not allowed", name_);
+ throw std::invalid_argument("Enumeration <null> not allowed");
+ }
+ enums.insert(e);
+ }
+
+ if (std::find(enums.begin(), enums.end(), def_value) == enums.end()) {
+ vlog.error("Default value %s for %s is not in list of valid values",
+ def_value.c_str(), name_);
+ throw std::invalid_argument("Default value is not in list of valid values");
+ }
+}
+
+bool EnumParameter::setParam(const char* v)
+{
+ std::set<std::string>::const_iterator iter;
+ if (immutable) return true;
+ if (!v)
+ throw std::invalid_argument("setParam(<null>) not allowed");
+ iter = std::find_if(enums.begin(), enums.end(),
+ [v](const std::string& e) {
+ return strcasecmp(e.c_str(), v) == 0;
+ });
+ if (iter == enums.end()) {
+ vlog.error("Enum parameter %s: Invalid value '%s'", getName(), v);
+ return false;
+ }
+ vlog.debug("Set %s(Enum) to %s", getName(), iter->c_str());
+ value = *iter;
+ return true;
+}
+
+std::string EnumParameter::getDefaultStr() const
+{
+ return def_value;
+}
+
+std::string EnumParameter::getValueStr() const
+{
+ return value;
+}
+
+bool EnumParameter::operator==(const char* other) const
+{
+ return strcasecmp(value.c_str(), other) == 0;
+}
+
+bool EnumParameter::operator==(const std::string& other) const
+{
+ return *this == other.c_str();
+}
+
+bool EnumParameter::operator!=(const char* other) const
+{
+ return strcasecmp(value.c_str(), other) != 0;
+}
+
+bool EnumParameter::operator!=(const std::string& other) const
+{
+ return *this != other.c_str();
+}
+
+// -=- BinaryParameter
+
+BinaryParameter::BinaryParameter(const char* name_, const char* desc_,
+ const uint8_t* v, size_t l)
+: VoidParameter(name_, desc_),
+ 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) {
+ 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 {
+ return binToHex(value, length);
+}
+
+std::vector<uint8_t> BinaryParameter::getData() const {
+ std::vector<uint8_t> out(length);
+ memcpy(out.data(), value, length);
+ return out;
+}
+
+// -=- ListParameter template
+
+template<typename ValueType>
+ListParameter<ValueType>::ListParameter(const char* name_,
+ const char* desc_,
+ const ListType& v)
+ : VoidParameter(name_, desc_), value(v), def_value(v)
+{
+}
+
+template<typename ValueType>
+bool ListParameter<ValueType>::setParam(const char* v)
+{
+ std::vector<std::string> entries;
+ ListType new_value;
+
+ if (immutable)
+ return true;
+
+ // setParam({}) ends up as setParam(nullptr)
+ if (v != nullptr)
+ entries = split(v, ',');
+
+ for (std::string& entry : entries) {
+ ValueType e;
+
+ entry.erase(0, entry.find_first_not_of(" \f\n\r\t\v"));
+ entry.erase(entry.find_last_not_of(" \f\n\r\t\v")+1);
+
+ // Special case, entire v was just whitespace
+ if (entry.empty() && (entries.size() == 1))
+ break;
+
+ if (!decodeEntry(entry.c_str(), &e)) {
+ vlog.error("List parameter %s: Invalid value '%s'",
+ getName(), entry.c_str());
+ return false;
+ }
+
+ new_value.push_back(e);
+ }
+
+ return setParam(new_value);
+}
+
+template<typename ValueType>
+bool ListParameter<ValueType>::setParam(const ListType& v)
+{
+ ListType vnorm;
+ if (immutable)
+ return true;
+ for (const ValueType& entry : v) {
+ if (!validateEntry(entry)) {
+ vlog.error("List parameter %s: Invalid value '%s'", getName(),
+ encodeEntry(entry).c_str());
+ return false;
+ }
+ vnorm.push_back(normaliseEntry(entry));
+ }
+ value = vnorm;
+ vlog.debug("set %s(List) to %s", getName(), getValueStr().c_str());
+ return true;
+}
+
+template<typename ValueType>
+std::string ListParameter<ValueType>::getDefaultStr() const
+{
+ std::string result;
+
+ for (ValueType entry : def_value) {
+ // FIXME: Might want to add a space here as well for readability,
+ // but this would sacrifice backward compatibility
+ if (!result.empty())
+ result += ',';
+ result += encodeEntry(entry);
+ }
+
+ return result;
+}
+
+template<typename ValueType>
+std::string ListParameter<ValueType>::getValueStr() const
+{
+ std::string result;
+
+ for (ValueType entry : value) {
+ // FIXME: Might want to add a space here as well for readability,
+ // but this would sacrifice backward compatibility
+ if (!result.empty())
+ result += ',';
+ result += encodeEntry(entry);
+ }
+
+ return result;
+}
+
+template<typename ValueType>
+typename ListParameter<ValueType>::const_iterator ListParameter<ValueType>::begin() const
+{
+ return value.begin();
+}
+
+template<typename ValueType>
+typename ListParameter<ValueType>::const_iterator ListParameter<ValueType>::end() const
+{
+ return value.end();
+}
+
+template<typename ValueType>
+bool ListParameter<ValueType>::validateEntry(const ValueType& /*entry*/) const
+{
+ return true;
+}
+
+template<typename ValueType>
+ValueType ListParameter<ValueType>::normaliseEntry(const ValueType& entry) const
+{
+ return entry;
+}
+
+// -=- IntListParameter
+
+template class core::ListParameter<int>;
+
+IntListParameter::IntListParameter(const char* name_, const char* desc_,
+ const ListType& v,
+ int minValue_, int maxValue_)
+ : ListParameter<int>(name_, desc_, v),
+ minValue(minValue_), maxValue(maxValue_)
+{
+ for (int entry : v) {
+ if (!validateEntry(entry)) {
+ vlog.error("Invalid default value %d for %s", entry, getName());
+ throw std::invalid_argument("Invalid default value");
+ }
+ }
+}
+
+bool IntListParameter::decodeEntry(const char* entry, int* out) const
+{
+ long n;
+ char *end;
+
+ assert(entry);
+ assert(out);
+
+ if (entry[0] == '\0')
+ return false;
+
+ n = strtol(entry, &end, 0);
+ if ((*end != 0) || (n < INT_MIN) || (n > INT_MAX))
+ return false;
+
+ *out = n;
+
+ return true;
+}
+
+std::string IntListParameter::encodeEntry(const int& entry) const
+{
+ char valstr[16];
+ sprintf(valstr, "%d", entry);
+ return valstr;
+}
+
+bool IntListParameter::validateEntry(const int& entry) const
+{
+ return (entry >= minValue) && (entry <= maxValue);
+}
+
+// -=- StringListParameter
+
+template class core::ListParameter<std::string>;
+
+StringListParameter::StringListParameter(const char* name_,
+ const char* desc_,
+ const std::list<const char*>& v_)
+ : ListParameter<std::string>(name_, desc_, {})
+{
+ for (const char* v: v_) {
+ if (!v) {
+ vlog.error("Default value <null> for %s not allowed", name_);
+ throw std::invalid_argument("Default value <null> not allowed");
+ }
+ value.push_back(v);
+ def_value.push_back(v);
+ }
+}
+
+StringListParameter::const_iterator StringListParameter::begin() const
+{
+ return ListParameter<std::string>::begin();
+}
+
+StringListParameter::const_iterator StringListParameter::end() const
+{
+ return ListParameter<std::string>::end();
+}
+
+bool StringListParameter::decodeEntry(const char* entry, std::string* out) const
+{
+ *out = entry;
+ return true;
+}
+
+std::string StringListParameter::encodeEntry(const std::string& entry) const
+{
+ return entry;
+}
+
+// -=- EnumListEntry
+
+EnumListEntry::EnumListEntry(const std::string& v)
+ : value(v)
+{
+}
+
+std::string EnumListEntry::getValueStr() const
+{
+ return value;
+}
+
+bool EnumListEntry::operator==(const char* other) const
+{
+ return strcasecmp(value.c_str(), other) == 0;
+}
+
+bool EnumListEntry::operator==(const std::string& other) const
+{
+ return *this == other.c_str();
+}
+
+bool EnumListEntry::operator!=(const char* other) const
+{
+ return strcasecmp(value.c_str(), other) != 0;
+}
+
+bool EnumListEntry::operator!=(const std::string& other) const
+{
+ return *this != other.c_str();
+}
+
+// -=- EnumListParameter
+
+EnumListParameter::EnumListParameter(const char* name_,
+ const char* desc_,
+ const std::set<const char*>& enums_,
+ const std::list<const char*>& v_)
+ : ListParameter<std::string>(name_, desc_, {})
+{
+ for (const char* v: v_) {
+ if (!v) {
+ vlog.error("Default value <null> for %s not allowed", name_);
+ throw std::invalid_argument("Default value <null> not allowed");
+ }
+ value.push_back(v);
+ def_value.push_back(v);
+ }
+
+ for (const char* e: enums_) {
+ if (!e) {
+ vlog.error("Enumeration <null> for %s not allowed", name_);
+ throw std::invalid_argument("Enumeration <null> not allowed");
+ }
+ enums.insert(e);
+ }
+
+ for (const std::string& def_entry : def_value) {
+ if (std::find(enums.begin(), enums.end(), def_entry) == enums.end()) {
+ vlog.error("Default value %s for %s is not in list of valid values",
+ def_entry.c_str(), name_);
+ throw std::invalid_argument("Default value is not in list of valid values");
+ }
+ }
+}
+
+EnumListParameter::const_iterator EnumListParameter::begin() const
+{
+ return ListParameter<std::string>::begin();
+}
+
+EnumListParameter::const_iterator EnumListParameter::end() const
+{
+ return ListParameter<std::string>::end();
+}
+
+bool EnumListParameter::decodeEntry(const char* entry, std::string* out) const
+{
+ *out = entry;
+ return true;
+}
+
+std::string EnumListParameter::encodeEntry(const std::string& entry) const
+{
+ return entry;
+}
+
+bool EnumListParameter::validateEntry(const std::string& entry) const
+{
+ for (const std::string& e : enums) {
+ if (strcasecmp(e.c_str(), entry.c_str()) == 0)
+ return true;
+ }
+ return false;
+}
+
+std::string EnumListParameter::normaliseEntry(const std::string& entry) const
+{
+ for (const std::string& e : enums) {
+ if (strcasecmp(e.c_str(), entry.c_str()) == 0)
+ return e;
+ }
+ throw std::logic_error("Entry is not in list of valid values");
+}
diff --git a/common/rfb/Configuration.h b/common/core/Configuration.h
index ec8d789a..431dd0c5 100644
--- a/common/rfb/Configuration.h
+++ b/common/core/Configuration.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2022 Pierre Ossman for Cendio AB
+ * Copyright 2011-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
@@ -41,22 +41,20 @@
// NB: NO LOCKING is performed when linking Configurations to groups
// or when adding Parameters to Configurations.
-#ifndef __RFB_CONFIGURATION_H__
-#define __RFB_CONFIGURATION_H__
+#ifndef __CORE_CONFIGURATION_H__
+#define __CORE_CONFIGURATION_H__
#include <limits.h>
#include <stdint.h>
+#include <list>
+#include <set>
#include <string>
#include <vector>
-namespace os { class Mutex; }
+namespace core {
-namespace rfb {
class VoidParameter;
- struct ParameterIterator;
-
- enum ConfigurationObject { ConfGlobal, ConfServer, ConfViewer };
// -=- Configuration
// Class used to access parameters.
@@ -64,22 +62,11 @@ namespace rfb {
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(); }
+ Configuration() {}
// - 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);
@@ -89,15 +76,18 @@ namespace rfb {
// - 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);
+ // - handleArg
+ // Parse a command line argument into a parameter, returning how
+ // many arguments were consumed
+ int handleArg(int argc, char* argv[], int index);
+
- // - writeConfigToFile
- // Write a new configuration parameters file, then mv it
- // over the old file.
- void writeToFile(const char* filename);
+ // - Iterate over all parameters
+ std::list<VoidParameter*>::iterator begin() { return params.begin(); }
+ std::list<VoidParameter*>::iterator end() { return params.end(); }
+ // - Returns the number of parameters
+ int size() { return params.size(); }
// - Get the Global Configuration object
// NB: This call does NOT lock the Configuration system.
@@ -106,21 +96,10 @@ namespace rfb {
// 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);
@@ -128,38 +107,18 @@ namespace rfb {
static bool removeParam(const char* param) {
return global()->remove(param);
}
+ static int handleParamArg(int argc, char* argv[], int index) {
+ return global()->handleArg(argc, argv, index);
+ }
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;
+ // - List of Parameters
+ std::list<VoidParameter*> params;
// 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
@@ -167,7 +126,7 @@ namespace rfb {
class VoidParameter {
public:
- VoidParameter(const char* name_, const char* desc_, ConfigurationObject co=ConfGlobal);
+ VoidParameter(const char* name_, const char* desc_);
virtual ~VoidParameter();
const char* getName() const;
const char* getDescription() const;
@@ -176,31 +135,27 @@ namespace rfb {
virtual bool setParam();
virtual std::string getDefaultStr() const = 0;
virtual std::string getValueStr() const = 0;
- virtual bool isBool() const;
+
+ virtual bool isDefault() 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);
+ AliasParameter(const char* name_, const char* desc_,VoidParameter* param_);
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;
@@ -208,14 +163,12 @@ namespace rfb {
class BoolParameter : public VoidParameter {
public:
- BoolParameter(const char* name_, const char* desc_, bool v,
- ConfigurationObject co=ConfGlobal);
+ BoolParameter(const char* name_, const char* desc_, bool v);
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;
@@ -225,8 +178,7 @@ namespace rfb {
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);
+ int minValue=INT_MIN, int maxValue=INT_MAX);
using VoidParameter::setParam;
bool setParam(const char* value) override;
virtual bool setParam(int v);
@@ -241,11 +193,7 @@ namespace rfb {
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;
+ StringParameter(const char* name_, const char* desc_, const char* v);
bool setParam(const char* value) override;
std::string getDefaultStr() const override;
std::string getValueStr() const override;
@@ -255,11 +203,29 @@ namespace rfb {
std::string def_value;
};
+ class EnumParameter : public VoidParameter {
+ public:
+ EnumParameter(const char* name_, const char* desc_,
+ const std::set<const char*>& enums, const char* v);
+ bool setParam(const char* value) override;
+ std::string getDefaultStr() const override;
+ std::string getValueStr() const override;
+ bool operator==(const char* other) const;
+ bool operator==(const std::string& other) const;
+ bool operator!=(const char* other) const;
+ bool operator!=(const std::string& other) const;
+ // operator const char*() omitted on purpose to force usage of above
+ // comparison operators
+ protected:
+ std::string value;
+ std::string def_value;
+ std::set<std::string> enums;
+ };
+
class BinaryParameter : public VoidParameter {
public:
BinaryParameter(const char* name_, const char* desc_,
- const uint8_t* v, size_t l,
- ConfigurationObject co=ConfGlobal);
+ const uint8_t* v, size_t l);
using VoidParameter::setParam;
~BinaryParameter() override;
bool setParam(const char* value) override;
@@ -276,25 +242,107 @@ namespace rfb {
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;
+ template<typename ValueType>
+ class ListParameter : public VoidParameter {
+ public:
+ typedef std::list<ValueType> ListType;
+ typedef typename ListType::const_iterator const_iterator;
+
+ ListParameter(const char* name_, const char* desc_,
+ const ListType& v);
+ using VoidParameter::setParam;
+ bool setParam(const char* value) override;
+ virtual bool setParam(const ListType& v);
+ std::string getDefaultStr() const override;
+ std::string getValueStr() const override;
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ protected:
+ virtual bool decodeEntry(const char* entry, ValueType* out) const = 0;
+ virtual std::string encodeEntry(const ValueType& entry) const = 0;
+ virtual bool validateEntry(const ValueType& entry) const;
+ virtual ValueType normaliseEntry(const ValueType& entry) const;
+
+ protected:
+ ListType value;
+ ListType def_value;
+ };
+
+ class IntListParameter : public ListParameter<int> {
+ public:
+ IntListParameter(const char* name_, const char* desc_,
+ const ListType& v,
+ int minValue=INT_MIN, int maxValue=INT_MAX);
+ protected:
+ bool decodeEntry(const char* entry, int* out) const override;
+ std::string encodeEntry(const int& entry) const override;
+ bool validateEntry(const int& entry) const override;
+
+ protected:
+ int minValue, maxValue;
+ };
+
+ class StringListParameter : public ListParameter<std::string> {
+ public:
+ StringListParameter(const char* name_, const char* desc_,
+ const std::list<const char*>& v);
+
+ class const_iterator : public ListType::const_iterator {
+ public:
+ const_iterator(const ListType::const_iterator& it) : ListType::const_iterator(it) {}
+ const char* operator*() const { return (ListType::const_iterator::operator*()).c_str(); }
+ };
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ protected:
+ bool decodeEntry(const char* entry, std::string* out) const override;
+ std::string encodeEntry(const std::string& entry) const override;
+ };
+
+ class EnumListEntry {
+ public:
+ EnumListEntry(const std::string& v);
+ std::string getValueStr() const;
+ bool operator==(const char* other) const;
+ bool operator==(const std::string& other) const;
+ bool operator!=(const char* other) const;
+ bool operator!=(const std::string& other) const;
+ // operator const char*() omitted on purpose to force usage of above
+ // comparison operators
+ protected:
+ std::string value;
+ };
+
+ class EnumListParameter : public ListParameter<std::string> {
+ public:
+ EnumListParameter(const char* name_, const char* desc_,
+ const std::set<const char*>& enums,
+ const std::list<const char*>& v);
+
+ class const_iterator : public ListType::const_iterator {
+ public:
+ const_iterator(const ListType::const_iterator& it) : ListType::const_iterator(it) {}
+ const EnumListEntry operator*() const { return EnumListEntry(ListType::const_iterator::operator*()); }
+ const EnumListEntry operator->() const { return EnumListEntry(*ListType::const_iterator::operator->()); }
+ };
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ protected:
+ bool decodeEntry(const char* entry, std::string* out) const override;
+ std::string encodeEntry(const std::string& entry) const override;
+ bool validateEntry(const std::string& entry) const override;
+ std::string normaliseEntry(const std::string& entry) const override;
+
+ protected:
+ std::set<std::string> enums;
};
};
-#endif // __RFB_CONFIGURATION_H__
+#endif // __CORE_CONFIGURATION_H__
diff --git a/common/rdr/Exception.cxx b/common/core/Exception.cxx
index f0c04a6a..5b4f0599 100644
--- a/common/rdr/Exception.cxx
+++ b/common/core/Exception.cxx
@@ -26,9 +26,8 @@
#include <stdio.h>
#include <stdarg.h>
-#include <rdr/Exception.h>
-#include <rdr/TLSException.h>
-#include <rfb/util.h>
+#include <core/Exception.h>
+#include <core/string.h>
#ifdef _WIN32
#include <winsock2.h>
@@ -40,20 +39,20 @@
#include <string.h>
-using namespace rdr;
+using namespace core;
getaddrinfo_error::getaddrinfo_error(const char* s, int err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", s,
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", s,
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
getaddrinfo_error::getaddrinfo_error(const std::string& s,
int err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", s.c_str(),
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", s.c_str(),
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
@@ -73,15 +72,15 @@ std::string getaddrinfo_error::strerror(int err_) const noexcept
}
posix_error::posix_error(const char* what_arg, int err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", what_arg,
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", what_arg,
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
posix_error::posix_error(const std::string& what_arg, int err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", what_arg.c_str(),
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", what_arg.c_str(),
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
@@ -102,16 +101,16 @@ std::string posix_error::strerror(int err_) const noexcept
#ifdef WIN32
win32_error::win32_error(const char* what_arg, unsigned err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", what_arg,
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", what_arg,
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
win32_error::win32_error(const std::string& what_arg,
unsigned err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", what_arg.c_str(),
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", what_arg.c_str(),
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
diff --git a/common/rdr/Exception.h b/common/core/Exception.h
index d3cecc18..04463a17 100644
--- a/common/rdr/Exception.h
+++ b/common/core/Exception.h
@@ -19,13 +19,13 @@
* USA.
*/
-#ifndef __RDR_EXCEPTION_H__
-#define __RDR_EXCEPTION_H__
+#ifndef __CORE_EXCEPTION_H__
+#define __CORE_EXCEPTION_H__
#include <stdexcept>
#include <string>
-namespace rdr {
+namespace core {
class posix_error : public std::runtime_error {
public:
@@ -70,11 +70,6 @@ namespace rdr {
std::string strerror(int err_) const noexcept;
};
- class end_of_stream : public std::runtime_error {
- public:
- end_of_stream() noexcept : std::runtime_error("End of stream") {}
- };
-
}
#endif
diff --git a/common/rfb/LogWriter.cxx b/common/core/LogWriter.cxx
index 8e39d544..98e5201c 100644
--- a/common/rfb/LogWriter.cxx
+++ b/common/core/LogWriter.cxx
@@ -22,17 +22,16 @@
#include <config.h>
#endif
-#include <string.h>
-
-#include <rfb/LogWriter.h>
-#include <rfb/Configuration.h>
-#include <rfb/util.h>
#include <stdlib.h>
+#include <string.h>
-rfb::LogParameter rfb::logParams;
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
-using namespace rfb;
+using namespace core;
+LogParameter core::logParams;
LogWriter::LogWriter(const char* name)
: m_name(name), m_level(0), m_log(nullptr), m_next(log_writers) {
@@ -113,23 +112,23 @@ bool LogWriter::setLogParams(const char* params) {
LogParameter::LogParameter()
- : StringParameter("Log",
+ : StringListParameter("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())
+ if (!StringListParameter::setParam(v))
+ return false;
+ for (const char* part : *this) {
+ if (part[0] == '\0')
continue;
- if (!LogWriter::setLogParams(parts[i].c_str()))
+ if (!LogWriter::setLogParams(part))
return false;
}
return true;
diff --git a/common/rfb/LogWriter.h b/common/core/LogWriter.h
index d1fd4990..58dcc063 100644
--- a/common/rfb/LogWriter.h
+++ b/common/core/LogWriter.h
@@ -18,12 +18,13 @@
// -=- LogWriter.h - The Log writer class.
-#ifndef __RFB_LOG_WRITER_H__
-#define __RFB_LOG_WRITER_H__
+#ifndef __CORE_LOG_WRITER_H__
+#define __CORE_LOG_WRITER_H__
#include <stdarg.h>
-#include <rfb/Logger.h>
-#include <rfb/Configuration.h>
+
+#include <core/Configuration.h>
+#include <core/Logger.h>
// Each log writer instance has a unique textual name,
// and is attached to a particular Log instance and
@@ -46,9 +47,7 @@
} \
}
-namespace rfb {
-
- class LogWriter;
+namespace core {
class LogWriter {
public:
@@ -101,13 +100,15 @@ namespace rfb {
LogWriter* m_next;
};
- class LogParameter : public StringParameter {
+ class LogParameter : public StringListParameter {
public:
LogParameter();
bool setParam(const char* v) override;
+ // We explicitly don't inherit setParam(std::list) as we want to
+ // force callers to use the above method to parse the values
};
extern LogParameter logParams;
};
-#endif // __RFB_LOG_WRITER_H__
+#endif // __CORE_LOG_WRITER_H__
diff --git a/common/rfb/Logger.cxx b/common/core/Logger.cxx
index 25f7ccb7..ad9a3d63 100644
--- a/common/rfb/Logger.cxx
+++ b/common/core/Logger.cxx
@@ -26,10 +26,10 @@
#include <stdio.h>
#include <string.h>
-#include <rfb/Logger.h>
-#include <rfb/LogWriter.h>
+#include <core/Logger.h>
+#include <core/LogWriter.h>
-using namespace rfb;
+using namespace core;
Logger* Logger::loggers = nullptr;
diff --git a/common/rfb/Logger.h b/common/core/Logger.h
index 76f03535..5291915f 100644
--- a/common/rfb/Logger.h
+++ b/common/core/Logger.h
@@ -18,8 +18,8 @@
// -=- Logger.h - The Logger class.
-#ifndef __RFB_LOGGER_H__
-#define __RFB_LOGGER_H__
+#ifndef __CORE_LOGGER_H__
+#define __CORE_LOGGER_H__
#include <stdarg.h>
#include <stdio.h>
@@ -28,7 +28,7 @@
// and is attached to a particular Logger instance and
// is assigned a particular log level.
-namespace rfb {
+namespace core {
class Logger {
public:
@@ -68,4 +68,4 @@ namespace rfb {
};
-#endif // __RFB_LOGGER_H__
+#endif // __CORE_LOGGER_H__
diff --git a/common/rfb/Logger_file.cxx b/common/core/Logger_file.cxx
index eabe420a..b8c72270 100644
--- a/common/rfb/Logger_file.cxx
+++ b/common/core/Logger_file.cxx
@@ -26,30 +26,24 @@
#include <stdlib.h>
#include <string.h>
-#include <os/Mutex.h>
+#include <core/Logger_file.h>
-#include <rfb/Logger_file.h>
-
-using namespace rfb;
+using namespace core;
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;
@@ -121,7 +115,8 @@ void Logger_File::closeFile()
static Logger_File logger("file");
-bool rfb::initFileLogger(const char* filename) {
+bool core::initFileLogger(const char* filename)
+{
logger.setFilename(filename);
logger.registerLogger();
return true;
diff --git a/common/rfb/Logger_file.h b/common/core/Logger_file.h
index 6f2a4ef6..6bce3e2d 100644
--- a/common/rfb/Logger_file.h
+++ b/common/core/Logger_file.h
@@ -18,17 +18,15 @@
// -=- Logger_file - log to a file
-#ifndef __RFB_LOGGER_FILE_H__
-#define __RFB_LOGGER_FILE_H__
+#ifndef __CORE_LOGGER_FILE_H__
+#define __CORE_LOGGER_FILE_H__
#include <time.h>
#include <limits.h>
-#include <rfb/Logger.h>
+#include <core/Logger.h>
-namespace os { class Mutex; }
-
-namespace rfb {
+namespace core {
class Logger_File : public Logger {
public:
@@ -47,7 +45,6 @@ namespace rfb {
char m_filename[PATH_MAX];
FILE* m_file;
time_t m_lastLogTime;
- os::Mutex* mutex;
};
bool initFileLogger(const char* filename);
diff --git a/common/rfb/Logger_stdio.cxx b/common/core/Logger_stdio.cxx
index 5e5c6dea..f27fc35d 100644
--- a/common/rfb/Logger_stdio.cxx
+++ b/common/core/Logger_stdio.cxx
@@ -22,14 +22,15 @@
#include <config.h>
#endif
-#include <rfb/Logger_stdio.h>
+#include <core/Logger_stdio.h>
-using namespace rfb;
+using namespace core;
static Logger_StdIO logStdErr("stderr", stderr);
static Logger_StdIO logStdOut("stdout", stdout);
-bool rfb::initStdIOLoggers() {
+bool core::initStdIOLoggers()
+{
logStdErr.registerLogger();
logStdOut.registerLogger();
return true;
diff --git a/common/rfb/Logger_stdio.h b/common/core/Logger_stdio.h
index a1d17a0f..7613a20b 100644
--- a/common/rfb/Logger_stdio.h
+++ b/common/core/Logger_stdio.h
@@ -18,12 +18,12 @@
// -=- Logger_stdio - standard output logger instances
-#ifndef __RFB_LOGGER_STDIO_H__
-#define __RFB_LOGGER_STDIO_H__
+#ifndef __CORE_LOGGER_STDIO_H__
+#define __CORE_LOGGER_STDIO_H__
-#include <rfb/Logger_file.h>
+#include <core/Logger_file.h>
-namespace rfb {
+namespace core {
class Logger_StdIO : public Logger_File {
public:
diff --git a/common/rfb/Logger_syslog.cxx b/common/core/Logger_syslog.cxx
index de9e425e..cf7d065d 100644
--- a/common/rfb/Logger_syslog.cxx
+++ b/common/core/Logger_syslog.cxx
@@ -26,10 +26,10 @@
#include <string.h>
#include <syslog.h>
-#include <rfb/Logger_syslog.h>
-#include <rfb/LogWriter.h>
+#include <core/Logger_syslog.h>
+#include <core/LogWriter.h>
-using namespace rfb;
+using namespace core;
Logger_Syslog::Logger_Syslog(const char* loggerName)
@@ -62,6 +62,7 @@ void Logger_Syslog::write(int level, const char *logname, const char *message)
static Logger_Syslog logger("syslog");
-void rfb::initSyslogLogger() {
+void core::initSyslogLogger()
+{
logger.registerLogger();
}
diff --git a/common/rfb/Logger_syslog.h b/common/core/Logger_syslog.h
index 20c46a5f..46adf932 100644
--- a/common/rfb/Logger_syslog.h
+++ b/common/core/Logger_syslog.h
@@ -18,13 +18,14 @@
// -=- Logger_syslog - log to syslog
-#ifndef __RFB_LOGGER_SYSLOG_H__
-#define __RFB_LOGGER_SYSLOG_H__
+#ifndef __CORE_LOGGER_SYSLOG_H__
+#define __CORE_LOGGER_SYSLOG_H__
#include <time.h>
-#include <rfb/Logger.h>
-namespace rfb {
+#include <core/Logger.h>
+
+namespace core {
class Logger_Syslog : public Logger {
public:
diff --git a/common/rfb/Rect.h b/common/core/Rect.h
index b82ed274..e4cb1634 100644
--- a/common/rfb/Rect.h
+++ b/common/core/Rect.h
@@ -16,26 +16,16 @@
* USA.
*/
-// rfb::Rect and rfb::Point structures
+// core::Rect and core::Point structures
-#ifndef __RFB_RECT_INCLUDED__
-#define __RFB_RECT_INCLUDED__
+#ifndef __CORE_RECT_INCLUDED__
+#define __CORE_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.
+#include <algorithm>
-#ifndef __rfbmax
-#define __rfbmax(a,b) (((a) > (b)) ? (a) : (b))
-#endif
-#ifndef __rfbmin
-#define __rfbmin(a,b) (((a) < (b)) ? (a) : (b))
-#endif
+namespace core {
-namespace rfb {
-
- // rfb::Point
+ // core::Point
//
// Represents a point in 2D space, by X and Y coordinates.
// Can also be used to represent a delta, or offset, between
@@ -61,7 +51,7 @@ namespace rfb {
int x, y;
};
- // rfb::Rect
+ // core::Rect
//
// Represents a rectangular region defined by its top-left (tl)
// and bottom-right (br) Points.
@@ -83,10 +73,10 @@ namespace rfb {
__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);
+ result.tl.x = std::max(tl.x, r.tl.x);
+ result.tl.y = std::max(tl.y, r.tl.y);
+ result.br.x = std::max(std::min(br.x, r.br.x), result.tl.x);
+ result.br.y = std::max(std::min(br.y, r.br.y), result.tl.y);
return result;
}
inline Rect union_boundary(const Rect &r) const
@@ -95,10 +85,10 @@ namespace rfb {
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);
+ result.tl.x = std::min(tl.x, r.tl.x);
+ result.tl.y = std::min(tl.y, r.tl.y);
+ result.br.x = std::max(br.x, r.br.x);
+ result.br.y = std::max(br.y, r.br.y);
return result;
}
inline Rect translate(const Point &p) const
@@ -127,4 +117,4 @@ namespace rfb {
Point br;
};
}
-#endif // __RFB_RECT_INCLUDED__
+#endif // __CORE_RECT_INCLUDED__
diff --git a/common/rfb/Region.cxx b/common/core/Region.cxx
index cfdf0ca2..03d788a9 100644
--- a/common/rfb/Region.cxx
+++ b/common/core/Region.cxx
@@ -21,100 +21,119 @@
#include <config.h>
#endif
-#include <rfb/Region.h>
-#include <rfb/LogWriter.h>
+#include <core/LogWriter.h>
+#include <core/Region.h>
extern "C" {
#include <pixman.h>
}
-static rfb::LogWriter vlog("Region");
+using namespace core;
-rfb::Region::Region() {
+static LogWriter vlog("Region");
+
+Region::Region()
+{
rgn = new struct pixman_region16;
pixman_region_init(rgn);
}
-rfb::Region::Region(const Rect& r) {
+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) {
+Region::Region(const Region& r)
+{
rgn = new struct pixman_region16;
pixman_region_init(rgn);
pixman_region_copy(rgn, r.rgn);
}
-rfb::Region::~Region() {
+Region::~Region()
+{
pixman_region_fini(rgn);
delete rgn;
}
-rfb::Region& rfb::Region::operator=(const rfb::Region& r) {
+Region& Region::operator=(const Region& r)
+{
pixman_region_copy(rgn, r.rgn);
return *this;
}
-void rfb::Region::clear() {
+void 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) {
+void 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) {
+void Region::translate(const Point& delta)
+{
pixman_region_translate(rgn, delta.x, delta.y);
}
-void rfb::Region::assign_intersect(const rfb::Region& r) {
+void Region::assign_intersect(const Region& r)
+{
pixman_region_intersect(rgn, rgn, r.rgn);
}
-void rfb::Region::assign_union(const rfb::Region& r) {
+void Region::assign_union(const Region& r)
+{
pixman_region_union(rgn, rgn, r.rgn);
}
-void rfb::Region::assign_subtract(const rfb::Region& r) {
+void Region::assign_subtract(const Region& r)
+{
pixman_region_subtract(rgn, rgn, r.rgn);
}
-rfb::Region rfb::Region::intersect(const rfb::Region& r) const {
- rfb::Region ret;
+Region Region::intersect(const Region& r) const
+{
+ 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;
+Region Region::union_(const Region& r) const
+{
+ 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;
+Region Region::subtract(const Region& r) const
+{
+ Region ret;
pixman_region_subtract(ret.rgn, rgn, r.rgn);
return ret;
}
-bool rfb::Region::operator==(const rfb::Region& r) const {
+bool Region::operator==(const Region& r) const
+{
return pixman_region_equal(rgn, r.rgn);
}
-bool rfb::Region::operator!=(const rfb::Region& r) const {
+bool Region::operator!=(const Region& r) const
+{
return !pixman_region_equal(rgn, r.rgn);
}
-int rfb::Region::numRects() const {
+int Region::numRects() const
+{
return pixman_region_n_rects(rgn);
}
-bool rfb::Region::get_rects(std::vector<Rect>* rects,
- bool left2right, bool topdown) const
+bool Region::get_rects(std::vector<Rect>* rects,
+ bool left2right, bool topdown) const
{
int nRects;
const pixman_box16_t* boxes;
@@ -156,14 +175,15 @@ bool rfb::Region::get_rects(std::vector<Rect>* rects,
return !rects->empty();
}
-rfb::Rect rfb::Region::get_bounding_rect() const {
+Rect 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
+void Region::debug_print(const char* prefix) const
{
Rect extents;
std::vector<Rect> rects;
diff --git a/common/rfb/Region.h b/common/core/Region.h
index 38de67ce..729f1475 100644
--- a/common/rfb/Region.h
+++ b/common/core/Region.h
@@ -19,15 +19,19 @@
// Region class wrapper around pixman's region operations
-#ifndef __RFB_REGION_INCLUDED__
-#define __RFB_REGION_INCLUDED__
+#ifndef __CORE_REGION_INCLUDED__
+#define __CORE_REGION_INCLUDED__
-#include <rfb/Rect.h>
#include <vector>
+#include <core/Rect.h>
+
struct pixman_region16;
-namespace rfb {
+namespace core {
+
+ struct Point;
+ struct Rect;
class Region {
public:
@@ -45,7 +49,7 @@ namespace rfb {
void clear();
void reset(const Rect& r);
- void translate(const rfb::Point& delta);
+ void translate(const Point& delta);
void assign_intersect(const Region& r);
void assign_union(const Region& r);
@@ -78,4 +82,4 @@ namespace rfb {
};
-#endif // __RFB_REGION_INCLUDED__
+#endif // __CORE_REGION_INCLUDED__
diff --git a/common/rfb/Timer.cxx b/common/core/Timer.cxx
index 6f7ec7ba..77e98daf 100644
--- a/common/rfb/Timer.cxx
+++ b/common/core/Timer.cxx
@@ -28,38 +28,16 @@
#include <algorithm>
-#include <rfb/Timer.h>
-#include <rfb/util.h>
-#include <rfb/LogWriter.h>
+#include <core/LogWriter.h>
+#include <core/Timer.h>
+#include <core/time.h>
-using namespace rfb;
+using namespace core;
#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() {
@@ -167,9 +145,7 @@ int Timer::getTimeoutMs() {
}
int Timer::getRemainingMs() {
- timeval now;
- gettimeofday(&now, nullptr);
- return __rfbmax(0, diffTimeMillis(dueTime, now));
+ return msUntil(&dueTime);
}
bool Timer::isBefore(timeval other) {
diff --git a/common/rfb/Timer.h b/common/core/Timer.h
index 362cb84e..cde672b2 100644
--- a/common/rfb/Timer.h
+++ b/common/core/Timer.h
@@ -17,13 +17,13 @@
* USA.
*/
-#ifndef __RFB_TIMER_H__
-#define __RFB_TIMER_H__
+#ifndef __CORE_TIMER_H__
+#define __CORE_TIMER_H__
#include <list>
#include <sys/time.h>
-namespace rfb {
+namespace core {
/* Timer
diff --git a/common/rfb/util.cxx b/common/core/string.cxx
index 3c62b1df..091836db 100644
--- a/common/rfb/util.cxx
+++ b/common/core/string.cxx
@@ -26,11 +26,10 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
-#include <sys/time.h>
-#include <rfb/util.h>
+#include <core/string.h>
-namespace rfb {
+namespace core {
std::string format(const char *fmt, ...)
{
@@ -65,6 +64,9 @@ namespace rfb {
std::vector<std::string> out;
const char *start, *stop;
+ if (src[0] == '\0')
+ return out;
+
start = src;
do {
stop = strchr(start, delimiter);
@@ -604,40 +606,6 @@ namespace rfb {
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) {
diff --git a/common/rfb/util.h b/common/core/string.h
index b47ac4c9..1465484d 100644
--- a/common/rfb/util.h
+++ b/common/core/string.h
@@ -18,21 +18,18 @@
*/
//
-// util.h - miscellaneous useful bits
+// string.h - string utility functions
//
-#ifndef __RFB_UTIL_H__
-#define __RFB_UTIL_H__
+#ifndef __CORE_STRING_H__
+#define __CORE_STRING_H__
-#include <limits.h>
#include <stdint.h>
#include <string>
#include <vector>
-struct timeval;
-
-namespace rfb {
+namespace core {
// Formats according to printf(), with a dynamic allocation
std::string format(const char *fmt, ...)
@@ -71,24 +68,8 @@ namespace rfb {
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);
+ // Convert a value to a string using the correct prefix to reduce
+ // the length of the string
std::string siPrefix(long long value, const char *unit,
int precision=6);
@@ -96,16 +77,4 @@ namespace rfb {
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
diff --git a/common/core/time.cxx b/common/core/time.cxx
new file mode 100644
index 00000000..47a0ff8a
--- /dev/null
+++ b/common/core/time.cxx
@@ -0,0 +1,88 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-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 <stddef.h>
+#include <sys/time.h>
+
+#include <core/time.h>
+
+namespace core {
+
+ unsigned msBetween(const struct timeval *first,
+ const struct timeval *second)
+ {
+ unsigned udiff;
+
+ if (isBefore(second, first))
+ return 0;
+
+ udiff = (second->tv_sec - first->tv_sec) * 1000000 +
+ (second->tv_usec - first->tv_usec);
+
+ return (udiff + 999) / 1000;
+ }
+
+ unsigned msSince(const struct timeval *then)
+ {
+ struct timeval now;
+
+ gettimeofday(&now, nullptr);
+
+ return msBetween(then, &now);
+ }
+
+ unsigned msUntil(const struct timeval *then)
+ {
+ struct timeval now;
+
+ gettimeofday(&now, nullptr);
+
+ return msBetween(&now, then);
+ }
+
+ 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;
+ }
+
+ struct timeval addMillis(struct 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;
+ }
+
+}
diff --git a/common/core/time.h b/common/core/time.h
new file mode 100644
index 00000000..319f336f
--- /dev/null
+++ b/common/core/time.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-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.
+ */
+
+//
+// time.h - time helper functions
+//
+
+#ifndef __CORE_TIME_H__
+#define __CORE_TIME_H__
+
+#include <limits.h>
+
+struct timeval;
+
+namespace core {
+
+ // 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 time until the given moment in milliseconds.
+ unsigned msUntil(const struct timeval *then);
+
+ // Returns true if first happened before seconds
+ bool isBefore(const struct timeval *first,
+ const struct timeval *second);
+
+ // Returns a new timeval a specified number of milliseconds later than
+ // the given timeval
+ struct timeval addMillis(struct timeval inTime, int millis);
+}
+
+#endif
diff --git a/common/os/winerrno.h b/common/core/winerrno.h
index a81fdc94..a81fdc94 100644
--- a/common/os/winerrno.h
+++ b/common/core/winerrno.h
diff --git a/common/os/os.cxx b/common/core/xdgdirs.cxx
index 2ac70550..2628f317 100644
--- a/common/os/os.cxx
+++ b/common/core/xdgdirs.cxx
@@ -21,8 +21,6 @@
#include <config.h>
#endif
-#include <os/os.h>
-
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
@@ -43,6 +41,8 @@
#define mkdir(path, mode) mkdir(path)
#endif
+#include <core/xdgdirs.h>
+
static const char* getvncdir(bool userDir, const char *xdg_env, const char *xdg_def)
{
static char dir[PATH_MAX], legacy[PATH_MAX];
@@ -109,27 +109,27 @@ static const char* getvncdir(bool userDir, const char *xdg_env, const char *xdg_
return (stat(dir, &st) != 0 && stat(legacy, &st) == 0) ? legacy : dir;
}
-const char* os::getuserhomedir()
+const char* core::getuserhomedir()
{
return getvncdir(true, nullptr, nullptr);
}
-const char* os::getvncconfigdir()
+const char* core::getvncconfigdir()
{
return getvncdir(false, "XDG_CONFIG_HOME", ".config");
}
-const char* os::getvncdatadir()
+const char* core::getvncdatadir()
{
return getvncdir(false, "XDG_DATA_HOME", ".local/share");
}
-const char* os::getvncstatedir()
+const char* core::getvncstatedir()
{
return getvncdir(false, "XDG_STATE_HOME", ".local/state");
}
-int os::mkdir_p(const char *path_, mode_t mode)
+int core::mkdir_p(const char *path_, mode_t mode)
{
char *path = strdup(path_);
char *p;
diff --git a/common/os/os.h b/common/core/xdgdirs.h
index a3448070..0769ba8b 100644
--- a/common/os/os.h
+++ b/common/core/xdgdirs.h
@@ -17,12 +17,12 @@
* USA.
*/
-#ifndef OS_OS_H
-#define OS_OS_H
+#ifndef CORE_XDGDIRS_H
+#define CORE_XDGDIRS_H
#include <sys/stat.h>
-namespace os {
+namespace core {
/*
* Get user home directory.
@@ -71,4 +71,4 @@ namespace os {
int mkdir_p(const char *path, mode_t mode);
}
-#endif /* OS_OS_H */
+#endif /* CORE_XDGDIRS_H */
diff --git a/common/network/CMakeLists.txt b/common/network/CMakeLists.txt
index f08eaa31..42472b8d 100644
--- a/common/network/CMakeLists.txt
+++ b/common/network/CMakeLists.txt
@@ -7,7 +7,7 @@ if(NOT WIN32)
endif()
target_include_directories(network PUBLIC ${CMAKE_SOURCE_DIR}/common)
-target_link_libraries(network os rdr rfb)
+target_link_libraries(network core rdr)
if(WIN32)
target_link_libraries(network ws2_32)
diff --git a/common/network/Socket.cxx b/common/network/Socket.cxx
index 49abbc84..7fc39d1e 100644
--- a/common/network/Socket.cxx
+++ b/common/network/Socket.cxx
@@ -32,22 +32,23 @@
#define errorNumber errno
#define closesocket close
#include <sys/socket.h>
-#endif
-
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
+#endif
-#include <rdr/Exception.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
-#include <network/Socket.h>
+#include <rdr/FdInStream.h>
+#include <rdr/FdOutStream.h>
-#include <rfb/LogWriter.h>
+#include <network/Socket.h>
using namespace network;
-static rfb::LogWriter vlog("Socket");
+static core::LogWriter vlog("Socket");
// -=- Socket initialisation
static bool socketsInitialised = false;
@@ -59,7 +60,7 @@ void network::initSockets() {
WSADATA initResult;
if (WSAStartup(requiredVersion, &initResult) != 0)
- throw rdr::socket_error("Unable to initialise Winsock2", errorNumber);
+ throw core::socket_error("Unable to initialise Winsock2", errorNumber);
#else
signal(SIGPIPE, SIG_IGN);
#endif
@@ -99,6 +100,11 @@ Socket::~Socket()
delete outstream;
}
+int Socket::getFd()
+{
+ return outstream->getFd();
+}
+
// if shutdown() is overridden then the override MUST call on to here
void Socket::shutdown()
{
@@ -114,7 +120,7 @@ void Socket::shutdown()
}
isShutdown_ = true;
- ::shutdown(getFd(), SHUT_RDWR);
+ ::shutdown(getFd(), SHUT_WR);
}
bool Socket::isShutdown() const
@@ -122,6 +128,11 @@ bool Socket::isShutdown() const
return isShutdown_;
}
+void Socket::cork(bool enable)
+{
+ outstream->cork(enable);
+}
+
// Was there a "?" in the ConnectionFilter used to accept this Socket?
void Socket::setRequiresQuery()
{
@@ -178,7 +189,7 @@ Socket* SocketListener::accept() {
// Accept an incoming connection
if ((new_sock = ::accept(fd, nullptr, nullptr)) < 0)
- throw rdr::socket_error("Unable to accept new connection", errorNumber);
+ throw core::socket_error("Unable to accept new connection", errorNumber);
// Create the socket object & check connection is allowed
Socket* s = createSocket(new_sock);
@@ -196,7 +207,7 @@ void SocketListener::listen(int sock)
if (::listen(sock, 5) < 0) {
int e = errorNumber;
closesocket(sock);
- throw rdr::socket_error("Unable to set socket to listening mode", e);
+ throw core::socket_error("Unable to set socket to listening mode", e);
}
fd = sock;
diff --git a/common/network/Socket.h b/common/network/Socket.h
index 34b8db8e..f1688c72 100644
--- a/common/network/Socket.h
+++ b/common/network/Socket.h
@@ -24,8 +24,11 @@
#include <list>
#include <limits.h>
-#include <rdr/FdInStream.h>
-#include <rdr/FdOutStream.h>
+
+namespace rdr {
+ class FdInStream;
+ class FdOutStream;
+}
namespace network {
@@ -40,12 +43,12 @@ namespace network {
rdr::FdInStream &inStream() {return *instream;}
rdr::FdOutStream &outStream() {return *outstream;}
- int getFd() {return outstream->getFd();}
+ int getFd();
void shutdown();
bool isShutdown() const;
- void cork(bool enable) { outstream->cork(enable); }
+ void cork(bool enable);
// information about the remote end of the socket
virtual const char* getPeerAddress() = 0; // a string e.g. "192.168.0.1"
diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx
index c5b86543..bf3a224c 100644
--- a/common/network/TcpSocket.cxx
+++ b/common/network/TcpSocket.cxx
@@ -35,19 +35,21 @@
#include <errno.h>
#endif
+#include <assert.h>
+#include <ctype.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
-#include <rdr/Exception.h>
+#include <core/Configuration.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
#include <network/TcpSocket.h>
-#include <rfb/LogWriter.h>
-#include <rfb/Configuration.h>
-#include <rfb/util.h>
-
#ifdef WIN32
-#include <os/winerrno.h>
+#include <core/winerrno.h>
#endif
#ifndef INADDR_NONE
@@ -68,12 +70,11 @@
#endif
using namespace network;
-using namespace rdr;
-static rfb::LogWriter vlog("TcpSocket");
+static core::LogWriter vlog("TcpSocket");
-static rfb::BoolParameter UseIPv4("UseIPv4", "Use IPv4 for incoming and outgoing connections.", true);
-static rfb::BoolParameter UseIPv6("UseIPv6", "Use IPv6 for incoming and outgoing connections.", true);
+static core::BoolParameter UseIPv4("UseIPv4", "Use IPv4 for incoming and outgoing connections.", true);
+static core::BoolParameter UseIPv6("UseIPv6", "Use IPv6 for incoming and outgoing connections.", true);
/* Tunnelling support. */
int network::findFreeTcpPort (void)
@@ -85,20 +86,105 @@ int network::findFreeTcpPort (void)
addr.sin_addr.s_addr = INADDR_ANY;
if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
- throw socket_error("Unable to create socket", errorNumber);
+ throw core::socket_error("Unable to create socket", errorNumber);
addr.sin_port = 0;
if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0)
- throw socket_error("Unable to find free port", errorNumber);
+ throw core::socket_error("Unable to find free port", errorNumber);
socklen_t n = sizeof(addr);
if (getsockname (sock, (struct sockaddr *)&addr, &n) < 0)
- throw socket_error("Unable to get port number", errorNumber);
+ throw core::socket_error("Unable to get port number", errorNumber);
closesocket (sock);
return ntohs(addr.sin_port);
}
+static bool isAllSpace(const char *string) {
+ if (string == nullptr)
+ return false;
+ while(*string != '\0') {
+ if (! isspace(*string))
+ return false;
+ string++;
+ }
+ return true;
+}
+
+void network::getHostAndPort(const char* hi, std::string* host,
+ int* port, int basePort)
+{
+ 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;
+ }
+}
+
int network::getSockPort(int sock)
{
vnc_sockaddr_t sa;
@@ -137,7 +223,7 @@ TcpSocket::TcpSocket(const char *host, int port)
hints.ai_next = nullptr;
if ((result = getaddrinfo(host, nullptr, &hints, &ai)) != 0) {
- throw getaddrinfo_error("Unable to resolve host by name", result);
+ throw core::getaddrinfo_error("Unable to resolve host by name", result);
}
sock = -1;
@@ -178,7 +264,7 @@ TcpSocket::TcpSocket(const char *host, int port)
if (sock == -1) {
err = errorNumber;
freeaddrinfo(ai);
- throw socket_error("Unable to create socket", err);
+ throw core::socket_error("Unable to create socket", err);
}
/* Attempt to connect to the remote host */
@@ -205,7 +291,7 @@ TcpSocket::TcpSocket(const char *host, int port)
if (err == 0)
throw std::runtime_error("No useful address for host");
else
- throw socket_error("Unable to connect to socket", err);
+ throw core::socket_error("Unable to connect to socket", err);
}
// Take proper ownership of the socket
@@ -302,7 +388,7 @@ TcpListener::TcpListener(const struct sockaddr *listenaddr,
int sock;
if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0)
- throw socket_error("Unable to create listening socket", errorNumber);
+ throw core::socket_error("Unable to create listening socket", errorNumber);
memcpy (&sa, listenaddr, listenaddrlen);
#ifdef IPV6_V6ONLY
@@ -310,7 +396,7 @@ TcpListener::TcpListener(const struct sockaddr *listenaddr,
if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one))) {
int e = errorNumber;
closesocket(sock);
- throw socket_error("Unable to set IPV6_V6ONLY", e);
+ throw core::socket_error("Unable to set IPV6_V6ONLY", e);
}
}
#endif /* defined(IPV6_V6ONLY) */
@@ -328,14 +414,14 @@ TcpListener::TcpListener(const struct sockaddr *listenaddr,
(char *)&one, sizeof(one)) < 0) {
int e = errorNumber;
closesocket(sock);
- throw socket_error("Unable to create listening socket", e);
+ throw core::socket_error("Unable to create listening socket", e);
}
#endif
if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
int e = errorNumber;
closesocket(sock);
- throw socket_error("Failed to bind socket", e);
+ throw core::socket_error("Failed to bind socket", e);
}
listen(sock);
@@ -446,7 +532,7 @@ void network::createTcpListeners(std::list<SocketListener*> *listeners,
snprintf (service, sizeof (service) - 1, "%d", port);
service[sizeof (service) - 1] = '\0';
if ((result = getaddrinfo(addr, service, &hints, &ai)) != 0)
- throw getaddrinfo_error("Unable to resolve listening address", result);
+ throw core::getaddrinfo_error("Unable to resolve listening address", result);
try {
createTcpListeners(listeners, ai);
@@ -485,7 +571,7 @@ void network::createTcpListeners(std::list<SocketListener*> *listeners,
try {
new_listeners.push_back(new TcpListener(current->ai_addr,
current->ai_addrlen));
- } catch (socket_error& e) {
+ } catch (core::socket_error& e) {
// Ignore this if it is due to lack of address family support on
// the interface or on the system
if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
@@ -506,7 +592,7 @@ void network::createTcpListeners(std::list<SocketListener*> *listeners,
TcpFilter::TcpFilter(const char* spec) {
std::vector<std::string> patterns;
- patterns = rfb::split(spec, ',');
+ patterns = core::split(spec, ',');
for (size_t i = 0; i < patterns.size(); i++) {
if (!patterns[i].empty())
@@ -608,11 +694,11 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
initSockets();
- parts = rfb::split(&p[1], '/');
+ parts = core::split(&p[1], '/');
if (parts.size() > 2)
throw std::invalid_argument("Invalid filter specified");
- if (parts[0].empty()) {
+ if (parts.empty() || parts[0].empty()) {
// Match any address
memset (&pattern.address, 0, sizeof (pattern.address));
pattern.address.u.sa.sa_family = AF_UNSPEC;
@@ -633,7 +719,7 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
}
if ((result = getaddrinfo (parts[0].c_str(), nullptr, &hints, &ai)) != 0) {
- throw getaddrinfo_error("Unable to resolve host by name", result);
+ throw core::getaddrinfo_error("Unable to resolve host by name", result);
}
memcpy (&pattern.address.u.sa, ai->ai_addr, ai->ai_addrlen);
@@ -666,9 +752,9 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
family = pattern.address.u.sa.sa_family;
if (pattern.prefixlen > (family == AF_INET ? 32: 128))
- throw std::invalid_argument(rfb::format("Invalid prefix length for "
- "filter address: %u",
- pattern.prefixlen));
+ throw std::invalid_argument(
+ core::format("Invalid prefix length for filter address: %u",
+ pattern.prefixlen));
// Compute mask from address and prefix length
memset (&pattern.mask, 0, sizeof (pattern.mask));
diff --git a/common/network/TcpSocket.h b/common/network/TcpSocket.h
index b029bff2..17854e10 100644
--- a/common/network/TcpSocket.h
+++ b/common/network/TcpSocket.h
@@ -49,6 +49,9 @@ namespace network {
/* Tunnelling support. */
int findFreeTcpPort (void);
+ void getHostAndPort(const char* hi, std::string* host,
+ int* port, int basePort=5900);
+
int getSockPort(int sock);
class TcpSocket : public Socket {
diff --git a/common/network/UnixSocket.cxx b/common/network/UnixSocket.cxx
index 48561245..9691cb23 100644
--- a/common/network/UnixSocket.cxx
+++ b/common/network/UnixSocket.cxx
@@ -28,17 +28,16 @@
#include <errno.h>
#include <stdlib.h>
#include <stddef.h>
+#include <string.h>
-#include <rdr/Exception.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
#include <network/UnixSocket.h>
-#include <rfb/LogWriter.h>
-
using namespace network;
-using namespace rdr;
-static rfb::LogWriter vlog("UnixSocket");
+static core::LogWriter vlog("UnixSocket");
// -=- UnixSocket
@@ -53,12 +52,12 @@ UnixSocket::UnixSocket(const char *path)
socklen_t salen;
if (strlen(path) >= sizeof(addr.sun_path))
- throw socket_error("Socket path is too long", ENAMETOOLONG);
+ throw core::socket_error("Socket path is too long", ENAMETOOLONG);
// - Create a socket
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock == -1)
- throw socket_error("Unable to create socket", errno);
+ throw core::socket_error("Unable to create socket", errno);
// - Attempt to connect
memset(&addr, 0, sizeof(addr));
@@ -72,7 +71,7 @@ UnixSocket::UnixSocket(const char *path)
}
if (result == -1)
- throw socket_error("Unable to connect to socket", err);
+ throw core::socket_error("Unable to connect to socket", err);
setFd(sock);
}
@@ -119,11 +118,11 @@ UnixListener::UnixListener(const char *path, int mode)
int err, result;
if (strlen(path) >= sizeof(addr.sun_path))
- throw socket_error("Socket path is too long", ENAMETOOLONG);
+ throw core::socket_error("Socket path is too long", ENAMETOOLONG);
// - Create a socket
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
- throw socket_error("Unable to create listening socket", errno);
+ throw core::socket_error("Unable to create listening socket", errno);
// - Delete existing socket (ignore result)
unlink(path);
@@ -138,14 +137,14 @@ UnixListener::UnixListener(const char *path, int mode)
umask(saved_umask);
if (result < 0) {
close(fd);
- throw socket_error("Unable to bind listening socket", err);
+ throw core::socket_error("Unable to bind listening socket", err);
}
// - Set socket mode
if (chmod(path, mode) < 0) {
err = errno;
close(fd);
- throw socket_error("Unable to set socket mode", err);
+ throw core::socket_error("Unable to set socket mode", err);
}
listen(fd);
diff --git a/common/os/CMakeLists.txt b/common/os/CMakeLists.txt
deleted file mode 100644
index 2573d088..00000000
--- a/common/os/CMakeLists.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-add_library(os STATIC
- Mutex.cxx
- Thread.cxx
- os.cxx)
-
-target_include_directories(os PUBLIC ${CMAKE_SOURCE_DIR}/common)
-target_link_libraries(os rdr)
-
-if(UNIX)
- target_link_libraries(os pthread)
-endif()
-
-if(UNIX)
- libtool_create_control_file(os)
-endif()
diff --git a/common/os/Mutex.cxx b/common/os/Mutex.cxx
deleted file mode 100644
index 1889e66b..00000000
--- a/common/os/Mutex.cxx
+++ /dev/null
@@ -1,158 +0,0 @@
-/* Copyright 2015 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
-
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <pthread.h>
-#endif
-
-#include <rdr/Exception.h>
-
-#include <os/Mutex.h>
-
-using namespace os;
-
-Mutex::Mutex()
-{
-#ifdef WIN32
- systemMutex = new CRITICAL_SECTION;
- InitializeCriticalSection((CRITICAL_SECTION*)systemMutex);
-#else
- int ret;
-
- systemMutex = new pthread_mutex_t;
- ret = pthread_mutex_init((pthread_mutex_t*)systemMutex, nullptr);
- if (ret != 0)
- throw rdr::posix_error("Failed to create mutex", ret);
-#endif
-}
-
-Mutex::~Mutex()
-{
-#ifdef WIN32
- DeleteCriticalSection((CRITICAL_SECTION*)systemMutex);
- delete (CRITICAL_SECTION*)systemMutex;
-#else
- pthread_mutex_destroy((pthread_mutex_t*)systemMutex);
- delete (pthread_mutex_t*)systemMutex;
-#endif
-}
-
-void Mutex::lock()
-{
-#ifdef WIN32
- EnterCriticalSection((CRITICAL_SECTION*)systemMutex);
-#else
- int ret;
-
- ret = pthread_mutex_lock((pthread_mutex_t*)systemMutex);
- if (ret != 0)
- throw rdr::posix_error("Failed to lock mutex", ret);
-#endif
-}
-
-void Mutex::unlock()
-{
-#ifdef WIN32
- LeaveCriticalSection((CRITICAL_SECTION*)systemMutex);
-#else
- int ret;
-
- ret = pthread_mutex_unlock((pthread_mutex_t*)systemMutex);
- if (ret != 0)
- throw rdr::posix_error("Failed to unlock mutex", ret);
-#endif
-}
-
-Condition::Condition(Mutex* mutex_)
-{
- this->mutex = mutex_;
-
-#ifdef WIN32
- systemCondition = new CONDITION_VARIABLE;
- InitializeConditionVariable((CONDITION_VARIABLE*)systemCondition);
-#else
- int ret;
-
- systemCondition = new pthread_cond_t;
- ret = pthread_cond_init((pthread_cond_t*)systemCondition, nullptr);
- if (ret != 0)
- throw rdr::posix_error("Failed to create condition variable", ret);
-#endif
-}
-
-Condition::~Condition()
-{
-#ifdef WIN32
- delete (CONDITION_VARIABLE*)systemCondition;
-#else
- pthread_cond_destroy((pthread_cond_t*)systemCondition);
- delete (pthread_cond_t*)systemCondition;
-#endif
-}
-
-void Condition::wait()
-{
-#ifdef WIN32
- BOOL ret;
-
- ret = SleepConditionVariableCS((CONDITION_VARIABLE*)systemCondition,
- (CRITICAL_SECTION*)mutex->systemMutex,
- INFINITE);
- if (!ret)
- throw rdr::win32_error("Failed to wait on condition variable", GetLastError());
-#else
- int ret;
-
- ret = pthread_cond_wait((pthread_cond_t*)systemCondition,
- (pthread_mutex_t*)mutex->systemMutex);
- if (ret != 0)
- throw rdr::posix_error("Failed to wait on condition variable", ret);
-#endif
-}
-
-void Condition::signal()
-{
-#ifdef WIN32
- WakeConditionVariable((CONDITION_VARIABLE*)systemCondition);
-#else
- int ret;
-
- ret = pthread_cond_signal((pthread_cond_t*)systemCondition);
- if (ret != 0)
- throw rdr::posix_error("Failed to signal condition variable", ret);
-#endif
-}
-
-void Condition::broadcast()
-{
-#ifdef WIN32
- WakeAllConditionVariable((CONDITION_VARIABLE*)systemCondition);
-#else
- int ret;
-
- ret = pthread_cond_broadcast((pthread_cond_t*)systemCondition);
- if (ret != 0)
- throw rdr::posix_error("Failed to broadcast condition variable", ret);
-#endif
-}
diff --git a/common/os/Mutex.h b/common/os/Mutex.h
deleted file mode 100644
index 63c7e0cc..00000000
--- a/common/os/Mutex.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Copyright 2015 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 __OS_MUTEX_H__
-#define __OS_MUTEX_H__
-
-namespace os {
- class Condition;
-
- class Mutex {
- public:
- Mutex();
- ~Mutex();
-
- void lock();
- void unlock();
-
- private:
- friend class Condition;
-
- void* systemMutex;
- };
-
- class AutoMutex {
- public:
- AutoMutex(Mutex* mutex) { m = mutex; m->lock(); }
- ~AutoMutex() { m->unlock(); }
- private:
- Mutex* m;
- };
-
- class Condition {
- public:
- Condition(Mutex* mutex);
- ~Condition();
-
- void wait();
-
- void signal();
- void broadcast();
-
- private:
- Mutex* mutex;
- void* systemCondition;
- };
-
-}
-
-#endif
diff --git a/common/os/Thread.cxx b/common/os/Thread.cxx
deleted file mode 100644
index 6dca75a1..00000000
--- a/common/os/Thread.cxx
+++ /dev/null
@@ -1,173 +0,0 @@
-/* Copyright 2015 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
-
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <pthread.h>
-#include <signal.h>
-#include <unistd.h>
-#endif
-
-#include <rdr/Exception.h>
-
-#include <os/Mutex.h>
-#include <os/Thread.h>
-
-using namespace os;
-
-Thread::Thread() : running(false), threadId(nullptr)
-{
- mutex = new Mutex;
-
-#ifdef WIN32
- threadId = new HANDLE;
-#else
- threadId = new pthread_t;
-#endif
-}
-
-Thread::~Thread()
-{
-#ifdef WIN32
- delete (HANDLE*)threadId;
-#else
- if (isRunning())
- pthread_cancel(*(pthread_t*)threadId);
- delete (pthread_t*)threadId;
-#endif
-
- delete mutex;
-}
-
-void Thread::start()
-{
- AutoMutex a(mutex);
-
-#ifdef WIN32
- *(HANDLE*)threadId = CreateThread(nullptr, 0, startRoutine, this, 0, nullptr);
- if (*(HANDLE*)threadId == nullptr)
- throw rdr::win32_error("Failed to create thread", GetLastError());
-#else
- int ret;
- sigset_t all, old;
-
- // Creating threads from libraries is a bit evil, so mitigate the
- // issue by at least avoiding signals on these threads
- sigfillset(&all);
- ret = pthread_sigmask(SIG_SETMASK, &all, &old);
- if (ret != 0)
- throw rdr::posix_error("Failed to mask signals", ret);
-
- ret = pthread_create((pthread_t*)threadId, nullptr, startRoutine, this);
-
- pthread_sigmask(SIG_SETMASK, &old, nullptr);
-
- if (ret != 0)
- throw rdr::posix_error("Failed to create thread", ret);
-#endif
-
- running = true;
-}
-
-void Thread::wait()
-{
- if (!isRunning())
- return;
-
-#ifdef WIN32
- DWORD ret;
-
- ret = WaitForSingleObject(*(HANDLE*)threadId, INFINITE);
- if (ret != WAIT_OBJECT_0)
- throw rdr::win32_error("Failed to join thread", GetLastError());
-#else
- int ret;
-
- ret = pthread_join(*(pthread_t*)threadId, nullptr);
- if (ret != 0)
- throw rdr::posix_error("Failed to join thread", ret);
-#endif
-}
-
-bool Thread::isRunning()
-{
- AutoMutex a(mutex);
-
- return running;
-}
-
-size_t Thread::getSystemCPUCount()
-{
-#ifdef WIN32
- SYSTEM_INFO si;
- size_t count;
- DWORD mask;
-
- GetSystemInfo(&si);
-
- count = 0;
- for (mask = si.dwActiveProcessorMask;mask != 0;mask >>= 1) {
- if (mask & 0x1)
- count++;
- }
-
- if (count > si.dwNumberOfProcessors)
- count = si.dwNumberOfProcessors;
-
- return count;
-#else
- long ret;
-
- ret = sysconf(_SC_NPROCESSORS_ONLN);
- if (ret == -1)
- return 0;
-
- return ret;
-#endif
-}
-
-#ifdef WIN32
-long unsigned __stdcall Thread::startRoutine(void* data)
-#else
-void* Thread::startRoutine(void* data)
-#endif
-{
- Thread *self;
-
- self = (Thread*)data;
-
- try {
- self->worker();
- } catch(...) {
- }
-
- self->mutex->lock();
- self->running = false;
- self->mutex->unlock();
-
-#ifdef WIN32
- return 0;
-#else
- return nullptr;
-#endif
-}
diff --git a/common/os/Thread.h b/common/os/Thread.h
deleted file mode 100644
index 4c39884b..00000000
--- a/common/os/Thread.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright 2015 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 __OS_THREAD_H__
-#define __OS_THREAD_H__
-
-#include <stddef.h>
-
-namespace os {
- class Mutex;
-
- class Thread {
- public:
- Thread();
- virtual ~Thread();
-
- void start();
- void wait();
-
- bool isRunning();
-
- public:
- static size_t getSystemCPUCount();
-
- protected:
- virtual void worker() = 0;
-
- private:
-#ifdef WIN32
- static long unsigned __stdcall startRoutine(void* data);
-#else
- static void* startRoutine(void* data);
-#endif
-
- private:
- Mutex *mutex;
- bool running;
-
- void *threadId;
- };
-}
-
-#endif
diff --git a/common/rdr/BufferedInStream.cxx b/common/rdr/BufferedInStream.cxx
index bf94a950..bcdeef4a 100644
--- a/common/rdr/BufferedInStream.cxx
+++ b/common/rdr/BufferedInStream.cxx
@@ -23,9 +23,9 @@
#include <assert.h>
-#include <rdr/BufferedInStream.h>
+#include <core/string.h>
-#include <rfb/util.h>
+#include <rdr/BufferedInStream.h>
using namespace rdr;
@@ -64,12 +64,10 @@ void BufferedInStream::ensureSpace(size_t needed)
uint8_t* newBuffer;
if (needed > MAX_BUF_SIZE)
- throw std::out_of_range(rfb::format("BufferedInStream overrun: "
- "requested size of %lu bytes "
- "exceeds maximum of %lu "
- "bytes",
- (long unsigned)needed,
- (long unsigned)MAX_BUF_SIZE));
+ throw std::out_of_range(core::format(
+ "BufferedInStream overrun: requested size of %lu bytes exceeds "
+ "maximum of %lu bytes",
+ (long unsigned)needed, (long unsigned)MAX_BUF_SIZE));
newSize = DEFAULT_BUF_SIZE;
while (newSize < needed)
diff --git a/common/rdr/BufferedOutStream.cxx b/common/rdr/BufferedOutStream.cxx
index efb71dd7..e2b756bb 100644
--- a/common/rdr/BufferedOutStream.cxx
+++ b/common/rdr/BufferedOutStream.cxx
@@ -22,9 +22,9 @@
#include <config.h>
#endif
-#include <rdr/BufferedOutStream.h>
+#include <core/string.h>
-#include <rfb/util.h>
+#include <rdr/BufferedOutStream.h>
using namespace rdr;
@@ -138,11 +138,10 @@ void BufferedOutStream::overrun(size_t needed)
// We'll need to allocate more buffer space...
if (totalNeeded > MAX_BUF_SIZE)
- throw std::out_of_range(rfb::format("BufferedOutStream overrun: "
- "requested size of %lu bytes "
- "exceeds maximum of %lu bytes",
- (long unsigned)totalNeeded,
- (long unsigned)MAX_BUF_SIZE));
+ throw std::out_of_range(core::format(
+ "BufferedOutStream overrun: requested size of %lu bytes exceeds "
+ "maximum of %lu bytes",
+ (long unsigned)totalNeeded, (long unsigned)MAX_BUF_SIZE));
newSize = DEFAULT_BUF_SIZE;
while (newSize < totalNeeded)
diff --git a/common/rdr/CMakeLists.txt b/common/rdr/CMakeLists.txt
index 2897119b..526b2971 100644
--- a/common/rdr/CMakeLists.txt
+++ b/common/rdr/CMakeLists.txt
@@ -3,7 +3,6 @@ add_library(rdr STATIC
AESOutStream.cxx
BufferedInStream.cxx
BufferedOutStream.cxx
- Exception.cxx
FdInStream.cxx
FdOutStream.cxx
FileInStream.cxx
@@ -13,17 +12,14 @@ add_library(rdr STATIC
TLSException.cxx
TLSInStream.cxx
TLSOutStream.cxx
+ TLSSocket.cxx
ZlibInStream.cxx
ZlibOutStream.cxx)
target_include_directories(rdr PUBLIC ${CMAKE_SOURCE_DIR}/common)
target_include_directories(rdr SYSTEM PUBLIC ${ZLIB_INCLUDE_DIRS})
-target_link_libraries(rdr ${ZLIB_LIBRARIES} os rfb)
-
-if(MSVC)
- # undef min and max macro
- target_compile_definitions(rfb PRIVATE NOMINMAX)
-endif()
+target_link_libraries(rdr core)
+target_link_libraries(rdr ${ZLIB_LIBRARIES})
if(GNUTLS_FOUND)
target_include_directories(rdr SYSTEM PUBLIC ${GNUTLS_INCLUDE_DIR})
@@ -32,7 +28,6 @@ endif()
if (NETTLE_FOUND)
target_include_directories(rdr SYSTEM PUBLIC ${NETTLE_INCLUDE_DIRS})
target_link_libraries(rdr ${NETTLE_LIBRARIES})
- target_link_directories(rdr PUBLIC ${NETTLE_LIBRARY_DIRS})
endif()
if(WIN32)
target_link_libraries(rdr ws2_32)
diff --git a/common/rdr/FdInStream.cxx b/common/rdr/FdInStream.cxx
index 23ea2f8c..25542a01 100644
--- a/common/rdr/FdInStream.cxx
+++ b/common/rdr/FdInStream.cxx
@@ -28,7 +28,7 @@
#include <winsock2.h>
#define errorNumber WSAGetLastError()
#define close closesocket
-#include <os/winerrno.h>
+#include <core/winerrno.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
@@ -41,8 +41,9 @@
#include <sys/select.h>
#endif
+#include <core/Exception.h>
+
#include <rdr/FdInStream.h>
-#include <rdr/Exception.h>
using namespace rdr;
@@ -92,7 +93,7 @@ size_t FdInStream::readFd(uint8_t* buf, size_t len)
} while (n < 0 && errorNumber == EINTR);
if (n < 0)
- throw socket_error("select", errorNumber);
+ throw core::socket_error("select", errorNumber);
if (n == 0)
return 0;
@@ -102,7 +103,7 @@ size_t FdInStream::readFd(uint8_t* buf, size_t len)
} while (n < 0 && errorNumber == EINTR);
if (n < 0)
- throw socket_error("read", errorNumber);
+ throw core::socket_error("read", errorNumber);
if (n == 0)
throw end_of_stream();
diff --git a/common/rdr/FdOutStream.cxx b/common/rdr/FdOutStream.cxx
index 6db8c0bb..416926c1 100644
--- a/common/rdr/FdOutStream.cxx
+++ b/common/rdr/FdOutStream.cxx
@@ -28,7 +28,7 @@
#ifdef _WIN32
#include <winsock2.h>
#define errorNumber WSAGetLastError()
-#include <os/winerrno.h>
+#include <core/winerrno.h>
#else
#include <sys/types.h>
#include <unistd.h>
@@ -44,10 +44,10 @@
#include <sys/select.h>
#endif
-#include <rdr/FdOutStream.h>
-#include <rdr/Exception.h>
-#include <rfb/util.h>
+#include <core/Exception.h>
+#include <core/time.h>
+#include <rdr/FdOutStream.h>
using namespace rdr;
@@ -68,7 +68,7 @@ FdOutStream::~FdOutStream()
unsigned FdOutStream::getIdleTime()
{
- return rfb::msSince(&lastWrite);
+ return core::msSince(&lastWrite);
}
void FdOutStream::cork(bool enable)
@@ -117,7 +117,7 @@ size_t FdOutStream::writeFd(const uint8_t* data, size_t length)
} while (n < 0 && errorNumber == EINTR);
if (n < 0)
- throw socket_error("select", errorNumber);
+ throw core::socket_error("select", errorNumber);
if (n == 0)
return 0;
@@ -134,7 +134,7 @@ size_t FdOutStream::writeFd(const uint8_t* data, size_t length)
} while (n < 0 && (errorNumber == EINTR));
if (n < 0)
- throw socket_error("write", errorNumber);
+ throw core::socket_error("write", errorNumber);
gettimeofday(&lastWrite, nullptr);
diff --git a/common/rdr/FileInStream.cxx b/common/rdr/FileInStream.cxx
index df09ea76..4dbe2d1f 100644
--- a/common/rdr/FileInStream.cxx
+++ b/common/rdr/FileInStream.cxx
@@ -24,7 +24,8 @@
#include <errno.h>
-#include <rdr/Exception.h>
+#include <core/Exception.h>
+
#include <rdr/FileInStream.h>
using namespace rdr;
@@ -33,7 +34,7 @@ FileInStream::FileInStream(const char *fileName)
{
file = fopen(fileName, "rb");
if (!file)
- throw posix_error("fopen", errno);
+ throw core::posix_error("fopen", errno);
}
FileInStream::~FileInStream(void) {
@@ -48,7 +49,7 @@ bool FileInStream::fillBuffer()
size_t n = fread((uint8_t*)end, 1, availSpace(), file);
if (n == 0) {
if (ferror(file))
- throw posix_error("fread", errno);
+ throw core::posix_error("fread", errno);
if (feof(file))
throw end_of_stream();
return false;
diff --git a/common/rdr/HexInStream.cxx b/common/rdr/HexInStream.cxx
index 69c3e260..b5a8826c 100644
--- a/common/rdr/HexInStream.cxx
+++ b/common/rdr/HexInStream.cxx
@@ -22,8 +22,10 @@
#endif
#include <algorithm>
+
+#include <core/string.h>
+
#include <rdr/HexInStream.h>
-#include <rfb/util.h>
using namespace rdr;
@@ -44,7 +46,7 @@ bool HexInStream::fillBuffer() {
uint8_t* optr = (uint8_t*) end;
for (size_t i=0; i<length; i++) {
- if (!rfb::hexToBin((const char*)&iptr[i*2], 2, &optr[i], 1))
+ if (!core::hexToBin((const char*)&iptr[i*2], 2, &optr[i], 1))
throw std::runtime_error("HexInStream: Invalid input data");
}
diff --git a/common/rdr/HexOutStream.cxx b/common/rdr/HexOutStream.cxx
index efab77f8..b3749c0d 100644
--- a/common/rdr/HexOutStream.cxx
+++ b/common/rdr/HexOutStream.cxx
@@ -20,9 +20,12 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+
#include <algorithm>
+
+#include <core/string.h>
+
#include <rdr/HexOutStream.h>
-#include <rfb/util.h>
using namespace rdr;
@@ -42,7 +45,7 @@ bool HexOutStream::flushBuffer()
size_t length = std::min((size_t)(ptr-sentUpTo), out_stream.avail()/2);
for (size_t i=0; i<length; i++)
- rfb::binToHex(&sentUpTo[i], 1, (char*)&optr[i*2], 2);
+ core::binToHex(&sentUpTo[i], 1, (char*)&optr[i*2], 2);
out_stream.setptr(length*2);
sentUpTo += length;
diff --git a/common/rdr/InStream.h b/common/rdr/InStream.h
index 5623142c..7ad4996f 100644
--- a/common/rdr/InStream.h
+++ b/common/rdr/InStream.h
@@ -38,6 +38,11 @@
namespace rdr {
+ class end_of_stream : public std::runtime_error {
+ public:
+ end_of_stream() noexcept : std::runtime_error("End of stream") {}
+ };
+
class InStream {
public:
@@ -182,9 +187,7 @@ namespace rdr {
private:
const uint8_t* restorePoint;
-#ifdef RFB_INSTREAM_CHECK
size_t checkedBytes;
-#endif
inline void check(size_t bytes) {
#ifdef RFB_INSTREAM_CHECK
@@ -204,11 +207,7 @@ namespace rdr {
protected:
- InStream() : restorePoint(nullptr)
-#ifdef RFB_INSTREAM_CHECK
- ,checkedBytes(0)
-#endif
- {}
+ InStream() : restorePoint(nullptr), checkedBytes(0) {}
const uint8_t* ptr;
const uint8_t* end;
};
diff --git a/common/rdr/MemInStream.h b/common/rdr/MemInStream.h
index 78ee2dee..a92e18f9 100644
--- a/common/rdr/MemInStream.h
+++ b/common/rdr/MemInStream.h
@@ -28,7 +28,6 @@
#define __RDR_MEMINSTREAM_H__
#include <rdr/InStream.h>
-#include <rdr/Exception.h>
namespace rdr {
diff --git a/common/rdr/RandomStream.cxx b/common/rdr/RandomStream.cxx
index 3a524102..9784c220 100644
--- a/common/rdr/RandomStream.cxx
+++ b/common/rdr/RandomStream.cxx
@@ -20,9 +20,11 @@
#include <config.h>
#endif
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
#include <rdr/RandomStream.h>
-#include <rdr/Exception.h>
-#include <rfb/LogWriter.h>
+
#include <time.h>
#include <stdlib.h>
#ifndef WIN32
@@ -35,7 +37,7 @@
#endif
#endif
-static rfb::LogWriter vlog("RandomStream");
+static core::LogWriter vlog("RandomStream");
using namespace rdr;
@@ -89,7 +91,7 @@ bool RandomStream::fillBuffer() {
#ifdef RFB_HAVE_WINCRYPT
if (provider) {
if (!CryptGenRandom(provider, availSpace(), (uint8_t*)end))
- throw rdr::win32_error("Unable to CryptGenRandom", GetLastError());
+ throw core::win32_error("Unable to CryptGenRandom", GetLastError());
end += availSpace();
} else {
#else
@@ -97,8 +99,8 @@ bool RandomStream::fillBuffer() {
if (fp) {
size_t n = fread((uint8_t*)end, 1, availSpace(), fp);
if (n <= 0)
- throw rdr::posix_error("Reading /dev/urandom or /dev/random "
- "failed", errno);
+ throw core::posix_error(
+ "Reading /dev/urandom or /dev/random failed", errno);
end += n;
} else {
#else
diff --git a/common/rdr/TLSException.cxx b/common/rdr/TLSException.cxx
index ee4f587b..8c93a3d3 100644
--- a/common/rdr/TLSException.cxx
+++ b/common/rdr/TLSException.cxx
@@ -22,9 +22,9 @@
#include <config.h>
#endif
-#include <rdr/TLSException.h>
+#include <core/string.h>
-#include <rfb/util.h>
+#include <rdr/TLSException.h>
#include <string.h>
#include <stdio.h>
@@ -35,11 +35,28 @@
using namespace rdr;
#ifdef HAVE_GNUTLS
-tls_error::tls_error(const char* s, int err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", s,
- gnutls_strerror(err_), err_)),
- err(err_)
+tls_error::tls_error(const char* s, int err_, int alert_) noexcept
+ : std::runtime_error(core::format("%s: %s (%d)", s,
+ strerror(err_, alert_), err_)),
+ err(err_), alert(alert_)
+{
+}
+
+const char* tls_error::strerror(int err_, int alert_) const noexcept
{
+ const char* msg;
+
+ msg = nullptr;
+
+ if ((alert_ != -1) &&
+ ((err_ == GNUTLS_E_WARNING_ALERT_RECEIVED) ||
+ (err_ == GNUTLS_E_FATAL_ALERT_RECEIVED)))
+ msg = gnutls_alert_get_name((gnutls_alert_description_t)alert_);
+
+ if (msg == nullptr)
+ msg = gnutls_strerror(err_);
+
+ return msg;
}
#endif /* HAVE_GNUTLS */
diff --git a/common/rdr/TLSException.h b/common/rdr/TLSException.h
index 62b090ba..75ee94f5 100644
--- a/common/rdr/TLSException.h
+++ b/common/rdr/TLSException.h
@@ -21,14 +21,16 @@
#ifndef __RDR_TLSEXCEPTION_H__
#define __RDR_TLSEXCEPTION_H__
-#include <rdr/Exception.h>
+#include <stdexcept>
namespace rdr {
class tls_error : public std::runtime_error {
public:
- int err;
- tls_error(const char* s, int err_) noexcept;
+ int err, alert;
+ tls_error(const char* s, int err_, int alert_=-1) noexcept;
+ private:
+ const char* strerror(int err_, int alert_) const noexcept;
};
}
diff --git a/common/rdr/TLSInStream.cxx b/common/rdr/TLSInStream.cxx
index ee2739f4..3e5ea2be 100644
--- a/common/rdr/TLSInStream.cxx
+++ b/common/rdr/TLSInStream.cxx
@@ -1,7 +1,7 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* 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
@@ -23,74 +23,25 @@
#include <config.h>
#endif
-#include <rdr/Exception.h>
-#include <rdr/TLSException.h>
#include <rdr/TLSInStream.h>
-#include <rfb/LogWriter.h>
-#include <errno.h>
+#include <rdr/TLSSocket.h>
-#ifdef HAVE_GNUTLS
-using namespace rdr;
-
-static rfb::LogWriter vlog("TLSInStream");
-
-ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size)
-{
- TLSInStream* self= (TLSInStream*) str;
- InStream *in = self->in;
-
- self->streamEmpty = false;
- delete self->saved_exception;
- self->saved_exception = nullptr;
+#ifdef HAVE_GNUTLS
- try {
- if (!in->hasData(1)) {
- self->streamEmpty = true;
- gnutls_transport_set_errno(self->session, EAGAIN);
- return -1;
- }
-
- if (in->avail() < size)
- size = in->avail();
-
- in->readBytes((uint8_t*)data, size);
- } catch (end_of_stream&) {
- return 0;
- } catch (socket_error& e) {
- vlog.error("Failure reading TLS data: %s", e.what());
- gnutls_transport_set_errno(self->session, e.err);
- self->saved_exception = new socket_error(e);
- return -1;
- } catch (std::exception& e) {
- vlog.error("Failure reading TLS data: %s", e.what());
- gnutls_transport_set_errno(self->session, EINVAL);
- self->saved_exception = new std::runtime_error(e.what());
- return -1;
- }
-
- return size;
-}
+using namespace rdr;
-TLSInStream::TLSInStream(InStream* _in, gnutls_session_t _session)
- : session(_session), in(_in), saved_exception(nullptr)
+TLSInStream::TLSInStream(TLSSocket* sock_)
+ : sock(sock_)
{
- gnutls_transport_ptr_t recv, send;
-
- gnutls_transport_set_pull_function(session, pull);
- gnutls_transport_get_ptr2(session, &recv, &send);
- gnutls_transport_set_ptr2(session, this, send);
}
TLSInStream::~TLSInStream()
{
- gnutls_transport_set_pull_function(session, nullptr);
-
- delete saved_exception;
}
bool TLSInStream::fillBuffer()
{
- size_t n = readTLS((uint8_t*) end, availSpace());
+ size_t n = sock->readTLS((uint8_t*) end, availSpace());
if (n == 0)
return false;
end += n;
@@ -98,39 +49,4 @@ bool TLSInStream::fillBuffer()
return true;
}
-size_t TLSInStream::readTLS(uint8_t* buf, size_t len)
-{
- int n;
-
- while (true) {
- streamEmpty = false;
- n = gnutls_record_recv(session, (void *) buf, len);
- if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) {
- // GnuTLS returns GNUTLS_E_AGAIN for a bunch of other scenarios
- // other than the pull function returning EAGAIN, so we have to
- // double check that the underlying stream really is empty
- if (!streamEmpty)
- continue;
- else
- return 0;
- }
- break;
- };
-
- if (n == GNUTLS_E_PULL_ERROR) {
- if (dynamic_cast<socket_error*>(saved_exception))
- throw *dynamic_cast<socket_error*>(saved_exception);
- else
- throw std::runtime_error(saved_exception->what());
- }
-
- if (n < 0)
- throw tls_error("readTLS", n);
-
- if (n == 0)
- throw end_of_stream();
-
- return n;
-}
-
#endif
diff --git a/common/rdr/TLSInStream.h b/common/rdr/TLSInStream.h
index 2269b09d..94266e50 100644
--- a/common/rdr/TLSInStream.h
+++ b/common/rdr/TLSInStream.h
@@ -1,5 +1,6 @@
/* 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
@@ -22,28 +23,25 @@
#ifdef HAVE_GNUTLS
-#include <gnutls/gnutls.h>
#include <rdr/BufferedInStream.h>
namespace rdr {
+ class TLSSocket;
+
class TLSInStream : public BufferedInStream {
public:
- TLSInStream(InStream* in, gnutls_session_t session);
+ TLSInStream(TLSSocket* sock);
virtual ~TLSInStream();
private:
bool fillBuffer() override;
- size_t readTLS(uint8_t* buf, size_t len);
- static ssize_t pull(gnutls_transport_ptr_t str, void* data, size_t size);
-
- gnutls_session_t session;
- InStream* in;
- bool streamEmpty;
- std::exception* saved_exception;
+ TLSSocket* sock;
};
-};
+
+}
#endif
+
#endif
diff --git a/common/rdr/TLSOutStream.cxx b/common/rdr/TLSOutStream.cxx
index 365ffd60..ba9d182f 100644
--- a/common/rdr/TLSOutStream.cxx
+++ b/common/rdr/TLSOutStream.cxx
@@ -1,7 +1,7 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* 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
@@ -23,108 +23,42 @@
#include <config.h>
#endif
-#include <rdr/Exception.h>
-#include <rdr/TLSException.h>
#include <rdr/TLSOutStream.h>
-#include <rfb/LogWriter.h>
-#include <errno.h>
+#include <rdr/TLSSocket.h>
#ifdef HAVE_GNUTLS
-using namespace rdr;
-
-static rfb::LogWriter vlog("TLSOutStream");
-
-ssize_t TLSOutStream::push(gnutls_transport_ptr_t str, const void* data,
- size_t size)
-{
- TLSOutStream* self= (TLSOutStream*) str;
- OutStream *out = self->out;
-
- delete self->saved_exception;
- self->saved_exception = nullptr;
- try {
- out->writeBytes((const uint8_t*)data, size);
- out->flush();
- } catch (socket_error& e) {
- vlog.error("Failure sending TLS data: %s", e.what());
- gnutls_transport_set_errno(self->session, e.err);
- self->saved_exception = new socket_error(e);
- return -1;
- } catch (std::exception& e) {
- vlog.error("Failure sending TLS data: %s", e.what());
- gnutls_transport_set_errno(self->session, EINVAL);
- self->saved_exception = new std::runtime_error(e.what());
- return -1;
- }
-
- return size;
-}
+using namespace rdr;
-TLSOutStream::TLSOutStream(OutStream* _out, gnutls_session_t _session)
- : session(_session), out(_out), saved_exception(nullptr)
+TLSOutStream::TLSOutStream(TLSSocket* sock_)
+ : sock(sock_)
{
- gnutls_transport_ptr_t recv, send;
-
- gnutls_transport_set_push_function(session, push);
- gnutls_transport_get_ptr2(session, &recv, &send);
- gnutls_transport_set_ptr2(session, recv, this);
}
TLSOutStream::~TLSOutStream()
{
-#if 0
- try {
-// flush();
- } catch (Exception&) {
- }
-#endif
- gnutls_transport_set_push_function(session, nullptr);
-
- delete saved_exception;
}
void TLSOutStream::flush()
{
BufferedOutStream::flush();
- out->flush();
+ sock->out->flush();
}
void TLSOutStream::cork(bool enable)
{
BufferedOutStream::cork(enable);
- out->cork(enable);
+ sock->out->cork(enable);
}
bool TLSOutStream::flushBuffer()
{
while (sentUpTo < ptr) {
- size_t n = writeTLS(sentUpTo, ptr - sentUpTo);
+ size_t n = sock->writeTLS(sentUpTo, ptr - sentUpTo);
sentUpTo += n;
}
return true;
}
-size_t TLSOutStream::writeTLS(const uint8_t* data, size_t length)
-{
- int n;
-
- n = gnutls_record_send(session, data, length);
- if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN)
- return 0;
-
- if (n == GNUTLS_E_PUSH_ERROR) {
- if (dynamic_cast<socket_error*>(saved_exception))
- throw *dynamic_cast<socket_error*>(saved_exception);
- else
- throw std::runtime_error(saved_exception->what());
- }
-
- if (n < 0)
- throw tls_error("writeTLS", n);
-
- return n;
-}
-
#endif
diff --git a/common/rdr/TLSOutStream.h b/common/rdr/TLSOutStream.h
index 659f16f0..aa9572ba 100644
--- a/common/rdr/TLSOutStream.h
+++ b/common/rdr/TLSOutStream.h
@@ -21,14 +21,16 @@
#define __RDR_TLSOUTSTREAM_H__
#ifdef HAVE_GNUTLS
-#include <gnutls/gnutls.h>
+
#include <rdr/BufferedOutStream.h>
namespace rdr {
+ class TLSSocket;
+
class TLSOutStream : public BufferedOutStream {
public:
- TLSOutStream(OutStream* out, gnutls_session_t session);
+ TLSOutStream(TLSSocket* out);
virtual ~TLSOutStream();
void flush() override;
@@ -36,15 +38,12 @@ namespace rdr {
private:
bool flushBuffer() override;
- size_t writeTLS(const uint8_t* data, size_t length);
- static ssize_t push(gnutls_transport_ptr_t str, const void* data, size_t size);
-
- gnutls_session_t session;
- OutStream* out;
- std::exception* saved_exception;
+ TLSSocket* sock;
};
-};
+
+}
#endif
+
#endif
diff --git a/common/rdr/TLSSocket.cxx b/common/rdr/TLSSocket.cxx
new file mode 100644
index 00000000..a29e41c1
--- /dev/null
+++ b/common/rdr/TLSSocket.cxx
@@ -0,0 +1,228 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2005 Martin Koegler
+ * Copyright (C) 2010 TigerVNC Team
+ * Copyright (C) 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
+ * 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 <core/Exception.h>
+#include <core/LogWriter.h>
+
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rdr/TLSException.h>
+#include <rdr/TLSSocket.h>
+
+#include <errno.h>
+
+#ifdef HAVE_GNUTLS
+
+using namespace rdr;
+
+static core::LogWriter vlog("TLSSocket");
+
+TLSSocket::TLSSocket(InStream* in_, OutStream* out_,
+ gnutls_session_t session_)
+ : session(session_), in(in_), out(out_), tlsin(this), tlsout(this)
+{
+ gnutls_transport_set_pull_function(
+ session, [](gnutls_transport_ptr_t sock, void* data, size_t size) {
+ return ((TLSSocket*)sock)->pull(data, size);
+ });
+ gnutls_transport_set_push_function(
+ session, [](gnutls_transport_ptr_t sock, const void* data, size_t size) {
+ return ((TLSSocket*)sock)->push(data, size);
+ });
+ gnutls_transport_set_ptr(session, this);
+}
+
+TLSSocket::~TLSSocket()
+{
+ gnutls_transport_set_pull_function(session, nullptr);
+ gnutls_transport_set_push_function(session, nullptr);
+ gnutls_transport_set_ptr(session, nullptr);
+}
+
+bool TLSSocket::handshake()
+{
+ int err;
+
+ err = gnutls_handshake(session);
+ if (err != GNUTLS_E_SUCCESS) {
+ gnutls_alert_description_t alert;
+ const char* msg;
+
+ if ((err == GNUTLS_E_PULL_ERROR) || (err == GNUTLS_E_PUSH_ERROR))
+ std::rethrow_exception(saved_exception);
+
+ alert = gnutls_alert_get(session);
+ msg = nullptr;
+
+ if ((err == GNUTLS_E_WARNING_ALERT_RECEIVED) ||
+ (err == GNUTLS_E_FATAL_ALERT_RECEIVED))
+ msg = gnutls_alert_get_name(alert);
+
+ if (msg == nullptr)
+ msg = gnutls_strerror(err);
+
+ if (!gnutls_error_is_fatal(err)) {
+ vlog.debug("Deferring completion of TLS handshake: %s", msg);
+ return false;
+ }
+
+ vlog.error("TLS Handshake failed: %s\n", msg);
+ gnutls_alert_send_appropriate(session, err);
+ throw rdr::tls_error("TLS Handshake failed", err, alert);
+ }
+
+ return true;
+}
+
+void TLSSocket::shutdown()
+{
+ int ret;
+
+ try {
+ if (tlsout.hasBufferedData()) {
+ tlsout.cork(false);
+ tlsout.flush();
+ if (tlsout.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());
+ }
+
+ // 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));
+}
+
+size_t TLSSocket::readTLS(uint8_t* buf, size_t len)
+{
+ int n;
+
+ while (true) {
+ streamEmpty = false;
+ n = gnutls_record_recv(session, (void *) buf, len);
+ if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) {
+ // GnuTLS returns GNUTLS_E_AGAIN for a bunch of other scenarios
+ // other than the pull function returning EAGAIN, so we have to
+ // double check that the underlying stream really is empty
+ if (!streamEmpty)
+ continue;
+ else
+ return 0;
+ }
+ break;
+ };
+
+ if (n == GNUTLS_E_PULL_ERROR)
+ std::rethrow_exception(saved_exception);
+
+ if (n < 0) {
+ gnutls_alert_send_appropriate(session, n);
+ throw tls_error("readTLS", n, gnutls_alert_get(session));
+ }
+
+ if (n == 0)
+ throw end_of_stream();
+
+ return n;
+}
+
+size_t TLSSocket::writeTLS(const uint8_t* data, size_t length)
+{
+ int n;
+
+ n = gnutls_record_send(session, data, length);
+ if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN)
+ return 0;
+
+ if (n == GNUTLS_E_PUSH_ERROR)
+ std::rethrow_exception(saved_exception);
+
+ if (n < 0) {
+ gnutls_alert_send_appropriate(session, n);
+ throw tls_error("writeTLS", n, gnutls_alert_get(session));
+ }
+
+ return n;
+}
+
+ssize_t TLSSocket::pull(void* data, size_t size)
+{
+ streamEmpty = false;
+ saved_exception = nullptr;
+
+ try {
+ if (!in->hasData(1)) {
+ streamEmpty = true;
+ gnutls_transport_set_errno(session, EAGAIN);
+ return -1;
+ }
+
+ if (in->avail() < size)
+ size = in->avail();
+
+ in->readBytes((uint8_t*)data, size);
+ } catch (end_of_stream&) {
+ return 0;
+ } catch (std::exception& e) {
+ core::socket_error* se;
+ vlog.error("Failure reading TLS data: %s", e.what());
+ se = dynamic_cast<core::socket_error*>(&e);
+ if (se)
+ gnutls_transport_set_errno(session, se->err);
+ else
+ gnutls_transport_set_errno(session, EINVAL);
+ saved_exception = std::current_exception();
+ return -1;
+ }
+
+ return size;
+}
+
+ssize_t TLSSocket::push(const void* data, size_t size)
+{
+ saved_exception = nullptr;
+
+ try {
+ out->writeBytes((const uint8_t*)data, size);
+ out->flush();
+ } catch (std::exception& e) {
+ core::socket_error* se;
+ vlog.error("Failure sending TLS data: %s", e.what());
+ se = dynamic_cast<core::socket_error*>(&e);
+ if (se)
+ gnutls_transport_set_errno(session, se->err);
+ else
+ gnutls_transport_set_errno(session, EINVAL);
+ saved_exception = std::current_exception();
+ return -1;
+ }
+
+ return size;
+}
+
+#endif
diff --git a/common/rdr/TLSSocket.h b/common/rdr/TLSSocket.h
new file mode 100644
index 00000000..ca29f8bc
--- /dev/null
+++ b/common/rdr/TLSSocket.h
@@ -0,0 +1,81 @@
+/* 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
+ * 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 __RDR_TLSSOCKET_H__
+#define __RDR_TLSSOCKET_H__
+
+#ifdef HAVE_GNUTLS
+
+#include <exception>
+
+#include <gnutls/gnutls.h>
+
+#include <rdr/TLSInStream.h>
+#include <rdr/TLSOutStream.h>
+
+namespace rdr {
+
+ class InStream;
+ class OutStream;
+
+ class TLSInStream;
+ class TLSOutStream;
+
+ class TLSSocket {
+ public:
+ TLSSocket(InStream* in, OutStream* out, gnutls_session_t session);
+ virtual ~TLSSocket();
+
+ TLSInStream& inStream() { return tlsin; }
+ TLSOutStream& outStream() { return tlsout; }
+
+ bool handshake();
+ void shutdown();
+
+ protected:
+ /* Used by the stream classes */
+ size_t readTLS(uint8_t* buf, size_t len);
+ size_t writeTLS(const uint8_t* data, size_t length);
+
+ friend TLSInStream;
+ friend TLSOutStream;
+
+ private:
+ ssize_t pull(void* data, size_t size);
+ ssize_t push(const void* data, size_t size);
+
+ gnutls_session_t session;
+
+ InStream* in;
+ OutStream* out;
+
+ TLSInStream tlsin;
+ TLSOutStream tlsout;
+
+ bool streamEmpty;
+
+ std::exception_ptr saved_exception;
+ };
+
+}
+
+#endif
+
+#endif
diff --git a/common/rdr/ZlibOutStream.cxx b/common/rdr/ZlibOutStream.cxx
index 73b5d459..1b8ac307 100644
--- a/common/rdr/ZlibOutStream.cxx
+++ b/common/rdr/ZlibOutStream.cxx
@@ -23,14 +23,15 @@
#include <stdio.h>
+#include <core/LogWriter.h>
+
#include <rdr/ZlibOutStream.h>
-#include <rfb/LogWriter.h>
#include <zlib.h>
#undef ZLIBOUT_DEBUG
-static rfb::LogWriter vlog("ZlibOutStream");
+static core::LogWriter vlog("ZlibOutStream");
using namespace rdr;
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 = &current->_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/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/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/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/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 &region) {
+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 &region) {
+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 &region) = 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 &region) 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 &region) 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 &region) 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