view src/main/java/com/glavsoft/rfb/protocol/Protocol.java @ 35:1b81deb0abb3

write a little part reconnection.
author one
date Wed, 12 Sep 2012 13:16:47 +0900
parents 758d025ee24b
children b0c7fad4c695
line wrap: on
line source

// Copyright (C) 2010, 2011 GlavSoft LLC.
// All rights reserved.
//
//-------------------------------------------------------------------------
// This file is part of the TightVNC software.  Please visit our Web site:
//
//                       http://www.tightvnc.com/
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//-------------------------------------------------------------------------
//

package com.glavsoft.rfb.protocol;

import com.glavsoft.core.SettingsChangedEvent;
import com.glavsoft.exceptions.*;
import com.glavsoft.rfb.*;
import com.glavsoft.rfb.client.ClientToServerMessage;
import com.glavsoft.rfb.client.FramebufferUpdateRequestMessage;
import com.glavsoft.rfb.client.SetEncodingsMessage;
import com.glavsoft.rfb.client.SetPixelFormatMessage;
import com.glavsoft.rfb.encoding.PixelFormat;
import com.glavsoft.rfb.encoding.decoder.DecodersContainer;
import com.glavsoft.rfb.protocol.state.HandshakeState;
import com.glavsoft.rfb.protocol.state.ProtocolState;
import com.glavsoft.transport.Reader;
import com.glavsoft.transport.Writer;
import com.glavsoft.viewer.swing.ClipboardControllerImpl;
import com.glavsoft.viewer.swing.Surface;

import java.util.logging.Logger;

import jp.ac.u_ryukyu.treevnc.MyRfbProto;
import jp.ac.u_ryukyu.treevnc.server.MyRfbProtoProxy;
import jp.ac.u_ryukyu.treevnc.server.VncProxyService;

public class Protocol implements ProtocolContext, IChangeSettingsListener {
	private ProtocolState state;
	private final Logger logger = Logger.getLogger("com.glavsoft.rfb.protocol");
	private final IPasswordRetriever passwordRetriever;
	private final ProtocolSettings settings;
	private int fbWidth;
	private int fbHeight;
	private PixelFormat pixelFormat;
	private final Reader reader;
	private final Writer writer;
	private String remoteDesctopName;
	private MessageQueue messageQueue;
	private final DecodersContainer decoders;
	private SenderTask senderTask;
	private ReceiverTask receiverTask;
	private IRfbSessionListener rfbSessionListener;
	private IRepaintController repaintController;
	private PixelFormat serverPixelFormat;
	private Thread senderThread;
	private Thread receiverThread;
	private byte[] initData;

	public Protocol(Reader reader, Writer writer,
			IPasswordRetriever passwordRetriever, ProtocolSettings settings) {
		this.reader = reader;
		this.writer = writer;
		this.passwordRetriever = passwordRetriever;
		this.settings = settings;
		decoders = new DecodersContainer();
		decoders.instantiateDecodersWhenNeeded(settings.encodings);
		state = new HandshakeState(this);
	}

	@Override
	public void changeStateTo(ProtocolState state) {
		this.state = state;
	}

	public void handshake() throws UnsupportedProtocolVersionException, UnsupportedSecurityTypeException,
			AuthenticationFailedException, TransportException, FatalException {
		while (state.next()) {
			continue;
		}
		this.messageQueue = new MessageQueue();
	}
	
	@Override
	public PixelFormat getPixelFormat() {
		return pixelFormat;
	}

	@Override
	public void setPixelFormat(PixelFormat pixelFormat) {
		this.pixelFormat = pixelFormat;
		if (repaintController != null) {
			repaintController.setPixelFormat(pixelFormat);
		}
	}

	@Override
	public String getRemoteDesktopName() {
		return remoteDesctopName;
	}

	@Override
	public void setRemoteDesktopName(String name) {
		remoteDesctopName = name;
	}

	@Override
	public int getFbWidth() {
		return fbWidth;
	}

	@Override
	public void setFbWidth(int fbWidth) {
		this.fbWidth = fbWidth;
	}

