package org.limewire.net; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import org.limewire.logging.Log; import org.limewire.logging.LogFactory; import org.limewire.net.ProxySettings.ProxyType; import org.limewire.nio.NBSocket; import org.limewire.nio.NBSocketFactory; import org.limewire.nio.observer.ConnectObserver; abstract class AbstractSocketController implements SocketController { private final static Log LOG = LogFactory.getLog(AbstractSocketController.class); /** The possibly null address to bind to. */ private InetSocketAddress lastBindAddr; private final ProxyManager proxyManager; private final SocketBindingSettings defaultSocketBindingSettings; AbstractSocketController(ProxyManager proxyManager, SocketBindingSettings defaultSocketBindingSettings) { this.proxyManager = proxyManager; this.defaultSocketBindingSettings = defaultSocketBindingSettings; } public Socket connect(NBSocketFactory factory, InetSocketAddress remoteAddress, InetSocketAddress localAddress, int timeout, ConnectObserver observer) throws IOException { return connect(localAddress, factory, remoteAddress, timeout, observer); } public Socket connect(NBSocket socket, InetSocketAddress localAddr, InetSocketAddress addr, int timeout, ConnectObserver observer) throws IOException { return connect(localAddr, null, addr, timeout, observer); } /** * Makes a connection to the given InetSocketAddress. * If observer is null, this will block. * Otherwise, the observer will be notified of success or failure. */ private Socket connect(InetSocketAddress localAddr, NBSocketFactory factory, InetSocketAddress addr, int timeout, ConnectObserver observer) throws IOException { ProxyType proxyType = proxyManager.getProxyType(addr.getAddress()); if (proxyType != ProxyType.NONE) return connectProxy(localAddr, factory, proxyType, addr, timeout, observer); else return connectPlain(localAddr, factory, addr, timeout, observer); } /** * Establishes a connection to the given host. * * If observer is null, this will block until a connection is established or an IOException is thrown. * Otherwise, this will return immediately and the Observer will be notified of success or failure. */ protected Socket connectPlain(InetSocketAddress localAddr, NBSocketFactory factory, InetSocketAddress addr, int timeout, ConnectObserver observer) throws IOException { NBSocket socket = factory.createSocket(); bindSocket(socket, localAddr); if(observer == null) { if(LOG.isDebugEnabled()) { String ipp = addr.getAddress().getHostAddress() + ":" + addr.getPort(); LOG.debug("Connecting to " + ipp + " (blocking)"); } socket.connect(addr, timeout); // blocking } else { if(LOG.isDebugEnabled()) { String ipp = addr.getAddress().getHostAddress() + ":" + addr.getPort(); LOG.debug("Connecting to " + ipp + " (non-blocking)"); } socket.connect(addr, timeout, observer); // non-blocking } return socket; } /** Attempts to bind the Socket locally using the values from localAddr, * or ConnectionSettings if it is null. */ protected void bindSocket(NBSocket socket, InetSocketAddress localAddr) throws IOException { if(localAddr != null) { socket.bind(localAddr); } else if(defaultSocketBindingSettings.isSocketBindingRequired()) { String bindAddrString = defaultSocketBindingSettings.getAddressToBindTo(); if(lastBindAddr == null || !lastBindAddr.getAddress().getHostAddress().equals(bindAddrString)) lastBindAddr = new InetSocketAddress(bindAddrString, 0); try { socket.bind(lastBindAddr); } catch(IOException iox) { defaultSocketBindingSettings.bindingFailed(); } } } /** * Connects to a host using a proxy. */ protected Socket connectProxy(InetSocketAddress localAddr, NBSocketFactory factory, ProxyType type, InetSocketAddress addr, int timeout, ConnectObserver observer) throws IOException { InetSocketAddress proxyAddr = proxyManager.getProxyHost(); if(observer != null) { return connectPlain(localAddr, factory, proxyAddr, timeout, proxyManager.getConnectorFor(type, observer, addr, timeout)); } else { Socket proxySocket = connectPlain(localAddr, factory, proxyAddr, timeout, null); try { return proxyManager.establishProxy(type, proxySocket, addr, timeout); } catch(IOException iox) { // Ensure the proxySocket is closed. Not all proxies cleanup correctly. try { proxySocket.close(); } catch(IOException ignored) {} throw iox; } } } }