view src/main/java/jp/ac/u_ryukyu/treevnc/server/MyRfbProtoProxy.java @ 115:804b1ce07aa0

remove unnecessary code
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 26 May 2014 11:06:27 +0900
parents 84f254d8bde4
children 38e461e9b9c9
line wrap: on
line source

package jp.ac.u_ryukyu.treevnc.server;

//import static org.junit.Assert.*;
//import org.junit.Test;

import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.LinkedList;

import com.glavsoft.exceptions.TransportException;
import com.glavsoft.rfb.encoding.EncodingType;
import com.glavsoft.transport.Reader;
import com.glavsoft.transport.Writer;

import java.util.concurrent.ExecutorService;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import jp.ac.u_ryukyu.treevnc.MyRfbProto;

public class MyRfbProtoProxy extends MyRfbProto {
	/**
	 * CheckMillis is one of new msgType for RFB 3.855 and 3.856.
	 */
	final static byte SpeedCheckMillis = 4;

	// Secyrity type of OS X
	final static int SecTypeReqAccess = 32;

	// Supported authentication types
	final static int AuthAccess = 32;

	private static final int INFLATE_BUFSIZE = 1024 * 100;
	boolean printStatusFlag = false;
	long startCheckTime;

	private ServerSocket servSock;
	protected int acceptPort;
	private LinkedList<Socket> cliListTmp;
	private LinkedList<Socket> cliList;
	boolean createBimgFlag;
	boolean proxyFlag = true;
	ExecutorService executor;

	byte[] pngBytes;

	private Inflater inflater = new Inflater();
	private Deflater deflater = new Deflater();

	public RequestScreenThread rThread;
	private Thread requestThread;
	private int rangeX = 256; // screenRange XPosition
	private int rangeY = 256; // screenRange YPosition
	// private int rangeWidth = 512; // screenRange Width
	private int rangeHeight = 256; // screenRange Height

	
	public MyRfbProtoProxy() {
		rThread = new RequestScreenThread(this);
		requestThread = new Thread(rThread);
	}

	@Override
    public boolean isRoot() {
        return true;
    }
    
	public void setStream(Writer _writer) {
		// os = _writer;
	}

	void initServSock(int port) throws IOException {
		servSock = new ServerSocket(port);
		acceptPort = port;
	}

	/*
	 * default port number is 5999.
	 */
	public int selectPort(int p) {
		if (servSock != null)
			return 0;
		int port = p;
		while (true) {
			try {
				initServSock(port);
				break;
			} catch (BindException e) {
				port++;
				continue;
			} catch (IOException e) {

			}
		}
		System.out.println("accept port = " + port);
		return port;
	}

	public int getAcceptPort() {
		return acceptPort;
	}

	void setSoTimeout(int num) throws IOException {
		servSock.setSoTimeout(num);
	}

	public Socket accept() throws IOException {
		return servSock.accept();
	}

	public void socketClose() throws IOException {
		servSock.close();
	}

	void addSock(Socket sock) {
		cliList.add(sock);
	}

	void addSockTmp(Socket sock) {
		System.out.println("connected " + sock.getInetAddress());
		cliListTmp.add(sock);
	}

	synchronized void changeStatusFlag() {
		printStatusFlag = true;
	}

	void printMills() {
		if (printStatusFlag) {

			changeStatusFlag();
		} else {
			changeStatusFlag();
		}
	}

	void requestThreadStart() {
		requestThread.start();
	}

	public synchronized void requestThreadNotify() {
		rThread.reStart();
	}

