diff options
Diffstat (limited to 'common')
84 files changed, 844 insertions, 639 deletions
diff --git a/common/network/Socket.cxx b/common/network/Socket.cxx index 8bb96763..879a63d0 100644 --- a/common/network/Socket.cxx +++ b/common/network/Socket.cxx @@ -39,6 +39,8 @@ #include <fcntl.h> #include <errno.h> +#include <rdr/Exception.h> + #include <network/Socket.h> using namespace network; @@ -53,7 +55,7 @@ void network::initSockets() { WSADATA initResult; if (WSAStartup(requiredVersion, &initResult) != 0) - throw rdr::SocketException("unable to initialise Winsock2", errorNumber); + throw rdr::socket_error("unable to initialise Winsock2", errorNumber); #else signal(SIGPIPE, SIG_IGN); #endif @@ -161,7 +163,7 @@ Socket* SocketListener::accept() { // Accept an incoming connection if ((new_sock = ::accept(fd, nullptr, nullptr)) < 0) - throw rdr::SocketException("unable to accept new connection", errorNumber); + throw rdr::socket_error("unable to accept new connection", errorNumber); // Create the socket object & check connection is allowed Socket* s = createSocket(new_sock); @@ -179,7 +181,7 @@ void SocketListener::listen(int sock) if (::listen(sock, 5) < 0) { int e = errorNumber; closesocket(sock); - throw rdr::SocketException("unable to set socket to listening mode", e); + throw rdr::socket_error("unable to set socket to listening mode", e); } fd = sock; diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx index 76055abb..e37861f4 100644 --- a/common/network/TcpSocket.cxx +++ b/common/network/TcpSocket.cxx @@ -38,7 +38,10 @@ #include <stdlib.h> #include <unistd.h> +#include <rdr/Exception.h> + #include <network/TcpSocket.h> + #include <rfb/LogWriter.h> #include <rfb/Configuration.h> #include <rfb/util.h> @@ -82,15 +85,15 @@ int network::findFreeTcpPort (void) addr.sin_addr.s_addr = INADDR_ANY; if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) - throw SocketException ("unable to create socket", errorNumber); + throw socket_error("unable to create socket", errorNumber); addr.sin_port = 0; if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0) - throw SocketException ("unable to find free port", errorNumber); + throw socket_error("unable to find free port", errorNumber); socklen_t n = sizeof(addr); if (getsockname (sock, (struct sockaddr *)&addr, &n) < 0) - throw SocketException ("unable to get port number", errorNumber); + throw socket_error("unable to get port number", errorNumber); closesocket (sock); return ntohs(addr.sin_port); @@ -134,7 +137,7 @@ TcpSocket::TcpSocket(const char *host, int port) hints.ai_next = nullptr; if ((result = getaddrinfo(host, nullptr, &hints, &ai)) != 0) { - throw GAIException("unable to resolve host by name", result); + throw getaddrinfo_error("unable to resolve host by name", result); } sock = -1; @@ -175,7 +178,7 @@ TcpSocket::TcpSocket(const char *host, int port) if (sock == -1) { err = errorNumber; freeaddrinfo(ai); - throw SocketException("unable to create socket", err); + throw socket_error("unable to create socket", err); } /* Attempt to connect to the remote host */ @@ -200,9 +203,9 @@ TcpSocket::TcpSocket(const char *host, int port) if (sock == -1) { if (err == 0) - throw Exception("No useful address for host"); + throw std::runtime_error("No useful address for host"); else - throw SocketException("unable to connect to socket", err); + throw socket_error("unable to connect to socket", err); } // Take proper ownership of the socket @@ -299,7 +302,7 @@ TcpListener::TcpListener(const struct sockaddr *listenaddr, int sock; if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0) - throw SocketException("Unable to create listening socket", errorNumber); + throw socket_error("Unable to create listening socket", errorNumber); memcpy (&sa, listenaddr, listenaddrlen); #ifdef IPV6_V6ONLY @@ -307,7 +310,7 @@ TcpListener::TcpListener(const struct sockaddr *listenaddr, if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one))) { int e = errorNumber; closesocket(sock); - throw SocketException("Unable to set IPV6_V6ONLY", e); + throw socket_error("Unable to set IPV6_V6ONLY", e); } } #endif /* defined(IPV6_V6ONLY) */ @@ -325,14 +328,14 @@ TcpListener::TcpListener(const struct sockaddr *listenaddr, (char *)&one, sizeof(one)) < 0) { int e = errorNumber; closesocket(sock); - throw SocketException("Unable to create listening socket", e); + throw socket_error("Unable to create listening socket", e); } #endif if (bind(sock, &sa.u.sa, listenaddrlen) == -1) { int e = errorNumber; closesocket(sock); - throw SocketException("Failed to bind socket", e); + throw socket_error("Failed to bind socket", e); } listen(sock); @@ -443,7 +446,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 GAIException("Unable to resolve listening address", result); + throw getaddrinfo_error("Unable to resolve listening address", result); try { createTcpListeners(listeners, ai); @@ -482,7 +485,7 @@ void network::createTcpListeners(std::list<SocketListener*> *listeners, try { new_listeners.push_back(new TcpListener(current->ai_addr, current->ai_addrlen)); - } catch (SocketException& e) { + } catch (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) { @@ -607,7 +610,7 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) { parts = rfb::split(&p[1], '/'); if (parts.size() > 2) - throw Exception("invalid filter specified"); + throw std::invalid_argument("invalid filter specified"); if (parts[0].empty()) { // Match any address @@ -630,7 +633,7 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) { } if ((result = getaddrinfo (parts[0].c_str(), nullptr, &hints, &ai)) != 0) { - throw GAIException("Unable to resolve host by name", result); + throw getaddrinfo_error("Unable to resolve host by name", result); } memcpy (&pattern.address.u.sa, ai->ai_addr, ai->ai_addrlen); @@ -641,8 +644,8 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) { if (parts.size() > 1) { if (family == AF_INET && (parts[1].find('.') != std::string::npos)) { - throw Exception("Mask no longer supported for filter, " - "use prefix instead"); + throw std::invalid_argument("Mask no longer supported for " + "filter, use prefix instead"); } pattern.prefixlen = (unsigned int) atoi(parts[1].c_str()); @@ -655,7 +658,7 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) { pattern.prefixlen = 128; break; default: - throw Exception("unknown address family"); + throw std::runtime_error("unknown address family"); } } } @@ -663,8 +666,9 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) { family = pattern.address.u.sa.sa_family; if (pattern.prefixlen > (family == AF_INET ? 32: 128)) - throw Exception("invalid prefix length for filter address: %u", - pattern.prefixlen); + throw std::invalid_argument(rfb::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/UnixSocket.cxx b/common/network/UnixSocket.cxx index fb631dae..fb017a53 100644 --- a/common/network/UnixSocket.cxx +++ b/common/network/UnixSocket.cxx @@ -29,7 +29,10 @@ #include <stdlib.h> #include <stddef.h> +#include <rdr/Exception.h> + #include <network/UnixSocket.h> + #include <rfb/LogWriter.h> using namespace network; @@ -50,12 +53,12 @@ UnixSocket::UnixSocket(const char *path) socklen_t salen; if (strlen(path) >= sizeof(addr.sun_path)) - throw SocketException("socket path is too long", ENAMETOOLONG); + throw socket_error("socket path is too long", ENAMETOOLONG); // - Create a socket sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock == -1) - throw SocketException("unable to create socket", errno); + throw socket_error("unable to create socket", errno); // - Attempt to connect memset(&addr, 0, sizeof(addr)); @@ -69,7 +72,7 @@ UnixSocket::UnixSocket(const char *path) } if (result == -1) - throw SocketException("Unable to connect to socket", err); + throw socket_error("Unable to connect to socket", err); setFd(sock); } @@ -116,11 +119,11 @@ UnixListener::UnixListener(const char *path, int mode) int err, result; if (strlen(path) >= sizeof(addr.sun_path)) - throw SocketException("socket path is too long", ENAMETOOLONG); + throw socket_error("socket path is too long", ENAMETOOLONG); // - Create a socket if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - throw SocketException("Unable to create listening socket", errno); + throw socket_error("Unable to create listening socket", errno); // - Delete existing socket (ignore result) unlink(path); @@ -135,14 +138,14 @@ UnixListener::UnixListener(const char *path, int mode) umask(saved_umask); if (result < 0) { close(fd); - throw SocketException("Unable to bind listening socket", err); + throw socket_error("Unable to bind listening socket", err); } // - Set socket mode if (chmod(path, mode) < 0) { err = errno; close(fd); - throw SocketException("Unable to set socket mode", err); + throw socket_error("Unable to set socket mode", err); } listen(fd); diff --git a/common/os/Mutex.cxx b/common/os/Mutex.cxx index b82de415..1889e66b 100644 --- a/common/os/Mutex.cxx +++ b/common/os/Mutex.cxx @@ -43,7 +43,7 @@ Mutex::Mutex() systemMutex = new pthread_mutex_t; ret = pthread_mutex_init((pthread_mutex_t*)systemMutex, nullptr); if (ret != 0) - throw rdr::PosixException("Failed to create mutex", ret); + throw rdr::posix_error("Failed to create mutex", ret); #endif } @@ -67,7 +67,7 @@ void Mutex::lock() ret = pthread_mutex_lock((pthread_mutex_t*)systemMutex); if (ret != 0) - throw rdr::PosixException("Failed to lock mutex", ret); + throw rdr::posix_error("Failed to lock mutex", ret); #endif } @@ -80,7 +80,7 @@ void Mutex::unlock() ret = pthread_mutex_unlock((pthread_mutex_t*)systemMutex); if (ret != 0) - throw rdr::PosixException("Failed to unlock mutex", ret); + throw rdr::posix_error("Failed to unlock mutex", ret); #endif } @@ -97,7 +97,7 @@ Condition::Condition(Mutex* mutex_) systemCondition = new pthread_cond_t; ret = pthread_cond_init((pthread_cond_t*)systemCondition, nullptr); if (ret != 0) - throw rdr::PosixException("Failed to create condition variable", ret); + throw rdr::posix_error("Failed to create condition variable", ret); #endif } @@ -120,14 +120,14 @@ void Condition::wait() (CRITICAL_SECTION*)mutex->systemMutex, INFINITE); if (!ret) - throw rdr::Win32Exception("Failed to wait on condition variable", GetLastError()); + 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::PosixException("Failed to wait on condition variable", ret); + throw rdr::posix_error("Failed to wait on condition variable", ret); #endif } @@ -140,7 +140,7 @@ void Condition::signal() ret = pthread_cond_signal((pthread_cond_t*)systemCondition); if (ret != 0) - throw rdr::PosixException("Failed to signal condition variable", ret); + throw rdr::posix_error("Failed to signal condition variable", ret); #endif } @@ -153,6 +153,6 @@ void Condition::broadcast() ret = pthread_cond_broadcast((pthread_cond_t*)systemCondition); if (ret != 0) - throw rdr::PosixException("Failed to broadcast condition variable", ret); + throw rdr::posix_error("Failed to broadcast condition variable", ret); #endif } diff --git a/common/os/Thread.cxx b/common/os/Thread.cxx index e99be63e..6dca75a1 100644 --- a/common/os/Thread.cxx +++ b/common/os/Thread.cxx @@ -66,7 +66,7 @@ void Thread::start() #ifdef WIN32 *(HANDLE*)threadId = CreateThread(nullptr, 0, startRoutine, this, 0, nullptr); if (*(HANDLE*)threadId == nullptr) - throw rdr::Win32Exception("Failed to create thread", GetLastError()); + throw rdr::win32_error("Failed to create thread", GetLastError()); #else int ret; sigset_t all, old; @@ -76,14 +76,14 @@ void Thread::start() sigfillset(&all); ret = pthread_sigmask(SIG_SETMASK, &all, &old); if (ret != 0) - throw rdr::PosixException("Failed to mask signals", ret); + 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::PosixException("Failed to create thread", ret); + throw rdr::posix_error("Failed to create thread", ret); #endif running = true; @@ -99,13 +99,13 @@ void Thread::wait() ret = WaitForSingleObject(*(HANDLE*)threadId, INFINITE); if (ret != WAIT_OBJECT_0) - throw rdr::Win32Exception("Failed to join thread", GetLastError()); + throw rdr::win32_error("Failed to join thread", GetLastError()); #else int ret; ret = pthread_join(*(pthread_t*)threadId, nullptr); if (ret != 0) - throw rdr::PosixException("Failed to join thread", ret); + throw rdr::posix_error("Failed to join thread", ret); #endif } diff --git a/common/os/winerrno.h b/common/os/winerrno.h index 052d4de2..a81fdc94 100644 --- a/common/os/winerrno.h +++ b/common/os/winerrno.h @@ -5,6 +5,8 @@ cat /usr/i686-pc-mingw32/sys-root/mingw/include/winerror.h \ | egrep -v 'EINTR|EBADF|EACCES|EFAULT|EINVAL|EMFILE|_QOS|PROVIDER|PROCTABLE' */ +#include <winsock2.h> + #undef EWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK #undef EINPROGRESS diff --git a/common/rdr/AESInStream.cxx b/common/rdr/AESInStream.cxx index d6d944a3..3a56ef73 100644 --- a/common/rdr/AESInStream.cxx +++ b/common/rdr/AESInStream.cxx @@ -21,8 +21,8 @@ #endif #include <assert.h> + #include <rdr/AESInStream.h> -#include <rdr/Exception.h> #ifdef HAVE_NETTLE using namespace rdr; @@ -68,7 +68,7 @@ bool AESInStream::fillBuffer() EAX_DIGEST(&eaxCtx256, aes256_encrypt, 16, macComputed); } if (memcmp(mac, macComputed, 16) != 0) - throw Exception("AESInStream: failed to authenticate message"); + throw std::runtime_error("AESInStream: failed to authenticate message"); in->setptr(2 + length + 16); end += length; diff --git a/common/rdr/BufferedInStream.cxx b/common/rdr/BufferedInStream.cxx index 3c04bafc..bf94a950 100644 --- a/common/rdr/BufferedInStream.cxx +++ b/common/rdr/BufferedInStream.cxx @@ -24,7 +24,8 @@ #include <assert.h> #include <rdr/BufferedInStream.h> -#include <rdr/Exception.h> + +#include <rfb/util.h> using namespace rdr; @@ -63,9 +64,12 @@ void BufferedInStream::ensureSpace(size_t needed) uint8_t* newBuffer; if (needed > MAX_BUF_SIZE) - throw Exception("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(rfb::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 0d6a1eb6..efb71dd7 100644 --- a/common/rdr/BufferedOutStream.cxx +++ b/common/rdr/BufferedOutStream.cxx @@ -23,8 +23,8 @@ #endif #include <rdr/BufferedOutStream.h> -#include <rdr/Exception.h> +#include <rfb/util.h> using namespace rdr; @@ -138,10 +138,11 @@ void BufferedOutStream::overrun(size_t needed) // We'll need to allocate more buffer space... if (totalNeeded > MAX_BUF_SIZE) - throw Exception("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(rfb::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/Exception.cxx b/common/rdr/Exception.cxx index 6a03fa54..694ee359 100644 --- a/common/rdr/Exception.cxx +++ b/common/rdr/Exception.cxx @@ -1,6 +1,7 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright (C) 2004 Red Hat Inc. * Copyright (C) 2010 TigerVNC Team + * Copyright 2014-2024 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +28,8 @@ #include <rdr/Exception.h> #include <rdr/TLSException.h> +#include <rfb/util.h> + #ifdef _WIN32 #include <winsock2.h> #include <windows.h> @@ -37,77 +40,94 @@ #include <string.h> -#ifdef HAVE_GNUTLS -#include <gnutls/gnutls.h> -#endif - using namespace rdr; -Exception::Exception(const char *format, ...) { - va_list ap; - va_start(ap, format); - (void) vsnprintf(str_, len, format, ap); - va_end(ap); +getaddrinfo_error::getaddrinfo_error(const char* s, int err_) + : std::runtime_error(rfb::format("%s: %s (%d)", s, + strerror(err_).c_str(), err_)), + err(err_) +{ +} + +getaddrinfo_error::getaddrinfo_error(const std::string& s, int err_) + : std::runtime_error(rfb::format("%s: %s (%d)", s.c_str(), + strerror(err_).c_str(), err_)), + err(err_) +{ } -GAIException::GAIException(const char* s, int err_) - : Exception("%s", s), err(err_) +std::string getaddrinfo_error::strerror(int err_) const { - strncat(str_, ": ", len-1-strlen(str_)); #ifdef _WIN32 - wchar_t *currStr = new wchar_t[len-strlen(str_)]; - wcsncpy(currStr, gai_strerrorW(err), len-1-strlen(str_)); - WideCharToMultiByte(CP_UTF8, 0, currStr, -1, str_+strlen(str_), - len-1-strlen(str_), nullptr, nullptr); - delete [] currStr; + char str[256]; + + WideCharToMultiByte(CP_UTF8, 0, gai_strerrorW(err_), -1, str, + sizeof(str), nullptr, nullptr); + + return str; #else - strncat(str_, gai_strerror(err), len-1-strlen(str_)); -#endif - strncat(str_, " (", len-1-strlen(str_)); - char buf[20]; -#ifdef WIN32 - if (err < 0) - sprintf(buf, "%x", err); - else + return gai_strerror(err_); #endif - sprintf(buf,"%d",err); - strncat(str_, buf, len-1-strlen(str_)); - strncat(str_, ")", len-1-strlen(str_)); } -PosixException::PosixException(const char* s, int err_) - : Exception("%s", s), err(err_) +posix_error::posix_error(const char* what_arg, int err_) + : std::runtime_error(rfb::format("%s: %s (%d)", what_arg, + strerror(err_).c_str(), err_)), + err(err_) +{ +} + +posix_error::posix_error(const std::string& what_arg, int err_) + : std::runtime_error(rfb::format("%s: %s (%d)", what_arg.c_str(), + strerror(err_).c_str(), err_)), + err(err_) { - strncat(str_, ": ", len-1-strlen(str_)); - strncat(str_, strerror(err), len-1-strlen(str_)); - strncat(str_, " (", len-1-strlen(str_)); - char buf[20]; - sprintf(buf,"%d",err); - strncat(str_, buf, len-1-strlen(str_)); - strncat(str_, ")", len-1-strlen(str_)); +} + +std::string posix_error::strerror(int err_) const +{ +#ifdef _WIN32 + char str[256]; + + WideCharToMultiByte(CP_UTF8, 0, _wcserror(err_), -1, str, + sizeof(str), nullptr, nullptr); + + return str; +#else + return ::strerror(err_); +#endif } #ifdef WIN32 -Win32Exception::Win32Exception(const char* s, unsigned err_) - : Exception("%s", s), err(err_) +win32_error::win32_error(const char* what_arg, unsigned err_) + : std::runtime_error(rfb::format("%s: %s (%d)", what_arg, + strerror(err_).c_str(), err_)), + err(err_) { - strncat(str_, ": ", len-1-strlen(str_)); - wchar_t *currStr = new wchar_t[len-strlen(str_)]; +} + +win32_error::win32_error(const std::string& what_arg, unsigned err_) + : std::runtime_error(rfb::format("%s: %s (%d)", what_arg.c_str(), + strerror(err_).c_str(), err_)), + err(err_) +{ +} + +std::string win32_error::strerror(unsigned err_) const +{ + wchar_t wstr[256]; + char str[256]; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, err, 0, currStr, len-1-strlen(str_), nullptr); - WideCharToMultiByte(CP_UTF8, 0, currStr, -1, str_+strlen(str_), - len-1-strlen(str_), nullptr, nullptr); - delete [] currStr; - - int l = strlen(str_); - if ((l >= 2) && (str_[l-2] == '\r') && (str_[l-1] == '\n')) - str_[l-2] = 0; - - strncat(str_, " (", len-1-strlen(str_)); - char buf[20]; - sprintf(buf,"%d",err); - strncat(str_, buf, len-1-strlen(str_)); - strncat(str_, ")", len-1-strlen(str_)); + nullptr, err_, 0, wstr, sizeof(wstr), nullptr); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, + sizeof(str), nullptr, nullptr); + + int l = strlen(str); + if ((l >= 2) && (str[l-2] == '\r') && (str[l-1] == '\n')) + str[l-2] = 0; + + return str; } #endif diff --git a/common/rdr/Exception.h b/common/rdr/Exception.h index c59f7e55..f3f878cb 100644 --- a/common/rdr/Exception.h +++ b/common/rdr/Exception.h @@ -1,6 +1,7 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright (C) 2004 Red Hat Inc. * Copyright (C) 2010 TigerVNC Team + * Copyright 2015-2024 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,46 +22,57 @@ #ifndef __RDR_EXCEPTION_H__ #define __RDR_EXCEPTION_H__ -namespace rdr { +#include <stdexcept> +#include <string> - struct Exception { - enum { len = 256 }; - char str_[len]; - Exception(const char *format=nullptr, ...) - __attribute__((__format__ (__printf__, 2, 3))); - virtual ~Exception() {} - virtual const char* str() const { return str_; } - }; +namespace rdr { - struct PosixException : public Exception { + class posix_error : public std::runtime_error { + public: int err; - PosixException(const char* s, int err_); + posix_error(const char* what_arg, int err_); + posix_error(const std::string& what_arg, int err_); + private: + std::string strerror(int err_) const; }; #ifdef WIN32 - struct Win32Exception : public Exception { + class win32_error : public std::runtime_error { + public: unsigned err; - Win32Exception(const char* s, unsigned err_); + win32_error(const char* what_arg, unsigned err_); + win32_error(const std::string& what_arg, unsigned err_); + private: + std::string strerror(unsigned err_) const; }; #endif #ifdef WIN32 - struct SocketException : public Win32Exception { - SocketException(const char* text, unsigned err_) : Win32Exception(text, err_) {} + class socket_error : public win32_error { + public: + socket_error(const char* what_arg, unsigned err_) : win32_error(what_arg, err_) {} + socket_error(const std::string& what_arg, unsigned err_) : win32_error(what_arg, err_) {} }; #else - struct SocketException : public PosixException { - SocketException(const char* text, int err_) : PosixException(text, err_) {} + class socket_error : public posix_error { + public: + socket_error(const char* what_arg, unsigned err_) : posix_error(what_arg, err_) {} + socket_error(const std::string& what_arg, unsigned err_) : posix_error(what_arg, err_) {} }; #endif - struct GAIException : public Exception { + class getaddrinfo_error : public std::runtime_error { + public: int err; - GAIException(const char* s, int err_); + getaddrinfo_error(const char* s, int err_); + getaddrinfo_error(const std::string& s, int err_); + private: + std::string strerror(int err_) const; }; - struct EndOfStream : public Exception { - EndOfStream() : Exception("End of stream") {} + class end_of_stream : public std::runtime_error { + public: + end_of_stream() : std::runtime_error("End of stream") {} }; } diff --git a/common/rdr/FdInStream.cxx b/common/rdr/FdInStream.cxx index bddee482..23ea2f8c 100644 --- a/common/rdr/FdInStream.cxx +++ b/common/rdr/FdInStream.cxx @@ -92,7 +92,7 @@ size_t FdInStream::readFd(uint8_t* buf, size_t len) } while (n < 0 && errorNumber == EINTR); if (n < 0) - throw SocketException("select", errorNumber); + throw socket_error("select", errorNumber); if (n == 0) return 0; @@ -102,9 +102,9 @@ size_t FdInStream::readFd(uint8_t* buf, size_t len) } while (n < 0 && errorNumber == EINTR); if (n < 0) - throw SocketException("read", errorNumber); + throw socket_error("read", errorNumber); if (n == 0) - throw EndOfStream(); + throw end_of_stream(); return n; } diff --git a/common/rdr/FdOutStream.cxx b/common/rdr/FdOutStream.cxx index 1b6049ca..6db8c0bb 100644 --- a/common/rdr/FdOutStream.cxx +++ b/common/rdr/FdOutStream.cxx @@ -117,7 +117,7 @@ size_t FdOutStream::writeFd(const uint8_t* data, size_t length) } while (n < 0 && errorNumber == EINTR); if (n < 0) - throw SocketException("select", errorNumber); + throw 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 SocketException("write", errorNumber); + throw socket_error("write", errorNumber); gettimeofday(&lastWrite, nullptr); diff --git a/common/rdr/FileInStream.cxx b/common/rdr/FileInStream.cxx index db646a7e..df09ea76 100644 --- a/common/rdr/FileInStream.cxx +++ b/common/rdr/FileInStream.cxx @@ -33,7 +33,7 @@ FileInStream::FileInStream(const char *fileName) { file = fopen(fileName, "rb"); if (!file) - throw PosixException("fopen", errno); + throw posix_error("fopen", errno); } FileInStream::~FileInStream(void) { @@ -48,9 +48,9 @@ bool FileInStream::fillBuffer() size_t n = fread((uint8_t*)end, 1, availSpace(), file); if (n == 0) { if (ferror(file)) - throw PosixException("fread", errno); + throw posix_error("fread", errno); if (feof(file)) - throw EndOfStream(); + throw end_of_stream(); return false; } end += n; diff --git a/common/rdr/HexInStream.cxx b/common/rdr/HexInStream.cxx index 11f98498..69c3e260 100644 --- a/common/rdr/HexInStream.cxx +++ b/common/rdr/HexInStream.cxx @@ -23,7 +23,6 @@ #include <algorithm> #include <rdr/HexInStream.h> -#include <rdr/Exception.h> #include <rfb/util.h> using namespace rdr; @@ -46,7 +45,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)) - throw Exception("HexInStream: Invalid input data"); + throw std::runtime_error("HexInStream: Invalid input data"); } in_stream.setptr(length*2); diff --git a/common/rdr/InStream.h b/common/rdr/InStream.h index 939439e1..5623142c 100644 --- a/common/rdr/InStream.h +++ b/common/rdr/InStream.h @@ -28,7 +28,7 @@ #include <stdint.h> #include <string.h> // for memcpy -#include <rdr/Exception.h> +#include <stdexcept> // Check that callers are using InStream properly, // useful when writing new protocol handling @@ -101,21 +101,21 @@ namespace rdr { inline void setRestorePoint() { #ifdef RFB_INSTREAM_CHECK if (restorePoint != nullptr) - throw Exception("Nested use of input stream restore point"); + throw std::logic_error("Nested use of input stream restore point"); #endif restorePoint = ptr; } inline void clearRestorePoint() { #ifdef RFB_INSTREAM_CHECK if (restorePoint == nullptr) - throw Exception("Incorrect clearing of input stream restore point"); + throw std::logic_error("Incorrect clearing of input stream restore point"); #endif restorePoint = nullptr; } inline void gotoRestorePoint() { #ifdef RFB_INSTREAM_CHECK if (restorePoint == nullptr) - throw Exception("Incorrect activation of input stream restore point"); + throw std::logic_error("Incorrect activation of input stream restore point"); #endif ptr = restorePoint; clearRestorePoint(); @@ -176,7 +176,7 @@ namespace rdr { inline const uint8_t* getptr(size_t length) { check(length); return ptr; } inline void setptr(size_t length) { if (length > avail()) - throw Exception("Input stream overflow"); + throw std::out_of_range("Input stream overflow"); skip(length); } private: @@ -189,11 +189,11 @@ namespace rdr { inline void check(size_t bytes) { #ifdef RFB_INSTREAM_CHECK if (bytes > checkedBytes) - throw Exception("Input stream used without underrun check"); + throw std::logic_error("Input stream used without underrun check"); checkedBytes -= bytes; #endif if (bytes > (size_t)(end - ptr)) - throw Exception("InStream buffer underrun"); + throw std::out_of_range("InStream buffer underrun"); } // overrun() is implemented by a derived class to cope with buffer overrun. diff --git a/common/rdr/MemInStream.h b/common/rdr/MemInStream.h index e10273b1..78ee2dee 100644 --- a/common/rdr/MemInStream.h +++ b/common/rdr/MemInStream.h @@ -59,7 +59,7 @@ namespace rdr { private: - bool overrun(size_t /*needed*/) override { throw EndOfStream(); } + bool overrun(size_t /*needed*/) override { throw end_of_stream(); } const uint8_t* start; bool deleteWhenDone; }; diff --git a/common/rdr/MemOutStream.h b/common/rdr/MemOutStream.h index 9bf2b810..bf05d92c 100644 --- a/common/rdr/MemOutStream.h +++ b/common/rdr/MemOutStream.h @@ -23,7 +23,6 @@ #ifndef __RDR_MEMOUTSTREAM_H__ #define __RDR_MEMOUTSTREAM_H__ -#include <rdr/Exception.h> #include <rdr/OutStream.h> namespace rdr { @@ -61,7 +60,7 @@ namespace rdr { len = (end - start) * 2; if (len < (size_t)(end - start)) - throw Exception("Overflow in MemOutStream::overrun()"); + throw std::out_of_range("Overflow in MemOutStream::overrun()"); uint8_t* newStart = new uint8_t[len]; memcpy(newStart, start, ptr - start); diff --git a/common/rdr/OutStream.h b/common/rdr/OutStream.h index 2921b232..b78ec4b0 100644 --- a/common/rdr/OutStream.h +++ b/common/rdr/OutStream.h @@ -27,7 +27,8 @@ #include <stdint.h> #include <string.h> // for memcpy -#include <rdr/Exception.h> +#include <stdexcept> + #include <rdr/InStream.h> namespace rdr { @@ -129,7 +130,7 @@ namespace rdr { inline uint8_t* getptr(size_t length) { check(length); return ptr; } inline void setptr(size_t length) { if (length > avail()) - throw Exception("Output stream overflow"); + throw std::out_of_range("Output stream overflow"); ptr += length; } private: diff --git a/common/rdr/RandomStream.cxx b/common/rdr/RandomStream.cxx index b045d48a..3a524102 100644 --- a/common/rdr/RandomStream.cxx +++ b/common/rdr/RandomStream.cxx @@ -89,7 +89,7 @@ bool RandomStream::fillBuffer() { #ifdef RFB_HAVE_WINCRYPT if (provider) { if (!CryptGenRandom(provider, availSpace(), (uint8_t*)end)) - throw rdr::Win32Exception("Unable to CryptGenRandom", GetLastError()); + throw rdr::win32_error("Unable to CryptGenRandom", GetLastError()); end += availSpace(); } else { #else @@ -97,8 +97,8 @@ bool RandomStream::fillBuffer() { if (fp) { size_t n = fread((uint8_t*)end, 1, availSpace(), fp); if (n <= 0) - throw rdr::PosixException("Reading /dev/urandom or /dev/random failed", - errno); + throw rdr::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 0f75a4da..ccff6090 100644 --- a/common/rdr/TLSException.cxx +++ b/common/rdr/TLSException.cxx @@ -24,6 +24,8 @@ #include <rdr/TLSException.h> +#include <rfb/util.h> + #include <string.h> #include <stdio.h> #ifdef HAVE_GNUTLS @@ -33,8 +35,10 @@ using namespace rdr; #ifdef HAVE_GNUTLS -TLSException::TLSException(const char* s, int err_) - : Exception("%s: %s (%d)", s, gnutls_strerror(err_), err_), err(err_) +tls_error::tls_error(const char* s, int err_) + : std::runtime_error(rfb::format("%s: %s (%d)", s, + gnutls_strerror(err_), err_)), + err(err_) { } #endif /* HAVE_GNUTLS */ diff --git a/common/rdr/TLSException.h b/common/rdr/TLSException.h index b519bfef..cfa73f69 100644 --- a/common/rdr/TLSException.h +++ b/common/rdr/TLSException.h @@ -25,9 +25,10 @@ namespace rdr { - struct TLSException : public Exception { + class tls_error : public std::runtime_error { + public: int err; - TLSException(const char* s, int err_); + tls_error(const char* s, int err_); }; } diff --git a/common/rdr/TLSInStream.cxx b/common/rdr/TLSInStream.cxx index f8f4fcf9..7c867e88 100644 --- a/common/rdr/TLSInStream.cxx +++ b/common/rdr/TLSInStream.cxx @@ -54,17 +54,17 @@ ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size) size = in->avail(); in->readBytes((uint8_t*)data, size); - } catch (EndOfStream&) { + } catch (end_of_stream&) { return 0; - } catch (SocketException& e) { - vlog.error("Failure reading TLS data: %s", e.str()); + } 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 SocketException(e); + self->saved_exception = new socket_error(e); return -1; - } catch (Exception& e) { - vlog.error("Failure reading TLS data: %s", e.str()); + } catch (std::exception& e) { + vlog.error("Failure reading TLS data: %s", e.what()); gnutls_transport_set_errno(self->session, EINVAL); - self->saved_exception = new Exception(e); + self->saved_exception = new std::exception(e); return -1; } @@ -121,10 +121,10 @@ size_t TLSInStream::readTLS(uint8_t* buf, size_t len) throw *saved_exception; if (n < 0) - throw TLSException("readTLS", n); + throw tls_error("readTLS", n); if (n == 0) - throw EndOfStream(); + throw end_of_stream(); return n; } diff --git a/common/rdr/TLSInStream.h b/common/rdr/TLSInStream.h index ca69ddde..2269b09d 100644 --- a/common/rdr/TLSInStream.h +++ b/common/rdr/TLSInStream.h @@ -41,7 +41,7 @@ namespace rdr { InStream* in; bool streamEmpty; - Exception* saved_exception; + std::exception* saved_exception; }; }; diff --git a/common/rdr/TLSOutStream.cxx b/common/rdr/TLSOutStream.cxx index ccb229e1..1e555fc1 100644 --- a/common/rdr/TLSOutStream.cxx +++ b/common/rdr/TLSOutStream.cxx @@ -46,15 +46,15 @@ ssize_t TLSOutStream::push(gnutls_transport_ptr_t str, const void* data, try { out->writeBytes((const uint8_t*)data, size); out->flush(); - } catch (SocketException& e) { - vlog.error("Failure sending TLS data: %s", e.str()); + } 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 SocketException(e); + self->saved_exception = new socket_error(e); return -1; - } catch (Exception& e) { - vlog.error("Failure sending TLS data: %s", e.str()); + } catch (std::exception& e) { + vlog.error("Failure sending TLS data: %s", e.what()); gnutls_transport_set_errno(self->session, EINVAL); - self->saved_exception = new Exception(e); + self->saved_exception = new std::exception(e); return -1; } @@ -118,7 +118,7 @@ size_t TLSOutStream::writeTLS(const uint8_t* data, size_t length) throw *saved_exception; if (n < 0) - throw TLSException("writeTLS", n); + throw tls_error("writeTLS", n); return n; } diff --git a/common/rdr/TLSOutStream.h b/common/rdr/TLSOutStream.h index 35714238..659f16f0 100644 --- a/common/rdr/TLSOutStream.h +++ b/common/rdr/TLSOutStream.h @@ -42,7 +42,7 @@ namespace rdr { gnutls_session_t session; OutStream* out; - Exception* saved_exception; + std::exception* saved_exception; }; }; diff --git a/common/rdr/ZlibInStream.cxx b/common/rdr/ZlibInStream.cxx index a90d50f7..c9f8aeca 100644 --- a/common/rdr/ZlibInStream.cxx +++ b/common/rdr/ZlibInStream.cxx @@ -23,7 +23,6 @@ #include <assert.h> #include <rdr/ZlibInStream.h> -#include <rdr/Exception.h> #include <zlib.h> using namespace rdr; @@ -50,7 +49,7 @@ void ZlibInStream::flushUnderlying() { while (bytesIn > 0) { if (!hasData(1)) - throw Exception("ZlibInStream: failed to flush remaining stream data"); + throw std::runtime_error("ZlibInStream: failed to flush remaining stream data"); skip(avail()); } @@ -76,7 +75,7 @@ void ZlibInStream::init() if (inflateInit(zs) != Z_OK) { delete zs; zs = nullptr; - throw Exception("ZlibInStream: inflateInit failed"); + throw std::runtime_error("ZlibInStream: inflateInit failed"); } } @@ -92,7 +91,7 @@ void ZlibInStream::deinit() bool ZlibInStream::fillBuffer() { if (!underlying) - throw Exception("ZlibInStream overrun: no underlying stream"); + throw std::runtime_error("ZlibInStream overrun: no underlying stream"); zs->next_out = (uint8_t*)end; zs->avail_out = availSpace(); @@ -107,7 +106,7 @@ bool ZlibInStream::fillBuffer() int rc = inflate(zs, Z_SYNC_FLUSH); if (rc < 0) { - throw Exception("ZlibInStream: inflate failed"); + throw std::runtime_error("ZlibInStream: inflate failed"); } bytesIn -= length - zs->avail_in; diff --git a/common/rdr/ZlibOutStream.cxx b/common/rdr/ZlibOutStream.cxx index f62eb22a..5079c723 100644 --- a/common/rdr/ZlibOutStream.cxx +++ b/common/rdr/ZlibOutStream.cxx @@ -24,7 +24,6 @@ #include <stdio.h> #include <rdr/ZlibOutStream.h> -#include <rdr/Exception.h> #include <rfb/LogWriter.h> #include <zlib.h> @@ -46,7 +45,7 @@ ZlibOutStream::ZlibOutStream(OutStream* os, int compressLevel) zs->avail_in = 0; if (deflateInit(zs, compressLevel) != Z_OK) { delete zs; - throw Exception("ZlibOutStream: deflateInit failed"); + throw std::runtime_error("ZlibOutStream: deflateInit failed"); } } @@ -54,7 +53,7 @@ ZlibOutStream::~ZlibOutStream() { try { flush(); - } catch (Exception&) { + } catch (std::exception&) { } deflateEnd(zs); delete zs; @@ -113,7 +112,7 @@ void ZlibOutStream::deflate(int flush) int rc; if (!underlying) - throw Exception("ZlibOutStream: underlying OutStream has not been set"); + throw std::runtime_error("ZlibOutStream: underlying OutStream has not been set"); if ((flush == Z_NO_FLUSH) && (zs->avail_in == 0)) return; @@ -134,7 +133,7 @@ void ZlibOutStream::deflate(int flush) if ((rc == Z_BUF_ERROR) && (flush != Z_NO_FLUSH)) break; - throw Exception("ZlibOutStream: deflate failed"); + throw std::runtime_error("ZlibOutStream: deflate failed"); } #ifdef ZLIBOUT_DEBUG @@ -168,7 +167,7 @@ void ZlibOutStream::checkCompressionLevel() // explicit flush we did above. It should be safe to ignore though // as the first flush should have left things in a stable state... if (rc != Z_BUF_ERROR) - throw Exception("ZlibOutStream: deflateParams failed"); + throw std::runtime_error("ZlibOutStream: deflateParams failed"); } compressionLevel = newLevel; diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx index a682b810..e8451337 100644 --- a/common/rfb/CConnection.cxx +++ b/common/rfb/CConnection.cxx @@ -147,11 +147,11 @@ bool CConnection::processMsg() case RFBSTATE_INITIALISATION: return processInitMsg(); break; case RFBSTATE_NORMAL: return reader_->readMsg(); break; case RFBSTATE_CLOSING: - throw Exception("CConnection::processMsg: called while closing"); + throw std::logic_error("CConnection::processMsg: called while closing"); case RFBSTATE_UNINITIALISED: - throw Exception("CConnection::processMsg: not initialised yet?"); + throw std::logic_error("CConnection::processMsg: not initialised yet?"); default: - throw Exception("CConnection::processMsg: invalid state"); + throw std::logic_error("CConnection::processMsg: invalid state"); } } @@ -172,7 +172,7 @@ bool CConnection::processVersionMsg() if (sscanf(verStr, "RFB %03d.%03d\n", &majorVersion, &minorVersion) != 2) { state_ = RFBSTATE_INVALID; - throw Exception("reading version failed: not an RFB server?"); + throw protocol_error("reading version failed: not an RFB server?"); } server.setVersion(majorVersion, minorVersion); @@ -185,8 +185,10 @@ bool CConnection::processVersionMsg() vlog.error("Server gave unsupported RFB protocol version %d.%d", server.majorVersion, server.minorVersion); state_ = RFBSTATE_INVALID; - throw Exception("Server gave unsupported RFB protocol version %d.%d", - server.majorVersion, server.minorVersion); + throw protocol_error(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)) { @@ -233,7 +235,7 @@ bool CConnection::processSecurityTypesMsg() secType = secTypeInvalid; } else { vlog.error("Unknown 3.3 security type %d", secType); - throw Exception("Unknown 3.3 security type"); + throw protocol_error("Unknown 3.3 security type"); } } else { @@ -283,7 +285,7 @@ bool CConnection::processSecurityTypesMsg() if (secType == secTypeInvalid) { state_ = RFBSTATE_INVALID; vlog.error("No matching security types"); - throw Exception("No matching security types"); + throw protocol_error("No matching security types"); } state_ = RFBSTATE_SECURITY; @@ -327,12 +329,12 @@ bool CConnection::processSecurityResultMsg() vlog.debug("Auth failed: Too many tries"); break; default: - throw Exception("Unknown security result from server"); + throw protocol_error("Unknown security result from server"); } if (server.beforeVersion(3,8)) { state_ = RFBSTATE_INVALID; - throw AuthFailureException("Authentication failed"); + throw auth_error("Authentication failed"); } state_ = RFBSTATE_SECURITY_REASON; @@ -358,7 +360,7 @@ bool CConnection::processSecurityReasonMsg() reason[len] = '\0'; state_ = RFBSTATE_INVALID; - throw AuthFailureException(reason.data()); + throw auth_error(reason.data()); } bool CConnection::processInitMsg() @@ -387,8 +389,8 @@ void CConnection::close() */ try { decoder.flush(); - } catch (rdr::Exception& e) { - vlog.error("%s", e.str()); + } catch (std::exception& e) { + vlog.error("%s", e.what()); } setFramebuffer(nullptr); @@ -835,6 +837,7 @@ void CConnection::updateEncodings() encodings.push_back(pseudoEncodingContinuousUpdates); encodings.push_back(pseudoEncodingFence); encodings.push_back(pseudoEncodingQEMUKeyEvent); + encodings.push_back(pseudoEncodingExtendedMouseButtons); if (Decoder::supported(preferredEncoding)) { encodings.push_back(preferredEncoding); diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h index 3f277d71..9101bf26 100644 --- a/common/rfb/CConnection.h +++ b/common/rfb/CConnection.h @@ -273,7 +273,7 @@ namespace rfb { bool processSecurityResultMsg(); bool processSecurityReasonMsg(); bool processInitMsg(); - void throwAuthFailureException(); + void throwAuthError(); void securityCompleted(); void requestNewUpdate(); diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx index 4489dbd4..0f3f6cd5 100644 --- a/common/rfb/CMsgHandler.cxx +++ b/common/rfb/CMsgHandler.cxx @@ -75,6 +75,11 @@ void CMsgHandler::endOfContinuousUpdates() server.supportsContinuousUpdates = true; } +void CMsgHandler::supportsExtendedMouseButtons() +{ + server.supportsExtendedMouseButtons = true; +} + void CMsgHandler::supportsQEMUKeyEvent() { server.supportsQEMUKeyEvent = true; diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h index 9e5f7de2..b484b695 100644 --- a/common/rfb/CMsgHandler.h +++ b/common/rfb/CMsgHandler.h @@ -57,6 +57,7 @@ namespace rfb { virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]); virtual void endOfContinuousUpdates(); virtual void supportsQEMUKeyEvent(); + virtual void supportsExtendedMouseButtons(); virtual void serverInit(int width, int height, const PixelFormat& pf, const char* name) = 0; diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx index 5dbfa5be..a10f7c47 100644 --- a/common/rfb/CMsgReader.cxx +++ b/common/rfb/CMsgReader.cxx @@ -119,7 +119,7 @@ bool CMsgReader::readMsg() ret = readEndOfContinuousUpdates(); break; default: - throw Exception("Unknown message type %d", currentMsgType); + throw protocol_error(format("Unknown message type %d", currentMsgType)); } if (ret) @@ -202,6 +202,10 @@ bool CMsgReader::readMsg() handler->supportsQEMUKeyEvent(); ret = true; break; + case pseudoEncodingExtendedMouseButtons: + handler->supportsExtendedMouseButtons(); + ret = true; + break; default: ret = readRect(dataRect, rectEncoding); break; @@ -301,7 +305,7 @@ bool CMsgReader::readExtendedClipboard(int32_t len) return false; if (len < 4) - throw Exception("Invalid extended clipboard message"); + throw protocol_error("Invalid extended clipboard message"); if (len > maxCutText) { vlog.error("Extended clipboard message too long (%d bytes) - ignoring", len); is->skip(len); @@ -323,7 +327,7 @@ bool CMsgReader::readExtendedClipboard(int32_t len) } if (len < (int32_t)(4 + 4*num)) - throw Exception("Invalid extended clipboard message"); + throw protocol_error("Invalid extended clipboard message"); num = 0; for (i = 0;i < 16;i++) { @@ -348,7 +352,7 @@ bool CMsgReader::readExtendedClipboard(int32_t len) continue; if (!zis.hasData(4)) - throw Exception("Extended clipboard decode error"); + throw protocol_error("Extended clipboard decode error"); lengths[num] = zis.readU32(); @@ -361,7 +365,7 @@ bool CMsgReader::readExtendedClipboard(int32_t len) size_t chunk; if (!zis.hasData(1)) - throw Exception("Extended clipboard decode error"); + throw protocol_error("Extended clipboard decode error"); chunk = zis.avail(); if (chunk > lengths[num]) @@ -377,7 +381,7 @@ bool CMsgReader::readExtendedClipboard(int32_t len) } if (!zis.hasData(lengths[num])) - throw Exception("Extended clipboard decode error"); + throw protocol_error("Extended clipboard decode error"); buffers[num] = new uint8_t[lengths[num]]; zis.readBytes(buffers[num], lengths[num]); @@ -407,7 +411,7 @@ bool CMsgReader::readExtendedClipboard(int32_t len) handler->handleClipboardNotify(flags); break; default: - throw Exception("Invalid extended clipboard action"); + throw protocol_error("Invalid extended clipboard action"); } } @@ -473,7 +477,7 @@ bool CMsgReader::readRect(const Rect& r, int encoding) vlog.error("Rect too big: %dx%d at %d,%d exceeds %dx%d", r.width(), r.height(), r.tl.x, r.tl.y, handler->server.width(), handler->server.height()); - throw Exception("Rect too big"); + throw protocol_error("Rect too big"); } if (r.is_empty()) @@ -485,7 +489,7 @@ bool CMsgReader::readRect(const Rect& r, int encoding) bool CMsgReader::readSetXCursor(int width, int height, const Point& hotspot) { if (width > maxCursorSize || height > maxCursorSize) - throw Exception("Too big cursor"); + throw protocol_error("Too big cursor"); std::vector<uint8_t> rgba(width*height*4); @@ -549,7 +553,7 @@ bool CMsgReader::readSetXCursor(int width, int height, const Point& hotspot) bool CMsgReader::readSetCursor(int width, int height, const Point& hotspot) { if (width > maxCursorSize || height > maxCursorSize) - throw Exception("Too big cursor"); + throw protocol_error("Too big cursor"); int data_len = width * height * (handler->server.pf().bpp/8); int mask_len = ((width+7)/8) * height; @@ -595,7 +599,7 @@ bool CMsgReader::readSetCursor(int width, int height, const Point& hotspot) bool CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hotspot) { if (width > maxCursorSize || height > maxCursorSize) - throw Exception("Too big cursor"); + throw protocol_error("Too big cursor"); const PixelFormat rgbaPF(32, 32, false, true, 255, 255, 255, 16, 8, 0); ManagedPixelBuffer pb(rgbaPF, width, height); @@ -656,7 +660,7 @@ bool CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hots bool CMsgReader::readSetVMwareCursor(int width, int height, const Point& hotspot) { if (width > maxCursorSize || height > maxCursorSize) - throw Exception("Too big cursor"); + throw protocol_error("Too big cursor"); uint8_t type; @@ -750,7 +754,7 @@ bool CMsgReader::readSetVMwareCursor(int width, int height, const Point& hotspot handler->setCursor(width, height, hotspot, data.data()); } else { - throw Exception("Unknown cursor type"); + throw protocol_error("Unknown cursor type"); } return true; diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx index 1bd8040f..0128c431 100644 --- a/common/rfb/CMsgWriter.cxx +++ b/common/rfb/CMsgWriter.cxx @@ -22,6 +22,7 @@ #endif #include <stdio.h> +#include <assert.h> #include <rdr/OutStream.h> #include <rdr/MemOutStream.h> @@ -31,7 +32,6 @@ #include <rfb/fenceTypes.h> #include <rfb/qemuTypes.h> #include <rfb/clipboardTypes.h> -#include <rfb/Exception.h> #include <rfb/PixelFormat.h> #include <rfb/Rect.h> #include <rfb/ServerParams.h> @@ -77,7 +77,7 @@ void CMsgWriter::writeSetDesktopSize(int width, int height, const ScreenSet& layout) { if (!server->supportsSetDesktopSize) - throw Exception("Server does not support SetDesktopSize"); + throw std::logic_error("Server does not support SetDesktopSize"); startMsg(msgTypeSetDesktopSize); os->pad(1); @@ -116,7 +116,7 @@ void CMsgWriter::writeEnableContinuousUpdates(bool enable, int x, int y, int w, int h) { if (!server->supportsContinuousUpdates) - throw Exception("Server does not support continuous updates"); + throw std::logic_error("Server does not support continuous updates"); startMsg(msgTypeEnableContinuousUpdates); @@ -133,11 +133,11 @@ void CMsgWriter::writeEnableContinuousUpdates(bool enable, void CMsgWriter::writeFence(uint32_t flags, unsigned len, const uint8_t data[]) { if (!server->supportsFence) - throw Exception("Server does not support fences"); + throw std::logic_error("Server does not support fences"); if (len > 64) - throw Exception("Too large fence payload"); + throw std::out_of_range("Too large fence payload"); if ((flags & ~fenceFlagsSupported) != 0) - throw Exception("Unknown fence flags"); + throw std::invalid_argument("Unknown fence flags"); startMsg(msgTypeClientFence); os->pad(3); @@ -173,18 +173,47 @@ void CMsgWriter::writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down) } -void CMsgWriter::writePointerEvent(const Point& pos, uint8_t buttonMask) +void CMsgWriter::writePointerEvent(const Point& pos, uint16_t buttonMask) { Point p(pos); + bool extendedMouseButtons; + if (p.x < 0) p.x = 0; if (p.y < 0) p.y = 0; if (p.x >= server->width()) p.x = server->width() - 1; if (p.y >= server->height()) p.y = server->height() - 1; + /* The highest bit in buttonMask is never sent to the server */ + assert(!(buttonMask & 0x8000)); + + /* Only send extended pointerEvent message when needed */ + extendedMouseButtons = buttonMask & 0x7f80; + startMsg(msgTypePointerEvent); - os->writeU8(buttonMask); - os->writeU16(p.x); - os->writeU16(p.y); + if (server->supportsExtendedMouseButtons && extendedMouseButtons) { + int higherBits; + int lowerBits; + + higherBits = (buttonMask >> 7) & 0xff; + assert(!(higherBits & 0xfc)); /* Bits 2-7 are reserved */ + + lowerBits = buttonMask & 0x7f; + lowerBits |= 0x80; /* Set marker bit to 1 */ + + os->writeU8(lowerBits); + os->writeU16(p.x); + os->writeU16(p.y); + os->writeU8(higherBits); + } else { + /* Marker bit must be set to 0, otherwise the server might confuse + * the marker bit with the highest bit in a normal PointerEvent + * message. + */ + buttonMask &= 0x7f; + os->writeU8(buttonMask); + os->writeU16(p.x); + os->writeU16(p.y); + } endMsg(); } @@ -192,7 +221,7 @@ void CMsgWriter::writePointerEvent(const Point& pos, uint8_t buttonMask) void CMsgWriter::writeClientCutText(const char* str) { if (strchr(str, '\r') != nullptr) - throw Exception("Invalid carriage return in clipboard data"); + throw std::invalid_argument("Invalid carriage return in clipboard data"); std::string latin1(utf8ToLatin1(str)); @@ -209,7 +238,7 @@ void CMsgWriter::writeClipboardCaps(uint32_t caps, size_t i, count; if (!(server->clipboardFlags() & clipboardCaps)) - throw Exception("Server does not support clipboard \"caps\" action"); + throw std::logic_error("Server does not support clipboard \"caps\" action"); count = 0; for (i = 0;i < 16;i++) { @@ -235,7 +264,7 @@ void CMsgWriter::writeClipboardCaps(uint32_t caps, void CMsgWriter::writeClipboardRequest(uint32_t flags) { if (!(server->clipboardFlags() & clipboardRequest)) - throw Exception("Server does not support clipboard \"request\" action"); + throw std::logic_error("Server does not support clipboard \"request\" action"); startMsg(msgTypeClientCutText); os->pad(3); @@ -247,7 +276,7 @@ void CMsgWriter::writeClipboardRequest(uint32_t flags) void CMsgWriter::writeClipboardPeek(uint32_t flags) { if (!(server->clipboardFlags() & clipboardPeek)) - throw Exception("Server does not support clipboard \"peek\" action"); + throw std::logic_error("Server does not support clipboard \"peek\" action"); startMsg(msgTypeClientCutText); os->pad(3); @@ -259,7 +288,7 @@ void CMsgWriter::writeClipboardPeek(uint32_t flags) void CMsgWriter::writeClipboardNotify(uint32_t flags) { if (!(server->clipboardFlags() & clipboardNotify)) - throw Exception("Server does not support clipboard \"notify\" action"); + throw std::logic_error("Server does not support clipboard \"notify\" action"); startMsg(msgTypeClientCutText); os->pad(3); @@ -278,7 +307,7 @@ void CMsgWriter::writeClipboardProvide(uint32_t flags, int i, count; if (!(server->clipboardFlags() & clipboardProvide)) - throw Exception("Server does not support clipboard \"provide\" action"); + throw std::logic_error("Server does not support clipboard \"provide\" action"); zos.setUnderlying(&mos); diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h index 61df567f..9cb4adec 100644 --- a/common/rfb/CMsgWriter.h +++ b/common/rfb/CMsgWriter.h @@ -54,7 +54,7 @@ namespace rfb { 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, uint8_t buttonMask); + void writePointerEvent(const Point& pos, uint16_t buttonMask); void writeClientCutText(const char* str); diff --git a/common/rfb/CSecurityDH.cxx b/common/rfb/CSecurityDH.cxx index 6eafbd9c..d8308cbf 100644 --- a/common/rfb/CSecurityDH.cxx +++ b/common/rfb/CSecurityDH.cxx @@ -86,9 +86,9 @@ bool CSecurityDH::readKey() uint16_t gen = is->readU16(); keyLength = is->readU16(); if (keyLength < MinKeyLength) - throw Exception("DH key is too short"); + throw protocol_error("DH key is too short"); if (keyLength > MaxKeyLength) - throw Exception("DH key is too long"); + throw protocol_error("DH key is too long"); if (!is->hasDataOrRestore(keyLength * 2)) return false; is->clearRestorePoint(); @@ -112,7 +112,7 @@ void CSecurityDH::writeCredentials() std::vector<uint8_t> bBytes(keyLength); if (!rs.hasData(keyLength)) - throw Exception("failed to generate DH private key"); + throw std::runtime_error("failed to generate DH private key"); rs.readBytes(bBytes.data(), bBytes.size()); nettle_mpz_set_str_256_u(b, bBytes.size(), bBytes.data()); mpz_powm(k, A, b, p); @@ -132,13 +132,13 @@ void CSecurityDH::writeCredentials() uint8_t buf[128]; if (!rs.hasData(128)) - throw Exception("failed to generate random padding"); + throw std::runtime_error("failed to generate random padding"); rs.readBytes(buf, 128); if (username.size() >= 64) - throw Exception("username is too long"); + throw std::out_of_range("username is too long"); memcpy(buf, username.c_str(), username.size() + 1); if (password.size() >= 64) - throw Exception("password is too long"); + throw std::out_of_range("password is too long"); memcpy(buf + 64, password.c_str(), password.size() + 1); aes128_encrypt(&aesCtx, 128, buf, buf); diff --git a/common/rfb/CSecurityMSLogonII.cxx b/common/rfb/CSecurityMSLogonII.cxx index f8ff36c1..85736b44 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 <rfb/Exception.h> #include <os/os.h> using namespace rfb; @@ -101,7 +100,7 @@ void CSecurityMSLogonII::writeCredentials() std::vector<uint8_t> bBytes(8); if (!rs.hasData(8)) - throw Exception("failed to generate DH private key"); + throw std::runtime_error("failed to generate DH private key"); rs.readBytes(bBytes.data(), bBytes.size()); nettle_mpz_set_str_256_u(b, bBytes.size(), bBytes.data()); mpz_powm(k, A, b, p); @@ -123,14 +122,14 @@ void CSecurityMSLogonII::writeCredentials() } if (!rs.hasData(256 + 64)) - throw Exception("failed to generate random padding"); + throw std::runtime_error("failed to generate random padding"); rs.readBytes(user, 256); rs.readBytes(pass, 64); if (username.size() >= 256) - throw Exception("username is too long"); + throw std::out_of_range("username is too long"); memcpy(user, username.c_str(), username.size() + 1); if (password.size() >= 64) - throw Exception("password is too long"); + throw std::out_of_range("password is too long"); memcpy(pass, password.c_str(), password.size() + 1); // DES-CBC with the original key as IV, and the reversed one as the DES key diff --git a/common/rfb/CSecurityRSAAES.cxx b/common/rfb/CSecurityRSAAES.cxx index 4baeb235..96fd20cd 100644 --- a/common/rfb/CSecurityRSAAES.cxx +++ b/common/rfb/CSecurityRSAAES.cxx @@ -134,7 +134,7 @@ static void random_func(void* ctx, size_t length, uint8_t* dst) { rdr::RandomStream* rs = (rdr::RandomStream*)ctx; if (!rs->hasData(length)) - throw Exception("failed to generate random"); + throw std::runtime_error("failed to generate random"); rs->readBytes(dst, length); } @@ -155,7 +155,7 @@ void CSecurityRSAAES::writePublicKey() if (!rsa_generate_keypair(&clientPublicKey, &clientKey, &rs, random_func, nullptr, nullptr, clientKeyLength, 0)) - throw Exception("failed to generate key"); + throw std::runtime_error("failed to generate key"); clientKeyN = new uint8_t[rsaKeySize]; clientKeyE = new uint8_t[rsaKeySize]; nettle_mpz_get_str_256(rsaKeySize, clientKeyN, clientPublicKey.n); @@ -174,9 +174,9 @@ bool CSecurityRSAAES::readPublicKey() is->setRestorePoint(); serverKeyLength = is->readU32(); if (serverKeyLength < MinKeyLength) - throw Exception("server key is too short"); + throw protocol_error("server key is too short"); if (serverKeyLength > MaxKeyLength) - throw Exception("server key is too long"); + throw protocol_error("server key is too long"); size_t size = (serverKeyLength + 7) / 8; if (!is->hasDataOrRestore(size * 2)) return false; @@ -189,7 +189,7 @@ bool CSecurityRSAAES::readPublicKey() nettle_mpz_set_str_256_u(serverKey.n, size, serverKeyN); nettle_mpz_set_str_256_u(serverKey.e, size, serverKeyE); if (!rsa_public_key_prepare(&serverKey)) - throw Exception("server key is invalid"); + throw protocol_error("server key is invalid"); return true; } @@ -215,14 +215,14 @@ void CSecurityRSAAES::verifyServer() "Please verify that the information is correct and press \"Yes\". " "Otherwise press \"No\"", f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]); if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, title, text.c_str())) - throw AuthCancelledException(); + throw auth_cancelled(); } void CSecurityRSAAES::writeRandom() { rdr::OutStream* os = cc->getOutStream(); if (!rs.hasData(keySize / 8)) - throw Exception("failed to generate random"); + throw std::runtime_error("failed to generate random"); rs.readBytes(clientRandom, keySize / 8); mpz_t x; mpz_init(x); @@ -236,7 +236,7 @@ void CSecurityRSAAES::writeRandom() } if (!res) { mpz_clear(x); - throw Exception("failed to encrypt random"); + throw std::runtime_error("failed to encrypt random"); } uint8_t* buffer = new uint8_t[serverKey.size]; nettle_mpz_get_str_256(serverKey.size, buffer, x); @@ -255,7 +255,7 @@ bool CSecurityRSAAES::readRandom() is->setRestorePoint(); size_t size = is->readU16(); if (size != clientKey.size) - throw Exception("client key length doesn't match"); + throw protocol_error("client key length doesn't match"); if (!is->hasDataOrRestore(size)) return false; is->clearRestorePoint(); @@ -268,7 +268,7 @@ bool CSecurityRSAAES::readRandom() if (!rsa_decrypt(&clientKey, &randomSize, serverRandom, x) || randomSize != (size_t)keySize / 8) { mpz_clear(x); - throw Exception("failed to decrypt server random"); + throw protocol_error("failed to decrypt server random"); } mpz_clear(x); return true; @@ -397,7 +397,7 @@ bool CSecurityRSAAES::readHash() sha256_digest(&ctx, hashSize, realHash); } if (memcmp(hash, realHash, hashSize) != 0) - throw Exception("hash doesn't match"); + throw protocol_error("hash doesn't match"); return true; } @@ -427,7 +427,7 @@ bool CSecurityRSAAES::readSubtype() return false; subtype = rais->readU8(); if (subtype != secTypeRA2UserPass && subtype != secTypeRA2Pass) - throw Exception("unknown RSA-AES subtype"); + throw protocol_error("unknown RSA-AES subtype"); return true; } @@ -443,7 +443,7 @@ void CSecurityRSAAES::writeCredentials() if (subtype == secTypeRA2UserPass) { if (username.size() > 255) - throw Exception("username is too long"); + throw std::out_of_range("username is too long"); raos->writeU8(username.size()); raos->writeBytes((const uint8_t*)username.data(), username.size()); } else { @@ -451,7 +451,7 @@ void CSecurityRSAAES::writeCredentials() } if (password.size() > 255) - throw Exception("password is too long"); + throw std::out_of_range("password is too long"); raos->writeU8(password.size()); raos->writeBytes((const uint8_t*)password.data(), password.size()); raos->flush(); diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx index 3b7868ba..9072ce50 100644 --- a/common/rfb/CSecurityTLS.cxx +++ b/common/rfb/CSecurityTLS.cxx @@ -80,7 +80,7 @@ CSecurityTLS::CSecurityTLS(CConnection* cc_, bool _anon) { int err = gnutls_global_init(); if (err != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_global_init()", err); + throw rdr::tls_error("gnutls_global_init()", err); } void CSecurityTLS::shutdown() @@ -146,15 +146,15 @@ bool CSecurityTLS::processMsg() return false; if (is->readU8() == 0) - throw Exception("Server failed to initialize TLS session"); + throw protocol_error("Server failed to initialize TLS session"); ret = gnutls_init(&session, GNUTLS_CLIENT); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_init()", ret); + throw rdr::tls_error("gnutls_init()", ret); ret = gnutls_set_default_priority(session); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_set_default_priority()", ret); + throw rdr::tls_error("gnutls_set_default_priority()", ret); setParam(); @@ -177,7 +177,7 @@ bool CSecurityTLS::processMsg() vlog.error("TLS Handshake failed: %s\n", gnutls_strerror (err)); shutdown(); - throw rdr::TLSException("TLS Handshake failed", err); + throw rdr::tls_error("TLS Handshake failed", err); } vlog.debug("TLS handshake completed with %s", @@ -201,10 +201,8 @@ void CSecurityTLS::setParam() char *prio; const char *err; - prio = (char*)malloc(strlen(Security::GnuTLSPriority) + - strlen(kx_anon_priority) + 1); - if (prio == nullptr) - throw Exception("Not enough memory for GnuTLS priority string"); + prio = new char[strlen(Security::GnuTLSPriority) + + strlen(kx_anon_priority) + 1]; strcpy(prio, Security::GnuTLSPriority); if (anon) @@ -212,12 +210,12 @@ void CSecurityTLS::setParam() ret = gnutls_priority_set_direct(session, prio, &err); - free(prio); + delete [] prio; if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::TLSException("gnutls_set_priority_direct()", ret); + throw rdr::tls_error("gnutls_set_priority_direct()", ret); } } else if (anon) { const char *err; @@ -229,7 +227,7 @@ void CSecurityTLS::setParam() if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::TLSException("gnutls_set_default_priority_append()", ret); + throw rdr::tls_error("gnutls_set_default_priority_append()", ret); } #else // We don't know what the system default priority is, so we guess @@ -237,22 +235,20 @@ void CSecurityTLS::setParam() static const char gnutls_default_priority[] = "NORMAL"; char *prio; - prio = (char*)malloc(strlen(gnutls_default_priority) + - strlen(kx_anon_priority) + 1); - if (prio == nullptr) - throw Exception("Not enough memory for GnuTLS priority string"); + 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); - free(prio); + delete [] prio; if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::TLSException("gnutls_set_priority_direct()", ret); + throw rdr::tls_error("gnutls_set_priority_direct()", ret); } #endif } @@ -260,17 +256,17 @@ void CSecurityTLS::setParam() if (anon) { ret = gnutls_anon_allocate_client_credentials(&anon_cred); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_anon_allocate_client_credentials()", ret); + throw rdr::tls_error("gnutls_anon_allocate_client_credentials()", ret); ret = gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_credentials_set()", ret); + throw rdr::tls_error("gnutls_credentials_set()", ret); vlog.debug("Anonymous session has been set"); } else { ret = gnutls_certificate_allocate_credentials(&cert_cred); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_certificate_allocate_credentials()", ret); + throw rdr::tls_error("gnutls_certificate_allocate_credentials()", ret); if (gnutls_certificate_set_x509_system_trust(cert_cred) < 1) vlog.error("Could not load system certificate trust store"); @@ -283,7 +279,7 @@ void CSecurityTLS::setParam() ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_credentials_set()", ret); + throw rdr::tls_error("gnutls_credentials_set()", ret); if (gnutls_server_name_set(session, GNUTLS_NAME_DNS, client->getServerName(), @@ -316,12 +312,12 @@ void CSecurityTLS::checkSession() return; if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) - throw Exception("Unsupported certificate type"); + 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)); - throw rdr::TLSException("server certificate verification()", err); + throw rdr::tls_error("server certificate verification()", err); } if (status != 0) { @@ -338,13 +334,14 @@ void CSecurityTLS::checkSession() &status_str, 0); if (err != GNUTLS_E_SUCCESS) - throw rdr::TLSException("Failed to get certificate error description", err); + throw rdr::tls_error("Failed to get certificate error description", err); error = (const char*)status_str.data; gnutls_free(status_str.data); - throw Exception("Invalid server certificate: %s", error.c_str()); + throw protocol_error(format("Invalid server certificate: %s", + error.c_str())); } err = gnutls_certificate_verification_status_print(status, @@ -352,7 +349,7 @@ void CSecurityTLS::checkSession() &status_str, 0); if (err != GNUTLS_E_SUCCESS) - throw rdr::TLSException("Failed to get certificate error description", err); + throw rdr::tls_error("Failed to get certificate error description", err); vlog.info("Server certificate errors: %s", status_str.data); @@ -363,7 +360,7 @@ void CSecurityTLS::checkSession() cert_list = gnutls_certificate_get_peers(session, &cert_list_size); if (!cert_list_size) - throw Exception("empty certificate chain"); + throw protocol_error("empty certificate chain"); /* Process only server's certificate, not issuer's certificate */ gnutls_x509_crt_t crt; @@ -371,7 +368,7 @@ void CSecurityTLS::checkSession() err = gnutls_x509_crt_import(crt, &cert_list[0], GNUTLS_X509_FMT_DER); if (err != GNUTLS_E_SUCCESS) - throw rdr::TLSException("Failed to decode server certificate", 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"); @@ -390,8 +387,8 @@ void CSecurityTLS::checkSession() hostsDir = os::getvncstatedir(); if (hostsDir == nullptr) { - throw Exception("Could not obtain VNC state directory path for " - "known hosts storage"); + throw std::runtime_error("Could not obtain VNC state directory " + "path for known hosts storage"); } std::string dbPath; @@ -410,12 +407,12 @@ void CSecurityTLS::checkSession() if ((known != GNUTLS_E_NO_CERTIFICATE_FOUND) && (known != GNUTLS_E_CERTIFICATE_KEY_MISMATCH)) { - throw rdr::TLSException("Could not load known hosts database", 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) - throw rdr::TLSException("Could not find certificate to display", err); + 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++) { @@ -447,7 +444,7 @@ void CSecurityTLS::checkSession() if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unknown certificate issuer", text.c_str())) - throw AuthCancelledException(); + throw auth_cancelled(); status &= ~(GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | @@ -467,7 +464,7 @@ void CSecurityTLS::checkSession() if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Certificate is not yet valid", text.c_str())) - throw AuthCancelledException(); + throw auth_cancelled(); status &= ~GNUTLS_CERT_NOT_ACTIVATED; } @@ -486,7 +483,7 @@ void CSecurityTLS::checkSession() if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Expired certificate", text.c_str())) - throw AuthCancelledException(); + throw auth_cancelled(); status &= ~GNUTLS_CERT_EXPIRED; } @@ -505,14 +502,14 @@ void CSecurityTLS::checkSession() if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Insecure certificate algorithm", text.c_str())) - throw AuthCancelledException(); + throw auth_cancelled(); status &= ~GNUTLS_CERT_INSECURE_ALGORITHM; } if (status != 0) { vlog.error("Unhandled certificate problems: 0x%x", status); - throw Exception("Unhandled certificate problems"); + throw std::logic_error("Unhandled certificate problems"); } if (!hostname_match) { @@ -530,7 +527,7 @@ void CSecurityTLS::checkSession() if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Certificate hostname mismatch", text.c_str())) - throw AuthCancelledException(); + throw auth_cancelled(); } } else if (known == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { std::string text; @@ -556,7 +553,7 @@ void CSecurityTLS::checkSession() if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unexpected server certificate", text.c_str())) - throw AuthCancelledException(); + throw auth_cancelled(); status &= ~(GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | @@ -579,7 +576,7 @@ void CSecurityTLS::checkSession() if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unexpected server certificate", text.c_str())) - throw AuthCancelledException(); + throw auth_cancelled(); status &= ~GNUTLS_CERT_NOT_ACTIVATED; } @@ -600,7 +597,7 @@ void CSecurityTLS::checkSession() if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unexpected server certificate", text.c_str())) - throw AuthCancelledException(); + throw auth_cancelled(); status &= ~GNUTLS_CERT_EXPIRED; } @@ -621,14 +618,14 @@ void CSecurityTLS::checkSession() if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unexpected server certificate", text.c_str())) - throw AuthCancelledException(); + throw auth_cancelled(); status &= ~GNUTLS_CERT_INSECURE_ALGORITHM; } if (status != 0) { vlog.error("Unhandled certificate problems: 0x%x", status); - throw Exception("Unhandled certificate problems"); + throw std::logic_error("Unhandled certificate problems"); } if (!hostname_match) { @@ -648,7 +645,7 @@ void CSecurityTLS::checkSession() if (!cc->showMsgBox(MsgBoxFlags::M_YESNO, "Unexpected server certificate", text.c_str())) - throw AuthCancelledException(); + throw auth_cancelled(); } } diff --git a/common/rfb/CSecurityVeNCrypt.cxx b/common/rfb/CSecurityVeNCrypt.cxx index 3ebb3855..1b6ecf22 100644 --- a/common/rfb/CSecurityVeNCrypt.cxx +++ b/common/rfb/CSecurityVeNCrypt.cxx @@ -105,7 +105,7 @@ bool CSecurityVeNCrypt::processMsg() os->writeU8(0); os->writeU8(0); os->flush(); - throw Exception("The server reported an unsupported VeNCrypt version"); + throw protocol_error("The server reported an unsupported VeNCrypt version"); } haveSentVersion = true; @@ -117,8 +117,8 @@ bool CSecurityVeNCrypt::processMsg() return false; if (is->readU8()) - throw Exception("The server reported it could not support the " - "VeNCrypt version"); + throw protocol_error("The server reported it could not " + "support the VeNCrypt version"); haveAgreedVersion = true; } @@ -131,7 +131,7 @@ bool CSecurityVeNCrypt::processMsg() nAvailableTypes = is->readU8(); if (!nAvailableTypes) - throw Exception("The server reported no VeNCrypt sub-types"); + throw protocol_error("The server reported no VeNCrypt sub-types"); availableTypes = new uint32_t[nAvailableTypes]; haveNumberOfTypes = true; @@ -172,7 +172,7 @@ bool CSecurityVeNCrypt::processMsg() /* Set up the stack according to the chosen type: */ if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt) - throw Exception("No valid VeNCrypt sub-type"); + throw protocol_error("No valid VeNCrypt sub-type"); vlog.info("Choosing security type %s (%d)", secTypeName(chosenType), chosenType); @@ -191,7 +191,7 @@ bool CSecurityVeNCrypt::processMsg() * happen, since if the server supports 0 sub-types, it doesn't support * this security type */ - throw Exception("The server reported 0 VeNCrypt sub-types"); + throw protocol_error("The server reported 0 VeNCrypt sub-types"); } return csecurity->processMsg(); diff --git a/common/rfb/ClientParams.cxx b/common/rfb/ClientParams.cxx index bc20c3d7..b86cc97f 100644 --- a/common/rfb/ClientParams.cxx +++ b/common/rfb/ClientParams.cxx @@ -22,11 +22,13 @@ #include <config.h> #endif -#include <rfb/Exception.h> +#include <stdexcept> + #include <rfb/encodings.h> #include <rfb/ledStates.h> #include <rfb/clipboardTypes.h> #include <rfb/ClientParams.h> +#include <rfb/util.h> using namespace rfb; @@ -62,7 +64,7 @@ void ClientParams::setDimensions(int width, int height) void ClientParams::setDimensions(int width, int height, const ScreenSet& layout) { if (!layout.validate(width, height)) - throw Exception("Attempted to configure an invalid screen layout"); + throw std::invalid_argument("Attempted to configure an invalid screen layout"); width_ = width; height_ = height; @@ -74,7 +76,7 @@ void ClientParams::setPF(const PixelFormat& pf) pf_ = pf; if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32) - throw Exception("setPF: not 8, 16 or 32 bpp?"); + throw std::invalid_argument("setPF: not 8, 16 or 32 bpp?"); } void ClientParams::setName(const char* name) @@ -160,7 +162,7 @@ uint32_t ClientParams::clipboardSize(unsigned int format) const return clipSizes[i]; } - throw Exception("Invalid clipboard format 0x%x", format); + throw std::invalid_argument(rfb::format("Invalid clipboard format 0x%x", format)); } void ClientParams::setClipboardCaps(uint32_t flags, const uint32_t* lengths) @@ -228,3 +230,10 @@ bool ClientParams::supportsContinuousUpdates() const return true; return false; } + +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 ea86ea78..f715c47f 100644 --- a/common/rfb/ClientParams.h +++ b/common/rfb/ClientParams.h @@ -101,6 +101,7 @@ namespace rfb { bool supportsLEDState() const; bool supportsFence() const; bool supportsContinuousUpdates() const; + bool supportsExtendedMouseButtons() const; int compressLevel; int qualityLevel; diff --git a/common/rfb/Configuration.cxx b/common/rfb/Configuration.cxx index 763a5635..44d42a88 100644 --- a/common/rfb/Configuration.cxx +++ b/common/rfb/Configuration.cxx @@ -30,12 +30,13 @@ #include <ctype.h> #include <string.h> +#include <stdexcept> + #include <os/Mutex.h> #include <rfb/util.h> #include <rfb/Configuration.h> #include <rfb/LogWriter.h> -#include <rfb/Exception.h> #define LOCK_CONFIG os::AutoMutex a(mutex) @@ -376,7 +377,7 @@ StringParameter::StringParameter(const char* name_, const char* desc_, { if (!v) { vlog.error("Default value <null> for %s not allowed",name_); - throw rfb::Exception("Default value <null> not allowed"); + throw std::invalid_argument("Default value <null> not allowed"); } } @@ -387,7 +388,7 @@ bool StringParameter::setParam(const char* v) { LOCK_CONFIG; if (immutable) return true; if (!v) - throw rfb::Exception("setParam(<null>) not allowed"); + throw std::invalid_argument("setParam(<null>) not allowed"); vlog.debug("Set %s(String) to %s", getName(), v); value = v; return true; diff --git a/common/rfb/Cursor.cxx b/common/rfb/Cursor.cxx index fa596bc5..94844144 100644 --- a/common/rfb/Cursor.cxx +++ b/common/rfb/Cursor.cxx @@ -24,9 +24,10 @@ #include <assert.h> #include <string.h> +#include <stdexcept> + #include <rfb/Cursor.h> #include <rfb/LogWriter.h> -#include <rfb/Exception.h> using namespace rfb; @@ -260,7 +261,7 @@ const uint8_t* RenderedCursor::getBuffer(const Rect& _r, int* stride) const r = _r.translate(offset.negate()); if (!r.enclosed_by(buffer.getRect())) - throw Exception("RenderedCursor: Invalid area requested"); + throw std::out_of_range("RenderedCursor: Invalid area requested"); return buffer.getBuffer(r, stride); } diff --git a/common/rfb/DecodeManager.cxx b/common/rfb/DecodeManager.cxx index ef415886..09118f36 100644 --- a/common/rfb/DecodeManager.cxx +++ b/common/rfb/DecodeManager.cxx @@ -114,14 +114,14 @@ bool DecodeManager::decodeRect(const Rect& r, int encoding, if (!Decoder::supported(encoding)) { vlog.error("Unknown encoding %d", encoding); - throw rdr::Exception("Unknown encoding"); + throw protocol_error("Unknown encoding"); } if (!decoders[encoding]) { decoders[encoding] = Decoder::createDecoder(encoding); if (!decoders[encoding]) { vlog.error("Unknown encoding %d", encoding); - throw rdr::Exception("Unknown encoding"); + throw protocol_error("Unknown encoding"); } } @@ -148,8 +148,8 @@ bool DecodeManager::decodeRect(const Rect& r, int encoding, try { if (!decoder->readRect(r, conn->getInStream(), conn->server, bufferStream)) return false; - } catch (rdr::Exception& e) { - throw Exception("Error reading rect: %s", e.str()); + } catch (std::exception& e) { + throw std::runtime_error(format("Error reading rect: %s", e.what())); } stats[encoding].rects++; @@ -243,14 +243,14 @@ void DecodeManager::logStats() iecPrefix(bytes, "B").c_str(), ratio); } -void DecodeManager::setThreadException(const rdr::Exception& e) +void DecodeManager::setThreadException(const std::exception& e) { os::AutoMutex a(queueMutex); if (threadException != nullptr) return; - threadException = new rdr::Exception("Exception on worker thread: %s", e.str()); + threadException = new std::runtime_error(format("Exception on worker thread: %s", e.what())); } void DecodeManager::throwThreadException() @@ -260,7 +260,7 @@ void DecodeManager::throwThreadException() if (threadException == nullptr) return; - rdr::Exception e(*threadException); + std::exception e(*threadException); delete threadException; threadException = nullptr; @@ -318,7 +318,7 @@ void DecodeManager::DecodeThread::worker() entry->decoder->decodeRect(entry->rect, entry->bufferStream->data(), entry->bufferStream->length(), *entry->server, entry->pb); - } catch (rdr::Exception& e) { + } catch (std::exception& e) { manager->setThreadException(e); } catch(...) { assert(false); diff --git a/common/rfb/DecodeManager.h b/common/rfb/DecodeManager.h index 5435bfc1..b11b7044 100644 --- a/common/rfb/DecodeManager.h +++ b/common/rfb/DecodeManager.h @@ -32,7 +32,6 @@ namespace os { } namespace rdr { - struct Exception; class MemOutStream; } @@ -55,7 +54,7 @@ namespace rfb { private: void logStats(); - void setThreadException(const rdr::Exception& e); + void setThreadException(const std::exception& e); void throwThreadException(); private: @@ -108,7 +107,7 @@ namespace rfb { }; std::list<DecodeThread*> threads; - rdr::Exception *threadException; + std::exception *threadException; }; } diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx index 5c1429d2..4526c0b3 100644 --- a/common/rfb/EncodeManager.cxx +++ b/common/rfb/EncodeManager.cxx @@ -32,7 +32,6 @@ #include <rfb/SMsgWriter.h> #include <rfb/UpdateTracker.h> #include <rfb/LogWriter.h> -#include <rfb/Exception.h> #include <rfb/util.h> #include <rfb/RawEncoder.h> @@ -1055,7 +1054,7 @@ void EncodeManager::OffsetPixelBuffer::update(const PixelFormat& pf, uint8_t* EncodeManager::OffsetPixelBuffer::getBufferRW(const Rect& /*r*/, int* /*stride*/) { - throw rfb::Exception("Invalid write attempt to OffsetPixelBuffer"); + throw std::logic_error("Invalid write attempt to OffsetPixelBuffer"); } template<class T> diff --git a/common/rfb/Exception.h b/common/rfb/Exception.h index 773c65fa..0e74209c 100644 --- a/common/rfb/Exception.h +++ b/common/rfb/Exception.h @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2014-2024 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,17 +19,25 @@ #ifndef __RFB_EXCEPTION_H__ #define __RFB_EXCEPTION_H__ -#include <rdr/Exception.h> +#include <stdexcept> namespace rfb { - typedef rdr::Exception Exception; - struct AuthFailureException : public Exception { - AuthFailureException(const char* reason) - : Exception("%s", reason) {} + class protocol_error : public std::runtime_error { + public: + protocol_error(const char* what_arg) : std::runtime_error(what_arg) {} + protocol_error(const std::string& what_arg) : std::runtime_error(what_arg) {} }; - struct AuthCancelledException : public rfb::Exception { - AuthCancelledException() - : Exception("Authentication cancelled") {} + + class auth_error : public std::runtime_error { + public: + auth_error(const char* reason) : std::runtime_error(reason) {} + auth_error(std::string& reason) : std::runtime_error(reason) {} + }; + + class auth_cancelled : public std::runtime_error { + public: + auth_cancelled() + : std::runtime_error("Authentication cancelled") {} }; } #endif diff --git a/common/rfb/H264Decoder.cxx b/common/rfb/H264Decoder.cxx index 3178a17b..89850ba4 100644 --- a/common/rfb/H264Decoder.cxx +++ b/common/rfb/H264Decoder.cxx @@ -30,7 +30,6 @@ #include <rdr/InStream.h> #include <rdr/OutStream.h> #include <rfb/LogWriter.h> -#include <rfb/Exception.h> #include <rfb/H264Decoder.h> #include <rfb/H264DecoderContext.h> @@ -128,12 +127,12 @@ void H264Decoder::decodeRect(const Rect& r, const uint8_t* buffer, } ctx = H264DecoderContext::createContext(r); if (!ctx) - throw Exception("H264Decoder: Context not be created"); + throw std::runtime_error("H264Decoder: Context not be created"); contexts.push_back(ctx); } if (!ctx->isReady()) - throw Exception("H264Decoder: Context is not ready"); + throw std::runtime_error("H264Decoder: Context is not ready"); if (reset & resetContext) ctx->reset(); diff --git a/common/rfb/H264DecoderContext.cxx b/common/rfb/H264DecoderContext.cxx index 87ac0d85..b2054554 100644 --- a/common/rfb/H264DecoderContext.cxx +++ b/common/rfb/H264DecoderContext.cxx @@ -22,8 +22,9 @@ #include <config.h> #endif +#include <stdexcept> + #include <os/Mutex.h> -#include <rfb/Exception.h> #include <rfb/LogWriter.h> #include <rfb/H264DecoderContext.h> @@ -45,7 +46,7 @@ H264DecoderContext *H264DecoderContext::createContext(const Rect &r) H264DecoderContext *ret = new H264DecoderContextType(r); if (!ret->initCodec()) { - throw Exception("H264DecoderContext: Unable to create context"); + throw std::runtime_error("H264DecoderContext: Unable to create context"); } return ret; diff --git a/common/rfb/H264LibavDecoderContext.cxx b/common/rfb/H264LibavDecoderContext.cxx index fa2f367b..2d8d03e7 100644 --- a/common/rfb/H264LibavDecoderContext.cxx +++ b/common/rfb/H264LibavDecoderContext.cxx @@ -33,7 +33,6 @@ extern "C" { #define FFMPEG_INIT_PACKET_DEPRECATED #endif -#include <rfb/Exception.h> #include <rfb/LogWriter.h> #include <rfb/PixelBuffer.h> #include <rfb/H264LibavDecoderContext.h> @@ -118,7 +117,7 @@ uint8_t* H264LibavDecoderContext::makeH264WorkBuffer(const uint8_t* buffer, uint { h264WorkBuffer = (uint8_t*)realloc(h264WorkBuffer, reserve_len); if (h264WorkBuffer == nullptr) { - throw Exception("H264LibavDecoderContext: Unable to allocate memory"); + throw std::bad_alloc(); } h264WorkBufferLength = reserve_len; } diff --git a/common/rfb/HextileDecoder.cxx b/common/rfb/HextileDecoder.cxx index dc9b9be7..35ec7928 100644 --- a/common/rfb/HextileDecoder.cxx +++ b/common/rfb/HextileDecoder.cxx @@ -189,7 +189,7 @@ void HextileDecoder::hextileDecode(const Rect& r, rdr::InStream* is, int w = ((wh >> 4) & 15) + 1; int h = (wh & 15) + 1; if (x + w > 16 || y + h > 16) { - throw rfb::Exception("HEXTILE_DECODE: Hextile out of bounds"); + throw protocol_error("HEXTILE_DECODE: Hextile out of bounds"); } ptr = buf + y * t.width() + x; int rowAdd = t.width() - w; diff --git a/common/rfb/Hostname.h b/common/rfb/Hostname.h index f6a11a60..de4a330e 100644 --- a/common/rfb/Hostname.h +++ b/common/rfb/Hostname.h @@ -23,7 +23,9 @@ #include <ctype.h> #include <stdlib.h> #include <string.h> -#include <rdr/Exception.h> + +#include <stdexcept> + #include <rfb/util.h> namespace rfb { @@ -47,7 +49,7 @@ namespace rfb { const char* portStart; if (hi == nullptr) - throw rdr::Exception("NULL host specified"); + throw std::invalid_argument("NULL host specified"); // Trim leading whitespace while(isspace(*hi)) @@ -60,7 +62,7 @@ namespace rfb { hostStart = &hi[1]; hostEnd = strchr(hostStart, ']'); if (hostEnd == nullptr) - throw rdr::Exception("unmatched [ in host"); + throw std::invalid_argument("unmatched [ in host"); portStart = hostEnd + 1; if (isAllSpace(portStart)) @@ -99,14 +101,14 @@ namespace rfb { char* end; if (portStart[0] != ':') - throw rdr::Exception("invalid port specified"); + 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 rdr::Exception("invalid port specified"); + throw std::invalid_argument("invalid port specified"); if ((portStart[1] != ':') && (*port < 100)) *port += basePort; diff --git a/common/rfb/JpegCompressor.cxx b/common/rfb/JpegCompressor.cxx index 42d5c475..67a86cd9 100644 --- a/common/rfb/JpegCompressor.cxx +++ b/common/rfb/JpegCompressor.cxx @@ -22,8 +22,9 @@ #include <config.h> #endif +#include <stdexcept> + #include <rfb/JpegCompressor.h> -#include <rdr/Exception.h> #include <rfb/Rect.h> #include <rfb/PixelFormat.h> #include <rfb/ClientParams.h> @@ -127,7 +128,7 @@ JpegCompressor::JpegCompressor(int bufferLen) : MemOutStream(bufferLen) if(setjmp(err->jmpBuffer)) { // this will execute if libjpeg has an error - throw rdr::Exception("%s", err->lastError); + throw std::runtime_error(err->lastError); } jpeg_create_compress(cinfo); @@ -171,7 +172,7 @@ void JpegCompressor::compress(const uint8_t *buf, volatile int stride, jpeg_abort_compress(cinfo); if (srcBufIsTemp && srcBuf) delete[] srcBuf; if (rowPointer) delete[] rowPointer; - throw rdr::Exception("%s", err->lastError); + throw std::runtime_error(err->lastError); } cinfo->image_width = w; @@ -256,5 +257,5 @@ void JpegCompressor::compress(const uint8_t *buf, volatile int stride, void JpegCompressor::writeBytes(const uint8_t* /*data*/, int /*length*/) { - throw rdr::Exception("writeBytes() is not valid with a JpegCompressor instance. Use compress() instead."); + throw std::logic_error("writeBytes() is not valid with a JpegCompressor instance. Use compress() instead."); } diff --git a/common/rfb/JpegDecompressor.cxx b/common/rfb/JpegDecompressor.cxx index 92ef014f..10c9e49c 100644 --- a/common/rfb/JpegDecompressor.cxx +++ b/common/rfb/JpegDecompressor.cxx @@ -24,7 +24,7 @@ #endif #include <rfb/JpegDecompressor.h> -#include <rdr/Exception.h> +#include <rfb/Exception.h> #include <rfb/Rect.h> #include <rfb/PixelFormat.h> @@ -120,7 +120,7 @@ JpegDecompressor::JpegDecompressor(void) if(setjmp(err->jmpBuffer)) { // this will execute if libjpeg has an error - throw rdr::Exception("%s", err->lastError); + throw std::runtime_error(err->lastError); } jpeg_create_decompress(dinfo); @@ -168,7 +168,7 @@ void JpegDecompressor::decompress(const uint8_t *jpegBuf, jpeg_abort_decompress(dinfo); if (dstBufIsTemp && dstBuf) delete[] dstBuf; if (rowPointer) delete[] rowPointer; - throw rdr::Exception("%s", err->lastError); + throw std::runtime_error(err->lastError); } src->pub.next_input_byte = jpegBuf; @@ -217,7 +217,7 @@ void JpegDecompressor::decompress(const uint8_t *jpegBuf, jpeg_abort_decompress(dinfo); if (dstBufIsTemp && dstBuf) delete[] dstBuf; if (rowPointer) delete[] rowPointer; - throw rdr::Exception("Tight Decoding: Wrong JPEG data received.\n"); + throw protocol_error("Tight Decoding: Wrong JPEG data received.\n"); } while (dinfo->output_scanline < dinfo->output_height) { diff --git a/common/rfb/PixelBuffer.cxx b/common/rfb/PixelBuffer.cxx index 0a287544..5590c214 100644 --- a/common/rfb/PixelBuffer.cxx +++ b/common/rfb/PixelBuffer.cxx @@ -28,9 +28,11 @@ #include <string.h> -#include <rfb/Exception.h> +#include <stdexcept> + #include <rfb/LogWriter.h> #include <rfb/PixelBuffer.h> +#include <rfb/util.h> using namespace rfb; @@ -70,9 +72,10 @@ PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) const const uint8_t* end; if (!r.enclosed_by(getRect())) - throw rfb::Exception("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(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())); data = getBuffer(r, &inStride); @@ -106,9 +109,10 @@ void PixelBuffer::getImage(const PixelFormat& pf, void* imageBuf, } if (!r.enclosed_by(getRect())) - throw rfb::Exception("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(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())); if (stride == 0) stride = r.width(); @@ -122,9 +126,9 @@ void PixelBuffer::getImage(const PixelFormat& pf, void* imageBuf, void PixelBuffer::setSize(int width, int height) { if ((width < 0) || (width > maxPixelBufferWidth)) - throw rfb::Exception("Invalid PixelBuffer width of %d pixels requested", width); + throw std::out_of_range(rfb::format("Invalid PixelBuffer width of %d pixels requested", width)); if ((height < 0) || (height > maxPixelBufferHeight)) - throw rfb::Exception("Invalid PixelBuffer height of %d pixels requested", height); + throw std::out_of_range(rfb::format("Invalid PixelBuffer height of %d pixels requested", height)); width_ = width; height_ = height; @@ -153,8 +157,10 @@ void ModifiablePixelBuffer::fillRect(const Rect& r, const void* pix) int w, h, b; if (!r.enclosed_by(getRect())) - throw rfb::Exception("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(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())); w = r.width(); h = r.height(); @@ -203,9 +209,10 @@ void ModifiablePixelBuffer::imageRect(const Rect& r, uint8_t* end; if (!r.enclosed_by(getRect())) - throw rfb::Exception("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(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())); bytesPerPixel = getPF().bpp/8; @@ -242,15 +249,17 @@ void ModifiablePixelBuffer::copyRect(const Rect &rect, drect = rect; if (!drect.enclosed_by(getRect())) - throw rfb::Exception("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(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())); srect = drect.translate(move_by_delta.negate()); if (!srect.enclosed_by(getRect())) - throw rfb::Exception("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(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())); bytesPerPixel = format.bpp/8; @@ -303,9 +312,10 @@ void ModifiablePixelBuffer::imageRect(const PixelFormat& pf, const Rect &dest, int dstStride; if (!dest.enclosed_by(getRect())) - throw rfb::Exception("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(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())); if (stride == 0) stride = dest.width(); @@ -332,9 +342,10 @@ FullFramePixelBuffer::~FullFramePixelBuffer() {} uint8_t* FullFramePixelBuffer::getBufferRW(const Rect& r, int* stride_) { if (!r.enclosed_by(getRect())) - throw rfb::Exception("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(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())); *stride_ = stride; return &data[(r.tl.x + (r.tl.y * stride)) * (format.bpp/8)]; @@ -347,9 +358,10 @@ void FullFramePixelBuffer::commitBufferRW(const Rect& /*r*/) const uint8_t* FullFramePixelBuffer::getBuffer(const Rect& r, int* stride_) const { if (!r.enclosed_by(getRect())) - throw rfb::Exception("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(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())); *stride_ = stride; return &data[(r.tl.x + (r.tl.y * stride)) * (format.bpp/8)]; @@ -359,13 +371,13 @@ void FullFramePixelBuffer::setBuffer(int width, int height, uint8_t* data_, int stride_) { if ((width < 0) || (width > maxPixelBufferWidth)) - throw rfb::Exception("Invalid PixelBuffer width of %d pixels requested", width); + throw std::out_of_range(rfb::format("Invalid PixelBuffer width of %d pixels requested", width)); if ((height < 0) || (height > maxPixelBufferHeight)) - throw rfb::Exception("Invalid PixelBuffer height of %d pixels requested", height); + throw std::out_of_range(rfb::format("Invalid PixelBuffer height of %d pixels requested", height)); if ((stride_ < 0) || (stride_ > maxPixelBufferStride) || (stride_ < width)) - throw rfb::Exception("Invalid PixelBuffer stride of %d pixels requested", stride_); + throw std::invalid_argument(rfb::format("Invalid PixelBuffer stride of %d pixels requested", stride_)); if ((width != 0) && (height != 0) && (data_ == nullptr)) - throw rfb::Exception("PixelBuffer requested without a valid memory area"); + throw std::logic_error(rfb::format("PixelBuffer requested without a valid memory area")); ModifiablePixelBuffer::setSize(width, height); stride = stride_; @@ -375,7 +387,7 @@ void FullFramePixelBuffer::setBuffer(int width, int height, void FullFramePixelBuffer::setSize(int /*w*/, int /*h*/) { // setBuffer() should be used - throw rfb::Exception("Invalid call to FullFramePixelBuffer::setSize()"); + throw std::logic_error("Invalid call to FullFramePixelBuffer::setSize()"); } // -=- Managed pixel buffer class diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx index b90fc206..e312b3c9 100644 --- a/common/rfb/PixelFormat.cxx +++ b/common/rfb/PixelFormat.cxx @@ -86,7 +86,7 @@ PixelFormat::PixelFormat(int b, int d, bool e, bool t, redShift(rs), greenShift(gs), blueShift(bs) { if (!isSane()) - throw Exception("invalid pixel format"); + throw std::invalid_argument("invalid pixel format"); updateState(); } @@ -180,7 +180,7 @@ void PixelFormat::read(rdr::InStream* is) } if (!isSane()) - throw Exception("invalid pixel format"); + throw protocol_error("invalid pixel format"); updateState(); } diff --git a/common/rfb/RREDecoder.cxx b/common/rfb/RREDecoder.cxx index 41bf501a..53ddc2da 100644 --- a/common/rfb/RREDecoder.cxx +++ b/common/rfb/RREDecoder.cxx @@ -107,7 +107,7 @@ void RREDecoder::rreDecode(const Rect& r, rdr::InStream* is, int h = is->readU16(); if (((x+w) > r.width()) || ((y+h) > r.height())) - throw Exception ("RRE decode error"); + 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); } diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx index 2b5c97bf..dc0c1e85 100644 --- a/common/rfb/SConnection.cxx +++ b/common/rfb/SConnection.cxx @@ -95,14 +95,14 @@ bool SConnection::processMsg() case RFBSTATE_INITIALISATION: return processInitMsg(); break; case RFBSTATE_NORMAL: return reader_->readMsg(); break; case RFBSTATE_QUERYING: - throw Exception("SConnection::processMsg: bogus data from client while " - "querying"); + throw std::logic_error("SConnection::processMsg: bogus data from " + "client while querying"); case RFBSTATE_CLOSING: - throw Exception("SConnection::processMsg: called while closing"); + throw std::logic_error("SConnection::processMsg: called while closing"); case RFBSTATE_UNINITIALISED: - throw Exception("SConnection::processMsg: not initialised yet?"); + throw std::logic_error("SConnection::processMsg: not initialised yet?"); default: - throw Exception("SConnection::processMsg: invalid state"); + throw std::logic_error("SConnection::processMsg: invalid state"); } } @@ -123,7 +123,7 @@ bool SConnection::processVersionMsg() if (sscanf(verStr, "RFB %03d.%03d\n", &majorVersion, &minorVersion) != 2) { state_ = RFBSTATE_INVALID; - throw Exception("reading version failed: not an RFB client?"); + throw protocol_error("reading version failed: not an RFB client?"); } client.setVersion(majorVersion, minorVersion); @@ -133,9 +133,10 @@ bool SConnection::processVersionMsg() if (client.majorVersion != 3) { // unknown protocol version - failConnection("Client needs protocol version %d.%d, server has %d.%d", - client.majorVersion, client.minorVersion, - defaultMajorVersion, defaultMinorVersion); + failConnection(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) { @@ -165,8 +166,9 @@ bool SConnection::processVersionMsg() if (*i == secTypeNone || *i == secTypeVncAuth) break; } if (i == secTypes.end()) { - failConnection("No supported security type for %d.%d client", - client.majorVersion, client.minorVersion); + failConnection(format("No supported security type for " + "%d.%d client", + client.majorVersion, client.minorVersion)); } os->writeU32(*i); @@ -213,7 +215,7 @@ void SConnection::processSecurityType(int secType) secTypes = security.GetEnabledSecTypes(); if (std::find(secTypes.begin(), secTypes.end(), secType) == secTypes.end()) - throw Exception("Requested security type not available"); + throw protocol_error("Requested security type not available"); vlog.info("Client requests security type %s(%d)", secTypeName(secType),secType); @@ -221,8 +223,8 @@ void SConnection::processSecurityType(int secType) try { state_ = RFBSTATE_SECURITY; ssecurity = security.GetSSecurity(this, secType); - } catch (rdr::Exception& e) { - failConnection("%s", e.str()); + } catch (std::exception& e) { + failConnection(e.what()); } } @@ -232,12 +234,12 @@ bool SConnection::processSecurityMsg() try { if (!ssecurity->processMsg()) return false; - } catch (AuthFailureException& e) { - vlog.error("AuthFailureException: %s", e.str()); + } catch (auth_error& e) { + vlog.error("Authentication error: %s", e.what()); state_ = RFBSTATE_SECURITY_FAILURE; // Introduce a slight delay of the authentication failure response // to make it difficult to brute force a password - authFailureMsg = e.str(); + authFailureMsg = e.what(); authFailureTimer.start(100); return true; } @@ -291,41 +293,39 @@ void SConnection::handleAuthFailureTimeout(Timer* /*t*/) authFailureMsg.size()); } os->flush(); - } catch (rdr::Exception& e) { - close(e.str()); + } catch (std::exception& e) { + close(e.what()); return; } close(authFailureMsg.c_str()); } -void SConnection::failConnection(const char* format, ...) +void SConnection::failConnection(const char* message) { - va_list ap; - char str[256]; - - va_start(ap, format); - (void) vsnprintf(str, sizeof(str), format, ap); - va_end(ap); - - vlog.info("Connection failed: %s", str); + vlog.info("Connection failed: %s", message); if (state_ == RFBSTATE_PROTOCOL_VERSION) { if (client.majorVersion == 3 && client.minorVersion == 3) { os->writeU32(0); - os->writeU32(strlen(str)); - os->writeBytes((const uint8_t*)str, strlen(str)); + os->writeU32(strlen(message)); + os->writeBytes((const uint8_t*)message, strlen(message)); os->flush(); } else { os->writeU8(0); - os->writeU32(strlen(str)); - os->writeBytes((const uint8_t*)str, strlen(str)); + os->writeU32(strlen(message)); + os->writeBytes((const uint8_t*)message, strlen(message)); os->flush(); } } state_ = RFBSTATE_INVALID; - throw Exception("%s", str); + throw protocol_error(message); +} + +void SConnection::failConnection(const std::string& message) +{ + failConnection(message.c_str()); } void SConnection::setAccessRights(AccessRights ar) @@ -336,7 +336,7 @@ void SConnection::setAccessRights(AccessRights ar) bool SConnection::accessCheck(AccessRights ar) const { if (state_ < RFBSTATE_QUERYING) - throw Exception("SConnection::accessCheck: invalid state"); + throw std::logic_error("SConnection::accessCheck: invalid state"); return (accessRights & ar) == ar; } @@ -433,6 +433,11 @@ void SConnection::supportsQEMUKeyEvent() writer()->writeQEMUKeyEvent(); } +void SConnection::supportsExtendedMouseButtons() +{ + writer()->writeExtendedMouseButtonsSupport(); +} + void SConnection::versionReceived() { } @@ -449,7 +454,7 @@ void SConnection::queryConnection(const char* /*userName*/) void SConnection::approveConnection(bool accept, const char* reason) { if (state_ != RFBSTATE_QUERYING) - throw Exception("SConnection::approveConnection: invalid state"); + throw std::logic_error("SConnection::approveConnection: invalid state"); if (!client.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) { if (accept) { @@ -474,9 +479,9 @@ void SConnection::approveConnection(bool accept, const char* reason) } else { state_ = RFBSTATE_INVALID; if (reason) - throw AuthFailureException(reason); + throw auth_error(reason); else - throw AuthFailureException("Connection rejected"); + throw auth_error("Connection rejected"); } } diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h index 0a11f67b..f030ae05 100644 --- a/common/rfb/SConnection.h +++ b/common/rfb/SConnection.h @@ -68,12 +68,13 @@ namespace rfb { // data is available. bool processMsg(); - // approveConnection() is called to either accept or reject the connection. - // If accept is false, the reason string gives the reason for the - // rejection. It can either be called directly from queryConnection() or - // later, after queryConnection() has returned. It can only be called when - // in state RFBSTATE_QUERYING. On rejection, an AuthFailureException is - // thrown, so this must be handled appropriately by the caller. + // approveConnection() is called to either accept or reject the + // connection. If accept is false, the reason string gives the + // reason for the rejection. It can either be called directly from + // queryConnection() or later, after queryConnection() has returned. + // It can only be called when in state RFBSTATE_QUERYING. On + // rejection, an auth_error is thrown, so this must be handled + // appropriately by the caller. void approveConnection(bool accept, const char* reason=nullptr); @@ -98,6 +99,8 @@ namespace rfb { void supportsQEMUKeyEvent() override; + virtual void supportsExtendedMouseButtons() override; + // Methods to be overridden in a derived class @@ -219,8 +222,8 @@ namespace rfb { // failConnection() prints a message to the log, sends a connection // failed message to the client (if possible) and throws an // Exception. - void failConnection(const char* format, ...) - __attribute__((__format__ (__printf__, 2, 3))); + void failConnection(const char* message); + void failConnection(const std::string& message); void setState(stateEnum s) { state_ = s; } diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h index 1d3c325f..c97e788a 100644 --- a/common/rfb/SDesktop.h +++ b/common/rfb/SDesktop.h @@ -98,7 +98,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*/, - uint8_t /*buttonMask*/) {}; + uint16_t /*buttonMask*/) {}; // handleClipboardRequest() is called whenever a client requests // the server to send over its clipboard data. It will only be diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx index 03917926..1dce634d 100644 --- a/common/rfb/SMsgHandler.cxx +++ b/common/rfb/SMsgHandler.cxx @@ -53,12 +53,13 @@ void SMsgHandler::setPixelFormat(const PixelFormat& pf) void SMsgHandler::setEncodings(int nEncodings, const int32_t* encodings) { bool firstFence, firstContinuousUpdates, firstLEDState, - firstQEMUKeyEvent; + firstQEMUKeyEvent, firstExtMouseButtonsEvent; firstFence = !client.supportsFence(); firstContinuousUpdates = !client.supportsContinuousUpdates(); firstLEDState = !client.supportsLEDState(); firstQEMUKeyEvent = !client.supportsEncoding(pseudoEncodingQEMUKeyEvent); + firstExtMouseButtonsEvent = !client.supportsEncoding(pseudoEncodingExtendedMouseButtons); client.setEncodings(nEncodings, encodings); @@ -72,6 +73,8 @@ void SMsgHandler::setEncodings(int nEncodings, const int32_t* encodings) supportsLEDState(); if (client.supportsEncoding(pseudoEncodingQEMUKeyEvent) && firstQEMUKeyEvent) supportsQEMUKeyEvent(); + if (client.supportsEncoding(pseudoEncodingExtendedMouseButtons) && firstExtMouseButtonsEvent) + supportsExtendedMouseButtons(); } void SMsgHandler::keyEvent(uint32_t /*keysym*/, uint32_t /*keycode*/, @@ -80,7 +83,7 @@ void SMsgHandler::keyEvent(uint32_t /*keysym*/, uint32_t /*keycode*/, } void SMsgHandler::pointerEvent(const Point& /*pos*/, - uint8_t /*buttonMask*/) + uint16_t /*buttonMask*/) { } @@ -167,3 +170,7 @@ 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 cff8b1bd..c5d13d78 100644 --- a/common/rfb/SMsgHandler.h +++ b/common/rfb/SMsgHandler.h @@ -57,7 +57,7 @@ namespace rfb { virtual void keyEvent(uint32_t keysym, uint32_t keycode, bool down); virtual void pointerEvent(const Point& pos, - uint8_t buttonMask); + uint16_t buttonMask); virtual void clientCutText(const char* str); @@ -98,6 +98,11 @@ namespace rfb { // 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(); + ClientParams client; }; } diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx index 9ddea53d..0497f887 100644 --- a/common/rfb/SMsgReader.cxx +++ b/common/rfb/SMsgReader.cxx @@ -107,7 +107,7 @@ bool SMsgReader::readMsg() break; default: vlog.error("unknown message type %d", currentMsgType); - throw Exception("unknown message type"); + throw protocol_error("unknown message type"); } if (ret) @@ -272,11 +272,32 @@ bool SMsgReader::readKeyEvent() bool SMsgReader::readPointerEvent() { + int mask; + int x; + int y; + if (!is->hasData(1 + 2 + 2)) return false; - int mask = is->readU8(); - int x = is->readU16(); - int y = is->readU16(); + + is->setRestorePoint(); + + mask = is->readU8(); + x = is->readU16(); + y = is->readU16(); + + if (handler->client.supportsExtendedMouseButtons() && mask & 0x80 ) { + int highBits; + int lowBits; + + if (!is->hasDataOrRestore(1)) + return false; + + highBits = is->readU8(); + lowBits = mask & 0x7f; /* Clear marker bit */ + mask = (highBits << 7) | lowBits; + } + + is->clearRestorePoint(); handler->pointerEvent(Point(x, y), mask); return true; } @@ -334,7 +355,7 @@ bool SMsgReader::readExtendedClipboard(int32_t len) return false; if (len < 4) - throw Exception("Invalid extended clipboard message"); + throw protocol_error("Invalid extended clipboard message"); if (len > maxCutText) { vlog.error("Extended clipboard message too long (%d bytes) - ignoring", len); is->skip(len); @@ -356,7 +377,7 @@ bool SMsgReader::readExtendedClipboard(int32_t len) } if (len < (int32_t)(4 + 4*num)) - throw Exception("Invalid extended clipboard message"); + throw protocol_error("Invalid extended clipboard message"); num = 0; for (i = 0;i < 16;i++) { @@ -381,7 +402,7 @@ bool SMsgReader::readExtendedClipboard(int32_t len) continue; if (!zis.hasData(4)) - throw Exception("Extended clipboard decode error"); + throw protocol_error("Extended clipboard decode error"); lengths[num] = zis.readU32(); @@ -394,7 +415,7 @@ bool SMsgReader::readExtendedClipboard(int32_t len) size_t chunk; if (!zis.hasData(1)) - throw Exception("Extended clipboard decode error"); + throw protocol_error("Extended clipboard decode error"); chunk = zis.avail(); if (chunk > lengths[num]) @@ -410,7 +431,7 @@ bool SMsgReader::readExtendedClipboard(int32_t len) } if (!zis.hasData(lengths[num])) - throw Exception("Extended clipboard decode error"); + throw protocol_error("Extended clipboard decode error"); buffers[num] = new uint8_t[lengths[num]]; zis.readBytes(buffers[num], lengths[num]); @@ -440,7 +461,7 @@ bool SMsgReader::readExtendedClipboard(int32_t len) handler->handleClipboardNotify(flags); break; default: - throw Exception("Invalid extended clipboard action"); + throw protocol_error("Invalid extended clipboard action"); } } @@ -464,7 +485,7 @@ bool SMsgReader::readQEMUMessage() ret = readQEMUKeyEvent(); break; default: - throw Exception("unknown QEMU submessage type %d", subType); + throw protocol_error(format("unknown QEMU submessage type %d", subType)); } if (!ret) { diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx index 0c03b51d..5ee0905b 100644 --- a/common/rfb/SMsgWriter.cxx +++ b/common/rfb/SMsgWriter.cxx @@ -31,7 +31,6 @@ #include <rfb/msgTypes.h> #include <rfb/fenceTypes.h> #include <rfb/clipboardTypes.h> -#include <rfb/Exception.h> #include <rfb/ClientParams.h> #include <rfb/UpdateTracker.h> #include <rfb/Encoder.h> @@ -49,7 +48,7 @@ SMsgWriter::SMsgWriter(ClientParams* client_, rdr::OutStream* os_) nRectsInUpdate(0), nRectsInHeader(0), needSetDesktopName(false), needCursor(false), needCursorPos(false), needLEDState(false), - needQEMUKeyEvent(false) + needQEMUKeyEvent(false), needExtMouseButtonsEvent(false) { } @@ -94,7 +93,7 @@ void SMsgWriter::writeBell() void SMsgWriter::writeServerCutText(const char* str) { if (strchr(str, '\r') != nullptr) - throw Exception("Invalid carriage return in clipboard data"); + throw std::invalid_argument("Invalid carriage return in clipboard data"); std::string latin1(utf8ToLatin1(str)); @@ -111,7 +110,7 @@ void SMsgWriter::writeClipboardCaps(uint32_t caps, size_t i, count; if (!client->supportsEncoding(pseudoEncodingExtendedClipboard)) - throw Exception("Client does not support extended clipboard"); + throw std::logic_error("Client does not support extended clipboard"); count = 0; for (i = 0;i < 16;i++) { @@ -137,9 +136,9 @@ void SMsgWriter::writeClipboardCaps(uint32_t caps, void SMsgWriter::writeClipboardRequest(uint32_t flags) { if (!client->supportsEncoding(pseudoEncodingExtendedClipboard)) - throw Exception("Client does not support extended clipboard"); + throw std::logic_error("Client does not support extended clipboard"); if (!(client->clipboardFlags() & clipboardRequest)) - throw Exception("Client does not support clipboard \"request\" action"); + throw std::logic_error("Client does not support clipboard \"request\" action"); startMsg(msgTypeServerCutText); os->pad(3); @@ -151,9 +150,9 @@ void SMsgWriter::writeClipboardRequest(uint32_t flags) void SMsgWriter::writeClipboardPeek(uint32_t flags) { if (!client->supportsEncoding(pseudoEncodingExtendedClipboard)) - throw Exception("Client does not support extended clipboard"); + throw std::logic_error("Client does not support extended clipboard"); if (!(client->clipboardFlags() & clipboardPeek)) - throw Exception("Client does not support clipboard \"peek\" action"); + throw std::logic_error("Client does not support clipboard \"peek\" action"); startMsg(msgTypeServerCutText); os->pad(3); @@ -165,9 +164,9 @@ void SMsgWriter::writeClipboardPeek(uint32_t flags) void SMsgWriter::writeClipboardNotify(uint32_t flags) { if (!client->supportsEncoding(pseudoEncodingExtendedClipboard)) - throw Exception("Client does not support extended clipboard"); + throw std::logic_error("Client does not support extended clipboard"); if (!(client->clipboardFlags() & clipboardNotify)) - throw Exception("Client does not support clipboard \"notify\" action"); + throw std::logic_error("Client does not support clipboard \"notify\" action"); startMsg(msgTypeServerCutText); os->pad(3); @@ -186,9 +185,9 @@ void SMsgWriter::writeClipboardProvide(uint32_t flags, int i, count; if (!client->supportsEncoding(pseudoEncodingExtendedClipboard)) - throw Exception("Client does not support extended clipboard"); + throw std::logic_error("Client does not support extended clipboard"); if (!(client->clipboardFlags() & clipboardProvide)) - throw Exception("Client does not support clipboard \"provide\" action"); + throw std::logic_error("Client does not support clipboard \"provide\" action"); zos.setUnderlying(&mos); @@ -215,11 +214,11 @@ void SMsgWriter::writeFence(uint32_t flags, unsigned len, const uint8_t data[]) { if (!client->supportsEncoding(pseudoEncodingFence)) - throw Exception("Client does not support fences"); + throw std::logic_error("Client does not support fences"); if (len > 64) - throw Exception("Too large fence payload"); + throw std::out_of_range("Too large fence payload"); if ((flags & ~fenceFlagsSupported) != 0) - throw Exception("Unknown fence flags"); + throw std::invalid_argument("Unknown fence flags"); startMsg(msgTypeServerFence); os->pad(3); @@ -237,7 +236,7 @@ void SMsgWriter::writeFence(uint32_t flags, unsigned len, void SMsgWriter::writeEndOfContinuousUpdates() { if (!client->supportsEncoding(pseudoEncodingContinuousUpdates)) - throw Exception("Client does not support continuous updates"); + throw std::logic_error("Client does not support continuous updates"); startMsg(msgTypeEndOfContinuousUpdates); endMsg(); @@ -249,7 +248,7 @@ void SMsgWriter::writeDesktopSize(uint16_t reason, uint16_t result) if (!client->supportsEncoding(pseudoEncodingDesktopSize) && !client->supportsEncoding(pseudoEncodingExtendedDesktopSize)) - throw Exception("Client does not support desktop size changes"); + throw std::logic_error("Client does not support desktop size changes"); msg.reason = reason; msg.result = result; @@ -260,7 +259,7 @@ void SMsgWriter::writeDesktopSize(uint16_t reason, uint16_t result) void SMsgWriter::writeSetDesktopName() { if (!client->supportsEncoding(pseudoEncodingDesktopName)) - throw Exception("Client does not support desktop name changes"); + throw std::logic_error("Client does not support desktop name changes"); needSetDesktopName = true; } @@ -271,7 +270,7 @@ void SMsgWriter::writeCursor() !client->supportsEncoding(pseudoEncodingXCursor) && !client->supportsEncoding(pseudoEncodingCursorWithAlpha) && !client->supportsEncoding(pseudoEncodingVMwareCursor)) - throw Exception("Client does not support local cursor"); + throw std::logic_error("Client does not support local cursor"); needCursor = true; } @@ -279,7 +278,7 @@ void SMsgWriter::writeCursor() void SMsgWriter::writeCursorPos() { if (!client->supportsEncoding(pseudoEncodingVMwareCursorPosition)) - throw Exception("Client does not support cursor position"); + throw std::logic_error("Client does not support cursor position"); needCursorPos = true; } @@ -288,9 +287,9 @@ void SMsgWriter::writeLEDState() { if (!client->supportsEncoding(pseudoEncodingLEDState) && !client->supportsEncoding(pseudoEncodingVMwareLEDState)) - throw Exception("Client does not support LED state"); + throw std::logic_error("Client does not support LED state"); if (client->ledState() == ledUnknown) - throw Exception("Server has not specified LED state"); + throw std::logic_error("Server has not specified LED state"); needLEDState = true; } @@ -298,11 +297,19 @@ void SMsgWriter::writeLEDState() void SMsgWriter::writeQEMUKeyEvent() { if (!client->supportsEncoding(pseudoEncodingQEMUKeyEvent)) - throw Exception("Client does not support QEMU key events"); + throw std::logic_error("Client does not support QEMU key events"); needQEMUKeyEvent = true; } +void SMsgWriter::writeExtendedMouseButtonsSupport() +{ + if (!client->supportsEncoding(pseudoEncodingExtendedMouseButtons)) + throw std::logic_error("Client does not support Extended Mouse Buttons"); + + needExtMouseButtonsEvent = true; +} + bool SMsgWriter::needFakeUpdate() { if (needSetDesktopName) @@ -315,6 +322,8 @@ bool SMsgWriter::needFakeUpdate() return true; if (needQEMUKeyEvent) return true; + if (needExtMouseButtonsEvent) + return true; if (needNoDataUpdate()) return true; @@ -363,6 +372,8 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects) nRects++; if (needQEMUKeyEvent) nRects++; + if (needExtMouseButtonsEvent) + nRects++; } os->writeU16(nRects); @@ -379,8 +390,8 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects) void SMsgWriter::writeFramebufferUpdateEnd() { if (nRectsInUpdate != nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeFramebufferUpdateEnd: " - "nRects out of sync"); + throw std::logic_error("SMsgWriter::writeFramebufferUpdateEnd: " + "nRects out of sync"); if (nRectsInHeader == 0) { // Send last rect. marker @@ -405,7 +416,7 @@ void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY) void SMsgWriter::startRect(const Rect& r, int encoding) { if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::startRect: nRects out of sync"); + throw std::logic_error("SMsgWriter::startRect: nRects out of sync"); os->writeS16(r.tl.x); os->writeS16(r.tl.y); @@ -470,7 +481,7 @@ void SMsgWriter::writePseudoRects() cursor.hotspot().x, cursor.hotspot().y, bitmap.data(), mask.data()); } else { - throw Exception("Client does not support local cursor"); + throw std::logic_error("Client does not support local cursor"); } needCursor = false; @@ -482,7 +493,7 @@ void SMsgWriter::writePseudoRects() if (client->supportsEncoding(pseudoEncodingVMwareCursorPosition)) { writeSetVMwareCursorPositionRect(cursorPos.x, cursorPos.y); } else { - throw Exception("Client does not support cursor position"); + throw std::logic_error("Client does not support cursor position"); } needCursorPos = false; @@ -502,6 +513,11 @@ void SMsgWriter::writePseudoRects() writeQEMUKeyEventRect(); needQEMUKeyEvent = false; } + + if (needExtMouseButtonsEvent) { + writeExtendedMouseButtonsRect(); + needExtMouseButtonsEvent = false; + } } void SMsgWriter::writeNoDataRects() @@ -519,7 +535,7 @@ void SMsgWriter::writeNoDataRects() // more after this writeSetDesktopSizeRect(client->width(), client->height()); } else { - throw Exception("Client does not support desktop size changes"); + throw std::logic_error("Client does not support desktop size changes"); } extendedDesktopSizeMsgs.clear(); @@ -529,9 +545,9 @@ void SMsgWriter::writeNoDataRects() void SMsgWriter::writeSetDesktopSizeRect(int width, int height) { if (!client->supportsEncoding(pseudoEncodingDesktopSize)) - throw Exception("Client does not support desktop resize"); + throw std::logic_error("Client does not support desktop resize"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeSetDesktopSizeRect: nRects out of sync"); + throw std::logic_error("SMsgWriter::writeSetDesktopSizeRect: nRects out of sync"); os->writeS16(0); os->writeS16(0); @@ -549,9 +565,9 @@ void SMsgWriter::writeExtendedDesktopSizeRect(uint16_t reason, ScreenSet::const_iterator si; if (!client->supportsEncoding(pseudoEncodingExtendedDesktopSize)) - throw Exception("Client does not support extended desktop resize"); + throw std::logic_error("Client does not support extended desktop resize"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeExtendedDesktopSizeRect: nRects out of sync"); + throw std::logic_error("SMsgWriter::writeExtendedDesktopSizeRect: nRects out of sync"); os->writeU16(reason); os->writeU16(result); @@ -575,9 +591,9 @@ void SMsgWriter::writeExtendedDesktopSizeRect(uint16_t reason, void SMsgWriter::writeSetDesktopNameRect(const char *name) { if (!client->supportsEncoding(pseudoEncodingDesktopName)) - throw Exception("Client does not support desktop rename"); + throw std::logic_error("Client does not support desktop rename"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeSetDesktopNameRect: nRects out of sync"); + throw std::logic_error("SMsgWriter::writeSetDesktopNameRect: nRects out of sync"); os->writeS16(0); os->writeS16(0); @@ -594,9 +610,9 @@ void SMsgWriter::writeSetCursorRect(int width, int height, const uint8_t* mask) { if (!client->supportsEncoding(pseudoEncodingCursor)) - throw Exception("Client does not support local cursors"); + throw std::logic_error("Client does not support local cursors"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeSetCursorRect: nRects out of sync"); + throw std::logic_error("SMsgWriter::writeSetCursorRect: nRects out of sync"); os->writeS16(hotspotX); os->writeS16(hotspotY); @@ -613,9 +629,9 @@ void SMsgWriter::writeSetXCursorRect(int width, int height, const uint8_t* mask) { if (!client->supportsEncoding(pseudoEncodingXCursor)) - throw Exception("Client does not support local cursors"); + throw std::logic_error("Client does not support local cursors"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeSetXCursorRect: nRects out of sync"); + throw std::logic_error("SMsgWriter::writeSetXCursorRect: nRects out of sync"); os->writeS16(hotspotX); os->writeS16(hotspotY); @@ -639,9 +655,9 @@ void SMsgWriter::writeSetCursorWithAlphaRect(int width, int height, const uint8_t* data) { if (!client->supportsEncoding(pseudoEncodingCursorWithAlpha)) - throw Exception("Client does not support local cursors"); + throw std::logic_error("Client does not support local cursors"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeSetCursorWithAlphaRect: nRects out of sync"); + throw std::logic_error("SMsgWriter::writeSetCursorWithAlphaRect: nRects out of sync"); os->writeS16(hotspotX); os->writeS16(hotspotY); @@ -667,9 +683,9 @@ void SMsgWriter::writeSetVMwareCursorRect(int width, int height, const uint8_t* data) { if (!client->supportsEncoding(pseudoEncodingVMwareCursor)) - throw Exception("Client does not support local cursors"); + throw std::logic_error("Client does not support local cursors"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeSetVMwareCursorRect: nRects out of sync"); + throw std::logic_error("SMsgWriter::writeSetVMwareCursorRect: nRects out of sync"); os->writeS16(hotspotX); os->writeS16(hotspotY); @@ -687,9 +703,9 @@ void SMsgWriter::writeSetVMwareCursorRect(int width, int height, void SMsgWriter::writeSetVMwareCursorPositionRect(int hotspotX, int hotspotY) { if (!client->supportsEncoding(pseudoEncodingVMwareCursorPosition)) - throw Exception("Client does not support cursor position"); + throw std::logic_error("Client does not support cursor position"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeSetVMwareCursorRect: nRects out of sync"); + throw std::logic_error("SMsgWriter::writeSetVMwareCursorRect: nRects out of sync"); os->writeS16(hotspotX); os->writeS16(hotspotY); @@ -702,11 +718,11 @@ void SMsgWriter::writeLEDStateRect(uint8_t state) { if (!client->supportsEncoding(pseudoEncodingLEDState) && !client->supportsEncoding(pseudoEncodingVMwareLEDState)) - throw Exception("Client does not support LED state updates"); + throw std::logic_error("Client does not support LED state updates"); if (client->ledState() == ledUnknown) - throw Exception("Server does not support LED state updates"); + throw std::logic_error("Server does not support LED state updates"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeLEDStateRect: nRects out of sync"); + throw std::logic_error("SMsgWriter::writeLEDStateRect: nRects out of sync"); os->writeS16(0); os->writeS16(0); @@ -724,9 +740,9 @@ void SMsgWriter::writeLEDStateRect(uint8_t state) void SMsgWriter::writeQEMUKeyEventRect() { if (!client->supportsEncoding(pseudoEncodingQEMUKeyEvent)) - throw Exception("Client does not support QEMU extended key events"); + throw std::logic_error("Client does not support QEMU extended key events"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeQEMUKeyEventRect: nRects out of sync"); + throw std::logic_error("SMsgWriter::writeQEMUKeyEventRect: nRects out of sync"); os->writeS16(0); os->writeS16(0); @@ -734,3 +750,17 @@ void SMsgWriter::writeQEMUKeyEventRect() os->writeU16(0); os->writeU32(pseudoEncodingQEMUKeyEvent); } + +void SMsgWriter::writeExtendedMouseButtonsRect() +{ + if (!client->supportsEncoding(pseudoEncodingExtendedMouseButtons)) + throw std::logic_error("Client does not support extended mouse button events"); + if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) + throw std::logic_error("SMsgWriter::writeExtendedMouseButtonsRect: nRects out of sync"); + + os->writeS16(0); + os->writeS16(0); + os->writeU16(0); + os->writeU16(0); + os->writeU32(pseudoEncodingExtendedMouseButtons); +} diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h index c46551e9..7bc0ed6a 100644 --- a/common/rfb/SMsgWriter.h +++ b/common/rfb/SMsgWriter.h @@ -93,6 +93,9 @@ namespace rfb { // And QEMU keyboard event handshake void writeQEMUKeyEvent(); + // let the client know we support extended mouse button support + void writeExtendedMouseButtonsSupport(); + // needFakeUpdate() returns true when an immediate update is needed in // order to flush out pseudo-rectangles to the client. bool needFakeUpdate(); @@ -148,6 +151,7 @@ namespace rfb { void writeSetVMwareCursorPositionRect(int hotspotX, int hotspotY); void writeLEDStateRect(uint8_t state); void writeQEMUKeyEventRect(); + void writeExtendedMouseButtonsRect(); ClientParams* client; rdr::OutStream* os; @@ -160,6 +164,7 @@ namespace rfb { bool needCursorPos; bool needLEDState; bool needQEMUKeyEvent; + bool needExtMouseButtonsEvent; typedef struct { uint16_t reason, result; diff --git a/common/rfb/SSecurity.h b/common/rfb/SSecurity.h index 8e296c5a..0911ecd8 100644 --- a/common/rfb/SSecurity.h +++ b/common/rfb/SSecurity.h @@ -20,14 +20,15 @@ // derived class for a particular security type overrides the processMsg() // method. -// processMsg() is called first when the security type has been decided on, and -// will keep being called whenever there is data to read from the client. It -// should return false when it needs more data, or true when the connection has -// been successfully authenticated. In the event of authentication failure an -// AuthFailureException should be thrown - this will result in a "failed" -// security result being sent to the client with the str() from the exception -// being sent as the reason. Any other type of failure should be indicated by -// some other kind of exception which will cause the connection to be aborted. +// processMsg() is called first when the security type has been decided +// on, and will keep being called whenever there is data to read from +// the client. It should return false when it needs more data, or true +// when the connection has been successfully authenticated. In the +// event of authentication failure an auth_error should be thrown - this +// will result in a "failed" security result being sent to the client +// with the str() from the exception being sent as the reason. Any +// other type of failure should be indicated by some other kind of +// exception which will cause the connection to be aborted. // // processMsg() must never block (or at least must never block until the client // has been authenticated) - this is to prevent denial of service attacks. diff --git a/common/rfb/SSecurityPlain.cxx b/common/rfb/SSecurityPlain.cxx index e009de39..e62e6d60 100644 --- a/common/rfb/SSecurityPlain.cxx +++ b/common/rfb/SSecurityPlain.cxx @@ -87,7 +87,7 @@ bool SSecurityPlain::processMsg() char password[1024]; if (!valid) - throw Exception("No password validator configured"); + throw std::logic_error("No password validator configured"); if (state == 0) { if (!is->hasData(8)) @@ -95,11 +95,11 @@ bool SSecurityPlain::processMsg() ulen = is->readU32(); if (ulen >= sizeof(username)) - throw AuthFailureException("Too long username"); + throw auth_error("Too long username"); plen = is->readU32(); if (plen >= sizeof(password)) - throw AuthFailureException("Too long password"); + throw auth_error("Too long password"); state = 1; } @@ -114,7 +114,7 @@ bool SSecurityPlain::processMsg() username[ulen] = 0; plen = 0; if (!valid->validate(sc, username, password)) - throw AuthFailureException("Authentication failed"); + throw auth_error("Authentication failed"); } return true; diff --git a/common/rfb/SSecurityRSAAES.cxx b/common/rfb/SSecurityRSAAES.cxx index 6dd700ce..2f26de26 100644 --- a/common/rfb/SSecurityRSAAES.cxx +++ b/common/rfb/SSecurityRSAAES.cxx @@ -36,12 +36,15 @@ #include <nettle/sha2.h> #include <nettle/base64.h> #include <nettle/asn1.h> + +#include <rdr/AESInStream.h> +#include <rdr/AESOutStream.h> +#include <rdr/Exception.h> + #include <rfb/SSecurityRSAAES.h> #include <rfb/SConnection.h> #include <rfb/LogWriter.h> #include <rfb/Exception.h> -#include <rdr/AESInStream.h> -#include <rdr/AESOutStream.h> #if !defined(WIN32) && !defined(__APPLE__) #include <rfb/UnixPasswordValidator.h> #endif @@ -156,18 +159,18 @@ void SSecurityRSAAES::loadPrivateKey() { FILE* file = fopen(keyFile, "rb"); if (!file) - throw rdr::PosixException("failed to open key file", errno); + throw rdr::posix_error("failed to open key file", errno); fseek(file, 0, SEEK_END); size_t size = ftell(file); if (size == 0 || size > MaxKeyFileSize) { fclose(file); - throw Exception("size of key file is zero or too big"); + throw std::runtime_error("size of key file is zero or too big"); } fseek(file, 0, SEEK_SET); std::vector<uint8_t> data(size); if (fread(data.data(), 1, data.size(), file) != size) { fclose(file); - throw rdr::PosixException("failed to read key", errno); + throw rdr::posix_error("failed to read key", errno); } fclose(file); @@ -184,7 +187,7 @@ void SSecurityRSAAES::loadPrivateKey() loadPKCS8Key(der.data(), der.size()); return; } - throw Exception("failed to import key"); + throw std::runtime_error("failed to import key"); } void SSecurityRSAAES::loadPKCS1Key(const uint8_t* data, size_t size) @@ -195,7 +198,7 @@ void SSecurityRSAAES::loadPKCS1Key(const uint8_t* data, size_t size) if (!rsa_keypair_from_der(&pub, &serverKey, 0, size, data)) { rsa_private_key_clear(&serverKey); rsa_public_key_clear(&pub); - throw Exception("failed to import key"); + throw std::runtime_error("failed to import key"); } serverKeyLength = serverKey.size * 8; serverKeyN = new uint8_t[serverKey.size]; @@ -235,7 +238,7 @@ void SSecurityRSAAES::loadPKCS8Key(const uint8_t* data, size_t size) loadPKCS1Key(i.data, i.length); return; failed: - throw Exception("failed to import key"); + throw std::runtime_error("failed to import key"); } bool SSecurityRSAAES::processMsg() @@ -296,9 +299,9 @@ bool SSecurityRSAAES::readPublicKey() is->setRestorePoint(); clientKeyLength = is->readU32(); if (clientKeyLength < MinKeyLength) - throw Exception("client key is too short"); + throw protocol_error("client key is too short"); if (clientKeyLength > MaxKeyLength) - throw Exception("client key is too long"); + throw protocol_error("client key is too long"); size_t size = (clientKeyLength + 7) / 8; if (!is->hasDataOrRestore(size * 2)) return false; @@ -311,7 +314,7 @@ bool SSecurityRSAAES::readPublicKey() nettle_mpz_set_str_256_u(clientKey.n, size, clientKeyN); nettle_mpz_set_str_256_u(clientKey.e, size, clientKeyE); if (!rsa_public_key_prepare(&clientKey)) - throw Exception("client key is invalid"); + throw protocol_error("client key is invalid"); return true; } @@ -319,7 +322,7 @@ static void random_func(void* ctx, size_t length, uint8_t* dst) { rdr::RandomStream* rs = (rdr::RandomStream*)ctx; if (!rs->hasData(length)) - throw Exception("failed to encrypt random"); + throw std::runtime_error("failed to encrypt random"); rs->readBytes(dst, length); } @@ -327,7 +330,7 @@ void SSecurityRSAAES::writeRandom() { rdr::OutStream* os = sc->getOutStream(); if (!rs.hasData(keySize / 8)) - throw Exception("failed to generate random"); + throw std::runtime_error("failed to generate random"); rs.readBytes(serverRandom, keySize / 8); mpz_t x; mpz_init(x); @@ -341,7 +344,7 @@ void SSecurityRSAAES::writeRandom() } if (!res) { mpz_clear(x); - throw Exception("failed to encrypt random"); + throw std::runtime_error("failed to encrypt random"); } uint8_t* buffer = new uint8_t[clientKey.size]; nettle_mpz_get_str_256(clientKey.size, buffer, x); @@ -360,7 +363,7 @@ bool SSecurityRSAAES::readRandom() is->setRestorePoint(); size_t size = is->readU16(); if (size != serverKey.size) - throw Exception("server key length doesn't match"); + throw protocol_error("server key length doesn't match"); if (!is->hasDataOrRestore(size)) return false; is->clearRestorePoint(); @@ -373,7 +376,7 @@ bool SSecurityRSAAES::readRandom() if (!rsa_decrypt(&serverKey, &randomSize, clientRandom, x) || randomSize != (size_t)keySize / 8) { mpz_clear(x); - throw Exception("failed to decrypt client random"); + throw protocol_error("failed to decrypt client random"); } mpz_clear(x); return true; @@ -502,7 +505,7 @@ bool SSecurityRSAAES::readHash() sha256_digest(&ctx, hashSize, realHash); } if (memcmp(hash, realHash, hashSize) != 0) - throw Exception("hash doesn't match"); + throw protocol_error("hash doesn't match"); return true; } @@ -562,11 +565,11 @@ void SSecurityRSAAES::verifyUserPass() #endif if (!valid->validate(sc, username, password)) { delete valid; - throw AuthFailureException("Authentication failed"); + throw auth_error("Authentication failed"); } delete valid; #else - throw Exception("No password validator configured"); + throw std::logic_error("No password validator configured"); #endif } @@ -577,7 +580,7 @@ void SSecurityRSAAES::verifyPass() pg->getVncAuthPasswd(&passwd, &passwdReadOnly); if (passwd.empty()) - throw Exception("No password configured"); + throw std::runtime_error("No password configured"); if (password == passwd) { accessRights = AccessDefault; @@ -589,7 +592,7 @@ void SSecurityRSAAES::verifyPass() return; } - throw AuthFailureException("Authentication failed"); + throw auth_error("Authentication failed"); } const char* SSecurityRSAAES::getUserName() const diff --git a/common/rfb/SSecurityTLS.cxx b/common/rfb/SSecurityTLS.cxx index 465126eb..4b036e27 100644 --- a/common/rfb/SSecurityTLS.cxx +++ b/common/rfb/SSecurityTLS.cxx @@ -80,7 +80,7 @@ SSecurityTLS::SSecurityTLS(SConnection* sc_, bool _anon) ret = gnutls_global_init(); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_global_init()", ret); + throw rdr::tls_error("gnutls_global_init()", ret); } void SSecurityTLS::shutdown() @@ -152,11 +152,11 @@ bool SSecurityTLS::processMsg() err = gnutls_init(&session, GNUTLS_SERVER); if (err != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_init()", err); + throw rdr::tls_error("gnutls_init()", err); err = gnutls_set_default_priority(session); if (err != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_set_default_priority()", err); + throw rdr::tls_error("gnutls_set_default_priority()", err); try { setParams(); @@ -186,7 +186,7 @@ bool SSecurityTLS::processMsg() } vlog.error("TLS Handshake failed: %s", gnutls_strerror (err)); shutdown(); - throw rdr::TLSException("TLS Handshake failed", err); + throw rdr::tls_error("TLS Handshake failed", err); } vlog.debug("TLS handshake completed with %s", @@ -208,10 +208,8 @@ void SSecurityTLS::setParams() char *prio; const char *err; - prio = (char*)malloc(strlen(Security::GnuTLSPriority) + - strlen(kx_anon_priority) + 1); - if (prio == nullptr) - throw Exception("Not enough memory for GnuTLS priority string"); + prio = new char[strlen(Security::GnuTLSPriority) + + strlen(kx_anon_priority) + 1]; strcpy(prio, Security::GnuTLSPriority); if (anon) @@ -219,12 +217,12 @@ void SSecurityTLS::setParams() ret = gnutls_priority_set_direct(session, prio, &err); - free(prio); + delete [] prio; if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::TLSException("gnutls_set_priority_direct()", ret); + throw rdr::tls_error("gnutls_set_priority_direct()", ret); } } else if (anon) { const char *err; @@ -236,7 +234,7 @@ void SSecurityTLS::setParams() if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::TLSException("gnutls_set_default_priority_append()", ret); + throw rdr::tls_error("gnutls_set_default_priority_append()", ret); } #else // We don't know what the system default priority is, so we guess @@ -244,22 +242,20 @@ void SSecurityTLS::setParams() static const char gnutls_default_priority[] = "NORMAL"; char *prio; - prio = (char*)malloc(strlen(gnutls_default_priority) + - strlen(kx_anon_priority) + 1); - if (prio == nullptr) - throw Exception("Not enough memory for GnuTLS priority string"); + 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); - free(prio); + delete [] prio; if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw rdr::TLSException("gnutls_set_priority_direct()", ret); + throw rdr::tls_error("gnutls_set_priority_direct()", ret); } #endif } @@ -267,18 +263,18 @@ void SSecurityTLS::setParams() #if defined (SSECURITYTLS__USE_DEPRECATED_DH) ret = gnutls_dh_params_init(&dh_params); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_dh_params_init()", ret); + throw rdr::tls_error("gnutls_dh_params_init()", ret); ret = gnutls_dh_params_import_pkcs3(dh_params, &ffdhe_pkcs3_param, GNUTLS_X509_FMT_PEM); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_dh_params_import_pkcs3()", ret); + throw rdr::tls_error("gnutls_dh_params_import_pkcs3()", ret); #endif if (anon) { ret = gnutls_anon_allocate_server_credentials(&anon_cred); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_anon_allocate_server_credentials()", ret); + throw rdr::tls_error("gnutls_anon_allocate_server_credentials()", ret); #if defined (SSECURITYTLS__USE_DEPRECATED_DH) gnutls_anon_set_server_dh_params(anon_cred, dh_params); @@ -286,14 +282,14 @@ void SSecurityTLS::setParams() ret = gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_credentials_set()", ret); + throw rdr::tls_error("gnutls_credentials_set()", ret); vlog.debug("Anonymous session has been set"); } else { ret = gnutls_certificate_allocate_credentials(&cert_cred); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_certificate_allocate_credentials()", ret); + throw rdr::tls_error("gnutls_certificate_allocate_credentials()", ret); #if defined (SSECURITYTLS__USE_DEPRECATED_DH) gnutls_certificate_set_dh_params(cert_cred, dh_params); @@ -303,11 +299,11 @@ void SSecurityTLS::setParams() X509_KeyFile, GNUTLS_X509_FMT_PEM); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("Failed to load certificate and key", ret); + throw rdr::tls_error("Failed to load certificate and key", ret); ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred); if (ret != GNUTLS_E_SUCCESS) - throw rdr::TLSException("gnutls_credentials_set()", ret); + throw rdr::tls_error("gnutls_credentials_set()", ret); vlog.debug("X509 session has been set"); diff --git a/common/rfb/SSecurityVeNCrypt.cxx b/common/rfb/SSecurityVeNCrypt.cxx index 164ea927..4617fddb 100644 --- a/common/rfb/SSecurityVeNCrypt.cxx +++ b/common/rfb/SSecurityVeNCrypt.cxx @@ -99,8 +99,8 @@ bool SSecurityVeNCrypt::processMsg() case 0x0001: /* 0.1 Legacy VeNCrypt, not supported */ os->writeU8(0xFF); /* This is not OK */ os->flush(); - throw Exception("The client cannot support the server's " - "VeNCrypt version"); + throw protocol_error("The client cannot support the server's " + "VeNCrypt version"); case 0x0002: /* 0.2 */ os->writeU8(0); /* OK */ @@ -109,7 +109,7 @@ bool SSecurityVeNCrypt::processMsg() default: os->writeU8(0xFF); /* Not OK */ os->flush(); - throw Exception("The client returned an unsupported VeNCrypt version"); + throw protocol_error("The client returned an unsupported VeNCrypt version"); } } @@ -138,7 +138,7 @@ bool SSecurityVeNCrypt::processMsg() os->flush(); haveSentTypes = true; } else - throw Exception("There are no VeNCrypt sub-types to send to the client"); + throw protocol_error("There are no VeNCrypt sub-types to send to the client"); } /* get type back from client (must be one of the ones we sent) */ @@ -163,7 +163,7 @@ bool SSecurityVeNCrypt::processMsg() /* Set up the stack according to the chosen type */ if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt) - throw Exception("No valid VeNCrypt sub-type"); + throw protocol_error("No valid VeNCrypt sub-type"); ssecurity = security->GetSSecurity(sc, chosenType); } diff --git a/common/rfb/SSecurityVncAuth.cxx b/common/rfb/SSecurityVncAuth.cxx index 6b369a6f..22d88079 100644 --- a/common/rfb/SSecurityVncAuth.cxx +++ b/common/rfb/SSecurityVncAuth.cxx @@ -83,7 +83,7 @@ bool SSecurityVncAuth::processMsg() if (!sentChallenge) { rdr::RandomStream rs; if (!rs.hasData(vncAuthChallengeSize)) - throw Exception("Could not generate random data for VNC auth challenge"); + throw std::runtime_error("Could not generate random data for VNC auth challenge"); rs.readBytes(challenge, vncAuthChallengeSize); os->writeBytes(challenge, vncAuthChallengeSize); os->flush(); @@ -100,7 +100,7 @@ bool SSecurityVncAuth::processMsg() pg->getVncAuthPasswd(&passwd, &passwdReadOnly); if (passwd.empty()) - throw Exception("No password configured"); + throw std::runtime_error("No password configured"); if (verifyResponse(passwd.c_str())) { accessRights = AccessDefault; @@ -113,7 +113,7 @@ bool SSecurityVncAuth::processMsg() return true; } - throw AuthFailureException("Authentication failed"); + throw auth_error("Authentication failed"); } VncAuthPasswdParameter::VncAuthPasswdParameter(const char* name_, diff --git a/common/rfb/SecurityClient.cxx b/common/rfb/SecurityClient.cxx index 9cd3b904..027d47df 100644 --- a/common/rfb/SecurityClient.cxx +++ b/common/rfb/SecurityClient.cxx @@ -22,12 +22,14 @@ #endif #include <assert.h> + +#include <stdexcept> + #include <rfb/CSecurityNone.h> #include <rfb/CSecurityStack.h> #include <rfb/CSecurityVeNCrypt.h> #include <rfb/CSecurityVncAuth.h> #include <rfb/CSecurityPlain.h> -#include <rfb/Exception.h> #include <rfb/Security.h> #ifdef HAVE_GNUTLS #include <rfb/CSecurityTLS.h> @@ -110,5 +112,5 @@ CSecurity* SecurityClient::GetCSecurity(CConnection* cc, uint32_t secType) } bail: - throw Exception("Security type not supported"); + throw std::invalid_argument("Security type not supported"); } diff --git a/common/rfb/SecurityServer.cxx b/common/rfb/SecurityServer.cxx index b5297736..d692f4fc 100644 --- a/common/rfb/SecurityServer.cxx +++ b/common/rfb/SecurityServer.cxx @@ -21,7 +21,6 @@ #include <config.h> #endif -#include <rfb/Exception.h> #include <rfb/Security.h> #include <rfb/SSecurityNone.h> #include <rfb/SSecurityStack.h> @@ -90,6 +89,6 @@ SSecurity* SecurityServer::GetSSecurity(SConnection* sc, uint32_t secType) } bail: - throw Exception("Security type not supported"); + throw std::invalid_argument("Security type not supported"); } diff --git a/common/rfb/ServerParams.cxx b/common/rfb/ServerParams.cxx index 9f6f5307..15749ba5 100644 --- a/common/rfb/ServerParams.cxx +++ b/common/rfb/ServerParams.cxx @@ -22,9 +22,11 @@ #include <config.h> #endif -#include <rfb/Exception.h> +#include <stdexcept> + #include <rfb/ledStates.h> #include <rfb/ServerParams.h> +#include <rfb/util.h> using namespace rfb; @@ -32,7 +34,7 @@ ServerParams::ServerParams() : majorVersion(0), minorVersion(0), supportsQEMUKeyEvent(false), supportsSetDesktopSize(false), supportsFence(false), - supportsContinuousUpdates(false), + supportsContinuousUpdates(false), supportsExtendedMouseButtons(false), width_(0), height_(0), ledState_(ledUnknown) { @@ -59,7 +61,7 @@ void ServerParams::setDimensions(int width, int height) void ServerParams::setDimensions(int width, int height, const ScreenSet& layout) { if (!layout.validate(width, height)) - throw Exception("Attempted to configure an invalid screen layout"); + throw std::invalid_argument("Attempted to configure an invalid screen layout"); width_ = width; height_ = height; @@ -71,7 +73,7 @@ void ServerParams::setPF(const PixelFormat& pf) pf_ = pf; if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32) - throw Exception("setPF: not 8, 16 or 32 bpp?"); + throw std::invalid_argument("setPF: not 8, 16 or 32 bpp?"); } void ServerParams::setName(const char* name) @@ -99,7 +101,7 @@ uint32_t ServerParams::clipboardSize(unsigned int format) const return clipSizes[i]; } - throw Exception("Invalid clipboard format 0x%x", format); + throw std::invalid_argument(rfb::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 791e3e7f..d730b891 100644 --- a/common/rfb/ServerParams.h +++ b/common/rfb/ServerParams.h @@ -79,6 +79,7 @@ namespace rfb { bool supportsSetDesktopSize; bool supportsFence; bool supportsContinuousUpdates; + bool supportsExtendedMouseButtons; private: diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx index 807f71a5..ccf45a9d 100644 --- a/common/rfb/TightDecoder.cxx +++ b/common/rfb/TightDecoder.cxx @@ -36,6 +36,7 @@ #include <rfb/PixelBuffer.h> #include <rfb/TightConstants.h> #include <rfb/TightDecoder.h> +#include <rfb/util.h> using namespace rfb; @@ -103,14 +104,14 @@ bool TightDecoder::readRect(const Rect& r, rdr::InStream* is, // Quit on unsupported compression type. if (comp_ctl > tightMaxSubencoding) - throw Exception("TightDecoder: bad subencoding value received"); + throw protocol_error("TightDecoder: bad subencoding value received"); // "Basic" compression type. int palSize = 0; if (r.width() > TIGHT_MAX_WIDTH) - throw Exception("TightDecoder: too large rectangle (%d pixels)", r.width()); + throw protocol_error(format("TightDecoder: too large rectangle (%d pixels)", r.width())); // Possible palette if ((comp_ctl & tightExplicitFilter) != 0) { @@ -142,12 +143,12 @@ bool TightDecoder::readRect(const Rect& r, rdr::InStream* is, break; case tightFilterGradient: if (server.pf().bpp == 8) - throw Exception("TightDecoder: invalid BPP for gradient filter"); + throw protocol_error("TightDecoder: invalid BPP for gradient filter"); break; case tightFilterCopy: break; default: - throw Exception("TightDecoder: unknown filter code received"); + throw protocol_error("TightDecoder: unknown filter code received"); } } @@ -383,7 +384,7 @@ void TightDecoder::decodeRect(const Rect& r, const uint8_t* buffer, netbuf = new uint8_t[dataSize]; if (!zis[streamId].hasData(dataSize)) - throw Exception("Tight decode error"); + throw protocol_error("Tight decode error"); zis[streamId].readBytes(netbuf, dataSize); zis[streamId].flushUnderlying(); diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index ea918e8f..cb36872a 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -22,6 +22,8 @@ #include <config.h> #endif +#include <rdr/Exception.h> + #include <network/TcpSocket.h> #include <rfb/ComparingUpdateTracker.h> @@ -129,8 +131,8 @@ void VNCSConnectionST::close(const char* reason) if (sock->outStream().hasBufferedData()) vlog.error("Failed to flush remaining socket data on close"); } - } catch (rdr::Exception& e) { - vlog.error("Failed to flush remaining socket data on close: %s", e.str()); + } catch (std::exception& e) { + vlog.error("Failed to flush remaining socket data on close: %s", e.what()); } // Just shutdown the socket and mark our state as closing. Eventually the @@ -146,8 +148,8 @@ bool VNCSConnectionST::init() { try { initialiseProtocol(); - } catch (rdr::Exception& e) { - close(e.str()); + } catch (std::exception& e) { + close(e.what()); return false; } return true; @@ -187,10 +189,10 @@ void VNCSConnectionST::processMessages() // We wait until now with this to aggregate responses and to give // higher priority to user actions such as keyboard and pointer events. writeFramebufferUpdate(); - } catch (rdr::EndOfStream&) { + } catch (rdr::end_of_stream&) { close("Clean disconnection"); - } catch (rdr::Exception &e) { - close(e.str()); + } catch (std::exception& e) { + close(e.what()); } } @@ -203,8 +205,8 @@ void VNCSConnectionST::flushSocket() // delayed because of congestion. if (!sock->outStream().hasBufferedData()) writeFramebufferUpdate(); - } catch (rdr::Exception &e) { - close(e.str()); + } catch (std::exception& e) { + close(e.what()); } } @@ -252,8 +254,8 @@ void VNCSConnectionST::pixelBufferChange() updates.clear(); updates.add_changed(server->getPixelBuffer()->getRect()); writeFramebufferUpdate(); - } catch(rdr::Exception &e) { - close(e.str()); + } catch(std::exception& e) { + close(e.what()); } } @@ -261,8 +263,8 @@ void VNCSConnectionST::writeFramebufferUpdateOrClose() { try { writeFramebufferUpdate(); - } catch(rdr::Exception &e) { - close(e.str()); + } catch(std::exception& e) { + close(e.what()); } } @@ -271,8 +273,8 @@ void VNCSConnectionST::screenLayoutChangeOrClose(uint16_t reason) try { screenLayoutChange(reason); writeFramebufferUpdate(); - } catch(rdr::Exception &e) { - close(e.str()); + } catch(std::exception& e) { + close(e.what()); } } @@ -280,8 +282,8 @@ void VNCSConnectionST::bellOrClose() { try { if (state() == RFBSTATE_NORMAL) writer()->writeBell(); - } catch(rdr::Exception& e) { - close(e.str()); + } catch(std::exception& e) { + close(e.what()); } } @@ -290,8 +292,8 @@ void VNCSConnectionST::setDesktopNameOrClose(const char *name) try { setDesktopName(name); writeFramebufferUpdate(); - } catch(rdr::Exception& e) { - close(e.str()); + } catch(std::exception& e) { + close(e.what()); } } @@ -300,8 +302,8 @@ void VNCSConnectionST::setCursorOrClose() try { setCursor(); writeFramebufferUpdate(); - } catch(rdr::Exception& e) { - close(e.str()); + } catch(std::exception& e) { + close(e.what()); } } @@ -310,8 +312,8 @@ void VNCSConnectionST::setLEDStateOrClose(unsigned int state) try { setLEDState(state); writeFramebufferUpdate(); - } catch(rdr::Exception& e) { - close(e.str()); + } catch(std::exception& e) { + close(e.what()); } } @@ -322,8 +324,8 @@ void VNCSConnectionST::requestClipboardOrClose() if (!accessCheck(AccessCutText)) return; if (!rfb::Server::acceptCutText) return; requestClipboard(); - } catch(rdr::Exception& e) { - close(e.str()); + } catch(std::exception& e) { + close(e.what()); } } @@ -334,8 +336,8 @@ void VNCSConnectionST::announceClipboardOrClose(bool available) if (!accessCheck(AccessCutText)) return; if (!rfb::Server::sendCutText) return; announceClipboard(available); - } catch(rdr::Exception& e) { - close(e.str()); + } catch(std::exception& e) { + close(e.what()); } } @@ -346,8 +348,8 @@ void VNCSConnectionST::sendClipboardDataOrClose(const char* data) if (!accessCheck(AccessCutText)) return; if (!rfb::Server::sendCutText) return; sendClipboardData(data); - } catch(rdr::Exception& e) { - close(e.str()); + } catch(std::exception& e) { + close(e.what()); } } @@ -418,8 +420,8 @@ void VNCSConnectionST::approveConnectionOrClose(bool accept, { try { approveConnection(accept, reason); - } catch (rdr::Exception& e) { - close(e.str()); + } catch (std::exception& e) { + close(e.what()); } } @@ -474,7 +476,7 @@ void VNCSConnectionST::setPixelFormat(const PixelFormat& pf) setCursor(); } -void VNCSConnectionST::pointerEvent(const Point& pos, uint8_t buttonMask) +void VNCSConnectionST::pointerEvent(const Point& pos, uint16_t buttonMask) { if (rfb::Server::idleTimeout) idleTimer.start(secsToMillis(rfb::Server::idleTimeout)); @@ -728,7 +730,7 @@ void VNCSConnectionST::enableContinuousUpdates(bool enable, Rect rect; if (!client.supportsFence() || !client.supportsContinuousUpdates()) - throw Exception("Client tried to enable continuous updates when not allowed"); + throw protocol_error("Client tried to enable continuous updates when not allowed"); continuousUpdates = enable; @@ -805,8 +807,8 @@ void VNCSConnectionST::handleTimeout(Timer* t) if ((t == &congestionTimer) || (t == &losslessTimer)) writeFramebufferUpdate(); - } catch (rdr::Exception& e) { - close(e.str()); + } catch (std::exception& e) { + close(e.what()); } if (t == &idleTimer) diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index d857ef32..17de9d01 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -123,7 +123,7 @@ namespace rfb { void queryConnection(const char* userName) override; void clientInit(bool shared) override; void setPixelFormat(const PixelFormat& pf) override; - void pointerEvent(const Point& pos, uint8_t buttonMask) override; + void pointerEvent(const Point& pos, uint16_t buttonMask) override; void keyEvent(uint32_t keysym, uint32_t keycode, bool down) override; void framebufferUpdateRequest(const Rect& r, diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index feda8a83..f4f48e1e 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -58,7 +58,6 @@ #include <network/Socket.h> #include <rfb/ComparingUpdateTracker.h> -#include <rfb/Exception.h> #include <rfb/KeyRemapper.h> #include <rfb/KeysymStr.h> #include <rfb/LogWriter.h> @@ -151,7 +150,7 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing, AccessRights a os.writeU32(strlen(reason)); os.writeBytes((const uint8_t*)reason, strlen(reason)); os.flush(); - } catch (rdr::Exception&) { + } catch (std::exception&) { } sock->shutdown(); closingSockets.push_back(sock); @@ -224,7 +223,7 @@ void VNCServerST::processSocketReadEvent(network::Socket* sock) return; } } - throw rdr::Exception("invalid Socket in VNCServerST"); + throw std::invalid_argument("invalid Socket in VNCServerST"); } void VNCServerST::processSocketWriteEvent(network::Socket* sock) @@ -237,7 +236,7 @@ void VNCServerST::processSocketWriteEvent(network::Socket* sock) return; } } - throw rdr::Exception("invalid Socket in VNCServerST"); + throw std::invalid_argument("invalid Socket in VNCServerST"); } void VNCServerST::blockUpdates() @@ -284,13 +283,13 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_, const ScreenSet& layout) screenLayout = ScreenSet(); if (desktopStarted) - throw Exception("setPixelBuffer: null PixelBuffer when desktopStarted?"); + throw std::logic_error("setPixelBuffer: null PixelBuffer when desktopStarted?"); return; } if (!layout.validate(pb->width(), pb->height())) - throw Exception("setPixelBuffer: invalid screen layout"); + throw std::invalid_argument("setPixelBuffer: invalid screen layout"); screenLayout = layout; @@ -342,9 +341,9 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_) void VNCServerST::setScreenLayout(const ScreenSet& layout) { if (!pb) - throw Exception("setScreenLayout: new screen layout without a PixelBuffer"); + throw std::logic_error("setScreenLayout: new screen layout without a PixelBuffer"); if (!layout.validate(pb->width(), pb->height())) - throw Exception("setScreenLayout: invalid screen layout"); + throw std::invalid_argument("setScreenLayout: invalid screen layout"); screenLayout = layout; @@ -378,7 +377,7 @@ void VNCServerST::sendClipboardData(const char* data) std::list<VNCSConnectionST*>::iterator ci; if (strchr(data, '\r') != nullptr) - throw Exception("Invalid carriage return in clipboard data"); + throw std::invalid_argument("Invalid carriage return in clipboard data"); for (ci = clipboardRequestors.begin(); ci != clipboardRequestors.end(); ++ci) @@ -485,7 +484,7 @@ void VNCServerST::keyEvent(uint32_t keysym, uint32_t keycode, bool down) } void VNCServerST::pointerEvent(VNCSConnectionST* client, - const Point& pos, uint8_t buttonMask) + const Point& pos, uint16_t buttonMask) { time_t now = time(nullptr); if (rfb::Server::maxIdleTime) @@ -566,7 +565,7 @@ unsigned int VNCServerST::setDesktopSize(VNCSConnectionST* requester, // Sanity check if (screenLayout != layout) - throw Exception("Desktop configured a different screen layout than requested"); + throw std::runtime_error("Desktop configured a different screen layout than requested"); // Notify other clients for (ci = clients.begin(); ci != clients.end(); ++ci) { @@ -727,7 +726,7 @@ void VNCServerST::startDesktop() slog.debug("starting desktop"); desktop->start(); if (!pb) - throw Exception("SDesktop::start() did not set a valid PixelBuffer"); + throw std::logic_error("SDesktop::start() did not set a valid PixelBuffer"); desktopStarted = true; // The tracker might have accumulated changes whilst we were // stopped, so flush those out diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index 6cc75a68..dc4f9aad 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -117,7 +117,7 @@ namespace rfb { // Event handlers void keyEvent(uint32_t keysym, uint32_t keycode, bool down); - void pointerEvent(VNCSConnectionST* client, const Point& pos, uint8_t buttonMask); + void pointerEvent(VNCSConnectionST* client, const Point& pos, uint16_t buttonMask); void handleClipboardRequest(VNCSConnectionST* client); void handleClipboardAnnounce(VNCSConnectionST* client, bool available); diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx index e274a697..633d1c36 100644 --- a/common/rfb/ZRLEDecoder.cxx +++ b/common/rfb/ZRLEDecoder.cxx @@ -64,7 +64,7 @@ static inline T readPixel(rdr::ZlibInStream* zis) static inline void zlibHasData(rdr::ZlibInStream* zis, size_t length) { if (!zis->hasData(length)) - throw Exception("ZRLE decode error"); + throw protocol_error("ZRLE decode error"); } ZRLEDecoder::ZRLEDecoder() : Decoder(DecoderOrdered) @@ -242,7 +242,7 @@ void ZRLEDecoder::zrleDecode(const Rect& r, rdr::InStream* is, } while (b == 255); if (end - ptr < len) { - throw Exception ("ZRLE decode error"); + throw protocol_error("ZRLE decode error"); } while (len-- > 0) *ptr++ = pix; @@ -267,7 +267,7 @@ void ZRLEDecoder::zrleDecode(const Rect& r, rdr::InStream* is, } while (b == 255); if (end - ptr < len) { - throw Exception ("ZRLE decode error"); + throw protocol_error("ZRLE decode error"); } } diff --git a/common/rfb/encodings.h b/common/rfb/encodings.h index e427572f..16868460 100644 --- a/common/rfb/encodings.h +++ b/common/rfb/encodings.h @@ -36,6 +36,7 @@ namespace rfb { const int pseudoEncodingXCursor = -240; const int pseudoEncodingCursor = -239; + const int pseudoEncodingExtendedMouseButtons = -316; const int pseudoEncodingDesktopSize = -223; const int pseudoEncodingLEDState = -261; const int pseudoEncodingExtendedDesktopSize = -308; diff --git a/common/rfb/obfuscate.cxx b/common/rfb/obfuscate.cxx index 2afc1512..a88d2822 100644 --- a/common/rfb/obfuscate.cxx +++ b/common/rfb/obfuscate.cxx @@ -28,11 +28,12 @@ #include <assert.h> #include <string.h> +#include <stdexcept> + extern "C" { #include <rfb/d3des.h> } -#include <rdr/Exception.h> #include <rfb/obfuscate.h> static unsigned char d3desObfuscationKey[] = {23,82,107,6,35,78,88,7}; @@ -57,7 +58,7 @@ std::string rfb::deobfuscate(const uint8_t *data, size_t len) char buf[9]; if (len != 8) - throw rdr::Exception("bad obfuscated password length"); + throw std::invalid_argument("bad obfuscated password length"); assert(data != nullptr); |