/*******************************************************************************
 * Copyright (c) 2005, 2009 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:
 *    Hoang M Nguyen, Intel - Initial API and Implementation
 *    Spundun Bhatt (spundun@gmail.com), with the support and encouragement of the University of Southern California Information Sciences Institute Distributed Scalable Systems Division.
 *
 * $Id: SocketListener.c,v 1.56 2009/09/11 19:16:13 jwest Exp $
 *
 *******************************************************************************/ 


/**
 *********************************************************

Each transport layer will provide and implement exactly the same 
pre-defined interface. Each will be in its own DLL or shared library
that is dynamically loaded at runtime.

The interaction between Agent Controller (AC) and the transport layer (TL)
is defined in "MsgPipeline.h" header file.

- from AC to TL, functions include "createTransportListener(), 
  destroyTransportListener(), etc.

- from TL to AC, see function callback in "transport_layer_data_t" structure.

  ------
  |    |
  | AC |   
  |    |<-------|
  ------        |
                V
              ------
              |    |
              | TL |
              |    |
              ------
               ^  ^
         |-----|  |---------------|
         |                        |
         V                        V
    ----------                ---------
    |        |                |       |
    | Client |                | Agent |
    |        |                |       |
    ----------                ---------


The interaction between the transport layer (TL) and the client
or the agent is defined in "TPTPMessageHeader.h" (CONNECT, DISCONNECT, etc.)
and basically any command or data.

The TL will process only CONNECT and DISCONNECT commands and forward
everything else to the AC for routing to the right destination for processing.

 *********************************************************/

#include <stdlib.h>

#ifdef _WIN32
  #include <direct.h>
#else
  #include <unistd.h>
  #include <signal.h>
  #include <sys/wait.h>
  #include <tptp/TPTPConfig.h>
#endif

#include "SocketListener.h"
#include "SSLSupport.h"

#include "tptp/TransportSupport.h"
#include "tptp/TPTPSupportUtils.h"

#include "SocketTLLog.h"

#include "tptp/dime.h"

#define DEFAULT_PORT_NUM  	10002
#define PROTO_VERSION	1

#ifndef _WIN32
	#define INVALID_SOCKET -1
#endif

/** thread status */
enum ThreadStatus { IDLE, RUNNING } ;

/*====================================================================*/
/*    internal function prototypes                                    */
/*====================================================================*/
THREAD_USER_FUNC_RET_TYPE processClientRequest(LPVOID args) ;
THREAD_USER_FUNC_RET_TYPE doListening(LPVOID args) ;
THREAD_USER_FUNC_RET_TYPE doSecureListening(LPVOID args) ;
int   serveRequest(SOCKET serverSock, server_block_ptr_t pServerData) ;
int   serveSecureRequest(server_block_ptr_t pServerData) ;
int   sendThisMessage(server_block_t* pServerData, tptp_uint32 connectionID, tptp_uint32 cmdSize, tptp_string* pCmdBlock, BOOL shouldAddHeader) ;
int   addMessageHeader(char * pCmdBlock, int cmdSize, char * buffer, int *pBufferLength, unsigned int flags) ;
int   processCONNECTCall(request_block_ptr_t pBlk, char *pMsg, int flags) ;
char * processTheMessageHeader(request_block_ptr_t pBlk, char *pMsg, unsigned int *pPayLoadLength) ;
int   forwardDataToPartner(request_block_ptr_t pBlk, int dataLen, char *pBuffer) ;
int forwardDataToPartnerWithoutDIME(request_block_ptr_t pBlk, int dataLen, char *pBuffer) ;

int processOneMsg(request_block_ptr_t pRequestDataBlock, 
				  char *buffer, unsigned int bufferLength) ;

int processRecdMsgs(request_block_ptr_t pRequestDataBlock, char *pBuffer, int bufferLength, int bytesRead) ;

int handleCONNECT(request_block_ptr_t pBlk, char *pMsg) ;

int handleCONNECT_DATA(request_block_ptr_t pBlk, char *pMsg) ;
int closeConnection(request_block_ptr_t pBlock);
int recvData(request_block_ptr_t pRdb, char *buffer, int length, int *bytesRead);
int writeData(request_block_ptr_t pBlock, char* buffer, int length); 
int setSSL(request_block_ptr_t pBlk);
int handleAUTHENTICATE(request_block_ptr_t pBlk, char *pMsg);

THREAD_USER_FUNC_RET_TYPE serveRequestThread(LPVOID args);

typedef struct { 
	SOCKET serverSock;
	server_block_ptr_t pServerData;
} serve_request_params_t;


/**
 *********************************************************
 *
 * @brief
 *    free the request block for this socket connection
 *
 *********************************************************/
void  freeRequestBlock(request_block_ptr_t pBlk)
{
	tptp_deleteLock( & pBlk->locker );
}


/**
 *********************************************************
 *
 * @brief
 *    Process the CONNECT request
 *
 * @return
 *    0 - success
 *    non-zero - error occurs
 *********************************************************/
int processCONNECTCall(request_block_ptr_t pBlk, char *pMsg, int flags)
{
	int rc = 0 ;
	char  *buffer = NULL;
	int   bufferLength = 0 ;
	char *pCurr = NULL ;
	int   uuidLength = 0 ;

	char *cmd = NULL;
	int   cmdLength = 0;

	/* prepare the response to the CONNECT cmd */
	/* It contains: the assigned connection id, an empty uuid string and protocol version */
	cmdLength = sizeof(int) + sizeof(int) + 1 + sizeof(int);
	cmd = (char*) tptp_malloc(cmdLength);
	if (!cmd) return -1;

	pCurr = writeUINTToBuffer(cmd, pBlk->connectionId);
	uuidLength = 0 ;
	pCurr = writeUINTToBuffer(pCurr, uuidLength);
	strcpy(pCurr, ""); /* null uuid string */
	pCurr = writeUINTToBuffer(pCurr+1, PROTO_VERSION);

	addBasicMsgHeader(cmd, cmdLength, &buffer, &bufferLength, flags) ;
	/* send the response */
	writeData(pBlk, buffer, bufferLength);

	if (cmd) tptp_free(cmd);
	if (buffer) tptp_free(buffer);

	return ( rc ) ;
}

/**
 *********************************************************
 *
 * @brief
 *    handle the CONNECT request
 *
 *********************************************************/