	/**
	 * 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 outputs
	 *            byte data[]
	 * @return number of total bytes
	 * @throws IOException
	 */
	public int unzip(Inflater inflater, LinkedList<ByteBuffer> inputs,
			int inputIndex, LinkedList<ByteBuffer> outputs, int bufSize)
			throws DataFormatException {
		int len = 0;
		ByteBuffer buf = multicastqueue.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) {
					buf.position(buf.position() + len0);
					len += len0;
					if (buf.remaining() == 0) {
						buf.flip();
						outputs.addLast(buf);
						buf = multicastqueue.allocate(bufSize);
					}
				}
			} while (!inflater.needsInput());
		}
		if (buf.position() != 0) {
			buf.flip();
			outputs.addLast(buf);
		}
		return len;
	}

	float maxMag = 1;

	/**
	 * send data to clients
	 * 
	 * @param dataLen
	 * @param is
	 * @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.
	 * @throws TransportException
	 */
	public void readSendData(int dataLen, Reader is) throws TransportException {
		LinkedList<ByteBuffer> bufs = new LinkedList<ByteBuffer>();
		ByteBuffer header = multicastqueue.allocate(16);
		is.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()) { // ZRLEE is
																// already
				// recompressed
				ByteBuffer len = multicastqueue.allocate(4);
				is.readBytes(len.array(), 0, 4);
				len.limit(4);
				ByteBuffer inputData = multicastqueue.allocate(dataLen - 20);

				is.readBytes(inputData.array(), 0, inputData.capacity());
				// System.out.println(dataLen);
				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>();
				//List<ByteBuffer> out = java.util.Collections.synchronizedList(new LinkedList<ByteBuffer>());
				int len2 = 0;
				try {
					unzip(inflater, inputs, 0, out, INFLATE_BUFSIZE);
					len2 = zip(nDeflater, out, 0, bufs);
					out = null;
					multicastqueue.heapAvailable();
				} catch (DataFormatException e) {
					throw new TransportException(e);
				} catch (IOException e) {
					throw new TransportException(e);
				}

				ByteBuffer blen = multicastqueue.allocate(4);
				blen.putInt(len2);
				blen.flip();
				bufs.addFirst(blen);		
				bufs.addFirst(header);
				addSerialNumber(bufs);
				multicastqueue.put(bufs);

				return;
			}
			bufs.add(header);
			if (dataLen > 16) {
				ByteBuffer b = multicastqueue.allocate(dataLen - 16);
				is.readBytes(b.array(), 0, dataLen - 16);
				b.limit(dataLen - 16);
				bufs.add(b);
			}
			multicastqueue.put(bufs);
			// is.reset();
			return;
		}
		is.reset();

		// 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 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();
	}

	/*
	 * @Test public void test1() { try { LinkedList<ByteBuffer> in = new
	 * LinkedList<ByteBuffer>(); LinkedList<ByteBuffer> out = new
	 * LinkedList<ByteBuffer>(); LinkedList<ByteBuffer> out2 = new
	 * LinkedList<ByteBuffer>(); // if (false) { // for(int i=0;i<10;i++) { //
	 * in.add(ByteBuffer.wrap("test1".getBytes())); //
	 * in.add(ByteBuffer.wrap("test2".getBytes())); //
	 * in.add(ByteBuffer.wrap("test3".getBytes())); //
	 * in.add(ByteBuffer.wrap("test44".getBytes())); // } // } else { String t =
	 * ""; for (int i = 0; i < 10; i++) { t += "test1"; t += "test2"; t +=
	 * "test3"; t += "test44"; } in.add(ByteBuffer.wrap(t.getBytes())); }
	 * 
	 * LinkedList<ByteBuffer> in1 = clone(in);
	 * 
	 * Deflater deflater = new Deflater(); zip(deflater, in, 0, out); //
	 * LinkedList<ByteBuffer> out3 = clone(out); zipped result is depend // on
	 * deflator's state unzip(inflater, out, 0, out2, INFLATE_BUFSIZE); //
	 * inflater.reset(); equalByteBuffers(in1, out2); LinkedList<ByteBuffer>
	 * out4 = new LinkedList<ByteBuffer>(); deflater = new Deflater();
	 * zip(deflater, out2, 0, out4); LinkedList<ByteBuffer> out5 = new
	 * LinkedList<ByteBuffer>(); unzip(inflater, out4, 0, out5,
	 * INFLATE_BUFSIZE); int len = equalByteBuffers(in1, out5);
	 * 
	 * System.out.println("Test Ok. " + len); } catch (Exception e) {
	 * assertEquals(0, 1); } }
	 */

	/*
	 * public int equalByteBuffers(LinkedList<ByteBuffer> in,
	 * LinkedList<ByteBuffer> out2) { int len = 0; Iterable<Byte> i =
	 * byteBufferIterator(in); Iterator<Byte> o =
	 * byteBufferIterator(out2).iterator();
	 * 
	 * for (int b : i) { len++; if (o.hasNext()) { int c = o.next();
	 * assertEquals(b, c); } else assertEquals(0, 1); } if (o.hasNext())
	 * assertEquals(0, 1); // System.out.println(); return len; }
	 */

	void sendRfbVersion(Writer writer) throws IOException, TransportException {
		// os.write(versionMsg_3_8.getBytes());
		writer.write(versionMsg_3_856.getBytes());
	}

	int readVersionMsg(Reader reader, Writer writer) throws IOException,
			TransportException {

		byte[] b = new byte[12];

		reader.readBytes(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 IOException("this is not an RFB server");
		}

		int rfbMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
		int rfbMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');

		if (rfbMajor < 3) {
			throw new IOException(
					"RFB server does not support protocol version 3");
		}

		if (rfbMinor == 855) {
			sendProxyFlag(writer);
			if (proxyFlag)
				sendPortNumber(writer);
		}
		return rfbMinor;
	}

	void sendProxyFlag(Writer writer) throws TransportException {
		if (proxyFlag)
			writer.writeInt(1);
		else
			writer.writeInt(0);
	}

	void sendPortNumber(Writer writer) throws TransportException {
		byte[] b = new byte[4];
		// b = castIntByte(getHost.getPort());
		b = castIntByte(9999);
		writer.write(b);
	}

	void sendSecurityType(Writer os) throws TransportException {
		// number-of-security-types
		os.writeInt(1);
		// security-types
		// 1:None
		os.writeInt(1);

		/*
		 * os.write(4); os.write(30); os.write(31); os.write(32); os.write(35);
		 * os.flush();
		 */
	}

	void readSecType(Reader reader) throws TransportException {
		byte[] b = new byte[1];
		reader.read(b);
	}

	

	void sendSecResult(Writer os) throws TransportException {
		byte[] b = castIntByte(0);
		os.write(b);
	}

	byte[] castIntByte(int len) {
		byte[] b = new byte[4];
		b[0] = (byte) ((len >>> 24) & 0xFF);
		b[1] = (byte) ((len >>> 16) & 0xFF);
		b[2] = (byte) ((len >>> 8) & 0xFF);
		b[3] = (byte) ((len >>> 0) & 0xFF);
		return b;
	}

	void readClientInit(Reader in) throws TransportException {
		byte[] b = new byte[0];
		in.readBytes(b);
	}
	
	@Override
	public boolean getReadyReconnect() {
		return readyReconnect;
	}
	

	

	@SuppressWarnings("unused")
    private void testScreenSize(LinkedList<ByteBuffer> list, ByteBuffer header) {
		int block = (64*64*3)+1; // size of one-block.
		int skip; // skip-byte
		int xBlock = (header.getShort(8)-header.getShort(4))/64; //xBlockNum
		int yBlock = (header.getShort(10)-header.getShort(6))/64; // yBlockNum;
		int outOfRangeT = (rangeY - header.getShort(6))/64 > 0 ? (rangeY - header.getShort(6))/64 : 0;
		int outOfRangeB = (header.getShort(6) + header.getShort(10))-(rangeY + rangeHeight)/64 > 0 ?
				(header.getShort(6) + header.getShort(10))-(rangeY + rangeHeight)/64 : 0;
		int outOfRangeL = (rangeX - header.getShort(4))/64 > 0 ? (rangeY - header.getShort(4))/64 : 0;
		int outOfRangeR = (header.getShort(4) + header.getShort(8))-(rangeY + rangeHeight)/64 > 0 ?
				(header.getShort(4) + header.getShort(8))-(rangeY + rangeHeight)/64 : 0;
		ByteBuffer input = list.getFirst();
		if((header.getShort(8)-header.getShort(4)%64)!=0)
			++xBlock;
		if((header.getShort(10)-header.getShort(6)%64)!=0)
			++yBlock;
		
		for(int i=0; i<yBlock; i++) {
			for(int g=0; g<xBlock; g++) {
				if(outOfRangeT < i && i < yBlock - outOfRangeB) {
					input.get(block);
				}
			}
		}
		if((rangeX-header.getShort(4))%64==0)
			skip = 4*block*(header.getShort(8)/64);
		else 
			skip =  (4*block*(header.getShort(8)/64))+1;
		

	}
	
	@SuppressWarnings("unused")
    private void createHeader(ByteBuffer buf) {
			buf.putShort(4, (short)256);	
			buf.putShort(6, (short)256);
			buf.putShort(8, (short)512);	
			buf.putShort(10, (short)256);
	}


	@Override
    public void stopReceiverTask() {
	    super.stopReceiverTask();
	    inflater = new Inflater();
	}
}