package com.limegroup.gnutella.util;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import com.limegroup.gnutella.io.ConnectObserver;
/**
* Factory for creating Sockets.
*/
public class Sockets {
private final static SocketController CONTROLLER =
CommonUtils.isWindowsXP() ?
new LimitedSocketController(4) :
new SimpleSocketController();
/**
* Ensure this cannot be constructed.
*/
private Sockets() {}
/**
* Connects and returns a socket to the given host, with a timeout.
* The timeout only applies to network conditions. More time might be spent
* waiting for an available slot to connect with.
*
* @param host the address of the host to connect to
* @param port the port to connect to
* @param timeout the desired timeout for connecting, in milliseconds,
* or 0 for no timeout. In case of a proxy connection, this timeout
* might be exceeded
* @return the connected Socket
* @throws IOException the connections couldn't be made in the
* requested time
* @throws <tt>IllegalArgumentException</tt> if the port is invalid
*/
public static Socket connect(String host, int port, int timeout) throws IOException {
return connect(host, port, timeout, null);
}
/**
* Sets up a socket for connecting.
* This method may either block or return immediately, depending on if
* if observer is null or not.
*
* If observer is non-null, this returns immediately. This may either return
* a connected or unconnected Socket, depending on if a connection was able to
* be established immediately. The ConnectObserver will always be notified of
* success via handleConnect(Socket), and failure via shutdown(). If the connection
* was established immediately, it is possible that handleConnect(Socket) is called
* before this method returns.
*
* If observer is null, this method blocks until a connection can be established.
* If no connection can be established, an IOException is thrown.
*
* @param host the address of the host to connect to
* @param port the port to connect to
* @param timeout the desired timeout for connecting, in milliseconds,
* or 0 for no timeout. In case of a proxy connection, this timeout
* might be exceeded
* @param observer the ConnectObserver to notify about non-blocking connect events
* @return the Socket (connected or unconnected)
* @throws IOException see above
* @throws <tt>IllegalArgumentException</tt> if the port is invalid
*/
public static Socket connect(String host, int port, int timeout, ConnectObserver observer) throws IOException {
InetAddress address = InetAddress.getByName(host);
InetSocketAddress addr = new InetSocketAddress(address, port);
return connect(addr, timeout, observer);
}
/**
* Sets up a socket for connecting.
* This method may either block or return immediately, depending on if
* if observer is null or not.
*
* If observer is non-null, this returns immediately. This may either return
* a connected or unconnected Socket, depending on if a connection was able to
* be established immediately. The ConnectObserver will always be notified of
* success via handleConnect(Socket), and failure via shutdown(). If the connection
* was established immediately, it is possible that handleConnect(Socket) is called
* before this method returns.
*
* If observer is null, this method blocks until a connection can be established.
* If no connection can be established, an IOException is thrown.
*
* @param addr address/port
* @param timeout the desired timeout for connecting, in milliseconds,
* or 0 for no timeout. In case of a proxy connection, this timeout
* might be exceeded
* @param observer the ConnectObserver to notify about non-blocking connect events
* @return the Socket (connected or unconnected)
* @throws IOException see above
* @throws <tt>IllegalArgumentException</tt> if the port is invalid
*/
public static Socket connect(InetSocketAddress addr, int timeout, ConnectObserver observer) throws IOException {
if(!NetworkUtils.isValidPort(addr.getPort()))
throw new IllegalArgumentException("port out of range: "+addr.getPort());
return CONTROLLER.connect(addr, timeout, observer);
}
/**
* Removes the given ConnectObserver from wanting to make a request.
* This returns true if it was able to remove the observer because the request had
* not been processed yet.
* Otherwise it returns false, and the ConnectObserver should expect some sort of callback
* indicating whether or not the connect succeeded.
*/
public static boolean removeConnectObserver(ConnectObserver observer) {
return CONTROLLER.removeConnectObserver(observer);
}
/** Returns the number of Sockets allowed to be created concurrently. */
public static int getNumAllowedSockets() {
return CONTROLLER.getNumAllowedSockets();
}
}