//______________________________________________________________________________
//   |       |
//   | knipp |           Knipp Medien und Kommunikation GmbH
//    -------
//
//
//     Knipp RRI Toolkit
//
//
//     Copyright (C) 2005 by Knipp Medien und Kommunikation GmbH
//
//     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; either version 2.1 
//     of the License, or 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 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 
//
//
//     initial author:    Klaus Malorny
//
//     version:           1.3 (15112), 2011/05/27 16:00:14
//                        $Revision: 14936 $ 
//                        $Date: 2010-11-05 15:57:40 +0100 (Fri, 05 Nov 2010) $
//                        $Author: Klaus.Malorny $
//

package de.knipp.rritoolkit.tcp;

import java.io.File;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.IOException;

import java.net.InetAddress;

import java.util.Properties;

import java.security.KeyStore;
import java.security.GeneralSecurityException;

  
/**
 *  class that holds the configuration data for the TCP connection
 *
 *  @version  $Revision: 14936 $
 *  @author   Klaus Malorny
 */

public class TcpParams
{
  /** the address of the server */
  
  private InetAddress serverAddress;
  
  
  /** the port number of the server */
  
  private int serverPort;

  
  /** the protocol */
  
  private String protocol;
  
  
  /** the client cert algorithm */
  
  private String clientCertAlgorithm;
  
    
  /** the trust certs algorithm */
  
  private String trustedCertsAlgorithm;
  
  
  /** the password for the certificate */
  
  private String certPassword;
  
  
  /** the keystore that holds the own certificates */
  
  private KeyStore certKeyStore;
  
  
  /** the keystore that holds the trusted root certificates */
  
  private KeyStore trustKeyStore;
  

  /** flag whether to check the CN */
  
  private boolean verifyServerName;
  
  
  /** the maximum receive message size */
  
  private int maxReceiveSize;
  
  
  /** the wait timeout in milliseconds */
  
  private int receiveTimeout;
  
  
  /** the idle timeout in milliseconds ({@code 0} = off) */
  
  private long idleTimeout;
  
  
  /**
   *  constructor. The protocol and the algorithms are initialized with
   *  Sun's recommendations.
   */
  
  public TcpParams ()
  {
    protocol = "TLS";
    clientCertAlgorithm = "SunX509";
    trustedCertsAlgorithm = "SunX509";
    verifyServerName = true;
  }
  
  
  /**
   *  copy constructor
   *
   *  @param other                 the other instance to copy from
   */
  
  public TcpParams (TcpParams other)
  {
    serverAddress = other.serverAddress;
    serverPort = other.serverPort;
    protocol = other.protocol;
    clientCertAlgorithm = other.clientCertAlgorithm;
    trustedCertsAlgorithm = other.trustedCertsAlgorithm;
    certPassword = other.certPassword;
    certKeyStore = other.certKeyStore;
    trustKeyStore = other.trustKeyStore;
    verifyServerName = other.verifyServerName;
    maxReceiveSize = other.maxReceiveSize;
    receiveTimeout = other.receiveTimeout;
    idleTimeout = other.idleTimeout;
  }
  
  
  
  
  /**
   *  set the server address
   *
   *  @param address                   the address
   */
  
  public void setServerAddress (InetAddress address)
  {
    serverAddress = address;
  }
  
  
  
  /**
   *  return the server address
   *
   *  @return                          the server address
   */
  
  public InetAddress getServerAddress ()
  {
    return serverAddress;
  }
  
  
  
  /**
   *  set the server port number
   *
   *  @param port                      the port number
   */
  
  public void setServerPort (int port)
  {
    serverPort = port;
  }
  
  
  
  /**
   *  return the server port number
   *
   *  @return                          the port number
   */
  
  public int getServerPort ()
  {
    return serverPort;
  }
  
  
  
  /**
   *  set the maximum message size that is accepted. 
   *
   *  @param maxSize              the size or {@code 0} for unlimited size
   */
  
  public void setMaxReceiveSize (int maxSize)
  {
    maxReceiveSize = maxSize;
  }
  
  
  