int handleCONNECT(request_block_ptr_t pBlk, char *pMsg)
{
	HashTable *pTab = NULL;
	int  connId = 0;

	addConnectionEntry_ptr_t pFunc = NULL ;

	TPTP_LOG_DEBUG_MSG(pBlk->pServerData, "Socket: handle CONNECT request (Control channel).");
	pBlk->connectionType = CONTROL_CHANNEL ;

	if (pBlk->pServerData->securityEnabled && !pBlk->secured) {
		processCONNECTCall(pBlk, pMsg, CONNECTION_REFUSED | SECURITY_REQUIRED);
		return setSSL(pBlk); 
	}

	/* tell the agent controller about the new connection  */
	/*    and receive the assigned connection id           */
	pFunc = pBlk->pServerData->agentControllerDataBlk.addConnectionEntry ;
	pFunc(pBlk->pServerData->cmo, pBlk->pServerData->agentControllerDataBlk.transportID, 
			&(pBlk->connectionId));


	/* save the socket and the control block away */
	/*   use the connection id as the index into the array for fast lookup */
	connId = pBlk->connectionId ;
	TPTP_LOG_DEBUG_MSG1(pBlk->pServerData, "Socket handleCONNECT: using Connection ID: %d", connId) ;

	/* add the request in the connection table */
	pTab = pBlk->pServerData->connectionTable ;
	tablePut(pTab, connId, (Entry_value_ptr_t) pBlk) ;

	if (pBlk->pServerData->securityEnabled && !pBlk->authenticated) {
		processCONNECTCall(pBlk, pMsg, CONNECTION_COMPLETE | AUTHENTICATION_FAILED);
	}
	else {
		processCONNECTCall(pBlk, pMsg, CONNECTION_COMPLETE);
		pBlk->authenticated = TRUE;
	}

	return 0 ;
}

/**
 *********************************************************
 *
 * @brief
 *    handle the CONNECT_DATA or CONNECT_CONSOLE request
 *
 *********************************************************/
int handleCONNECT_DATA(request_block_ptr_t pBlk, char *pMsg)
{
	HashTable           *pTab = NULL ;
	int  connId = 0 ;

	addDataConnectionEntry_ptr_t pFunc = NULL ;

	TPTP_LOG_DEBUG_MSG(pBlk->pServerData, "Socket: handle CONNECT_DATA/CONNECT_CONSOLE request (Data channel).");

	if (pBlk->pServerData->securityEnabled && !pBlk->secured) {
		processCONNECTCall(pBlk, pMsg, CONNECTION_REFUSED | SECURITY_REQUIRED);
		return setSSL(pBlk); 
	}

	pBlk->connectionType = DATA_CHANNEL ;

	/* tell the agent controller about the new connection  */
	/*    and receive the assigned connection id           */
		
	/* read in the flags */
	pMsg = readUINTFromBuffer(pMsg, &pBlk->flags);

	pFunc = pBlk->pServerData->agentControllerDataBlk.addDataConnectionEntry ;
	pFunc(pBlk->pServerData->cmo, pBlk->pServerData->agentControllerDataBlk.transportID,
			pBlk->flags, &(pBlk->connectionId)) ;

	/* save the socket and the control block away */
	/*   use the connection id as the index into the array for fast lookup */
	connId = pBlk->connectionId ;
	TPTP_LOG_DEBUG_MSG1(pBlk->pServerData, "Socket handleCONNECT_DATA: using Connection ID: %d", connId) ;

	/* add the request in the connection table */
	pTab = pBlk->pServerData->connectionTable ;
	tablePut(pTab, connId, (Entry_value_ptr_t) pBlk) ;

	/* CONNECT command. Go handle it. */
	processCONNECTCall(pBlk, pMsg, DATA_CONNECTION_COMPLETE) ;

	return 0 ;
}

/**
 *********************************************************
 *
 * @brief
 *    handle the DISCONNECT request
 *
 *********************************************************/
int handleDISCONNECT(request_block_ptr_t pBlk, char *pMsg)
{

	TPTP_LOG_DEBUG_MSG(pBlk->pServerData, "Socket: handle DISCONNECT request.");
	if (pBlk->connectionType == DATA_CHANNEL)
	{
		/* pass the command to the agent controller to be processed */
		removeConnectionEntry_ptr_t pRemoveFunc = 
			pBlk->pServerData->agentControllerDataBlk.removeDataConnectionEntry;

		pRemoveFunc(pBlk->pServerData->cmo, pBlk->connectionId);
	}
	else
	{
		/* pass the command to the agent controller to be processed */
		removeDataConnectionEntry_ptr_t pDataRemoveFunc = 
			pBlk->pServerData->agentControllerDataBlk.removeConnectionEntry;

		pDataRemoveFunc(pBlk->pServerData->cmo, pBlk->connectionId);
	}

	return 0 ;
}

/**
 *********************************************************
 *
 * @brief
 *    Extract out the message header from the given message
 *
 * @return
 *    The pointer to the message without the header
 *
 *    NULL if the message is intended to the transport layer
 *    and it has been processed and responded by the transport.
 *
 *********************************************************/
char * processTheMessageHeader(request_block_ptr_t pBlk, char *pMsg, unsigned int *pPayLoadLength)
{
	unsigned int magicNumber = 0;
	unsigned int flags = 0 ;

	/* read in the magic number */
	pMsg = readUINTFromBuffer(pMsg, &magicNumber);

	/* read in the flags */
	pMsg = readUINTFromBuffer(pMsg, &flags);

	/* read in the payload length */
	pMsg = readUINTFromBuffer(pMsg, pPayLoadLength) ;

	if ((flags & CONNECT) != 0)	{
		handleCONNECT(pBlk, pMsg) ;

		/* prevent it from forwarding to the AC */
		pMsg = NULL ;
	}
	else if (((flags & CONNECT_DATA) != 0) || ((flags & CONNECT_CONSOLE) != 0))
	{
		if ((flags & CONNECT_CONSOLE) != 0)
			pBlk->isForConsole = TRUE;

		handleCONNECT_DATA(pBlk, pMsg) ;

		/* prevent it from forwarding to the AC */
		pMsg = NULL ;
	}
	else if ((flags & DISCONNECT) != 0)
	{
		handleDISCONNECT(pBlk, pMsg) ;

		/* prevent it from forwarding to the AC */
		pMsg = NULL ;
	}
	else if (pBlk->pServerData->securityEnabled && !pBlk->secured) {  
		pMsg = NULL ;
	}
	else if ((flags & AUTHENTICATE) != 0) {
		handleAUTHENTICATE(pBlk, pMsg) ;
		pMsg = NULL ;
	} 
	else if (pBlk->pServerData->securityEnabled && !pBlk->authenticated) {
		processCONNECTCall(pBlk, pMsg, AUTHENTICATION_FAILED);
		pMsg = NULL ;
	}
	else
	{
		if (flags != 0)
		{
			TPTP_LOG_DEBUG_MSG1(pBlk->pServerData, "Socket processTheMessageHeader: Message flag (0x%08x) not handled by TL.", flags);
		}
		else
		{
			TPTP_LOG_DEBUG_MSG(pBlk->pServerData, "Socket processTheMessageHeader: Stripped header from non-TL message.");
		}
	}


	return ( pMsg ) ;
}

