package jacorb.security.ssl;

/*
 *        Written for JacORB - a free Java ORB
 *
 *   Copyright (C) 1999  André Benvenuti.
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free
 *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* 
 * We follow the design of socket factories in package javax.net and javax.net.ssl.
 * Because this package don't the JDK yet we don't extend its classes, but we are fully compatible.
 *
 * The basic idea is to setup policies related to the sockets being constructed,
 * in the factory: no special configuration is done in the code which asks for the sockets.
 * 
 * We will not define an abstract SSLSocketFactory but implement one using the iSaSiLk packages.
 * The sockets returned to the application have to be subclasses of java.net.Socket,
 * so we can return sockets of class iaik.security.ssl.Socket.
 * By now we wont directly expose security relevant APIs, but will probably as we implement Security Objects. 
 * Which factory classes is used will de decide in jacorb.util.Environment as this is specific
 * to the environment configuration.
 * So the getDefault method could return null if no SSL support at all, or a factory that encapsulates
 * a particular implementation and take care of initialising and pass specific parameters. 
 * bnv: just to be sure...
 */

public class SSLSocketFactory 
    extends jacorb.util.net.SocketFactory 
{
    private static SSLSocketFactory defaultFactory;
    private iaik.security.ssl.SSLClientContext defaultContext;
    private iaik.security.ssl.CipherSuite[] cs;

    public SSLSocketFactory() 
    {
	SSLSetup sslSetup = SSLSetup.getDefault ();
	defaultContext = sslSetup.getDefaultSSLClientContext ();
	cs = sslSetup.getCipherSuites();
    }

    public java.net.Socket createSocket ( java.lang.String host,
					  int port
					  )
	throws java.io.IOException,
	java.net.UnknownHostException
	/* Returns a socket connected to a ServerSocket on the named host, at the given port.
	 * This socket is configured using the socket options established for this factory.
	 * Parameters:
	 * 	host - the server host
	 * 	port - the server port
	 * Throws:
	 * 	java.io.IOException - if the connection can't be established
	 * 	java.net.UnknownHostException - if the host is not known
	 */
    {
	return new iaik.security.ssl.SSLSocket ( host, port, defaultContext );
    }

    public java.net.Socket createSocket ( java.lang.String host,
					  int port,
					  java.net.InetAddress clientHost,
					  int clientPort
					  )
	throws java.io.IOException,
	java.net.UnknownHostException
	/* Returns a socket connected to a ServerSocket on the named host, at the given port.
	 * The client address address is the specified host and port. This socket is configured using the socket options established for this factory.
	 * Parameters:
	 * 	host - the server host
	 * 	port - the server port
	 * 	clientHost - the client host
	 * 	clientPort - the client port
	 * Throws:
	 * 	java.io.IOException - if the connection can't be established
	 * 	java.net.UnknownHostException - if the host is not known
	 */
    {
	return new iaik.security.ssl.SSLSocket ( host, port, defaultContext );
    }

    public java.net.Socket createSocket ( java.net.InetAddress host,
					  int port
					  )
	throws java.io.IOException
	/*Returns a socket connected to a ServerSocket at the specified network address and port. This socket is configured using the socket options established for this factory.
	 * Parameters:
	 * 	host - the server host
	 * 	port - the server port
	 * Throws:
	 * 	java.io.IOException - if the connection can't be established
	 */
    {
	return new iaik.security.ssl.SSLSocket ( host, port, defaultContext );
    }

    public java.net.Socket createSocket ( java.net.InetAddress address,
					  int port,
					  java.net.InetAddress clientAddress,
					  int clientPort
					  )
	throws java.io.IOException
	/* Returns a socket connected to a ServerSocket at the specified network address and port. The client is bound to the specified network address and port, and the socket is configured using the socket options established for this factory.
	 * Parameters:
	 * 	address - the server network address
	 * 	port - the server port
	 * 	clientAddress - the client network address
	 * 	clientPort - the client port
	 * Throws:
	 * 	java.io.IOException - if the connection can't be established
	 */
    {
	return new iaik.security.ssl.SSLSocket ( address, port, defaultContext );
    }

    synchronized public static jacorb.util.net.SocketFactory getDefault()
    /* Returns the default SSL socket factory.
     * If SSL has not been configured for this virtual machine,
     * the factory will be inoperative (reporting instantiation exceptions).
     */
    {
	if ( defaultFactory == null ) {
	    defaultFactory = new SSLSocketFactory ();
	}
	return defaultFactory;
    }

    public java.lang.String[] getDefaultCipherSuites()
    /* Returns the list of cipher suites which are enabled by default. Unless a different list is enabled, handshaking on an SSL connection will use one of these cipher suites. The minimum quality of service for these defaults requires confidentiality protection and server authentication.
     * Returns:
     *	array of the cipher suites enabled by default
     * See Also: 
     */
    {
	java.lang.String lst [] = new java.lang.String[ cs.length ];
	for ( int i = 0; i < lst.length; i++ )
	    lst [ i ] = cs[ i ].toString ();
	return lst;
    }

    public java.lang.String[] getSupportedCipherSuites()
    /* Returns the names of the cipher suites which could be enabled for use on an SSL connection.
     * Normally, only a subset of these will actually be enabled by default, since this list may include
     * cipher suites which do not meet quality of service requirements for those defaults.
     * Such cipher suites are useful in specialized applications.
     * Returns:
     * 	an array of cipher suite names
     */
    {
	iaik.security.ssl.CipherSuite [] suites = iaik.security.ssl.CipherSuite.getDefault ();
	java.lang.String lst [] = new java.lang.String[ suites.length ];
	for ( int i = 0; i < lst.length; i++ )
	    lst [ i ] = suites[ i ].toString ();
	return lst;
    }

    public static boolean isSSL ( java.net.Socket s )
    { return ( s instanceof iaik.security.ssl.SSLSocket); }

    public java.net.Socket createSocket ( java.net.Socket s,
					  java.lang.String host,
					  int port,
					  boolean autoClose
					  )
	throws java.io.IOException
	/* Returns a socket layered over an existing socket to a ServerSocket on the named host, at the given port. This constructor can be used when tunneling SSL through a proxy. The host and port refer to the logical destination server. This socket is configured using the socket options established for this factory.
	 * Parameters:
	 *	s - the existing socket
	 *	host - the server host
	 *	port - the server port
	 *	autoClose - close the underlying socket when this socket is closed
	 * Throws:
	 *	java.io.IOException - if the connection can't be established
	 *	java.net.UnknownHostException - if the host is not known
	 */
    {
	// iaik.security.ssl.Socket has no constructor supporting this.
	throw new java.io.IOException ( "Not implemented by this factory" );
    }
}
