//  Libiqxmlrpc - an object-oriented XML-RPC solution.
//  Copyright (C) 2004-2006 Anton Dedov
//
//  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 (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
//  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
//
//  $Id: ssl_lib.h,v 1.4 2006-09-07 04:45:21 adedov Exp $

/*! \file */
#ifndef _libiqnet_ssl_lib_h_
#define _libiqnet_ssl_lib_h_

#include "api_export.h"

#include <openssl/ssl.h>

#include <stdexcept>

namespace iqnet {
namespace ssl {

class Ctx;

//! Global SSL context.
/*! One must initialize it with appropriate ssl::Ctx
    object before using iqnet's SSL code.
    \see ssl::Ctx
*/
extern LIBIQXMLRPC_API Ctx* ctx;

//! Throws concrete SSL IO subsystem's exception.
void LIBIQXMLRPC_API throw_io_exception( SSL*, int ret );

//! SSL context class. Initializes SSL library.
/*!
  \code
  using namespace iqnet;
  ssl::ctx = ssl::Ctx::client_server( "/path/to/cert", "/path/to/key" );
  //...
  \endcode
*/
class LIBIQXMLRPC_API Ctx {
  static bool initialized;
  SSL_CTX* ctx;

public:
  static Ctx* client_server( const std::string& cert_path, const std::string& key_path );
  static Ctx* server_only( const std::string& cert_path, const std::string& key_path );
  static Ctx* client_only();

  ~Ctx();

  SSL_CTX* context() { return ctx; }

private:
  Ctx( const std::string&, const std::string&, bool init_client );
  Ctx();

  void init_library();
};

//! Exception class to wrap errors generated by openssl library.
class LIBIQXMLRPC_API exception: public std::exception {
  unsigned long ssl_err;
  std::string msg;

public:
  exception() throw();
  explicit exception( unsigned long ssl_err ) throw();
  exception( const std::string& msg ) throw();
  virtual ~exception() throw() {}

  const char*   what() const throw() { return msg.c_str(); }
  unsigned long code() const throw() { return ssl_err; }
};

class LIBIQXMLRPC_API not_initialized: public ssl::exception {
public:
  not_initialized():
    exception( "Libiqnet::ssl not initialized." ) {}
};

class LIBIQXMLRPC_API connection_close: public ssl::exception {
  bool clean;
public:
  connection_close( bool clean_ ):
    exception( "Connection has been closed." ),
    clean(clean_) {}

  bool is_clean() const { return clean; }
};

class LIBIQXMLRPC_API io_error: public ssl::exception {
public:
  io_error( int err ):
    exception( err ) {}
};

class LIBIQXMLRPC_API need_write: public ssl::io_error {
public:
  need_write():
    io_error( SSL_ERROR_WANT_WRITE ) {}
};

class LIBIQXMLRPC_API need_read: public ssl::io_error {
public:
  need_read():
    io_error( SSL_ERROR_WANT_READ ) {}
};

} // namespace ssl
} // namespace iqnet

#endif
