changeset 29:750ecaa1e1b9

add echoClient.java and waitreply.java. modify MyRfbProto.java
author e085711
date Wed, 06 Jul 2011 11:56:15 +0900
parents 68f0bc9c4211
children a335a1038a23
files RfbProto.java src/myVncClient/MyVncClient.java src/myVncClient/VncViewer.java src/myVncClient/echoClient.java src/myVncClient/waitreply.java
diffstat 5 files changed, 1647 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RfbProto.java	Wed Jul 06 11:56:15 2011 +0900
@@ -0,0 +1,1379 @@
+package myVncClient;
+//
+//  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.net.ServerSocket;
+import java.util.zip.*;
+import java.nio.*;
+
+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 String SigEnableContinuousUpdates = "CUC_ENCU";
+
+	// 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;
+	protected DataInputStream is;
+//	private long numBytesRead = 0;
+	protected 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 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;
+	protected 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;
+	}
+	
+	RfbProto(String h, int p) throws IOException {
+		host = h;
+		port = p;
+
+		sock = new Socket(host, port);
+		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
+		// [NONE]
+
+		// Supported non-standard client-to-server messages
+		// [NONE]
+
+		// 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);
+*/
+			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);
+		}
+
+		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.
+		//
+		if (wereZlibUpdates)
+			recordFromBeginning = false;
+
+		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++;
+	}
+
+	// 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();
+		// System.out.println("readU16&32");
+
+		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 (updateRectEncoding == EncodingZlib && !recordFromBeginning) {
+				// Here we cannot write Zlib-encoded rectangles because the
+				// decoder won't be able to reproduce zlib stream state.
+				if (!zlibWarningShown) {
+					System.out.println("Warning: Raw encoding will be used "
+							+ "instead of Zlib in recorded session.");
+					zlibWarningShown = true;
+				}
+				rec.writeIntBE(EncodingRaw);
+			} else {
+				rec.writeIntBE(updateRectEncoding);
+				if (updateRectEncoding == EncodingTight && !recordFromBeginning
+						&& !tightWarningShown) {
+					System.out.println("Warning: Re-compressing Tight-encoded "
+							+ "updates for session recording.");
+					tightWarningShown = true;
+				}
+			}
+		}
+
+		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 CopyRect source X and Y.
+
+	int copyRectSrcX, copyRectSrcY;
+
+	void readCopyRect() throws IOException {
+		copyRectSrcX = readU16();
+		copyRectSrcY = readU16();
+
+		// If the session is being recorded:
+		if (rec != null) {
+			rec.writeShortBE(copyRectSrcX);
+			rec.writeShortBE(copyRectSrcY);
+		}
+	}
+
+	//
+	// 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;
+			}
+		}
+
+		if (rec != null && recordFromBeginning)
+			for (int i = 0; i < byteCount; i++)
+				rec.writeByte(portion[i]);
+
+		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;
+	}
+
+	//
+	// Compress and write the data into the recorded session file. This
+	// method assumes the recording is on (rec != null).
+	//
+
+	void recordCompressedData(byte[] data, int off, int len) throws IOException {
+		Deflater deflater = new Deflater();
+		deflater.setInput(data, off, len);
+		int bufSize = len + len / 100 + 12;
+		byte[] buf = new byte[bufSize];
+		deflater.finish();
+		int compressedSize = deflater.deflate(buf);
+		recordCompactLen(compressedSize);
+		rec.write(buf, 0, compressedSize);
+	}
+
+	void recordCompressedData(byte[] data) throws IOException {
+		recordCompressedData(data, 0, data.length);
+	}
+
+	//
+	// Write an integer in compact representation (1..3 bytes) into the
+	// recorded session file. This method assumes the recording is on
+	// (rec != null).
+	//
+
+	void recordCompactLen(int len) throws IOException {
+		byte[] buf = new byte[3];
+		int bytes = 0;
+		buf[bytes++] = (byte) (len & 0x7F);
+		if (len > 0x7F) {
+			buf[bytes - 1] |= 0x80;
+			buf[bytes++] = (byte) (len >> 7 & 0x7F);
+			if (len > 0x3FFF) {
+				buf[bytes - 1] |= 0x80;
+				buf[bytes++] = (byte) (len >> 14 & 0xFF);
+			}
+		}
+		rec.write(buf, 0, bytes);
+	}
+
+	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;
+	}
+
+}
--- a/src/myVncClient/MyVncClient.java	Wed Jul 06 11:31:30 2011 +0900
+++ b/src/myVncClient/MyVncClient.java	Wed Jul 06 11:56:15 2011 +0900
@@ -174,6 +174,12 @@
 			fatalError("Network error: could not connect to server: " + host
 					+ ":" + port, e);
 		} catch (EOFException e) {
+
+		    //insert
+		    echo = new echoClient();
+		    echo.openport();
+		    echo.losthost();
+
 			if (showOfflineDesktop) {
 				e.printStackTrace();
 				System.out
@@ -637,22 +643,20 @@
 	//
 
 	void readParameters() {
-//		host = readParameter("HOST", !inAnApplet);
-		if (mainArgs.length > 0)
-			host = mainArgs[0];
-		else
-			host = "hades.cr.ie.u-ryukyu.ac.jp";
-		/*
-		 * if (host == null) { host = getCodeBase().getHost(); if
-		 * (host.equals("")) { fatalError("HOST parameter not specified"); } }
-		 */
+	    if (mainArgs.length > 0){
+		host = mainArgs[0];
+		echo = new echoClient(host);
+	    }else{
+		host = "cls080.ie.u-ryukyu.ac.jp";
+		echo = new echoClient();
+	    }
 
-//		port = readIntParameter("PORT", 5550);
+
 		if (mainArgs.length > 1)
 			port = Integer.parseInt(mainArgs[1]);
 		else
 			port = 5550;
-		// Read "ENCPASSWORD" or "PASSWORD" parameter if specified.
+
 		readPasswordParameters();
 
 		String str;
--- a/src/myVncClient/VncViewer.java	Wed Jul 06 11:31:30 2011 +0900
+++ b/src/myVncClient/VncViewer.java	Wed Jul 06 11:56:15 2011 +0900
@@ -31,7 +31,7 @@
 	MyRfbProto rfb;
 	Thread rfbThread;
 	Thread accThread;
-	
+    echoClient echo;
 
 	Frame vncFrame;
 	Container vncContainer;
@@ -206,6 +206,8 @@
 			fatalError("Network error: could not connect to server: " + host
 					+ ":" + port, e);
 		} catch (EOFException e) {
+		    
+
 			if (showOfflineDesktop) {
 				e.printStackTrace();
 				System.out
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/myVncClient/echoClient.java	Wed Jul 06 11:56:15 2011 +0900
@@ -0,0 +1,217 @@
+package myVncClient;
+
+import java.io.*;
+import java.net.*;
+
+
+public class echoClient {
+    Revalue value = new Revalue();
+	waitreply wr;// = new waitreply();
+    String responseLine,treenum,parent,line;
+    Socket echoSocket = null;
+    BufferedReader lostis = null;
+    DataOutputStream os = null;
+    PrintStream lostos;
+    BufferedReader is = null;
+    Socket clientSocket = null;
+    ServerSocket echoServer=null;
+
+    String host;
+    
+    echoClient(){
+    	wr = new waitreply(this);
+    }
+    echoClient(String _host){
+    	wr = new waitreply(this);
+	host  =  _host;
+    }
+
+    //    Revalue hostn(String args){
+    void openport(){
+	// ソケットや入出力用のストリームの宣言
+	
+	// ポート9999番を開く
+	try {
+	    if(host == null){
+		echoSocket = new Socket("133.13.48.18", 9999);
+		System.out.println();
+	    }
+	    else{
+		echoSocket = new Socket(host, 9999);
+	    }
+	    os = new DataOutputStream(echoSocket.getOutputStream());
+	    is = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
+	} catch (UnknownHostException e) {
+	    System.err.println("Don't know about host: localhost");
+	} catch (IOException e) {
+	    System.err.println("Couldn't get I/O for the connection to: localhost");
+	}
+	}
+	
+
+    
+	/*
+	try {
+	    echoServer = new ServerSocket(9998);
+	}
+	catch (IOException e) {
+	    System.out.println(e);
+	}
+	
+	try {
+	    //clientSocket = echoServer.accept();
+	    lostis = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+	    lostos = new PrintStream(clientSocket.getOutputStream());
+	    while (true){
+		line = is.readLine();
+	    }	    
+	}
+	catch (IOException e){
+	    System.out.println(e);
+	}
+	*/
+	
+/*
+	catch(InterruptedException e){
+	    e.printStackTrace();
+	}
+*/
+
+
+
+    Revalue hostn(String args){
+	
+	// サーバーにメッセージを送る
+	if (echoSocket != null && os != null && is != null) {
+	    try {
+		//ip情報を取得する
+		InetAddress addr = InetAddress.getLocalHost();
+		//System.out.println(addr.getHostAddress());
+		String add = new String(addr.getHostAddress());
+	
+		// メッセージを送ります
+		os.writeBytes(add + "\n");
+		os.writeBytes(args + "\n");
+
+		if ((value.responseLine = is.readLine()) != null) {
+		    System.out.println("Server: " + value.responseLine);
+		}
+		if ((value.parent = is.readLine()) != null) {
+		    System.out.println("parent: " + value.parent);
+		}
+		if ((value.treenum = is.readLine()) != null) {
+		    System.out.println("treenum: " + value.treenum);
+		}
+
+		// 開いたソケットなどをクローズ
+		os.close();
+		is.close();
+		echoSocket.close();
+	    } catch (UnknownHostException e) {
+		System.err.println("Trying to connect to unknown host: " + e);
+	    } catch (IOException e) {
+		System.err.println("IOException: " + e);
+
+	    }
+		wr.start();	
+	}
+	return value;
+    }
+
+    Revalue losthost(){
+	if (echoSocket != null && os != null && is != null) {
+	    try {
+		
+		//落ちた番号を報告
+		os.writeBytes("1\n");
+		os.writeBytes(value.parent + "\n");
+		
+
+
+		if ((value.responseLine = is.readLine()) != null) {
+		    System.out.println("Server: " + value.responseLine);
+		}
+		if ((value.parent = is.readLine()) != null) {
+		    System.out.println("parent: " + value.parent);
+		}
+		if ((value.treenum = is.readLine()) != null) {
+		    System.out.println("treenum: " + value.treenum);
+		}
+
+		// 開いたソケットなどをクローズ
+		os.close();
+		is.close();
+		echoSocket.close();
+
+	    } catch (UnknownHostException e) {
+		System.err.println("Trying to connect to unknown host: " + e);
+	    } catch (IOException e) {
+		System.err.println("IOException: " + e);
+	    }
+	}
+	return value;
+    }
+
+    void lostchild(){
+	if (echoSocket != null && os != null && is != null) {
+	    try {
+
+		//自分の番号を報告
+		os.writeBytes("2\n");
+		os.writeBytes(value.treenum + "\n");
+
+		os.close();
+		is.close();
+		echoSocket.close();
+
+	    } catch (UnknownHostException e) {
+		System.err.println("Trying to connect to unknown host: " + e);
+	    } catch (IOException e) {
+		System.err.println("IOException: " + e);
+	    }
+	}
+    }
+
+    Revalue Interruption(Socket clientSocket){  
+    	
+		try {
+			clientSocket = echoServer.accept();
+			lostis = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+			lostos = new PrintStream(clientSocket.getOutputStream());
+			while (true){
+				line = lostis.readLine();
+			}	    
+		}catch (IOException e){
+			System.out.println(e);
+		}
+		try{
+		    echoServer.close();
+		}
+		catch (IOException e){
+		    System.out.println(e);
+		}    	
+	try{
+	    if ((value.responseLine = lostis.readLine()) != null) {
+		System.out.println("Server: " + value.responseLine);
+	    }
+	    if ((value.parent = lostis.readLine()) != null) {
+		System.out.println("parent: " + value.parent);
+	    }
+	    if ((value.treenum = lostis.readLine()) != null) {
+		System.out.println("treenum: " + value.treenum);
+	    }
+	}	  
+	catch (UnknownHostException e) {
+	    System.err.println("Trying to connect to unknown host: " + e);
+	} catch (IOException e) {
+	    System.err.println("IOException: " + e);
+	}
+	return value;
+    }
+}
+
+class Revalue{
+    public String responseLine;
+    public String parent;
+    public String treenum;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/myVncClient/waitreply.java	Wed Jul 06 11:56:15 2011 +0900
@@ -0,0 +1,33 @@
+package myVncClient;
+
+import java.net.*;
+import java.io.*;
+
+
+public class waitreply extends Thread{
+	echoClient echo;
+	Socket clientSocket = null;
+	ServerSocket echoServer=null;
+
+	
+	waitreply(echoClient _echo){
+		echo = _echo;
+	}
+	public void run(){
+		try {
+			echoServer = new ServerSocket(9998);
+		}
+		catch (IOException e) {
+			System.out.println(e);
+		}
+		while(true){
+			try {
+			clientSocket = echoServer.accept();
+			echo.Interruption(clientSocket);
+			}catch (IOException e){
+				System.out.println(e);
+			}
+		}
+	}
+}
+