#include <errno.h>
#include <iostream>
#include <string>
#include <sstream>
#include <fcntl.h>
#include <arpa/inet.h>
#include "openssl/ssl.h"
#include "openssl/bio.h"
#include "openssl/err.h"
#include "BaseSocket.h"

using namespace std;

class CServerSocket : public CBaseSocket
{
public:

	/// @brief 생성자.
	CServerSocket( const int & socket)
		: CBaseSocket(socket)	{	};

	/// @brief 소멸자.
	~CServerSocket() { Close(); };

	ssize_t ReadEx( void * vptr, size_t size )
	{ return Read(vptr, size); };

};

int main ( int argc, char * argv[] )
{
	if(argc != 4)
	{
		cerr << argv[0] << " server port file" << endl;
		return EXIT_FAILURE;
	}

	int f = open( argv[3], O_RDONLY );

	string sendval;
	if(f > 0 ) 
	{		
		while(true)
		{
			char szBuffer[1024] = {0};
			int n = 0;
			if((n = read(f, szBuffer,sizeof(szBuffer))) <=0)
				break;

			sendval.append(szBuffer,n);
		}

		close( f );
	}
	else
	{
		cerr << "The file '"<< argv[3] << "' was not opened" <<endl;
	}

	cout << "Send Data : " << sendval << ",Size : " << sendval.size () << endl;

    BIO * bio;
    SSL * ssl;
    SSL_CTX * ctx = NULL;
    SSL_METHOD *meth;

    /* Set up the library */
    SSL_library_init();
    //ERR_load_BIO_strings();
    SSL_load_error_strings();

    /* Setup the connection */
	meth = (SSL_METHOD*)SSLv3_method();

    /* Set up the SSL context */
    ctx = SSL_CTX_new(meth);
    if(ctx == NULL )
    {
  		cerr << "Error ctx" << endl;
  		ERR_print_errors_fp(stderr);
    	return 1;
    }
    
    bio = BIO_new_ssl_connect(ctx);

    /* Set the SSL_MODE_AUTO_RETRY flag */

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

    /* Create and setup the connection */
    ostringstream connstr;
    connstr << argv[1] <<  ":" << argv[2];
    BIO_set_conn_hostname(bio, connstr.str().c_str());

    if(BIO_do_connect(bio) <= 0)
    {
        cerr << "Error attempting to connect" << endl;
        ERR_print_errors_fp(stderr);
        BIO_free_all(bio);
        SSL_CTX_free(ctx);
        return 1;
    }
    
	// send header 
	int nH = htonl(sendval.size());
    if( BIO_write(bio, &nH, 4) <= 0 )
    {
        cerr << "Send fail.[Header]" << endl;
        //printf("Failed write\n");
        ERR_print_errors_fp(stderr);
        return 1;
    }	
    else
    {
        cout << "Send success.[Header]"<< endl;
    }

	// send body 
	if( BIO_write(bio, sendval.c_str(), sendval.size()) <= 0 )
	{
		cerr << "Send fail.[Body]" << endl;		
		//printf("Failed write\n");
        ERR_print_errors_fp(stderr);
        return 1;		
	}
	else
	{
	    cout << "Send success.[Body]"<< endl;

	}

	// read header
	int nR = 0;
	int r = BIO_read(bio, &nR, 4);
	if(r < 0 )
	{
		cerr << "Socket Read Error.[Header]" << errno << endl;
		ERR_print_errors_fp(stderr);
		return 1;
	}
	else if ( r == 0)
	{
		cerr << "Server closed.[Header]" << errno << endl;
		ERR_print_errors_fp(stderr);
		return 1;
	}
	else 
	{
		nR = ntohl(nR);

		cout << "Resv success.[Header]," << nR << endl;
	}

	// read body
	string readval;
	while(nR > 0)
	{
		char szBuffer[1025] = {0};
		r = BIO_read(bio, szBuffer, 1024);
		
		if(r < 0 )
		{
			cerr << "Socket Read Error." << endl;
			ERR_print_errors_fp(stderr);
			break;
		}
		else if ( r == 0)
		{
			cerr << "Server closed."  << endl;
			ERR_print_errors_fp(stderr);
			break;
		}
		else
		{
		    szBuffer[r] = 0;
			readval.append(szBuffer, r);
		}
	}

	if(!readval.empty())
	{
		cout << "Read Data : " << readval << ", Size = " << readval.size() << endl;
	}

	cout << "end" << endl;

	// 그냥 시그널 대기
	pause();	
	
    /* Close the connection and free the context */
    BIO_free_all(bio);
    SSL_CTX_free(ctx);

	return EXIT_SUCCESS;
}