/**
 *********************************************************
 *
 * @brief
 *    process a given complete message 
 *
 *********************************************************/
int processOneMsg(request_block_ptr_t pRequestDataBlock, 
				  char *buffer, unsigned int bufferLength)
{
	/* pass the message to the agent controller to be processed */
	processMessage_ptr_t pFunc = NULL ;

	char *pMsg = NULL ;
	char c = '\0';
	unsigned int payLoadLength = 0 ;

	/* 
	 * TPTP_LOG_DEBUG_MSG1(pRequestDataBlock->pServerData, "Received control(%d bytes). ", bufferLength) ;
	 */
	/* Strip out the message header */
	pMsg = processTheMessageHeader(pRequestDataBlock, buffer, &payLoadLength) ;

	if (pMsg != NULL)
	{	
		//On add the null if we have space for it!
		if (payLoadLength < TPTP_DEFAULT_BUFFER_MAX_LENGTH)
		{
			c = pMsg[payLoadLength];
			pMsg[payLoadLength] = '\0';
		}
		pFunc = pRequestDataBlock->pServerData->processMessage ;
		#ifdef MVS
				__atoe(pMsg);
		#endif
		pFunc(pRequestDataBlock->pServerData->nexto, payLoadLength, pMsg) ;
		
		if (c != '\0') pMsg[payLoadLength] = c;
	}

	return 0 ;
}


/**
 *********************************************************
 *
 * @brief
 *    process received messages by examining the buffer.
 *    This will process one message/command at a time
 *    until the end of the received buffer.
 *
 *    If there is incomplete command, it will move to the beginning
 *    of the buffer.
 *
 * @return
 *    0 - process all messages
 *    negative - Error.
 *    positive - number of bytes left to be processed
 *               These bytes have been copied out in front of the buffer
 *
 *********************************************************/
int processRecdMsgs(request_block_ptr_t pRequestDataBlock, char *pBuffer, int bufferLength, int bytesRead)
{
	int      hasMore = 1 ;
	int 	moreToProcess = 0;
	char     *pMsg = NULL ;
	unsigned int magicNumber = 0;
	unsigned int payLoadLength = 0 ;
	unsigned int msgLength = 0 ;
	unsigned int bytesToBeProcessed = bytesRead ;
	char  *pBeginning = pBuffer ;

	if (pRequestDataBlock->connectionType == DATA_CHANNEL)
	{
		if (pRequestDataBlock->isForConsole) 
		{
			TPTP_LOG_DEBUG_MSG(pRequestDataBlock->pServerData, "Socket processRecdMsgs: Forward msg from DATA channel for Console I/O.");
			forwardDataToPartnerWithoutDIME(pRequestDataBlock, bytesRead, pBuffer) ;
		}
		else
		{
			TPTP_LOG_DEBUG_MSG(pRequestDataBlock->pServerData, "Socket processRecdMsgs: Forward msg from DATA channel.");
			forwardDataToPartner(pRequestDataBlock, bytesRead, pBuffer);
		}
		return 0;
	}

	do
	{
		if (pRequestDataBlock->connectionType == DATA_CHANNEL)
		{
			DIME_HEADER_PTR_T  dH = (DIME_HEADER_PTR_T) pBuffer ;

			MAKE_DIME_HEADER((char*)dH);
			msgLength = sizeof(DIME_HEADER_T)+dH->id_length+dH->options_length+dH->type_length + dH->data_length;
			MAKE_DIME_HEADER((char*)dH); // this call changes endian back!
		
			TPTP_LOG_DEBUG_MSG(pRequestDataBlock->pServerData, "Socket processRecdMsgs: Adjust dime hdr on msg from DATA channel.");
		} else {
			/* process one message at a time in the given buffer */
			TPTP_LOG_DEBUG_MSG(pRequestDataBlock->pServerData, "Socket processRecdMsgs: Process msg from Control channel.");

			/* read in the magic number */
			pMsg = readUINTFromBuffer(pBuffer, &magicNumber);

			/* Compare against the magic number of the AC which is 0x54b674de */
			if (magicNumber != 0x54b674de) {
				/* Compare against the magic number of the RAC which is 0x82656780 */
				if (magicNumber == 0x82656780) {
					TPTP_LOG_ERROR_MSG(pRequestDataBlock->pServerData, "RAC message was received, so ignore.");
				}
				else {
					TPTP_LOG_ERROR_MSG(pRequestDataBlock->pServerData, "Non-AC message was received, so ignore.");
				}
				
				return -1;
			}

			/* read in the payload length */
			readUINTFromBuffer(pMsg+4, &payLoadLength); /* skip flags */

			msgLength = payLoadLength + sizeof(tptp_basic_msg_header_t) ;
		}

		if (msgLength <= bytesToBeProcessed) 
		{
			TPTP_LOG_DEBUG_MSG(pRequestDataBlock->pServerData, "Socket: Read at least one complete message, process it.");

			if (pRequestDataBlock->connectionType == DATA_CHANNEL)
			{
				if (pRequestDataBlock->isForConsole) 
				{
					TPTP_LOG_DEBUG_MSG(pRequestDataBlock->pServerData, "Socket processRecdMsgs: Forward msg from DATA channel for Console I/O.");
					forwardDataToPartnerWithoutDIME(pRequestDataBlock, msgLength, pBuffer) ;
				}
				else
				{
					TPTP_LOG_DEBUG_MSG(pRequestDataBlock->pServerData, "Socket processRecdMsgs: Forward msg from DATA channel.");
					forwardDataToPartner(pRequestDataBlock, msgLength, pBuffer) ;
				}
			} else {
				/* we have one complete message, consume it */
				TPTP_LOG_DEBUG_MSG(pRequestDataBlock->pServerData, "Socket processRecdMsgs: Process msg from Control channel.");
				processOneMsg(pRequestDataBlock, pBuffer, msgLength) ;
			}

			/* advance to the next message in the buffer */
			pBuffer += msgLength ;

			/* the remainder length of data to be processed */
			bytesToBeProcessed -= msgLength ;
		}
		else
		{
			/* reach the end of the last complete message */
			TPTP_LOG_DEBUG_MSG1(pRequestDataBlock->pServerData, "Socket: Too few bytes remain to form complete Control msg len=%d.", msgLength);
			hasMore = 0 ;
		}

		if (pRequestDataBlock->connectionType == DATA_CHANNEL)
		{
			moreToProcess = bytesToBeProcessed >= sizeof(DIME_HEADER_T);
		} else {
			moreToProcess = bytesToBeProcessed >= sizeof(tptp_basic_msg_header_t);
		}	

	} while (moreToProcess && (hasMore != 0));

	if (bytesToBeProcessed > 0)
	{
		/* move the incomplete message to the beginning of the buffer */
		memmove(pBeginning, pBeginning+bytesRead-bytesToBeProcessed, bytesToBeProcessed) ;
	}

	return ( bytesToBeProcessed ) ;
}

