package com.limegroup.gnutella.util; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.net.UnknownHostException; import org.limewire.nio.NIOServerSocket; import org.limewire.nio.NIOSocket; /** * Returns two sockets A and B, so that the input of A is connected to * the output of B and vice versa. Typical use: * <pre> * PipedSocketFactory factory=new PipedSocketFactory("1.1.1.1", "2.2.2.2"); * Connection cA=new Connection(factory.getSocketA()); * Connection cB=new Connection(factory.getSocketB()); * cA.send(m1); * cB.receive(); * cB.send(m2); * cA.receive(); * </pre> */ public class PipedSocketFactory { private final ServerSocket ss; private final String hostA; private final String hostB; private NIOSocket socketA; private NIOSocket socketB; /** * @param hostA the address to use for socket A * @param hostB the address to use for socket B */ public PipedSocketFactory(String hostA, String hostB) throws IOException, UnknownHostException { this.hostA = hostA; this.hostB = hostB; ss = new NIOServerSocket(); ss.setReuseAddress(true); ss.bind(new InetSocketAddress(0)); } public Socket getSocketA() throws Exception { if(socketA == null) setupSockets(); return socketA; } public Socket getSocketB() throws Exception { if(socketB == null) setupSockets(); return socketB; } private void setupSockets() throws Exception { socketA = new FakedNIOSocket(InetAddress.getLocalHost(), ss.getLocalPort(), hostA, hostB); socketB = (NIOSocket)ss.accept(); } private static class FakedNIOSocket extends NIOSocket { private final String local; private final String remote; FakedNIOSocket(InetAddress host, int port, String local, String remote) throws IOException { super(host, port); this.local = local; this.remote = remote; } @Override public InetAddress getInetAddress() { try { return InetAddress.getByName(remote); } catch(UnknownHostException uhe) { throw new RuntimeException(uhe); } } @Override public InetAddress getLocalAddress() { try { return InetAddress.getByName(local); } catch(UnknownHostException uhe) { throw new RuntimeException(uhe); } } @Override public SocketAddress getRemoteSocketAddress() { return new InetSocketAddress(getInetAddress(), getPort()); } } }