/*--- formatted by Jindent 2.1, (www.c-lab.de/~jindent) ---*/

/**
 * ***************************************************************
 * The LEAP libraries, when combined with certain JADE platform components,
 * provide a run-time environment for enabling FIPA agents to execute on
 * lightweight devices running Java. LEAP and JADE teams have jointly
 * designed the API for ease of integration and hence to take advantage
 * of these dual developments and extensions so that users only see
 * one development platform and a
 * single homogeneous set of APIs. Enabling deployment to a wide range of
 * devices whilst still having access to the full development
 * environment and functionalities that JADE provides.
 * Copyright (C) 2001 Telecom Italia LAB S.p.A.
 * Copyright (C) 2001 Broadcom Eireann Research.
 * Copyright (C) 2001 Motorola.
 * 
 * GNU Lesser General Public License
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation,
 * version 2.1 of the License.
 * 
 * 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 * **************************************************************
 */
package jade.imtp.leap.JICP;

//#J2ME_EXCLUDE_FILE

import jade.core.Profile;
import jade.mtp.TransportAddress;
import jade.imtp.leap.*;
import jade.imtp.leap.SSLHelper;
import jade.util.Logger;
import java.io.*;
import java.net.*;
import javax.net.ssl.*;



/**
 * JICPSPeer  -  JICP Secure Peer
 * 
 * This JICP peer uses secure connections 
 * with or without mutual authentication 
 * of the endpoints by using digital certificates.
 * It leverages SSL/TLS.
 *
 * @author Giovanni Caire - TILAB
 * @author Giosue Vitaglione - TILAB
 * @author Jamie Lawrence - Broadcom Eireann Research
 * @author Ronnie Taib - Motorola
 * @author Nicolas Lhuillier - Motorola
 */
public class JICPSPeer extends JICPPeer {


	protected static Logger myLogger = Logger.getMyLogger( JICPSPeer.class.getName() );
	private SSLContext ctx = null;

	public TransportAddress activate(ICP.Listener l, String peerID, Profile p) throws ICPException {
		if (myLogger.isLoggable(Logger.FINE)) {
			myLogger.log(Logger.FINE, 
					"About to activate JICP peer." );
		}
		ctx = SSLHelper.createContext(); // create context at activation time
                setUseSSLAuth(SSLHelper.needAuth());
		if (myLogger.isLoggable(Logger.FINE)) {
			myLogger.log(Logger.FINE, 
					"activate() context created ctx="+ctx );
		}
		TransportAddress ta = super.activate(l, peerID, p);
		if (myLogger.isLoggable(Logger.INFO)) {
			myLogger.log(Logger.INFO, 
					"JICP Secure Peer activated. (auth="+getUseSSLAuth()+", ta="+ta+")");
		}
		return ta;
	}

	/**
     Subclasses may re-define this method to return their own
     ConnectionFactory
	 */
	public ConnectionFactory getConnectionFactory() {
		return new ConnectionFactory() {
			public Connection createConnection(Socket s) {
				return new JICPSConnection(s);
			}
			public Connection createConnection(TransportAddress ta) throws IOException {
				return new JICPSConnection(ta, getUseSSLAuth());
			}
		};
	}

	protected ServerSocket getServerSocket(String host, int port, boolean changePortIfBusy) throws ICPException {
		// socket to be created
		ServerSocket sss = null;

		if ( getUseSSLAuth() ) {
			sss=getServerSocketWithAuth(host, port, changePortIfBusy);
			if (myLogger.isLoggable(Logger.FINE)) {
				myLogger.log(Logger.FINE, 
				"Creating JICPSPeer with mutual Authentication." );
			}
		} else {
			sss=getServerSocketNoAuth(host, port, changePortIfBusy);
			if (myLogger.isLoggable(Logger.WARNING)) {
				myLogger.log(Logger.WARNING, 
				"Creating JICPSPeer with NO-AUTHENTICATION (only confidentiality)." );
			}

		}
		return sss;
	}

