changeset 207:b31903e5b02d

rename myRFBProto
author oc
date Wed, 02 Jul 2014 18:14:20 +0900
parents 2b3eb4a9492f
children f1d7cb4a1868
files src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEESender.java src/main/java/com/glavsoft/rfb/protocol/Protocol.java src/main/java/com/glavsoft/rfb/protocol/ReceiverTask.java src/main/java/jp/ac/u_ryukyu/treevnc/CreateConnectionParam.java src/main/java/jp/ac/u_ryukyu/treevnc/MyRfbProto.java src/main/java/jp/ac/u_ryukyu/treevnc/RequestScreenThread.java src/main/java/jp/ac/u_ryukyu/treevnc/TreeRFBProto.java src/main/java/jp/ac/u_ryukyu/treevnc/TreeVNCNetwork.java src/main/java/jp/ac/u_ryukyu/treevnc/TreeVncCommand.java src/main/java/jp/ac/u_ryukyu/treevnc/TreeVncCommandChannelListener.java src/viewer_swing/java/com/glavsoft/viewer/CuiViewer.java src/viewer_swing/java/com/glavsoft/viewer/Viewer.java src/viewer_swing/java/com/glavsoft/viewer/ViewerInterface.java src/viewer_swing/java/com/glavsoft/viewer/swing/SwingConnectionWorkerFactory.java src/viewer_swing/java/com/glavsoft/viewer/swing/SwingRfbConnectionWorker.java src/viewer_swing/java/com/glavsoft/viewer/swing/SwingViewerWindow.java
diffstat 16 files changed, 772 insertions(+), 778 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEESender.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEESender.java	Wed Jul 02 18:14:20 2014 +0900
@@ -1,6 +1,6 @@
 package com.glavsoft.rfb.encoding.decoder;
 
-import jp.ac.u_ryukyu.treevnc.MyRfbProto;
+import jp.ac.u_ryukyu.treevnc.TreeRFBProto;
 
 import com.glavsoft.drawing.Renderer;
 import com.glavsoft.exceptions.TransportException;