  /**
   *  return the maximum message size that is accepted.
   *
   *  @return                     the size or {@code 0} for unlimited size
   */
  
  public int getMaxReceiveSize ()
  {
    return maxReceiveSize;
  }

  
  /**
   *  set the maximum time to wait for a response
   *
   *  @param timeout              the timeout time in milliseconds, if
   *                              {@code 0}, it is waited indefinitely
   */
  
  public void setReceiveTimeout (int timeout)
  {
    receiveTimeout = timeout;
  }
  
  
  /**
   *  return the maximum time to wait for a response
   *
   *  @return                     the timeout time in milliseconds, if
   *                              {@code 0}, it is waited indefinitely
   */
  
  public int getReceiveTimeout ()
  {
    return receiveTimeout;
  }
  
  
  
  
  /**
   *  set the delay from which on an idle connection is considered as closed
   *
   *  @param timeout              the idle timeout (off if {@code 0})
   */
  
  public void setIdleTimeout (long timeout)
  {
    idleTimeout = timeout;
  }
  
  
  
  /**
   *  return the delay from which on an idle connection is considered as 
   *  closed
   *
   *  @return                    the idle timeout ({@code 0} if off)
   */
  
  public long getIdleTimeout ()
  {
    return idleTimeout;
  }
  
  
  
  /**
   *  set the name of the SSL protocol
   *
   *  @param theProtocol               the protocol's name
   */
  
  public void setProtocol (String theProtocol)
  {
    protocol = theProtocol;
  }
  
  
  
  /**
   *  return the name of the SSL protocol
   *
   *  @return                          the protocol's name
   */
  
  public String getProtocol ()
  {
    return protocol;
  }
  
  
  
  /**
   *  set the name of the client certificate algorithm
   *
   *  @param algorithm                 the name
   */
  
  public void setCertAlgorithm (String algorithm)
  {
    clientCertAlgorithm = algorithm;
  }
  
  
  /**
   *  return the name of the client certificate algorithm
   *
   *  @return                          the name
   */
  
  public String getCertAlgorithm ()
  {
    return clientCertAlgorithm;
  }
  
  

  /**
   *  set the name of the trusted certificates algorithm
   *
   *  @param algorithm                 the name
   */
  
  public void setTrustAlgorithm (String algorithm)
  {
    trustedCertsAlgorithm = algorithm;
  }
  
  
  /**
   *  return the name of the trusted certificates algorithm
   *
   *  @return                          the name
   */
  
  public String getTrustAlgorithm ()
  {
    return trustedCertsAlgorithm;
  }
  
  
  
  
  /**
   *  load a key store
   *
   *  @param is                        the input stream
   *  @param storeType                 the store type (may be {@code null}
   *                                   for the default type)
   *  @param storePassword             the store password (may be
   *                                   {@code null})
   *  @return                          the loaded key store
   *  @throws IOException              if the loading failed due to I/O problems
   *  @throws GeneralSecurityException if the key store could not be loaded
   */
  
  private static KeyStore loadKeyStore (InputStream is, String storeType,
    String storePassword)
    throws IOException, GeneralSecurityException
  {
    if (storeType == null) storeType = KeyStore.getDefaultType ();
    KeyStore store = KeyStore.getInstance (storeType);
    
    store.load (is, storePassword == null ? 
      null : storePassword.toCharArray ());
    
    return store;
  }
  
  
  
  /**
   *  load a key store from the given file
   *
   *  @param file                      the file
   *  @param storeType                 the store type (may be {@code null}
   *                                   for the default type)
   *  @param storePassword             the store password (may be
   *                                   {@code null})
   *  @return                          the loaded key store
   *  @throws IOException              if the loading failed due to I/O problems
   *  @throws GeneralSecurityException if the key store could not be loaded
   */
  
  private static KeyStore loadKeyStore (File file, String storeType,
    String storePassword)
    throws IOException, GeneralSecurityException
  {
    return loadKeyStore (new FileInputStream (file), storeType, storePassword);
  }
  
  
  