/**
 *********************************************************
 *
 * @brief
 *    receive and process incoming request message
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
THREAD_USER_FUNC_RET_TYPE processClientRequest(LPVOID args) 
{
	int    rc = 1;
	unsigned int  bytesRead;
	unsigned char* buffer;
	unsigned int  bufferLength = 2*TPTP_DEFAULT_BUFFER_LENGTH;
	int      offset = 0 ;
	removeConnectionEntry_ptr_t pFunc = NULL ;
	removeDataConnectionEntry_ptr_t pFuncData = NULL ;

	/* set up environmental info for this incoming message */
	request_block_ptr_t pRdb = (request_block_ptr_t) args ;

	/* initial status before the thread is running */
	pRdb->threadStatus = RUNNING ;

	buffer = (unsigned char*) tptp_malloc(bufferLength + 1);

	/* accept and process one connection at a time */
	while ((pRdb->threadStatus == RUNNING) && (rc > 0))
	{
		bytesRead = 0 ;

		/* Another message might come in while we're processing
		 *    so we read until the pipe is empty                 */
		while ( (rc = recvData(pRdb, buffer+offset, bufferLength-offset, &bytesRead)) > 0)
		{
			TPTP_LOG_DEBUG_MSG1(pRdb->pServerData, "Socket processClientRequest: Read %d bytes.", bytesRead) ;

			bytesRead += offset;
			
			// We can pass the DATA_CHANNEL data through processRecdMsgs at any size, as it will always be written
			// in its entirety, once we get into processRecdMsgs. (bug 234596)
			if ((bytesRead + offset) < sizeof(tptp_basic_msg_header_t) && !(pRdb->connectionType == DATA_CHANNEL))
			{
				/* too small to determine the payload length. Go read some more */
				offset += bytesRead ;
			}
			else
			{
				offset = processRecdMsgs(pRdb, buffer, bufferLength, bytesRead) ;
				if (offset < 0) {
					pRdb->threadStatus = IDLE;
					break;
				}
			}
		}
	}

	if (pRdb->connectionType == DATA_CHANNEL) {
		pFuncData = pRdb->pServerData->agentControllerDataBlk.removeDataConnectionEntry;
		pFuncData(pRdb->pServerData->cmo, pRdb->connectionId);
	} else {
		pFunc = pRdb->pServerData->agentControllerDataBlk.removeConnectionEntry;
		pFunc(pRdb->pServerData->cmo, pRdb->connectionId);
	}

	closeConnection(pRdb);
	freeRequestBlock(pRdb);
	tptp_free(buffer);
	
	return ( 0 ) ;
}


/**
 *********************************************************
 *
 * @brief
 *    main running thread that accepts connection,
 *    set up the environment and process it in a new separate thread
 *
 * @return
 *    Pointer to the data block used to process this client request
 *    NULL if error
 *********************************************************/
request_block_ptr_t  getInitRequestDataBlock(SOCKET clientSock, server_block_ptr_t pServerData)
{
	request_block_ptr_t pRequestDataBlock = NULL ;

	pRequestDataBlock = (request_block_ptr_t) malloc(sizeof(request_block_t)) ;
	pRequestDataBlock->clientSock = clientSock ;
	pRequestDataBlock->pServerData = pServerData ;
	pRequestDataBlock->connectionId = 0 ;
	pRequestDataBlock->connectionType = 0 ;
	
	pRequestDataBlock->ssl_socket = NULL;
	pRequestDataBlock->authenticated = FALSE;
	pRequestDataBlock->secured = FALSE;

	pRequestDataBlock->isForConsole = FALSE ;
	
	pRequestDataBlock->pSendFunc = NULL ;

	tptp_initializeLock( & pRequestDataBlock->locker );

	return ( pRequestDataBlock ) ;
}

THREAD_USER_FUNC_RET_TYPE serveRequestThread(LPVOID args) {
	
	serve_request_params_t * params = (serve_request_params_t *)args;
	serveRequest(params->serverSock, params->pServerData);
	
	return 0;
}