	private ServerSocket getServerSocketWithAuth(String host, int port, boolean changePortIfBusy) throws ICPException {  
		// Create the SSLContext if necessary
		if (ctx == null) {
			ctx = SSLHelper.createContextWithAuth();
		}

		// socket to be created
		SSLServerSocket sss = null;

		try {
			// create factory
			SSLServerSocketFactory serverSocketFactory = ctx.getServerSocketFactory();
			try {
				// create server socket
				sss =(SSLServerSocket)serverSocketFactory.createServerSocket(port);
			} catch (IOException ioe) {
				if (changePortIfBusy) {
					// The specified port is busy. Let the system find a free one
					try {
						sss = (SSLServerSocket) serverSocketFactory.createServerSocket(0);
					} catch (IOException ioe2) {
						throw new ICPException("Problems initializing server socket. No free port found.", ioe2);
					}
				} else {
					throw new ICPException("I/O error opening server socket on port "+port, ioe);
				} // end if (changePortIfBusy)
			}
		} catch (Exception e) {
			throw new ICPException("Error creating SSLServerSocketFactory.", e);
		}

		if (myLogger.isLoggable(Logger.FINE)) {
			myLogger.log(Logger.FINE, getChiperDebugString(sss) );
		}

		return sss;
	} // end getServerSocketWithAuth

	private static String getChiperDebugString(SSLServerSocket sss){
		// debug
		StringBuffer sb = new StringBuffer();
		sb.append( "\n--EnabledProtocols:\n" );
		String prot[] = sss.getEnabledProtocols();
		for (int i=0; i<prot.length; i++) 
			sb.append( "  "+prot[i] );
		sb.append( "\n--EnabledCipherSuites:\n" );
		String suite[] = sss.getEnabledCipherSuites() ;
		for (int i=0; i<suite.length; i++) 
			sb.append(  "  "+suite[i] );
		sb.append( "\n--SupportedCipherSuites\n" );
		String supported_suite[] = sss.getSupportedCipherSuites() ;
		for (int i=0; i<supported_suite.length; i++) 
			sb.append( "  "+supported_suite[i] );
		sb.append( "\n--\n" );
		return sb.toString();
	}

	private ServerSocket getServerSocketNoAuth(String host, int port, boolean changePortIfBusy) throws ICPException {  
		// Create the SSLContext if necessary
		if (ctx == null) {
			ctx = SSLHelper.createContextNoAuth();
		}
		// Create the SSLServerSocket
		SSLServerSocket sss = null;

		try {
			SSLServerSocketFactory ssf = ctx.getServerSocketFactory();
			try {
				sss = (SSLServerSocket) ssf.createServerSocket(port); 
			} 
			catch (IOException ioe) {
				if (changePortIfBusy) {
					// The specified port is busy. Let the system find a free one
					try {
						sss = (SSLServerSocket) ssf.createServerSocket(0);
					}
					catch (IOException ioe2) {
						throw new ICPException("Problems initializing server socket. No free port found.", ioe2);
					}
				}
				else {
					throw new ICPException("I/O error opening server socket on port "+port, ioe);
				}
			}
		}
		catch (Exception e) {
			throw new ICPException("Error creating SSLServerSocketFactory.", e);
		}

		// Initialize the SSLServerSocket to disable authentication
		try {
			sss.setEnabledCipherSuites(new String[] {"SSL_DH_anon_WITH_RC4_128_MD5"});

			String[] ecs = sss.getEnabledCipherSuites();
			//DEBUG
			//for (int i=0; i<ecs.length; i++) { 
			//	System.out.println("--"+i+"-- "+ecs[i]);
			//}
		}
		catch (Exception e) {
			throw new ICPException("Error enabling cypher suites.", e);
		}

		return sss;
	} // end getServerSocketNoAuth(..)



	private boolean useSSLAuth=false;
	private boolean getUseSSLAuth(){ // if needed, may become public
		return useSSLAuth;
	}
	private void setUseSSLAuth(boolean b){
		useSSLAuth = b;
	}


} // end class

