#include "CcCollectdClientSocket.h"

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

#ifdef __FreeBSD__
	#include <sys/endian.h>
    #include <sys/socket.h>
    #include <sys/uio.h>
#else
	#include <endian.h>
	#include <sys/sendfile.h>
#endif



#define HOSTNAME_SIZE		256


// 생성자.
CCcCollectdClientSocket::CCcCollectdClientSocket()
	: CBaseSocket( SOCKET_NOT_VALID )
	  , m_nPacketHeaderLen ( sizeof(m_packetHeader))
	  , m_nPacketDataLen( 0 )
{
}

// 소멸자
CCcCollectdClientSocket::~CCcCollectdClientSocket()
{
	// 소멸자 Socket 명시적 Close 처리.
	Close();
}


// Packet Header 정보를 Log 파일에 Logging 처리
void CCcCollectdClientSocket::PrintHeaderToLog()
{
	_LOG( LINF, "------------------------------------" );
	_LOG( LINF, "stx         [%02x]", m_packetHeader.stx );
	_LOG( LINF, "type        [%02x]", m_packetHeader.type );
	_LOG( LINF, "command     [%02x][%02x][%02x][%02x]", m_packetHeader.command[0], m_packetHeader.command[1], m_packetHeader.command[2], m_packetHeader.command[3] );
	_LOG( LINF, "result      [%02x][%02x][%02x][%02x]", m_packetHeader.result[0], m_packetHeader.result[1], m_packetHeader.result[2], m_packetHeader.result[3] );
	_LOG( LINF, "data_length [%u]", m_nPacketDataLen );
	_LOG( LINF, "extend_code [%02x][%02x]", m_packetHeader.extend_code[0], m_packetHeader.extend_code[1] );
	_LOG( LINF, "------------------------------------" );
}


// socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
// @param size [in] read 할 데이터 크기
// @return On success return true, otherwise return false.
bool CCcCollectdClientSocket::GetPacketData( unsigned int size )
{
	// 1. 수신할 크기가 임시버퍼보다 큰 경우 오류 반환.
	if( size > DEFAULT_SOCKET_TEMP_BUFFER_SIZE )
		return false;

	// 2. 데이터 수신 처리.
	int nRead = ReadNTimeout( m_tempBuffer, size );

	// 오류 발생시
	if( nRead <= 0 )
		return false;

	// 3. 정상인 경우는 ReadNTimeout 함수가 무조건 요청 크기만큼 read 처리하므로 정상수신임.
	return true;
}

// socket 에서 지정된 크기만큼의 데이터를 읽어 출력변수에 저장처리.
// @param size [in] read 할 데이터 크기
// @param value [out] 읽은 데이터를 저장할 string 변수
// @return On success return true, otherwise return false.
bool CCcCollectdClientSocket::GetPacketData( unsigned int& size, std::string& value )
{
	// 1. 수신할 크기가 임시버퍼보다 큰 경우 새로운 버퍼를 생성한다.
	BYTE * pBuffer = NULL;
	bool bNewBufferCreated = false;
	if( size > DEFAULT_SOCKET_TEMP_BUFFER_SIZE )
	{
		pBuffer = new BYTE[size];	// 신규 메모리 할당.
		bNewBufferCreated = true;
	}
	else
		pBuffer = m_tempBuffer;

	// 2. 데이터 수신 처리.
	int nRead = ReadNTimeout( pBuffer, size );

	// 오류 발생시
	if( nRead <= 0 )
	{
		// 신규로 생성된 버퍼인 경우 메모리 해제 처리.
		if( bNewBufferCreated == true )
			delete[] pBuffer;

		return false;
	}

	// 3. 수신 데이터 저장 처리 - 기존 데이터 뒤에 붙여 준다=> 이게 사용하기 편함.
	value.append( (char *)pBuffer, size );

	// 신규로 생성된 버퍼인 경우 메모리 해제 처리.
	if( bNewBufferCreated == true )
		delete[] pBuffer;

	return true;
}


// pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리 및 Endian 변환
unsigned long long CCcCollectdClientSocket::GetDataToUInt64( BYTE * pValue, bool bConvertEndian )
{
	BYTE tempBuffer[8];
	unsigned long long result;

	memcpy( tempBuffer, pValue, 8 );
	unsigned long long * pResult = ( unsigned long long * )tempBuffer;

	// Endian 변환처리.
	if( bConvertEndian == true )
	{
		// Network byte order (big endian) 을 Host byte order 로 변환 처리
		//result = be64toh( *pResult );
		result = do_ntohll( *pResult );
	}
	else
		result = *pResult;

	return  result;
}

// Packet 정보 중 String 정보를 전송하기 위한 함수.
bool CCcCollectdClientSocket::SendString( const std::string& strData )
{
	if( IsValidSocket() == false )
		return false;

	// 크기값을 저장하기 위한 임시 변수.
	unsigned int nSize = 0;

	// String Data 전송
	nSize = htonl( strData.size() );
	WriteN( &nSize, 4 );
	if( strData.size() > 0 )
		WriteN( strData.c_str(), strData.size() );

	return true;
}

// byte ordering function for 64bit variable
uint64_t CCcCollectdClientSocket::do_htonll( uint64_t hostlonglong )
{
	int x = 1;

	/* little endian */
	if( *(char *)&x == 1 )
		return ( ( ( (uint64_t)htonl( hostlonglong ) ) << 32 ) + htonl( hostlonglong >> 32 ) );

	/* big endian */
	else
		return hostlonglong;
}

uint64_t CCcCollectdClientSocket::do_ntohll( uint64_t netlonglong )
{
	int x = 1;

	/* little endian */
	if( *(char *)&x == 1 )
		return ( ( ( (uint64_t)ntohl( netlonglong ) ) << 32 ) + ntohl( netlonglong >> 32 ) );

	/* big endian */
	else
		return netlonglong;

}

/////////////////////////////////////////////////////////////////

// 전달받은 Target 으로 Socket 접속을 수행
bool CCcCollectdClientSocket::ConnectTarget( const std::string& szTarget, int nPort )
{
	return Connect( szTarget, nPort );
}

