Mercurial > hg > Applications > TreeVNC
view src/main/java/com/glavsoft/rfb/protocol/ReceiverTask.java @ 256:dfec8bc1eb8e
fix --retina option
author | oc |
---|---|
date | Tue, 18 Nov 2014 14:10:53 +0900 |
parents | a931be447973 |
children | 11b59b223222 |
line wrap: on
line source
// Copyright (C) 2010, 2011, 2012, 2013 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.drawing.Renderer; import com.glavsoft.exceptions.CommonException; import com.glavsoft.exceptions.ProtocolException; import com.glavsoft.exceptions.TransportException; import com.glavsoft.rfb.ClipboardController; import com.glavsoft.rfb.IRepaintController; import com.glavsoft.rfb.client.FramebufferUpdateRequestMessage; import com.glavsoft.rfb.client.SetPixelFormatMessage; import com.glavsoft.rfb.encoding.EncodingType; import com.glavsoft.rfb.encoding.PixelFormat; import com.glavsoft.rfb.encoding.decoder.Decoder; import com.glavsoft.rfb.encoding.decoder.DecodersContainer; import com.glavsoft.rfb.encoding.decoder.FramebufferUpdateRectangle; import com.glavsoft.rfb.encoding.decoder.RichCursorDecoder; import com.glavsoft.rfb.encoding.decoder.ZRLEESender; import com.glavsoft.transport.Reader; import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.util.Timer; import java.util.TimerTask; import java.util.logging.Logger; import jp.ac.u_ryukyu.treevnc.CheckDelayReply; import jp.ac.u_ryukyu.treevnc.SendCheckDelay; import jp.ac.u_ryukyu.treevnc.TreeRFBProto; import jp.ac.u_ryukyu.treevnc.TreeVncProtocol; public class ReceiverTask implements Runnable { private static final byte FRAMEBUFFER_UPDATE = 0; private static final byte SET_COLOR_MAP_ENTRIES = 1; private static final byte BELL = 2; private static final byte SERVER_CUT_TEXT = 3; private static Logger logger = Logger.getLogger("com.glavsoft.rfb.protocol.ReceiverTask"); private final Reader reader; private volatile boolean isRunning = false; private Renderer renderer; private final IRepaintController repaintController; private final ClipboardController clipboardController; protected final DecodersContainer decoders; protected FramebufferUpdateRequestMessage fullscreenFbUpdateIncrementalRequest; protected final ProtocolContext context; protected PixelFormat pixelFormat; protected boolean needSendPixelFormat; private TreeRFBProto rfb; private long checkCounter = 0; private boolean firstTime = true; public int numberOfRectangles = 0; private Timer timer = null; public ReceiverTask(Reader reader, IRepaintController repaintController, ClipboardController clipboardController, DecodersContainer decoders, ProtocolContext context, TreeRFBProto _rfb) { rfb = _rfb; this.reader = reader; this.repaintController = repaintController; this.clipboardController = clipboardController; this.context = context; this.decoders = decoders; Decoder decoder = new ZRLEESender(rfb); decoders.setDecoderByType(EncodingType.ZLIB, decoder); decoders.setDecoderByType(EncodingType.ZRLE, decoder); decoders.setDecoderByType(EncodingType.ZRLEE, decoder); if(!rfb.getCuiVersion()) renderer = repaintController.createRenderer(reader, context.getFbWidth(), context.getFbHeight(),context.getPixelFormat()); fullscreenFbUpdateIncrementalRequest = new FramebufferUpdateRequestMessage(0, 0, context.getFbWidth(), context.getFbHeight(), true); if(rfb.isTreeManager()) { fullscreenFbUpdateIncrementalRequest.sendFullScreenRequest(); connectionFinished(); } } @Override public void run() { isRunning = true; while (isRunning) { try { if(! rfb.isTreeManager()) { // client has 8byte packet sequence number // add serial number flag (4byte) reader.mark(20+8+4); getLost(reader); //check seq consistency } else { reader.mark(20); } byte messageId = reader.readByte(); switch (messageId) { case FRAMEBUFFER_UPDATE: // logger.fine("Server message: FramebufferUpdate (0)"); framebufferUpdateMessage(); break; case SET_COLOR_MAP_ENTRIES: logger.severe("Server message SetColorMapEntries is not implemented. Skip."); setColorMapEntries(); break; case BELL: logger.fine("Server message: Bell"); // System.out.print("\0007"); // System.out.flush(); break; case SERVER_CUT_TEXT: logger.fine("Server message: CutText (3)"); serverCutText(); break; default: logger.severe("Unsupported server message. Id = " + messageId); } } catch (TransportException e) { logger.severe("Close session: " + e.getMessage()); if(!rfb.isTreeManager() && !(rfb.getTerminationType())) { System.out.println("task stop"); TreeVncProtocol echo = new TreeVncProtocol(rfb.getConnectionParam().getHostName(), rfb.getConnectionParam().getPort()); int counter = 3; while(counter-- > 0) { try { if (rfb.isLeader()) { echo.lostParent(rfb.getMyAddress(),rfb.getAcceptPort()); } break; } catch (Exception e1) { logger.severe("Cannot send lostHost: " + e1.getMessage()); sleep(3000); } } } stopTask(); } catch (ProtocolException e) { logger.severe(e.getMessage()); if (isRunning) { context.cleanUpSession(e.getMessage() + "\nConnection closed."); } stopTask(); } catch (CommonException e) { logger.severe(e.getMessage()); if (isRunning) { context.cleanUpSession("Connection closed.."); } stopTask(); } catch (Throwable te) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); te.printStackTrace(pw); logger.severe(te.getMessage()); if (isRunning) { context.cleanUpSession(te.getMessage() + "\n" + sw.toString()); } stopTask(); } } } private void sleep(int i) { try { Thread.sleep(i); } catch (InterruptedException e) { // nothing. } } private void setColorMapEntries() throws TransportException { reader.readByte(); // padding reader.readUInt16(); // first color index int length = reader.readUInt16(); while (length-- > 0) { reader.readUInt16(); // R reader.readUInt16(); // G reader.readUInt16(); // B } } private void serverCutText() throws TransportException { reader.readByte(); // padding reader.readInt16(); // padding int length = reader.readInt32() & Integer.MAX_VALUE; clipboardController.updateSystemClipboard(reader.readBytes(length)); } public void framebufferUpdateMessage() throws CommonException, UnsupportedEncodingException { reader.readByte(); // padding this.numberOfRectangles = reader.readUInt16(); if(numberOfRectangles != 1) System.out.println("numberofrectangle : " + numberOfRectangles); if(rfb.isTreeManager() && firstTime) { if(rfb.checkDelay) { SendCheckDelay sendCheckDelay = new SendCheckDelay(rfb); Thread sendCheckDelayThread = new Thread(sendCheckDelay, "send-check-delay"); sendCheckDelayThread.start(); this.firstTime = false; } if(rfb.fixRetinaDisplay) { timer = new Timer(true); timer.schedule(new TimerTask() { @Override public void run() { context.setFbWidth(1280); context.setFbHeight(800); context.sendMessage(new FramebufferUpdateRequestMessage(0, 0, context.getFbWidth(), context.getFbHeight(), true)); } }, 0, 100); } } while (numberOfRectangles-- > 0) { FramebufferUpdateRectangle rect = new FramebufferUpdateRectangle(); rect.fill(reader); long time = System.currentTimeMillis(); if(rfb.isTreeManager() && rfb.checkDelay) System.out.println(time + " : size : " + rect.width * rect.height); Decoder decoder = decoders.getDecoderByType(rect.getEncodingType()); logger.finest(rect.toString() + (0 == numberOfRectangles ? "\n---" : "")); if (decoder != null) { decoder.decode(reader, renderer, rect); // TreeVNC processing here if(!(rfb.getCuiVersion())) repaintController.repaintBitmap(rect); } else if (rect.getEncodingType() == EncodingType.RICH_CURSOR) { RichCursorDecoder.getInstance().decode(reader, renderer, rect); if(repaintController!=null) repaintController.repaintCursor(); } else if (rect.getEncodingType() == EncodingType.CURSOR_POS) { renderer.decodeCursorPosition(rect); repaintController.repaintCursor(); } else if (rect.getEncodingType() == EncodingType.DESKTOP_SIZE || rect.getEncodingType() == EncodingType.INIT_DATA ) { fullscreenFbUpdateIncrementalRequest = new FramebufferUpdateRequestMessage(0, 0, rect.width, rect.height, false); rfb.setCuiVersion(false); boolean visible = true; if (rect.getEncodingType() == EncodingType.INIT_DATA) { int length = reader.readInt32(); byte[] initData = new byte[length]; reader.read(initData); String name = new String(initData, 24, length - 24, "UTF-8"); rfb.getContext().setRemoteDesktopName(name); rfb.getContext().setInitData(initData); repaintController.updateRemoteDesktopName(rfb.getContext()); reader.reset(); rfb.readSendData(length + 20, reader, null ); // size of UpdateRectangleMessage with initData. short id = (short) rect.x; visible = (id != rfb.getId()); } synchronized (renderer.getLock()) { if(!(rfb.getCuiVersion())) renderer = repaintController.createRenderer(reader, rect.width, rect.height, context.getPixelFormat()); } if (rect.getEncodingType() == EncodingType.INIT_DATA) { repaintController.setVisible(visible); } context.sendMessage(new FramebufferUpdateRequestMessage(0, 0, rect.width, rect.height, false)); // repaintController.repaintCursor(); } else if (rect.getEncodingType() == EncodingType.CHECK_DELAY) { int checkDelaySize = 24; reader.reset(); rfb.readSendData(checkDelaySize, reader, null); int port = rfb.acceptPort; String address = rfb.getMyAddress(); sendCheckDelayReply(rect.time, port, address); } else throw new CommonException("Unprocessed encoding: " + rect.toString()); } if (!rfb.isTreeManager()) { return; } synchronized (this) { if (needSendPixelFormat) { needSendPixelFormat = false; context.setPixelFormat(pixelFormat); context.sendMessage(new SetPixelFormatMessage(pixelFormat)); logger.fine("sent: "+pixelFormat); context.sendRefreshMessage(); logger.fine("sent: nonincremental fb update"); } else { context.sendMessage(new FramebufferUpdateRequestMessage(0, 0, context.getFbWidth(), context.getFbHeight(), false)); } } } private void sendCheckDelayReply(long time, int port, String address) throws UnsupportedEncodingException { context.sendMessage(new CheckDelayReply(time, port, address)); } public synchronized void queueUpdatePixelFormat(PixelFormat pf) { pixelFormat = pf; needSendPixelFormat = true; // context.sendMessage(new FramebufferUpdateRequestMessage(0, 0, 1, 1, false)); } public void stopTask() { isRunning = false; } private void connectionFinished() { rfb.vncConnected(true); } private void getLost(Reader reader) throws Exception { int addSerialNumFlag = reader.readInt32(); long num = reader.readInt64(); if (addSerialNumFlag == 1) { rfb.setAddSerialNum(true); if(num != ++checkCounter) { System.out.println("LostData" + (num - checkCounter)); checkCounter = num; } } } }