Mercurial > hg > Applications > TreeVNC
view src/main/java/jp/ac/u_ryukyu/treevnc/TreeVncCommandChannelListener.java @ 606:82755931810c
fix
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 19 Feb 2020 15:02:10 +0900 |
parents | 141f627665ab |
children |
line wrap: on
line source
package jp.ac.u_ryukyu.treevnc; import com.glavsoft.exceptions.TransportException; import com.glavsoft.rfb.protocol.ProtocolContext; import com.glavsoft.rfb.protocol.ProtocolContext.TreeCommand; import com.glavsoft.rfb.protocol.state.HandshakeState; import com.glavsoft.transport.Reader; import com.glavsoft.transport.Writer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public class TreeVncCommandChannelListener implements Runnable { 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(TreeRFBProto _rfb, int p) { rfb = _rfb; port = p; } public void commandMainLoop() { acceptThread = new Thread(new Runnable() { @Override public void run() { TreeVncCommand cmd = null; do { try { cmd = cmdQueue.poll(1000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { continue; } if (cmd!=null) { cmd.handleTreeVncCommand(); } } while (cmd == null || cmd.getCommand() != TreeCommand.QUIT_LOOP); } },"root-command-loop"); acceptThread.start(); } public void run() { commandMainLoop(); while (true) { try { final Socket newCli = rfb.accept(); final OutputStream os = newCli.getOutputStream(); final InputStream is = newCli.getInputStream(); new Thread(new Runnable() { public void run() { TreeVncCommand cmd = newClientHandler(newCli, new Writer(os), new Reader(is)); if (cmd!=null) cmdQueue.add(cmd); } },"accepting").start(); } catch (Exception e) { System.out.println("failed to connect incoming client" + e.getMessage()); } } } public TreeVncCommand newClientHandler (final Socket newCli, final Writer os, final Reader is) { TreeVncCommand cmd = null; try { cmd = initialConnection(rfb, os, is, newCli); if (cmd!=null && cmd.getCommand()!=TreeCommand.NEW_NODE) { // TreeVNC command is processed newCli.close(); return cmd; } } catch (Exception e) { try { System.out.println("new client faild :" + e.getMessage()); newCli.close(); return null; } catch (IOException e1) { System.out.println("new client close faild"); return null; } } return cmd; } public TreeVncCommand initialConnection(TreeRFBProto myRfbProto, final Writer os, final Reader is, Socket connection) throws IOException, TransportException { /** * initial connection of RFB protocol */ rfb = myRfbProto; InetAddress adr = connection.getLocalAddress(); String myHostAddress = adr.getHostAddress(); String intf = NetworkInterface.getByInetAddress(adr).getName(); sendRfbVersion(os); byte[] b; if ((b = readVersionMsg(is, os))!=null) { // direct TreeVNC Command from TreeRoot // such as connectTo, connectToAsLeader // or direct TreeVNC Command from lower node // such as LostParent, LostChild TreeVncCommand cmd = treeVncCommand(b,is,os,myHostAddress,intf); if (cmd!=null) return cmd; } // normal connection from TreeVNC node candidate sendSecurityType(os); readSecType(is); sendSecResult(os); readClientInit(is); sendInitData(os); System.out.println("direct connection from "+connection.getInetAddress()); return new TreeVncCommand(rfb, myHostAddress, TreeCommand.NEW_NODE, os, is, connection, intf); } /** * handle TreeVNC Command * @param b byte [] command * @param is * @param os * @param myHostName * @return * @throws TransportException * @throws IOException * * TreeVNC Command is sent as a possible replied version message. 12 bytes is already read. * Command 4 byte (including padding) * lenght 4 byte * port 4 byte * rest of data ( add padding if it is shorter than 12 byte) */ TreeVncCommand treeVncCommand(byte[] b, Reader is, Writer os, String myHostName,String intf) throws TransportException, IOException { ByteBuffer buf = ByteBuffer.wrap(b); TreeCommand command = TreeCommand.create(buf.get()&0xff); // make it unsigned buf.get(); short value = buf.getShort(); int length = buf.getInt(); int port = buf.getInt(); String hostname = null; if (length>4) { if (length>1024) { System.out.println("Too long TreeVncCommand "); return null; } byte namebuf[] = new byte[length-4]; try { is.readBytes(namebuf); } catch (TransportException e) { return null; } hostname = new String(namebuf); } return new TreeVncCommand(rfb, myHostName, command, port, hostname, intf, value); } void sendRfbVersion(Writer writer) throws IOException, TransportException { writer.write(versionMsg_3_856.getBytes()); } byte[] readVersionMsg(Reader reader, Writer writer) throws IOException, TransportException { byte[] b = new byte[HandshakeState.PROTOCOL_STRING_LENGTH]; reader.readBytes(b); if ((b[0]&0xff)>=220) return b; // TreeVNC extension command. 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"); } return null; } void readSecType(Reader reader) throws TransportException { byte[] b = new byte[1]; reader.read(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 sendSecResult(Writer os) throws TransportException { ByteBuffer b = ByteBuffer.allocate(4); b.order(ByteOrder.BIG_ENDIAN); b.putInt(0); os.write(b.array()); } void readClientInit(Reader in) throws TransportException { byte[] b = new byte[0]; in.readBytes(b); } void sendInitData(Writer os) throws TransportException { ProtocolContext context = rfb.context; if (context != null) { os.write(context.getInitData()); } else { // In case of "-d" we have no context // Send dummy data // width : 1920 // height : 1080 // title : "girefly" byte[] dummyInitData = {7, -128, 4, 56, 32, 24, 0, 1, 0, -1, 0, -1, 0, -1, 16, 8, 0, 0, 0, 0, 0, 0, 0, 7, 103, 105, 114, 101, 102, 108, 121}; os.write(dummyInitData); } } public byte[] createOriginalInitData(int width, int height, String desktopName) { byte[] titleBytes = null; int titleLength = 0; byte[] pixelFormat = {32, 24, 0, 1, 0, -1, 0, -1, 0, -1, 16, 8, 0, 0, 0, 0, 0, 0, 0}; try { titleBytes = desktopName.getBytes("UTF-8"); titleLength = titleBytes.length; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } ByteBuffer initData = ByteBuffer.allocate(2+2+19+1+titleLength); // w+h+pixelFormat+titleLength+titleBytes initData.putShort((short) width); initData.putShort((short) height); initData.put(pixelFormat); initData.put((byte) titleLength); initData.put(titleBytes); initData.flip(); return initData.array(); } public void waitForShutdown() { if (acceptThread!=null) { try { acceptThread.join(); } catch (InterruptedException e) { } } } }