// cc_collect 로부터 available size 정보를 요청, 결과를 수신처리한다.
bool CCcCollectdClientSocket::GetAvailableSize( unsigned long long& uSize )
{
	if( IsValidSocket() == false )
		return false;

	// 정보 요청을 위한 Packet Header 생성.
	struct CcCollectdPacketHeader stHeader;
	memset( &stHeader, 0x00, sizeof( struct CcCollectdPacketHeader ) );

	stHeader.stx = HEADER_STX_CODE;
	stHeader.type = HEADER_TYPE_REQUEST;
	stHeader.command[0] = REQUEST_AVAILABLE_SIZE;

	// Data 부분의 길이를 계산한다.
	// - Data 부분 길이는 없음.
	stHeader.data_length = htonl( 0 );

	// Packet Header 정보 전송
	if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
	{
		LOG( LERR, "request [REQUEST_AVAILABLE_SIZE] send fail to cc_collectd. " );
		return false;
	}

	// 응답 대기...
	// 최대 3분 대기
	int nTimeout = 60 * 3; // 최대 3분간 대기
	int nRead;

	// Socket 으로 부터 Packet Header 부분 수신.
	// 수신된 정보는 멤버변수에 저장처리.
	nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, nTimeout );

	// nRead  0: Socket Closed
	//       -1: error 
	//       -2: Timeout 이므로
	if( nRead == -2 )
	{
		// Timeout 발생시
		LOG( LERR, "cc_collectd REQUEST_AVAILABLE_SIZE reponse wait. but timeout[%d sec] occured.", nTimeout );
		return false;
	}
	else if( nRead == 0 || nRead == -1 )
	{
		// Socket Close 또는 오류 발생시
		LOG( LERR, "cc_collectd REQUEST_AVAILABLE_SIZE reponse wait. but socket closed or error [%d]", nRead );
		return false;
	}

	// STX code 검사.
	if( m_packetHeader.stx != HEADER_STX_CODE )
	{
		LOG( LERR, "Not valid stx code." );
		PrintHeaderToLog();

		return false;
	}

	// Data Length 부분 값을 멤버 변수에 저장처리.
	m_nPacketDataLen = ntohl( m_packetHeader.data_length );

	// 해당 Packet 에 대한 응답패킷인지 검사.
	if( m_packetHeader.type != HEADER_TYPE_RESPONSE
		|| m_packetHeader.command[0] != REQUEST_AVAILABLE_SIZE )
	{
		// 다른 패킷이 들어온 경우

		// ** 정석대로라면 그냥 냅둬어 수신부에서 처리해야 하지만
		// 현재 수신 처리부가 없어 당장 문제가 생길수 있으므로 
		// 데이터 부분까지 수신하여 임시버퍼에 저장처리 해 놓는다. 
		GetPacketData( m_nPacketDataLen );
		return false;
	}

	// Data 부분이 존재하는 경우.. 수신 처리.
	if( m_nPacketDataLen > 0 )
	{
		// Data 항목은 
		// - 8 Byte Network byte order 로 구성된 available size 정보가 들어 있음.
		if( GetPacketData( m_nPacketDataLen ) == false )
		{
			LOG( LERR, "available size body receive failed." );
			return false;
		}

		BYTE * pPos = m_tempBuffer;
		uSize = GetDataToUInt64( pPos, true );
	}
	else
	{
		// cc_collectd 로 부터 Available size 응답을 받았지만.. body 가 없는 경우.
		// 이런 경우는 없지만.. 오류 처리를 위해 코딩.
		LOG( LERR, "available size body length zero. check." );
		return false;
	}

	_LOG( LDBG, "cc_collectd available size result received. [%llu]", uSize );
	return true;
}