/**
 *********************************************************
 *
 * @brief
 *    main running thread that accepts connection,
 *    set up the environment and process it in a new separate thread
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
int serveRequest(SOCKET serverSock, server_block_ptr_t pServerData)
{
	SOCKET   clientSock ;
	int      rc = 0 ;
	request_block_ptr_t pRequestDataBlock = NULL ;
	TID threadId;
	HANDLE threadHandle ;
	int numAcceptAttempts = 0;
	const int TOTAL_ACCEPT_ATTEMPTS = 120;

	if(serverSock == INVALID_SOCKET) {
		TPTP_LOG_ERROR_MSG(pServerData, "serveRequest attempted to listen on an invalid server socket.") ;
		return -1;
	}

	/* initial status before the thread is running */
	pServerData->threadStatus = RUNNING ;
	pServerData->serverSock   = serverSock ;

	/* accept and process one connection at a time */
	while (pServerData->threadStatus == RUNNING)
	{
        clientSock = acceptSocketConnection(serverSock); 

		if (isSocketValid(clientSock) == 0)
		{
			// If the accept attempt returns an invalid socket, note it
			numAcceptAttempts++;
			TPTP_LOG_ERROR_MSG1(pServerData, "accept() call received invalid socket request. (Attempt %d)" , numAcceptAttempts);

			// If we receive an extraordinarily large number of failures, terminate the listening thread 
			if(numAcceptAttempts >= TOTAL_ACCEPT_ATTEMPTS) {
				TPTP_LOG_ERROR_MSG(pServerData, "serveRequest accept() calls have reached failure threshold, ending server socket listen thread.") ;	
				return -1;
			}
			
			SLEEP(500);
		}

		else
		{
			// Reset the numAcceptAttempts variable to 0, as we had a successfull listen
			numAcceptAttempts = 0;

			setHandleInherited((HANDLE) clientSock);

			/* set up the data block for each request */
			pRequestDataBlock = getInitRequestDataBlock(clientSock, pServerData) ;

			/* go create a new thread to process each incoming connection request */
			rc = tptpStartThread(processClientRequest, 
				(LPVOID) pRequestDataBlock, &threadId, &threadHandle) ;
			CLOSE_THREAD_HANDLE(threadHandle);

		}
	}

	return ( rc ) ;
}

/**
 *********************************************************
 *
 * @brief
 *    main running thread that accepts connection,
 *    set up the environment and process it in a new separate thread
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
int serveSecureRequest(server_block_ptr_t pServerData) {
	int      rc = 0 ;
	request_block_ptr_t pRequestDataBlock = NULL;
	TID threadId;
	HANDLE threadHandle;
	ssl_socket_t ssl_socket;

	/* initial status before the thread is running */
	pServerData->threadStatus = RUNNING ;

	/* accept and process one connection at a time */
	while (pServerData->threadStatus == RUNNING) {
        ssl_socket = ssl_accept(); 
		if (ssl_socket == NULL) break;

		/* set up the data block for each request */
		pRequestDataBlock = getInitRequestDataBlock(0, pServerData);
		pRequestDataBlock->ssl_socket = ssl_socket;

		/* go create a new thread to process each incoming connection request */
		rc = tptpStartThread(processClientRequest, (LPVOID) pRequestDataBlock, &threadId, &threadHandle);
		CLOSE_THREAD_HANDLE(threadHandle);
	}

	return rc;
}

/**
 *********************************************************
 *
 * @brief
 *    set up the server socket for listening incoming requests
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
THREAD_USER_FUNC_RET_TYPE doListening(LPVOID args) 
{
	int      rc = 0;
	SOCKET   serverSockets[FD_SETSIZE];
	int socketNum = 0;
	int i;
 	TID pthreadId;
	HANDLE pthreadHandle;
		
	serve_request_params_t * params;
	
	server_block_ptr_t  pParam = (server_block_ptr_t) args ;

	/* create and initialize the server socket */
	rc = getTheSocket(pParam->port, serverSockets, &socketNum) ;

	if (socketNum == 0)
	{
		TPTP_LOG_ERROR_MSG(pParam, "Error: unable to create the server socket.") ;
	}

	/* ready to accept incoming connection requests */
	if (socketNum != 0 && rc == 0)
	{
		TPTP_LOG_DEBUG_MSG1(pParam, "Socket server is running at port number of %d.", pParam->port) ;
		for (i=0; i < socketNum; ++i) {
			
			params = (serve_request_params_t *)tptp_malloc(sizeof(serve_request_params_t));
			params->pServerData = pParam;
			params->serverSock = serverSockets[i];
			
			if(params->serverSock != INVALID_SOCKET) {
				tptpStartThread(serveRequestThread, params, &pthreadId, &pthreadHandle);
			}
			
		}
	}

	return ( 0 );
}

/**
 *********************************************************
 *
 * @brief
 *    place to set up listening incoming secure requests
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
THREAD_USER_FUNC_RET_TYPE doSecureListening(LPVOID args) {
	server_block_ptr_t  pServerData = (server_block_ptr_t) args;

	/* ready to accept incoming connection requests */
	serveSecureRequest(pServerData);

	return 0;
}

/**
 *********************************************************
 *
 * @brief
 *    create a socket listener instance
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
tptp_int32 createSocketListener(tptp_object* cmo, transport_layer_data_t * pTransportData, tptp_object* tlo) 
{
	server_block_t* pServerData;
	SocketConfigInfo socketInfo;
	int rc;

	rc = initForSocketCalls() ;
	if (rc != 0) {
		if (pTransportData->logEventEntry) 
			pTransportData->logEventEntry(cmo, "Socket TL", pTransportData->transportID, __FILE__, __LINE__, TPTP_FATAL, "Unable to initialize socket library.");
			
		return rc;
	}

	/* prepare the globally available server data block */
	pServerData = (server_block_ptr_t) malloc(sizeof(server_block_t)) ;
	pServerData->cmo = cmo;
	pServerData->threadStatus = 0 ;
	pServerData->agentControllerDataBlk = *pTransportData ;

	/* allocate connection table */
	pServerData->connectionTable = tableCreate();

	rc = getSocketConfigInfo(pTransportData->configurationData, &socketInfo);
	if (rc != -1) 
	{
		pServerData->port = socketInfo.portNumber;
		pServerData->securityEnabled = socketInfo.securityEnabled;
		pServerData->sslProviderLib = socketInfo.sslProviderLib; 
		pServerData->params = socketInfo.params; 
	} 
	else 
	{
		pServerData->port = DEFAULT_PORT_NUM;
		pServerData->securityEnabled = FALSE; 
		pServerData->sslProviderLib = NULL; 
		pServerData->params = NULL; 
	}

	tlo->data = pServerData;
	tlo->objectID = SOCKET_LISTENER_OBJECT_ID;

	TPTP_LOG_DEBUG_MSG(pServerData, "createTransportListener (socket)") ;

	return rc;
}