	@Override
	public int getFbHeight() {
		return fbHeight;
	}

	@Override 
	public byte[] getInitData() {
		return initData;
	}
	
	@Override
	public void setInitData(byte[] initData) {
		this.initData = initData;
	}
	
	@Override
	public void setFbHeight(int fbHeight) {
		this.fbHeight = fbHeight;
	}

	@Override
	public IPasswordRetriever getPasswordRetriever() {
		return passwordRetriever;
	}

	@Override
	public ProtocolSettings getSettings() {
		return settings;
	}

	@Override
	public Logger getLogger() {
		return logger;
	}

	@Override
	public Writer getWriter() {
		return writer;
	}

	@Override
	public Reader getReader() {
		return reader;
	}

	/**
	 * Following the server initialisation message it's up to the client to send
	 * whichever protocol messages it wants.  Typically it will send a
	 * SetPixelFormat message and a SetEncodings message, followed by a
	 * FramebufferUpdateRequest.  From then on the server will send
	 * FramebufferUpdate messages in response to the client's
	 * FramebufferUpdateRequest messages.  The client should send
	 * FramebufferUpdateRequest messages with incremental set to true when it has
	 * finished processing one FramebufferUpdate and is ready to process another.
	 * With a fast client, the rate at which FramebufferUpdateRequests are sent
	 * should be regulated to avoid hogging the network.
	 */
	public void startNormalHandling(IRfbSessionListener rfbSessionListener,
			IRepaintController repaintController, ClipboardController clipboardController) {
		this.rfbSessionListener = rfbSessionListener;
		this.repaintController = repaintController;
//		if (settings.getBitsPerPixel() == 0) {
//			settings.setBitsPerPixel(pixelFormat.bitsPerPixel); // the same the server sent when not initialized yet
//		}
		serverPixelFormat = pixelFormat;
		serverPixelFormat.trueColourFlag = 1; // correct flag - we don't support color maps
		setPixelFormat(createPixelFormat(settings));
		sendMessage(new SetPixelFormatMessage(pixelFormat));
		logger.fine("sent: "+pixelFormat);

		sendSupportedEncodingsMessage(settings);
		settings.addListener(this); // to support pixel format (color depth), and encodings changes
		settings.addListener(repaintController);

		sendRefreshMessage();
		senderTask = new SenderTask(messageQueue, writer, this);
		senderThread = new Thread(senderTask);
		senderThread.start();
		decoders.resetDecoders();
		receiverTask = new ReceiverTask(
				reader, repaintController,
				clipboardController,
				decoders, this);
		receiverThread = new Thread(receiverTask);
		receiverThread.start();
	}

	@Override
	public void sendMessage(ClientToServerMessage message) {
		messageQueue.put(message);
	}

	private void sendSupportedEncodingsMessage(ProtocolSettings settings) {
		decoders.instantiateDecodersWhenNeeded(settings.encodings);
		SetEncodingsMessage encodingsMessage = new SetEncodingsMessage(settings.encodings);
		sendMessage(encodingsMessage);
		logger.fine("sent: " + encodingsMessage.toString());
	}

	/**
	 * create pixel format by bpp
	 */
	private PixelFormat createPixelFormat(ProtocolSettings settings) {
		int serverBigEndianFlag = serverPixelFormat.bigEndianFlag;
		switch (settings.getBitsPerPixel()) {
		case ProtocolSettings.BPP_32:
			return PixelFormat.create32bppPixelFormat(serverBigEndianFlag);
		case ProtocolSettings.BPP_16:
			return PixelFormat.create16bppPixelFormat(serverBigEndianFlag);
		case ProtocolSettings.BPP_8:
			return PixelFormat.create8bppBGRPixelFormat(serverBigEndianFlag);
		case ProtocolSettings.BPP_6:
			return PixelFormat.create6bppPixelFormat(serverBigEndianFlag);
		case ProtocolSettings.BPP_3:
			return PixelFormat.create3bppPixelFormat(serverBigEndianFlag);
		case ProtocolSettings.BPP_SERVER_SETTINGS:
			return serverPixelFormat;
		default:
			// unsupported bpp, use default
			return PixelFormat.create32bppPixelFormat(serverBigEndianFlag);
		}
	}

