#include "types.h"
#include "mpool.h"
#include "tktree.h"
#include "clstree.h"
#include "sha1.h"
#include "listen.h"
#include "ssl_conf.h"
#include "rovm.h"

#include "thread.h"
#include "thread_mutex.h"
#include "thread_cond.h"

#include "mpm_worker_fdqueue.h"
#include "mpm_worker_pod.h"
#include "mpm_worker.h"

#include "connection.h"
#include "request.h"
#include "proc_rc.h"

#include "log.h"
#include "common.h"
#include "ticket.h"
#include "utils.h"

/*  _________________________________________________________________
**
**  Logfile Support
**  _________________________________________________________________
*/

static const struct 
{
  const char *cpPattern;
  const char *cpAnnotation;
} ssl_log_annotate[] = 
  {
    { "*envelope*bad*decrypt*", "wrong pass phrase!?" },
    { "*CLIENT_HELLO*unknown*protocol*", "speaking not SSL to HTTPS port!?" },
    { "*CLIENT_HELLO*http*request*", "speaking HTTP to HTTPS port!?" },
    { "*SSL3_READ_BYTES:sslv3*alert*bad*certificate*", "Subject CN in certificate not server name or identical to CA!?" },
    { "*self signed certificate in certificate chain*", "Client certificate signed by CA not known to server?" },
    { "*peer did not return a certificate*", "No CAs known to server for verification?" },
    { "*no shared cipher*", "Too restrictive SSLCipherSuite or using DSA server certificate?" },
    { "*no start line*", "Bad file contents or format - or even just a forgotten SSLCertificateKeyFile?" },
    { "*bad password read*", "You entered an incorrect pass phrase!?" },
    { "*bad mac decode*", "Browser still remembered details of a re-created server certificate?" },
    { NULL, NULL }
  };

static const char *
ssl_log_annotation (const char *error)
{
  int i = 0;
  
  while (ssl_log_annotate[i].cpPattern != NULL
         && rv_strcmp_match (error, ssl_log_annotate[i].cpPattern) != 0)
    i++;
  
  return ssl_log_annotate[i].cpAnnotation;
}

void
ssl_die (void)
{
  /*
   * This is used for fatal errors and here
   * it is common module practice to really
   * exit from the complete program.
   */
  exit (1);
}

/*
 * Prints the SSL library error information.
 */
void
ssl_log_ssl_error (const char *file, int line, int level, struct rovm *r)
{
  unsigned long e;
  
  while ((e = ERR_get_error ())) 
    {
      const char *annotation;
      char err[256];
      
      ERR_error_string_n (e, err, sizeof err);
      annotation = ssl_log_annotation (err);
      
      if (annotation)
        rovm_log (NULL, level, file, line, 
                  "SSL Library Error: %lu %s %s", e, err, annotation);
      else
        rovm_log (NULL, level, file, line, 
                  "SSL Library Error: %lu %s", e, err);
    }
}