  /**
   *  set the client certificate key store
   *
   *  @param keyStore                  the key store
   */
  
  public void setCertKeyStore (KeyStore keyStore)
  {
    certKeyStore = keyStore;
  }
  
  
  /**
   *  set the client certificate key store
   *
   *  @param is                        the input stream
   *  @param storeType                 the store type (may be {@code null}
   *                                   for the default type)
   *  @param storePassword             the store password (may be
   *                                   {@code null})
   *  @throws IOException              if the loading failed due to I/O problems
   *  @throws GeneralSecurityException if the key store could not be loaded
   */
  
  public void setCertKeyStore (InputStream is, String storeType, 
    String storePassword)
    throws IOException, GeneralSecurityException
  {
    certKeyStore = loadKeyStore (is, storeType, storePassword);
  }
    
  
  /**
   *  set the client certificate key store
   *
   *  @param file                      the file
   *  @param storeType                 the store type (may be {@code null}
   *                                   for the default type)
   *  @param storePassword             the store password (may be
   *                                   {@code null})
   *  @throws IOException              if the loading failed due to I/O problems
   *  @throws GeneralSecurityException if the key store could not be loaded
   */
  
  public void setCertKeyStore (File file, String storeType,
    String storePassword)
    throws IOException, GeneralSecurityException
  {
    certKeyStore = loadKeyStore (file, storeType, storePassword);
  }
  
  
  
  /**
   *  return the client key store
   *
   *  @return                         the key store, may be {@code null}
   */
  
  public KeyStore getCertKeyStore ()
  {
    return certKeyStore;
  }  
  
  /**
   *  set the password for the private key of the client certificate
   *
   *  @param password                  the password, may be {@code null}
   */
  
  public void setCertPassword (String password)
  {
    certPassword = password; 
  }
  
  
  
  /**
   * return the password for the private key of the client certificate
   *
   *  @return                          the password, may be {@code null}
   */
  
  public String getCertPassword ()
  {
    return certPassword;
  }

  
  
  
  /**
   *  set the trust certificate key store
   *
   *  @param keyStore                  the key store
   */
  
  public void setTrustKeyStore (KeyStore keyStore)
  {
    trustKeyStore = keyStore;
  }
  
  
  /**
   *  set the trust certificate key store
   *
   *  @param is                        the input stream
   *  @param storeType                 the store type (may be {@code null}
   *                                   for the default type)
   *  @param storePassword             the store password (may be
   *                                   {@code null})
   *  @throws IOException              if the loading failed due to I/O problems
   *  @throws GeneralSecurityException if the key store could not be loaded
   */
  
  public void setTrustKeyStore (InputStream is, String storeType, 
    String storePassword)
    throws IOException, GeneralSecurityException
  {
    trustKeyStore = loadKeyStore (is, storeType, storePassword);
  }
    
  
  /**
   *  set the trust certificate key store
   *
   *  @param file                      the file
   *  @param storeType                 the store type (may be {@code null}
   *                                   for the default type)
   *  @param storePassword             the store password (may be
   *                                   {@code null})
   *  @throws IOException              if the loading failed due to I/O problems
   *  @throws GeneralSecurityException if the key store could not be loaded
   */
  
  public void setTrustKeyStore (File file, String storeType,
    String storePassword)
    throws IOException, GeneralSecurityException
  {
    trustKeyStore = loadKeyStore (file, storeType, storePassword);
  }
  
  
  
  /**
   *  return the client key store
   *
   *  @return                         the key store, may be {@code null}
   */
  
  public KeyStore getTrustKeyStore ()
  {
    return trustKeyStore;
  }  

  
  /**
   *  set whether the common name of the server certificate shall be
   *  verified, i.e. shall be compared to the reverse mapping of the
   *  server address.
   *
   *  @param verify               if {@code true}, the name is verified
   */
  
  public void setVerifyServerName (boolean verify)
  {
    verifyServerName = verify;
  }
  
  
  
