view src/myVncProxy/MyRfbProto.java @ 60:3ccedb44aaa0

merge
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sat, 09 Jul 2011 11:45:36 +0900
parents a240b19b66f0 39741f18b4f2
children 626cf8cc002c
line wrap: on
line source

package myVncProxy;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;

import javax.imageio.ImageIO;

import myVncProxy.MulticastQueue.Client;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.io.OutputStream;

class MyRfbProto extends RfbProto {

	final static String versionMsg_3_998 = "RFB 003.998\n";

	private int messageType;
	private int rectangles;
	private int rectX;
	private int rectY;
	private int rectW;
	private int rectH;
	private int encoding;
	private int zLen;
	private int dataLen;

	private ServerSocket servSock;
	private int acceptPort;
	private byte initData[];
	private LinkedList<Socket> cliListTmp;
	private LinkedList<Socket> cliList;
	private LinkedList<Thread> sendThreads;
	boolean createBimgFlag;

	ExecutorService executor;

	byte[] pngBytes;

	private MulticastQueue<byte[]> multicastqueue = new MulticastQueue<byte[]>();

	MyRfbProto(String h, int p, VncViewer v) throws IOException {
		super(h, p, v);
		cliList = new LinkedList<Socket>();
		cliListTmp = new LinkedList<Socket>();
		createBimgFlag = false;
		sendThreads = new LinkedList<Thread>();
		// executor = Executors.newCachedThreadPool();
		// executor = Executors.newSingleThreadExecutor();
	}

	MyRfbProto(String h, int p) throws IOException {
		super(h, p);
		cliList = new LinkedList<Socket>();
		cliListTmp = new LinkedList<Socket>();
		createBimgFlag = false;
		sendThreads = new LinkedList<Thread>();
		// executor = Executors.newCachedThreadPool();
		// executor = Executors.newSingleThreadExecutor();
	}

	// over write
	void writeVersionMsg() throws IOException {
		clientMajor = 3;
		if (serverMinor >= 9) {
			clientMinor = 9;
			os.write(versionMsg_3_998.getBytes());
		} else if (serverMajor > 3 || serverMinor >= 8) {
			clientMinor = 8;
			os.write(versionMsg_3_8.getBytes());
		} else if (serverMinor >= 9) {
			clientMinor = 9;
			os.write(versionMsg_3_998.getBytes());
		} else if (serverMinor >= 7) {
			clientMinor = 7;
			os.write(versionMsg_3_7.getBytes());
		} else {
			clientMinor = 3;
			os.write(versionMsg_3_3.getBytes());
		}
		protocolTightVNC = false;
		initCapabilities();
	}

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

