Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@589 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
new file mode 100644
index 0000000..1422b54
--- /dev/null
+++ b/common/rfb/SConnection.cxx
@@ -0,0 +1,322 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <rfb/Exception.h>
+#include <rfb/secTypes.h>
+#include <rfb/SMsgReaderV3.h>
+#include <rfb/SMsgWriterV3.h>
+#include <rfb/SConnection.h>
+#include <rfb/ServerCore.h>
+
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+
+static LogWriter vlog("SConnection");
+
+// AccessRights values
+const SConnection::AccessRights SConnection::AccessView = 0x0001;
+const SConnection::AccessRights SConnection::AccessKeyEvents = 0x0002;
+const SConnection::AccessRights SConnection::AccessPtrEvents = 0x0004;
+const SConnection::AccessRights SConnection::AccessCutText = 0x0008;
+const SConnection::AccessRights SConnection::AccessDefault = 0x03ff;
+const SConnection::AccessRights SConnection::AccessNoQuery = 0x0400;
+const SConnection::AccessRights SConnection::AccessFull = 0xffff;
+
+
+SConnection::SConnection(SSecurityFactory* secFact, bool reverseConnection_)
+ : readyForSetColourMapEntries(false),
+ is(0), os(0), reader_(0), writer_(0),
+ security(0), securityFactory(secFact), state_(RFBSTATE_UNINITIALISED),
+ reverseConnection(reverseConnection_)
+{
+ defaultMajorVersion = 3;
+ defaultMinorVersion = 8;
+ if (rfb::Server::protocol3_3)
+ defaultMinorVersion = 3;
+
+ cp.setVersion(defaultMajorVersion, defaultMinorVersion);
+}
+
+SConnection::~SConnection()
+{
+ if (security) security->destroy();
+ deleteReaderAndWriter();
+}
+
+void SConnection::deleteReaderAndWriter()
+{
+ delete reader_;
+ reader_ = 0;
+ delete writer_;
+ writer_ = 0;
+}
+
+void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
+{
+ is = is_;
+ os = os_;
+}
+
+void SConnection::initialiseProtocol()
+{
+ cp.writeVersion(os);
+ state_ = RFBSTATE_PROTOCOL_VERSION;
+}
+
+void SConnection::processMsg()
+{
+ switch (state_) {
+ case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
+ case RFBSTATE_SECURITY_TYPE: processSecurityTypeMsg(); break;
+ case RFBSTATE_SECURITY: processSecurityMsg(); break;
+ case RFBSTATE_INITIALISATION: processInitMsg(); break;
+ case RFBSTATE_NORMAL: reader_->readMsg(); break;
+ case RFBSTATE_QUERYING:
+ throw Exception("SConnection::processMsg: bogus data from client while "
+ "querying");
+ case RFBSTATE_UNINITIALISED:
+ throw Exception("SConnection::processMsg: not initialised yet?");
+ default:
+ throw Exception("SConnection::processMsg: invalid state");
+ }
+}
+
+void SConnection::processVersionMsg()
+{
+ vlog.debug("reading protocol version");
+ bool done;
+ if (!cp.readVersion(is, &done)) {
+ state_ = RFBSTATE_INVALID;
+ throw Exception("reading version failed: not an RFB client?");
+ }
+ if (!done) return;
+
+ vlog.info("Client needs protocol version %d.%d",
+ cp.majorVersion, cp.minorVersion);
+
+ if (cp.majorVersion != 3) {
+ // unknown protocol version
+ char msg[256];
+ sprintf(msg,"Error: client needs protocol version %d.%d, server has %d.%d",
+ cp.majorVersion, cp.minorVersion,
+ defaultMajorVersion, defaultMinorVersion);
+ throwConnFailedException(msg);
+ }
+
+ if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) {
+ vlog.error("Client uses unofficial protocol version %d.%d",
+ cp.majorVersion,cp.minorVersion);
+ if (cp.minorVersion >= 8)
+ cp.minorVersion = 8;
+ else if (cp.minorVersion == 7)
+ cp.minorVersion = 7;
+ else
+ cp.minorVersion = 3;
+ vlog.error("Assuming compatibility with version %d.%d",
+ cp.majorVersion,cp.minorVersion);
+ }
+
+ versionReceived();
+
+ std::list<rdr::U8> secTypes;
+ std::list<rdr::U8>::iterator i;
+ securityFactory->getSecTypes(&secTypes, reverseConnection);
+
+ if (cp.isVersion(3,3)) {
+
+ // cope with legacy 3.3 client only if "no authentication" or "vnc
+ // authentication" is supported.
+ for (i=secTypes.begin(); i!=secTypes.end(); i++) {
+ if (*i == secTypeNone || *i == secTypeVncAuth) break;
+ }
+ if (i == secTypes.end()) {
+ char msg[256];
+ sprintf(msg,"No supported security type for %d.%d client",
+ cp.majorVersion, cp.minorVersion);
+ throwConnFailedException(msg);
+ }
+
+ os->writeU32(*i);
+ if (*i == secTypeNone) os->flush();
+ state_ = RFBSTATE_SECURITY;
+ security = securityFactory->getSSecurity(*i, reverseConnection);
+ processSecurityMsg();
+ return;
+ }
+
+ // list supported security types for >=3.7 clients
+
+ if (secTypes.empty())
+ throwConnFailedException("No supported security types");
+
+ os->writeU8(secTypes.size());
+ for (i=secTypes.begin(); i!=secTypes.end(); i++)
+ os->writeU8(*i);
+ os->flush();
+ state_ = RFBSTATE_SECURITY_TYPE;
+}
+
+
+void SConnection::processSecurityTypeMsg()
+{
+ vlog.debug("processing security type message");
+ int secType = is->readU8();
+
+ // Verify that the requested security type should be offered
+ std::list<rdr::U8> secTypes;
+ std::list<rdr::U8>::iterator i;
+ securityFactory->getSecTypes(&secTypes, reverseConnection);
+ for (i=secTypes.begin(); i!=secTypes.end(); i++)
+ if (*i == secType) break;
+ if (i == secTypes.end())
+ throw Exception("Requested security type not available");
+
+ vlog.info("Client requests security type %s(%d)",
+ secTypeName(secType),secType);
+
+ try {
+ state_ = RFBSTATE_SECURITY;
+ security = securityFactory->getSSecurity(secType, reverseConnection);
+ } catch (rdr::Exception& e) {
+ throwConnFailedException(e.str());
+ }
+
+ processSecurityMsg();
+}
+
+void SConnection::processSecurityMsg()
+{
+ vlog.debug("processing security message");
+ try {
+ bool done = security->processMsg(this);
+ if (done) {
+ state_ = RFBSTATE_QUERYING;
+ queryConnection(security->getUserName());
+ }
+ } catch (AuthFailureException& e) {
+ vlog.error("AuthFailureException: %s", e.str());
+ os->writeU32(secResultFailed);
+ if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
+ os->writeString(e.str());
+ os->flush();
+ throw;
+ }
+}
+
+void SConnection::processInitMsg()
+{
+ vlog.debug("reading client initialisation");
+ reader_->readClientInit();
+}
+
+void SConnection::throwConnFailedException(const char* msg)
+{
+ vlog.info(msg);
+ if (state_ == RFBSTATE_PROTOCOL_VERSION) {
+ if (cp.majorVersion == 3 && cp.minorVersion == 3) {
+ os->writeU32(0);
+ os->writeString(msg);
+ os->flush();
+ } else {
+ os->writeU8(0);
+ os->writeString(msg);
+ os->flush();
+ }
+ }
+ state_ = RFBSTATE_INVALID;
+ throw ConnFailedException(msg);
+}
+
+void SConnection::writeConnFailedFromScratch(const char* msg,
+ rdr::OutStream* os)
+{
+ os->writeBytes("RFB 003.003\n", 12);
+ os->writeU32(0);
+ os->writeString(msg);
+ os->flush();
+}
+
+void SConnection::versionReceived()
+{
+}
+
+void SConnection::authSuccess()
+{
+}
+
+void SConnection::queryConnection(const char* userName)
+{
+ approveConnection(true);
+}
+
+void SConnection::approveConnection(bool accept, const char* reason)
+{
+ if (state_ != RFBSTATE_QUERYING)
+ throw Exception("SConnection::approveConnection: invalid state");
+
+ if (!reason) reason = "Authentication failure";
+
+ if (!cp.beforeVersion(3,8) || security->getType() != secTypeNone) {
+ if (accept) {
+ os->writeU32(secResultOK);
+ } else {
+ os->writeU32(secResultFailed);
+ if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message
+ os->writeString(reason);
+ }
+ os->flush();
+ }
+
+ if (accept) {
+ state_ = RFBSTATE_INITIALISATION;
+ reader_ = new SMsgReaderV3(this, is);
+ writer_ = new SMsgWriterV3(&cp, os);
+ authSuccess();
+ } else {
+ state_ = RFBSTATE_INVALID;
+ throw AuthFailureException(reason);
+ }
+}
+
+void SConnection::setInitialColourMap()
+{
+}
+
+void SConnection::clientInit(bool shared)
+{
+ writer_->writeServerInit();
+ state_ = RFBSTATE_NORMAL;
+}
+
+void SConnection::setPixelFormat(const PixelFormat& pf)
+{
+ SMsgHandler::setPixelFormat(pf);
+ readyForSetColourMapEntries = true;
+}
+
+void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental)
+{
+ if (!readyForSetColourMapEntries) {
+ readyForSetColourMapEntries = true;
+ if (!cp.pf().trueColour) {
+ setInitialColourMap();
+ }
+ }
+}