// cc_collect 로 File 저장 목적으로 전송 
bool CCcCollectdClientSocket::SendFile( const std::string strProcessName, const std::string strFileName
										, const int& fd, const unsigned long long& uFileSize
										, std::string& strMessage )
{
	// 입력 받은 정보가 유효한지 검사.
	// strProcessName : 생략 가능하지만.. 문자열에 '/' 가 포함되서는 안된다.
	// strFileName : 생략 불가, 문자열에 '/' 가 포함되서는 안된다.
	if( strProcessName.empty() == false )
	{
		std::string::size_type pos = strProcessName.find( '/' );
		if( pos != std::string::npos )
		{
			// '/' 문자가 포함된 경우...
			char tempBuffer[1024];
			snprintf( tempBuffer, sizeof( tempBuffer ) - 1
					, "process name[%s] not valid that include slash." 
					, strProcessName.c_str() );

			strMessage.append( tempBuffer );
			LOG( LERR, "%s", strMessage.c_str() );
			
			return false;
		}
	}

	if( strFileName.empty() == false )
	{
		std::string::size_type pos = strFileName.find( '/' );
		if( pos != std::string::npos )
		{
			// '/' 문자가 포함된 경우...
			char tempBuffer[1024];
			snprintf( tempBuffer, sizeof( tempBuffer ) - 1
					, "file name[%s] not valid that include slash." 
					, strFileName.c_str() );

			strMessage.append( tempBuffer );
			LOG( LERR, "%s", strMessage.c_str() );
			
			return false;
		}
	}
	else
	{
		// filename 이 없는 경우.
		strMessage = "filename not vaild. empty.";
		LOG( LERR, "filename not vaild. empty." );
		return false;
	}
		

	unsigned long long uAvailableSize = 0;

	// 1. cc_collectd 로 부터 available size 정보를 수신
	if( GetAvailableSize( uAvailableSize ) == false )
	{
		// available size 체크 실패시...
		strMessage = "cc_collectd available size check fail.";
		return false;
	}

	// 2. 수신된 uAvailableSize 과 전송할 File size 비교
	if( uAvailableSize <= uFileSize )
	{
		char tempBuffer[1024];
		snprintf( tempBuffer, sizeof( tempBuffer ) - 1
				  , "file size[%llu] too large than cc_collect available size [%llu]" 
				  , uFileSize, uAvailableSize );
		
		strMessage.append( tempBuffer );
		LOG( LERR, "%s", strMessage.c_str() );

		return false;
	}

	// 3. 장비의 hostname 정보를 추출한다.
	char szHostName[HOSTNAME_SIZE];
	memset( szHostName, 0x00, HOSTNAME_SIZE );
	if( gethostname( szHostName, HOSTNAME_SIZE - 1 ) != 0 )
	{
		int errorNum = errno;

		strMessage = "hostname get failed. check hostname.";
		LOG( LERR, "hostname get failed. [%d][%s]", errorNum, strerror( errorNum ) );

		return false;
	}

	if( strlen( szHostName ) == 0 )
	{
		strMessage = "hostname not vaild. check hostname.";
		LOG( LERR, "hostname not valid. length 0" );
		return false;
	}
	std::string strHostName = szHostName;   // 추출된 hostname 정보를 전송하기 편하도록 string 객체에 저장처리.


	// 4. 파일 전송 관련 요청 송신
	struct CcCollectdPacketHeader stHeader;
	memset( &stHeader, 0x00, sizeof( struct CcCollectdPacketHeader ) );

	stHeader.stx        = HEADER_STX_CODE;
	stHeader.type       = HEADER_TYPE_REQUEST;
	stHeader.command[0] = REQUEST_FILE_SAVE;

	// Data 부분
	// strHostName    : string ( 4 + string.size() )
	// strProcessName : string ( 4 + string.size() )
	// strFileName    : string ( 4 + string.size() )
	// uFileSize      : 8 Byte	---------->본 항목까지만 header data_length 에 포함시킨다.
	// 저장할 파일 내용.

	// Data 부분의 길이를 계산한다.
	unsigned int nTemp = 0;	
	nTemp += ( 4 + strHostName.size() );     // strHostName
	nTemp += ( 4 + strProcessName.size() );  // strProcessName
	nTemp += ( 4 + strFileName.size() );     // strFileName	
	nTemp += 8;                              // uFileSize

	stHeader.data_length = htonl( nTemp );
	
	// Packet Header 정보 전송
	if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
	{
		strMessage = "request [REQUEST_FILE_SAVE] send fail to cc_collectd.";
		LOG( LERR, "%s", strMessage.c_str() );
		return false;
	}

	// Body 부분 전송
	// strHostName
	SendString( strHostName );
	// strProcessName
	SendString( strProcessName );
	// strFileName
	SendString( strFileName );	
	// uFileSize (Network byte order )
	//uAvailableSize = htobe64( uFileSize );
	uAvailableSize = do_htonll( uFileSize );	

	WriteN( &uAvailableSize, 8 );

	// 파일 내용 전송
	if( uFileSize > 0 )
	{
		off_t offset = 0;

		// sendfile() 에 대한 함수 정의가 Linux, FreeBSD 에서 다르므로.. OS 별로 처리한다.
#ifdef __FreeBSD__

		// FreeBSD 의 경우.. 10G 까지 전송 테스트 됨.

		off_t sbytes;
		int ret = sendfile( fd, m_sock, offset, uFileSize, NULL, &sbytes, 0 );

		if( ret == -1 )
		{
			int errorNum = errno;
			LOG( LERR, "sendfile function error. [%d][%s]", errorNum, strerror( errorNum ) );
			// 전송 실패 발생시... 
			strMessage = "file send fail to cc_collectd";
			return false;
		}
		else if( ( unsigned long long )sbytes != uFileSize )
		{
			LOG( LERR, "sendfile error. file[%s] size[%llu] send size[%ld]", strFileName.c_str(), uFileSize, sbytes );
			strMessage = "file send fail to cc_collectd. file size not match.";
			return false;
		}

#else
		// Linux 의 경우 sendfile 함수가 2G 까지만 전송 가능하므로....루프로 전송 처리가 되도록 처리한다.
		
		ssize_t bytes_sent;
		size_t total_bytes_sent = 0;
	
		while( total_bytes_sent < uFileSize )
		{
			if( (bytes_sent = sendfile(m_sock, fd, &offset, uFileSize - total_bytes_sent)) <= 0 ) 
			{
				int errorNum = errno;
				if (errorNum == EINTR || errorNum == EAGAIN) 
				{
					// Interrupted system call/try again
					// Just skip to the top of the loop and try again 
					continue;
				}
				else
				{
					LOG( LERR, "sendfile function error. [%d][%s]", errorNum, strerror( errorNum ) );
					
					// 전송 실패 발생시... 
					strMessage = "file send fail to cc_collectd";
					return false;
				}
			}

			total_bytes_sent += bytes_sent;
		}
		
		if( ( unsigned long long )total_bytes_sent != uFileSize )
		{
			LOG( LERR, "sendfile error. file[%s] size[%llu] send size[%ld]", strFileName.c_str(), uFileSize, total_bytes_sent );
			strMessage = "file send fail to cc_collectd. file size not match.";
			return false;
		}
#endif

	}

	// 5. File 전송 처리 결과 수신.
	// - 최대 10 분 동안 응답 대기	
	int nTimeout = 60 * 10; // 최대 10분간 대기
	int nRead;

	// Socket 으로 부터 Packet Header 부분 수신.
	// 수신된 정보는 멤버변수에 저장처리.
	nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, nTimeout );

	// nRead  0: Socket Closed
	//       -1: error 
	//       -2: Timeout 이므로
	if( nRead == -2 )
	{
		// Timeout 발생시
		LOG( LERR, "cc_collectd REQUEST_FILE_SAVE reponse wait. but timeout[%d sec] occured.", nTimeout );
		strMessage = "cc_collectd REQUEST_FILE_SAVE reponse timeout[10 min] occured.";
		return false;
	}
	else if( nRead == 0 || nRead == -1 )
	{
		// Socket Close 또는 오류 발생시
		LOG( LERR, "cc_collectd REQUEST_FILE_SAVE reponse wait. but socket closed or error [%d]", nRead );
		strMessage = "cc_collectd REQUEST_FILE_SAVE reponse wait. but session closed.";
		return false;
	}

	// STX code 검사.
	if( m_packetHeader.stx != HEADER_STX_CODE )
	{
		LOG( LERR, "Not valid stx code." );
		strMessage = "cc_collectd REQUEST_FILE_SAVE reponse not valid.";
		PrintHeaderToLog();

		return false;
	}

	// Data Length 부분 값을 멤버 변수에 저장처리.
	m_nPacketDataLen = ntohl( m_packetHeader.data_length );

	// 해당 Packet 에 대한 응답패킷인지 검사.
	if( m_packetHeader.type != HEADER_TYPE_RESPONSE
		|| m_packetHeader.command[0] != REQUEST_FILE_SAVE )
	{
		// 다른 패킷이 들어온 경우

		// ** 정석대로라면 그냥 냅둬어 수신부에서 처리해야 하지만
		// 현재 수신 처리부가 없어 당장 문제가 생길수 있으므로 
		// 데이터 부분까지 수신하여 임시버퍼에 저장처리 해 놓는다. 
		GetPacketData( m_nPacketDataLen );

		strMessage = "cc_collectd REQUEST_FILE_SAVE reponse not valid.";
		return false;
	}

	// Data 부분이 존재하는 경우.. 수신 처리.
	if( m_nPacketDataLen > 0 )
	{
		if( GetPacketData( m_nPacketDataLen, strMessage ) == false )
		{
			LOG( LERR, "cc_collectd REQUEST_FILE_SAVE body receive failed." );
			strMessage = "cc_collectd REQUEST_FILE_SAVE body receive failed.";
			return false;
		}

	}

	// 성공 실패 여부 확인
	if( m_packetHeader.result[0] != HEADER_RESULT_SUCCESS )
	{
		_LOG( LDBG, "cc_collectd REQUEST_FILE_SAVE result received. error[%s]", strMessage.c_str() );
		return false;
	}
	else
	{
		_LOG( LDBG, "cc_collectd REQUEST_FILE_SAVE result received. success." );
		return true;
	}
}