/**
 *********************************************************
 *
 * @brief
 *    destroy a socket listener instance
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
tptp_int32 destroySocketListener(tptp_object* tlo)
{
	int rc = 0 ;
	SOCKET sock ;
	server_block_t* pServerData = (server_block_t*)tlo->data;

	tlo->data = 0;
	tlo->objectID = -1;

	TPTP_LOG_DEBUG_MSG(pServerData, "stopTransportListener (socket)") ;
	
	/* stop the running thread */
	pServerData->threadStatus = IDLE ;

	/* stop accepting connection */
	if (pServerData->securityEnabled) {
		ssl_reset();
	} else {
		sock = pServerData->serverSock ;
		rc = closeSocket(sock) ;
	}

	/* free the connection table */
    tableDelete( pServerData->connectionTable );
	pServerData->connectionTable = NULL ;

	free( pServerData );

	return ( rc ) ;
}

/**
 *********************************************************
 *
 * @brief
 *    set the function for forwarding messages
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
tptp_int32 setSocketProcessMessageFunc( server_block_t* pServerData, tptp_object* nexto, processMessage_ptr_t func)
{
	pServerData->processMessage = func;
	pServerData->nexto = nexto;

	return 0;
}

/**
 *********************************************************
 *
 * @brief
 *    create a new running thread to handle socket connections
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
tptp_int32 startSocketListener(server_block_t* pServerData)
{
	int       rc = 0 ;
	TID threadId;
	HANDLE threadHandle ;

	TPTP_LOG_DEBUG_MSG(pServerData, "startTransportListener (socket)") ;

	/* create new thread to listen for incoming connection requests */
	if (pServerData->securityEnabled) {
	 	if (ssl_init(pServerData)) return -1;
		rc = tptpStartThread(doSecureListening,(LPVOID) pServerData, &threadId, &threadHandle);
		CLOSE_THREAD_HANDLE(threadHandle);
	}
	else {
		rc = tptpStartThread(doListening,(LPVOID) pServerData, &threadId, &threadHandle);
		CLOSE_THREAD_HANDLE(threadHandle);
	}

	return rc;
}

int closeConnection(request_block_ptr_t pBlock) {
	int rc=0;
	if (pBlock == NULL) return -1;

	if (pBlock->ssl_socket != NULL) {
		rc = ssl_close(pBlock->ssl_socket);  
		pBlock->ssl_socket = NULL; 
	}
	else {
  		rc = closeSocket(pBlock->clientSock);
  	}
	
  	pBlock->secured = FALSE;
  	pBlock->authenticated = FALSE;
  	
  	return rc;
}

/**
 *********************************************************
 *
 * @brief
 *    terminate the given connection
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/

tptp_int32   terminateSocketConnection(server_block_t* pServerData, tptp_uint32  connectionID)
{
	request_block_ptr_t pBlock ;

	TPTP_LOG_DEBUG_MSG1(pServerData, "terminateConnection (socket): connection id(%d)", connectionID) ;

	/* retrieve the corresponding socket */
	pBlock = (request_block_ptr_t) tableGet(pServerData->connectionTable, connectionID) ;

	/* go close it down */
	return closeConnection(pBlock) ;
}


/**
 *********************************************************
 *
 * @brief
 *    send a given message to the given destination (identified by connection id)
 *
 * @return
 *    Negative - Error
 *    0 - Socket is closed gracefully
 *    Positive - the number of bytes that have been sent
 *********************************************************/

tptp_int32   sendSocketMessage( server_block_t* pServerData, tptp_uint32 connectionID, tptp_uint32 cmdSize, tptp_string* pCmdBlock)
{
	TPTP_LOG_DEBUG_MSG1(pServerData, "sendMessage (socket) to this connection id(%d)", connectionID) ;
	
	return ( sendThisMessage(pServerData, connectionID, cmdSize, pCmdBlock, TRUE ) ) ;
}

/**
 *********************************************************
 *
 * @brief
 *    send a given message to the given destination (identified by connection id)
 *
 * @return
 *    Negative - Error
 *    0 - Socket is closed gracefully
 *    Positive - the number of bytes that have been sent
 *********************************************************/

tptp_int32 sendThisMessage( server_block_t* pServerData, tptp_uint32 connectionID, tptp_uint32 cmdSize, tptp_string* pCmdBlock, BOOL shouldAddHeader)
{
	int rc = 0 ;
	int  bytesSent  = 0 ;
	char *buffer = NULL;
	int  bufferLength = 0 ;
	unsigned int flags = 0 ;

	char *pSendBuffer = NULL ;

	#ifdef MVS
		tptp_string* nativeBuffer = 0;
	#endif

	/* locate the sender's block */
	request_block_ptr_t pBlock = 
		(request_block_ptr_t) tableGet(pServerData->connectionTable, connectionID) ;

	if (pBlock == NULL) {
		return -1;
	}

	if (shouldAddHeader == TRUE)
	{
		#ifdef MVS
			// Convert Control Channel data
			native2unicode(&nativeBuffer, (char *)pCmdBlock, cmdSize);
			cmdSize = strlen(nativeBuffer);
			addBasicMsgHeader(nativeBuffer, cmdSize, &buffer, &bufferLength, flags) ;
			if(nativeBuffer != 0) {
				tptp_free(nativeBuffer);
			}
		#else
			/* add the header to the message if requested */
			addBasicMsgHeader(pCmdBlock, cmdSize, &buffer, &bufferLength, flags) ;
		#endif
		pSendBuffer  = buffer ;
	}
	else
	{
		/* MVS - we do not expect a message without a header so we do not convert */
		pSendBuffer  = pCmdBlock ;
		bufferLength = cmdSize ;
	}

	/* synchronizing among threads. Single writer. */
	tptp_getWriteLock( & pBlock->locker );

	/* go send the message */
	bytesSent = writeData(pBlock, pSendBuffer, bufferLength);
	if (bytesSent < 0)
	{
		TPTP_LOG_ERROR_MSG1(pServerData, "Socket: Failed to send data on connection ID %d", connectionID);
	}
	else
	{
		TPTP_LOG_DEBUG_MSG2(pServerData, "Socket: Sent %d bytes on connection ID %d", bytesSent, connectionID);
//		if (pBlock->connectionType == CONTROL_CHANNEL)
//			printThisEnvelope((tptp_basic_msg_header_ptr_t) pSendBuffer);

		rc = bytesSent ;
	}

	tptp_releaseWriteLock(& pBlock->locker);

	if (buffer) tptp_free(buffer);

	return ( rc ) ;
}



