package org.zarroboogs.smartzpn.tunnel; import android.annotation.SuppressLint; import org.zarroboogs.smartzpn.core.LocalVpnService; import org.zarroboogs.smartzpn.core.ProxyConfigLoader; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; public abstract class Tunnel { final static ByteBuffer GL_BUFFER = ByteBuffer.allocate(20000); public static long SessionCount; protected abstract void onConnected(ByteBuffer buffer) throws Exception; protected abstract boolean isTunnelEstablished(); protected abstract void beforeSend(ByteBuffer buffer) throws Exception; protected abstract void afterReceived(ByteBuffer buffer) throws Exception; protected abstract void onDispose(); private SocketChannel m_InnerChannel; private ByteBuffer m_SendRemainBuffer; private Selector m_Selector; private Tunnel m_BrotherTunnel; private boolean m_Disposed; private InetSocketAddress m_ServerEP; protected InetSocketAddress m_DestAddress; public Tunnel(SocketChannel innerChannel, Selector selector) { this.m_InnerChannel = innerChannel; this.m_Selector = selector; SessionCount++; } public Tunnel(InetSocketAddress serverAddress, Selector selector) throws IOException { SocketChannel innerChannel = SocketChannel.open(); innerChannel.configureBlocking(false); this.m_InnerChannel = innerChannel; this.m_Selector = selector; this.m_ServerEP = serverAddress; SessionCount++; } public void setBrotherTunnel(Tunnel brotherTunnel) { m_BrotherTunnel = brotherTunnel; } public void connect(InetSocketAddress destAddress) throws Exception { if (LocalVpnService.Instance.protect(m_InnerChannel.socket())) {//保护socket不走vpn m_DestAddress = destAddress; m_InnerChannel.register(m_Selector, SelectionKey.OP_CONNECT, this);//注册连接事件 m_InnerChannel.connect(m_ServerEP);//连接目标 } else { throw new Exception("VPN protect socket failed."); } } protected void beginReceive() throws Exception { if (m_InnerChannel.isBlocking()) { m_InnerChannel.configureBlocking(false); } m_InnerChannel.register(m_Selector, SelectionKey.OP_READ, this);//注册读事件 } protected boolean write(ByteBuffer buffer, boolean copyRemainData) throws Exception { int bytesSent; while (buffer.hasRemaining()) { bytesSent = m_InnerChannel.write(buffer); if (bytesSent == 0) { break;//不能再发送了,终止循环 } } if (buffer.hasRemaining()) {//数据没有发送完毕 if (copyRemainData) {//拷贝剩余数据,然后侦听写入事件,待可写入时写入。 //拷贝剩余数据 if (m_SendRemainBuffer == null) { m_SendRemainBuffer = ByteBuffer.allocate(buffer.capacity()); } m_SendRemainBuffer.clear(); m_SendRemainBuffer.put(buffer); m_SendRemainBuffer.flip(); m_InnerChannel.register(m_Selector, SelectionKey.OP_WRITE, this);//注册写事件 } return false; } else {//发送完毕了 return true; } } protected void onTunnelEstablished() throws Exception { this.beginReceive();//开始接收数据 m_BrotherTunnel.beginReceive();//兄弟也开始收数据吧 } @SuppressLint("DefaultLocale") public void onConnectable() { try { if (m_InnerChannel.finishConnect()) {//连接成功 onConnected(GL_BUFFER);//通知子类TCP已连接,子类可以根据协议实现握手等。 } else {//连接失败 LocalVpnService.Instance.writeLog("Error: connect to %s failed.", m_ServerEP); this.dispose(); } } catch (Exception e) { LocalVpnService.Instance.writeLog("Error: connect to %s failed: %s", m_ServerEP, e); this.dispose(); } } public void onReadable(SelectionKey key) { try { ByteBuffer buffer = GL_BUFFER; buffer.clear(); int bytesRead = m_InnerChannel.read(buffer); if (bytesRead > 0) { buffer.flip(); afterReceived(buffer);//先让子类处理,例如解密数据。 if (isTunnelEstablished() && buffer.hasRemaining()) {//将读到的数据,转发给兄弟。 m_BrotherTunnel.beforeSend(buffer);//发送之前,先让子类处理,例如做加密等。 if (!m_BrotherTunnel.write(buffer, true)) { key.cancel();//兄弟吃不消,就取消读取事件。 if (ProxyConfigLoader.IS_DEBUG) System.out.printf("%s can not read more.\n", m_ServerEP); } } } else if (bytesRead < 0) { this.dispose();//连接已关闭,释放资源。 } } catch (Exception e) { e.printStackTrace(); this.dispose(); } } public void onWritable(SelectionKey key) { try { this.beforeSend(m_SendRemainBuffer);//发送之前,先让子类处理,例如做加密等。 if (this.write(m_SendRemainBuffer, false)) {//如果剩余数据已经发送完毕 key.cancel();//取消写事件。 if (isTunnelEstablished()) { m_BrotherTunnel.beginReceive();//这边数据发送完毕,通知兄弟可以收数据了。 } else { this.beginReceive();//开始接收代理服务器响应数据 } } } catch (Exception e) { this.dispose(); } } public void dispose() { disposeInternal(true); } void disposeInternal(boolean disposeBrother) { if (m_Disposed) { return; } else { try { m_InnerChannel.close(); } catch (Exception e) { } if (m_BrotherTunnel != null && disposeBrother) { m_BrotherTunnel.disposeInternal(false);//把兄弟的资源也释放了。 } m_InnerChannel = null; m_SendRemainBuffer = null; m_Selector = null; m_BrotherTunnel = null; m_Disposed = true; SessionCount--; onDispose(); } } }