/*******************************************************************************
 * Copyright (c) 2008 Intel Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Igor Alelekov, Intel - Initial API and implementation
 *
 * $Id: SSLSupport.c,v 1.2 2008/02/06 12:40:06 ialelekov Exp $
 *******************************************************************************/ 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "SSLTypes.h"
#include "SSLSupport.h"
#include "SocketTLLog.h"
#include "tptp/TPTPUtils.h"
#include "tptp/tptpSSLProvider.h"

/* Resolved SSL functions */
static ssl_provider_accept_t ssl_provider_accept; 
static ssl_provider_handshake_t ssl_provider_handshake; 
static ssl_provider_read_t ssl_provider_read; 
static ssl_provider_write_t ssl_provider_write; 
static ssl_provider_close_t ssl_provider_close; 
static ssl_provider_reset_t ssl_provider_reset; 
static ssl_provider_reset_t ssl_provider_reset; 
static ssl_provider_getValue_t ssl_provider_getValue; 
static ssl_provider_setValue_t ssl_provider_setValue; 
static ssl_provider_getName_t ssl_provider_getName; 

int ssl_init(server_block_ptr_t pServerData) {
	tptp_param_t* param;
	tptp_node_t*  node;
	log_service_t* logService;
	char *fullLibName;

	DLL_REFERENCE sslLibrary;
	ssl_provider_init_t ssl_provider_init;
	int rc;

	if (!pServerData->securityEnabled) return 0;

	if (pServerData->sslProviderLib == NULL) {
		TPTP_LOG_ERROR_MSG(pServerData, "No ssl provider library supplied");
		return -1;
	}

#ifdef _WIN32
	fullLibName = pServerData->sslProviderLib;
#else
	fullLibName = (char*) malloc(strlen(pServerData->sslProviderLib)+7);
	sprintf(fullLibName, "lib%s.so", pServerData->sslProviderLib);
#endif

	sslLibrary = LOAD_LIBRARY(fullLibName);
	
#ifndef _WIN32
	free(fullLibName);
	fullLibName = NULL;
#endif
	
	if (sslLibrary == NULL) {
		TPTP_LOG_ERROR_MSG1(pServerData, "Unable to find ssl provider library %s", pServerData->sslProviderLib);
		return -1;
	}

	ssl_provider_init = (ssl_provider_init_t) RESOLVE_ENTRY_POINT(sslLibrary, SSL_INIT);
	ssl_provider_accept = (ssl_provider_accept_t) RESOLVE_ENTRY_POINT(sslLibrary, SSL_ACCEPT); 
	ssl_provider_handshake = (ssl_provider_handshake_t) RESOLVE_ENTRY_POINT(sslLibrary, SSL_HANDSHAKE); 
	ssl_provider_read = (ssl_provider_read_t) RESOLVE_ENTRY_POINT(sslLibrary, SSL_READ);
	ssl_provider_write = (ssl_provider_write_t) RESOLVE_ENTRY_POINT(sslLibrary, SSL_WRITE); 
	ssl_provider_close = (ssl_provider_close_t) RESOLVE_ENTRY_POINT(sslLibrary, SSL_CLOSE); 
	ssl_provider_reset = (ssl_provider_reset_t) RESOLVE_ENTRY_POINT(sslLibrary, SSL_RESET); 
	ssl_provider_getValue = (ssl_provider_getValue_t) RESOLVE_ENTRY_POINT(sslLibrary, SSL_GET_VALUE); 
	ssl_provider_setValue = (ssl_provider_setValue_t) RESOLVE_ENTRY_POINT(sslLibrary, SSL_SET_VALUE); 
	ssl_provider_getName = (ssl_provider_getName_t) RESOLVE_ENTRY_POINT(sslLibrary, SSL_GET_PROVIDER_NAME); 
	
    /* Check to make sure we found everything */ 
    if (ssl_provider_init &&
    	ssl_provider_accept &&
    	ssl_provider_handshake &&
    	ssl_provider_read &&
    	ssl_provider_write &&
    	ssl_provider_close &&
    	ssl_provider_reset &&
    	ssl_provider_getValue &&
    	ssl_provider_setValue &&
    	ssl_provider_getName) {

		for (node = pServerData->params->head; node != 0; node = node->next) {
			param = (tptp_param_t*) node->data;
			if (param != NULL && param->name != NULL && param->value != NULL) {
				ssl_setValue(param->name, param->value);
			}
		}
    	
    	logService = (log_service_t*) tptp_malloc(sizeof(log_service_t));
    	logService->cmo = pServerData->cmo;
    	logService->logEventEntry = pServerData->agentControllerDataBlk.logEventEntry;
    	
		rc = (*ssl_provider_init)(logService, pServerData->port);
		if (rc) {
			TPTP_LOG_ERROR_MSG1(pServerData, "Unable to initialize ssl provider %s", pServerData->sslProviderLib);
		} else {
			TPTP_LOG_DEBUG_MSG1(pServerData, "SSL provider \"%s\" successfully initialized", ssl_getProviderName());
		}
    } 
	else {
		TPTP_LOG_ERROR_MSG1(pServerData, "Unable to resolve ssl provider library %s", pServerData->sslProviderLib);
		rc = -1;
	}
	
	return rc;
}

ssl_socket_t ssl_accept() {
	return (ssl_provider_accept == NULL) ? NULL : (*ssl_provider_accept)();
}

int ssl_handshake(ssl_socket_t ssl_socket) {
	return (ssl_socket == NULL || ssl_provider_handshake == NULL) ? -1 : (*ssl_provider_handshake)(ssl_socket);
}

int ssl_read(ssl_socket_t ssl_socket, char* buffer, int length) {
	return (ssl_socket == NULL || ssl_provider_read == NULL) ? -1 : (*ssl_provider_read)(ssl_socket, buffer, length);
}

int ssl_write(ssl_socket_t ssl_socket, char* buffer, int length) {
	return (ssl_socket == NULL || ssl_provider_write == NULL) ? -1 : (*ssl_provider_write)(ssl_socket, buffer, length);
}

int ssl_close(ssl_socket_t ssl_socket) {
	return (ssl_socket == NULL || ssl_provider_close == NULL) ? -1 : (*ssl_provider_close)(ssl_socket);
}

int ssl_reset() {
	return (ssl_provider_reset == NULL) ? -1 : (*ssl_provider_reset)();
}

char* ssl_getValue(const char* name) {
	return (ssl_provider_getValue == NULL) ? NULL : (*ssl_provider_getValue)(name);
}

void ssl_setValue(const char* name, const char* value) {
	if (ssl_provider_setValue != NULL) (*ssl_provider_setValue)(name, value);
}

char* ssl_getProviderName() {
	return (ssl_provider_getName == NULL) ? NULL : (*ssl_provider_getName)();
}