	@Override
	public void settingsChanged(SettingsChangedEvent e) {
		ProtocolSettings settings = (ProtocolSettings) e.getSource();
		if (settings.isChangedEncodings()) {
			sendSupportedEncodingsMessage(settings);
		}
		if (settings.changedBitsPerPixel() && receiverTask != null) {
			receiverTask.queueUpdatePixelFormat(createPixelFormat(settings));
		}
	}

	@Override
	public void sendRefreshMessage() {
		sendMessage(new FramebufferUpdateRequestMessage(0, 0, fbWidth, fbHeight, false));
		logger.fine("sent: full FB Refresh");
	}

	@Override
	public void cleanUpSession(String message) {
		cleanUpSession();
		rfbSessionListener.rfbSessionStopped(message);
	}

	public synchronized void cleanUpSession() {
		if (senderTask != null) { senderTask.stopTask(); }
		if (receiverTask != null) { receiverTask.stopTask(); }
		if (senderTask != null) {
			try {
				senderThread.join(1000);
			} catch (InterruptedException e) {
				// nop
			}
			senderTask = null;
		}
		if (receiverTask != null) {
			try {
				receiverThread.join(1000);
			} catch (InterruptedException e) {
				// nop
			}
			receiverTask = null;
		}
	}

	public void startNormalHandling(VncProxyService vncProxyService,
			Surface surface, ClipboardControllerImpl clipboardController,
			MyRfbProtoProxy rfb) 
	{
		this.rfbSessionListener = vncProxyService;
		this.repaintController = surface;
//		if (settings.getBitsPerPixel() == 0) {
//			settings.setBitsPerPixel(pixelFormat.bitsPerPixel); // the same the server sent when not initialized yet
//		}
		serverPixelFormat = pixelFormat;
		serverPixelFormat.trueColourFlag = 1; // correct flag - we don't support color maps
		setPixelFormat(createPixelFormat(settings));
		sendMessage(new SetPixelFormatMessage(pixelFormat));
		logger.fine("sent: "+pixelFormat);

		sendSupportedEncodingsMessage(settings);
		settings.addListener(this); // to support pixel format (color depth), and encodings changes
		settings.addListener(surface);

		sendRefreshMessage();
		senderTask = new SenderTask(messageQueue, writer, this);
		senderThread = new Thread(senderTask);
		senderThread.start();
		decoders.resetDecoders();
		receiverTask = new TreeTask(
				reader, repaintController,
				clipboardController,
				decoders, this, rfb);
		receiverThread = new Thread(receiverTask);
		receiverThread.start();
	}

	
	public void startTreeClientHandling(IRfbSessionListener rfbSessionListener,
			IRepaintController repaintController, 
			ClipboardController clipboardController, MyRfbProto rfb) {
		this.rfbSessionListener = rfbSessionListener;
		this.repaintController = repaintController;
//		if (settings.getBitsPerPixel() == 0) {
//			settings.setBitsPerPixel(pixelFormat.bitsPerPixel); // the same the server sent when not initialized yet
//		}
		serverPixelFormat = pixelFormat;
		serverPixelFormat.trueColourFlag = 1; // correct flag - we don't support color maps
		setPixelFormat(createPixelFormat(settings));
		sendMessage(new SetPixelFormatMessage(pixelFormat));
		logger.fine("sent: "+pixelFormat);

		sendSupportedEncodingsMessage(settings);
		settings.addListener(this); // to support pixel format (color depth), and encodings changes
		settings.addListener(repaintController);

		sendRefreshMessage();
		senderTask = new SenderTask(messageQueue, writer, this);
		senderThread = new Thread(senderTask);
		senderThread.start();
		decoders.resetDecoders();
		receiverTask = new TreeTask(
				reader, repaintController,
				clipboardController,
				decoders, this, rfb);
		receiverThread = new Thread(receiverTask);
		receiverThread.start();
	}
	
}