📄 rfbproto.java
字号:
// Copyright (C) 2006 Teamviewer GmbH. All Rights Reserved.
// Copyright (C) 2002-2004 Ultr@VNC Team. All Rights Reserved.
// Copyright (C) 2004 Kenn Min Chong, John Witchel. All Rights Reserved.
// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved.
// Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved.
// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
// Copyright (C) 2003 Helmut Eller <helmut@online-marketwatch.com>
//
// 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
//4/19/04
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.zip.*;
class TunnelReader extends InputStream {
URL url;
InputStream tunnel;
TunnelReader (URL url) throws IOException {
this.url = url;
this.tunnel = connect (url);
}
InputStream getInputStream () throws IOException {
return this;
// return connect (url);
}
private final static void trace (String string) {
// System.err.println ("Reader: " + string);
}
InputStream connect (URL url) throws IOException {
trace ("connect");
URLConnection get = url.openConnection();
get.setDoOutput (false);
get.setDoInput (true);
get.setUseCaches (false);
get.setRequestProperty("X-Agent","DynGate");
get.connect ();
return get.getInputStream ();
}
void reconnect () throws IOException {
tunnel = connect (url);
}
synchronized public int read () throws IOException {
trace ("read");
for (;;) {
int n = tunnel.read ();
if (n >= 0) {
// trace ("read: " + " -> " + n);
return n;
} else
reconnect ();
}
}
synchronized public int read (byte[] bytes) throws IOException {
trace ("read");
for (;;) {
int n = tunnel.read (bytes);
if (n >= 0) {
// trace ("read: " + " -> " + n);
return n;
} else
reconnect ();
}
}
synchronized public int read (byte[] bytes, int offset, int length)
throws IOException {
trace ("read");
for (;;) {
int n = tunnel.read (bytes, offset, length);
if (n >= 0) {
// trace ("read: " + " -> " + n);
return n;
} else
reconnect ();
}
}
public long skip (long n) throws IOException {
trace ("skip ...");
return tunnel.skip (n);
}
synchronized public int available () throws IOException {
trace ("available");
int n = tunnel.available ();
// trace ("available: -> " + n);
return n;
}
public void close () throws IOException {
trace ("Reader close ...");
tunnel.close ();
tunnel = null;
url = null;
}
public void mark (int readlimit) {
trace ("Reader mark ...");
tunnel.mark (readlimit);
}
public void reset () throws IOException {
trace ("Reader reset ...");
tunnel.reset ();
}
public boolean markSupported () {
trace ("markSupported ...");
return tunnel.markSupported ();
}
}
class TunnelWriter extends OutputStream {
URL url;
URLConnection post;
OutputStream out;
TunnelWriter (URL url) throws IOException {
this.url = url;
// connect ();
}
OutputStream getOutputStream () {
return this;
}
private final static void trace (String string) {
// System.err.println ("Writer: " + string);
}
void connect () throws IOException {
trace ("connect");
URLConnection post = url.openConnection();
post.setDoOutput (true);
post.setDoInput (true);
post.setUseCaches (false);
post.setRequestProperty("X-Agent","DynGate");
out = post.getOutputStream ();
this.post = post;
}
void forceOutput () throws IOException {
trace ("flush");
out.flush ();
out.close ();
InputStream in = post.getInputStream ();
// Commented code is for crappy Netscape4.
try {
int b = in.read (); // needed for Explorer
// trace ("read -> 1 [" + b + "]");
// in.close ();
} catch (Exception e) {
// e.printStackTrace ();
// System.err.println (e.getMessage ());
}
}
synchronized public void flush () throws IOException {
forceOutput ();
}
synchronized public void write (int b) throws IOException {
trace ("write");
connect ();
out.write (b);
forceOutput ();
// trace ("write <- 1");
}
synchronized public void write (byte[] b) throws IOException {
trace ("write");
connect ();
out.write (b);
forceOutput ();
// trace ("write <- " + b.length);
}
synchronized public void write (byte[] b, int offset, int length)
throws IOException {
trace ("write");
connect ();
out.write (b, offset, length);
forceOutput ();
// trace ("write <- " + length);
}
public void close () throws IOException {
trace ("close");
flush ();
post = null;
out = null;
}
}
class RfbProto {
final String versionMsg = "RFB 003.003\n";
final static int ConnFailed = 0, NoAuth = 1, VncAuth = 2;
final static int VncAuthOK = 0, VncAuthFailed = 1, VncAuthTooMany = 2;
final static int FramebufferUpdate = 0,
SetColourMapEntries = 1,
Bell = 2,
ServerCutText = 3,
rfbFileTransfer = 7;
final int SetPixelFormat = 0,
FixColourMapEntries = 1,
SetEncodings = 2,
FramebufferUpdateRequest = 3,
KeyboardEvent = 4,
PointerEvent = 5,
ClientCutText = 6;
final static int EncodingRaw = 0,
EncodingCopyRect = 1,
EncodingRRE = 2,
EncodingCoRRE = 4,
EncodingHextile = 5,
EncodingZlib = 6,
EncodingTight = 7,
EncodingCompressLevel0 = 0xFFFFFF00,
EncodingQualityLevel0 = 0xFFFFFFE0,
EncodingXCursor = 0xFFFFFF10,
EncodingRichCursor = 0xFFFFFF11,
EncodingLastRect = 0xFFFFFF20,
EncodingNewFBSize = 0xFFFFFF21;
final int HextileRaw = (1 << 0);
final int HextileBackgroundSpecified = (1 << 1);
final int HextileForegroundSpecified = (1 << 2);
final int HextileAnySubrects = (1 << 3);
final int HextileSubrectsColoured = (1 << 4);
final static int TightExplicitFilter = 0x04;
final static int TightFill = 0x08;
final static int TightJpeg = 0x09;
final static int TightMaxSubencoding = 0x09;
final static int TightFilterCopy = 0x00;
final static int TightFilterPalette = 0x01;
final static int TightFilterGradient = 0x02;
final static int TightMinToCompress = 12;
// sf@2004 - FileTransfer part
ArrayList remoteDirsList;
ArrayList remoteFilesList;
ArrayList a;
boolean fFTInit = true; // sf@2004
boolean fFTAllowed = true;
boolean fAbort = false;
boolean fFileReceptionError = false;
boolean fFileReceptionRunning = false;
boolean inDirectory2;
FileOutputStream fos;
FileInputStream fis;
String sendFileSource;
String receivePath;
long fileSize;
long receiveFileSize;
long fileChunkCounter;
final static int sz_rfbFileTransferMsg = 12,
// FileTransfer Content types and Params defines
rfbDirContentRequest = 1,
// Client asks for the content of a given Server directory
rfbDirPacket = 2, // Full directory name or full file name.
// Null content means end of Directory
rfbFileTransferRequest = 3,
// Client asks the server for the tranfer of a given file
rfbFileHeader = 4,
// First packet of a file transfer, containing file's features
rfbFilePacket = 5, // One slice of the file
rfbEndOfFile = 6,
// End of file transfer (the file has been received or error)
rfbAbortFileTransfer = 7,
// The file transfer must be aborted, whatever the state
rfbFileTransferOffer = 8,
// The client offers to send a file to the server
rfbFileAcceptHeader = 9, // The server accepts or rejects the file
rfbCommand = 10,
// The Client sends a simple command (File Delete, Dir create etc...)
rfbCommandReturn = 11,
// New FT Protocole (V2) The zipped checksums of the destination file (Delta Transfer)
rfbFileChecksums = 12,
// The Client receives the server's answer about a simple command
// rfbDirContentRequest client Request - content params
rfbRDirContent = 1, // Request a Server Directory contents
rfbRDrivesList = 2, // Request the server's drives list
// rfbDirPacket & rfbCommandReturn server Answer - content params
rfbADirectory = 1, // Reception of a directory name
rfbAFile = 2, // Reception of a file name
rfbADrivesList = 3, // Reception of a list of drives
rfbADirCreate = 4, // Response to a create dir command
rfbADirDelete = 5, // Response to a delete dir command
rfbAFileCreate = 6, // Response to a create file command
rfbAFileDelete = 7, // Response to a delete file command
// rfbCommand Command - content params
rfbCDirCreate = 1, // Request the server to create the given directory
rfbCDirDelete = 2, // Request the server to delete the given directory
rfbCFileCreate = 3, // Request the server to create the given file
rfbCFileDelete = 4, // Request the server to delete the given file
// Errors - content params or "size" field
rfbRErrorUnknownCmd = 1, // Unknown FileTransfer command.
rfbRErrorCmd = 0xFFFFFFFF,
// Error when a command fails on remote side (ret in "size" field)
sz_rfbBlockSize = 8192, // new FT protocole (v2)
// Size of a File Transfer packet (before compression)
sz_rfbZipDirectoryPrefix = 9;
String rfbZipDirectoryPrefix = "!UVNCDIR-\0";
// Transfered directory are zipped in a file with this prefix. Must end with "-"
// End of FileTransfer part
String host;
int port;
Socket sock;
DataInputStream is;
OutputStream os;
OutputStreamWriter osw;
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- 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- 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;
int makeSessionIDRequest (URL url) throws IOException {
URLConnection c = url.openConnection();
System.err.println ("UrlConnection.class: "
+ c.getClass ());
c.setDoInput (true);
c.setUseCaches (false);
c.connect ();
InputStream in = c.getInputStream ();
byte[] headdata = new byte[2];
int count = in.read (headdata);
byte[] buffer = new byte[8];
count = in.read (buffer);
System.err.println ("buffer: <<"
+ new String (buffer) + ">>");
if (count != 8)
throw new IOException ("Couldn't read session id.");
int id = (buffer[0] - 48) * 10000000
+ (buffer[1] - 48) * 1000000
+ (buffer[2] - 48) * 100000
+ (buffer[3] - 48) * 10000
+ (buffer[4] - 48) * 1000
+ (buffer[5] - 48) * 100
+ (buffer[6] - 48) * 10
+ (buffer[7] - 48);
System.err.println ("session-id: " + id);
return id;
}
int getSessionID (URL url) throws IOException {
final int OPEN_STATE_PENDING = 1;
final int OPEN_STATE_OK = 2;
final int OPEN_STATE_FAILED = 3;
class Opener extends Thread {
URL url;
int id;
IOException error;
int openState = OPEN_STATE_PENDING;
Opener (URL u) { url = u ;}
public void run () {
synchronized (this) {
try {
id = makeSessionIDRequest (url);
openState = OPEN_STATE_OK;
} catch (IOException e) {
error = e;
openState = OPEN_STATE_FAILED;
}
this.notifyAll ();
}
}
}
Opener o = new Opener (url);
o.start ();
synchronized (o) {
long end = System.currentTimeMillis () + (15 * 1000);
do {
try { o.wait (end - System.currentTimeMillis ()); }
catch (InterruptedException e) {}
} while (o.openState == OPEN_STATE_PENDING
&& ((end - System.currentTimeMillis ()) > 0));
switch (o.openState) {
case OPEN_STATE_PENDING: throw new IOException ("timeout");
case OPEN_STATE_FAILED: throw o.error;
case OPEN_STATE_OK: return o.id;
default: throw new Error ("Bug");
}
}
}
void initHttp (String host, int port, int DynGateID)
throws IOException {
int sid = 0;
try
{
sid = getSessionID (new URL ("http", host, port,"/din.aspx?s=00000000&client=DynGate"));
} catch (IOException e) {
System.err.println ("Tunnel-connection failed: "
+ e.getMessage () + "\n");
throw e;
}
URL wurl = new URL("http", host, port, "/dout.aspx?s=" + sid + "&client=DynGate");
URL rurl = new URL("http", host, port, "/din.aspx?s=" + sid + "&client=DynGate");
os = new TunnelWriter (wurl).getOutputStream();
is = new DataInputStream
(new BufferedInputStream
(new TunnelReader (rurl).getInputStream (),
16384));
}
void initTcp (String host, int port) throws IOException {
sock = new Socket (host, port);
is = new DataInputStream
(new BufferedInputStream (sock.getInputStream (),
16384));
os = sock.getOutputStream ();
}
// Constructor. Make a TCP connection to the RFB server.
RfbProto(String h, int p, VncViewer v) throws IOException {
viewer = v;
host = h;
port = p;
initTcp (h, p);
}
/* Try to establish a direct TCP socket connection to port p. If
that fails, fallback to a HTTP-tunnel to port tunnelPort. p ==
-1 enforces HTTP-tunneling. */
RfbProto(String h, int p, int tunnelPort, int DynGateID, VncViewer v)
throws IOException {
viewer = v;
host = h;
port = p;
if (port == -1)
initHttp (h, tunnelPort, DynGateID);
else
try {
initTcp (h, p);
} catch (Exception e) {
System.err.println ("Socket-connection failed: "
+ e.getMessage () + "\n"
+ "Trying HTTP tunnel...");
initHttp (h, tunnelPort, DynGateID);
}
//Dump DynGate init header
byte[] inbuf = new byte[25];
is.readFully(inbuf);
//Send our connection-request
byte[] auth = new byte[9];
auth[0] = 23;
auth[1] = 36;
auth[2] = 26;
auth[3] = 4;
auth[4] = 0;
auth[5] = (byte)(DynGateID);
auth[6] = (byte)(DynGateID >> 8);
auth[7] = (byte)(DynGateID >> 16);
auth[8] = (byte)(DynGateID >> 24);
os.write(auth);
os.flush();
}
void close() {
try {
if (sock != null)
sock.close();
if (rec != null) {
rec.close();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -