#define USE_SOCKETS
#ifndef WIN32
#define SOCKET int
#endif

#ifdef __XCODE__
#include "xcode_quiet.h"
#endif

#include "tcplib.h"

#ifdef WIN32
#include <windows.h>
#include <wincrypt.h>
#endif

#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "lprintf.h"
#include "lib.h"

#ifdef DO_THREADS
#include "thread.h"
#endif

#ifdef OPENSSL
#include "encrypt_lib.h"
#include <openssl/rsa.h>       /* SSLeay stuff */
#include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/pem.h>
#define HAS_DH 1 
#ifndef HAS_DH
#include <openssl/dh.h>
#endif

#else
#include "sslc.h"
#include "cert.h"
#endif
#include "myssl.h"
#include "emsg.h"
#ifdef DO_THREADS
#include "mt_cb.h"
#endif
#include <stdio.h>
#include <stdarg.h>
#ifdef WIN32
#include <direct.h>
#define mkdir _mkdir
#endif
#include "lib.h"
#include "calist.h"
#include "tcplib.h"
#define DMID 15
#include "debug.h"

#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE (!FALSE)
#endif


enum {T_CTX,T_SSL,T_BIO,T_PKEY,T_MALLOC, T_LAST};
static char *tname[] = {"ctx","ssl","bio","pkey","malloc"};

int tssl_count(int type, int add);
void tssl_show(void);
static int debug=FALSE;
int bio_count(BIO *x)
{
	int n=0;
	for (;x!=NULL;) {
		n++;
        x = BIO_next(x);
	}
	return n;
}

BIO *TBIO_new_fp(FILE *stream, int close_flag, char *src, int line)
{
	if (debug) printf("bio_new_fp %s %d\n",src,line);
	tssl_count(T_BIO,1);
	return BIO_new_fp(stream,close_flag);
}
void TBIO_free_all(BIO *b, char *src, int line)
{
	int n = bio_count(b);
	if (debug) printf("TBIO_FREE_all %s:%d %d\n",src,line,n);
	tssl_count(T_BIO,-n);
	BIO_free_all(b);
}
void TBIO_free(BIO *b, char *src, int line)
{
	int n = bio_count(b);
	if (debug) printf("TBIO_FREE %s:%d\n",src,line);
	if (n>1) {		
		emsg("tbio_free: freeing bio which was a bio chain\n");
		lib_abort();
	}
	tssl_count(T_BIO,-1);
	BIO_free(b);
}
BIO *TBIO_new_socket(int sock, int close_flag, char *src, int line)
{
	if (debug) printf("bio_new_socket %s %d\n",src,line);
	tssl_count(T_BIO,1);
	return BIO_new_socket(sock,close_flag);	
}
BIO *	TBIO_new(BIO_METHOD *type, char *src, int line)
{
	if (debug) printf("bio_new %s %d\n",src,line);
	tssl_count(T_BIO,1);
	return BIO_new(type);
}
BIO *TBIO_new_mem_buf(const void *buf, int len, char *src, int line)
{
	if (debug) printf("bio_new_buf %s %d\n",src,line);
	tssl_count(T_BIO,1); 
	return BIO_new_mem_buf(buf,len);
}
void TSSL_set_bio(SSL *a, BIO *r, BIO *w)
{
	if (debug) printf("set_bio\n");
	tssl_count(T_BIO,-1); //frees counter of bio as it's freed in ssl_Free...
	SSL_set_bio(a,r,w);
}

void TSSL_free(SSL *ssl)
{
	tssl_count(T_SSL,-1);
	SSL_free(ssl);
}
SSL *TSSL_new(SSL_CTX *ctx)
{
	tssl_count(T_SSL,1);
	return SSL_new(ctx);
}


SSL_CTX *TSSL_CTX_new(const SSL_METHOD *meth, char *src, int line)
{
	tssl_count(T_CTX,1);
	
	return SSL_CTX_new(meth);
}
void TSSL_CTX_free(SSL_CTX *x)
{
	tssl_count(T_CTX,-1);
	SSL_CTX_free(x);
}
EVP_PKEY * TEVP_PKEY_new(void)
{
	tssl_count(T_PKEY,1);
	return EVP_PKEY_new();
}
EVP_PKEY *TPEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x,pem_password_cb *cb, void *u)
{
	tssl_count(T_PKEY,1);
	return PEM_read_bio_PrivateKey(bp,x,cb,u);
}

X509 *TPEM_read_bio_X509(BIO *bp, X509 **x, pem_password_cb *cb, void *u)
{
	tssl_count(T_PKEY,1);
	return PEM_read_bio_X509(bp,x,cb,u);
}
X509 *TX509_new(void)
{
	return X509_new();
}
void TX509_free(X509 *a)
{
	X509_free(a);
}

RSA * TRSA_new(void)
{
	return RSA_new();
}
void TRSA_free(RSA *rsa)
{
	RSA_free(rsa);
}

void TEVP_PKEY_free(EVP_PKEY *pkey)
{
	tssl_count(T_PKEY,-1);
	EVP_PKEY_free(pkey);
}

static int totals[T_LAST+1];
int tssl_count(int type, int add)
{
	int r;
	myssl_mutex_wait();
	r = totals[type] += add;
	myssl_mutex_release(__LINE__);
	return r;
}
int tssl_count_ssl(void)
{
	return totals[T_SSL];
}
void tssl_show()
{
	int i;
	for (i=0; i<T_LAST; i++) {
		printf("OPENSSL: %s %d\n",tname[i],totals[i]);
		emsg("OPENSSL: %s %d\n",tname[i],totals[i]);
	}
	printf("\n");
}