/**
 *********************************************************
 *
 * @brief
 *    common interface to retrieve peer monitoring info
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
tptp_int32 getSocketPeerConnectionInfo(server_block_t* pServerData, tptp_string* type, tptp_string** ci )
{
	char   ciFormat[] = "<%s><transportType>TPTP_SOCKET</transportType><host>%s</host><port>%d</port></%s>";
	char*               ipAddrStr;

	if ( ci == NULL )
	{
		return TPTP_UNEXPECTED_NULL_ARG;
	}

	/* Get the local host IP address */
	/* NOTE: This has problems if there are multiple IP addresses, but in
	         the case of compatibility mode, this isn't really used anyway */
	
	if (getSocketIPStringIPv4M( (SOCKET)NULL, &ipAddrStr) < 0) {
		TPTP_LOG_ERROR_MSG(pServerData, "Unable to get local IP address");
		return -1;
	}
	
	*ci = (char *)tptp_malloc( (2*strlen(type)) + strlen(ciFormat) + 11 + strlen(ipAddrStr) + 1 );
	if ( *ci == NULL )
	{
		return TPTP_SYS_NO_MEM;
	}

	sprintf( *ci, ciFormat, type, ipAddrStr, pServerData->port, type );

	return 0;
}


/**
 *********************************************************
 *
 * @brief
 *    common interface to establish a connection with
 *    another Agent Controller
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
tptp_int32 createSocketPeerConnection( server_block_t* pServerData, tptp_string* sourceConnectionInfo, tptp_uint32* connectionID )
{
	tptp_string*     ipAddrStr;
	unsigned long    ipAddr;
	unsigned int     port;
	SOCKET           sock;
	tptp_int32       rc;
	TID              threadId;
	HANDLE           threadHandle;
	char             xmlRootName[32] = "sourceConnectionInfo";

	/* Extract the peer address from the sourceConnectionInfo fragment */
	rc = getXmlFragmentElementInt( sourceConnectionInfo, xmlRootName, "port", &port );
	if ( rc != 0 )
	{
		/* If this failed, check for the shutdown case */
		strcpy( xmlRootName, SHUTDOWNCONNECTION_XML_NAME );
		rc = getXmlFragmentElementInt( sourceConnectionInfo, xmlRootName, "port", &port );
		if ( rc != 0 )
		{
			TPTP_LOG_ERROR_MSG1( pServerData, "Unable to find port in connection info: %s", sourceConnectionInfo );
			return rc;	
		}
	}
	rc = getXmlFragmentElementString( sourceConnectionInfo, xmlRootName, "host", &ipAddrStr );
	if ( rc != 0 )
	{
		TPTP_LOG_ERROR_MSG1( pServerData, "Unable to find host in connection info: %s", sourceConnectionInfo );
		return rc;	
	}
	rc = convertIPAddressStringToUlongIPv4M( ipAddrStr, &ipAddr );
	if ( rc != 0 )
	{
		TPTP_LOG_ERROR_MSG1( pServerData, "Unable to convert IP address string to unsigned long: %s", ipAddrStr );
		tptp_free( ipAddrStr );
		return rc;	
	}

	/* TODO: Check to see if this is local */

	/* Connect to the remote AC */
	rc = connectToTCPServerIPv4M( ipAddr, (unsigned short)port, &sock);
	if ( rc != 0 )
	{
		TPTP_LOG_ERROR_MSG2( pServerData, "Unable to connect to peer: %s, port %d", ipAddrStr, port );
		return rc;
	}

	/* Start a thread to handle responses */
	if (isSocketValid(sock) == 0)
	{
		TPTP_LOG_ERROR_MSG(pServerData, "Accept() received an invalid socket request." );
	}
	else
	{
		request_block_ptr_t pRequestDataBlock = NULL ;
		addConnectionEntry_ptr_t pFunc = NULL ;

		setHandleInherited((HANDLE) sock) ;

		/* set up the data block for each request */
		pRequestDataBlock = getInitRequestDataBlock(sock, pServerData) ;

		/* go create a new thread to process each incoming connection request */
		rc = tptpStartThread(processClientRequest, 
				(LPVOID) pRequestDataBlock, &threadId, &threadHandle) ;
		CLOSE_THREAD_HANDLE(threadHandle);

	
		TPTP_LOG_DEBUG_MSG(pServerData, "Socket: Creating peer connection.");
		pRequestDataBlock->connectionType = CONTROL_CHANNEL ;

		/* tell the agent controller about the new connection  */
		/*    and receive the assigned connection id           */
		pFunc = pServerData->agentControllerDataBlk.addConnectionEntry ;
		if ( pFunc != NULL )
		{
			pFunc(pServerData->cmo, pServerData->agentControllerDataBlk.transportID, 
					&(pRequestDataBlock->connectionId));

			/* save the socket and the control block away */
			/*   use the connection id as the index into the array for fast lookup */
			*connectionID = pRequestDataBlock->connectionId ;

			/* add the request in the connection table */
			tablePut(pServerData->connectionTable, *connectionID, (Entry_value_ptr_t) pRequestDataBlock) ;
		}
		else
		{
			return -1; /* TODO: More specific error code */
		}
	}

	return rc;
}


/**
 *********************************************************
 *
 * @brief
 *    stop the server socket. Stop accepting connection requests.
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/

tptp_int32 stopSocketListener(server_block_t* pServerData)
{
	TPTP_LOG_DEBUG_MSG(pServerData, "stopTransportListener (socket)") ;
	
	/* stop the running thread */
	pServerData->threadStatus = IDLE ;

	return 0;
}


/**
 *********************************************************
 *
 * @brief
 *    common interface to set up the data path between source and destination
 *    (socket).
 *
 * @return
 *    0 - Success
 *    negative - Not supported
 *    positive - Error number
 *********************************************************/

tptp_int32 setSocketIncomingDataFunc( server_block_t* pServerData, tptp_uint32 connectionID, tptp_uint32 partnerID, tptp_object* partner, sendData_ptr_t newDataFunc )
{
	/* locate the block */
	request_block_ptr_t pBlock = 
		(request_block_ptr_t) tableGet(pServerData->connectionTable, connectionID) ;

	TPTP_LOG_DEBUG_MSG2(pServerData, "setIncomingDataFunc(socket) connectionID(%d) partnerID(%d)",
		connectionID, partnerID) ;

	pBlock->connectionPartnerID = partnerID ;
	pBlock->partner = partner;
	pBlock->pSendFunc = newDataFunc ;

	return 0 ;
}


