aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/tightvnc/vncviewer/RfbProto.java
diff options
context:
space:
mode:
authorAdam Tkac <atkac@redhat.com>2009-03-13 13:11:51 +0000
committerAdam Tkac <atkac@redhat.com>2009-03-13 13:11:51 +0000
commitd0e84634e0058af86d39f1609dff2089684247d7 (patch)
treec74c060f6cc64f5318f330e70861c2d7ce4e5b6f /java/src/com/tightvnc/vncviewer/RfbProto.java
parentb184fc81d62fab3c2f909e8a15961ec0ca491b99 (diff)
downloadtigervnc-d0e84634e0058af86d39f1609dff2089684247d7.tar.gz
tigervnc-d0e84634e0058af86d39f1609dff2089684247d7.zip
Rename java/src/com/tightvnc to java/src/com/tigervnc.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@3672 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'java/src/com/tightvnc/vncviewer/RfbProto.java')
-rw-r--r--java/src/com/tightvnc/vncviewer/RfbProto.java1497
1 files changed, 0 insertions, 1497 deletions
diff --git a/java/src/com/tightvnc/vncviewer/RfbProto.java b/java/src/com/tightvnc/vncviewer/RfbProto.java
deleted file mode 100644
index d1a94507..00000000
--- a/java/src/com/tightvnc/vncviewer/RfbProto.java
+++ /dev/null
@@ -1,1497 +0,0 @@
-//
-// 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
-//
-
-package com.tightvnc.vncviewer;
-
-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;
-
- // Standard server-to-client messages
- final static int
- FramebufferUpdate = 0,
- SetColourMapEntries = 1,
- Bell = 2,
- ServerCutText = 3;
-
- // Non-standard server-to-client messages
- final static int
- EndOfContinuousUpdates = 150;
- final static String
- SigEndOfContinuousUpdates = "CUS_EOCU";
-
- // Standard client-to-server messages
- final static int
- SetPixelFormat = 0,
- FixColourMapEntries = 1,
- SetEncodings = 2,
- FramebufferUpdateRequest = 3,
- KeyboardEvent = 4,
- PointerEvent = 5,
- ClientCutText = 6;
-
- // Non-standard client-to-server messages
- final static int EnableContinuousUpdates = 150;
- final static int VideoRectangleSelection = 151;
- final static int VideoFreeze = 152;
- final static String SigVideoFreeze = "VD_FREEZ";
- final static String SigEnableContinuousUpdates = "CUC_ENCU";
- final static String SigVideoRectangleSelection = "VRECTSEL";
-
- // 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;
- OutputStream os;
- SessionRecorder rec;
- boolean inNormalProtocol = false;
- VncViewer viewer;
-
- // Input stream is declared private to make sure it can be accessed
- // only via RfbProto methods. We have to do this because we want to
- // count how many bytes were read.
- private DataInputStream is;
- private long numBytesRead = 0;
- public long getNumBytesRead() { return numBytesRead; }
-
- // 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 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;
-
- // "Continuous updates" is a TightVNC-specific feature that allows
- // receiving framebuffer updates continuously, without sending update
- // requests. The variables below track the state of this feature.
- // Initially, continuous updates are disabled. They can be enabled
- // by calling tryEnableContinuousUpdates() method, and only if this
- // feature is supported by the server. To disable continuous updates,
- // tryDisableContinuousUpdates() should be called.
- private boolean continuousUpdatesActive = false;
- private boolean continuousUpdatesEnding = false;
-
- // 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);
- sock.setTcpNoDelay(true);
- } 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;
- initCapabilities();
- }
-
-
- //
- // 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 = readU32();
-
- 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 = readU8();
- 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 = readU32();
-
- 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 {
- int reasonLen = readU32();
- byte[] reason = new byte[reasonLen];
- readFully(reason);
- throw new Exception(new String(reason));
- }
-
- //
- // Initialize capability lists (TightVNC protocol extensions).
- //
-
- void initCapabilities() {
- tunnelCaps = new CapsContainer();
- authCaps = new CapsContainer();
- serverMsgCaps = new CapsContainer();
- clientMsgCaps = new CapsContainer();
- encodingCaps = new CapsContainer();
-
- // Supported authentication methods
- authCaps.add(AuthNone, StandardVendor, SigAuthNone,
- "No authentication");
- authCaps.add(AuthVNC, StandardVendor, SigAuthVNC,
- "Standard VNC password authentication");
-
- // Supported non-standard server-to-client messages
- serverMsgCaps.add(EndOfContinuousUpdates, TightVncVendor,
- SigEndOfContinuousUpdates,
- "End of continuous updates notification");
-
- // Supported non-standard client-to-server messages
- clientMsgCaps.add(EnableContinuousUpdates, TightVncVendor,
- SigEnableContinuousUpdates,
- "Enable/disable continuous updates");
- clientMsgCaps.add(VideoRectangleSelection, TightVncVendor,
- SigVideoRectangleSelection,
- "Select a rectangle to be treated as video");
- clientMsgCaps.add(VideoFreeze, TightVncVendor,
- SigVideoFreeze,
- "Disable/enable video rectangle");
-
- // Supported encoding types
- encodingCaps.add(EncodingCopyRect, StandardVendor,
- SigEncodingCopyRect, "Standard CopyRect encoding");
- encodingCaps.add(EncodingRRE, StandardVendor,
- SigEncodingRRE, "Standard RRE encoding");
- encodingCaps.add(EncodingCoRRE, StandardVendor,
- SigEncodingCoRRE, "Standard CoRRE encoding");
- encodingCaps.add(EncodingHextile, StandardVendor,
- SigEncodingHextile, "Standard Hextile encoding");
- encodingCaps.add(EncodingZRLE, StandardVendor,
- SigEncodingZRLE, "Standard ZRLE encoding");
- encodingCaps.add(EncodingZlib, TridiaVncVendor,
- SigEncodingZlib, "Zlib encoding");
- encodingCaps.add(EncodingTight, TightVncVendor,
- SigEncodingTight, "Tight encoding");
-
- // Supported pseudo-encoding types
- encodingCaps.add(EncodingCompressLevel0, TightVncVendor,
- SigEncodingCompressLevel0, "Compression level");
- encodingCaps.add(EncodingQualityLevel0, TightVncVendor,
- SigEncodingQualityLevel0, "JPEG quality level");
- encodingCaps.add(EncodingXCursor, TightVncVendor,
- SigEncodingXCursor, "X-style cursor shape update");
- encodingCaps.add(EncodingRichCursor, TightVncVendor,
- SigEncodingRichCursor, "Rich-color cursor shape update");
- encodingCaps.add(EncodingPointerPos, TightVncVendor,
- SigEncodingPointerPos, "Pointer position update");
- encodingCaps.add(EncodingLastRect, TightVncVendor,
- SigEncodingLastRect, "LastRect protocol extension");
- encodingCaps.add(EncodingNewFBSize, TightVncVendor,
- SigEncodingNewFBSize, "Framebuffer size change");
- }
-
- //
- // Setup tunneling (TightVNC protocol extensions)
- //
-
- void setupTunneling() throws IOException {
- int nTunnelTypes = readU32();
- if (nTunnelTypes != 0) {
- readCapabilityList(tunnelCaps, nTunnelTypes);
-
- // We don't support tunneling yet.
- writeInt(NoTunneling);
- }
- }
-
- //
- // Negotiate authentication scheme (TightVNC protocol extensions)
- //
-
- int negotiateAuthenticationTight() throws Exception {
- int nAuthTypes = readU32();
- if (nAuthTypes == 0)
- return AuthNone;
-
- readCapabilityList(authCaps, nAuthTypes);
- for (int i = 0; i < authCaps.numEnabled(); i++) {
- int authType = authCaps.getByOrder(i);
- if (authType == AuthNone || authType == AuthVNC) {
- writeInt(authType);
- return authType;
- }
- }
- throw new Exception("No suitable authentication scheme found");
- }
-
- //
- // Read a capability list (TightVNC protocol extensions)
- //
-
- void readCapabilityList(CapsContainer caps, int count) throws IOException {
- int code;
- byte[] vendor = new byte[4];
- byte[] name = new byte[8];
- for (int i = 0; i < count; i++) {
- code = readU32();
- readFully(vendor);
- readFully(name);
- caps.enable(new CapabilityInfo(code, vendor, name));
- }
- }
-
- //
- // Write a 32-bit integer into the output stream.
- //
-
- void writeInt(int value) throws IOException {
- byte[] b = new byte[4];
- b[0] = (byte) ((value >> 24) & 0xff);
- b[1] = (byte) ((value >> 16) & 0xff);
- b[2] = (byte) ((value >> 8) & 0xff);
- b[3] = (byte) (value & 0xff);
- os.write(b);
- }
-
- //
- // Write the client initialisation message
- //
-
- void writeClientInit() throws IOException {
- if (viewer.options.shareDesktop) {
- os.write(1);
- } else {
- os.write(0);
- }
- viewer.options.disableShareDesktop();
- }
-
-
- //
- // Read the server initialisation message
- //
-
- String desktopName;
- int framebufferWidth, framebufferHeight;
- int bitsPerPixel, depth;
- boolean bigEndian, trueColour;
- int redMax, greenMax, blueMax, redShift, greenShift, blueShift;
-
- void readServerInit() throws IOException {
- framebufferWidth = readU16();
- framebufferHeight = readU16();
- bitsPerPixel = readU8();
- depth = readU8();
- bigEndian = (readU8() != 0);
- trueColour = (readU8() != 0);
- redMax = readU16();
- greenMax = readU16();
- blueMax = readU16();
- redShift = readU8();
- greenShift = readU8();
- blueShift = readU8();
- byte[] pad = new byte[3];
- readFully(pad);
- int nameLength = readU32();
- byte[] name = new byte[nameLength];
- readFully(name);
- desktopName = new String(name);
-
- // Read interaction capabilities (TightVNC protocol extensions)
- if (protocolTightVNC) {
- int nServerMessageTypes = readU16();
- int nClientMessageTypes = readU16();
- int nEncodingTypes = readU16();
- readU16();
- readCapabilityList(serverMsgCaps, nServerMessageTypes);
- readCapabilityList(clientMsgCaps, nClientMessageTypes);
- readCapabilityList(encodingCaps, nEncodingTypes);
- }
-
- if (!clientMsgCaps.isEnabled(EnableContinuousUpdates)) {
- viewer.options.disableContUpdates();
- }
-
- inNormalProtocol = true;
- }
-
-
- //
- // Create session file and write initial protocol messages into it.
- //
-
- void startSession(String fname) throws IOException {
- rec = new SessionRecorder(fname);
- rec.writeHeader();
- rec.write(versionMsg_3_3.getBytes());
- rec.writeIntBE(SecTypeNone);
- rec.writeShortBE(framebufferWidth);
- rec.writeShortBE(framebufferHeight);
- byte[] fbsServerInitMsg = {
- 32, 24, 0, 1, 0,
- (byte)0xFF, 0, (byte)0xFF, 0, (byte)0xFF,
- 16, 8, 0, 0, 0, 0
- };
- rec.write(fbsServerInitMsg);
- rec.writeIntBE(desktopName.length());
- rec.write(desktopName.getBytes());
- numUpdatesInSession = 0;
-
- // FIXME: If there were e.g. ZRLE updates only, that should not
- // affect recording of Zlib and Tight updates. So, actually
- // we should maintain separate flags for Zlib, ZRLE and
- // Tight, instead of one ``wereZlibUpdates'' variable.
- //
-
- zlibWarningShown = false;
- tightWarningShown = false;
- }
-
- //
- // Close session file.
- //
-
- void closeSession() throws IOException {
- if (rec != null) {
- rec.close();
- rec = null;
- }
- }
-
-
- //
- // Set new framebuffer size
- //
-
- void setFramebufferSize(int width, int height) {
- framebufferWidth = width;
- framebufferHeight = height;
- }
-
-
- //
- // Read the server message type
- //
-
- int readServerMessageType() throws IOException {
- int msgType = readU8();
-
- // If the session is being recorded:
- if (rec != null) {
- if (msgType == Bell) { // Save Bell messages in session files.
- rec.writeByte(msgType);
- if (numUpdatesInSession > 0)
- rec.flush();
- }
- }
-
- return msgType;
- }
-
-
- //
- // Read a FramebufferUpdate message
- //
-
- int updateNRects;
-
- void readFramebufferUpdate() throws IOException {
- skipBytes(1);
- updateNRects = readU16();
-
- // If the session is being recorded:
- if (rec != null) {
- rec.writeByte(FramebufferUpdate);
- rec.writeByte(0);
- rec.writeShortBE(updateNRects);
- }
-
- numUpdatesInSession++;
- }
-
- //
- // Returns true if encoding is not pseudo
- //
- // FIXME: Find better way to differ pseudo and real encodings
- //
-
- boolean isRealDecoderEncoding(int encoding) {
- if ((encoding >= 1) && (encoding <= 16)) {
- return true;
- }
- return false;
- }
-
- // Read a FramebufferUpdate rectangle header
-
- int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding;
-
- void readFramebufferUpdateRectHdr() throws Exception {
- updateRectX = readU16();
- updateRectY = readU16();
- updateRectW = readU16();
- updateRectH = readU16();
- updateRectEncoding = readU32();
-
- if (updateRectEncoding == EncodingZlib ||
- updateRectEncoding == EncodingZRLE ||
- updateRectEncoding == EncodingTight)
- wereZlibUpdates = true;
-
- // If the session is being recorded:
- if (rec != null) {
- if (numUpdatesInSession > 1)
- rec.flush(); // Flush the output on each rectangle.
- rec.writeShortBE(updateRectX);
- rec.writeShortBE(updateRectY);
- rec.writeShortBE(updateRectW);
- rec.writeShortBE(updateRectH);
-
- //
- // If this is pseudo encoding or CopyRect that write encoding ID
- // in this place. All real encoding ID will be written to record stream
- // in decoder classes.
-
- if (((!isRealDecoderEncoding(updateRectEncoding))) && (rec != null)) {
- rec.writeIntBE(updateRectEncoding);
- }
- }
-
- if (updateRectEncoding < 0 || updateRectEncoding > MaxNormalEncoding)
- return;
-
- if (updateRectX + updateRectW > framebufferWidth ||
- updateRectY + updateRectH > framebufferHeight) {
- throw new Exception("Framebuffer update rectangle too large: " +
- updateRectW + "x" + updateRectH + " at (" +
- updateRectX + "," + updateRectY + ")");
- }
- }
-
- //
- // Read a ServerCutText message
- //
-
- String readServerCutText() throws IOException {
- skipBytes(3);
- int len = readU32();
- byte[] text = new byte[len];
- readFully(text);
- return new String(text);
- }
-
-
- //
- // Read an integer in compact representation (1..3 bytes).
- // Such format is used as a part of the Tight encoding.
- // Also, this method records data if session recording is active and
- // the viewer's recordFromBeginning variable is set to true.
- //
-
- int readCompactLen() throws IOException {
- int[] portion = new int[3];
- portion[0] = readU8();
- int byteCount = 1;
- int len = portion[0] & 0x7F;
- if ((portion[0] & 0x80) != 0) {
- portion[1] = readU8();
- byteCount++;
- len |= (portion[1] & 0x7F) << 7;
- if ((portion[1] & 0x80) != 0) {
- portion[2] = readU8();
- byteCount++;
- len |= (portion[2] & 0xFF) << 14;
- }
- }
-
- return len;
- }
-
-
- //
- // Write a FramebufferUpdateRequest message
- //
-
- void writeFramebufferUpdateRequest(int x, int y, int w, int h,
- boolean incremental)
- throws IOException
- {
- byte[] b = new byte[10];
-
- b[0] = (byte) FramebufferUpdateRequest;
- b[1] = (byte) (incremental ? 1 : 0);
- b[2] = (byte) ((x >> 8) & 0xff);
- b[3] = (byte) (x & 0xff);
- b[4] = (byte) ((y >> 8) & 0xff);
- b[5] = (byte) (y & 0xff);
- b[6] = (byte) ((w >> 8) & 0xff);
- b[7] = (byte) (w & 0xff);
- b[8] = (byte) ((h >> 8) & 0xff);
- b[9] = (byte) (h & 0xff);
-
- os.write(b);
- }
-
-
- //
- // Write a SetPixelFormat message
- //
-
- void writeSetPixelFormat(int bitsPerPixel, int depth, boolean bigEndian,
- boolean trueColour,
- int redMax, int greenMax, int blueMax,
- int redShift, int greenShift, int blueShift)
- throws IOException
- {
- byte[] b = new byte[20];
-
- b[0] = (byte) SetPixelFormat;
- b[4] = (byte) bitsPerPixel;
- b[5] = (byte) depth;
- b[6] = (byte) (bigEndian ? 1 : 0);
- b[7] = (byte) (trueColour ? 1 : 0);
- b[8] = (byte) ((redMax >> 8) & 0xff);
- b[9] = (byte) (redMax & 0xff);
- b[10] = (byte) ((greenMax >> 8) & 0xff);
- b[11] = (byte) (greenMax & 0xff);
- b[12] = (byte) ((blueMax >> 8) & 0xff);
- b[13] = (byte) (blueMax & 0xff);
- b[14] = (byte) redShift;
- b[15] = (byte) greenShift;
- b[16] = (byte) blueShift;
-
- os.write(b);
- }
-
-
- //
- // Write a FixColourMapEntries message. The values in the red, green and
- // blue arrays are from 0 to 65535.
- //
-
- void writeFixColourMapEntries(int firstColour, int nColours,
- int[] red, int[] green, int[] blue)
- throws IOException
- {
- byte[] b = new byte[6 + nColours * 6];
-
- b[0] = (byte) FixColourMapEntries;
- b[2] = (byte) ((firstColour >> 8) & 0xff);
- b[3] = (byte) (firstColour & 0xff);
- b[4] = (byte) ((nColours >> 8) & 0xff);
- b[5] = (byte) (nColours & 0xff);
-
- for (int i = 0; i < nColours; i++) {
- b[6 + i * 6] = (byte) ((red[i] >> 8) & 0xff);
- b[6 + i * 6 + 1] = (byte) (red[i] & 0xff);
- b[6 + i * 6 + 2] = (byte) ((green[i] >> 8) & 0xff);
- b[6 + i * 6 + 3] = (byte) (green[i] & 0xff);
- b[6 + i * 6 + 4] = (byte) ((blue[i] >> 8) & 0xff);
- b[6 + i * 6 + 5] = (byte) (blue[i] & 0xff);
- }
-
- os.write(b);
- }
-
-
- //
- // Write a SetEncodings message
- //
-
- void writeSetEncodings(int[] encs, int len) throws IOException {
- byte[] b = new byte[4 + 4 * len];
-
- b[0] = (byte) SetEncodings;
- b[2] = (byte) ((len >> 8) & 0xff);
- b[3] = (byte) (len & 0xff);
-
- for (int i = 0; i < len; i++) {
- b[4 + 4 * i] = (byte) ((encs[i] >> 24) & 0xff);
- b[5 + 4 * i] = (byte) ((encs[i] >> 16) & 0xff);
- b[6 + 4 * i] = (byte) ((encs[i] >> 8) & 0xff);
- b[7 + 4 * i] = (byte) (encs[i] & 0xff);
- }
-
- os.write(b);
- }
-
-
- //
- // Write a ClientCutText message
- //
-
- void writeClientCutText(String text) throws IOException {
- byte[] b = new byte[8 + text.length()];
-
- b[0] = (byte) ClientCutText;
- b[4] = (byte) ((text.length() >> 24) & 0xff);
- b[5] = (byte) ((text.length() >> 16) & 0xff);
- b[6] = (byte) ((text.length() >> 8) & 0xff);
- b[7] = (byte) (text.length() & 0xff);
-
- System.arraycopy(text.getBytes(), 0, b, 8, text.length());
-
- os.write(b);
- }
-
-
- //
- // A buffer for putting pointer and keyboard events before being sent. This
- // is to ensure that multiple RFB events generated from a single Java Event
- // will all be sent in a single network packet. The maximum possible
- // length is 4 modifier down events, a single key event followed by 4
- // modifier up events i.e. 9 key events or 72 bytes.
- //
-
- byte[] eventBuf = new byte[72];
- int eventBufLen;
-
-
- // Useful shortcuts for modifier masks.
-
- final static int CTRL_MASK = InputEvent.CTRL_MASK;
- final static int SHIFT_MASK = InputEvent.SHIFT_MASK;
- final static int META_MASK = InputEvent.META_MASK;
- final static int ALT_MASK = InputEvent.ALT_MASK;
-
-
- //
- // Write a pointer event message. We may need to send modifier key events
- // around it to set the correct modifier state.
- //
-
- int pointerMask = 0;
-
- void writePointerEvent(MouseEvent evt) throws IOException {
- int modifiers = evt.getModifiers();
-
- int mask2 = 2;
- int mask3 = 4;
- if (viewer.options.reverseMouseButtons2And3) {
- mask2 = 4;
- mask3 = 2;
- }
-
- // Note: For some reason, AWT does not set BUTTON1_MASK on left
- // button presses. Here we think that it was the left button if
- // modifiers do not include BUTTON2_MASK or BUTTON3_MASK.
-
- if (evt.getID() == MouseEvent.MOUSE_PRESSED) {
- if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
- pointerMask = mask2;
- modifiers &= ~ALT_MASK;
- } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
- pointerMask = mask3;
- modifiers &= ~META_MASK;
- } else {
- pointerMask = 1;
- }
- } else if (evt.getID() == MouseEvent.MOUSE_RELEASED) {
- pointerMask = 0;
- if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
- modifiers &= ~ALT_MASK;
- } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
- modifiers &= ~META_MASK;
- }
- }
-
- eventBufLen = 0;
- writeModifierKeyEvents(modifiers);
-
- int x = evt.getX();
- int y = evt.getY();
-
- if (x < 0) x = 0;
- if (y < 0) y = 0;
-
- eventBuf[eventBufLen++] = (byte) PointerEvent;
- eventBuf[eventBufLen++] = (byte) pointerMask;
- eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff);
- eventBuf[eventBufLen++] = (byte) (x & 0xff);
- eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff);
- eventBuf[eventBufLen++] = (byte) (y & 0xff);
-
- //
- // Always release all modifiers after an "up" event
- //
-
- if (pointerMask == 0) {
- writeModifierKeyEvents(0);
- }
-
- os.write(eventBuf, 0, eventBufLen);
- }
-
-
- //
- // Write a key event message. We may need to send modifier key events
- // around it to set the correct modifier state. Also we need to translate
- // from the Java key values to the X keysym values used by the RFB protocol.
- //
-
- void writeKeyEvent(KeyEvent evt) throws IOException {
-
- int keyChar = evt.getKeyChar();
-
- //
- // Ignore event if only modifiers were pressed.
- //
-
- // Some JVMs return 0 instead of CHAR_UNDEFINED in getKeyChar().
- if (keyChar == 0)
- keyChar = KeyEvent.CHAR_UNDEFINED;
-
- if (keyChar == KeyEvent.CHAR_UNDEFINED) {
- int code = evt.getKeyCode();
- if (code == KeyEvent.VK_CONTROL || code == KeyEvent.VK_SHIFT ||
- code == KeyEvent.VK_META || code == KeyEvent.VK_ALT)
- return;
- }
-
- //
- // Key press or key release?
- //
-
- boolean down = (evt.getID() == KeyEvent.KEY_PRESSED);
-
- int key;
- if (evt.isActionKey()) {
-
- //
- // An action key should be one of the following.
- // If not then just ignore the event.
- //
-
- switch(evt.getKeyCode()) {
- case KeyEvent.VK_HOME: key = 0xff50; break;
- case KeyEvent.VK_LEFT: key = 0xff51; break;
- case KeyEvent.VK_UP: key = 0xff52; break;
- case KeyEvent.VK_RIGHT: key = 0xff53; break;
- case KeyEvent.VK_DOWN: key = 0xff54; break;
- case KeyEvent.VK_PAGE_UP: key = 0xff55; break;
- case KeyEvent.VK_PAGE_DOWN: key = 0xff56; break;
- case KeyEvent.VK_END: key = 0xff57; break;
- case KeyEvent.VK_INSERT: key = 0xff63; break;
- case KeyEvent.VK_F1: key = 0xffbe; break;
- case KeyEvent.VK_F2: key = 0xffbf; break;
- case KeyEvent.VK_F3: key = 0xffc0; break;
- case KeyEvent.VK_F4: key = 0xffc1; break;
- case KeyEvent.VK_F5: key = 0xffc2; break;
- case KeyEvent.VK_F6: key = 0xffc3; break;
- case KeyEvent.VK_F7: key = 0xffc4; break;
- case KeyEvent.VK_F8: key = 0xffc5; break;
- case KeyEvent.VK_F9: key = 0xffc6; break;
- case KeyEvent.VK_F10: key = 0xffc7; break;
- case KeyEvent.VK_F11: key = 0xffc8; break;
- case KeyEvent.VK_F12: key = 0xffc9; break;
- default:
- return;
- }
-
- } else {
-
- //
- // A "normal" key press. Ordinary ASCII characters go straight through.
- // For CTRL-<letter>, CTRL is sent separately so just send <letter>.
- // Backspace, tab, return, escape and delete have special keysyms.
- // Anything else we ignore.
- //
-
- key = keyChar;
-
- if (key < 0x20) {
- if (evt.isControlDown()) {
- key += 0x60;
- } else {
- switch(key) {
- case KeyEvent.VK_BACK_SPACE: key = 0xff08; break;
- case KeyEvent.VK_TAB: key = 0xff09; break;
- case KeyEvent.VK_ENTER: key = 0xff0d; break;
- case KeyEvent.VK_ESCAPE: key = 0xff1b; break;
- }
- }
- } else if (key == 0x7f) {
- // Delete
- key = 0xffff;
- } else if (key > 0xff) {
- // JDK1.1 on X incorrectly passes some keysyms straight through,
- // so we do too. JDK1.1.4 seems to have fixed this.
- // The keysyms passed are 0xff00 .. XK_BackSpace .. XK_Delete
- // Also, we pass through foreign currency keysyms (0x20a0..0x20af).
- if ((key < 0xff00 || key > 0xffff) &&
- !(key >= 0x20a0 && key <= 0x20af))
- return;
- }
- }
-
- // Fake keyPresses for keys that only generates keyRelease events
- if ((key == 0xe5) || (key == 0xc5) || // XK_aring / XK_Aring
- (key == 0xe4) || (key == 0xc4) || // XK_adiaeresis / XK_Adiaeresis
- (key == 0xf6) || (key == 0xd6) || // XK_odiaeresis / XK_Odiaeresis
- (key == 0xa7) || (key == 0xbd) || // XK_section / XK_onehalf
- (key == 0xa3)) { // XK_sterling
- // Make sure we do not send keypress events twice on platforms
- // with correct JVMs (those that actually report KeyPress for all
- // keys)
- if (down)
- brokenKeyPressed = true;
-
- if (!down && !brokenKeyPressed) {
- // We've got a release event for this key, but haven't received
- // a press. Fake it.
- eventBufLen = 0;
- writeModifierKeyEvents(evt.getModifiers());
- writeKeyEvent(key, true);
- os.write(eventBuf, 0, eventBufLen);
- }
-
- if (!down)
- brokenKeyPressed = false;
- }
-
- eventBufLen = 0;
- writeModifierKeyEvents(evt.getModifiers());
- writeKeyEvent(key, down);
-
- // Always release all modifiers after an "up" event
- if (!down)
- writeModifierKeyEvents(0);
-
- os.write(eventBuf, 0, eventBufLen);
- }
-
-
- //
- // Add a raw key event with the given X keysym to eventBuf.
- //
-
- void writeKeyEvent(int keysym, boolean down) {
- eventBuf[eventBufLen++] = (byte) KeyboardEvent;
- eventBuf[eventBufLen++] = (byte) (down ? 1 : 0);
- eventBuf[eventBufLen++] = (byte) 0;
- eventBuf[eventBufLen++] = (byte) 0;
- eventBuf[eventBufLen++] = (byte) ((keysym >> 24) & 0xff);
- eventBuf[eventBufLen++] = (byte) ((keysym >> 16) & 0xff);
- eventBuf[eventBufLen++] = (byte) ((keysym >> 8) & 0xff);
- eventBuf[eventBufLen++] = (byte) (keysym & 0xff);
- }
-
-
- //
- // Write key events to set the correct modifier state.
- //
-
- int oldModifiers = 0;
-
- void writeModifierKeyEvents(int newModifiers) {
- if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK))
- writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0);
-
- if ((newModifiers & SHIFT_MASK) != (oldModifiers & SHIFT_MASK))
- writeKeyEvent(0xffe1, (newModifiers & SHIFT_MASK) != 0);
-
- if ((newModifiers & META_MASK) != (oldModifiers & META_MASK))
- writeKeyEvent(0xffe7, (newModifiers & META_MASK) != 0);
-
- if ((newModifiers & ALT_MASK) != (oldModifiers & ALT_MASK))
- writeKeyEvent(0xffe9, (newModifiers & ALT_MASK) != 0);
-
- oldModifiers = newModifiers;
- }
-
-
- //
- // Enable continuous updates for the specified area of the screen (but
- // only if EnableContinuousUpdates message is supported by the server).
- //
-
- void tryEnableContinuousUpdates(int x, int y, int w, int h)
- throws IOException
- {
- if (!clientMsgCaps.isEnabled(EnableContinuousUpdates)) {
- System.out.println("Continuous updates not supported by the server");
- return;
- }
-
- if (continuousUpdatesActive) {
- System.out.println("Continuous updates already active");
- return;
- }
-
- byte[] b = new byte[10];
-
- b[0] = (byte) EnableContinuousUpdates;
- b[1] = (byte) 1; // enable
- b[2] = (byte) ((x >> 8) & 0xff);
- b[3] = (byte) (x & 0xff);
- b[4] = (byte) ((y >> 8) & 0xff);
- b[5] = (byte) (y & 0xff);
- b[6] = (byte) ((w >> 8) & 0xff);
- b[7] = (byte) (w & 0xff);
- b[8] = (byte) ((h >> 8) & 0xff);
- b[9] = (byte) (h & 0xff);
-
- os.write(b);
-
- continuousUpdatesActive = true;
- System.out.println("Continuous updates activated");
- }
-
-
- //
- // Disable continuous updates (only if EnableContinuousUpdates message
- // is supported by the server).
- //
-
- void tryDisableContinuousUpdates() throws IOException
- {
- if (!clientMsgCaps.isEnabled(EnableContinuousUpdates)) {
- System.out.println("Continuous updates not supported by the server");
- return;
- }
-
- if (!continuousUpdatesActive) {
- System.out.println("Continuous updates already disabled");
- return;
- }
-
- if (continuousUpdatesEnding)
- return;
-
- byte[] b = { (byte)EnableContinuousUpdates, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- os.write(b);
-
- if (!serverMsgCaps.isEnabled(EndOfContinuousUpdates)) {
- // If the server did not advertise support for the
- // EndOfContinuousUpdates message (should not normally happen
- // when EnableContinuousUpdates is supported), then we clear
- // 'continuousUpdatesActive' variable immediately. Normally,
- // it will be reset on receiving EndOfContinuousUpdates message
- // from the server.
- continuousUpdatesActive = false;
- } else {
- // Indicate that we are waiting for EndOfContinuousUpdates.
- continuousUpdatesEnding = true;
- }
- }
-
-
- //
- // Process EndOfContinuousUpdates message received from the server.
- //
-
- void endOfContinuousUpdates()
- {
- continuousUpdatesActive = false;
- continuousUpdatesEnding = false;
- }
-
-
- //
- // Check if continuous updates are in effect.
- //
-
- boolean continuousUpdatesAreActive()
- {
- return continuousUpdatesActive;
- }
-
- /**
- * Send a rectangle selection to be treated as video by the server (but
- * only if VideoRectangleSelection message is supported by the server).
- * @param rect specifies coordinates and size of the rectangule.
- * @throws java.io.IOException
- */
- void trySendVideoSelection(Rectangle rect) throws IOException
- {
- if (!clientMsgCaps.isEnabled(VideoRectangleSelection)) {
- System.out.println("Video area selection is not supported by the server");
- return;
- }
-
- // Send zero coordinates if the rectangle is empty.
- if (rect.isEmpty()) {
- rect = new Rectangle();
- }
-
- int x = rect.x;
- int y = rect.y;
- int w = rect.width;
- int h = rect.height;
-
- byte[] b = new byte[10];
-
- b[0] = (byte) VideoRectangleSelection;
- b[1] = (byte) 0; // reserved
- b[2] = (byte) ((x >> 8) & 0xff);
- b[3] = (byte) (x & 0xff);
- b[4] = (byte) ((y >> 8) & 0xff);
- b[5] = (byte) (y & 0xff);
- b[6] = (byte) ((w >> 8) & 0xff);
- b[7] = (byte) (w & 0xff);
- b[8] = (byte) ((h >> 8) & 0xff);
- b[9] = (byte) (h & 0xff);
-
- os.write(b);
-
- System.out.println("Video rectangle selection message sent");
- }
-
- void trySendVideoFreeze(boolean freeze) throws IOException
- {
- if (!clientMsgCaps.isEnabled(VideoFreeze)) {
- System.out.println("Video freeze is not supported by the server");
- return;
- }
-
- byte[] b = new byte[2];
- byte fb = 0;
- if (freeze) {
- fb = 1;
- }
-
- b[0] = (byte) VideoFreeze;
- b[1] = (byte) fb;
-
- os.write(b);
-
- System.out.println("Video freeze selection message sent");
- }
-
- public void startTiming() {
- timing = true;
-
- // Carry over up to 1s worth of previous rate for smoothing.
-
- if (timeWaitedIn100us > 10000) {
- timedKbits = timedKbits * 10000 / timeWaitedIn100us;
- timeWaitedIn100us = 10000;
- }
- }
-
- public void stopTiming() {
- timing = false;
- if (timeWaitedIn100us < timedKbits/2)
- timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s
- }
-
- public long kbitsPerSecond() {
- return timedKbits * 10000 / timeWaitedIn100us;
- }
-
- public long timeWaited() {
- return timeWaitedIn100us;
- }
-
- //
- // Methods for reading data via our DataInputStream member variable (is).
- //
- // In addition to reading data, the readFully() methods updates variables
- // used to estimate data throughput.
- //
-
- public void readFully(byte b[]) throws IOException {
- readFully(b, 0, b.length);
- }
-
- public void readFully(byte b[], int off, int len) throws IOException {
- long before = 0;
- if (timing)
- before = System.currentTimeMillis();
-
- is.readFully(b, off, len);
-
- if (timing) {
- long after = System.currentTimeMillis();
- long newTimeWaited = (after - before) * 10;
- int newKbits = len * 8 / 1000;
-
- // limit rate to between 10kbit/s and 40Mbit/s
-
- if (newTimeWaited > newKbits*1000) newTimeWaited = newKbits*1000;
- if (newTimeWaited < newKbits/4) newTimeWaited = newKbits/4;
-
- timeWaitedIn100us += newTimeWaited;
- timedKbits += newKbits;
- }
-
- numBytesRead += len;
- }
-
- final int available() throws IOException {
- return is.available();
- }
-
- // FIXME: DataInputStream::skipBytes() is not guaranteed to skip
- // exactly n bytes. Probably we don't want to use this method.
- final int skipBytes(int n) throws IOException {
- int r = is.skipBytes(n);
- numBytesRead += r;
- return r;
- }
-
- final int readU8() throws IOException {
- int r = is.readUnsignedByte();
- numBytesRead++;
- return r;
- }
-
- final int readU16() throws IOException {
- int r = is.readUnsignedShort();
- numBytesRead += 2;
- return r;
- }
-
- final int readU32() throws IOException {
- int r = is.readInt();
- numBytesRead += 4;
- return r;
- }
-}