/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 *
 * The iWear Framework is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation as in version 2 of the License.

 * 
 * The iWear Framework 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 General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWEAR_SSLFILTER_H
#define __IWEAR_SSLFILTER_H

#ifndef __IWEAR_SSL_H
#include <net/ssl.h>
#endif

#ifndef __IWEAR_CONNECTION_H
#include <net/connection.h>
#endif

#define DEFAULT_KEY_FILENAME "host.pem"
#define DEFAULT_CERT_FILENAME "certs.pem"

namespace iwear
{
    namespace net
    {

enum ssl_role {
    ssl_client = 0,
    ssl_server = 1
};

class SSLFilter
{
    private:
	/**
	 * SSL_CTX object.
	 */
	SSL_CTX *ssl_ctx;

	/**
	 * SSL object.
	 */
	SSL *ssl;

	/**
	 * BIO for internal purposed. Required for BIO_pair.
	 */
	BIO *internal_bio;
	
	/**
	 * BIO for reading and writing cipher text from/to network
	 */
	BIO *network_bio;

	/**
	 * BIO for reading and writing plain text
	 */
	BIO *ssl_bio;

	/**
	 * Connection reference used to store connection given in constructor.
	 */
	Connection& conn;
	
	/**
	 * Holds the role, ssl_client or ssl_server.
	 */
	ssl_role role;
	
	string keyfile;
	string certfile;

	int bufcount;

	/**
	 * Buffer for synchronizing read data from Network. This is used
	 * by sync_network_read. Required because the other side can send
	 * more data than needed in the current step.
	 */
	char sync_recv_buf[4096];

	/**
	 * Index pointing to the start of the pending data in the buffer.
	 */
	int sync_recv_buf_ptr;

	/**
	 * Amount of pending bytes still in buffer.
	 */
	int sync_recv_pending;

	/**
	 * Synchronizes encrypted data from network to application
	 * during handshake. Calls read of the underlying connection to do so.
	 */
	virtual bool sync_network_read( void );

	/**
	 * Synchronizes encrypted data from network to application
	 * during handshake. Calls write of the underlying connection to do so.
	 */
	virtual bool sync_network_write( void );
	
	/**
	 * Temporary RSA Callback function - generates an RSA key of given length.
	 * Called by OpenSSL Library when a temporary/ephemeral RSA key is required.
	 */
	static RSA *tmp_rsa_callback(SSL *ssl, int is_export, int keylength);
	
	/**
	 * Temporary DH Callback function - creates DH parameters of given length.
	 * Called by OpenSSL Library when temporary DH parameters are required,
	 * e.g. when the server sends its certificate.
	 * @note The DH parameters are compiled in because calculation takes some time.
	 */
	static DH *tmp_dh_callback(SSL *ssl, int is_export, int keylength);
	
	/**
	 * Certificate verification callback function.
	 * Called by OpenSSL when certificate verification happens.
	 */
	static int verify_callback(int ok, X509_STORE_CTX *ctx);

	int alert_code;

	static void info_callback(const SSL* ssl, int where, int ret);
	
    protected:
	
    public:
	/**
	 * Constructor.
	 * Creates a new SSLFilter Object for the given Connection.
	 * ssl_role is used to specifiy if we are on the client or server
	 * side, valid values are ssl_client or ssl_server.
	 */
	SSLFilter( Connection&, ssl_role );

	/**
	 * Destructor.
	 * Frees all BIOs used, and shuts down SSL and deletes SSL and SSL_CTX objects.
	 */
	virtual ~SSLFilter();

	/**
	 * This function performs handshake between client and server (and vice-versa).
	 */
	virtual bool handshake( void );

	/**
	 * Encrypts len bytes of data from buffer buf. Returns a pointer
	 * to the encrypted data, and len is set to the length of the
	 * encrypted data.
	 */
	virtual char* encrypt( const void *buf, ssize_t *len );

	/**
	 * Decrypts size bytes of data from buffer buf, and stores plain text
	 * to buffer dest, and size is set to the length of this plain text.
	 */
	virtual char* decrypt( char *dest, const void *buf, ssize_t *size );

	/**
	 * This function retrieves the peer's certificate.
	 */
	virtual X509* get_cert( void ) const;
};
    }
}
#endif

