changeset 69:1f05b73b15df

modify MyVncClient.java and CuiMyVNcClient.java
author e085711
date Sun, 07 Aug 2011 04:22:07 +0900
parents 4e31d8494360
children affdcbdc90ea
files src/myVncClient/CuiMyVncClient.java src/myVncClient/InterfaceForViewer.java src/myVncClient/MyRfbProto.java src/myVncClient/MyVncClient.java src/myVncClient/RfbProto.java
diffstat 5 files changed, 340 insertions(+), 141 deletions(-) [+]
line wrap: on
line diff
--- a/src/myVncClient/CuiMyVncClient.java	Sat Aug 06 23:34:37 2011 +0900
+++ b/src/myVncClient/CuiMyVncClient.java	Sun Aug 07 04:22:07 2011 +0900
@@ -9,7 +9,7 @@
 import myVncClient.AcceptThread;
 import myVncClient.OptionsNoFrame;
 
-public class CuiMyVncClient implements InterfaceForViewer, java.lang.Runnable {
+public class CuiMyVncClient implements InterfaceForViewer {
 
 	public static void main(String[] argv) {
 		CuiMyVncClient v = new CuiMyVncClient();
@@ -75,6 +75,7 @@
 	String parent, treenum;
 	private String leaderflag;
 	boolean runflag = false;
+	boolean first = true;
 
 	EchoClient echo;
 
@@ -95,7 +96,13 @@
 	//
 
 	public void init(EchoClient value) {
-
+		Random rnd = new Random();
+		long ran = rnd.nextInt(5000);
+		try {
+			Thread.sleep(ran);
+		} catch (InterruptedException e1) {
+			e1.printStackTrace();
+		}
 		// readParameters();
 
 		readParameters(value);
@@ -133,7 +140,12 @@
 	public void run() {
 
 		try {
-			connectAndAuthenticate();
+			if (first) {
+				connectAndAuthenticate();
+				first = false;
+			}else {
+				reConnectAndAuthenticate();
+			}
 			accThread = new Thread(new AcceptThread(rfb, 5999));
 			accThread.start();
 			doProtocolInitialisation();
@@ -153,10 +165,11 @@
 			 */
 
 			int counter = 0;
-			// window を消してnullを突っ込んでGCで削除させる。
+
 			/*
-			 * vncFrame.setVisible(false); vncFrame = null;
-			 */
+  			vncFrame.setVisible(false); 
+			 vncFrame.dispose();
+*/			 
 			while (true) {
 				/**
 				 * if my last node case reconnectoion stop
@@ -177,19 +190,18 @@
 				echo.openport();
 				// runflag = echo.losthost();
 				if (echo.losthost()) {
-					break;
+					return;
 				}
 				counter++;
 			}
 
 			// System.exit(0);
-		} catch (Exception e) {
+		}catch (Exception e) {
 			System.out.println(e);
 			System.exit(0);
 		}
-
-		try {
-
+		try{
+			
 			processNormalProtocol();// main loop
 
 		} catch (NoRouteToHostException e) {
@@ -316,6 +328,54 @@
 		}
 	}
 
+	
+	
+	void reConnectAndAuthenticate() throws Exception {
+		showConnectionStatus("Initializing...");
+
+		showConnectionStatus("Connecting to " + host + ", port " + port + "...");
+
+		rfb.changeParent(host, port);
+
+		showConnectionStatus("Connected to server");
+
+		rfb.readVersionMsg();
+		showConnectionStatus("RFB server supports protocol version "
+				+ rfb.serverMajor + "." + rfb.serverMinor);
+
+		rfb.writeVersionMsg();
+		showConnectionStatus("Using RFB protocol version " + rfb.clientMajor
+				+ "." + rfb.clientMinor);
+
+		int secType = rfb.negotiateSecurity();
+		int authType;
+		if (secType == RfbProto.SecTypeTight) {
+			showConnectionStatus("Enabling TightVNC protocol extensions");
+			rfb.setupTunneling();
+			authType = rfb.negotiateAuthenticationTight();
+		} else {
+			authType = secType;
+		}
+
+		switch (authType) {
+		case RfbProto.AuthNone:
+			showConnectionStatus("No authentication needed");
+			rfb.authenticateNone();
+			break;
+		case RfbProto.AuthVNC:
+			showConnectionStatus("Performing standard VNC authentication");
+			if (passwordParam != null) {
+				rfb.authenticateVNC(passwordParam);
+			} else {
+				String pw = askPassword();
+				rfb.authenticateVNC(pw);
+			}
+			break;
+		default:
+			throw new Exception("Unknown authentication scheme " + authType);
+		}
+	}	
+
 	//
 	// Show a message describing the connection status.
 	// To hide the connection status label, use (msg == null).
--- a/src/myVncClient/InterfaceForViewer.java	Sat Aug 06 23:34:37 2011 +0900
+++ b/src/myVncClient/InterfaceForViewer.java	Sun Aug 07 04:22:07 2011 +0900
@@ -3,7 +3,7 @@
 import java.awt.Graphics; 
 import java.net.Socket;
 
-public interface InterfaceForViewer {
+public interface InterfaceForViewer extends java.lang.Runnable{
 
 	public void init(EchoClient value);
 	public void start_threads();
--- a/src/myVncClient/MyRfbProto.java	Sat Aug 06 23:34:37 2011 +0900
+++ b/src/myVncClient/MyRfbProto.java	Sun Aug 07 04:22:07 2011 +0900
@@ -1,5 +1,6 @@
 package myVncClient;
 
+
 import java.awt.Graphics;
 import java.awt.Image;
 import java.awt.image.BufferedImage;
@@ -15,23 +16,25 @@
 import java.net.BindException;
 import java.net.ServerSocket;
 import java.net.Socket;
+import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.util.Iterator;
 import java.util.LinkedList;
 
 import javax.imageio.ImageIO;
 
-
 import myVncClient.MulticastQueue.Client;
 
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.zip.DataFormatException;
 import java.util.zip.Deflater;
 import java.util.zip.Inflater;
 import java.io.OutputStream;
 
 public
-class MyRfbProto<ByteBuffersIterator> extends RfbProto {
+class MyRfbProto extends RfbProto {
 	final static String versionMsg_3_998 = "RFB 003.998\n";
 	/**
 	 * CheckMillis is one of new msgType for RFB 3.998. 
@@ -49,7 +52,7 @@
 	private int rectH;
 	private int encoding;
 	private int zLen;
-	private boolean clicomp;
+	private boolean clicomp = false;
 
 	private ServerSocket servSock;
 	private int acceptPort;
@@ -62,12 +65,16 @@
 
 	byte[] pngBytes;
 
-
 	// private MulticastQueue<LinkedList<ByteBuffer>> multicastqueue = new MostRecentMultiCast<LinkedList<ByteBuffer>>(10);
 	private MulticastQueue<LinkedList<ByteBuffer>> multicastqueue = new MulticastQueue<LinkedList<ByteBuffer>>();
 	private int clients = 0;
 	private Inflater inflater = new Inflater();
+	private Deflater deflater = new Deflater();
 
+	public
+	MyRfbProto() throws IOException {
+	}
+	
 	MyRfbProto(String h, int p, VncViewer v) throws IOException {
 		super(h, p, v);
 		cliList = new LinkedList<Socket>();
@@ -87,8 +94,20 @@
 		// executor = Executors.newCachedThreadPool();
 		// executor = Executors.newSingleThreadExecutor();
 	}
-	
-	
+	void changeParent(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;		
+	}
+
 	// over write
 	void writeVersionMsg() throws IOException {
 		clientMajor = 3;
@@ -117,7 +136,7 @@
 		acceptPort = port;
 	}
 
-
+	// 5550を開けるが、開いてないなら+1のポートを開ける。
 	void selectPort(int p) {
 		int port = p;
 		while (true) {
@@ -305,40 +324,13 @@
 		rectW = readU16();           //  8
 		rectH = readU16();           //  10
 		encoding = readU32();      //   12
-//		System.out.println("encoding = "+encoding);
-		if (encoding == EncodingZRLE)
+		// System.out.println("encoding = "+encoding);
+		if (encoding == EncodingZRLE|| encoding==EncodingZRLEE||encoding==EncodingZlib)
 			zLen = readU32();
 		else
 			zLen = 0;
 		is.reset();
-/*
-		int dataLen;
-		switch (encoding) {
-		case RfbProto.EncodingRaw:
-			dataLen = rectW * rectH * 4 + 16;
-			mark(dataLen);
-			break;
-		case RfbProto.EncodingCopyRect:
-			dataLen = 16 + 4;
-			mark(dataLen);
-			break;
-		case RfbProto.EncodingRRE:
-		case RfbProto.EncodingCoRRE:
-		case RfbProto.EncodingHextile:
-			
-		case RfbProto.EncodingZlib:
-		case RfbProto.EncodingTight:
-		case RfbProto.EncodingZRLE:
-			dataLen = zLen + 20;
-			mark(dataLen);
-			break;
-		default:
-			dataLen = 1000000;
-			mark(dataLen);
-		}
-	
-*/	
-	
+
 	}
 
 	int checkAndMark() throws IOException {
@@ -361,6 +353,7 @@
 			break;
 		case RfbProto.EncodingZlib:
 		case RfbProto.EncodingZRLE:
+		case RfbProto.EncodingZRLEE:
 			dataLen = zLen + 20;
 			is.mark(dataLen);
 			break;
@@ -435,12 +428,7 @@
 		BufferedImage bimg = ImageIO.read(new ByteArrayInputStream(pngBytes));
 		return bimg;
 	}
-/*
-	void readPngData() throws IOException {
-		pngBytes = new byte[is.available()];
-		readFully(pngBytes);
-	}
-*/
+
 	void printFramebufferUpdate() {
 
 		System.out.println("messageType=" + messageType);
@@ -479,9 +467,6 @@
 		System.out.println("checkMillis: " + time);
 	}
 
-	void printStatus() {
-		System.out.println();
-	}
 
 	synchronized void changeStatusFlag() {
 		printStatusFlag = true;
@@ -536,9 +521,16 @@
 		while(inputIndex < inputs.size() ) {
 			ByteBuffer b1 = inputs.get(inputIndex++);
 			deflater.setInput(b1.array(),b1.position(),b1.remaining());
-			if (inputIndex==inputs.size())	deflater.finish();
+			/**
+			 * If we finish() stream and reset() it, Deflater start new gzip stream, this makes continuous zlib reader unhappy.
+			 * if we remove finish(), Deflater.deflate() never flushes its output. The original zlib deflate has flush flag. I'm pretty
+			 * sure this a kind of bug of Java library.
+			 */
+			if (inputIndex==inputs.size())	
+				deflater.finish();
+			int len1 = 0;
 			do {
-				int len1 = deflater.deflate(c1.array(),c1.position(),c1.remaining());
+				len1 = deflater.deflate(c1.array(),c1.position(),c1.remaining());
 				if (len1>0) {
 					len += len1;
 					c1.position(c1.position()+len1); 
@@ -547,7 +539,7 @@
 						c1 = ByteBuffer.allocate(INFLATE_BUFSIZE);
 					}
 				}
-			} while (!deflater.needsInput()&&!deflater.finished());
+			} while (len1 >0 || !deflater.needsInput()); // &&!deflater.finished());
 		}
 		if (c1.position()!=0) {
 			c1.flip();	outputs.addLast(c1);
@@ -566,13 +558,15 @@
 	 *@return  number of total bytes            
 	 * @throws IOException
 	 */
-	public int unzip(Inflater inflater, LinkedList<ByteBuffer> inputs, int inputIndex, LinkedList<ByteBuffer> outputs)
+	public int unzip(Inflater inflater, LinkedList<ByteBuffer> inputs, int inputIndex, LinkedList<ByteBuffer> outputs,int bufSize)
 																	throws DataFormatException {
 		int len=0;
-		ByteBuffer buf = ByteBuffer.allocate(INFLATE_BUFSIZE);
+		ByteBuffer buf = ByteBuffer.allocate(bufSize);
 		while (inputIndex < inputs.size()) {
 			ByteBuffer input = inputs.get(inputIndex++);
 			inflater.setInput(input.array(),input.position(),input.limit());
+//			if (inputIndex==inputs.size())	    if inflater/deflater has symmetry, we need this
+//				inflater.end();                         but this won't work
 			do {
 				int len0 = inflater.inflate(buf.array(),buf.position(),buf.remaining());
 				if (len0>0) {
@@ -581,7 +575,7 @@
 					if (buf.remaining()==0) {
 						buf.flip();
 						outputs.addLast(buf);
-						buf = ByteBuffer.allocate(INFLATE_BUFSIZE);
+						buf = ByteBuffer.allocate(bufSize);
 					}
 				}
 			} while (!inflater.needsInput());
@@ -593,6 +587,20 @@
 		return len;
 	}
 	
+	/**
+	 * send data to clients
+	 * @param dataLen
+	 * @throws IOException
+	 * @throws DataFormatException
+	 * 
+	 * Zlibed packet is compressed in context dependent way, that is, it have to send from the beginning. But this is
+	 * impossible. So we have to compress it again for each clients. Separate deflater for each clients is necessary. 
+	 * 
+	 * Java's deflater does not support flush. This means to get the result, we have to finish the compression. Reseting
+	 * start new compression, but it is not accepted well in zlib continuous reading. So we need new Encoding ZRLEE
+	 * which reset decoder for each packet. ZRLEE can be invisible from user, but it have to be implemented in the clients.
+	 * ZRLEE compression is not context dependent, so no recompression is necessary.
+	 */
 	void readSendData(int dataLen) throws IOException, DataFormatException {
 		LinkedList<ByteBuffer>bufs = new LinkedList<ByteBuffer>();
 		ByteBuffer header = ByteBuffer.allocate(16);
@@ -600,23 +608,24 @@
 		header.limit(16);
 		if (header.get(0)==RfbProto.FramebufferUpdate) {
 			int encoding = header.getInt(12);
-			if (encoding==RfbProto.EncodingZlib||encoding==RfbProto.EncodingZRLE) {
+			if (encoding==RfbProto.EncodingZRLE||encoding==RfbProto.EncodingZlib) { // ZRLEE is already recompressed
 				ByteBuffer len = ByteBuffer.allocate(4);
 				readFully(len.array(),0,4); len.limit(4);
 				ByteBuffer inputData = ByteBuffer.allocate(dataLen-20);
 				readFully(inputData.array(),0,inputData.capacity()); inputData.limit(dataLen-20);
 				LinkedList<ByteBuffer>inputs = new LinkedList<ByteBuffer>();
 				inputs.add(inputData);
-				if (clicomp) {
-					unzip(inflater, inputs, 0, bufs);
-				} else {
-					Deflater nDeflater = new Deflater();
-					LinkedList<ByteBuffer> out = new LinkedList<ByteBuffer>();
-					unzip(inflater, inputs, 0 , out);
-					int len2 = zip(nDeflater, out, 0, bufs);
-					ByteBuffer blen = ByteBuffer.allocate(4); blen.putInt(len2); blen.flip();
-					bufs.addFirst(blen);
-				}
+
+				header.putInt(12, RfbProto.EncodingZRLEE); // means recompress every time
+				// using new Deflecter every time is incompatible with the protocol, clients have to be modified.
+				Deflater nDeflater = deflater; // new Deflater();
+				LinkedList<ByteBuffer> out = new LinkedList<ByteBuffer>();
+				unzip(inflater, inputs, 0 , out, INFLATE_BUFSIZE);
+				// dump32(inputs);
+				int len2 = zip(nDeflater, out, 0, bufs);
+				ByteBuffer blen = ByteBuffer.allocate(4); blen.putInt(len2); blen.flip();
+				bufs.addFirst(blen);
+
 				bufs.addFirst(header);
 				multicastqueue.put(bufs);
 				is.reset();
@@ -642,8 +651,48 @@
 		// createBimgFlag = true;
 		// rfb.addSockTmp(newCli);
 		//		addSock(newCli);
+		final int myId = clients; 
 		final Client <LinkedList<ByteBuffer>> c = multicastqueue.newClient();
-
+		final AtomicInteger writerRunning = new AtomicInteger();
+		writerRunning.set(1);
+		/**
+		 * Timeout thread. If a client is suspended, it has top of queue indefinitely, which caused memory
+		 * overflow. After the timeout, we poll the queue and discard it. Start long wait if writer is running.
+		 */
+		final Runnable timer = new Runnable() {
+			public void run() {
+				int count = 0;
+				for(;;) {
+					long timeout = 30000/8;
+					try {
+						synchronized(this) {
+							int state,flag;
+							writerRunning.set(0);
+							wait(timeout);
+							flag = 0;
+							while((state=writerRunning.get())==0) {
+								c.poll(); // discard, should be timeout
+								count++;
+								if (flag==0) {
+									System.out.println("Discarding "+myId + " count="+ count); flag = 1;
+								}
+								wait(10); // if this is too short, writer cannot take the poll, if this is too long, memory will overflow...
+							}
+							if (flag==1) System.out.println("Resuming "+myId + " count="+count);
+							if (state!=1) {
+								System.out.println("Client died "+myId);
+								break;
+							}
+						}
+					} catch (InterruptedException e) {
+					}
+				}
+			}
+		};
+		new Thread(timer).start();
+		/**
+		 * discard all incoming from clients
+		 */
 		final Runnable reader = new Runnable() {
 			public void run() {
 				byte b[] = new byte[4096];
@@ -651,9 +700,10 @@
 					try {
 						int c = is.read(b);
 						if (c<=0) throw new IOException();
-						System.out.println("client read "+c);
+						// System.out.println("client read "+c);
 					} catch (IOException e) {
 						try {
+							writerRunning.set(2);
 							os.close();
 							is.close();
 						} catch (IOException e1) {
@@ -663,12 +713,12 @@
 				}
 			}
 		};
+		/**
+		 * send packets to a client
+		 */
 		Runnable sender = new Runnable() {
-
-
 			public void run() {
-
-			    Deflater deflater = new Deflater();
+				writerRunning.set(1);
 				try {
 					/**
 					 *  initial connection of RFB protocol
@@ -680,65 +730,93 @@
 					sendSecResult(os);
 					readClientInit(is);
 					sendInitData(os);
-					new Thread(reader).start();
+					new Thread(reader).start(); // discard incoming packet here after.
 					for (;;) {
 						LinkedList<ByteBuffer> bufs = c.poll();
 						int inputIndex = 0;
-						ByteBuffer header = bufs.get(inputIndex++);
+						ByteBuffer header = bufs.get(inputIndex);
 						if (header==null) continue;
 						if (header.get(0)==RfbProto.FramebufferUpdate) {
-							System.out.println("client "+ clients);
-							int encoding = header.getInt(12);
-							if (encoding==RfbProto.EncodingZlib||encoding==RfbProto.EncodingZRLE) {
-								LinkedList<ByteBuffer> outs;
-								if (clicomp) {
-									outs = new LinkedList<ByteBuffer>();
-									int len2 = zip(deflater, bufs, inputIndex, outs);
-									ByteBuffer blen = ByteBuffer.allocate(4); blen.putInt(len2); blen.flip();
-									outs.addFirst(blen);
-									outs.addFirst(header);
-									inputIndex = 0;
-								} else {
-									outs = bufs;
-									inputIndex = 0;
-								}
-								while(inputIndex < outs.size()) {
-								   ByteBuffer out=  outs.get(inputIndex++);
-								   os.write(out.array(),out.position(),out.limit());
-								}
-							}
-							if (encoding==RfbProto.EncodingRaw) {
-								LinkedList<ByteBuffer> outs = bufs;
-								inputIndex = 0;
-								while( inputIndex < outs.size()){
-									ByteBuffer out = outs.get(inputIndex++);
-									os.write(out.array(), out.position(), out.limit());
-								}
-							}
-							os.flush();
-							continue;
+							// System.out.println("client "+ myId);
 						}
-						os.write(header.array(),header.position(),header.limit());
-						while(inputIndex < bufs.size()) {
-							ByteBuffer b = bufs.get(inputIndex++);
-							os.write(b.array(), b.position(), b.limit());
-						}
-						os.flush();
+						writeToClient(os, bufs, inputIndex);
+						writerRunning.set(1);  // yes my client is awaking.
 					}
 				} catch (IOException e) {
 					try {
+						writerRunning.set(2);
 						os.close();
 					} catch (IOException e1) {
 					}
 					/* if socket closed 	cliList.remove(newCli); */
 				}
 			}
+
+			public void writeToClient(final OutputStream os,
+					LinkedList<ByteBuffer> bufs, int inputIndex)
+					throws IOException {
+				while(inputIndex < bufs.size()) {
+					ByteBuffer b = bufs.get(inputIndex++);
+					os.write(b.array(), b.position(), b.limit());
+				}
+				os.flush();
+			}
 		};
 		clients++;
 		new Thread(sender).start();
 
 	}
 
+
+	public void dump32(LinkedList<ByteBuffer>bufs) {
+		int len =0;
+		for(ByteBuffer b: bufs) 	len += b.remaining();
+		ByteBuffer top = bufs.getFirst();
+		ByteBuffer end = bufs.getLast();
+		System.err.println("length: "+len);
+		System.err.print("head 0: ");
+		for(int i = 0; i<16 && i < top.remaining(); i++) {
+			System.err.print(" "+ top.get(i));
+		}			
+		System.err.print("tail 0: ");
+		for(int i = 0; i<16 && i < end.remaining(); i++) {
+			System.err.print(" "+end.get(i));
+		}
+		System.err.println();
+	}
+
+	private Iterable<Byte> byteBufferIterator(final LinkedList<ByteBuffer> in) {
+		return new Iterable<Byte>() {
+			public Iterator<Byte> iterator() {
+				return new Iterator<Byte>() {
+					int bytes = 0;
+					int buffers = 0;
+					public boolean hasNext() {
+						for(;;) {
+							if (buffers>=in.size()) return false;
+							ByteBuffer b = in.get(buffers);
+							if (! (bytes<b.remaining())) {
+								buffers ++; bytes=0;
+							} else return true;
+						}
+					}
+					public Byte next() {
+						ByteBuffer bf =in.get(buffers); 
+						byte b = bf.get(bytes++); 
+						if (bf.remaining()<=bytes) {
+							buffers++;
+							bytes = 0;
+						}
+						// System.out.print(b);
+						return b;
+					}
+					public void remove() {
+					}
+				};
+			}
+		};
+	}
+
 }
 
 
--- a/src/myVncClient/MyVncClient.java	Sat Aug 06 23:34:37 2011 +0900
+++ b/src/myVncClient/MyVncClient.java	Sun Aug 07 04:22:07 2011 +0900
@@ -10,7 +10,7 @@
 		WindowListener {
 
 	/**
-	 * 
+	 * e
 	 */
 	private static final long serialVersionUID = 1L;
 	boolean inAnApplet = true;
@@ -19,7 +19,7 @@
 	String parent, treenum;
 	private String leaderflag;
 	boolean runflag = false;
-
+	boolean first = true;
 	//
 	// main() is called when run as a java program from the command line.
 	// It simply runs the applet inside a newly-created frame.
@@ -107,7 +107,12 @@
 
 		try {
 
-			connectAndAuthenticate();
+			if (first) {
+				connectAndAuthenticate();
+				first = false;
+			}else {
+				reConnectAndAuthenticate();
+			}
 			accThread = new Thread(new AcceptThread(rfb, 5999));
 			accThread.start();
 
@@ -130,10 +135,9 @@
 			 */
 
 			int counter = 0;
-			// window を消してnullを突っ込んでGCで削除させる。
-			/*
-			 * vncFrame.setVisible(false); vncFrame = null;
-			 */
+			 vncFrame.setVisible(false); 
+			 vncFrame.dispose();
+			 
 			while (true) {
 				/**
 				 * if my last node case reconnectoion stop
@@ -158,7 +162,7 @@
 				}
 				counter++;
 			}
-
+			
 			// System.exit(0);
 		} catch (Exception e) {
 			System.out.println(e);
@@ -375,6 +379,51 @@
 		}
 	}
 
+	void reConnectAndAuthenticate() throws Exception {
+		showConnectionStatus("Initializing...");
+
+		showConnectionStatus("Connecting to " + host + ", port " + port + "...");
+
+		rfb.changeParent(host, port);
+
+		showConnectionStatus("Connected to server");
+
+		rfb.readVersionMsg();
+		showConnectionStatus("RFB server supports protocol version "
+				+ rfb.serverMajor + "." + rfb.serverMinor);
+
+		rfb.writeVersionMsg();
+		showConnectionStatus("Using RFB protocol version " + rfb.clientMajor
+				+ "." + rfb.clientMinor);
+
+		int secType = rfb.negotiateSecurity();
+		int authType;
+		if (secType == RfbProto.SecTypeTight) {
+			showConnectionStatus("Enabling TightVNC protocol extensions");
+			rfb.setupTunneling();
+			authType = rfb.negotiateAuthenticationTight();
+		} else {
+			authType = secType;
+		}
+
+		switch (authType) {
+		case RfbProto.AuthNone:
+			showConnectionStatus("No authentication needed");
+			rfb.authenticateNone();
+			break;
+		case RfbProto.AuthVNC:
+			showConnectionStatus("Performing standard VNC authentication");
+			if (passwordParam != null) {
+				rfb.authenticateVNC(passwordParam);
+			} else {
+				String pw = askPassword();
+				rfb.authenticateVNC(pw);
+			}
+			break;
+		default:
+			throw new Exception("Unknown authentication scheme " + authType);
+		}
+	}	
 	//
 	// Show a message describing the connection status.
 	// To hide the connection status label, use (msg == null).
--- a/src/myVncClient/RfbProto.java	Sat Aug 06 23:34:37 2011 +0900
+++ b/src/myVncClient/RfbProto.java	Sun Aug 07 04:22:07 2011 +0900
@@ -26,18 +26,16 @@
 //
 
 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";
@@ -77,8 +75,8 @@
 
 	// Supported encodings and pseudo-encodings
 	final static int EncodingRaw = 0, EncodingCopyRect = 1, EncodingRRE = 2,
-			EncodingCoRRE = 4, EncodingHextile = 5, EncodingZlib = 6,
-			EncodingTight = 7, EncodingZRLE = 16,
+ 			EncodingCoRRE = 4, EncodingHextile = 5, EncodingZlib = 6,
+			EncodingTight = 7, EncodingZRLEE = 15, EncodingZRLE = 16,
 			EncodingCompressLevel0 = 0xFFFFFF00,
 			EncodingQualityLevel0 = 0xFFFFFFE0, EncodingXCursor = 0xFFFFFF10,
 			EncodingRichCursor = 0xFFFFFF11, EncodingPointerPos = 0xFFFFFF18,
@@ -87,6 +85,7 @@
 			SigEncodingCopyRect = "COPYRECT", SigEncodingRRE = "RRE_____",
 			SigEncodingCoRRE = "CORRE___", SigEncodingHextile = "HEXTILE_",
 			SigEncodingZlib = "ZLIB____", SigEncodingTight = "TIGHT___",
+			SigEncodingZRLEE = "ZRLEE___",
 			SigEncodingZRLE = "ZRLE____",
 			SigEncodingCompressLevel0 = "COMPRLVL",
 			SigEncodingQualityLevel0 = "JPEGQLVL",
@@ -176,9 +175,6 @@
 //	private boolean closed;
 	protected boolean closed;
 
-	public RfbProto(){
-	}
-	
 	//
 	// Constructor. Make TCP connection to RFB server.
 	//
@@ -226,7 +222,11 @@
 		timedKbits = 0;
 	}
 	
-	
+	public RfbProto() {
+		
+	}
+
+
 
 	synchronized void close() {
 		try {
@@ -469,13 +469,16 @@
 		encodingCaps.add(EncodingHextile, StandardVendor, SigEncodingHextile,
 				"Standard Hextile encoding");
 		encodingCaps.add(EncodingZRLE, StandardVendor, SigEncodingZRLE,
-				"Standard ZRLE encoding");
+	    		"Standard ZRLE encoding");		
+		encodingCaps.add(EncodingZRLEE, StandardVendor, SigEncodingZRLEE,
+	    		"Standard ZRLE(E) 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,
@@ -490,6 +493,7 @@
 				"LastRect protocol extension");
 		encodingCaps.add(EncodingNewFBSize, TightVncVendor,
 				SigEncodingNewFBSize, "Framebuffer size change");
+
 	}
 
 	//
@@ -562,9 +566,13 @@
 	void writeClientInit() throws IOException {
 /*
 		if (viewer.options.shareDesktop) {
+*/
+		
+		/**
+		 * shared flag
+		 */
 			os.write(1);
-*/
-			os.write(0);
+//			os.write(0);
 
 //		viewer.options.disableShareDesktop();
 	}
@@ -692,6 +700,8 @@
 	void readFramebufferUpdate() throws IOException {
 		skipBytes(1);
 		updateNRects = readU16();
+		// System.out.println(updateNRects);
+
 		// If the session is being recorded:
 		if (rec != null) {
 			rec.writeByte(FramebufferUpdate);
@@ -716,6 +726,7 @@
 
 		if (updateRectEncoding == EncodingZlib
 				|| updateRectEncoding == EncodingZRLE
+				|| updateRectEncoding == EncodingZRLEE
 				|| updateRectEncoding == EncodingTight)
 			wereZlibUpdates = true;
 
@@ -948,6 +959,8 @@
 	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.
@@ -1205,7 +1218,7 @@
 		if (!down)
 			writeModifierKeyEvents(0);
 
-		//os.write(eventBuf, 0, eventBufLen);
+		os.write(eventBuf, 0, eventBufLen);
 	}
 
 	//
@@ -1378,5 +1391,4 @@
 		numBytesRead += 4;
 		return r;
 	}
-
 }