diff options
author | DRC <dcommander@users.sourceforge.net> | 2011-10-07 05:38:00 +0000 |
---|---|---|
committer | DRC <dcommander@users.sourceforge.net> | 2011-10-07 05:38:00 +0000 |
commit | c19ab9ec7f3ac4823802388ac953e9494c613575 (patch) | |
tree | 63513ffd7ce0b3ab3de2d9b619cc4e5b892eea31 /java/com/tigervnc/rfb/CConnection.java | |
parent | bba54b0b14fded1d457f426cdc8843a34d6c9dc5 (diff) | |
download | tigervnc-c19ab9ec7f3ac4823802388ac953e9494c613575.tar.gz tigervnc-c19ab9ec7f3ac4823802388ac953e9494c613575.zip |
Move Java source up one level and allow Java viewer to be built as a standalone project (per community request)
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4715 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'java/com/tigervnc/rfb/CConnection.java')
-rw-r--r-- | java/com/tigervnc/rfb/CConnection.java | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/java/com/tigervnc/rfb/CConnection.java b/java/com/tigervnc/rfb/CConnection.java new file mode 100644 index 00000000..15e19896 --- /dev/null +++ b/java/com/tigervnc/rfb/CConnection.java @@ -0,0 +1,356 @@ +/* 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. + */ + +package com.tigervnc.rfb; + +import java.util.*; + +import com.tigervnc.rdr.*; + +abstract public class CConnection extends CMsgHandler { + + public CConnection() { + security = new SecurityClient(); + } + + // setStreams() sets the streams to be used for the connection. These must + // be set before initialiseProtocol() and processMsg() are called. The + // CSecurity object may call setStreams() again to provide alternative + // streams over which the RFB protocol is sent (i.e. encrypting/decrypting + // streams). Ownership of the streams remains with the caller + // (i.e. SConnection will not delete them). + public void setStreams(InStream is_, OutStream os_) { + is = is_; + os = os_; + } + + // initialiseProtocol() should be called once the streams and security + // types are set. Subsequently, processMsg() should be called whenever + // there is data to read on the InStream. + public void initialiseProtocol() { + state_ = RFBSTATE_PROTOCOL_VERSION; + } + + // processMsg() should be called whenever there is data to read on the + // InStream. You must have called initialiseProtocol() first. + public void processMsg() { + switch (state_) { + + case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break; + case RFBSTATE_SECURITY_TYPES: processSecurityTypesMsg(); break; + case RFBSTATE_SECURITY: processSecurityMsg(); break; + case RFBSTATE_SECURITY_RESULT: processSecurityResultMsg(); break; + case RFBSTATE_INITIALISATION: processInitMsg(); break; + case RFBSTATE_NORMAL: reader_.readMsg(); break; + case RFBSTATE_UNINITIALISED: + throw new Exception("CConnection.processMsg: not initialised yet?"); + default: + throw new Exception("CConnection.processMsg: invalid state"); + } + } + + private void processVersionMsg() { + vlog.debug("reading protocol version"); + Boolean done = new Boolean(true); + if (!cp.readVersion(is, done)) { + state_ = RFBSTATE_INVALID; + throw new Exception("reading version failed: not an RFB server?"); + } + if (!done.booleanValue()) return; + + vlog.info("Server supports RFB protocol version "+cp.majorVersion+"."+ + cp.minorVersion); + + // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8 + if (cp.beforeVersion(3,3)) { + String msg = ("Server gave unsupported RFB protocol version "+ + cp.majorVersion+"."+cp.minorVersion); + vlog.error(msg); + state_ = RFBSTATE_INVALID; + throw new Exception(msg); + } else if (useProtocol3_3 || cp.beforeVersion(3,7)) { + cp.setVersion(3,3); + } else if (cp.afterVersion(3,8)) { + cp.setVersion(3,8); + } + + cp.writeVersion(os); + state_ = RFBSTATE_SECURITY_TYPES; + + vlog.info("Using RFB protocol version "+ + cp.majorVersion+"."+cp.minorVersion); + } + + private void processSecurityTypesMsg() { + vlog.info("processing security types message"); + + int secType = Security.secTypeInvalid; + + List<Integer> secTypes = new ArrayList<Integer>(); + secTypes = security.GetEnabledSecTypes(); + //for (Iterator i = secTypes.iterator(); i.hasNext(); ) + // vlog.info(((Integer)i.next()).toString()); + + if (cp.isVersion(3,3)) { + + // legacy 3.3 server may only offer "vnc authentication" or "none" + + secType = is.readU32(); + if (secType == Security.secTypeInvalid) { + throwConnFailedException(); + + } else if (secType == Security.secTypeNone || secType == Security.secTypeVncAuth) { + Iterator i; + for (i = secTypes.iterator(); i.hasNext(); ) { + int refType = (Integer)i.next(); + if (refType == secType) { + secType = refType; + break; + } + if (!i.hasNext()) + secType = Security.secTypeInvalid; + } + + } else { + vlog.error("Unknown 3.3 security type "+secType); + throw new Exception("Unknown 3.3 security type"); + } + + } else { + + // 3.7 server will offer us a list + + int nServerSecTypes = is.readU8(); + if (nServerSecTypes == 0) + throwConnFailedException(); + + for (int i = 0; i < nServerSecTypes; i++) { + int serverSecType = is.readU8(); + vlog.info("Server offers security type "+ + Security.secTypeName(serverSecType)+"("+serverSecType+")"); + + /* + * Use the first type sent by server which matches client's type. + * It means server's order specifies priority. + */ + if (secType == Security.secTypeInvalid) { + for (Iterator j = secTypes.iterator(); j.hasNext(); ) { + int refType = (Integer)j.next(); + if (refType == serverSecType) { + secType = refType; + break; + } + } + } + } + + // Inform the server of our decision + if (secType != Security.secTypeInvalid) { + os.writeU8(secType); + os.flush(); + vlog.info("Choosing security type "+Security.secTypeName(secType)+ + "("+secType+")"); + } + } + + if (secType == Security.secTypeInvalid) { + state_ = RFBSTATE_INVALID; + vlog.error("No matching security types"); + throw new Exception("No matching security types"); + } + + state_ = RFBSTATE_SECURITY; + csecurity = security.GetCSecurity(secType); + processSecurityMsg(); + } + + private void processSecurityMsg() { + vlog.debug("processing security message"); + if (csecurity.processMsg(this)) { + state_ = RFBSTATE_SECURITY_RESULT; + processSecurityResultMsg(); + } + } + + private void processSecurityResultMsg() { + vlog.debug("processing security result message"); + int result; + if (cp.beforeVersion(3,8) && csecurity.getType() == Security.secTypeNone) { + result = Security.secResultOK; + } else { + if (!is.checkNoWait(1)) return; + result = is.readU32(); + } + switch (result) { + case Security.secResultOK: + securityCompleted(); + return; + case Security.secResultFailed: + vlog.debug("auth failed"); + break; + case Security.secResultTooMany: + vlog.debug("auth failed - too many tries"); + break; + default: + throw new Exception("Unknown security result from server"); + } + String reason; + if (cp.beforeVersion(3,8)) + reason = "Authentication failure"; + else + reason = is.readString(); + state_ = RFBSTATE_INVALID; + throw new AuthFailureException(reason); + } + + private void processInitMsg() { + vlog.debug("reading server initialisation"); + reader_.readServerInit(); + } + + private void throwConnFailedException() { + state_ = RFBSTATE_INVALID; + String reason; + reason = is.readString(); + throw new ConnFailedException(reason); + } + + private void securityCompleted() { + state_ = RFBSTATE_INITIALISATION; + reader_ = new CMsgReaderV3(this, is); + writer_ = new CMsgWriterV3(cp, os); + vlog.debug("Authentication success!"); + authSuccess(); + writer_.writeClientInit(shared); + } + + // Methods to initialise the connection + + // setServerName() is used to provide a unique(ish) name for the server to + // which we are connected. This might be the result of getPeerEndpoint on + // a TcpSocket, for example, or a host specified by DNS name & port. + // The serverName is used when verifying the Identity of a host (see RA2). + public void setServerName(String name) { + serverName = name; + } + + public void setServerPort(int port) { + serverPort = port; + } + + public void initSecTypes() { + nSecTypes = 0; + } + + // setShared sets the value of the shared flag which will be sent to the + // server upon initialisation. + public void setShared(boolean s) { shared = s; } + + // setProtocol3_3 configures whether or not the CConnection should + // only ever support protocol version 3.3 + public void setProtocol3_3(boolean s) { useProtocol3_3 = s; } + + // Methods to be overridden in a derived class + + // getCSecurity() gets the CSecurity object for the given type. The type + // is guaranteed to be one of the secTypes passed in to addSecType(). The + // CSecurity object's destroy() method will be called by the CConnection + // from its destructor. + //abstract public CSecurity getCSecurity(int secType); + + // getCurrentCSecurity() gets the CSecurity instance used for this + // connection. + //public CSecurity getCurrentCSecurity() { return security; } + + // setClientSecTypeOrder() determines whether the client should obey the + // server's security type preference, by picking the first server security + // type that the client supports, or whether it should pick the first type + // that the server supports, from the client-supported list of types. + public void setClientSecTypeOrder( boolean csto ) { + clientSecTypeOrder = csto; + } + + // authSuccess() is called when authentication has succeeded. + public void authSuccess() {} + + // serverInit() is called when the ServerInit message is received. The + // derived class must call on to CConnection::serverInit(). + public void serverInit() { + state_ = RFBSTATE_NORMAL; + vlog.debug("initialisation done"); + } + + // Other methods + + public CMsgReaderV3 reader() { return reader_; } + public CMsgWriterV3 writer() { return writer_; } + + public InStream getInStream() { return is; } + public OutStream getOutStream() { return os; } + + public String getServerName() { return serverName; } + public int getServerPort() { return serverPort; } + + public static final int RFBSTATE_UNINITIALISED = 0; + public static final int RFBSTATE_PROTOCOL_VERSION = 1; + public static final int RFBSTATE_SECURITY_TYPES = 2; + public static final int RFBSTATE_SECURITY = 3; + public static final int RFBSTATE_SECURITY_RESULT = 4; + public static final int RFBSTATE_INITIALISATION = 5; + public static final int RFBSTATE_NORMAL = 6; + public static final int RFBSTATE_INVALID = 7; + + public int state() { return state_; } + + protected void setState(int s) { state_ = s; } + + private void throwAuthFailureException() { + String reason; + vlog.debug("state="+state()+", ver="+cp.majorVersion+"."+cp.minorVersion); + if (state() == RFBSTATE_SECURITY_RESULT && !cp.beforeVersion(3,8)) { + reason = is.readString(); + } else { + reason = "Authentication failure"; + } + state_ = RFBSTATE_INVALID; + vlog.error(reason); + throw new AuthFailureException(reason); + } + + InStream is = null; + OutStream os = null; + CMsgReaderV3 reader_ = null; + CMsgWriterV3 writer_ = null; + boolean shared = false; + public CSecurity csecurity; + public SecurityClient security; + public static final int maxSecTypes = 8; + int nSecTypes; + int[] secTypes; + int state_ = RFBSTATE_UNINITIALISED; + String serverName; + int serverPort; + boolean useProtocol3_3 = false; + boolean clientSecTypeOrder; + public static java.net.Socket sock; + + public static java.net.Socket getSocket() { return sock; } + public static void setSocket(java.net.Socket sock_) { sock = sock_; } + + static LogWriter vlog = new LogWriter("CConnection"); +} |