FileDocCategorySizeDatePackage
SocketFetcher.javaAPI DocGlassfish v2 API12997Mon May 14 15:28:46 BST 2007com.sun.mail.util

SocketFetcher

public class SocketFetcher extends Object
This class is used to get Sockets. Depending on the arguments passed it will either return a plain java.net.Socket or dynamically load the SocketFactory class specified in the classname param and return a socket created by that SocketFactory.
author
Max Spivak
author
Bill Shannon

Fields Summary
Constructors Summary
private SocketFetcher()

    
Methods Summary
private static voidconfigureSSLSocket(java.net.Socket socket, java.util.Properties props, java.lang.String prefix)
Configure the SSL options for the socket (if it's an SSL socket), based on the mail..ssl.protocols and mail..ssl.ciphersuites properties.

	if (!(socket instanceof SSLSocket))
	    return;
	SSLSocket sslsocket = (SSLSocket)socket;

	String protocols = props.getProperty(prefix + ".ssl.protocols", null);
	if (protocols != null)
	    sslsocket.setEnabledProtocols(stringArray(protocols));
	else {
	    /*
	     * At least the UW IMAP server insists on only the TLSv1
	     * protocol for STARTTLS, and won't accept the old SSLv2
	     * or SSLv3 protocols.  Here we enable only the TLSv1
	     * protocol.  XXX - this should probably be parameterized.
	     */
	    sslsocket.setEnabledProtocols(new String[] {"TLSv1"});
	}
	String ciphers = props.getProperty(prefix + ".ssl.ciphersuites", null);
	if (ciphers != null)
	    sslsocket.setEnabledCipherSuites(stringArray(ciphers));
	/*
	System.out.println("SSL protocols after " +
	    Arrays.asList(sslsocket.getEnabledProtocols()));
	System.out.println("SSL ciphers after " +
	    Arrays.asList(sslsocket.getEnabledCipherSuites()));
	*/
    
private static java.net.SocketcreateSocket(java.net.InetAddress localaddr, int localport, java.lang.String host, int port, int cto, javax.net.SocketFactory sf, boolean useSSL)
Create a socket with the given local address and connected to the given host and port. Use the specified connection timeout. If a socket factory is specified, use it. Otherwise, use the SSLSocketFactory if useSSL is true.

	Socket socket;

	if (sf != null)
	    socket = sf.createSocket();
	else if (useSSL)
	    socket = SSLSocketFactory.getDefault().createSocket();
	else
	    socket = new Socket();
	if (localaddr != null)
	    socket.bind(new InetSocketAddress(localaddr, localport));
	if (cto >= 0)
	    socket.connect(new InetSocketAddress(host, port), cto);
	else
	    socket.connect(new InetSocketAddress(host, port));
	return socket;
    
private static java.lang.ClassLoadergetContextClassLoader()
Convenience method to get our context class loader. Assert any privileges we might have and then call the Thread.getContextClassLoader method.

	return (ClassLoader)
		AccessController.doPrivileged(new PrivilegedAction() {
	    public Object run() {
		ClassLoader cl = null;
		try {
		    cl = Thread.currentThread().getContextClassLoader();
		} catch (SecurityException ex) { }
		return cl;
	    }
	});
    
public static java.net.SocketgetSocket(java.lang.String host, int port, java.util.Properties props, java.lang.String prefix, boolean useSSL)
This method returns a Socket. Properties control the use of socket factories and other socket characteristics. The properties used are:

  • prefix.socketFactory.class
  • prefix.socketFactory.fallback
  • prefix.socketFactory.port
  • prefix.timeout
  • prefix.connectiontimeout
  • prefix.localaddress
  • prefix.localport

If the socketFactory.class property isn't set, the socket returned is an instance of java.net.Socket connected to the given host and port. If the socketFactory.class property is set, it is expected to contain a fully qualified classname of a javax.net.SocketFactory subclass. In this case, the class is dynamically instantiated and a socket created by that SocketFactory is returned.

If the socketFactory.fallback property is set to false, don't fall back to using regular sockets if the socket factory fails.

The socketFactory.port specifies a port to use when connecting through the socket factory. If unset, the port argument will be used.

If the connectiontimeout property is set, we use a separate thread to make the connection so that we can timeout that connection attempt.

If the timeout property is set, it is used to set the socket timeout.

If the localaddress property is set, it's used as the local address to bind to. If the localport property is also set, it's used as the local port number to bind to.

param
host The host to connect to
param
port The port to connect to at the host
param
props Properties object containing socket properties
param
prefix Property name prefix, e.g., "mail.imap"
param
useSSL use the SSL socket factory as the default


	if (prefix == null)
	    prefix = "socket";
	if (props == null)
	    props = new Properties();	// empty
	String s = props.getProperty(prefix + ".connectiontimeout", null);
	int cto = -1;
	if (s != null) {
	    try {
		cto = Integer.parseInt(s);
	    } catch (NumberFormatException nfex) { }
	}

	Socket socket = null;
	String timeout = props.getProperty(prefix + ".timeout", null);
	String localaddrstr = props.getProperty(prefix + ".localaddress", null);
	InetAddress localaddr = null;
	if (localaddrstr != null)
	    localaddr = InetAddress.getByName(localaddrstr);
	String localportstr = props.getProperty(prefix + ".localport", null);
	int localport = 0;
	if (localportstr != null) {
	    try {
		localport = Integer.parseInt(localportstr);
	    } catch (NumberFormatException nfex) { }
	}

	boolean fb = false;
	String fallback =
	    props.getProperty(prefix + ".socketFactory.fallback", null);
	fb = fallback == null || (!fallback.equalsIgnoreCase("false"));

	String sfClass =
	    props.getProperty(prefix + ".socketFactory.class", null);
	int sfPort = -1;
	try {
	    SocketFactory sf = getSocketFactory(sfClass);
	    if (sf != null) {
		String sfPortStr =
		    props.getProperty(prefix + ".socketFactory.port", null);
		if (sfPortStr != null) {
		    try {
			sfPort = Integer.parseInt(sfPortStr);
		    } catch (NumberFormatException nfex) { }
		}

		// if port passed in via property isn't valid, use param
		if (sfPort == -1)
		    sfPort = port;
		socket = createSocket(localaddr, localport,
				    host, sfPort, cto, sf, useSSL);
	    }
	} catch (SocketTimeoutException sex) {
	    throw sex;
	} catch (Exception ex) {
	    if (!fb) {
		if (ex instanceof InvocationTargetException) {
		    Throwable t =
		      ((InvocationTargetException)ex).getTargetException();
		    if (t instanceof Exception)
			ex = (Exception)t;
		}
		if (ex instanceof IOException)
		    throw (IOException)ex;
		IOException ioex = new IOException(
				    "Couldn't connect using \"" + sfClass + 
				    "\" socket factory to host, port: " +
				    host + ", " + sfPort +
				    "; Exception: " + ex);
		ioex.initCause(ex);
		throw ioex;
	    }
	}

	if (socket == null)
	    socket = createSocket(localaddr, localport,
				host, port, cto, null, useSSL);

	int to = -1;
	if (timeout != null) {
	    try {
		to = Integer.parseInt(timeout);
	    } catch (NumberFormatException nfex) { }
	}
	if (to >= 0)
	    socket.setSoTimeout(to);

	configureSSLSocket(socket, props, prefix);
	return socket;
    
public static java.net.SocketgetSocket(java.lang.String host, int port, java.util.Properties props, java.lang.String prefix)

	return getSocket(host, port, props, prefix, false);
    
private static javax.net.SocketFactorygetSocketFactory(java.lang.String sfClass)
Return a socket factory of the specified class.

	if (sfClass == null || sfClass.length() == 0)
	    return null;

	// dynamically load the class 

	ClassLoader cl = getContextClassLoader();
	Class clsSockFact = null;
	if (cl != null) {
	    try {
		clsSockFact = cl.loadClass(sfClass);
	    } catch (ClassNotFoundException cex) { }
	}
	if (clsSockFact == null)
	    clsSockFact = Class.forName(sfClass);
	// get & invoke the getDefault() method
	Method mthGetDefault = clsSockFact.getMethod("getDefault", 
						     new Class[]{});
	SocketFactory sf = (SocketFactory)
	    mthGetDefault.invoke(new Object(), new Object[]{});
	return sf;
    
public static java.net.SocketstartTLS(java.net.Socket socket)
Start TLS on an existing socket. Supports the "STARTTLS" command in many protocols. This version for compatibility possible third party code that might've used this API even though it shouldn't.

	return startTLS(socket, new Properties(), "socket");
    
public static java.net.SocketstartTLS(java.net.Socket socket, java.util.Properties props, java.lang.String prefix)
Start TLS on an existing socket. Supports the "STARTTLS" command in many protocols.

	InetAddress a = socket.getInetAddress();
	String host = a.getHostName();
	int port = socket.getPort();
//System.out.println("SocketFetcher: startTLS host " + host + ", port " + port);

	try {
	    SSLSocketFactory ssf;
	    String sfClass =
		props.getProperty(prefix + ".socketFactory.class", null);
	    SocketFactory sf = getSocketFactory(sfClass);
	    if (sf != null && sf instanceof SSLSocketFactory)
		ssf = (SSLSocketFactory)sf;
	    else
		ssf = (SSLSocketFactory)SSLSocketFactory.getDefault();
	    socket = ssf.createSocket(socket, host, port, true);
	    configureSSLSocket(socket, props, prefix);
	} catch (Exception ex) {
	    if (ex instanceof InvocationTargetException) {
		Throwable t =
		  ((InvocationTargetException)ex).getTargetException();
		if (t instanceof Exception)
		    ex = (Exception)t;
	    }
	    if (ex instanceof IOException)
		throw (IOException)ex;
	    // wrap anything else before sending it on
	    IOException ioex = new IOException("Exception in startTLS: host " +
				host + ", port " + port + "; Exception: " + ex);
	    ioex.initCause(ex);
	    throw ioex;
	}
	return socket;
    
private static java.lang.String[]stringArray(java.lang.String s)
Parse a string into whitespace separated tokens and return the tokens in an array.

	StringTokenizer st = new StringTokenizer(s);
	List tokens = new ArrayList();
	while (st.hasMoreTokens())
	    tokens.add(st.nextToken());
	return (String[])tokens.toArray(new String[tokens.size()]);