/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.horizon.internal.control; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; /** * * This class holds the RfbProto data for writing to to the vnc port of the horizonbox * * @author Jurgen Kuijpers * @since 1.9.0 */ class RfbProto { private final static int secTypeNone = 1; private final static String versionMsg_3_8 = "RFB 003.008\n"; private final static int VncAuthOK = 0, VncAuthFailed = 1, VncAuthTooMany = 2; private final static int keyboardEvent = 4; private OutputStream os; private byte[] eventBuf = new byte[72]; private int eventBufLen = 0; private Socket sock; private DataInputStream is; public RfbProto(String host, int port) throws Exception { initConnection(host, port); } /** * Writes a key down event given key value: key */ public void writeKeyDown(int key) { writeKeyEvent(key, true); } /** * Writes a key up event given key value: key */ public void writeKeyUp(int key) { writeKeyEvent(key, false); } /** * Writes the buffer and flushes the stream */ public void writeBuffer() throws IOException { os.write(eventBuf, 0, eventBufLen); eventBufLen = 0; os.flush(); } /** * Closes the socket connection to the box */ public synchronized void close() { try { sock.close(); } catch (IOException e) { throw new RuntimeException(e); } } private void initConnection(String host, int port) throws Exception { sock = new Socket(host, port); is = new DataInputStream(new BufferedInputStream(sock.getInputStream(), 16384)); os = sock.getOutputStream(); readVersionMsg(); writeVersionMsg(); selectSecurityTypeNone(); authenticate(); os.write(0); } private void readVersionMsg() throws Exception { byte[] b = new byte[12]; readFully(b); } private void writeVersionMsg() throws IOException { os.write(versionMsg_3_8.getBytes()); } private void writeKeyEvent(int key, boolean down) { eventBuf[eventBufLen++] = (byte) keyboardEvent; eventBuf[eventBufLen++] = (byte) (down ? 1 : 0); eventBuf[eventBufLen++] = (byte) 0; eventBuf[eventBufLen++] = (byte) 0; eventBuf[eventBufLen++] = (byte) ((key >> 24) & 0xff); eventBuf[eventBufLen++] = (byte) ((key >> 16) & 0xff); eventBuf[eventBufLen++] = (byte) ((key >> 8) & 0xff); eventBuf[eventBufLen++] = (byte) (key & 0xff); } private void selectSecurityTypeNone() throws Exception { int nSecTypes = readU8(); byte[] secTypes = new byte[nSecTypes]; readFully(secTypes); os.write(secTypeNone); } private void readConnFailedReason() throws Exception { int reasonLen = readU32(); byte[] reason = new byte[reasonLen]; readFully(reason); throw new Exception(new String(reason)); } private void authenticate() throws Exception { int securityResult = readU32(); switch (securityResult) { case VncAuthOK: break; case VncAuthFailed: readConnFailedReason(); throw new Exception("No Authentication" + ": failed"); case VncAuthTooMany: throw new Exception("No authentication" + ": failed, too many tries"); default: throw new Exception("No authentication" + ": unknown result " + securityResult); } } private void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); } private void readFully(byte b[], int off, int len) throws IOException { is.readFully(b, off, len); } private int readU8() throws IOException { return is.readUnsignedByte(); } private int readU32() throws IOException { return is.readInt(); } }