	// 5550を開けるが、開いてないなら+1のポートを開ける。
	void selectPort() {
		int i = 5550;
		while (true) {
			try {
				initServSock(i);
				break;
			} catch (BindException e) {
				i++;
				continue;
			} catch (IOException e) {

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

	int getAcceptPort() {
		return acceptPort;
	}

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

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

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

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

	void mark(int len) throws IOException {
		is.mark(len);
	}

	void reset() throws IOException {
		is.reset();
	}

	boolean markSupported() {
		return is.markSupported();
	}

	void readServerInit() throws IOException {

		mark(255);
		skipBytes(20);
		int nlen = readU32();
		int blen = 20 + 4 + nlen;
		initData = new byte[blen];
		reset();

		mark(blen);
		readFully(initData);
		reset();

		framebufferWidth = readU16();
		framebufferHeight = readU16();
		bitsPerPixel = readU8();
		depth = readU8();
		bigEndian = (readU8() != 0);
		trueColour = (readU8() != 0);
		redMax = readU16();
		greenMax = readU16();
		blueMax = readU16();
		redShift = readU8();
		greenShift = readU8();
		blueShift = readU8();
		byte[] pad = new byte[3];
		readFully(pad);
		int nameLength = readU32();
		byte[] name = new byte[nameLength];
		readFully(name);
		desktopName = new String(name);

		// Read interaction capabilities (TightVNC protocol extensions)
		if (protocolTightVNC) {
			int nServerMessageTypes = readU16();
			int nClientMessageTypes = readU16();
			int nEncodingTypes = readU16();
			readU16();
			readCapabilityList(serverMsgCaps, nServerMessageTypes);
			readCapabilityList(clientMsgCaps, nClientMessageTypes);
			readCapabilityList(encodingCaps, nEncodingTypes);
		}

		inNormalProtocol = true;
	}

	void sendRfbVersion(OutputStream os) throws IOException {
		os.write(versionMsg_3_998.getBytes());
	}

	void readVersionMsg(InputStream is) throws IOException {

		byte[] b = new byte[12];

		is.read(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("Host " + host + " port " + port
					+ " is not an RFB server");
		}

		serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
		serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');

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

	}

	void sendSecurityType(OutputStream os) throws IOException {
		// number-of-security-types
		os.write(1);
		// security-types
		// 1:None
		os.write(1);
	}

	void readSecType(InputStream is) throws IOException {
		byte[] b = new byte[1];
		is.read(b);

	}

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

	void readClientInit(InputStream in) throws IOException {
		byte[] b = new byte[0];
		in.read(b);
	}

	void sendInitData(OutputStream os) throws IOException {
		os.write(initData);
	}

	void sendData(byte b[]) {
		try {
			multicastqueue.put(b);

			/*
			 * // for(Socket cli : cliList){ // try{ //
			 * cli.getOutputStream().write(b, 0, b.length); //
			 * }catch(IOException e){ // // if socket closed //
			 * cliList.remove(cli); // } // }
			 */
			// System.out.println("cliSize="+cliSize());
		} catch (Exception e) {
		}
	}

	void sendPngImage() {
		try {
			for (Socket cli : cliListTmp) {
				try {
					sendPngData(cli);
					addSock(cli);
				} catch (IOException e) {
					// if socket closed
					cliListTmp.remove(cli);
				}
			}
			// System.out.println("cliSize="+cliSize());
		} catch (Exception e) {
		}
		cliListTmp.clear();
	}

	boolean ready() throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		return br.ready();
	}

	int cliSize() {
		return cliList.size();
	}

	void printNumBytesRead() {
		System.out.println("numBytesRead=" + numBytesRead);
	}

	void bufResetSend(int size) throws IOException {
		reset();
		int len = size;
		if (available() < size)
			len = available();
		byte buffer[] = new byte[len];
		readFully(buffer);
		sendData(buffer);
	}

	void readSendData() throws IOException {
		byte buffer[] = new byte[dataLen];
		readFully(buffer);
		reset();

		for (Socket cli : cliList) {
			try {
				OutputStream out = cli.getOutputStream();
				executor.execute(new SendThread(out, buffer));
			} catch (IOException e) {
				// if client socket closed
				cliListTmp.remove(cli);
			} catch (Exception e) {

			}

		}
	}

	void regiFramebufferUpdate() throws IOException {
		mark(20);
		messageType = readU8();
		skipBytes(1);
		rectangles = readU16();
		rectX = readU16();
		rectY = readU16();
		rectW = readU16();
		rectH = readU16();
		encoding = readU32();
		if (encoding == 16)
			zLen = readU32();
		reset();
	}

	void checkAndMark() throws IOException {
		switch (encoding) {
		case RfbProto.EncodingRaw:
			dataLen = rectW * rectH * 4 + 16;
			mark(dataLen);
			break;
		case RfbProto.EncodingZRLE:
			dataLen = zLen + 20;
			mark(dataLen);
			break;
		default:
			mark(1000000);
		}
	}

	BufferedImage createBufferedImage(Image img) {
		BufferedImage bimg = new BufferedImage(img.getWidth(null),
				img.getHeight(null), BufferedImage.TYPE_INT_RGB);

		Graphics g = bimg.getGraphics();
		g.drawImage(img, 0, 0, null);
		g.dispose();
		return bimg;
	}

	void createPngBytes(BufferedImage bimg) throws IOException {
		pngBytes = getImageBytes(bimg, "png");
	}

	byte[] getBytes(BufferedImage img) throws IOException {
		byte[] b = getImageBytes(img, "png");
		return b;
	}

	byte[] getImageBytes(BufferedImage image, String imageFormat)
			throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		BufferedOutputStream os = new BufferedOutputStream(bos);
		image.flush();
		ImageIO.write(image, imageFormat, os);
		os.flush();
		os.close();
		return bos.toByteArray();
	}

	void sendPngData(Socket sock) throws IOException {
		byte[] dataLength = castIntByte(pngBytes.length);
		sock.getOutputStream().write(dataLength);
		sock.getOutputStream().write(pngBytes);
	}

	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;
	}

	BufferedImage createBimg() throws IOException {
		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);
		System.out.println("rectangles=" + rectangles);
		System.out.println("encoding=" + encoding);
		switch (encoding) {
		case RfbProto.EncodingRaw:
			System.out.println("rectW * rectH * 4 + 16 =" + rectW * rectH * 4
					+ 16);
			break;
		default:
		}
	}

	void newClient(acceptThread acceptThread, final Socket newCli,
			final OutputStream os, final InputStream is) throws IOException {
		// createBimgFlag = true;
		// rfb.addSockTmp(newCli);
		//		addSock(newCli);
		final Client<byte[]> c = multicastqueue.newClient();
		Runnable sender = new Runnable() {
			public void run() {
				try {
					// 初期接続確立の部分
					sendRfbVersion(os);
					readVersionMsg(is);
					sendSecurityType(os);
					readSecType(is);
					sendSecResult(os);
					readClientInit(is);
					sendInitData(os);

					for (;;) {
						byte[] b = c.poll();
						os.write(b, 0, b.length);
					}
				} catch (IOException e) {
					//接続が切れた処理
					//lockしないと駄目
					//					cliList.remove(newCli);
				}

			}

		};
		new Thread(sender).start();

	}
}