11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved. 21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be 31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file. 41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccipackage org.chromium.components.devtools_bridge; 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport android.net.LocalSocket; 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport android.net.LocalSocketAddress; 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.io.IOException; 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.nio.ByteBuffer; 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.ExecutorService; 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.Executors; 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.atomic.AtomicInteger; 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.atomic.AtomicReference; 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.locks.Lock; 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.locks.ReadWriteLock; 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.locks.ReentrantReadWriteLock; 191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Base class for client and server that tunnels DevToolsServer's UNIX socket 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * over WebRTC data channel. 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Server runs on a android device with Chromium (or alike). Client runs where socket 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * needed to be accesses (it could be the same device if socket names are different; this 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * configuration useful for testing). 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Client listens LocalServerSocket and each time it receives connection it forwards 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * CLIENT_OPEN packet to the server with newly assigned connection id. On receiving this packet 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * server tries to connect to DevToolsServer socket. If succeeded it sends back SERVER_OPEN_ACK 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * with the same connection id. If failed it sends SERVER_CLOSE. 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * When input stream on client shuts down it sends CLIENT_CLOSE. The same with SERVER_CLOSE 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * on the server side (only if SERVER_OPEN_ACK had sent). Between CLIENT_OPEN and CLIENT_CLOSE 351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * any amount of data packets may be transferred (the same for SERVER_OPEN_ACK/SERVER_CLOSE 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * on the server side). 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Since all communication is reliable and ordered it's safe for client to assume that 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * if CLIENT_CLOSE has sent and SERVER_CLOSE has received with the same connection ID this 401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * ID is safe to be reused. 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccipublic abstract class SocketTunnelBase { 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Data channel is threadsafe but access to the reference needs synchromization. 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private final ReadWriteLock mDataChanneliReferenceLock = new ReentrantReadWriteLock(); 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private volatile AbstractDataChannel mDataChannel; 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Packet structure encapsulated in buildControlPacket, buildDataPacket and PacketDecoderBase. 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Structure of control packet: 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // 1-st byte: CONTROL_CONNECTION_ID. 501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // 2-d byte: op code. 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // 3-d byte: connection id. 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Structure of data packet: 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // 1-st byte: connection id. 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // 2..n: data. 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private static final int CONTROL_PACKET_SIZE = 3; 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Client to server control packets. 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected static final byte CLIENT_OPEN = (byte) 0; 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected static final byte CLIENT_CLOSE = (byte) 1; 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Server to client control packets. 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected static final byte SERVER_OPEN_ACK = (byte) 0; 651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected static final byte SERVER_CLOSE = (byte) 1; 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Must not exceed WebRTC limit. Exceeding it closes 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // data channel automatically. TODO(serya): WebRTC limit supposed to be removed. 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci static final int READING_BUFFER_SIZE = 4 * 1024; 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private static final int CONTROL_CONNECTION_ID = 0; 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // DevTools supports up to ~10 connections at the time. A few extra IDs usefull for 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // delays in closing acknowledgement. 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected static final int MIN_CONNECTION_ID = 1; 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected static final int MAX_CONNECTION_ID = 64; 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Signaling thread isn't accessible via API. Assumes that first caller 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // checkCalledOnSignalingThread is called on it indeed. It also works well for tests. 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private final AtomicReference<Thread> mSignalingThread = new AtomicReference<Thread>(); 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // For writing in socket without blocking signaling thread. 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private final ExecutorService mWritingThread = Executors.newSingleThreadExecutor(); 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public boolean isBound() { 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci final Lock lock = mDataChanneliReferenceLock.readLock(); 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci lock.lock(); 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return mDataChannel != null; 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } finally { 911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci lock.unlock(); 921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci /** 961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Binds the tunnel to the data channel. Tunnel starts its activity when data channel 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * open. 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void bind(AbstractDataChannel dataChannel) { 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Observer registrution must not be done in constructor. 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci final Lock lock = mDataChanneliReferenceLock.writeLock(); 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci lock.lock(); 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mDataChannel = dataChannel; 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } finally { 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci lock.unlock(); 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci dataChannel.registerObserver(new DataChannelObserver()); 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci /** 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Stops all tunnel activity and returns the prevously bound data channel. 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * It's safe to dispose the data channel after it. 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public AbstractDataChannel unbind() { 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci final Lock lock = mDataChanneliReferenceLock.writeLock(); 1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci lock.lock(); 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci final AbstractDataChannel dataChannel; 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci dataChannel = mDataChannel; 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mDataChannel = null; 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } finally { 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci lock.unlock(); 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci dataChannel.unregisterObserver(); 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mSignalingThread.set(null); 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mWritingThread.shutdownNow(); 1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return dataChannel; 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void checkCalledOnSignalingThread() { 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!mSignalingThread.compareAndSet(null, Thread.currentThread())) { 1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (mSignalingThread.get() != Thread.currentThread()) { 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci throw new RuntimeException("Must be called on signaling thread"); 1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected static void checkConnectionId(int connectionId) throws ProtocolError { 1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (connectionId < MIN_CONNECTION_ID || connectionId > MAX_CONNECTION_ID) { 1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci throw new ProtocolError("Invalid connection id: " + Integer.toString(connectionId)); 1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void onProtocolError(ProtocolError e) { 1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci checkCalledOnSignalingThread(); 1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // When integrity of data channel is broken then best way to survive is to close it. 1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci final Lock lock = mDataChanneliReferenceLock.readLock(); 1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci lock.lock(); 1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mDataChannel.close(); 1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } finally { 1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci lock.unlock(); 1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected abstract void onReceivedDataPacket(int connectionId, byte[] data) 1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci throws ProtocolError; 1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected abstract void onReceivedControlPacket(int connectionId, byte opCode) 1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci throws ProtocolError; 1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void onSocketException(IOException e, int connectionId) {} 1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void onDataChannelOpened() {} 1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void onDataChannelClosed() {} 1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci static ByteBuffer buildControlPacket(int connectionId, byte opCode) { 1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ByteBuffer packet = ByteBuffer.allocateDirect(CONTROL_PACKET_SIZE); 1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci packet.put((byte) CONTROL_CONNECTION_ID); 1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci packet.put(opCode); 1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci packet.put((byte) connectionId); 1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return packet; 1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci static ByteBuffer buildDataPacket(int connectionId, byte[] buffer, int count) { 1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ByteBuffer packet = ByteBuffer.allocateDirect(count + 1); 1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci packet.put((byte) connectionId); 1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci packet.put(buffer, 0, count); 1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return packet; 1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void sendToDataChannel(ByteBuffer packet) { 1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci packet.limit(packet.position()); 1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci packet.position(0); 1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci final Lock lock = mDataChanneliReferenceLock.readLock(); 1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci lock.lock(); 1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (mDataChannel != null) { 1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mDataChannel.send(packet, AbstractDataChannel.MessageType.BINARY); 1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } finally { 1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci lock.unlock(); 1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci /** 1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Packet decoding exposed for tests. 1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci abstract static class PacketDecoderBase { 1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void decodePacket(ByteBuffer packet) throws ProtocolError { 2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (packet.remaining() == 0) { 2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci throw new ProtocolError("Empty packet"); 2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int connectionId = packet.get(); 2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (connectionId != CONTROL_CONNECTION_ID) { 2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci checkConnectionId(connectionId); 2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci byte[] data = new byte[packet.remaining()]; 2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci packet.get(data); 2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci onReceivedDataPacket(connectionId, data); 2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (packet.remaining() != CONTROL_PACKET_SIZE - 1) { 2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci throw new ProtocolError("Invalid control packet size"); 2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci byte opCode = packet.get(); 2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci connectionId = packet.get(); 2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci checkConnectionId(connectionId); 2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci onReceivedControlPacket(connectionId, opCode); 2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected abstract void onReceivedDataPacket(int connectionId, byte[] data) 2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci throws ProtocolError; 2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected abstract void onReceivedControlPacket(int connectionId, byte opcode) 2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci throws ProtocolError; 2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private final class DataChannelObserver 2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci extends PacketDecoderBase implements AbstractDataChannel.Observer { 2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void onStateChange(AbstractDataChannel.State state) { 2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci checkCalledOnSignalingThread(); 2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (state == AbstractDataChannel.State.OPEN) { 2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci onDataChannelOpened(); 2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci onDataChannelClosed(); 2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void onMessage(ByteBuffer message) { 2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci checkCalledOnSignalingThread(); 2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci decodePacket(message); 2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } catch (ProtocolError e) { 2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci onProtocolError(e); 2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void onReceivedDataPacket(int connectionId, byte[] data) throws ProtocolError { 2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci checkCalledOnSignalingThread(); 2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SocketTunnelBase.this.onReceivedDataPacket(connectionId, data); 2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void onReceivedControlPacket(int connectionId, byte opCode) throws ProtocolError { 2611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci checkCalledOnSignalingThread(); 2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SocketTunnelBase.this.onReceivedControlPacket(connectionId, opCode); 2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci /** 2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Any problem happened while handling incoming message that breaks state integrity. 2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci static class ProtocolError extends Exception { 2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public ProtocolError(String description) { 2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci super(description); 2731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci /** 2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Base utility class for client and server connections. 2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected abstract class ConnectionBase { 2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected final int mId; 2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected final LocalSocket mSocket; 2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private final AtomicInteger mOpenedStreams = new AtomicInteger(2); // input and output. 2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private volatile boolean mConnected; 2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private byte[] mBuffer; 2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private ConnectionBase(int id, LocalSocket socket, boolean preconnected) { 2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mId = id; 2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mSocket = socket; 2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mConnected = preconnected; 2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected ConnectionBase(int id, LocalSocket socket) { 2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci this(id, socket, true); 2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected ConnectionBase(int id) { 2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci this(id, new LocalSocket(), false); 2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected boolean connect(LocalSocketAddress address) { 3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci assert !mConnected; 3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mSocket.connect(address); 3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mConnected = true; 3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return true; 3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } catch (IOException e) { 3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci onSocketException(e, mId); 3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void runReadingLoop() { 3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mBuffer = new byte[READING_BUFFER_SIZE]; 3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci boolean open; 3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci do { 3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci open = pump(); 3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } while (open); 3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } catch (IOException e) { 3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci onSocketException(e, mId); 3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } finally { 3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mBuffer = null; 3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private boolean pump() throws IOException { 3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int count = mSocket.getInputStream().read(mBuffer); 3281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (count <= 0) 3291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sendToDataChannel(buildDataPacket(mId, mBuffer, count)); 3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return true; 3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void writeData(byte[] data) { 3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Called on writing thread. 3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mSocket.getOutputStream().write(data); 3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } catch (IOException e) { 3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci onSocketException(e, mId); 3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void onReceivedDataPacket(final byte[] data) { 3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mWritingThread.execute(new Runnable() { 3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void run() { 3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci writeData(data); 3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci }); 3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void terminate() { 3531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci close(); 3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void shutdownOutput() { 3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Shutdown output on writing thread to make sure all pending writes finished. 3581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mWritingThread.execute(new Runnable() { 3591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @Override 3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void run() { 3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci shutdownOutputOnWritingThread(); 3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci }); 3641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private void shutdownOutputOnWritingThread() { 3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (mConnected) mSocket.shutdownOutput(); 3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } catch (IOException e) { 3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci onSocketException(e, mId); 3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci releaseStream(); 3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void shutdownInput() { 3761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 3771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (mConnected) mSocket.shutdownInput(); 3781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } catch (IOException e) { 3791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci onSocketException(e, mId); 3801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci releaseStream(); 3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private void releaseStream() { 3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (mOpenedStreams.decrementAndGet() == 0) close(); 3861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void close() { 3891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try { 3901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mSocket.close(); 3911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } catch (IOException e) { 3921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci onSocketException(e, mId); 3931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 397