From ce0907dd799c4fae886b9f757314a844c8dc9c02 Mon Sep 17 00:00:00 2001 From: Constantin Kaplinsky Date: Fri, 8 Sep 2006 12:55:37 +0000 Subject: [PATCH] Implemented support for TightVNC protocol extensions in the server code. This version has one incompatibility with TightVNC 1.3.x viewers - such viewers would not be able to connect without authentication. This will be fixed in the nearest time. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@651 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- common/rfb/CapsContainer.cxx | 5 ++ common/rfb/CapsContainer.h | 2 +- common/rfb/CapsList.cxx | 81 ++++++++++++++++++++ common/rfb/CapsList.h | 58 ++++++++++++++ common/rfb/ConnParams.cxx | 3 +- common/rfb/ConnParams.h | 1 + common/rfb/SConnection.cxx | 142 +++++++++++++++++++++++++++++++++++ common/rfb/SConnection.h | 9 +++ common/rfb/rfb.dsp | 8 ++ 9 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 common/rfb/CapsList.cxx create mode 100644 common/rfb/CapsList.h diff --git a/common/rfb/CapsContainer.cxx b/common/rfb/CapsContainer.cxx index 2eb91f64..cea5f3aa 100644 --- a/common/rfb/CapsContainer.cxx +++ b/common/rfb/CapsContainer.cxx @@ -16,6 +16,11 @@ * USA. */ +// +// CapsContainer class implementation. +// FIXME: Extend the comment. +// + #include using namespace rfb; diff --git a/common/rfb/CapsContainer.h b/common/rfb/CapsContainer.h index 0abbff0b..c7c8ab23 100644 --- a/common/rfb/CapsContainer.h +++ b/common/rfb/CapsContainer.h @@ -50,7 +50,7 @@ namespace rfb { class CapsContainer { public: CapsContainer(int maxCaps = 64); - ~CapsContainer(); + virtual ~CapsContainer(); void add(const CapabilityInfo *capinfo, const char *desc = 0); void add(rdr::U32 code, const char *vendor, const char *name, diff --git a/common/rfb/CapsList.cxx b/common/rfb/CapsList.cxx new file mode 100644 index 00000000..e5f0aff9 --- /dev/null +++ b/common/rfb/CapsList.cxx @@ -0,0 +1,81 @@ +/* Copyright (C) 2006 Constantin Kaplinsky. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// +// CapsList class implementation. +// FIXME: Extend the comment. +// + +#include +#include + +using namespace rfb; + +const char *const CapsList::VENDOR_STD = "STDV"; +const char *const CapsList::VENDOR_TIGHT = "TGHT"; + +CapsList::CapsList(int maxCaps) + : CapsContainer(maxCaps) +{ +} + +CapsList::~CapsList() +{ +} + +void +CapsList::addStandard(rdr::U32 code, const char *name) +{ + add3rdParty(code, name, VENDOR_STD); +} + +void +CapsList::addTightExt(rdr::U32 code, const char *name) +{ + add3rdParty(code, name, VENDOR_TIGHT); +} + +void +CapsList::add3rdParty(rdr::U32 code, const char *name, const char *vendor) +{ + add(code, vendor, name); + + // NOTE: This code is a bit tricky and not the most efficient. However, + // that's not a problem as we prefer simplicity to performance here. + // Here we need to "enable capability" but that requires comparing + // name and vendor strings. So we just make CapsContainer compare + // the same strings with themselves. + CapabilityInfo tmp; + if (getInfo(code, &tmp)) + enable(&tmp); +} + +void +CapsList::write(rdr::OutStream* os) const +{ + int count = getSize(); + CapabilityInfo cap; + + for (int i = 0; i < count; i++) { + getInfo(getByOrder(i), &cap); + os->writeU32(cap.code); + os->writeBytes(&cap.vendorSignature, 4); + os->writeBytes(&cap.nameSignature, 8); + } +} + diff --git a/common/rfb/CapsList.h b/common/rfb/CapsList.h new file mode 100644 index 00000000..ce17aabd --- /dev/null +++ b/common/rfb/CapsList.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2006 Constantin Kaplinsky. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// +// CapsList class declaration. +// FIXME: Extend the comment. +// + +#ifndef __RFB_CAPSLIST_H__ +#define __RFB_CAPSLIST_H__ + +#include + +namespace rdr { class OutStream; } + +namespace rfb { + + // NOTE: Here we use the CapsContainer class for an off-design purpose. + // However, that class is so good that I believe it's better to + // use its well-tested reliable code instead of writing new class + // from the scratch. + + class CapsList : private CapsContainer { + public: + CapsList(int maxCaps = 64); + virtual ~CapsList(); + + int getSize() const { return numEnabled(); } + + void addStandard(rdr::U32 code, const char *name); + void addTightExt(rdr::U32 code, const char *name); + void add3rdParty(rdr::U32 code, const char *name, const char *vendor); + + void write(rdr::OutStream* os) const; + + protected: + static const char *const VENDOR_STD; + static const char *const VENDOR_TIGHT; + }; + +} + +#endif // __RFB_CAPSLIST_H__ diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx index d4ae5894..42134c3c 100644 --- a/common/rfb/ConnParams.cxx +++ b/common/rfb/ConnParams.cxx @@ -26,7 +26,8 @@ using namespace rfb; ConnParams::ConnParams() - : majorVersion(0), minorVersion(0), width(0), height(0), useCopyRect(false), + : majorVersion(0), minorVersion(0), tightExtensionsEnabled(false), + width(0), height(0), useCopyRect(false), supportsLocalCursor(false), supportsLocalXCursor(false), supportsDesktopResize(true), supportsLastRect(false), customCompressLevel(false), compressLevel(6), noJpeg(false), qualityLevel(-1), diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h index 47e6a5fb..e29adf87 100644 --- a/common/rfb/ConnParams.h +++ b/common/rfb/ConnParams.h @@ -39,6 +39,7 @@ namespace rfb { int majorVersion; int minorVersion; + bool tightExtensionsEnabled; void setVersion(int major, int minor) { majorVersion = major; minorVersion = minor; diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx index 3901a811..d97be6cb 100644 --- a/common/rfb/SConnection.cxx +++ b/common/rfb/SConnection.cxx @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -85,6 +86,8 @@ void SConnection::processMsg() switch (state_) { case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break; case RFBSTATE_SECURITY_TYPE: processSecurityTypeMsg(); break; + case RFBSTATE_TIGHT_TUNN_TYPE: processTunnelTypeMsg(); break; + case RFBSTATE_TIGHT_AUTH_TYPE: processAuthTypeMsg(); break; case RFBSTATE_SECURITY: processSecurityMsg(); break; case RFBSTATE_INITIALISATION: processInitMsg(); break; case RFBSTATE_NORMAL: reader_->readMsg(); break; @@ -161,6 +164,9 @@ void SConnection::processVersionMsg() return; } + // Add a special security type to advertise TightVNC protocol extensions. + secTypes.push_back(secTypeTight); + // list supported security types for >=3.7 clients if (secTypes.empty()) @@ -179,9 +185,100 @@ void SConnection::processSecurityTypeMsg() vlog.debug("processing security type message"); int secType = is->readU8(); + if (secType == secTypeTight) { + vlog.info("Enabling TightVNC protocol extensions"); + cp.tightExtensionsEnabled = true; + offerTunneling(); + } else { + processSecurityType(secType); + } +} + +// +// TightVNC-specific protocol initialization (tunneling, authentication) +// + +void SConnection::offerTunneling() +{ + vlog.debug("offering list of tunneling methods"); + int nTypes = 0; + + // Advertise our tunneling capabilities (currently, nothing to advertise). + os->writeU32(nTypes); + + if (nTypes) { + state_ = RFBSTATE_TIGHT_TUNN_TYPE; + } else { + offerAuthentication(); + } +} + +// NOTE: This function is never called in current version. +void SConnection::processTunnelTypeMsg() +{ + vlog.debug("processing tunneling type message (TightVNC extension)"); + int tunnelType = is->readU32(); + vlog.error("unsupported tunneling type %d requested, ignoring", tunnelType); + offerAuthentication(); +} + +void SConnection::offerAuthentication() +{ + vlog.debug("offering list of authentication methods"); + + // FIXME: Security types and TightVNC's auth types should be distinguished + // although we use the same codes for NoAuth and VncAuth. + + // See processVersionMsg(), the code below is very similar. + std::list secTypes; + std::list::iterator i; + securityFactory->getSecTypes(&secTypes, reverseConnection); + + if (secTypes.empty()) + throwConnFailedException("No supported security types"); + + // FIXME: We should send an empty list for "no authentication". + + CapsList caps; + for (i = secTypes.begin(); i != secTypes.end(); i++) { + // FIXME: Use mapping instead (authType -> ProtocolCapability). + // Each auth type should provide its capability data. + // FIXME: Check that client will send auth type listed in capabilities. + // Currently, capabilities should duplicate secTypes exactly, + // but that may change in the future. + switch(*i) { + case secTypeNone: + caps.addStandard(secTypeNone, "NOAUTH__"); + break; + case secTypeVncAuth: + caps.addStandard(secTypeVncAuth, "VNCAUTH_"); + break; + } + } + os->writeU32(caps.getSize()); + caps.write(os); + os->flush(); + + // FIXME: Capability list is never empty here, otherwise + // we would not expect authentication type message. + state_ = RFBSTATE_TIGHT_AUTH_TYPE; +} + +void SConnection::processAuthTypeMsg() +{ + vlog.debug("processing authentication type message (TightVNC extension)"); + + // FIXME: Security types and TightVNC's auth types should be distinguished + // although we use the same codes for NoAuth and VncAuth. + + int secType = is->readU32(); processSecurityType(secType); } +// +// End of TightVNC-specific code +// + void SConnection::processSecurityType(int secType) { // Verify that the requested security type should be offered @@ -307,9 +404,54 @@ void SConnection::setInitialColourMap() void SConnection::clientInit(bool shared) { writer_->writeServerInit(); + + // FIXME: Is this a right place for this code? + if (cp.tightExtensionsEnabled) + sendInteractionCaps(); + state_ = RFBSTATE_NORMAL; } +// FIXME: Is this class a right place for this function? +void SConnection::sendInteractionCaps() +{ + // Advertise support for non-standard server-to-client messages. + CapsList scaps; + int nServerMsgTypes = scaps.getSize(); + + // Advertise support for non-standard client-to-server messages. + CapsList ccaps; + int nClientMsgTypes = ccaps.getSize(); + + // Advertise all supported encoding types (except raw encoding). + CapsList ecaps; + // FIXME: Add actually registered encodings (and CopyRect which is special). + // Ideally, encoders themselves should provide capability info. + ecaps.addStandard(encodingCopyRect, "COPYRECT"); + ecaps.addStandard(encodingRRE, "RRE_____"); + ecaps.addStandard(encodingHextile, "HEXTILE_"); + ecaps.addStandard(encodingZRLE, "ZRLE____"); + ecaps.addTightExt(encodingTight, "TIGHT___"); + ecaps.addTightExt(pseudoEncodingCompressLevel0, "COMPRLVL"); + ecaps.addTightExt(pseudoEncodingQualityLevel0, "JPEGQLVL"); + ecaps.addTightExt(pseudoEncodingXCursor, "X11CURSR"); + ecaps.addTightExt(pseudoEncodingCursor, "RCHCURSR"); + ecaps.addTightExt(pseudoEncodingLastRect, "LASTRECT"); + ecaps.addStandard(pseudoEncodingDesktopSize, "NEWFBSIZ"); + + os->writeU16(scaps.getSize()); + os->writeU16(ccaps.getSize()); + os->writeU16(ecaps.getSize()); + os->writeU16(0); + if (scaps.getSize()) + scaps.write(os); + if (ccaps.getSize()) + ccaps.write(os); + if (ecaps.getSize()) + ecaps.write(os); + os->flush(); +} + void SConnection::setPixelFormat(const PixelFormat& pf) { SMsgHandler::setPixelFormat(pf); diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h index 4c766315..e41ef5fb 100644 --- a/common/rfb/SConnection.h +++ b/common/rfb/SConnection.h @@ -155,6 +155,8 @@ namespace rfb { RFBSTATE_UNINITIALISED, RFBSTATE_PROTOCOL_VERSION, RFBSTATE_SECURITY_TYPE, + RFBSTATE_TIGHT_TUNN_TYPE, + RFBSTATE_TIGHT_AUTH_TYPE, RFBSTATE_SECURITY, RFBSTATE_QUERYING, RFBSTATE_INITIALISATION, @@ -180,6 +182,13 @@ namespace rfb { void processSecurityMsg(); void processInitMsg(); + // These functions add support for TightVNC protocol extensions. + void offerTunneling(); + void processTunnelTypeMsg(); + void offerAuthentication(); + void processAuthTypeMsg(); + void sendInteractionCaps(); + int defaultMajorVersion, defaultMinorVersion; rdr::InStream* is; rdr::OutStream* os; diff --git a/common/rfb/rfb.dsp b/common/rfb/rfb.dsp index a39ef84e..f24563e0 100644 --- a/common/rfb/rfb.dsp +++ b/common/rfb/rfb.dsp @@ -118,6 +118,10 @@ SOURCE=.\CapsContainer.cxx # End Source File # Begin Source File +SOURCE=.\CapsList.cxx +# End Source File +# Begin Source File + SOURCE=.\CConnection.cxx # End Source File # Begin Source File @@ -385,6 +389,10 @@ SOURCE=.\CapsContainer.h # End Source File # Begin Source File +SOURCE=.\CapsList.h +# End Source File +# Begin Source File + SOURCE=.\CConnection.h # End Source File # Begin Source File -- 2.39.5