/**
 *********************************************************
 *
 * @brief
 *    send a given message to the given destination (identified by connection id)
 *
 * @return
 *    Negative - Error
 *    0 - Socket is closed gracefully
 *    Positive - the number of bytes that have been sent
 *********************************************************/

tptp_int32 sendSocketData(server_block_t* pServerData, tptp_uint32 connectionID, tptp_uint32 dataSize, tptp_string* pDataBlock)
{
	int bytesSent = 0 ;

	int rc = 0 ;

	/* locate the block */
	request_block_ptr_t pBlock = 
		(request_block_ptr_t) tableGet(pServerData->connectionTable, connectionID) ;

	if (pBlock == NULL) return -1;

	/* go send the message */
	bytesSent = writeData(pBlock, pDataBlock, dataSize); 
	if (bytesSent < 0)
	{
		TPTP_LOG_ERROR_MSG1(pServerData,"Socket: Failed to send data on connection ID %d", connectionID);
	}
	else
	{
		TPTP_LOG_DEBUG_MSG2(pServerData, "Socket: Sent %d bytes of Data on connection ID %d", bytesSent, connectionID);
		rc = bytesSent ;
	}
	
	return ( rc ) ;
}


/**
 *********************************************************
 *
 * @brief
 *    process the data received from socket of a specific agent
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/
int forwardDataToPartner(request_block_ptr_t pBlk, int dataLen, char *pBuffer)
{
	sendData_ptr_t pSendFunc = pBlk->pSendFunc ;

	TPTP_LOG_DEBUG_MSG2(pBlk->pServerData, "Send data from connectionId(%d) to PartnerID(%d).", 
		pBlk->connectionId, pBlk->connectionPartnerID) ;

	if (pSendFunc != NULL)
		pSendFunc(pBlk->partner, pBlk->connectionPartnerID, dataLen, pBuffer) ;
	else
		TPTP_LOG_ERROR_MSG(pBlk->pServerData, "Data path is NOT established yet.") ;

	return 0 ;
}


/**
 *********************************************************
 *
 * @brief
 *    process the data received from socket for console
 *
 * @return
 *    0 - Success
 *    nonzero - Error.
 *********************************************************/

int forwardDataToPartnerWithoutDIME(request_block_ptr_t pBlk, int dataLen, char *pBuffer)
{
	int dimeLength = 0;

	#ifdef MVS
		// JGW-ZOS (This z/os code does not run in standard scenarios)
		int rc = 0;
		char* nativeBuffer = 0;
		unicode2native(&nativeBuffer, pBuffer, dataLen);
		dataLen = strlen(nativeBuffer);

		DIME_HEADER_PTR_T  pDime = (DIME_HEADER_PTR_T) nativeBuffer ;

	#else
		DIME_HEADER_PTR_T  pDime = (DIME_HEADER_PTR_T) pBuffer ;
	#endif


	MAKE_DIME_HEADER((char*)pDime);
	dimeLength = GET_DIME_LENGTH(pDime) ;

	dataLen -= dimeLength ;


	#ifdef MVS
		// JGW-ZOS (This z/os code does not run in standard scenarios)
		nativeBuffer += dimeLength ;
		rc = forwardDataToPartner(pBlk, dataLen, nativeBuffer);

		if(nativeBuffer != 0)
			tptp_free(nativeBuffer);
		return (rc) ;
	#else
		pBuffer += dimeLength ;

		return (forwardDataToPartner(pBlk, dataLen, pBuffer)) ;
	#endif

}

/**
  *********************************************************
  *
  * @brief
  *    handle the AUTHENTICATE request
  *
  *********************************************************/
int handleAUTHENTICATE(request_block_ptr_t pBlk, char *pMsg) {
	char *name=NULL, *psw=NULL;
	BOOL success;

	pMsg = readStringFromBuffer(pMsg, &name);
	pMsg = readStringFromBuffer(pMsg, &psw);

	if (name != NULL && psw != NULL) {
		success = vrfusrpwd(name, psw) > 0;
	}
	else{
		success = FALSE;
	}
			
	if (success) {			
		TPTP_LOG_DEBUG_MSG1(pBlk->pServerData, "User %s is authenticated", name);
	}
	else if (name != NULL) {
		TPTP_LOG_DEBUG_MSG1(pBlk->pServerData, "User %s is not authenticated", name);
	}
	else {
		TPTP_LOG_DEBUG_MSG(pBlk->pServerData, "User <null> is not authenticated");
	}
 
	pBlk->authenticated = success;
	if (success) {
	 	processCONNECTCall(pBlk, pMsg, AUTHENTICATION_SUCCESSFUL);
	}
	else {
		processCONNECTCall(pBlk, pMsg, AUTHENTICATION_FAILED);
	}

	if (name != NULL) tptp_free(name);
	if (psw != NULL) tptp_free(psw);
	
	return 0 ;
}

int setSSL(request_block_ptr_t pBlk) {
	int err = ssl_handshake(pBlk->ssl_socket); 
	if (err) {
		TPTP_LOG_DEBUG_MSG(pBlk->pServerData, "SSL: ssl_handshake error");
		ssl_close(pBlk->ssl_socket);
		pBlk->ssl_socket = NULL;
	}
	else {
		pBlk->secured = TRUE;
	}

	return err;	
}

int recvData(request_block_ptr_t pRdb, char *buffer, int length, int *bytesRead) {
	int result;

	if (pRdb->pServerData->securityEnabled) {
		 result = ssl_read(pRdb->ssl_socket, buffer, length);
		 *bytesRead = result;
	}
	else {
		result = readFromSocket(pRdb->clientSock, buffer, length, bytesRead);
	}
		
	return result;
}

int writeData(request_block_ptr_t pBlock, char* buffer, int length) { 
	if (pBlock->pServerData->securityEnabled) {
		return ssl_write(pBlock->ssl_socket, buffer, length);
	}
	else {
		return writeToSocket(pBlock->clientSock, buffer, length);
	}
}