  /**
   *  return whether the server name shall be verified
   *
   *  @return               {@code true} if so
   */
  
  public boolean verifyServerName ()
  {
    return verifyServerName;
  }
  
  
  
  
  
  /**
   *  initialize the object from the given properties. Missing properties
   *  cause the respective data unchanged. The following properties are
   *  recognized:<br><br>
   *  <table border=0>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>server.name</td>
   *  <td valign=baseline>required</td>
   *  <td valign=baseline>Host name or IP address of server</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>server.port</td>
   *  <td valign=baseline>required</td>
   *  <td valign=baseline>Port number</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>protocol</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>The protocol name</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>cert.algorithm</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>The designated algorithm for dealing with client
   *    certificates</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>cert.keystore.path</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>The path to the file containing the 
   *    client certificate</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>cert.keystore.type</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>The type of the key store, typically "jks" 
   *    or "pkcs12"</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>cert.keystore.password</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>The password, if the keystore is protected</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>cert.password</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>The password for the certificate itself</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>trust.algorithm</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>The designated algorithm for dealing with trusted
   *    certificates</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>trust.keystore.path</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>The path to the file containing the trusted
   *    root certificates</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>trust.keystore.type</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>The type of the key store, typically "jks" 
   *    or "pkcs12"</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>trust.keystore.password</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>The password, if the keystore is protected</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>trust.verifyname</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>Specifies whether the name shall be verified.
   *    If "true" or "yes" (case insensitive) are specified, the verification
   *    is done</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>timeout.receive</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>the timeout in milliseconds when reading
   *    responses from the server</td>
   *  </tr>
   *  <tr>
   *  <td valign=baseline><i>prefix</i>timeout.idle</td>
   *  <td valign=baseline>optional</td>
   *  <td valign=baseline>the idle timeout in milliseconds. If the given
   *    time no communication has taken place, the connection is considered
   *    as closed</td>
   *  </tr>
   *  </table>
   *
   *  @param props                      the properties
   *  @param prefix                     the prefix
   *  @throws IOException               if the specified files could not be 
   *                                    loaded
   *  @throws GeneralSecurityException  if the key stores or the passwords are
   *                                    invalid
   *  @throws NumberFormatException     if a numeric property is not parsable
   */
  
  public void setupFromProperties (Properties props, String prefix)
    throws IOException, GeneralSecurityException, NumberFormatException
  {
    setServerAddress (InetAddress.getByName (
      props.getProperty (prefix + "server.name")));
    
    setServerPort (Integer.parseInt (
      props.getProperty (prefix + "server.port")));
    
    String temp = props.getProperty (prefix + "protocol");
    if (temp != null) setProtocol (temp);
    
    temp = props.getProperty (prefix + "cert.algorithm");
    if (temp != null) setCertAlgorithm (temp);
    
    temp = props.getProperty (prefix + "cert.keystore.path");
    
    if (temp != null)
    {
      String type = props.getProperty (prefix + "cert.keystore.type");
      String password = props.getProperty (prefix + "cert.keystore.password");
      setCertKeyStore (new File (temp), type, password);
    }
    
    setCertPassword (props.getProperty (prefix + "cert.password"));
    
    temp = props.getProperty (prefix + "trust.keystore.path");
    
    if (temp != null)
    {
      String type = props.getProperty (prefix + "trust.keystore.type");
      String password = props.getProperty (prefix + "trust.keystore.password");
      setTrustKeyStore (new File (temp), type, password);
    }
    
    temp = props.getProperty (prefix + "trust.verifyname");
    
    if (temp != null)
    {
      temp = temp.toLowerCase ();
      setVerifyServerName (temp.equals ("yes") || temp.equals ("true"));
    }
    
    temp = props.getProperty (prefix + "timeout.receive");
    if (temp != null) setReceiveTimeout (Integer.parseInt (temp));
    
    temp = props.getProperty (prefix + "timeout.idle");
    if (temp != null) setIdleTimeout (Long.parseLong (temp));
  }
  
}



