package org.kne.cloud.network; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketOption; import java.net.SocketOptions; import java.net.StandardSocketOptions; import java.net.UnknownHostException; import java.nio.channels.SocketChannel; import java.util.Map; public class SocketToSocketProxy extends Proxy { private SocketListener sl; private SocketChannelListener scl; private DatagramSocketListener dsl; private MultipurposeSocketAddress listen, cbind, defaultConnect; private Map detectedConnect; private SocketBridgeFactory defaultFactory; private SocketChannelBridgeFactory defaultChannelFactory; private Map detectedFactory; private int defaultSoTimeout=120*60*1000; public int getDefaultSoTimeout() { return defaultSoTimeout; } public void setDefaultSoTimeout(int defaultSoTimeout) { this.defaultSoTimeout = defaultSoTimeout; } public SocketToSocketProxy(MultipurposeSocketAddress listen, MultipurposeSocketAddress connect) throws IOException { this(listen, new MultipurposeSocketAddress(new InetSocketAddress(0)), connect); } public SocketToSocketProxy(String l, String r) throws IOException { this(new MultipurposeSocketAddress(l), new MultipurposeSocketAddress(r)); } public SocketToSocketProxy(MultipurposeSocketAddress listen, MultipurposeSocketAddress cbind, MultipurposeSocketAddress defaultConnect, Map detectedConnect) throws IOException { this(listen,cbind,defaultConnect,detectedConnect,new DefaultSocketBridgeFactory(),null); } public SocketToSocketProxy(MultipurposeSocketAddress listen, MultipurposeSocketAddress cbind, MultipurposeSocketAddress defaultConnect, Map detectedConnect,SocketBridgeFactory defaultFactory,Map detectedFactory) throws IOException { this(listen, cbind, defaultConnect, detectedConnect, defaultFactory, detectedFactory, new DefaultSocketChannelBridgeFactory()); } public SocketToSocketProxy(MultipurposeSocketAddress listen, MultipurposeSocketAddress cbind, MultipurposeSocketAddress defaultConnect, Map detectedConnect,SocketBridgeFactory defaultFactory,Map detectedFactory,SocketChannelBridgeFactory defaultChannelFactory) throws IOException { this.listen = listen; this.cbind = cbind; this.defaultConnect = defaultConnect; this.detectedConnect = detectedConnect; this.defaultFactory=defaultFactory; this.detectedFactory=detectedFactory; this.defaultChannelFactory=defaultChannelFactory; open(); } public SocketToSocketProxy(MultipurposeSocketAddress listen, MultipurposeSocketAddress cbind, MultipurposeSocketAddress defaultConnect) throws IOException { this(listen, cbind, defaultConnect,null); } private void open() throws IOException { if (listen.isStream()) { if ((detectedConnect == null || detectedConnect.isEmpty())&&(detectedFactory==null||detectedFactory.isEmpty())) { if(listen.supportNIO()&&defaultConnect.supportNIO()&&defaultChannelFactory!=null) { scl=new SocketChannelListener(listen); }else { sl = new SocketListener(listen); } } else { sl = new SocketListener(new ProtocolDetectorServerSocket(listen.listenServerSocket())); } if(scl!=null) { scl.setCon((socx)->{ SocketChannel sck=null; try { sck=defaultConnect.connectSocketChannel(InetAddress.getByName(cbind.getHost()), cbind.getPort()); runChannelBridge(defaultChannelFactory, socx, sck); } catch (IOException e) { e.printStackTrace(); } finally { if (sck != null) try { sck.close(); } catch (IOException e) { e.printStackTrace(); } try { socx.close(); } catch (IOException e) { e.printStackTrace(); } } }); }else { sl.setCon((sox) -> { Socket sk = null; try { if (sox instanceof ProtocolDetectorSocket) { ProtocolStack ps = ((ProtocolDetectorSocket) sox).getProtocolStack(); if (!ps.isEmpty()) { String pname=ps.pop().getName(); MultipurposeSocketAddress pmsa = detectedConnect.get(pname); if(pmsa!=null) { sk = pmsa.connectSocket(InetAddress.getByName(cbind.getHost()), cbind.getPort()); }else { sk = defaultConnect.connectSocket(InetAddress.getByName(cbind.getHost()), cbind.getPort()); } SocketBridgeFactory sbf=detectedFactory.get(pname); if(sbf!=null) { runBridge(sbf,sox,sk); }else { runBridge(defaultFactory,sox,sk); } runBridge(defaultFactory,sox,sk); } else { sk = defaultConnect.connectSocket(InetAddress.getByName(cbind.getHost()), cbind.getPort()); runBridge(defaultFactory,sox,sk); } } else { sk = defaultConnect.connectSocket(InetAddress.getByName(cbind.getHost()), cbind.getPort()); runBridge(defaultFactory,sox,sk); } } catch (IOException e) { e.printStackTrace(); } finally { if (sk != null) try { sk.close(); } catch (IOException e) { e.printStackTrace(); } try { sox.close(); } catch (IOException e) { e.printStackTrace(); } } }); } } else { dsl = new DatagramSocketListener(listen); dsl.setCon((dox) -> { }); } } protected void runBridge(SocketBridgeFactory sbf,Socket sk, Socket sox) throws IOException { sk.setSoTimeout(defaultSoTimeout); sox.setSoTimeout(defaultSoTimeout); sk.setTcpNoDelay(true); sox.setTcpNoDelay(true); SocketBridge sb = sbf.createBridge(sk, sox); sb.run(); } protected void runChannelBridge(SocketChannelBridgeFactory sbf,SocketChannel sk, SocketChannel sox) throws IOException { //sk.setSoTimeout(defaultSoTimeout); //sox.setSoTimeout(defaultSoTimeout); sk.setOption(StandardSocketOptions.TCP_NODELAY, true); sox.setOption(StandardSocketOptions.TCP_NODELAY, true); SocketChannelBridge sb = sbf.createBridge(sk, sox); sb.run(); } public MultipurposeSocketAddress getListen() { return listen; } public MultipurposeSocketAddress getCbind() { return cbind; } public MultipurposeSocketAddress getDefaultConnect() { return defaultConnect; } public Map getDetectedConnect() { return detectedConnect; } public SocketBridgeFactory getDefaultFactory() { return defaultFactory; } public Map getDetectedFactory() { return detectedFactory; } public SocketChannelBridgeFactory getDefaultChannelFactory() { return defaultChannelFactory; } @Override public void close() throws IOException { if (dsl != null) dsl.close(); if (sl != null) sl.close(); if(scl!=null) scl.close(); } public InetAddress getListenAddress() { if (sl != null) { return sl.getServerSocket().getInetAddress(); } else if(scl!=null){ try { return ((InetSocketAddress)scl.getServerSocketChannel().getLocalAddress()).getAddress(); } catch (IOException e) { return null; } }else { return dsl.getDatagramServerSocket().getLocalAddress(); } } public int getListenPort() { if (sl != null) { return sl.getServerSocket().getLocalPort(); } else if(scl!=null){ try { return ((InetSocketAddress)scl.getServerSocketChannel().getLocalAddress()).getPort(); } catch (IOException e) { return -1; } } else { return dsl.getDatagramServerSocket().getLocalPort(); } } }