📄 rfbproto.java
字号:
//// Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved.// Copyright (C) 2001-2006 Constantin Kaplinsky. All Rights Reserved.// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.// Copyright (C) 1999 AT&T Laboratories Cambridge. 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.////// RfbProto.java//import java.io.*;import java.awt.*;import java.awt.event.*;import java.net.Socket;import java.util.zip.*;class RfbProto { final static String versionMsg_3_3 = "RFB 003.003\n", versionMsg_3_7 = "RFB 003.007\n", versionMsg_3_8 = "RFB 003.008\n"; // Vendor signatures: standard VNC/RealVNC, TridiaVNC, and TightVNC final static String StandardVendor = "STDV", TridiaVncVendor = "TRDV", TightVncVendor = "TGHT"; // Security types final static int SecTypeInvalid = 0, SecTypeNone = 1, SecTypeVncAuth = 2, SecTypeTight = 16; // Supported tunneling types final static int NoTunneling = 0; final static String SigNoTunneling = "NOTUNNEL"; // Supported authentication types final static int AuthNone = 1, AuthVNC = 2, AuthUnixLogin = 129; final static String SigAuthNone = "NOAUTH__", SigAuthVNC = "VNCAUTH_", SigAuthUnixLogin = "ULGNAUTH"; // VNC authentication results final static int VncAuthOK = 0, VncAuthFailed = 1, VncAuthTooMany = 2; // Server-to-client messages final static int FramebufferUpdate = 0, SetColourMapEntries = 1, Bell = 2, ServerCutText = 3; // Client-to-server messages final static int SetPixelFormat = 0, FixColourMapEntries = 1, SetEncodings = 2, FramebufferUpdateRequest = 3, KeyboardEvent = 4, PointerEvent = 5, ClientCutText = 6; // Supported encodings and pseudo-encodings final static int EncodingRaw = 0, EncodingCopyRect = 1, EncodingRRE = 2, EncodingCoRRE = 4, EncodingHextile = 5, EncodingZlib = 6, EncodingTight = 7, EncodingZRLE = 16, EncodingCompressLevel0 = 0xFFFFFF00, EncodingQualityLevel0 = 0xFFFFFFE0, EncodingXCursor = 0xFFFFFF10, EncodingRichCursor = 0xFFFFFF11, EncodingPointerPos = 0xFFFFFF18, EncodingLastRect = 0xFFFFFF20, EncodingNewFBSize = 0xFFFFFF21; final static String SigEncodingRaw = "RAW_____", SigEncodingCopyRect = "COPYRECT", SigEncodingRRE = "RRE_____", SigEncodingCoRRE = "CORRE___", SigEncodingHextile = "HEXTILE_", SigEncodingZlib = "ZLIB____", SigEncodingTight = "TIGHT___", SigEncodingZRLE = "ZRLE____", SigEncodingCompressLevel0 = "COMPRLVL", SigEncodingQualityLevel0 = "JPEGQLVL", SigEncodingXCursor = "X11CURSR", SigEncodingRichCursor = "RCHCURSR", SigEncodingPointerPos = "POINTPOS", SigEncodingLastRect = "LASTRECT", SigEncodingNewFBSize = "NEWFBSIZ"; final static int MaxNormalEncoding = 255; // Contstants used in the Hextile decoder final static int HextileRaw = 1, HextileBackgroundSpecified = 2, HextileForegroundSpecified = 4, HextileAnySubrects = 8, HextileSubrectsColoured = 16; // Contstants used in the Tight decoder final static int TightMinToCompress = 12; final static int TightExplicitFilter = 0x04, TightFill = 0x08, TightJpeg = 0x09, TightMaxSubencoding = 0x09, TightFilterCopy = 0x00, TightFilterPalette = 0x01, TightFilterGradient = 0x02; String host; int port; Socket sock; DataInputStream is; OutputStream os; SessionRecorder rec; boolean inNormalProtocol = false; VncViewer viewer; // Java on UNIX does not call keyPressed() on some keys, for example // swedish keys To prevent our workaround to produce duplicate // keypresses on JVMs that actually works, keep track of if // keyPressed() for a "broken" key was called or not. boolean brokenKeyPressed = false; // This will be set to true on the first framebuffer update // containing Zlib-, ZRLE- or Tight-encoded data. boolean wereZlibUpdates = false; // This will be set to false if the startSession() was called after // we have received at least one Zlib-, ZRLE- or Tight-encoded // framebuffer update. boolean recordFromBeginning = true; // This fields are needed to show warnings about inefficiently saved // sessions only once per each saved session file. boolean zlibWarningShown; boolean tightWarningShown; // Before starting to record each saved session, we set this field // to 0, and increment on each framebuffer update. We don't flush // the SessionRecorder data into the file before the second update. // This allows us to write initial framebuffer update with zero // timestamp, to let the player show initial desktop before // playback. int numUpdatesInSession; // Measuring network throughput. boolean timing; long timeWaitedIn100us; long timedKbits; // Protocol version and TightVNC-specific protocol options. int serverMajor, serverMinor; int clientMajor, clientMinor; boolean protocolTightVNC; CapsContainer tunnelCaps, authCaps; CapsContainer serverMsgCaps, clientMsgCaps; CapsContainer encodingCaps; // If true, informs that the RFB socket was closed. private boolean closed; // // Constructor. Make TCP connection to RFB server. // RfbProto(String h, int p, VncViewer v) throws IOException { viewer = v; host = h; port = p; if (viewer.socketFactory == null) { sock = new Socket(host, port); } else { try { Class factoryClass = Class.forName(viewer.socketFactory); SocketFactory factory = (SocketFactory)factoryClass.newInstance(); if (viewer.inAnApplet) sock = factory.createSocket(host, port, viewer); else sock = factory.createSocket(host, port, viewer.mainArgs); } catch(Exception e) { e.printStackTrace(); throw new IOException(e.getMessage()); } } is = new DataInputStream(new BufferedInputStream(sock.getInputStream(), 16384)); os = sock.getOutputStream(); timing = false; timeWaitedIn100us = 5; timedKbits = 0; } synchronized void close() { try { sock.close(); closed = true; System.out.println("RFB socket closed"); if (rec != null) { rec.close(); rec = null; } } catch (Exception e) { e.printStackTrace(); } } synchronized boolean closed() { return closed; } // // Read server's protocol version message // void readVersionMsg() throws Exception { byte[] b = new byte[12]; readFully(b); if ((b[0] != 'R') || (b[1] != 'F') || (b[2] != 'B') || (b[3] != ' ') || (b[4] < '0') || (b[4] > '9') || (b[5] < '0') || (b[5] > '9') || (b[6] < '0') || (b[6] > '9') || (b[7] != '.') || (b[8] < '0') || (b[8] > '9') || (b[9] < '0') || (b[9] > '9') || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n')) { throw new Exception("Host " + host + " port " + port + " is not an RFB server"); } serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0'); serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0'); if (serverMajor < 3) { throw new Exception("RFB server does not support protocol version 3"); } } // // Write our protocol version message // void writeVersionMsg() throws IOException { clientMajor = 3; if (serverMajor > 3 || serverMinor >= 8) { clientMinor = 8; os.write(versionMsg_3_8.getBytes()); } else if (serverMinor >= 7) { clientMinor = 7; os.write(versionMsg_3_7.getBytes()); } else { clientMinor = 3; os.write(versionMsg_3_3.getBytes()); } protocolTightVNC = false; } // // Negotiate the authentication scheme. // int negotiateSecurity() throws Exception { return (clientMinor >= 7) ? selectSecurityType() : readSecurityType(); } // // Read security type from the server (protocol version 3.3). // int readSecurityType() throws Exception { int secType = is.readInt(); switch (secType) { case SecTypeInvalid: readConnFailedReason(); return SecTypeInvalid; // should never be executed case SecTypeNone: case SecTypeVncAuth: return secType; default: throw new Exception("Unknown security type from RFB server: " + secType); } } // // Select security type from the server's list (protocol versions 3.7/3.8). // int selectSecurityType() throws Exception { int secType = SecTypeInvalid; // Read the list of secutiry types. int nSecTypes = is.readUnsignedByte(); if (nSecTypes == 0) { readConnFailedReason(); return SecTypeInvalid; // should never be executed } byte[] secTypes = new byte[nSecTypes]; readFully(secTypes); // Find out if the server supports TightVNC protocol extensions for (int i = 0; i < nSecTypes; i++) { if (secTypes[i] == SecTypeTight) { protocolTightVNC = true; os.write(SecTypeTight); return SecTypeTight; } } // Find first supported security type. for (int i = 0; i < nSecTypes; i++) { if (secTypes[i] == SecTypeNone || secTypes[i] == SecTypeVncAuth) { secType = secTypes[i]; break; } } if (secType == SecTypeInvalid) { throw new Exception("Server did not offer supported security type"); } else { os.write(secType); } return secType; } // // Perform "no authentication". // void authenticateNone() throws Exception { if (clientMinor >= 8) readSecurityResult("No authentication"); } // // Perform standard VNC Authentication. // void authenticateVNC(String pw) throws Exception { byte[] challenge = new byte[16]; readFully(challenge); if (pw.length() > 8) pw = pw.substring(0, 8); // Truncate to 8 chars // Truncate password on the first zero byte. int firstZero = pw.indexOf(0); if (firstZero != -1) pw = pw.substring(0, firstZero); byte[] key = {0, 0, 0, 0, 0, 0, 0, 0}; System.arraycopy(pw.getBytes(), 0, key, 0, pw.length()); DesCipher des = new DesCipher(key); des.encrypt(challenge, 0, challenge, 0); des.encrypt(challenge, 8, challenge, 8); os.write(challenge); readSecurityResult("VNC authentication"); } // // Read security result. // Throws an exception on authentication failure. // void readSecurityResult(String authType) throws Exception { int securityResult = is.readInt(); switch (securityResult) { case VncAuthOK: System.out.println(authType + ": success"); break; case VncAuthFailed: if (clientMinor >= 8) readConnFailedReason(); throw new Exception(authType + ": failed"); case VncAuthTooMany: throw new Exception(authType + ": failed, too many tries"); default: throw new Exception(authType + ": unknown result " + securityResult); } } // // Read the string describing the reason for a connection failure, // and throw an exception. // void readConnFailedReason() throws Exception {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -