/* Copyright 2013 Akira Ohta (akohta001@gmail.com)
    This file is part of ntch.

    The ntch 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, either version 3 of the License, or
    (at your option) any later version.

    The ntch 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 ntch.  If not, see <http://www.gnu.org/licenses/>.
    
*/
#include <sys/types.h>
#include <sys/socket.h>
/* OpenSSL headers */
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#include "utils/nt_std_t.h"
#include "utils/nt_mutex.h"



BOOL nt_ssl_connect(
			const char *connect_host_string,
			const char *pem_path,
			BOOL strict_verify, 
			char *wr_buf, 
			size_t *data_lenp,
			size_t buf_len)
{
	SSL_CTX  *ctx;
	SSL *ssl;
	BIO *bio;
	BOOL result = FALSE;
	int n, idx;
	int data_len;
	nt_mutex_handle h_mutex;

	
	data_len = *data_lenp;

	SSL_load_error_strings();
	SSL_library_init();

	ctx = SSL_CTX_new(SSLv23_client_method());
	if(!ctx){
		return FALSE;
	}
	
	if(!SSL_CTX_load_verify_locations(ctx, pem_path, NULL))
		goto ERROR_TRAP2;

	bio = BIO_new_ssl_connect(ctx);
	if(!bio)
		goto ERROR_TRAP2;

	BIO_get_ssl(bio, &ssl);
	SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

	BIO_set_conn_hostname(bio, connect_host_string); 

	h_mutex = nt_mutex_get_one_time_handle(NT_MUTEX_ROOT_NAME_NET);
	if(!h_mutex)
		goto ERROR_TRAP1;
	if(!nt_mutex_add_mbs_moniker(h_mutex, connect_host_string))
		goto ERROR_TRAP1;
	nt_mutex_lock(h_mutex);
	if(BIO_do_connect(bio) <= 0){
		nt_mutex_unlock(h_mutex);
		goto ERROR_TRAP1;
	}
	nt_mutex_unlock(h_mutex);
	
	if(SSL_get_verify_result(ssl) != X509_V_OK){
		if(strict_verify)
			goto ERROR_TRAP1;
	}


	idx = 0;
	while(idx < data_len){
		n = BIO_write(bio, wr_buf+idx, data_len-idx);
		if(n <= 0 && !BIO_should_retry(bio))
			goto ERROR_TRAP1;
		idx += n;
	}
	idx = 0;
	while(1){
		n = BIO_read(bio, wr_buf+idx, buf_len-idx);
		if(n < 0)
			goto ERROR_TRAP1;
		if(n == 0)
			break;
		idx += n;
		if(idx >= buf_len)
			goto ERROR_TRAP1;
	}
	*data_lenp = idx;
	
	result = TRUE;


ERROR_TRAP1:
	BIO_free_all(bio);
ERROR_TRAP2:
	SSL_CTX_free(ctx);

	ERR_free_strings();

	return result;
}