@@ -9,9 +9,9 @@
 
 public class ZRLEESender extends Decoder {
 
-	private MyRfbProto rfb;
+	private TreeRFBProto rfb;
 
-	public ZRLEESender(MyRfbProto rfb) {
+	public ZRLEESender(TreeRFBProto rfb) {
 		this.rfb = rfb;
 	}
 
--- a/src/main/java/com/glavsoft/rfb/protocol/Protocol.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/main/java/com/glavsoft/rfb/protocol/Protocol.java	Wed Jul 02 18:14:20 2014 +0900
@@ -40,7 +40,7 @@
 
 import java.util.logging.Logger;
 
-import jp.ac.u_ryukyu.treevnc.MyRfbProto;
+import jp.ac.u_ryukyu.treevnc.TreeRFBProto;
 
 public class Protocol implements ProtocolContext, IChangeSettingsListener {
 	private ProtocolState state;
@@ -182,7 +182,7 @@
 	 */
     public void startNormalHandling(IRfbSessionListener rfbSessionListener,
             IRepaintController repaintController, ClipboardController clipboardController,
-            MyRfbProto rfb) 
+            TreeRFBProto rfb) 
     {
         receiverTask = new ReceiverTask(
                 reader, repaintController,
--- a/src/main/java/com/glavsoft/rfb/protocol/ReceiverTask.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/main/java/com/glavsoft/rfb/protocol/ReceiverTask.java	Wed Jul 02 18:14:20 2014 +0900
@@ -46,7 +46,7 @@
 import java.io.UnsupportedEncodingException;
 import java.util.logging.Logger;
 
-import jp.ac.u_ryukyu.treevnc.MyRfbProto;
+import jp.ac.u_ryukyu.treevnc.TreeRFBProto;
 import jp.ac.u_ryukyu.treevnc.TreeVncProtocol;
 
 public class ReceiverTask implements Runnable {
@@ -68,13 +68,13 @@
 	protected final ProtocolContext context;
 	protected PixelFormat pixelFormat;
 	protected boolean needSendPixelFormat;
-	private MyRfbProto rfb;
+	private TreeRFBProto rfb;
 	private long checkCounter = 0;
 	
 	public ReceiverTask(Reader reader,
             IRepaintController repaintController, ClipboardController clipboardController,
             DecodersContainer decoders, ProtocolContext context,
-            MyRfbProto _rfb) {
+            TreeRFBProto _rfb) {
 		rfb = _rfb;
 		this.reader = reader;
 		this.repaintController = repaintController;
--- a/src/main/java/jp/ac/u_ryukyu/treevnc/CreateConnectionParam.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/treevnc/CreateConnectionParam.java	Wed Jul 02 18:14:20 2014 +0900
@@ -8,10 +8,10 @@
 public class CreateConnectionParam {
 	private String hostName;
 	private int portNumber = ConnectionParams.DEFAULT_VNC_ROOT;
-	private MyRfbProto rfb;
+	private TreeRFBProto rfb;
     private String myHostName;
 	
-	public CreateConnectionParam(MyRfbProto rfb) {
+	public CreateConnectionParam(TreeRFBProto rfb) {
 		this.rfb = rfb;
 	}
 
--- a/src/main/java/jp/ac/u_ryukyu/treevnc/MyRfbProto.java	Wed Jul 02 17:58:55 2014 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,730 +0,0 @@
-package jp.ac.u_ryukyu.treevnc;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.BindException;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.zip.DataFormatException;
-import java.util.zip.Deflater;
-import java.util.zip.Inflater;
-
-import com.glavsoft.exceptions.TransportException;
-import com.glavsoft.rfb.client.ClientToServerMessage;
-import com.glavsoft.rfb.encoding.EncodingType;
-import com.glavsoft.rfb.protocol.Protocol;
-import com.glavsoft.rfb.protocol.ProtocolContext;
-import com.glavsoft.transport.Reader;
-import com.glavsoft.transport.Writer;
-import com.glavsoft.viewer.ViewerInterface;
-import com.glavsoft.viewer.swing.ConnectionParams;
-
-
-public class MyRfbProto {
-	final static int FramebufferUpdateRequest = 3;
-	final static int CheckDelay = 11;
-	protected final static int FramebufferUpdate = 0;
-	protected ProtocolContext context;
-	private int clients = 0;
-	public MulticastQueue<LinkedList<ByteBuffer>> multicastqueue = new MulticastQueue<LinkedList<ByteBuffer>>();
-	private RequestScreenThread rThread;
-	public int acceptPort = 0;
-    private String myAddress;
-	protected boolean readyReconnect = false;
-	private boolean cuiVersion;
-	private long counter = 0; // packet serial number
-    public ServerSocket servSock;
-    private boolean permitChangeScreen = true;
-    private static final int INFLATE_BUFSIZE = 1024 * 100;
-
-    private Inflater inflater = new Inflater();
-    private Deflater deflater = new Deflater();
-    ViewerInterface viewer;
-	private short id;  // my tree node id ( = 0 in root )
-    private boolean leader;
-    private TreeVncCommandChannelListener acceptThread;
-    private boolean firstTime = true;
-    private TreeRootFinderListener getCast;
-    private CreateConnectionParam cp;
-    private boolean hasViewer = false;
-	public boolean showTreeNode = false;
-    private boolean reconnecting;
-    private short reconnectingId;  // Change Server Request to id's node VNC server
-    private TreeVNCNetwork nets = new TreeVNCNetwork();
-	private boolean isTreeManager;
-
-	public MyRfbProto(boolean isTreeManager) {
-		rThread = new RequestScreenThread(this);
-		nets.setMyRfb(this);
-		this.isTreeManager = isTreeManager;
-	}
-	
-	public boolean isTreeManager() {
-		return isTreeManager;
-	}
-	
-	public ProtocolContext getContext() {
-		return context;
-	}
-	
-	/**
-	 * handle new client accept 
-	 *     it also handle TreeVNC Command
-	 * @param acceptThread
-	 * @param newCli
-	 * @param os
-	 * @param is
-	 * @throws IOException
-	 * @throws TransportException
-	 */
-	public void newClient(final Socket newCli,final Writer os, final Reader is) { 
-
-		final int myId = clients;
-		final MulticastQueue.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 = 50000 / 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, "timer-discard-multicastqueue").start();
-		/**
-		 * handle command from lower node
-		 */
-		final Runnable reader = new Runnable() {
-
-            public void run() {
-				for (;;) {
-					try {
-		                final byte b[] = new byte[4096];
-						final int c = is.readByte(b);
-						if (c <= 0)
-							throw new IOException();
-						if (isTreeManager()) {
-							if (b[0] == ClientToServerMessage.SERVER_CHANGE_REQUEST) {
-								if (permitChangeScreen()) {
-									ByteBuffer buf = ByteBuffer.wrap(b);
-									buf.order(ByteOrder.BIG_ENDIAN);
-								    short id = buf.getShort(2);
-									int length = buf.getInt(4);
-									if (length == 0) 
-										continue;
-				                	String newHostName = new String(b, 8, length);
-				                	System.out.println("Root server change request :" + newHostName);
-									// please remove these numbers.
-				                	if (viewer != null) {
-					                    changeVNCServer(viewer, newHostName, 3200, 1980, id);				                		
-				                	}
-				                } else {
-				                    continue;
-				                }
-							}
-						} else if (b[0] == ClientToServerMessage.SERVER_CHANGE_REQUEST) {
-						    ClientToServerMessage sc = new ClientToServerMessage() {
-                                @Override
-                                public void send(Writer writer)
-                                        throws TransportException {
-                                    writer.write(b,0,c);
-                                }
-						    };
-							context.sendMessage(sc);
-						}
-						// System.out.println("client read "+c);
-					} catch (Exception e) {
-						try {
-							writerRunning.set(2);
-							os.close();
-							is.close();
-							break;
-						} catch (IOException e1) {
-						} catch (TransportException e1) {
-							e1.printStackTrace();
-						}
-						return;
-					}
-				}
-			}
-
-		};
-		/**
-		 * send packets to a client (one thread for each client )
-		 */
-		Runnable sender = new Runnable() {
-			public void run() {
-				writerRunning.set(1);
-				try {
-					requestThreadNotify();
-
-					// after this, we discard upward packet.
-					new Thread(reader, "upward-packet-processing").start(); 
-
-					for (;;) {
-						LinkedList<ByteBuffer> bufs = c.poll();
-						int inputIndex = 0;
-						ByteBuffer header = bufs.get(inputIndex);
-						if (header == null)
-							continue;
-						else if (header.get(0) == CheckDelay) {
-							writeToClient(os, bufs, inputIndex);
-							continue;
-						} else if (header.get(0) == FramebufferUpdate) {
-							 //System.out.println("client "+ myId);
-						}
-						/*
-						 * if(i%20==0){ sendDataCheckDelay(); } i++;
-						 */
-						writeToClient(os, bufs, inputIndex);
-						writerRunning.set(1); // yes my client is awaking.
-					}
-				} catch (Exception e) {
-					try {
-						writerRunning.set(2);
-						os.close();
-					} catch (IOException e1) {
-						System.out.println("root writer close faild :" + e1);
-					}
-					System.out.println("root writer faild :" + e);
-					/* if socket closed cliList.remove(newCli); */
-				}
-			}
-
-			public void writeToClient(final Writer os,
-					LinkedList<ByteBuffer> bufs, int inputIndex)
-					throws TransportException {
-				while (inputIndex < bufs.size()) {
-					ByteBuffer b = bufs.get(inputIndex++);
-					os.write(b.array(), b.position(), b.limit());
-				}
-				os.flush();
-				bufs = null;
-				multicastqueue.heapAvailable();
-			}
-		};
-		clients++;
-		new Thread(sender, "writer-to-lower-node").start();
-
-	}
-
-	
-
-    public boolean permitChangeScreen() {
-        return permitChangeScreen;
-    }
-    
-
-    public void setPermitChangeScreen(boolean v) {
-         permitChangeScreen = v;
-    }
-    
-	public void requestThreadNotify() {
-		rThread.reStart();
-	}
-	
-	
-    public void setProtocolContext(Protocol workingProtocol) {
-        context = workingProtocol;
-    }
-
-    public Socket accept() throws IOException {
-        return servSock.accept();
-    }
-
-    public int selectPort(int p) {
-        int port = p;
-        while (true) {
-            try {
-                servSock = new ServerSocket(port);
-                acceptPort = port;
-                myAddress = "127.0.0.1";
-                getNetworkInterfaces();
-                break;
-            } catch (BindException e) {
-                port++;
-                continue;
-            } catch (IOException e) {
-
-            }
-        }
-        System.out.println("accept port = " + port);
-        return port;
-    }
-
-
-
-	public void writeFramebufferUpdateRequest(int x, int y, int w, int h,
-			boolean incremental) throws TransportException {
-		byte[] b = new byte[10];
-
-		b[0] = (byte) FramebufferUpdateRequest; // 3 is 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);
-	}
-	
-	public void setViewer(ViewerInterface v) {
-		viewer = v;
-	}
-	
-	public ViewerInterface getViewer() {
-		return viewer;
-	}
-
-
-	void sendInitData(OutputStream os) throws IOException {
-		os.write(context.getInitData());
-	}
-
-	
-	@Override
-	public void setTerminationType(boolean setType) {
-		normalTermination = setType;
-	}
-	
-	@Override
-	public boolean getTerminationType() {
-		return normalTermination;
-	}
-	
-	
-	public void addHostToSelectionPanel(int port, String hostname,String myHostName) {
-		if (rootSelectionPanel != null) {
-			rootSelectionPanel.checkBox(Integer.toString(port) + ":" + hostname + ":" + myHostName);
-			rootSelectionPanel.setButton();
-			rootSelectionPanel.visible();			
-		}
-	}
-	
-	@Override
-	public void createRootSelectionPanel(CreateConnectionParam cp) {
-		rootSelectionPanel = new TreeVncRootSelectionPanel();
-		rootSelectionPanel.setCp(cp);
-	}
-	
-    public void close() {
-	    // none
-	}
-	
-	public int getAcceptPort() {
-		return acceptPort;
-	}
-	
-	public boolean getReadyReconnect() {
-		return readyReconnect;
-	}
-
-
-	public boolean getCuiVersion() {
-		return cuiVersion;
-	} 
-	
-	public void  setCuiVersion(boolean flag) {
-		cuiVersion = flag;
-	}
-
-	public void readCheckDelay(Reader reader) throws TransportException {
-		
-	}
-
-	public synchronized void vncConnected(boolean ready) {
-	    if (ready && reconnecting) {
-	    	Socket vncSocket = viewer.getVNCSocket();
-	    	NetworkInterface ni = getInterface(vncSocket);
-	    	if (ni!=null) {
-	    		vncInterface = ni.getName();
-	    		System.out.println("VNCNetworkInterface :" + vncInterface);
-	    	}
-	        sendDesktopSizeChange(reconnectingId);
-	        reconnecting = false;
-	        if (reconnectingId == 0) {
-	        	viewer.setVisible(false);
-	        }
-	    } 
-	    if (reconnectingId!=0) {
-	        readyReconnect = ready;
-	        if (ready) {
-	            notifyAll();
-	        }
-	    }
-	}	
-
-
-	public synchronized void waitForVNCConnection() throws InterruptedException {
-	    if (reconnectingId!=0) {
-	        while (!readyReconnect) {
-	            wait();
-	        }
-	    }
-	}
-
-
-	public void sendDesktopSizeChange(short id) {
-		LinkedList<ByteBuffer> desktopSize = new LinkedList<ByteBuffer>();
-		int width = context.getFbWidth();
-		int height = context.getFbHeight();
-		desktopSize.add(new UpdateRectangleMessage(width, height, EncodingType.INIT_DATA, context.getInitData(),id).getMessage());
-		addSerialNumber(desktopSize);
-		multicastqueue.put(desktopSize);
-	}
-
-
-	public void addSerialNumber(LinkedList<ByteBuffer> bufs) {
-		ByteBuffer serialNum = multicastqueue.allocate(8);
-		serialNum.putLong(counter++);
-		serialNum.flip();
-		bufs.addFirst(serialNum);
-	}
-
-
-    public void resetDecoder() {
-        context.resetDecoder();
-    }
-
-    public void stopReceiverTask() {
-        if (context!=null)
-            context.cleanUpSession(null);
-        // cleanup zlib decoder for new VNCServer
-        if (isTreeManager())
-            inflater = new Inflater();
-    }
-
-    public String getMyAddress() {
-        return myAddress;
-    }
-
-    /**
-     * gzip byte arrays
-     * 
-     * @param deflater
-     * @param inputs
-     *            byte data[]
-     * @param inputIndex
-     * @param outputs
-     *            byte data[]
-     * @return byte length in last byte array
-     * @throws IOException
-     */
-    public int zip(Deflater deflater, LinkedList<ByteBuffer> inputs,
-            int inputIndex, LinkedList<ByteBuffer> outputs) throws IOException {
-        int len = 0;
-        ByteBuffer c1 = multicastqueue.allocate(INFLATE_BUFSIZE);
-        while (inputIndex < inputs.size()) {
-            ByteBuffer b1 = inputs.get(inputIndex++);
-            deflater.setInput(b1.array(), b1.position(), b1.remaining());
-            /**
-             * 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 {
-                len1 = deflater.deflate(c1.array(), c1.position(),
-                        c1.remaining());
-                if (len1 > 0) {
-                    len += len1;
-                    c1.position(c1.position() + len1);
-                    if (c1.remaining() == 0) {
-                        c1.flip();
-                        outputs.addLast(c1);
-                        c1 = multicastqueue.allocate(INFLATE_BUFSIZE);
-                    }
-                }
-            } while (len1 > 0 || !deflater.needsInput()); // &&!deflater.finished());
-        }
-        if (c1.position() != 0) {
-            c1.flip();
-            outputs.addLast(c1);
-        }
-        deflater.reset();
-        return len;
-    }
-
-    /**
-     * gunzip byte arrays
-     * 
-     * @param inflater
-     * @param inputs
-     *            byte data[]
-     * @param bytes
-     *            byte data[]
-     * @return number of total bytes
-     * @throws IOException
-     */
-    public int unzip(Inflater inflater, LinkedList<ByteBuffer> inputs,
-            int inputIndex, byte[] bytes, int bufSize)
-            throws DataFormatException {
-        int position = 0;
-        int limit = bytes.length;
-        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(bytes, position,
-                        limit-position);
-                if (len0 > 0) {
-                	position += len0;
-                    if (position > limit) {
-                    	throw new DataFormatException();
-                    }
-                }
-            } while (!inflater.needsInput());
-        }
-        return position;
-    }
-
-    /**
-     * read FrameBuffferUpdate. If it is ZLE, make it ZLEE which is self contained compressed packet.
-     * put the packet to the multicastqueue. Then normal rendering engine read the same stream using is.reset().
-     * @param dataLen
-     * @param reader
-     * @throws TransportException
-     */
-    public void readSendData(int dataLen, Reader reader, byte[] bytes)
-            throws TransportException {
-        LinkedList<ByteBuffer> bufs = new LinkedList<ByteBuffer>();
-        ByteBuffer header = multicastqueue.allocate(16);
-        ByteBuffer serial = multicastqueue.allocate(8);
-        if (!isTreeManager()) {
-            reader.readBytes(serial.array(),0,8);
-            serial.limit(8);
-        }
-        reader.mark(dataLen);
-        reader.readBytes(header.array(), 0, 16);
-        header.limit(16);
-        if (header.get(0) == FramebufferUpdate) {
-            int encoding = header.getInt(12);
-            if (encoding == EncodingType.ZRLE.getId()
-                    || encoding == EncodingType.ZLIB.getId()) { 
-                // recompress into ZREE
-                // uncompressed result is remain in bytes
-                ByteBuffer len = multicastqueue.allocate(4);
-                reader.readBytes(len.array(), 0, 4);
-                len.limit(4);
-                ByteBuffer inputData = multicastqueue.allocate(dataLen - 20);
-                reader.readBytes(inputData.array(), 0, inputData.capacity());
-                inputData.limit(dataLen - 20);
-                LinkedList<ByteBuffer> inputs = new LinkedList<ByteBuffer>();
-                inputs.add(inputData);
-
-                header.putInt(12, EncodingType.ZRLEE.getId()); // 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>();
-                try {
-                    unzip(inflater, inputs, 0, bytes, INFLATE_BUFSIZE);
-                    // dump32(inputs);
-                    out.add(ByteBuffer.wrap(bytes));
-                    int len2 = zip(nDeflater, out, 0, bufs);
-                    ByteBuffer blen = multicastqueue.allocate(4);
-                    blen.putInt(len2);
-                    blen.flip();
-                    bufs.addFirst(blen);
-                    bufs.addFirst(header);
-                    addSerialNumber(bufs);
-                    multicastqueue.put(bufs);
-                } catch (DataFormatException e) {
-                    throw new TransportException(e);
-                } catch (IOException e) {
-                    throw new TransportException(e);
-                }
-                return;
-            }
-            //    ZRLEE is already compressed
-            bufs.add(header);
-            if (dataLen > 16) {
-                ByteBuffer b = multicastqueue.allocate(dataLen - 16);
-                reader.readBytes(b.array(), 0, dataLen - 16);
-                b.limit(dataLen - 16);
-                bufs.add(b);
-            }
-            this.addSerialNumber(bufs);
-            multicastqueue.put(bufs);
-            return;
-        }
-        // It may be compressed. We can inflate here to avoid repeating clients
-        // decompressing here,
-        // but it may generate too many large data. It is better to do it in
-        // each client.
-        // But we have do inflation for all input data, so we have to do it
-        // here.
-    }
-
-	public abstract void addHostToSelectionPanel(int port, String hostname,String myHostName) ;
-
-	public void createRootSelectionPanel(CreateConnectionParam createConnectionParam) {
-		
-	}
-
-	public void setId(short id) {
-		this.id = id;
-	}
-
-	public short getId() {
-		return id;
-	}
-
-    public void setMyAddress(String myHostName) {
-        this.myAddress = myHostName;
-        
-    }
-
-    public void setLeader(boolean leader) {
-        this.leader = leader;
-    }
-
-    public boolean isLeader() {
-        return leader;
-    }
-
-    public void setTreeManager(String intf, TreeManagement clients) {
-    	interfaces.put(intf, clients);
-    }
-    
-    public TreeManagement getTreeManager(String intf) {
-        return interfaces.get(intf);
-    }
-
-    /**
-     * chnageVNCServer is called when host change.
-     * 
-     * @param vncProxyService 
-     * @param hostName
-     *            HostAddress
-     * @param width
-     *            FrameWidth
-     * @param height
-     *            FrameHeight
-     * @param id 
-     * @throws InterruptedException 
-     */
-    public void changeVNCServer(ViewerInterface vncProxyService, String hostName, int width, int height, short id)
-    		throws UnknownHostException, IOException, InterruptedException {
-    	// stop reader stop
-        stopReceiverTask();
-        reconnectingId = id;
-    	vncProxyService.inhelitClients(vncProxyService, hostName);
-        // after connecting VNC server, rfb send SEND_INIT_DATA command and wakes me up if necessary 
-    	reconnecting = true;
-    	if (reconnectingId!=0) {
-    	    waitForVNCConnection();
-    	}
-    }
-
-    /**
-     * start accepting children
-     * run rootFinderListener if necessary
-     */
-    public void createConnectionAndStart(ViewerInterface v) {
-    	selectPort(ConnectionParams.DEFAULT_VNC_ROOT);
-        startTreeVncCommandListener();
-    	if(isTreeManager() && firstTime) {
-    		getCast = new TreeRootFinderListener(v);
-    		Thread thread = new Thread(getCast, "tree-root-find-listener");
-    		thread.start();
-    		firstTime = false;
-    	}
-    }
-
-	public void startTreeVncCommandListener() {
-        acceptThread = new TreeVncCommandChannelListener(this, getAcceptPort());
-    	Thread thread = new Thread(acceptThread, "TreeVNC-accept");
-    	thread.start();
-    }
-
-    public TreeVncCommandChannelListener getAcceptThread() {
-        return acceptThread;
-    }
-
-    public void setConnectionParam(CreateConnectionParam createConnectionParam) {
-        cp =  createConnectionParam;
-    }
-
-    public CreateConnectionParam getConnectionParam() {
-        return cp;
-    }
-
-    public boolean hasViewer() {
-        return hasViewer;
-    }
-
-    public void setHasViewer(boolean b) {
-        hasViewer = b;
-    }
-
-    public void setReconnecting(boolean b) {
-        reconnecting = b;
-    }
-
-	public int getReconnectingId() {
-		return reconnectingId;
-	}
-	
-
-	public void setShowTree(boolean showTree) {
-		showTreeNode  = showTree;
-	}
-
-	
-}
--- a/src/main/java/jp/ac/u_ryukyu/treevnc/RequestScreenThread.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/treevnc/RequestScreenThread.java	Wed Jul 02 18:14:20 2014 +0900
@@ -3,10 +3,10 @@
 import com.glavsoft.rfb.protocol.Protocol;
 
 public class RequestScreenThread implements Runnable {
-	public MyRfbProto rfb;
+	public TreeRFBProto rfb;
 	Protocol protocol;
 
-	public RequestScreenThread(MyRfbProto _rfb) {
+	public RequestScreenThread(TreeRFBProto _rfb) {
 		rfb = _rfb;
 	}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/ac/u_ryukyu/treevnc/TreeRFBProto.java	Wed Jul 02 18:14:20 2014 +0900
@@ -0,0 +1,721 @@
+package jp.ac.u_ryukyu.treevnc;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.BindException;
+import java.net.NetworkInterface;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.LinkedList;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.client.ClientToServerMessage;
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.rfb.protocol.Protocol;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+import com.glavsoft.viewer.ViewerInterface;
+import com.glavsoft.viewer.swing.ConnectionParams;
+
+
+public class TreeRFBProto {
+	final static int FramebufferUpdateRequest = 3;
+	final static int CheckDelay = 11;
+	protected final static int FramebufferUpdate = 0;
+	protected ProtocolContext context;
+	private int clients = 0;
+	public MulticastQueue<LinkedList<ByteBuffer>> multicastqueue = new MulticastQueue<LinkedList<ByteBuffer>>();
+	private RequestScreenThread rThread;
+	public int acceptPort = 0;
+    private String myAddress;
+	protected boolean readyReconnect = false;
+	private boolean cuiVersion;
+	private long counter = 0; // packet serial number
+    public ServerSocket servSock;
+    private boolean permitChangeScreen = true;
+    private static final int INFLATE_BUFSIZE = 1024 * 100;
+
+    private Inflater inflater = new Inflater();
+    private Deflater deflater = new Deflater();
+    ViewerInterface viewer;
+	private short id;  // my tree node id ( = 0 in root )
+    private boolean leader;
+    private TreeVncCommandChannelListener acceptThread;
+    private boolean firstTime = true;
+    private TreeRootFinderListener getCast;
+    private CreateConnectionParam cp;
+    private boolean hasViewer = false;
+	public boolean showTreeNode = false;
+    private boolean reconnecting;
+    private short reconnectingId;  // Change Server Request to id's node VNC server
+    private TreeVNCNetwork nets = new TreeVNCNetwork();
+
+	private boolean normalTermination;
+	private TreeVncRootSelectionPanel rootSelectionPanel;
+	private boolean isTreeManager;
+	private String vncInterface;
+
+	public TreeRFBProto(boolean isTreeManager) {
+		rThread = new RequestScreenThread(this);
+		nets.setMyRfb(this);
+		this.isTreeManager = isTreeManager;
+	}
+	
+	public boolean isTreeManager() {
+		return isTreeManager;
+	}
+	
+	public ProtocolContext getContext() {
+		return context;
+	}
+	
+	/**
+	 * handle new client accept 
+	 *     it also handle TreeVNC Command
+	 * @param acceptThread
+	 * @param newCli
+	 * @param os
+	 * @param is
+	 * @throws IOException
+	 * @throws TransportException
+	 */
+	public void newClient(final Socket newCli,final Writer os, final Reader is) { 
+
+		final int myId = clients;
+		final MulticastQueue.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 = 50000 / 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, "timer-discard-multicastqueue").start();
+		/**
+		 * handle command from lower node
+		 */
+		final Runnable reader = new Runnable() {
+
+            public void run() {
+				for (;;) {
+					try {
+		                final byte b[] = new byte[4096];
+						final int c = is.readByte(b);
+						if (c <= 0)
+							throw new IOException();
+						if (isTreeManager()) {
+							if (b[0] == ClientToServerMessage.SERVER_CHANGE_REQUEST) {
+								if (permitChangeScreen()) {
+									ByteBuffer buf = ByteBuffer.wrap(b);
+									buf.order(ByteOrder.BIG_ENDIAN);
+								    short id = buf.getShort(2);
+									int length = buf.getInt(4);
+									if (length == 0) 
+										continue;
+				                	String newHostName = new String(b, 8, length);
+				                	System.out.println("Root server change request :" + newHostName);
+									// please remove these numbers.
+				                	if (viewer != null) {
+					                    changeVNCServer(viewer, newHostName, 3200, 1980, id);				                		
+				                	}
+				                } else {
+				                    continue;
+				                }
+							}
+						} else if (b[0] == ClientToServerMessage.SERVER_CHANGE_REQUEST) {
+						    ClientToServerMessage sc = new ClientToServerMessage() {
+                                @Override
+                                public void send(Writer writer)
+                                        throws TransportException {
+                                    writer.write(b,0,c);
+                                }
+						    };
+							context.sendMessage(sc);
+						}
+						// System.out.println("client read "+c);
+					} catch (Exception e) {
+						try {
+							writerRunning.set(2);
+							os.close();
+							is.close();
+							break;
+						} catch (IOException e1) {
+						} catch (TransportException e1) {
+							e1.printStackTrace();
+						}
+						return;
+					}
+				}
+			}
+
+		};
+		/**
+		 * send packets to a client (one thread for each client )
+		 */
+		Runnable sender = new Runnable() {
+			public void run() {
+				writerRunning.set(1);
+				try {
+					requestThreadNotify();
+
+					// after this, we discard upward packet.
+					new Thread(reader, "upward-packet-processing").start(); 
+
+					for (;;) {
+						LinkedList<ByteBuffer> bufs = c.poll();
+						int inputIndex = 0;
+						ByteBuffer header = bufs.get(inputIndex);
+						if (header == null)
+							continue;
+						else if (header.get(0) == CheckDelay) {
+							writeToClient(os, bufs, inputIndex);
+							continue;
+						} else if (header.get(0) == FramebufferUpdate) {
+							 //System.out.println("client "+ myId);
+						}
+						/*
+						 * if(i%20==0){ sendDataCheckDelay(); } i++;
+						 */
+						writeToClient(os, bufs, inputIndex);
+						writerRunning.set(1); // yes my client is awaking.
+					}
+				} catch (Exception e) {
+					try {
+						writerRunning.set(2);
+						os.close();
+					} catch (IOException e1) {
+						System.out.println("root writer close faild :" + e1);
+					}
+					System.out.println("root writer faild :" + e);
+					/* if socket closed cliList.remove(newCli); */
+				}
+			}
+
+			public void writeToClient(final Writer os,
+					LinkedList<ByteBuffer> bufs, int inputIndex)
+					throws TransportException {
+				while (inputIndex < bufs.size()) {
+					ByteBuffer b = bufs.get(inputIndex++);
+					os.write(b.array(), b.position(), b.limit());
+				}
+				os.flush();
+				bufs = null;
+				multicastqueue.heapAvailable();
+			}
+		};
+		clients++;
+		new Thread(sender, "writer-to-lower-node").start();
+
+	}
+
+	
+
+    public boolean permitChangeScreen() {
+        return permitChangeScreen;
+    }
+    
+
+    public void setPermitChangeScreen(boolean v) {
+         permitChangeScreen = v;
+    }
+    
+	public void requestThreadNotify() {
+		rThread.reStart();
+	}
+	
+	
+    public void setProtocolContext(Protocol workingProtocol) {
+        context = workingProtocol;
+    }
+
+    public Socket accept() throws IOException {
+        return servSock.accept();
+    }
+
+    public int selectPort(int p) {
+        int port = p;
+        while (true) {
+            try {
+                servSock = new ServerSocket(port);
+                acceptPort = port;
+                myAddress = "127.0.0.1";
+                nets.getNetworkInterfaces();
+                break;
+            } catch (BindException e) {
+                port++;
+                continue;
+            } catch (IOException e) {
+
+            }
+        }
+        System.out.println("accept port = " + port);
+        return port;
+    }
+
+
+
+	public void writeFramebufferUpdateRequest(int x, int y, int w, int h,
+			boolean incremental) throws TransportException {
+		byte[] b = new byte[10];
+
+		b[0] = (byte) FramebufferUpdateRequest; // 3 is 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);
+	}
+	
+	public void setViewer(ViewerInterface v) {
+		viewer = v;
+	}
+	
+	public ViewerInterface getViewer() {
+		return viewer;
+	}
+
+
+	void sendInitData(OutputStream os) throws IOException {
+		os.write(context.getInitData());
+	}
+
+	
+	public void setTerminationType(boolean setType) {
+		normalTermination = setType;
+	}
+	
+	public boolean getTerminationType() {
+		return normalTermination;
+	}
+	
+	
+	public void addHostToSelectionPanel(int port, String hostname,String myHostName) {
+		if (rootSelectionPanel != null) {
+			rootSelectionPanel.checkBox(Integer.toString(port) + ":" + hostname + ":" + myHostName);
+			rootSelectionPanel.setButton();
+			rootSelectionPanel.visible();			
+		}
+	}
+	
+	public void createRootSelectionPanel(CreateConnectionParam cp) {
+		rootSelectionPanel = new TreeVncRootSelectionPanel();
+		rootSelectionPanel.setCp(cp);
+	}
+	
+    public void close() {
+	    // none
+	}
+	
+	public int getAcceptPort() {
+		return acceptPort;
+	}
+	
+	public boolean getReadyReconnect() {
+		return readyReconnect;
+	}
+
+
+	public boolean getCuiVersion() {
+		return cuiVersion;
+	} 
+	
+	public void  setCuiVersion(boolean flag) {
+		cuiVersion = flag;
+	}
+
+	public void readCheckDelay(Reader reader) throws TransportException {
+		
+	}
+
+	public synchronized void vncConnected(boolean ready) {
+	    if (ready && reconnecting) {
+	    	Socket vncSocket = viewer.getVNCSocket();
+	    	NetworkInterface ni = nets.getInterface(vncSocket);
+	    	if (ni!=null) {
+	    		vncInterface = ni.getName();
+	    		System.out.println("VNCNetworkInterface :" + vncInterface);
+	    	}
+	        sendDesktopSizeChange(reconnectingId);
+	        reconnecting = false;
+	        if (reconnectingId == 0) {
+	        	viewer.setVisible(false);
+	        }
+	    } 
+	    if (reconnectingId!=0) {
+	        readyReconnect = ready;
+	        if (ready) {
+	            notifyAll();
+	        }
+	    }
+	}	
+
+
+	public synchronized void waitForVNCConnection() throws InterruptedException {
+	    if (reconnectingId!=0) {
+	        while (!readyReconnect) {
+	            wait();
+	        }
+	    }
+	}
+
+
+	public void sendDesktopSizeChange(short id) {
+		LinkedList<ByteBuffer> desktopSize = new LinkedList<ByteBuffer>();
+		int width = context.getFbWidth();
+		int height = context.getFbHeight();
+		desktopSize.add(new UpdateRectangleMessage(width, height, EncodingType.INIT_DATA, context.getInitData(),id).getMessage());
+		addSerialNumber(desktopSize);
+		multicastqueue.put(desktopSize);
+	}
+
+
+	public void addSerialNumber(LinkedList<ByteBuffer> bufs) {
+		ByteBuffer serialNum = multicastqueue.allocate(8);
+		serialNum.putLong(counter++);
+		serialNum.flip();
+		bufs.addFirst(serialNum);
+	}
+
+
+    public void resetDecoder() {
+        context.resetDecoder();
+    }
+
+    public void stopReceiverTask() {
+        if (context!=null)
+            context.cleanUpSession(null);
+        // cleanup zlib decoder for new VNCServer
+        if (isTreeManager())
+            inflater = new Inflater();
+    }
+
+    public String getMyAddress() {
+        return myAddress;
+    }
+
+    /**
+     * gzip byte arrays
+     * 
+     * @param deflater
+     * @param inputs
+     *            byte data[]
+     * @param inputIndex
+     * @param outputs
+     *            byte data[]
+     * @return byte length in last byte array
+     * @throws IOException
+     */
+    public int zip(Deflater deflater, LinkedList<ByteBuffer> inputs,
+            int inputIndex, LinkedList<ByteBuffer> outputs) throws IOException {
+        int len = 0;
+        ByteBuffer c1 = multicastqueue.allocate(INFLATE_BUFSIZE);
+        while (inputIndex < inputs.size()) {
+            ByteBuffer b1 = inputs.get(inputIndex++);
+            deflater.setInput(b1.array(), b1.position(), b1.remaining());
+            /**
+             * 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 {
+                len1 = deflater.deflate(c1.array(), c1.position(),
+                        c1.remaining());
+                if (len1 > 0) {
+                    len += len1;
+                    c1.position(c1.position() + len1);
+                    if (c1.remaining() == 0) {
+                        c1.flip();
+                        outputs.addLast(c1);
+                        c1 = multicastqueue.allocate(INFLATE_BUFSIZE);
+                    }
+                }
+            } while (len1 > 0 || !deflater.needsInput()); // &&!deflater.finished());
+        }
+        if (c1.position() != 0) {
+            c1.flip();
+            outputs.addLast(c1);
+        }
+        deflater.reset();
+        return len;
+    }
+
+    /**
+     * gunzip byte arrays
+     * 
+     * @param inflater
+     * @param inputs
+     *            byte data[]
+     * @param bytes
+     *            byte data[]
+     * @return number of total bytes
+     * @throws IOException
+     */
+    public int unzip(Inflater inflater, LinkedList<ByteBuffer> inputs,
+            int inputIndex, byte[] bytes, int bufSize)
+            throws DataFormatException {
+        int position = 0;
+        int limit = bytes.length;
+        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(bytes, position,
+                        limit-position);
+                if (len0 > 0) {
+                	position += len0;
+                    if (position > limit) {
+                    	throw new DataFormatException();
+                    }
+                }
+            } while (!inflater.needsInput());
+        }
+        return position;
+    }
+
+    /**
+     * read FrameBuffferUpdate. If it is ZLE, make it ZLEE which is self contained compressed packet.
+     * put the packet to the multicastqueue. Then normal rendering engine read the same stream using is.reset().
+     * @param dataLen
+     * @param reader
+     * @throws TransportException
+     */
+    public void readSendData(int dataLen, Reader reader, byte[] bytes)
+            throws TransportException {
+        LinkedList<ByteBuffer> bufs = new LinkedList<ByteBuffer>();
+        ByteBuffer header = multicastqueue.allocate(16);
+        ByteBuffer serial = multicastqueue.allocate(8);
+        if (!isTreeManager()) {
+            reader.readBytes(serial.array(),0,8);
+            serial.limit(8);
+        }
+        reader.mark(dataLen);
+        reader.readBytes(header.array(), 0, 16);
+        header.limit(16);
+        if (header.get(0) == FramebufferUpdate) {
+            int encoding = header.getInt(12);
+            if (encoding == EncodingType.ZRLE.getId()
+                    || encoding == EncodingType.ZLIB.getId()) { 
+                // recompress into ZREE
+                // uncompressed result is remain in bytes
+                ByteBuffer len = multicastqueue.allocate(4);
+                reader.readBytes(len.array(), 0, 4);
+                len.limit(4);
+                ByteBuffer inputData = multicastqueue.allocate(dataLen - 20);
+                reader.readBytes(inputData.array(), 0, inputData.capacity());
+                inputData.limit(dataLen - 20);
+                LinkedList<ByteBuffer> inputs = new LinkedList<ByteBuffer>();
+                inputs.add(inputData);
+
+                header.putInt(12, EncodingType.ZRLEE.getId()); // 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>();
+                try {
+                    unzip(inflater, inputs, 0, bytes, INFLATE_BUFSIZE);
+                    // dump32(inputs);
+                    out.add(ByteBuffer.wrap(bytes));
+                    int len2 = zip(nDeflater, out, 0, bufs);
+                    ByteBuffer blen = multicastqueue.allocate(4);
+                    blen.putInt(len2);
+                    blen.flip();
+                    bufs.addFirst(blen);
+                    bufs.addFirst(header);
+                    addSerialNumber(bufs);
+                    multicastqueue.put(bufs);
+                } catch (DataFormatException e) {
+                    throw new TransportException(e);
+                } catch (IOException e) {
+                    throw new TransportException(e);
+                }
+                return;
+            }
+            //    ZRLEE is already compressed
+            bufs.add(header);
+            if (dataLen > 16) {
+                ByteBuffer b = multicastqueue.allocate(dataLen - 16);
+                reader.readBytes(b.array(), 0, dataLen - 16);
+                b.limit(dataLen - 16);
+                bufs.add(b);
+            }
+            this.addSerialNumber(bufs);
+            multicastqueue.put(bufs);
+            return;
+        }
+        // It may be compressed. We can inflate here to avoid repeating clients
+        // decompressing here,
+        // but it may generate too many large data. It is better to do it in
+        // each client.
+        // But we have do inflation for all input data, so we have to do it
+        // here.
+    }
+
+	public void setId(short id) {
+		this.id = id;
+	}
+
+	public short getId() {
+		return id;
+	}
+
+    public void setMyAddress(String myHostName) {
+        this.myAddress = myHostName;
+        
+    }
+
+    public void setLeader(boolean leader) {
+        this.leader = leader;
+    }
+
+    public boolean isLeader() {
+        return leader;
+    }
+
+    public void setTreeManager(String intf, TreeManagement clients) {
+    		nets.setTreeManager(intf, clients);
+    }
+    
+    public TreeManagement getTreeManager(String intf) {
+        return nets.getTreeManager(intf);
+    }
+
+    /**
+     * chnageVNCServer is called when host change.
+     * 
+     * @param vncProxyService 
+     * @param hostName
+     *            HostAddress
+     * @param width
+     *            FrameWidth
+     * @param height
+     *            FrameHeight
+     * @param id 
+     * @throws InterruptedException 
+     */
+    public void changeVNCServer(ViewerInterface vncProxyService, String hostName, int width, int height, short id)
+    		throws UnknownHostException, IOException, InterruptedException {
+    	// stop reader stop
+        stopReceiverTask();
+        reconnectingId = id;
+    	vncProxyService.inhelitClients(vncProxyService, hostName);
+        // after connecting VNC server, rfb send SEND_INIT_DATA command and wakes me up if necessary 
+    	reconnecting = true;
+    	if (reconnectingId!=0) {
+    	    waitForVNCConnection();
+    	}
+    }
+
+    /**
+     * start accepting children
+     * run rootFinderListener if necessary
+     */
+    public void createConnectionAndStart(ViewerInterface v) {
+    	selectPort(ConnectionParams.DEFAULT_VNC_ROOT);
+        startTreeVncCommandListener();
+    	if(isTreeManager() && firstTime) {
+    		getCast = new TreeRootFinderListener(v);
+    		Thread thread = new Thread(getCast, "tree-root-find-listener");
+    		thread.start();
+    		firstTime = false;
+    	}
+    }
+
+	public void startTreeVncCommandListener() {
+        acceptThread = new TreeVncCommandChannelListener(this, getAcceptPort());
+    	Thread thread = new Thread(acceptThread, "TreeVNC-accept");
+    	thread.start();
+    }
+
+    public TreeVncCommandChannelListener getAcceptThread() {
+        return acceptThread;
+    }
+
+    public void setConnectionParam(CreateConnectionParam createConnectionParam) {
+        cp =  createConnectionParam;
+    }
+
+    public CreateConnectionParam getConnectionParam() {
+        return cp;
+    }
+
+    public boolean hasViewer() {
+        return hasViewer;
+    }
+
+    public void setHasViewer(boolean b) {
+        hasViewer = b;
+    }
+
+    public void setReconnecting(boolean b) {
+        reconnecting = b;
+    }
+
+	public int getReconnectingId() {
+		return reconnectingId;
+	}
+	
+
+	public void setShowTree(boolean showTree) {
+		showTreeNode  = showTree;
+	}
+
+	
+}
--- a/src/main/java/jp/ac/u_ryukyu/treevnc/TreeVNCNetwork.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/treevnc/TreeVNCNetwork.java	Wed Jul 02 18:14:20 2014 +0900
@@ -13,13 +13,12 @@
 
     
     private HashMap<String, TreeManagement> interfaces = new HashMap<String, TreeManagement>();
-    private String vncInterface;
-    private MyRfbProto myRfb;
-    public MyRfbProto getMyRfb() {
+    private TreeRFBProto myRfb;
+    public TreeRFBProto getMyRfb() {
         return myRfb;
     }
 
-    public void setMyRfb(MyRfbProto myRfb) {
+    public void setMyRfb(TreeRFBProto myRfb) {
         this.myRfb = myRfb;
     }
 
@@ -37,7 +36,7 @@
         }
     }
     
-    private NetworkInterface getInterface(Socket vncSocket) {
+    NetworkInterface getInterface(Socket vncSocket) {
         InetAddress address = vncSocket.getInetAddress();
         try {
             return NetworkInterface.getByInetAddress(address);
@@ -47,7 +46,15 @@
     }
 
     private void addNetworkInterface(NetworkInterface ni, TreeManagement treeManager) {
-        interfaces.put(ni.getName(), treeManager);
+        setTreeManager(ni.getName(), treeManager);
     }
 
+	public void setTreeManager(String intf, TreeManagement treeManager) {
+        interfaces.put(intf, treeManager);
+	}
+
+	public TreeManagement getTreeManager(String intf) {
+		return interfaces.get(intf);
+	}
+
 }
--- a/src/main/java/jp/ac/u_ryukyu/treevnc/TreeVncCommand.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/treevnc/TreeVncCommand.java	Wed Jul 02 18:14:20 2014 +0900
@@ -10,7 +10,7 @@
 import com.glavsoft.transport.Writer;
 
 public class TreeVncCommand {
-    MyRfbProto rfb;
+    TreeRFBProto rfb;
     int port;
     String hostname;
     String myHostName;
@@ -21,7 +21,7 @@
 	private short value;
     private String intf;
 
-    public TreeVncCommand(MyRfbProto rfb,String myHostName, TreeCommand command, int port, String hostname, String intf, short value) {
+    public TreeVncCommand(TreeRFBProto rfb,String myHostName, TreeCommand command, int port, String hostname, String intf, short value) {
         this.rfb = rfb;
         this.myHostName = myHostName;
         this.hostname = hostname;
@@ -31,7 +31,7 @@
         this.value = value;
     }
 
-    public TreeVncCommand(MyRfbProto rfb, String myHostAddress, TreeCommand newNode,
+    public TreeVncCommand(TreeRFBProto rfb, String myHostAddress, TreeCommand newNode,
             Writer os, Reader is, Socket connection) {
         this.rfb = rfb;
         this.myHostName = myHostAddress; 
--- a/src/main/java/jp/ac/u_ryukyu/treevnc/TreeVncCommandChannelListener.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/main/java/jp/ac/u_ryukyu/treevnc/TreeVncCommandChannelListener.java	Wed Jul 02 18:14:20 2014 +0900
@@ -18,14 +18,14 @@
 import com.glavsoft.transport.Writer;
 
 public class TreeVncCommandChannelListener implements Runnable {
-    public MyRfbProto rfb = null;
+    public TreeRFBProto rfb = null;
     byte[] imageBytes;
     int port;
     LinkedBlockingQueue<TreeVncCommand> cmdQueue = new LinkedBlockingQueue<TreeVncCommand>();
     private Thread acceptThread;
     protected final static String versionMsg_3_856 = "RFB 003.856\n";
     
-    public TreeVncCommandChannelListener(MyRfbProto _rfb, int p) {
+    public TreeVncCommandChannelListener(TreeRFBProto _rfb, int p) {
         rfb = _rfb;
         port = p;
 
@@ -92,7 +92,7 @@
         return cmd;
     }
 
-    public TreeVncCommand initialConnection(MyRfbProto myRfbProto, final Writer os, final Reader is, Socket connection)
+    public TreeVncCommand initialConnection(TreeRFBProto myRfbProto, final Writer os, final Reader is, Socket connection)
             throws IOException, TransportException {
         /**
          * initial connection of RFB protocol
--- a/src/viewer_swing/java/com/glavsoft/viewer/CuiViewer.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/viewer_swing/java/com/glavsoft/viewer/CuiViewer.java	Wed Jul 02 18:14:20 2014 +0900
@@ -19,8 +19,7 @@
 import java.util.logging.*;
 
 import jp.ac.u_ryukyu.treevnc.CreateConnectionParam;
-import jp.ac.u_ryukyu.treevnc.MyRfbProto;
-import jp.ac.u_ryukyu.treevnc.MyRfbProtoClient;
+import jp.ac.u_ryukyu.treevnc.TreeRFBProto;
 
 public class CuiViewer implements Runnable, WindowListener, ViewerInterface {
 
@@ -35,7 +34,7 @@
 	private final ProtocolSettings settings;
 	protected UiSettings uiSettings;
 	private ConnectionPresenter connectionPresenter;
-	protected MyRfbProto myRfb;
+	protected TreeRFBProto myRfb;
 	private boolean cuiVersion;
     private boolean showTree = false;
 
@@ -211,7 +210,7 @@
 	public void startTreeViewer(String hostName, boolean cui) {
 		CuiViewer viewer = new CuiViewer();
 		viewer.cuiVersion = cui;
-		MyRfbProto rfb = new MyRfbProto(false);
+		TreeRFBProto rfb = new TreeRFBProto(false);
 		CreateConnectionParam cp = new CreateConnectionParam(rfb);
 		if (hostName==null) {     
 		    try {
@@ -232,7 +231,7 @@
 	public void setIsTreeVNC(boolean flag) {
 	}
 
-	public MyRfbProto getRfb() {
+	public TreeRFBProto getRfb() {
 		return myRfb;
 	}
 
--- a/src/viewer_swing/java/com/glavsoft/viewer/Viewer.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/viewer_swing/java/com/glavsoft/viewer/Viewer.java	Wed Jul 02 18:14:20 2014 +0900
@@ -47,10 +47,7 @@
 import java.util.logging.*;
 
 import jp.ac.u_ryukyu.treevnc.CreateConnectionParam;
-import jp.ac.u_ryukyu.treevnc.MyRfbProto;
-import jp.ac.u_ryukyu.treevnc.MyRfbProtoClient;
-import jp.ac.u_ryukyu.treevnc.MyRfbProtoProxy;
-import jp.ac.u_ryukyu.treevnc.TreeManagement;
+import jp.ac.u_ryukyu.treevnc.TreeRFBProto;
 
 @SuppressWarnings("serial")
 public class Viewer extends JApplet implements Runnable, WindowListener , ViewerInterface {
@@ -68,7 +65,7 @@
     private volatile boolean isAppletStopped = false;
     private ConnectionPresenter connectionPresenter;
     boolean isTreeVNC = false;
-    protected MyRfbProto myRfb;
+    protected TreeRFBProto myRfb;
 	private boolean noConnection;
     public int vncport = ConnectionParams.DEFAULT_RFB_PORT;
     private int fbWidth;
@@ -292,7 +289,7 @@
 	 * start TreeVNC viewer
 	 */
 	public void startTreeViewer(String hostName,boolean cui) {
-		MyRfbProto rfb = new MyRfbProto(false);
+		TreeRFBProto rfb = new TreeRFBProto(false);
 		rfb.setCuiVersion(cui);
 		rfb.setHasViewer(true);
         rfb.setViewer(this);
@@ -334,7 +331,7 @@
 		isTreeVNC = flag;
 	}
 	
-	public MyRfbProto getRfb() {
+	public TreeRFBProto getRfb() {
 		return myRfb;
 	}
 
@@ -380,7 +377,7 @@
             System.exit(0);
         }
         String hostname = "localhost";
-        MyRfbProto rfb = new MyRfbProto(true);
+        TreeRFBProto rfb = new TreeRFBProto(true);
         myRfb = rfb;
         rfb.setShowTree(showTree);
         rfb.setViewer(this);
@@ -395,7 +392,7 @@
         run();
     }
 
-    public void initRoot(MyRfbProto myRfbProto, String hostName) {
+    public void initRoot(TreeRFBProto myRfbProto, String hostName) {
         setIsTreeVNC(true);
         connectionParams.setConnectionParam(hostName, vncport);
         isApplet = true;
--- a/src/viewer_swing/java/com/glavsoft/viewer/ViewerInterface.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/viewer_swing/java/com/glavsoft/viewer/ViewerInterface.java	Wed Jul 02 18:14:20 2014 +0900
@@ -3,13 +3,13 @@
 import java.io.IOException;
 import java.net.Socket;
 
-import jp.ac.u_ryukyu.treevnc.MyRfbProto;
+import jp.ac.u_ryukyu.treevnc.TreeRFBProto;
 
 public interface ViewerInterface extends Runnable {
 
 	public boolean getCuiVersion();
 
-	public MyRfbProto getRfb();
+	public TreeRFBProto getRfb();
 
 	public void closeApp();
 
--- a/src/viewer_swing/java/com/glavsoft/viewer/swing/SwingConnectionWorkerFactory.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/SwingConnectionWorkerFactory.java	Wed Jul 02 18:14:20 2014 +0900
@@ -31,7 +31,7 @@
 
 import javax.swing.*;
 
-import jp.ac.u_ryukyu.treevnc.MyRfbProto;
+import jp.ac.u_ryukyu.treevnc.TreeRFBProto;
 
 /**
  * @author dime at tightvnc.com
@@ -42,10 +42,10 @@
     private String predefinedPassword;
     private final ConnectionPresenter presenter;
     private final SwingViewerWindowFactory viewerWindowFactory;
-    private MyRfbProto myRfb;
+    private TreeRFBProto myRfb;
 
     public SwingConnectionWorkerFactory(JFrame parentWindow, String predefinedPassword, ConnectionPresenter presenter,
-                                        SwingViewerWindowFactory viewerWindowFactory, MyRfbProto rfb) {
+                                        SwingViewerWindowFactory viewerWindowFactory, TreeRFBProto rfb) {
         this.parentWindow = parentWindow;
         this.predefinedPassword = predefinedPassword;
         this.presenter = presenter;
--- a/src/viewer_swing/java/com/glavsoft/viewer/swing/SwingRfbConnectionWorker.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/SwingRfbConnectionWorker.java	Wed Jul 02 18:14:20 2014 +0900
@@ -45,7 +45,7 @@
 import java.util.concurrent.ExecutionException;
 import java.util.logging.Logger;
 
-import jp.ac.u_ryukyu.treevnc.MyRfbProto;
+import jp.ac.u_ryukyu.treevnc.TreeRFBProto;
 
 /**
 * @author dime at tightvnc.com
@@ -64,7 +64,7 @@
     protected Socket workingSocket;
     protected ProtocolSettings rfbSettings;
     protected UiSettings uiSettings;
-    private MyRfbProto myRfb;
+    private TreeRFBProto myRfb;
 
     @Override
     public Void doInBackground() throws Exception {
@@ -87,7 +87,7 @@
     }
 
     public SwingRfbConnectionWorker(String predefinedPassword, ConnectionPresenter presenter, JFrame parentWindow,
-                                    SwingViewerWindowFactory viewerWindowFactory, MyRfbProto myRfb) {
+                                    SwingViewerWindowFactory viewerWindowFactory, TreeRFBProto myRfb) {
         this.predefinedPassword = predefinedPassword;
         this.presenter = presenter;
         this.parentWindow = parentWindow;
--- a/src/viewer_swing/java/com/glavsoft/viewer/swing/SwingViewerWindow.java	Wed Jul 02 17:58:55 2014 +0900
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/SwingViewerWindow.java	Wed Jul 02 18:14:20 2014 +0900
@@ -52,7 +52,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Logger;
 
-import jp.ac.u_ryukyu.treevnc.MyRfbProto;
+import jp.ac.u_ryukyu.treevnc.TreeRFBProto;
 import jp.ac.u_ryukyu.treevnc.ScreenChangeRequest;
 
 public class SwingViewerWindow implements IChangeSettingsListener {
@@ -217,7 +217,7 @@
 
     public void setRemoteDesktopName(String name) {
         remoteDesktopName = name;
-        MyRfbProto rfb = viewer.getRfb();
+        TreeRFBProto rfb = viewer.getRfb();
         if (rfb!=null) {
         	int port = rfb.getAcceptPort();
         	remoteDesktopName += ":" + port;