Files
interactive/rcts/rc_balanced/ftsd/FtsdSocketControl.cpp
2026-08-07 17:38:18 +09:00

1200 lines
36 KiB
C++

#include "FtsdSocketControl.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <iterator>
// NEW 2016-05-12 huibong data 수신 실패시 timeout 처리 관련 기능 추가.
#define FTSD_DATA_RECV_TIMEOUT 2 //sec ( 3 sec 이상일 경우.. Alive check 와 충돌로 timeout 처리가 안 될 수 있음.)
/// @brief 생성자.
CFtsdSocketControl::CFtsdSocketControl( )
: CBaseSocket( SOCKET_NOT_VALID )
, m_nPacketHeaderLen ( sizeof(m_packetHeader))
, m_nPacketDataLen( 0 )
{
}
/// @brief 소멸자
CFtsdSocketControl::~CFtsdSocketControl()
{
// 소멸자 Socket 명시적 Close 처리.
Close();
}
/// @brief 전달받은 Target 으로 Socket 접속을 수행
/// @param szTarget [in] 접속 대상 Host name 또는 IP
/// @param nPort [in] 접속 Port
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool CFtsdSocketControl::ConnectTarget( const std::string& szTarget, int nPort )
{
return Connect( szTarget, nPort );
}
/// @brief Packet Header 정보를 Log 파일에 Logging 처리
void CFtsdSocketControl::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, "------------------------------------" );
}
/// @brief Alive Check 를 위한 패킷 전송 => 해당 패킷의 응답은 필요없으므로 수신시 무시할 것.
/// @return 전송 성공시 true, 실패시 false 반환.
bool CFtsdSocketControl::SendAliveCheck()
{
if( IsValidSocket() == false )
return false;
// 정보 요청을 위한 Packet Header 생성.
struct FileTransferPacketHeader stHeader;
memset(&stHeader, 0x00, sizeof(struct FileTransferPacketHeader));
stHeader.stx = HEADER_STX_CODE;
stHeader.type = HEADER_TYPE_REQUEST;
stHeader.command[0] = COMMON_ALIVE_CHECK;
// Packet Header 정보 전송
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
return false;
return true;
}
/// @brief 연결된 Socket 을 통해 Transfer Daemon 으로 File Replication 명령 전송.
/// @param szFileName [in] 복제할 원본 Source 파일명
/// @param nFileSize [in] 복제할 원본 Source 파일의 크기.
/// @param szTargetTranId [in[ RC 간 복제 처리시 변경할 대상 Tran ID 정보 값
/// @param nFileHashCheckLevel [in] File 에 대한 Hash Check Level 정보
/// @param bUseInternalIp [in] 내부망을 이용하여 파일 송수신을 수행할지 여부
/// @param vecTargetFhs [in] 복제할 Target FHS 정보
/// @return Replication 복제 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool CFtsdSocketControl::SendFileReplicationRequest(const std::string& szFileName, unsigned long long nFileSize
, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs)
{
std::string szTargetTranId;
szTargetTranId.clear();
return SendFileReplicationRequest( szFileName, nFileSize, szTargetTranId, nFileHashCheckLevel, bUseInternalIp, vecTargetFhs);
}
bool CFtsdSocketControl::SendFileReplicationRequest(const std::string& szFileName, unsigned long long nFileSize
, const std::string& szTargetTranId, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs)
{
if( IsValidSocket() == false )
return false;
// 정보 요청을 위한 Packet Header 생성.
struct FileTransferPacketHeader stHeader;
memset(&stHeader, 0x00, sizeof(struct FileTransferPacketHeader));
stHeader.stx = HEADER_STX_CODE;
stHeader.type = HEADER_TYPE_REQUEST;
stHeader.command[0] = CONTROL_FILE_REPLICATION;
// Data 부분의 길이를 계산한다.
unsigned int nTemp = 0;
nTemp = 4 + szFileName.size(); // File Name ( 4 + 가변 )
nTemp += 8; // File Size ( 8 Byte )
nTemp += ( 4 + szTargetTranId.size()); // Target Tran ID ( 4 + 가변 )
nTemp += 4; // File Hash check Level ( 4 Byte )
nTemp += 1; // 내부망 IP 사용 여부 ( 1 Byte )
nTemp += 4; // FHS Count ( 4 Byte )
std::vector< std::string >::const_iterator it;
for( it = vecTargetFhs.begin(); it != vecTargetFhs.end() ; it++ )
{
nTemp = nTemp + 4 + it->size() ; // Target FHS 정보 ( 4 + 가변 )
}
stHeader.data_length = htonl( nTemp );
// Packet Header 정보 전송
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
{
LOG( LERR, "File Replication request send failed.");
return false;
}
// Packet Data 부분 전송
// File Name 부분
nTemp = htonl( szFileName.size() );
WriteN( &nTemp, 4);
WriteN( szFileName.c_str(), szFileName.size() );
// File Size 전송
WriteN( &nFileSize, 8 );
// Target Tran ID 부분
nTemp = htonl( szTargetTranId.size() );
WriteN( &nTemp, 4);
if( szTargetTranId.size() > 0 )
WriteN( szTargetTranId.c_str(), szTargetTranId.size() );
// File Hash Check Level 전송
nTemp = htonl( nFileHashCheckLevel );
WriteN( &nTemp, 4);
// 내부망 사용 여부 전달
if( bUseInternalIp == true )
m_tempBuffer[0] = 0x01;
else
m_tempBuffer[0] = 0x00;
WriteN( m_tempBuffer, 1);
// Target FHS Count 정보 전달.
nTemp = htonl( vecTargetFhs.size() );
WriteN( &nTemp, 4);
// Loop 를 돌면서 각 FHS 정보를 전달한다.
for( it = vecTargetFhs.begin(); it != vecTargetFhs.end() ; it++ )
{
nTemp = htonl( it->size() );
WriteN( &nTemp, 4);
WriteN( it->c_str(), it->size());
}
return true;
}
/// @brief File Replication 요청에 대한 처리 결과를 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값.
/// @param bSuccess [out] File Replication 이 정상적으로 수행되었는지 여부
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보.
/// @param mapSuccessFhs [out] Replication 에 대한 처리 성공시 성공한 FHS 및 File 정보를 저장
/// @param mapFailFhs [out] Replication 에 대한 처리 성공시 실패한 FHS 및 오류메시지 정보를 저장.
/// @return -1 : Read 수신시 오류 발생시 => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///< 0 : nTimeout 에 지정된 시간안에 완료 응답을 받지 못한 경우. \n
///< 이 기능은 호출 함수의 Block 을 해제하기 위한 기능으로 \n
///< 이 값이 반환된 경우 다른 작업을 한 후 다시 호출하도록 한다. \n
///< 1 : 파일 복제 처리에 대한 응답을 수신한 경우, Output 인자를 확인할 것. \n
///< 2 : Transfer Daemon 으로 부터 Packet 을 수신하였으나 File Replication 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 멤버변수 상에 저장된다. ( 단 Alive Packet 은 아님)
int CFtsdSocketControl::GetFileReplicationResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage
, std::map< std::string, std::string>& mapSuccessFhs
, std::map< std::string, std::string>& mapFailFhs )
{
// 복제 요청에 대한 응답 패킷 대기
// 수신 대기 Timeout 은 전달받은 값으로 설정.
if( IsValidSocket() == false )
return -1;
int nRead;
bool isAlivePacket;
do
{
isAlivePacket = false;
// Socket 으로 부터 Packet Header 부분 수신.
// 수신된 정보는 멤버변수에 저장처리.
nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, nTimeout );
// nRead 0: Socket Closed, -1: error , -2: Timeout 이므로
if( nRead == -2 )
return 0; // Timeout 반환.
else if( nRead == 0 || nRead == -1 )
return -1; // Socket Close 또는 오류 발생시
// STX code 검사.
if( m_packetHeader.stx != HEADER_STX_CODE )
{
LOG( LERR, "Not valid stx code.");
return -1;
}
// Data Length 부분 값을 멤버 변수에 저장처리.
m_nPacketDataLen = ntohl( m_packetHeader.data_length );
// Alive Check Packet 인 경우 해당 패킷은 무시처리 후 다시 수신 처리한다.
if( m_packetHeader.type == HEADER_TYPE_REQUEST
&& m_packetHeader.command[0] == COMMON_ALIVE_CHECK
&& m_nPacketDataLen == 0 )
{
isAlivePacket = true;
}
} while( isAlivePacket == true );
// Alive Packet 이 아닌 경우 해당 Packet 에 대한 복제에 대한 응답패킷인지 검사.
if( m_packetHeader.type != HEADER_TYPE_RESPONSE
|| m_packetHeader.command[0] != CONTROL_FILE_REPLICATION )
{
// 다른 패킷이 들어온 경우
// ** 정석대로라면 그냥 냅둬어 수신부에서 처리해야 하지만
// 현재 수신 처리부가 없어 당장 문제가 생길수 있으므로
// 데이터 부분까지 수신하여 임시버퍼에 저장처리 해 놓는다.
GetPacketData( m_nPacketDataLen );
return 2;
}
// Replication 에 대한 응답 패킷인 경우
// 1. 성공, 실패 여부 판단.
if( m_packetHeader.result[0] != HEADER_RESULT_SUCCESS )
{
// 오류가 발생한 경우임
bSuccess = false;
// Packet Data 상에서 오류 메시지를 수신받아 반환 처리.
if( GetPacketData( m_nPacketDataLen, szErrorMessage ) == false )
{
LOG( LERR, "Error msg receive failed.");
return -1;
}
else
return 1;
}
// 2. 성공인 경우
bSuccess = true;
unsigned int nCount;
unsigned int nLength;
std::string szKey;
std::string szValue;
// 2.1 성공 목록의 Count 정보 수신
if( GetPacketData( 4 ) == false )
{
LOG( LERR, "Success count receive failed.");
return -1;
}
nCount = GetDataToUInt( m_tempBuffer, true);
for( unsigned int i = 0; i < nCount; i++)
{
szKey.clear();
szValue.clear();
GetPacketData( 4 );
nLength = GetDataToUInt( m_tempBuffer, true);
GetPacketData( nLength, szKey );
GetPacketData( 4 );
nLength = GetDataToUInt( m_tempBuffer, true);
GetPacketData( nLength, szValue );
mapSuccessFhs[ szKey ] = szValue;
}
// 2.2 실패 목록의 Count 정보 수신
if( GetPacketData( 4 ) == false )
{
LOG( LERR, "Failed count receive failed.");
return -1;
}
nCount = GetDataToUInt( m_tempBuffer, true);
for( unsigned int i = 0; i < nCount; i++)
{
szKey.clear();
szValue.clear();
GetPacketData( 4 );
nLength = GetDataToUInt( m_tempBuffer, true);
GetPacketData( nLength, szKey );
GetPacketData( 4 );
nLength = GetDataToUInt( m_tempBuffer, true);
GetPacketData( nLength, szValue );
mapFailFhs[ szKey ] = szValue;
}
return 1;
}
/// @brief 대상과 연결된 Socket 을 통해 Transfer Daemon 으로 File Cache 명령 전송.
/// @param szFileName [in] Cache 처리할 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @param nFileSize [in] Cache 처리할 원본 Source 파일의 크기.
/// @param nFileHashCheckLevel [in] File 에 대한 Hash Check Level 정보 ( conf 파일에 지정됨)
/// @param bUseInternalIp [in] 내부망을 이용하여 파일 송수신을 수행할지 여부 \n
///< 해당값을 true 로 지정시 ftsd 상에서 내부망을 우선 사용하여 파일 복제 시도
///< 만약 내부망 사용 불가시 자동으로 외부망 사용.
/// @param vecTargetFhs [in] Cache 대상 Target FHS Host Name 정보
/// @return Cache 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool CFtsdSocketControl::SendFileCacheRequest(const std::string& szFileName, unsigned long long nFileSize
, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs)
{
if( IsValidSocket() == false )
return false;
// 정보 요청을 위한 Packet Header 생성.
struct FileTransferPacketHeader stHeader;
memset(&stHeader, 0x00, sizeof(struct FileTransferPacketHeader));
stHeader.stx = HEADER_STX_CODE;
stHeader.type = HEADER_TYPE_REQUEST;
stHeader.command[0] = CONTROL_FILE_CACHE;
// Data 부분의 길이를 계산한다.
unsigned int nTemp = 0;
nTemp = 4 + szFileName.size(); // File Name ( 4 + 가변 )
nTemp += 8; // File Size ( 8 Byte )
nTemp += 4; // Target Tran ID ( 4 + 실제값은 사용 안하므로 0 )
nTemp += 4; // File Hash check Level ( 4 Byte )
nTemp += 1; // 내부망 IP 사용 여부 ( 1 Byte )
nTemp += 4; // FHS Count ( 4 Byte )
std::vector< std::string >::const_iterator it;
for( it = vecTargetFhs.begin(); it != vecTargetFhs.end() ; it++ )
{
nTemp = nTemp + 4 + it->size() ; // Target FHS 정보 ( 4 + 가변 )
}
stHeader.data_length = htonl( nTemp );
// Packet Header 정보 전송
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
{
LOG( LERR, "File Cache request send failed.");
return false;
}
// Packet Data 부분 전송
// File Name 부분
nTemp = htonl( szFileName.size() );
WriteN( &nTemp, 4);
WriteN( szFileName.c_str(), szFileName.size() );
// File Size 전송
WriteN( &nFileSize, 8 );
// Target Tran ID 부분
nTemp = htonl( 0 );
WriteN( &nTemp, 4);
// File Hash Check Level 전송
nTemp = htonl( nFileHashCheckLevel );
WriteN( &nTemp, 4);
// 내부망 사용 여부 전달
if( bUseInternalIp == true )
m_tempBuffer[0] = 0x01;
else
m_tempBuffer[0] = 0x00;
WriteN( m_tempBuffer, 1);
// Target FHS Count 정보 전달.
nTemp = htonl( vecTargetFhs.size() );
WriteN( &nTemp, 4);
// Loop 를 돌면서 각 FHS 정보를 전달한다.
for( it = vecTargetFhs.begin(); it != vecTargetFhs.end() ; it++ )
{
nTemp = htonl( it->size() );
WriteN( &nTemp, 4);
WriteN( it->c_str(), it->size());
}
return true;
}
/// @brief File Cache 요청에 대한 처리 결과를 transfer daemon 으로 부터 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
/// @param bSuccess [out] File Cache 처리가 정상적으로 수행되었는지 여부 \n
///< trnsfer 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
///< 정상적으로 처리된 경우 true 가 저장되며 \n
///< mapSuccessFhs, mapFailFhs 상에 관련 정보가 저장됨.
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
/// @param mapSuccessFhs [out] bSuccess == true 인 경우 \n
///< Cache 처리에 성공한 FHS 및 저장된 File 이름 정보를 저장
/// @param mapFailFhs [out] bSuccess == true 인 경우 \n
///< Cache 처리에 실패한 FHS Host Name 및 발생된 오류메시지 정보를 저장.
/// @return -1 : Socket 통신 관련 오류 발생하여 Transfer Daemon 과 연결이 끊어진 경우 \n
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 Transfer Daemon으로부터
///< Cache 에 대한 처리 결과 정보를 수신하지 못한 경우. \n
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
///< 응답을 대기할 수 있다. \n
///< 1 : 파일 Cache 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
///< 2 : Transfer Daemon 으로 부터 Data 을 수신하였으나 File Cache 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
int CFtsdSocketControl::GetFileCacheResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage
, std::map< std::string, std::string>& mapSuccessFhs
, std::map< std::string, std::string>& mapFailFhs )
{
// Cache 처리 요청에 대한 응답 패킷 대기
// 수신 대기 Timeout 은 전달받은 값으로 설정.
if( IsValidSocket() == false )
return -1;
int nRead;
bool isAlivePacket;
do
{
isAlivePacket = false;
// Socket 으로 부터 Packet Header 부분 수신.
// 수신된 정보는 멤버변수에 저장처리.
nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, nTimeout );
// nRead 0: Socket Closed, -1: error , -2: Timeout 이므로
if( nRead == -2 )
return 0; // Timeout 반환.
else if( nRead == 0 || nRead == -1 )
return -1; // Socket Close 또는 오류 발생시
// STX code 검사.
if( m_packetHeader.stx != HEADER_STX_CODE )
{
LOG( LERR, "Not valid stx code.");
return -1;
}
// Data Length 부분 값을 멤버 변수에 저장처리.
m_nPacketDataLen = ntohl( m_packetHeader.data_length );
// Alive Check Packet 인 경우 해당 패킷은 무시처리 후 다시 수신 처리한다.
if( m_packetHeader.type == HEADER_TYPE_REQUEST
&& m_packetHeader.command[0] == COMMON_ALIVE_CHECK
&& m_nPacketDataLen == 0 )
{
isAlivePacket = true;
}
} while( isAlivePacket == true );
// Alive Packet 이 아닌 경우 해당 Packet 에 대한 Cache 처리 요청에 대한 응답패킷인지 검사.
if( m_packetHeader.type != HEADER_TYPE_RESPONSE
|| m_packetHeader.command[0] != CONTROL_FILE_CACHE )
{
// 다른 패킷이 들어온 경우
// ** 정석대로라면 그냥 냅둬어 수신부에서 처리해야 하지만
// 현재 수신 처리부가 없어 당장 문제가 생길수 있으므로
// 데이터 부분까지 수신하여 임시버퍼에 저장처리 해 놓는다.
GetPacketData( m_nPacketDataLen );
return 2;
}
// Cache 요청에 대한 응답 패킷인 경우
// 1. 성공, 실패 여부 판단.
if( m_packetHeader.result[0] != HEADER_RESULT_SUCCESS )
{
// 오류가 발생한 경우임
bSuccess = false;
// Packet Data 상에서 오류 메시지를 수신받아 반환 처리.
if( GetPacketData( m_nPacketDataLen, szErrorMessage ) == false )
{
LOG( LERR, "Error msg receive failed.");
return -1;
}
else
return 1;
}
// 2. 성공인 경우
bSuccess = true;
unsigned int nCount;
unsigned int nLength;
std::string szKey;
std::string szValue;
// 2.1 성공 목록의 Count 정보 수신
if( GetPacketData( 4 ) == false )
{
LOG( LERR, "Success count receive failed.");
return -1;
}
nCount = GetDataToUInt( m_tempBuffer, true);
for( unsigned int i = 0; i < nCount; i++)
{
szKey.clear();
szValue.clear();
GetPacketData( 4 );
nLength = GetDataToUInt( m_tempBuffer, true);
GetPacketData( nLength, szKey );
GetPacketData( 4 );
nLength = GetDataToUInt( m_tempBuffer, true);
GetPacketData( nLength, szValue );
mapSuccessFhs[ szKey ] = szValue;
}
// 2.2 실패 목록의 Count 정보 수신
if( GetPacketData( 4 ) == false )
{
LOG( LERR, "Failed count receive failed.");
return -1;
}
nCount = GetDataToUInt( m_tempBuffer, true);
for( unsigned int i = 0; i < nCount; i++)
{
szKey.clear();
szValue.clear();
GetPacketData( 4 );
nLength = GetDataToUInt( m_tempBuffer, true);
GetPacketData( nLength, szKey );
GetPacketData( 4 );
nLength = GetDataToUInt( m_tempBuffer, true);
GetPacketData( nLength, szValue );
mapFailFhs[ szKey ] = szValue;
}
return 1;
}
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 Content Check 명령 전송.
bool CFtsdSocketControl::SendFileCheckRequest(const std::string& szFileName, bool bHashCheck, unsigned long long nHashCheckSize )
{
if( IsValidSocket() == false )
return false;
// 정보 요청을 위한 Packet Header 생성.
struct FileTransferPacketHeader stHeader;
memset(&stHeader, 0x00, sizeof(struct FileTransferPacketHeader));
stHeader.stx = HEADER_STX_CODE;
stHeader.type = HEADER_TYPE_REQUEST;
stHeader.command[0] = CONTROL_FILE_CHECK;
// Data 부분의 길이를 계산한다.
unsigned int nTemp = 0;
nTemp = 4 + szFileName.size(); // File Name ( 4 + 가변 )
nTemp += 4; // File Hash 추출 여부 ( 4 Byte )
if( bHashCheck == true )
{
nTemp += 8; // File Hash 추출 Size 정보 ( 8 Byte )
}
stHeader.data_length = htonl( nTemp );
// Packet Header 정보 전송
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
{
LOG( LERR, "File[%s] Check request send failed.", szFileName.c_str() );
return false;
}
// Packet Data 부분 전송
// 1. File Name 부분
nTemp = htonl( szFileName.size() );
WriteN( &nTemp, 4);
WriteN( szFileName.c_str(), szFileName.size() );
// 2. Hash 추출 여부
if( bHashCheck == true )
{
nTemp = htonl( 1 );
WriteN( &nTemp, 4);
// 3. Hash 추출 size (MByte 단위 ) 값 전송.
WriteN( &nHashCheckSize, 8 );
}
else
{
nTemp = htonl( 0 );
WriteN( &nTemp, 4);
}
return true;
}
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 Unlink 명령 전송.
bool CFtsdSocketControl::SendFileUnlinkRequest(const std::string& szFileName, unsigned long long nFileSize, bool bForceUnlink )
{
if( IsValidSocket() == false )
return false;
// 정보 요청을 위한 Packet Header 생성.
struct FileTransferPacketHeader stHeader;
memset(&stHeader, 0x00, sizeof(struct FileTransferPacketHeader));
stHeader.stx = HEADER_STX_CODE;
stHeader.type = HEADER_TYPE_REQUEST;
stHeader.command[0] = CONTROL_FILE_UNLINK;
// Data 부분의 길이를 계산한다.
unsigned int nTemp = 0;
nTemp = 4 + szFileName.size(); // File Name ( 4 + 가변 )
nTemp += 8; // File Size ( 8 Byte )
nTemp += 4; // Unlink Mode ( 4 Byte )
stHeader.data_length = htonl( nTemp );
// Packet Header 정보 전송
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
{
LOG( LERR, "File[%s] Unlink request send failed.", szFileName.c_str() );
return false;
}
// Packet Data 부분 전송
// 1. File Name 부분
nTemp = htonl( szFileName.size() );
WriteN( &nTemp, 4);
WriteN( szFileName.c_str(), szFileName.size() );
// 2. File Size 부분
WriteN( &nFileSize, 8 );
// 3. Unlink Mode 정보
if( bForceUnlink == true )
{
nTemp = htonl( UNLINK_MODE_FORCE );
}
else
{
nTemp = htonl( UNLINK_MODE_NORMAL );
}
WriteN( &nTemp, 4);
return true;
}
/// @brief File Check 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
int CFtsdSocketControl::GetFileCheckResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage, unsigned long long& nFileSize, std::string& szHashValue )
{
if( IsValidSocket() == false )
return -1;
int nRead;
bool isAlivePacket;
do
{
isAlivePacket = false;
// Socket 으로 부터 Packet Header 부분 수신.
// 수신된 정보는 멤버변수에 저장처리.
nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, nTimeout );
// nRead 0: Socket Closed, -1: error , -2: Timeout 이므로
if( nRead == -2 )
return 0; // Timeout 반환.
else if( nRead == 0 || nRead == -1 )
return -1; // Socket Close 또는 오류 발생시
// STX code 검사.
if( m_packetHeader.stx != HEADER_STX_CODE )
{
LOG( LERR, "Not valid stx code.");
return -1;
}
// Data Length 부분 값을 멤버 변수에 저장처리.
m_nPacketDataLen = ntohl( m_packetHeader.data_length );
// Alive Check Packet 인 경우 해당 패킷은 무시처리 후 다시 수신 처리한다.
if( m_packetHeader.type == HEADER_TYPE_REQUEST
&& m_packetHeader.command[0] == COMMON_ALIVE_CHECK
&& m_nPacketDataLen == 0 )
{
isAlivePacket = true;
}
} while( isAlivePacket == true );
// Alive Packet 이 아닌 경우 해당 Packet 에 대한 Check에 대한 응답 패킷인지 검사.
if( m_packetHeader.type != HEADER_TYPE_RESPONSE
|| m_packetHeader.command[0] != CONTROL_FILE_CHECK )
{
// 다른 패킷이 들어온 경우
// ** 정석대로라면 그냥 냅둬어 수신부에서 처리해야 하지만
// 현재 수신 처리부가 없어 당장 문제가 생길수 있으므로
// 데이터 부분까지 수신하여 임시버퍼에 저장처리 해 놓는다.
GetPacketData( m_nPacketDataLen );
return 2;
}
// Check 에 대한 응답 패킷이 경우.
// 1. 성공, 실패 여부 판단.
if( m_packetHeader.result[0] != HEADER_RESULT_SUCCESS )
{
// 오류가 발생한 경우임
bSuccess = false;
// Packet Data 상에서 오류 메시지를 수신받아 반환 처리.
if( GetPacketData( m_nPacketDataLen, szErrorMessage ) == false )
{
LOG( LERR, "Error msg receive failed.");
return -1;
}
else
return 1;
}
// 2. 성공인 경우
bSuccess = true;
// 2.1 File Size 정보 추출..
if( GetPacketData( 8 ) == false )
{
LOG( LERR, "File size receive fail.");
return -1;
}
nFileSize = GetDataToUInt64( m_tempBuffer );
// 2.2 File Hash 필드의 Length 정보 추출.
if( GetPacketData( 4 ) == false )
{
LOG( LERR, "Hash length receive fail.");
return -1;
}
unsigned int nLength = GetDataToUInt( m_tempBuffer, true);
if( nLength > 0 )
{
// 추출된 Hash 정보 저장.
GetPacketData( nLength, szHashValue );
}
return 1;
}
/// @brief File Unlink 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
int CFtsdSocketControl::GetFileUnlinkResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage )
{
if( IsValidSocket() == false )
return -1;
int nRead;
bool isAlivePacket;
do
{
isAlivePacket = false;
// Socket 으로 부터 Packet Header 부분 수신.
// 수신된 정보는 멤버변수에 저장처리.
nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, nTimeout );
// nRead 0: Socket Closed, -1: error , -2: Timeout 이므로
if( nRead == -2 )
return 0; // Timeout 반환.
else if( nRead == 0 || nRead == -1 )
return -1; // Socket Close 또는 오류 발생시
// STX code 검사.
if( m_packetHeader.stx != HEADER_STX_CODE )
{
LOG( LERR, "Not valid stx code.");
return -1;
}
// Data Length 부분 값을 멤버 변수에 저장처리.
m_nPacketDataLen = ntohl( m_packetHeader.data_length );
// Alive Check Packet 인 경우 해당 패킷은 무시처리 후 다시 수신 처리한다.
if( m_packetHeader.type == HEADER_TYPE_REQUEST
&& m_packetHeader.command[0] == COMMON_ALIVE_CHECK
&& m_nPacketDataLen == 0 )
{
isAlivePacket = true;
}
} while( isAlivePacket == true );
// Alive Packet 이 아닌 경우 해당 Packet 에 대한 Unlink 에 대한 응답 패킷인지 검사.
if( m_packetHeader.type != HEADER_TYPE_RESPONSE
|| m_packetHeader.command[0] != CONTROL_FILE_UNLINK )
{
// 다른 패킷이 들어온 경우
// ** 정석대로라면 그냥 냅둬어 수신부에서 처리해야 하지만
// 현재 수신 처리부가 없어 당장 문제가 생길수 있으므로
// 데이터 부분까지 수신하여 임시버퍼에 저장처리 해 놓는다.
GetPacketData( m_nPacketDataLen );
return 2;
}
// Unlink 에 대한 응답 패킷이 경우.
// 1. 성공, 실패 여부 판단.
if( m_packetHeader.result[0] != HEADER_RESULT_SUCCESS )
{
// 오류가 발생한 경우임
bSuccess = false;
// Packet Data 상에서 오류 메시지를 수신받아 반환 처리.
if( GetPacketData( m_nPacketDataLen, szErrorMessage ) == false )
{
LOG( LERR, "Error msg receive failed.");
return -1;
}
else
return 1;
}
// 2. 성공인 경우
bSuccess = true;
// 2.1 성공인 경우 Data 부분이 존재하지 않으므로.. Pass..
return 1;
}
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460)
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 Content Check 명령 전송. (토토디스크 지원용)
/// @param szFileName [in] 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @return Check 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool CFtsdSocketControl::SendFileCheckTOTORequest( const std::string& szFileName )
{
if( IsValidSocket() == false )
return false;
// 정보 요청을 위한 Packet Header 생성.
struct FileTransferPacketHeader stHeader;
memset( &stHeader, 0x00, sizeof( struct FileTransferPacketHeader ) );
stHeader.stx = HEADER_STX_CODE;
stHeader.type = HEADER_TYPE_REQUEST;
stHeader.command[0] = CONTROL_FILE_CHECK_TOTO;
// Data 부분의 길이를 계산한다.
unsigned int nTemp = 0;
nTemp = 4 + szFileName.size(); // File Name ( 4 + 가변 )
stHeader.data_length = htonl( nTemp );
// Packet Header 정보 전송
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
{
LOG( LERR, "TOTO File[%s] Check request send failed.", szFileName.c_str() );
return false;
}
// Packet Data 부분 전송
// 1. File Name 부분
nTemp = htonl( szFileName.size() );
WriteN( &nTemp, 4 );
WriteN( szFileName.c_str(), szFileName.size() );
return true;
}
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460, #27533)
/// @brief File Check 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
int CFtsdSocketControl::GetFileCheckTOTOResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage
, unsigned long long& nFileSize, std::string& szTotoMd5, std::string& szChecksum, std::string& szDnaCheckKey )
{
if( IsValidSocket() == false )
return -1;
int nRead;
bool isAlivePacket;
do
{
isAlivePacket = false;
// Socket 으로 부터 Packet Header 부분 수신.
// 수신된 정보는 멤버변수에 저장처리.
nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, nTimeout );
// nRead 0: Socket Closed, -1: error , -2: Timeout 이므로
if( nRead == -2 )
return 0; // Timeout 반환.
else if( nRead == 0 || nRead == -1 )
return -1; // Socket Close 또는 오류 발생시
// STX code 검사.
if( m_packetHeader.stx != HEADER_STX_CODE )
{
LOG( LERR, "Not valid stx code." );
return -1;
}
// Data Length 부분 값을 멤버 변수에 저장처리.
m_nPacketDataLen = ntohl( m_packetHeader.data_length );
// Alive Check Packet 인 경우 해당 패킷은 무시처리 후 다시 수신 처리한다.
if( m_packetHeader.type == HEADER_TYPE_REQUEST
&& m_packetHeader.command[0] == COMMON_ALIVE_CHECK
&& m_nPacketDataLen == 0 )
{
isAlivePacket = true;
}
} while( isAlivePacket == true );
// Alive Packet 이 아닌 경우 해당 Packet 에 대한 Check에 대한 응답 패킷인지 검사.
if( m_packetHeader.type != HEADER_TYPE_RESPONSE
|| m_packetHeader.command[0] != CONTROL_FILE_CHECK_TOTO )
{
// 다른 패킷이 들어온 경우
// ** 정석대로라면 그냥 냅둬어 수신부에서 처리해야 하지만
// 현재 수신 처리부가 없어 당장 문제가 생길수 있으므로
// 데이터 부분까지 수신하여 임시버퍼에 저장처리 해 놓는다.
GetPacketData( m_nPacketDataLen );
return 2;
}
// Check 에 대한 응답 패킷이 경우.
// 1. 성공, 실패 여부 판단.
if( m_packetHeader.result[0] != HEADER_RESULT_SUCCESS )
{
// 오류가 발생한 경우임
bSuccess = false;
// Packet Data 상에서 오류 메시지를 수신받아 반환 처리.
if( GetPacketData( m_nPacketDataLen, szErrorMessage ) == false )
{
LOG( LERR, "Error msg receive failed." );
return -1;
}
else
return 1;
}
// 2. 성공인 경우
bSuccess = true;
// 2.1 File Size 정보 추출..
if( GetPacketData( 8 ) == false )
{
LOG( LERR, "File size receive fail." );
return -1;
}
nFileSize = GetDataToUInt64( m_tempBuffer );
unsigned int nLength = 0;
// 2.2 totorasa 용 MD5 Hash 값 정보 수신 및 저장
if( GetPacketData( 4 ) == false )
{
LOG( LERR, "szTotoMd5 length receive fail." );
return -1;
}
nLength = GetDataToUInt( m_tempBuffer, true );
if( nLength > 0 )
{
// 추출된 정보 저장.
GetPacketData( nLength, szTotoMd5 );
}
// 2.3 totorasa 용 Checksum 값 정보 수신 및 저장
if( GetPacketData( 4 ) == false )
{
LOG( LERR, "szChecksum length receive fail." );
return -1;
}
nLength = GetDataToUInt( m_tempBuffer, true );
if( nLength > 0 )
{
// 추출된 정보 저장.
GetPacketData( nLength, szChecksum );
}
// 2.4 totorasa 용 DNA CHECK Key 값 정보 수신 및 저장
if( GetPacketData( 4 ) == false )
{
LOG( LERR, "szDnaCheckKey length receive fail." );
return -1;
}
nLength = GetDataToUInt( m_tempBuffer, true );
if( nLength > 0 )
{
// 추출된 정보 저장.
GetPacketData( nLength, szDnaCheckKey );
}
return 1;
}
///////////////////////////////////////////////////////////////////////////////////////
/// @brief Packet Header 부분의 수신 처리를 위한 함수.
/// @param timeout [in] 대기시간.
/// @retrun 성공시 true, 오류 발생및 실패시 fasle 반환.
bool CFtsdSocketControl::GetPacketHeader( int timeout )
{
if( IsValidSocket() == false )
return false;
int nRead;
bool isAlivePacket;
do
{
isAlivePacket = false;
// Socket 으로 부터 Packet Header 부분 수신.
// 수신된 정보는 멤버변수에 저장처리.
nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, timeout );
// 오류 발생시
if( nRead <= 0 )
return false;
// STX code 검사.
if( m_packetHeader.stx != HEADER_STX_CODE )
{
LOG( LERR, "Not valid stx code.");
return false;
}
// Data Length 부분 값을 멤버 변수에 저장처리.
m_nPacketDataLen = ntohl( m_packetHeader.data_length );
// Alive Check Packet 인 경우 해당 패킷은 무시처리 후 다시 수신 처리한다.
if( m_packetHeader.type == HEADER_TYPE_REQUEST
&& m_packetHeader.command[0] == COMMON_ALIVE_CHECK
&& m_nPacketDataLen == 0 )
{
isAlivePacket = true;
}
} while( isAlivePacket == true );
return true;
}
/// @brief socket 에서 지정된 크기만큼의 데이터를 읽어 출력변수에 저장처리.
/// @param size [in] read 할 데이터 크기
/// @param value [out] 읽은 데이터를 저장할 string 변수
/// @return On success return true, otherwise return false.
bool CFtsdSocketControl::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, FTSD_DATA_RECV_TIMEOUT );
// 오류 발생시
if( nRead <= 0 )
{
// 신규로 생성된 버퍼인 경우 메모리 해제 처리.
if( bNewBufferCreated == true )
delete [] pBuffer;
return false;
}
// 3. 수신 데이터 저장 처리 - 기존 데이터 뒤에 붙여 준다=> 이게 사용하기 편함.
value.append( (char *)pBuffer, size );
// 신규로 생성된 버퍼인 경우 메모리 해제 처리.
if( bNewBufferCreated == true )
delete [] pBuffer;
return true;
}
/// @brief socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
/// @param size [in] read 할 데이터 크기
/// @return On success return true, otherwise return false.
bool CFtsdSocketControl::GetPacketData( unsigned int size )
{
// 1. 수신할 크기가 임시버퍼보다 큰 경우 오류 반환.
if( size > DEFAULT_SOCKET_TEMP_BUFFER_SIZE )
return false;
// 2. 데이터 수신 처리.
int nRead = ReadNTimeout( m_tempBuffer, size, FTSD_DATA_RECV_TIMEOUT );
// 오류 발생시
if( nRead <= 0 )
return false;
// 3. 정상인 경우는 ReadNTimeout 함수가 무조건 요청 크기만큼 read 처리하므로 정상수신임.
return true;
}
/// @brief 전달받은 데이터를 unsigned int 형으로 변환처리 및 Endian 변환
unsigned int CFtsdSocketControl::GetDataToUInt( BYTE * pValue, bool bConvertEndian )
{
BYTE tempBuffer[4];
unsigned int result;
memcpy(tempBuffer, pValue, 4);
unsigned int * pInt = (unsigned int *)tempBuffer;
// Endian 변환처리.
if( bConvertEndian == true )
{
result = ntohl( *pInt );
}
else
result = *pInt;
return result;
}
unsigned long long CFtsdSocketControl::GetDataToUInt64( BYTE * pValue )
{
unsigned long long * pResult;
BYTE tempBuffer[8];
memcpy(tempBuffer, pValue, 8);
pResult = (unsigned long long *)tempBuffer;
return *pResult;
}