// cc_collect 로 File 존재 여부 확인
bool CCcCollectdClientSocket::CheckFile( const std::string strProcessName, const std::string strFileName
										 , unsigned long long& uFileSize, std::string& strErrorMessage )
{
	// 입력 받은 정보가 유효한지 검사.
	// strProcessName : 생략 가능하지만.. 문자열에 '/' 가 포함되서는 안된다.
	// strFileName : 생략 불가, 문자열에 '/' 가 포함되서는 안된다.
	if( strProcessName.empty() == false )
	{
		std::string::size_type pos = strProcessName.find( '/' );
		if( pos != std::string::npos )
		{
			// '/' 문자가 포함된 경우...
			char tempBuffer[1024];
			snprintf( tempBuffer, sizeof( tempBuffer ) - 1
					  , "process name[%s] not valid that include slash."
					  , strProcessName.c_str() );

			strErrorMessage.append( tempBuffer );
			LOG( LERR, "%s", strErrorMessage.c_str() );

			return false;
		}
	}

	if( strFileName.empty() == false )
	{
		std::string::size_type pos = strFileName.find( '/' );
		if( pos != std::string::npos )
		{
			// '/' 문자가 포함된 경우...
			char tempBuffer[1024];
			snprintf( tempBuffer, sizeof( tempBuffer ) - 1
					  , "file name[%s] not valid that include slash."
					  , strFileName.c_str() );

			strErrorMessage.append( tempBuffer );
			LOG( LERR, "%s", strErrorMessage.c_str() );

			return false;
		}
	}
	else
	{
		// filename 이 없는 경우.
		strErrorMessage = "filename not vaild. empty.";
		LOG( LERR, "filename not vaild. empty." );
		return false;
	}


	// 장비의 hostname 정보를 추출한다.
	char szHostName[HOSTNAME_SIZE];
	memset( szHostName, 0x00, HOSTNAME_SIZE );
	if( gethostname( szHostName, HOSTNAME_SIZE - 1 ) != 0 )
	{
		int errorNum = errno;

		strErrorMessage = "hostname get failed. check hostname.";
		LOG( LERR, "hostname get failed. [%d][%s]", errorNum, strerror( errorNum ) );

		return false;
	}

	if( strlen( szHostName ) == 0 )
	{
		strErrorMessage = "hostname not vaild. check hostname.";
		LOG( LERR, "hostname not valid. length 0" );
		return false;
	}
	std::string strHostName = szHostName;   // 추출된 hostname 정보를 전송하기 편하도록 string 객체에 저장처리.
	
	// 파일 Check 관련 요청 송신
	struct CcCollectdPacketHeader stHeader;
	memset( &stHeader, 0x00, sizeof( struct CcCollectdPacketHeader ) );

	stHeader.stx        = HEADER_STX_CODE;
	stHeader.type       = HEADER_TYPE_REQUEST;
	stHeader.command[0] = REQUEST_FILE_CHECK;

	// Data 부분
	// strHostName    : string ( 4 + string.size() )
	// strProcessName : string ( 4 + string.size() )
	// strFileName    : string ( 4 + string.size() )
		

	// Data 부분의 길이를 계산한다.
	unsigned int nTemp = 0;
	nTemp += ( 4 + strHostName.size() );     // strHostName
	nTemp += ( 4 + strProcessName.size() );  // strProcessName
	nTemp += ( 4 + strFileName.size() );     // strFileName	
	
	stHeader.data_length = htonl( nTemp );

	// Packet Header 정보 전송
	if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
	{
		strErrorMessage = "request [REQUEST_FILE_CHECK] send fail to cc_collectd.";
		LOG( LERR, "%s", strErrorMessage.c_str() );
		return false;
	}

	// Body 부분 전송
	// strHostName
	SendString( strHostName );
	// strProcessName
	SendString( strProcessName );
	// strFileName
	SendString( strFileName );
	

	// File Check 처리 결과 수신.
	// - 최대 30 sec 동안 응답 대기	
	int nTimeout = 30;
	int nRead;

	// Socket 으로 부터 Packet Header 부분 수신.
	// 수신된 정보는 멤버변수에 저장처리.
	nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, nTimeout );

	// nRead  0: Socket Closed
	//       -1: error 
	//       -2: Timeout 이므로
	if( nRead == -2 )
	{
		// Timeout 발생시
		LOG( LERR, "cc_collectd REQUEST_FILE_CHECK reponse wait. but timeout[%d sec] occured.", nTimeout );
		strErrorMessage = "cc_collectd REQUEST_FILE_CHECK reponse timeout[30 sec] occured.";
		return false;
	}
	else if( nRead == 0 || nRead == -1 )
	{
		// Socket Close 또는 오류 발생시
		LOG( LERR, "cc_collectd REQUEST_FILE_CHECK reponse wait. but socket closed or error [%d]", nRead );
		strErrorMessage = "cc_collectd REQUEST_FILE_CHECK reponse wait. but session closed.";
		return false;
	}

	// STX code 검사.
	if( m_packetHeader.stx != HEADER_STX_CODE )
	{
		LOG( LERR, "Not valid stx code." );
		strErrorMessage = "cc_collectd REQUEST_FILE_CHECK reponse not valid.";
		PrintHeaderToLog();

		return false;
	}

	// Data Length 부분 값을 멤버 변수에 저장처리.
	m_nPacketDataLen = ntohl( m_packetHeader.data_length );

	// 해당 Packet 에 대한 응답패킷인지 검사.
	if( m_packetHeader.type != HEADER_TYPE_RESPONSE
		|| m_packetHeader.command[0] != REQUEST_FILE_CHECK )
	{
		// 다른 패킷이 들어온 경우

		// ** 정석대로라면 그냥 냅둬어 수신부에서 처리해야 하지만
		// 현재 수신 처리부가 없어 당장 문제가 생길수 있으므로 
		// 데이터 부분까지 수신하여 임시버퍼에 저장처리 해 놓는다. 
		GetPacketData( m_nPacketDataLen );

		strErrorMessage = "cc_collectd REQUEST_FILE_CHECK reponse not valid.";
		return false;
	}


	// 성공 실패 여부 확인
	if( m_packetHeader.result[0] == HEADER_RESULT_SUCCESS )
	{
		// 성공인 경우...
		// - File Size 정보를 수신 처리한다.

		// Data 항목은 
		// - 8 Byte Network byte order 로 구성된 available size 정보가 들어 있음.
		if( GetPacketData( m_nPacketDataLen ) == false )
		{
			LOG( LERR, "cc_collectd REQUEST_FILE_CHECK file size body receive failed." );
			strErrorMessage = "cc_collectd REQUEST_FILE_CHECK file size body receive failed.";
			return false;
		}

		BYTE * pPos = m_tempBuffer;
		uFileSize = GetDataToUInt64( pPos, true );

		return true;
	}
	else
	{
		// 오류가 발생한 경우..
		// - 수신할 메시지가 존재하는 경우.. 수신 처리한다.
		if( m_nPacketDataLen > 0 )
		{
			if( GetPacketData( m_nPacketDataLen, strErrorMessage ) == false )
			{
				LOG( LERR, "cc_collectd REQUEST_FILE_CHECK error body receive failed." );
				strErrorMessage = "cc_collectd REQUEST_FILE_CHECK error body receive failed.";
				return false;
			}
		}

		// 오류 반환 처리.
		return false;
	}
}
