base
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
/***************************************************************************
|
||||
Argument Parser Class (ArgParser.cpp)
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2013/02/13
|
||||
copyright : (C) 2013 Solbox Inc.
|
||||
author : Development 1 Team
|
||||
- 2013/02/13 - 1st dadamin
|
||||
email : dev1@solbox.com
|
||||
version : 3.2.0
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
// CHG 2020-11-09 huibong FreeBSD 12.2 컴파일시 오류 발생 관련 header 추가 (#33297)
|
||||
// - _exit() 사용 컴파일 오류 발생 관련 #include <unistd.h> 구문 추가
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ArgParser.h"
|
||||
|
||||
|
||||
CArgParser::CArgParser(int argc, char** argv)
|
||||
{
|
||||
for (int i=1; i<argc; i++)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
cout << "arg i = " << i << "," << argv[i] << endl;
|
||||
#endif // _DEBUG
|
||||
m_args.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
CArgParser::~CArgParser()
|
||||
{
|
||||
m_args.clear();
|
||||
}
|
||||
|
||||
void CArgParser::dashes2underscores(const char *input, char *output)
|
||||
{
|
||||
char c = 0;
|
||||
char *o = output;
|
||||
const char *i = input;
|
||||
// first two characters are copied as-is
|
||||
*o = *i++;
|
||||
if (*o++ == '\0')
|
||||
return;
|
||||
*o = *i++;
|
||||
if (*o++ == '\0')
|
||||
return;
|
||||
for (; ((c = *i)); ++i)
|
||||
{
|
||||
if (c == '=')
|
||||
{
|
||||
strcpy(o, i);
|
||||
return;
|
||||
}
|
||||
if (c == '-')
|
||||
*o++ = '_';
|
||||
else
|
||||
*o++ = c;
|
||||
}
|
||||
*o++ = '\0';
|
||||
}
|
||||
|
||||
bool CArgParser::parsewitharg(vector<char*>::iterator &i, std::string *ret, va_list ap)
|
||||
{
|
||||
const char *first = *i;
|
||||
char tmp[strlen(first)+1];
|
||||
dashes2underscores(first, tmp);
|
||||
first = tmp;
|
||||
const char *a;
|
||||
int strlen_a;
|
||||
|
||||
// does this argument match any of the possibilities?
|
||||
while (1)
|
||||
{
|
||||
a = va_arg(ap, char*);
|
||||
if (a == NULL)
|
||||
return false;
|
||||
strlen_a = strlen(a);
|
||||
char a2[strlen_a+1];
|
||||
dashes2underscores(a, a2);
|
||||
if (strncmp(a2, first, strlen(a2)) == 0)
|
||||
{
|
||||
if (first[strlen_a] == '=')
|
||||
{
|
||||
*ret = first + strlen_a + 1;
|
||||
i = m_args.erase(i);
|
||||
return true;
|
||||
}
|
||||
else if (first[strlen_a] == '\0')
|
||||
{
|
||||
// find second part (or not)
|
||||
if (i+1 == m_args.end())
|
||||
{
|
||||
cerr << "[error] Option " << *i << " requires an argument." << std::endl;
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
i = m_args.erase(i);
|
||||
*ret = *i;
|
||||
i = m_args.erase(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CArgParser::argparseflag(vector<char*>::iterator &i, ...)
|
||||
{
|
||||
const char *first = *i;
|
||||
char tmp[strlen(first)+1];
|
||||
dashes2underscores(first, tmp);
|
||||
first = tmp;
|
||||
const char *a;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, i);
|
||||
while (1)
|
||||
{
|
||||
a = va_arg(ap, char*);
|
||||
if (a == NULL)
|
||||
{
|
||||
va_end(ap);
|
||||
return false;
|
||||
}
|
||||
|
||||
char a2[strlen(a)+1];
|
||||
dashes2underscores(a, a2);
|
||||
if (strcmp(a2, first) == 0)
|
||||
{
|
||||
i = m_args.erase(i);
|
||||
va_end(ap);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CArgParser::argparsewitharg(vector<char*>::iterator &i, string *ret, ...)
|
||||
{
|
||||
bool r;
|
||||
va_list ap;
|
||||
va_start(ap, ret);
|
||||
r = parsewitharg(i, ret, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool CArgParser::checkvalue(const char *c, string *ret/* = NULL*/)
|
||||
{
|
||||
for (vector<char*>::iterator i = m_args.begin(); i != m_args.end(); ++i)
|
||||
{
|
||||
if(ret)
|
||||
{
|
||||
if(argparsewitharg(i,ret, c, (char*)NULL))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(argparseflag(i,c, (char*)NULL))
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/***************************************************************************
|
||||
Argument Parser Class Header ( ArgParser.h )
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2013/02/13
|
||||
copyright : (C) 2013 Solbox Inc.
|
||||
author : Development 1 Team
|
||||
- 2013/02/13 - 1st dadamin
|
||||
email : dev1@solbox.com
|
||||
version : 3.2.0
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
#ifndef __ARGUMENT_PARSER_H__
|
||||
#define __ARGUMENT_PARSER_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CArgParser
|
||||
{
|
||||
public:
|
||||
CArgParser(int argc, char** argv);
|
||||
~CArgParser();
|
||||
|
||||
bool argparseflag(vector<char*>::iterator &i, ...);
|
||||
bool argparsewitharg(vector<char*>::iterator &i, string *ret, ...);
|
||||
|
||||
bool checkvalue(const char *c, string *ret = NULL);
|
||||
|
||||
inline bool empty() { return m_args.empty(); }
|
||||
|
||||
protected:
|
||||
void dashes2underscores(const char *input, char *output);
|
||||
bool parsewitharg(vector<char*>::iterator &i, std::string *ret, va_list ap);
|
||||
|
||||
private:
|
||||
vector<char*> m_args;
|
||||
};
|
||||
|
||||
#endif // __ARGUMENT_PARSER_H__
|
||||
@@ -0,0 +1,46 @@
|
||||
/***************************************************************************
|
||||
BaseParameter.h
|
||||
-----------------------------------------
|
||||
begin : 2010/11/10
|
||||
copyright : (C) 2010 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
|
||||
CopyRight(C) 2010 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
소스 수정 히스토리
|
||||
|
||||
작성자 작성일 Revision 내용
|
||||
장희준 2011/11/10 627 ADD - 최초 등록
|
||||
***************************************************************************/
|
||||
#ifndef __BASEPARAMETER_H__
|
||||
#define __BASEPARAMETER_H__
|
||||
|
||||
class CBaseParameter
|
||||
{
|
||||
// Attributes
|
||||
private:
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
// Operations
|
||||
private:
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
CBaseParameter() {};
|
||||
virtual ~CBaseParameter() {};
|
||||
|
||||
virtual void Print() {};
|
||||
|
||||
};
|
||||
|
||||
#endif // __BASEPARAMETER_H__
|
||||
|
||||
@@ -0,0 +1,792 @@
|
||||
#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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/***************************************************************************
|
||||
client 에서 cc_collectd 와의 통신을 수행하기 위한 class
|
||||
-----------------------------------------
|
||||
begin : 2014/09/29
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __CC_COLLECTD_CLIENT_SOCKET_H__
|
||||
#define __CC_COLLECTD_CLIENT_SOCKET_H__
|
||||
|
||||
#include "BaseSocket.h"
|
||||
#include "CcCollectdProtocol.h"
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
///< BYTE 타입 정의
|
||||
#ifndef _BYTE_DEFINED
|
||||
#define _BYTE_DEFINED
|
||||
typedef unsigned char BYTE;
|
||||
#endif // _BYTE_DEFINED
|
||||
|
||||
|
||||
#define DEFAULT_SOCKET_TEMP_BUFFER_SIZE 1024 // Socket 관련 data 송수신시 사용할 임시버퍼 크기.
|
||||
|
||||
|
||||
// CCcCollectdClientSocket
|
||||
// cc_collectd 모듈과 통신 수행 관련 Interface 지원 목적을 위한 통신 관련 처리 class
|
||||
class CCcCollectdClientSocket : public CBaseSocket
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// 생성자
|
||||
CCcCollectdClientSocket();
|
||||
|
||||
// 소멸자
|
||||
~CCcCollectdClientSocket();
|
||||
|
||||
|
||||
// 전달받은 Target 으로 Socket 접속을 수행
|
||||
// @param szTarget [in] 접속 대상 Host name 또는 IP
|
||||
// @param nPort [in] 접속 Port
|
||||
// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
|
||||
bool ConnectTarget( const std::string& szTarget, int nPort );
|
||||
|
||||
// cc_collect 로 File 존재 여부 확인
|
||||
// @param strProcessName [in] 프로세스 명, 저장시 프로세스 명에 따른 폴더 생성 후 파일 수신, 저장 처리함.
|
||||
// 생략 가능하지만.. '/' 문자가 포함되서는 안됨.
|
||||
//
|
||||
// @param strFileName [in] 저장 파일명
|
||||
// a.log 같은 단순 형식 사용,
|
||||
// /a/b.log 같은 경로 정보 포함시 오류 발생.
|
||||
//
|
||||
// @param nFileSize [out] 해당 파일이 존재할 경우 파일의 크기
|
||||
// 만약 해당 파일이 존재하지 않을 경우.. 크기는 0
|
||||
//
|
||||
// @param strErrorMessage [out] 수신된 오류 메시지 저장
|
||||
// @return
|
||||
// 성공시 true, 파일 크기는 nFileSize 항목 참고.
|
||||
// 오류 발생시 false, 오류 내역은 strMessage 항목 참고
|
||||
bool CheckFile( const std::string strProcessName, const std::string strFileName
|
||||
, unsigned long long& uFileSize
|
||||
, std::string& strErrorMessage );
|
||||
|
||||
|
||||
// cc_collect 로 File 저장 목적으로 전송
|
||||
// @param strProcessName [in] 프로세스 명, 저장시 프로세스 명에 따른 폴더 생성 후 파일 수신, 저장 처리함.
|
||||
// 생략 가능하지만.. '/' 문자가 포함되서는 안됨.
|
||||
//
|
||||
// @param strFileName [in] 저장 파일명
|
||||
// a.log 같은 단순 형식 사용,
|
||||
// /a/b.log 같은 경로 정보 포함시 오류 발생.
|
||||
//
|
||||
// @param fd [in] 전송할 파일에 대한 descriter
|
||||
// @param nFileSize [in] 전송할 파일의 크기
|
||||
// 0 파일 전송 가능.
|
||||
// @param strMessage [out] 수신된 메시지 저장 (정상, 오류 모두 메시지 수신 가능)
|
||||
// @return
|
||||
// 저장 성공시 true
|
||||
// 실패 발생시 false, 오류 내역은 strMessage 항목 참고
|
||||
bool SendFile( const std::string strProcessName, const std::string strFileName
|
||||
, const int& fd, const unsigned long long& uFileSize
|
||||
, std::string& strMessage );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// cc_collect 로부터 available size 정보를 요청, 결과를 수신처리한다.
|
||||
bool GetAvailableSize( unsigned long long& uSize );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Packet Header 정보를 Log 파일에 Logging 처리
|
||||
void PrintHeaderToLog();
|
||||
|
||||
// socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
|
||||
// @param size [in] read 할 데이터 크기
|
||||
// @return On success return true, otherwise return false.
|
||||
bool GetPacketData( unsigned int size );
|
||||
|
||||
// pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리.
|
||||
unsigned long long GetDataToUInt64( BYTE * pValue, bool bConvertEndian = true );
|
||||
|
||||
// socket 에서 지정된 크기만큼의 데이터를 읽어 출력변수에 저장처리.
|
||||
// @param size [in] read 할 데이터 크기
|
||||
// @param value [out] 읽은 데이터를 저장할 string 변수
|
||||
// @return On success return true, otherwise return false.
|
||||
bool GetPacketData( unsigned int& size, std::string& value );
|
||||
|
||||
// Packet 정보 중 String 정보를 전송하기 위한 함수.
|
||||
bool SendString( const std::string& strData );
|
||||
|
||||
// Linux 5.4 의 경우 unsigned long long 의 byteorder 변환함수 제공 안함.
|
||||
// Linux 6.X, FreeBSD 에서는 be64toh 등의 함수 제공
|
||||
// - Liunx 5.X 장비 지원해야 하므로... 64bit 변환 함수 개발하여 사용.
|
||||
// - 기존 htonl 등의 함수와의 혼동을 피하기 위해 함수명은 C Style 로 구성.
|
||||
uint64_t do_htonll( uint64_t hostlonglong );
|
||||
uint64_t do_ntohll( uint64_t netlonglong );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Packet Header 변수
|
||||
struct CcCollectdPacketHeader m_packetHeader;
|
||||
|
||||
// m_packetHeader 구조체의 크기를 저장하기 위한 상수
|
||||
const int m_nPacketHeaderLen;
|
||||
|
||||
// Packet Header 에 저장된 Data 부분의 길이 정보값.
|
||||
unsigned int m_nPacketDataLen;
|
||||
|
||||
// Packet Data 부분의 수신처리시 임시로 사용할 버퍼.
|
||||
BYTE m_tempBuffer[DEFAULT_SOCKET_TEMP_BUFFER_SIZE];
|
||||
|
||||
};
|
||||
|
||||
#endif /* __CC_COLLECTD_CLIENT_SOCKET_H__ */
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
cc_collectd 통신 관련 protocol header
|
||||
-----------------------------------------
|
||||
begin : 2014/09/25
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef __CC_COLLECTD_PROTOCOL_H__
|
||||
#define __CC_COLLECTD_PROTOCOL_H__
|
||||
|
||||
|
||||
// cc_collectd 에서 사용할 통신 Header 구조체
|
||||
// - 계산상 크기는 16Byte 이지만...
|
||||
// - 통신상 sizeof() : 20Byte ( 64Bit OS )
|
||||
struct CcCollectdPacketHeader {
|
||||
|
||||
char stx; // Packet 유효성 관리 코드
|
||||
char type; // Request or Response 여부 ( 0x00: Request, 0x01: Response )
|
||||
char command[4]; // Command Code ( 4 Byte) : 0th client-cc_collectd 간 사용, 그외는 미사용.
|
||||
char result[4]; // Result Code ( 4 Byte )
|
||||
unsigned int data_length; // Packet Data 부분의 길이값 ( Network Byte Order 사용)
|
||||
char extend_code[2]; // 확장 및 Padding bits ( 2 Byte )
|
||||
};
|
||||
|
||||
// Packet Header stx 코드
|
||||
#define HEADER_STX_CODE 0x04
|
||||
|
||||
// Packet Header type 구분코드
|
||||
#define HEADER_TYPE_REQUEST 0x00
|
||||
#define HEADER_TYPE_RESPONSE 0x01
|
||||
|
||||
|
||||
// Packet command 공통.
|
||||
#define COMMON_ALIVE_CHECK 0x7F
|
||||
|
||||
// Packet command
|
||||
// client <-> cc_collect 통신 (command 0th byte 만 사용)
|
||||
#define REQUEST_NOT_VALID 0x00 // 유효하지 않은 요청.
|
||||
#define REQUEST_AVAILABLE_SIZE 0x01 // Client 에서 전송 가능한 Available Size 요청
|
||||
#define REQUEST_FILE_SAVE 0x02 // Client 에서 저장 목적의 File 전송
|
||||
#define REQUEST_FILE_CHECK 0x03 // Client 에서 File 존재 여부 확인 요청
|
||||
|
||||
|
||||
// Packet Result
|
||||
// => type이 Response 인 경우에만 세팅됨.( 0th Byte 만 사용시 )
|
||||
#define HEADER_RESULT_SUCCESS 0x00
|
||||
#define HEADER_RESULT_ERROR 0x01
|
||||
|
||||
|
||||
// 기타 정보
|
||||
#define LENGTH_FIELD_SIZE 4 // 가변데이터 형식 사용시 Length 필드의 메모리 크기 (unsigned int)
|
||||
|
||||
|
||||
#endif /* __CC_COLLECTD_PROTOCOL_H__ */
|
||||
@@ -0,0 +1,230 @@
|
||||
/***************************************************************************
|
||||
Config Class (DaemonConfigs.cpp)
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/04/28
|
||||
copyright : (C) 2013 Solbox Inc.
|
||||
author : Development Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.5
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
#include "DaemonConfigs.h"
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include "Config.h"
|
||||
|
||||
CDeamonConfig *CDeamonConfig::m_pInstance = NULL;
|
||||
|
||||
CCommonConfig::CCommonConfig( string szFilename, string szProgramName )
|
||||
: m_szConfigFile(szFilename), m_szProgramName(szProgramName)
|
||||
{
|
||||
}
|
||||
|
||||
CCommonConfig::~CCommonConfig()
|
||||
{
|
||||
}
|
||||
|
||||
bool CCommonConfig::LoadConf()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
cout << "CCommonConfig::LoadConf() =>" << endl;
|
||||
#endif // _DEBUG
|
||||
string szValue;
|
||||
|
||||
// Config 처리를 위한 객체 생성
|
||||
Config conf;
|
||||
|
||||
// Config File open
|
||||
if( conf.Open( m_szConfigFile ) == false )
|
||||
{
|
||||
m_szErrMessage = "Config file open failed.[" + m_szConfigFile + "]";
|
||||
return false;
|
||||
}
|
||||
|
||||
// log path
|
||||
if( conf.GetConfig( "COMMON", "DEFAULT_LOG_DIR", szValue ) )
|
||||
{
|
||||
m_szAppLogRoot = szValue;
|
||||
}
|
||||
|
||||
// log level
|
||||
if( conf.GetConfig( "COMMON", "LOG_LEVEL", szValue ) )
|
||||
{
|
||||
m_nLogLevel = atoi( szValue.c_str() );
|
||||
}
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
PrintValue();
|
||||
#endif // _DEBUG
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCommonConfig::CheckValue()
|
||||
{
|
||||
if(m_szAppLogRoot.empty())
|
||||
{
|
||||
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->DEFAULT_LOG_DIR";
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_nLogLevel <= 0)
|
||||
{
|
||||
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->LOG_LEVEL";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCommonConfig::PrintValue()
|
||||
{
|
||||
cout << "Log Value : " << m_szAppLogRoot << "," << m_nLogLevel << endl;
|
||||
}
|
||||
|
||||
CDeamonConfig::CDeamonConfig(string szFilename, string szProgramName)
|
||||
: CCommonConfig(szFilename, szProgramName)
|
||||
{
|
||||
m_nLogServerPort = 0;
|
||||
}
|
||||
|
||||
CDeamonConfig::~CDeamonConfig()
|
||||
{
|
||||
}
|
||||
|
||||
bool CDeamonConfig::LoadConf()
|
||||
{
|
||||
CCommonConfig::LoadConf();
|
||||
|
||||
std::vector< std::string > vecValue;
|
||||
#ifdef _DEBUG
|
||||
cout << "CMyConfig::LoadConf() =>" << endl;
|
||||
#endif // _DEBUG
|
||||
string szValue;
|
||||
|
||||
// Config 처리를 위한 객체 생성
|
||||
Config conf;
|
||||
|
||||
// Config File open
|
||||
if( conf.Open( m_szConfigFile ) == false )
|
||||
{
|
||||
m_szErrMessage = "Config file open failed.[" + m_szConfigFile + "]";
|
||||
return false;
|
||||
}
|
||||
|
||||
// default log
|
||||
szValue.clear();
|
||||
if( conf.GetConfig( m_szProgramName, "DEFAULT_LOG_DIR", szValue ) )
|
||||
{
|
||||
m_szAppLogRoot = szValue;
|
||||
}
|
||||
|
||||
// log level
|
||||
szValue.clear();
|
||||
if( conf.GetConfig( m_szProgramName, "LOG_LEVEL", szValue ) )
|
||||
{
|
||||
m_nLogLevel = atoi( szValue.c_str() );
|
||||
}
|
||||
|
||||
// log backup server host
|
||||
if( conf.GetConfig( m_szProgramName, "LOG_SERVER_HOST", szValue ) == false )
|
||||
{
|
||||
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->LOG_SERVER_HOST";
|
||||
return false;
|
||||
}
|
||||
m_szLogServer = szValue;
|
||||
szValue.clear();
|
||||
|
||||
// log backup server host
|
||||
if( conf.GetConfig( m_szProgramName, "LOG_SERVER_PORT", szValue ) == false )
|
||||
{
|
||||
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->LOG_SERVER_PORT";
|
||||
return false;
|
||||
}
|
||||
m_nLogServerPort = atoi( szValue.c_str() );;
|
||||
szValue.clear();
|
||||
|
||||
// application logfile retention period(unit : day)
|
||||
if( conf.GetConfig( m_szProgramName, "APP_LOG_PERIOD", szValue ) == false )
|
||||
{
|
||||
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->APP_LOG_PERIOD";
|
||||
return false;
|
||||
}
|
||||
m_nAppLogPeriod = atoi( szValue.c_str() );;
|
||||
szValue.clear();
|
||||
|
||||
// log file searching target directory list
|
||||
if( conf.GetConfig( m_szProgramName, "SEARCHING_DIR_LIST", vecValue ) == false )
|
||||
{
|
||||
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->SEARCHING_DIR_LIST";
|
||||
return false;
|
||||
}
|
||||
m_vecSearchingDirList = vecValue;
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
PrintValue();
|
||||
#endif // _DEBUG
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDeamonConfig::CheckValue()
|
||||
{
|
||||
if (CCommonConfig::CheckValue() == false)
|
||||
return false;
|
||||
|
||||
|
||||
if(m_szLogServer.empty())
|
||||
{
|
||||
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->LOG_SERVER_HOST";
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_nLogServerPort <= 0)
|
||||
{
|
||||
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->LOG_SERVER_PORT";
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_nAppLogPeriod <= 0)
|
||||
{
|
||||
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->APP_LOG_PERIOD";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDeamonConfig::PrintValue()
|
||||
{
|
||||
CCommonConfig::PrintValue();
|
||||
}
|
||||
|
||||
bool CDeamonConfig::Init(string szProgramName, string szFilename)
|
||||
{
|
||||
if (CDeamonConfig::m_pInstance == NULL)
|
||||
{
|
||||
CDeamonConfig::m_pInstance = new CDeamonConfig(szFilename, szProgramName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDeamonConfig::Exit()
|
||||
{
|
||||
if (CDeamonConfig::m_pInstance != NULL)
|
||||
{
|
||||
delete CDeamonConfig::m_pInstance;
|
||||
CDeamonConfig::m_pInstance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CDeamonConfig* CDeamonConfig::GetInstance()
|
||||
{
|
||||
return CDeamonConfig::m_pInstance;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/***************************************************************************
|
||||
Config Class Header ( DaemonConfigs.h )
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/04/28
|
||||
copyright : (C) 2013 Solbox Inc.
|
||||
author : Development Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.5.0
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
#ifndef __DAEMON_CONFIGS_H__
|
||||
#define __DAEMON_CONFIGS_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class CCommonConfig
|
||||
{
|
||||
public:
|
||||
CCommonConfig( string szFilename, string szProgramName );
|
||||
virtual ~CCommonConfig();
|
||||
|
||||
bool LoadConf();
|
||||
bool CheckValue();
|
||||
|
||||
void PrintValue();
|
||||
|
||||
inline const char * GetErrMessage() { return m_szErrMessage.c_str(); }
|
||||
|
||||
inline const char * GetConfigFile() { return m_szConfigFile.c_str(); }
|
||||
inline const char * GetAppLogRoot() { return m_szAppLogRoot.c_str(); }
|
||||
inline int GetAppLogLevel() { return m_nLogLevel; }
|
||||
|
||||
protected:
|
||||
string m_szConfigFile;
|
||||
string m_szProgramName;
|
||||
|
||||
string m_szErrMessage;
|
||||
|
||||
// log
|
||||
string m_szAppLogRoot;
|
||||
int m_nLogLevel;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
class CDeamonConfig : public CCommonConfig
|
||||
{
|
||||
public:
|
||||
static bool Init( string szProgramName, string szFilename );
|
||||
static void Exit();
|
||||
static CDeamonConfig* GetInstance();
|
||||
|
||||
inline const char * GetLogServer() {return m_szLogServer.c_str(); }
|
||||
inline int GetLogServerPort() {return m_nLogServerPort; }
|
||||
inline int GetAppLogPeriod() {return m_nAppLogPeriod; }
|
||||
inline std::vector<std::string> GetSearchingDirList() {return m_vecSearchingDirList; }
|
||||
|
||||
private:
|
||||
static CDeamonConfig* m_pInstance;
|
||||
|
||||
public:
|
||||
bool LoadConf();
|
||||
bool CheckValue();
|
||||
|
||||
void PrintValue();
|
||||
|
||||
protected:
|
||||
CDeamonConfig(string szFilename, string szProgramName);
|
||||
virtual ~CDeamonConfig();
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private:
|
||||
string m_szLogServer;
|
||||
int m_nLogServerPort;
|
||||
int m_nAppLogPeriod;
|
||||
|
||||
std::vector< std::string > m_vecSearchingDirList;
|
||||
};
|
||||
|
||||
#endif // __RC_MNGD_CONFIG_H__
|
||||
@@ -0,0 +1,140 @@
|
||||
/***************************************************************************
|
||||
HostInfo.cpp
|
||||
-----------------------------------------
|
||||
begin : 2011/10/18
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/resource.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <queue>
|
||||
|
||||
#include "HostInfo.h"
|
||||
#include "String.h"
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
#define HOSTNAME_SIZE 256
|
||||
|
||||
using namespace std;
|
||||
|
||||
CHostInfo::CHostInfo()
|
||||
{
|
||||
m_szHostname = "";
|
||||
m_nHostNumber = -1;
|
||||
|
||||
MakeHostInfos();
|
||||
}
|
||||
|
||||
CHostInfo::~CHostInfo()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CHostInfo::MakeHostInfos()
|
||||
{
|
||||
MakeHostname();
|
||||
MakeShortHostname();
|
||||
MakeHostNumber();
|
||||
}
|
||||
|
||||
void CHostInfo::MakeHostname()
|
||||
{
|
||||
char hostname[HOSTNAME_SIZE];
|
||||
memset( hostname, 0x00, HOSTNAME_SIZE );
|
||||
|
||||
/// 호스트 이름 얻기.
|
||||
if( gethostname( hostname, HOSTNAME_SIZE - 1 ) != 0 )
|
||||
{
|
||||
LOG( LERR, "can't get hostname. errno=%d, err=%s", errno, strerror(errno) );
|
||||
return;
|
||||
}
|
||||
|
||||
/// 호스트 이름 설정.
|
||||
m_szHostname = hostname;
|
||||
}
|
||||
|
||||
void CHostInfo::MakeShortHostname()
|
||||
{
|
||||
string shortHostName = "";
|
||||
|
||||
/// bd-01-fhs001.ktsh[x-cdn].co.kr 형식에서 '.'을 기준으로 토큰화 시킴.
|
||||
vector<string> tokens = CString::Tokenize( m_szHostname, "." );
|
||||
if( tokens.size() == 0 )
|
||||
{
|
||||
LOG( LERR, "invalid hostname(%s)", m_szHostname.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
/// bd-01-fhs001.ktsh[x-cdn].co.kr 형식에서 bd-01-fhs001만 추출.
|
||||
m_szShortHostname = tokens[0];
|
||||
}
|
||||
|
||||
void CHostInfo::MakeHostNumber()
|
||||
{
|
||||
string hostnumber = "";
|
||||
|
||||
/// bd-01-fhs001.ktsh[x-cdn].co.kr 형식에서 '.'을 기준으로 토큰화 시킴.
|
||||
vector<string> tokens = CString::Tokenize( m_szHostname, "." );
|
||||
if( tokens.size() == 0 )
|
||||
{
|
||||
LOG( LERR, "invalid hostname(%s)", m_szHostname.c_str() );
|
||||
return;
|
||||
}
|
||||
/// bd-01-fhs001.ktsh[x-cdn].co.kr 형식에서 bd-01-fhs001만 추출.
|
||||
hostnumber = tokens[0];
|
||||
|
||||
/// bd-01-fhs001에서 '-'을 기준으로 토큰화 시킴.
|
||||
tokens.clear();
|
||||
tokens = CString::Tokenize( hostnumber, "-" );
|
||||
if( tokens.size() == 0 )
|
||||
{
|
||||
LOG( LERR, "invalid hostname(%s)", m_szHostname.c_str() );
|
||||
return;
|
||||
}
|
||||
/// bd-01-fhs001에서 fhs001만 추출.
|
||||
hostnumber = tokens[ tokens.size() - 1 ];
|
||||
|
||||
/// fhs001에서 fhs 제거
|
||||
hostnumber = CString::Replace( hostnumber, "fhs", "" );
|
||||
|
||||
/// 혹시 있을지 모르는 공백 제거
|
||||
hostnumber = CString::Trim( hostnumber );
|
||||
if( hostnumber.empty() == true )
|
||||
{
|
||||
LOG( LERR, "invalid hostname(%s)", m_szHostname.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
m_nHostNumber = atoi( hostnumber.c_str() );
|
||||
|
||||
LOG( LDEV, "host info: hostname(%s), hostnumber(%d)", m_szHostname.c_str(), m_nHostNumber );
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/***************************************************************************
|
||||
HostInfo.h
|
||||
-----------------------------------------
|
||||
begin : 2011/10/18
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
소스 수정 히스토리
|
||||
|
||||
작성자 작성일 Revision 내용
|
||||
장희준 2011/10/18 ? ADD - 최초 등록
|
||||
***************************************************************************/
|
||||
#ifndef __HOSTINFO_H__
|
||||
#define __HOSTINFO_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
///@brief 양방향 FHS 장비의 호스트 이름과 호스트명에 있는 호스트 번호를 얻는 클래스.
|
||||
/// 양방향 FHS 장비의 호스트 이름 형식은 'bd-01-fhs001.ktsh[x-cdn].co.kr'으로 되어 있다.
|
||||
/// 호스트 이름 : bd-01-fhs001.ktsh[x-cdn].co.kr
|
||||
/// 호스트 번호 : 001
|
||||
class CHostInfo
|
||||
{
|
||||
// Attributes
|
||||
private:
|
||||
///@brief 호스트 이름 저장.
|
||||
/// 형식 : bd-01-fhs001.ktsh.co.kr
|
||||
std::string m_szHostname;
|
||||
|
||||
///@brief 호스트 이름 저장.
|
||||
/// 형식 : bd-01-fhs001
|
||||
std::string m_szShortHostname;
|
||||
|
||||
///@brief 호스트 번호 저장.
|
||||
int m_nHostNumber;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
// Operations
|
||||
private:
|
||||
///@brief 호스트 정보를 만드는 함수로 아래의 MakeXXX() 함수들을 호출한다.
|
||||
///@param none.
|
||||
///@return none.
|
||||
void MakeHostInfos();
|
||||
|
||||
///@brief 호스트 이름을 만드는 함수.
|
||||
///@param none.
|
||||
///@return none.
|
||||
void MakeHostname();
|
||||
|
||||
///@brief 호스트 이름을 만드는 함수.
|
||||
///@param none.
|
||||
///@return none.
|
||||
void MakeShortHostname();
|
||||
|
||||
|
||||
///@brief 호스트 번호를 만드는 함수.
|
||||
///@param none.
|
||||
///@return none.
|
||||
void MakeHostNumber();
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
///@brief 생성자.
|
||||
/// 호스트 정보를 생성한다.
|
||||
CHostInfo();
|
||||
|
||||
///@brief 소멸자.
|
||||
virtual ~CHostInfo();
|
||||
|
||||
///@brief 호스트 이름을 얻는 함수.
|
||||
///@param none.
|
||||
///@return 저장된 호스트 이름을 반환한다.
|
||||
inline std::string GetHostname() { return m_szHostname; };
|
||||
|
||||
///@brief 호스트 이름을 얻는 함수.
|
||||
///@param none.
|
||||
///@return 저장된 호스트 이름을 반환한다.
|
||||
inline std::string GetShortHostname() { return m_szShortHostname; };
|
||||
|
||||
///@brief 호스트 번호를 얻는 함수.
|
||||
///@param none.
|
||||
///@return 저장된 호스트 번호를 반환한다.
|
||||
inline int GetHostNumber() { return m_nHostNumber; };
|
||||
};
|
||||
|
||||
#endif // __HOSTINFO_H__
|
||||
@@ -0,0 +1,79 @@
|
||||
/***************************************************************************
|
||||
Inode.cpp
|
||||
-----------------------------------------
|
||||
begin : 2011/10/06
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
#include "Inode.h"
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
CInode::CInode()
|
||||
{
|
||||
m_szFilename = "";
|
||||
m_nDeviceId = 0;
|
||||
m_nInum = 0;
|
||||
m_nMode = 0;
|
||||
m_nSize = 0;
|
||||
m_nATime = 0;
|
||||
m_nMTime = 0;
|
||||
m_nCTime = 0;
|
||||
}
|
||||
|
||||
CInode::~CInode()
|
||||
{
|
||||
}
|
||||
|
||||
void CInode::Print( int logLevel )
|
||||
{
|
||||
_LOG_( logLevel, "Print info of %s.", m_szFilename.c_str() );
|
||||
_LOG_( logLevel, " filename = %s", m_szFilename.c_str() );
|
||||
_LOG_( logLevel, " device id = %lu", m_nDeviceId );
|
||||
_LOG_( logLevel, " inode num = %lld", m_nInum );
|
||||
_LOG_( logLevel, " mode = %d", m_nMode );
|
||||
_LOG_( logLevel, " size = %lld", m_nSize );
|
||||
_LOG_( logLevel, " ATime = %jd", m_nATime );
|
||||
_LOG_( logLevel, " MTime = %jd", m_nMTime );
|
||||
_LOG_( logLevel, " CTime = %jd", m_nCTime );
|
||||
}
|
||||
|
||||
bool CInode::LoadInfo( std::string path )
|
||||
{
|
||||
if( path.length() == 0 )
|
||||
{
|
||||
LOG( LWAR, "can't get inode because input parameter filename is empty." );
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat statbuf;
|
||||
|
||||
if( stat( path.c_str(), &statbuf ) == -1 )
|
||||
{
|
||||
LOG( LWAR, "can't get inode because stat(%s) was failed. errno:%d, errmsg:%s", path.c_str(), errno, strerror(errno) );
|
||||
return false;
|
||||
}
|
||||
|
||||
SetFilename( path );
|
||||
SetDeviceId( statbuf.st_dev );
|
||||
SetInum( statbuf.st_ino );
|
||||
SetFileMode( statbuf.st_mode );
|
||||
SetSize( statbuf.st_size );
|
||||
SetATime( statbuf.st_atime );
|
||||
SetMTime( statbuf.st_mtime );
|
||||
SetCTime( statbuf.st_ctime );
|
||||
|
||||
Print(LDEV);
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/***************************************************************************
|
||||
Inode.h
|
||||
-----------------------------------------
|
||||
begin : 2011/10/06
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
소스 수정 히스토리
|
||||
|
||||
작성자 작성일 Revision 내용
|
||||
장희준 2011/10/06 ? ADD - 최초 등록
|
||||
***************************************************************************/
|
||||
#ifndef __INODE_H__
|
||||
#define __INODE_H__
|
||||
|
||||
#include "Logger.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
|
||||
///@brief stat 함수로 얻는 struct stat 정보를 wrapping 하는 클래스.
|
||||
class CInode
|
||||
{
|
||||
// Attributes
|
||||
private:
|
||||
///@breif 파일명 저장
|
||||
std::string m_szFilename;
|
||||
|
||||
///@brief 디바이스 id 저장
|
||||
unsigned long m_nDeviceId;
|
||||
|
||||
///@brief inode 저장.
|
||||
unsigned long long m_nInum;
|
||||
|
||||
///@brief protection 모드 저장
|
||||
mode_t m_nMode;
|
||||
|
||||
///@brief 파일 크기(bytes)
|
||||
unsigned long long m_nSize;
|
||||
|
||||
///@brief 마지막 접근 시간 - tiem of last access
|
||||
time_t m_nATime;
|
||||
|
||||
///@brief 마지막 수정 시간 - time of last modification
|
||||
time_t m_nMTime;
|
||||
|
||||
///@breif 마지막 변경 시간 - time of last change
|
||||
time_t m_nCTime;
|
||||
|
||||
///@brief CInode을 테스트하는 클래스가 private에 접근할 수 있도록 하기 위함.
|
||||
friend class CInodeTest;
|
||||
friend class CLogFileCleanerTest;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
// Operations
|
||||
private:
|
||||
|
||||
protected:
|
||||
/// 정보를 설정 함수들.
|
||||
inline void SetFilename( std::string filename ) { m_szFilename = filename; };
|
||||
inline void SetDeviceId( unsigned long deviceid ) { m_nDeviceId = deviceid; };
|
||||
inline void SetInum( unsigned long long inum ) { m_nInum = inum; };
|
||||
inline void SetFileMode( mode_t mode ) { m_nMode = mode; };
|
||||
inline void SetSize( unsigned long long size ) { m_nSize = size; };
|
||||
inline void SetATime( time_t atime ) { m_nATime = atime; };
|
||||
inline void SetMTime( time_t mtime ) { m_nATime = mtime; };
|
||||
inline void SetCTime( time_t ctime ) { m_nATime = ctime; };
|
||||
|
||||
public:
|
||||
CInode();
|
||||
virtual ~CInode();
|
||||
|
||||
///@brief 파일의 정보를 구해서 설정하는 함수.
|
||||
///@param path [in] 파일의 절대 경로.
|
||||
///@return 파일의 정보를 구해서 설정하면 true, 그렇지 못 하면 false.
|
||||
bool LoadInfo( std::string path );
|
||||
|
||||
///@brief 파일의 정보를 출력하는 함수.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@return none.
|
||||
void Print( int logLevel = LDBG );
|
||||
|
||||
/// 정보를 얻는 함수들.
|
||||
inline std::string GetFilename() { return m_szFilename; };
|
||||
inline unsigned long GetDeviceId() { return m_nDeviceId; };
|
||||
inline unsigned long long GetInum() { return m_nInum; };
|
||||
inline mode_t GetFileMode() { return m_nMode; };
|
||||
inline unsigned long long GetSize() { return m_nSize; };
|
||||
inline time_t GetATime() { return m_nATime; };
|
||||
inline time_t GetMTime() { return m_nMTime; };
|
||||
inline time_t GetCTime() { return m_nCTime; };
|
||||
};
|
||||
|
||||
#endif // __INODE_H__
|
||||
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/***************************************************************************
|
||||
LogFileCleaner.cpp
|
||||
-----------------------------------------
|
||||
begin : 2011/11/09
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
#include "LogFileCleaner.h"
|
||||
#include "DaemonConfigs.h"
|
||||
#include "Logger.h"
|
||||
#include "String.h"
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SECONDS_CORRESPOND_TO_ONE_DAY 86400
|
||||
|
||||
//#define __HJ_TEST__
|
||||
|
||||
#define ACCESS_LOG_PRE_NAME "access_log_"
|
||||
#define ERROR_LOG_PRE_NAME "error_log_"
|
||||
|
||||
using namespace std;
|
||||
|
||||
CLogFileCleaner::CLogFileCleaner() : CLogFileProcessThread( "CLogFileCleaner" )
|
||||
{
|
||||
}
|
||||
|
||||
CLogFileCleaner::~CLogFileCleaner()
|
||||
{
|
||||
}
|
||||
|
||||
bool CLogFileCleaner::DoWork()
|
||||
{
|
||||
/// 로그 보존기간 설정값 가지고 오기.
|
||||
unsigned int logPeriod = CDeamonConfig::GetInstance()->GetAppLogPeriod();
|
||||
|
||||
std::vector< std::string > vecSearchingDirList = CDeamonConfig::GetInstance()->GetSearchingDirList();
|
||||
std::vector< std::string >::iterator it;
|
||||
|
||||
for (it=vecSearchingDirList.begin(); it<vecSearchingDirList.end(); it++)
|
||||
{
|
||||
std::string szSearchingDir = *it;
|
||||
|
||||
// return은 bool type이지만.. 여러장비에서 구동하기위해 return값을 무시하기로한다.
|
||||
UnlinkFiles( szSearchingDir, logPeriod );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogFileCleaner::UnlinkFiles( std::string path, unsigned int period )
|
||||
{
|
||||
|
||||
LOG( LDBG, "Unlink Request dir is [%s].", path.c_str() );
|
||||
|
||||
/// 디렉토리 open.
|
||||
DIR* pDir = opendir( path.c_str() );
|
||||
|
||||
if( pDir == NULL )
|
||||
{
|
||||
//_LOG( LINF, "can't unlink files because opendir(%s) is failed.", path.c_str() );
|
||||
_LOG( LINF, "[UNLINK] directory [%s] not exist.", path.c_str() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string fullname;
|
||||
struct dirent* pDirEnt;
|
||||
|
||||
/// 디렉토리 내의 파일들을 검색.
|
||||
while( ( pDirEnt = readdir( pDir ) ) != NULL )
|
||||
{
|
||||
if( pDirEnt->d_name[0] == '.' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/// 파일의 전체 경로 만들기.
|
||||
fullname = path + "/" + string( pDirEnt->d_name );
|
||||
|
||||
if( IsDirectory( fullname ) == true )
|
||||
{
|
||||
/// 디렉토리이면 재귀 호출.
|
||||
UnlinkFiles( fullname, period );
|
||||
}
|
||||
else
|
||||
{
|
||||
/// 로그 파일이 아니면 skip.
|
||||
if( IsLogFile( fullname ) == false )
|
||||
{
|
||||
LOG( LDEV, "%s is not log file.", fullname.c_str() );
|
||||
continue;
|
||||
}
|
||||
|
||||
/// 파일이면 CInode 정보를 가지고 온다.
|
||||
CInode inode;
|
||||
if( inode.LoadInfo( fullname ) == false )
|
||||
{
|
||||
/// 파일 정보를 가지고 오지 못 하면 skip.
|
||||
LOG( LWAR, "inode info loading is failed. file=%s", fullname.c_str() );
|
||||
continue;
|
||||
}
|
||||
|
||||
/// 로그 파일 보존기간이 경과 했으면 삭제.
|
||||
if( IsPassedPeriod( inode, period ) == true )
|
||||
{
|
||||
LOG( LDBG, "%s is deleted.", fullname.c_str() );
|
||||
Unlink( inode.GetFilename() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 디렉토리 close.
|
||||
closedir( pDir );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogFileCleaner::IsPassedPeriod( CInode& inode, unsigned int period )
|
||||
{
|
||||
|
||||
|
||||
/// period는 일 단위이기 때문에 초 단위로 환산한다.
|
||||
time_t periodBySecond = period * SECONDS_CORRESPOND_TO_ONE_DAY;
|
||||
|
||||
#ifdef __HJ_TEST__
|
||||
/// 테스트를 위해서 periodBySecond을 5초로 한다.
|
||||
periodBySecond = 5;
|
||||
#endif
|
||||
|
||||
|
||||
time_t current = time( NULL );;
|
||||
|
||||
LOG( LDEV, "current = %jd, inode.GetATime() = %jd, periodBySecond = %jd, current - inode.GetATime() = %jd",
|
||||
current, inode.GetATime(), periodBySecond, current - inode.GetATime() );
|
||||
|
||||
if( current < inode.GetATime() )
|
||||
{
|
||||
LOG( LWAR, "current timestamp is less than the create time of %s.", inode.GetFilename().c_str() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 보존 기간 확인.
|
||||
if( ( current - inode.GetATime() ) < periodBySecond )
|
||||
{
|
||||
/// 보존 기간이 경과 되지 않았으면
|
||||
LOG( LDEV, "%s is not passed period(%jd sec).", inode.GetFilename().c_str(), periodBySecond );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 파일의 확장자가 log이면 true 반환, 그렇지 않으면 false 반환.
|
||||
bool CLogFileCleaner::IsLogFile( std::string filename )
|
||||
{
|
||||
int n1 = filename.find(ACCESS_LOG_PRE_NAME);
|
||||
int n2 = filename.find(ERROR_LOG_PRE_NAME);
|
||||
LOG( LDBG, "%s, %d, %d ", filename.c_str(), n1, n2 );
|
||||
|
||||
//!! 아파치 로그인지를 확인한다.
|
||||
//if( filename.find(ACCESS_LOG_PRE_NAME) >= 0 || filename.find(ERROR_LOG_PRE_NAME) >=0 )
|
||||
if( n1 >= 0 || n2 >=0 )
|
||||
{
|
||||
LOG( LDBG, "%s is apache log file.", filename.c_str() );
|
||||
return true;
|
||||
}
|
||||
|
||||
/// '.'을 구분자로한 토큰을 벡터에 넣는다.
|
||||
vector<string> tokens = CString::Tokenize( filename, "." );
|
||||
|
||||
/// 벡터의 크기가 1이면 '.'이 없다는 말이다. 즉, 로그 파일이 아니다.
|
||||
if( tokens.size() == 1 )
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 파일 이름에서 확장자를 가지고 온다.
|
||||
string extension = tokens[ tokens.size() - 1 ];
|
||||
|
||||
/// 확장자 비교.
|
||||
if( extension.compare( "log" ) != 0 )
|
||||
{
|
||||
/// 확장자가 'log'가 아님.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/***************************************************************************
|
||||
LogFileCleaner.h
|
||||
-----------------------------------------
|
||||
begin : 2011/11/09
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
소스 수정 히스토리
|
||||
|
||||
작성자 작성일 Revision 내용
|
||||
장희준 2011/11/09 ? ADD - 최초 등록
|
||||
***************************************************************************/
|
||||
#ifndef __LOGFILECLEANER_H__
|
||||
#define __LOGFILECLEANER_H__
|
||||
|
||||
#include "LogFileProcessThread.h"
|
||||
#include "Inode.h"
|
||||
|
||||
///@brief 로그 디렉토리에서 일정 시간이 지난 로그 파일 삭제
|
||||
class CLogFileCleaner : public CLogFileProcessThread
|
||||
{
|
||||
// Attributes
|
||||
private:
|
||||
///@brief CLogFileCleaner을 테스트하는 클래스가 private에 접근할 수 있도록 하기 위함.
|
||||
// friend class CLogFileCleanerTest;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
|
||||
// Operations
|
||||
private:
|
||||
///@brief 경로 path와 path의 하위 디렉토리에서 보존기간이 지난 로그 파일을 검색해서 삭제하는 함수.
|
||||
///@param path [in] 최상위 로그 디렉토리 경로.
|
||||
///@param period [in] 로그 파일 보존 기간.
|
||||
///@return 경로 path가 존재하지 않거나 디렉토리가 아니면 false, 반환 그렇지 않으면 true 반환.
|
||||
bool UnlinkFiles( std::string path, unsigned int period );
|
||||
|
||||
///@brief 로그 파일의 보존 기간이 초과했는지 여부를 판단하는 함수.
|
||||
///@param inode [in] 파일의 inode 정보
|
||||
///@param period [in] 보존 기간
|
||||
///@return 파일의 마지막 접근 시간이 period를 초과했으면 true, 그렇지 않으면 false.
|
||||
bool IsPassedPeriod( CInode& inode, unsigned int period );
|
||||
|
||||
///@brief 파일이 로그 파일인지 여부를 판단하는 함수.
|
||||
/// 파일의 확장자가 ".log"이면 로그 파일로 판단한다.
|
||||
///@param filename [in] 파일명
|
||||
///@return filename이 디렉토리이거나 파일의 확장자가 ".log"이 아니면 false, 그렇지 않으면 true 반환.
|
||||
bool IsLogFile( std::string filename );
|
||||
|
||||
protected:
|
||||
///@brief 로그 파일을 삭제하는 메인 함수.
|
||||
/// 보존 기간이 지난 로그 파일들을 삭제한다.
|
||||
///@param none.
|
||||
///@return m_szLogRoot이 유효한 디렉토리이면 true 반환, 그렇지 않으면 false 반환.
|
||||
bool DoWork();
|
||||
|
||||
public:
|
||||
///@brief 생성자.
|
||||
CLogFileCleaner();
|
||||
|
||||
///@brief 소멸자.
|
||||
virtual ~CLogFileCleaner();
|
||||
|
||||
///@brief 스레드가 시작하기 전에 초기화 작업을 하는 함수로 CProcessStatus의 초기화 여부와
|
||||
/// 최상위 로그 디렉토리의 유효성을 확인한다.
|
||||
/// CBaseThread로부터 상속 받음.
|
||||
///@param none.
|
||||
///@return CProcessStatus가 초기화 되지 않았거나 m_szLogRoot이 유효한 디렉토리가 아니면 false 반환,
|
||||
/// 그렇지 않으면 true 반환.
|
||||
//bool ThreadInit();
|
||||
};
|
||||
|
||||
#endif // __LOGFILECLEANER_H__
|
||||
@@ -0,0 +1,359 @@
|
||||
|
||||
// CHG 2020-11-09 huibong FreeBSD 12.2 컴파일시 오류 발생 관련 header 추가 (#33297)
|
||||
// - unlink(), sleep() 사용 컴파일 오류 발생 관련 #include <unistd.h> 구문 추가
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "LogFileProcessThread.h"
|
||||
#include "HostInfo.h"
|
||||
|
||||
/// 테스트를 위해 값을 4,7에서 0, 23로 변경했음.
|
||||
#define TIME_SCOPE_FIRST_BEGIN 0
|
||||
#define TIME_SCOPE_FIRST_END 23
|
||||
#define TIME_SCOPE_BEGIN 4
|
||||
#define TIME_SCOPE_END 7
|
||||
|
||||
using namespace std;
|
||||
|
||||
CLogFileProcessThread::CLogFileProcessThread(string myname)
|
||||
{
|
||||
// 멤버 변수 초기화
|
||||
m_threadHandle = 0;
|
||||
|
||||
m_szMyName = myname;
|
||||
m_nToday = GetToday();
|
||||
m_TimeScope.begin = TIME_SCOPE_FIRST_BEGIN;
|
||||
m_TimeScope.end = TIME_SCOPE_FIRST_END;
|
||||
SetStatus( LFP_READY );
|
||||
bFirst = true;
|
||||
}
|
||||
|
||||
CLogFileProcessThread::~CLogFileProcessThread()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CLogFileProcessThread::ThreadInit(const sig_atomic_t *sighandle)
|
||||
{
|
||||
m_sighandle = sighandle;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CLogFileProcessThread::Rand( uint32_t max, uint32_t key )
|
||||
{
|
||||
srand( time(NULL) + key );
|
||||
return ( rand() % max );
|
||||
}
|
||||
|
||||
bool CLogFileProcessThread::IsBeginWork( struct tm& now )
|
||||
{
|
||||
|
||||
|
||||
int status = GetStatus();
|
||||
|
||||
switch( status )
|
||||
{
|
||||
/// READY 상태는 현재 시간이 작업 구간에 있는지를 확인 할 수 있는 상태이다.
|
||||
case LFP_READY:
|
||||
return IsInWorkTimeScope( now.tm_hour );
|
||||
|
||||
/// DONE 상태는 오늘 이미 작업을 마쳤기 때문에 날자가 변경 되었는지를 확인해서
|
||||
/// 날자가 변경 되었으면 상태를 READY로 변경해서 작업 시간에 작업을 다시 할 수 있도록 한다.
|
||||
case LFP_DONE:
|
||||
if( IsChangedDay( now.tm_mday ) == true )
|
||||
{
|
||||
LOG( LDEV1, "call SetStatus( LFP_READY )" );
|
||||
SetStatus( LFP_READY );
|
||||
m_nToday = now.tm_mday;
|
||||
}
|
||||
break;
|
||||
|
||||
/// SLEEP, WORKING 상태를 이미 작업이 시작된 상태로 IsBeginWork() 함수가 외부에 노출 되지 않았기 때문에
|
||||
/// 정상적인 경우에는 SLEEP, WORKING 상태에서 IsBeginWork() 함수가 호출 될 수 없다.
|
||||
case LFP_SLEEP:
|
||||
case LFP_WORKING:
|
||||
default:
|
||||
LOG( LWAR, "%s is invalid status.", GetStrStatus( GetStatus() ).c_str() );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CLogFileProcessThread::IsInWorkTimeScope( int hour )
|
||||
{
|
||||
|
||||
|
||||
if( hour >= m_TimeScope.begin && hour < m_TimeScope.end )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CLogFileProcessThread::SetStatus( LogFileProcessStatus status )
|
||||
{
|
||||
switch( status )
|
||||
{
|
||||
case LFP_READY:
|
||||
case LFP_SLEEP:
|
||||
case LFP_WORKING:
|
||||
case LFP_DONE:
|
||||
_LOG( LINF, "change status of %s %s to %s.", m_szMyName.c_str(), GetStrStatus( m_nStatus ).c_str(), GetStrStatus( status ).c_str() );
|
||||
m_nStatus = status;
|
||||
break;
|
||||
|
||||
default:
|
||||
_LOG( LERR, "can't set status of CLogFileProcess because of invalid status(%d)", status );
|
||||
}
|
||||
}
|
||||
|
||||
string CLogFileProcessThread::GetStrStatus( LogFileProcessStatus status )
|
||||
{
|
||||
string res = "";
|
||||
|
||||
switch( status )
|
||||
{
|
||||
case LFP_READY:
|
||||
res = "READY";
|
||||
break;
|
||||
|
||||
case LFP_SLEEP:
|
||||
res = "SLEEP";
|
||||
break;
|
||||
|
||||
case LFP_WORKING:
|
||||
res = "WORKING";
|
||||
break;
|
||||
|
||||
case LFP_DONE:
|
||||
res = "DONE";
|
||||
|
||||
default:
|
||||
res = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CLogFileProcessThread::IsChangedDay( int day )
|
||||
{
|
||||
|
||||
|
||||
bool res = ( m_nToday != day ? true : false );
|
||||
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CLogFileProcessThread::IsDirectory( string path )
|
||||
{
|
||||
|
||||
|
||||
struct stat dirStat;
|
||||
|
||||
if( lstat ( path.c_str(), &dirStat ) != 0 )
|
||||
{
|
||||
LOG( LERR, "lstat failed. check path(%s).", path.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
// 해당 정보가 Directory 가 아닌 경우
|
||||
if( S_ISDIR( dirStat.st_mode ) == false )
|
||||
{
|
||||
LOG( LDBG, "%s is not directory.", path.c_str() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogFileProcessThread::Unlink( string filename )
|
||||
{
|
||||
|
||||
|
||||
if( IsDirectory( filename ) == true )
|
||||
{
|
||||
LOG( LWAR, "can't unlink file(%s) because %s is direcotry.", filename.c_str(), filename.c_str() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int error = unlink( filename.c_str() );
|
||||
|
||||
if( error == -1 )
|
||||
{
|
||||
LOG( LWAR, "can't unlink file(%s). errno=%d, error=%s",
|
||||
filename.c_str(), error, strerror( error ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_LOG( LINF, "unlinke file: %s", filename.c_str() );
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CLogFileProcessThread::GetMaxSleepSecond( struct tm& now )
|
||||
{
|
||||
if( IsInWorkTimeScope( now.tm_hour ) == false )
|
||||
{
|
||||
LOG( LWAR, "can't get sleep time because of invalid hour(%d).", now.tm_hour );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// (현재 시간 + 1분)에서 (m_TimeScope.end - 1 )시 59분까지의 남은 분을 계산한다. 초 단위 생략.
|
||||
/// (남은 분 * 60)으로 초 단위로 환산한 범위에서 random 한 값을 반환 한다.
|
||||
|
||||
// 우선 시간을 빼고 분만 가지고 계산.
|
||||
// 58분 경우 59로 계산 되므로 해당 값이 '0'되는 것을 방지 하기 위해서 59 => 60으로 변경 한다.
|
||||
int min = 60 - ( now.tm_min + 1 );
|
||||
if( min < 0 )
|
||||
{
|
||||
LOG( LERR, "can't get sleep time because invalid time[%02d:%02d:%02d].",
|
||||
now.tm_hour, now.tm_min, now.tm_sec );
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
/// 시간을 계산해서 분에 더한다.
|
||||
int hour = ( m_TimeScope.end - 1 ) - now.tm_hour;
|
||||
if( hour < 0 )
|
||||
{
|
||||
LOG( LERR, "can't get sleep time because invalid time[%02d:%02d:%02d].",
|
||||
now.tm_hour, now.tm_min, now.tm_sec );
|
||||
return -1;
|
||||
}
|
||||
|
||||
min += (hour * 60);
|
||||
|
||||
/// 분을 초로 환산한다.
|
||||
int sec = min * 60;
|
||||
|
||||
return sec;
|
||||
}
|
||||
|
||||
|
||||
int CLogFileProcessThread::GetToday()
|
||||
{
|
||||
time_t timestamp = time( NULL );
|
||||
struct tm now;
|
||||
localtime_r( ×tamp, &now );
|
||||
|
||||
return now.tm_mday;
|
||||
}
|
||||
|
||||
|
||||
///@brief 이 함수에서 컨트롤 로직이 표현된다.
|
||||
void CLogFileProcessThread::Execute()
|
||||
{
|
||||
time_t timestamp;
|
||||
struct tm now;
|
||||
|
||||
while (*m_sighandle == 0)
|
||||
{
|
||||
/// 현재 시각 확인
|
||||
timestamp = time( NULL );
|
||||
localtime_r( ×tamp, &now );
|
||||
|
||||
/// 작업 시작 여부 확인.
|
||||
if( IsBeginWork( now ) == false )
|
||||
{
|
||||
LOG( LDEV1, "I'm sleeping now for 1 minute." );
|
||||
|
||||
/// 작업을 하지 않아야 하면 1분 대기.
|
||||
sleep( 60 ); /// 60초
|
||||
continue;
|
||||
}
|
||||
|
||||
/// 여기서 부터 작업 시작.
|
||||
|
||||
/// 현재 시간부터 TIME_SCOPE_END까지 최대 대기 할 수 있는 시간을 초 단위로 가지고 온다.
|
||||
int maxSleepSecond = GetMaxSleepSecond( now );
|
||||
if( maxSleepSecond < 0 )
|
||||
{
|
||||
LOG( LERR, "invalid max sleep time. current time = [%02d:%02d:%02d].",
|
||||
now.tm_hour, now.tm_min, now.tm_sec );
|
||||
continue;
|
||||
}
|
||||
|
||||
/// 0 ~ maxSleepSecond 사이의 랜덤한 값을 가지고 온다.
|
||||
CHostInfo hostInfo;
|
||||
int sleeptime = Rand( maxSleepSecond, hostInfo.GetHostNumber() );
|
||||
|
||||
_LOG( LINF, "CLogFileProcess will begin work after %d seconds.", sleeptime );
|
||||
|
||||
if ( bFirst == true )
|
||||
sleeptime = 5;
|
||||
|
||||
/// 위에서 계산한 sleeptime 만큼 대기한 후에 실제 작업 시작.
|
||||
LOG( LDEV1, "call SetStatus( LFP_SLEEP )" );
|
||||
SetStatus( LFP_SLEEP );
|
||||
sleep( sleeptime );
|
||||
|
||||
/// 여기서 부터 실제 작업 시작.
|
||||
/// 실제 작업 구현은 CLogFileProcess를 상속받은 자식 클래스에서 구현한다.
|
||||
LOG( LDEV1, "call SetStatus( LFP_WORKING )" );
|
||||
SetStatus( LFP_WORKING );
|
||||
if( DoWork() == false )
|
||||
{
|
||||
LOG( LWAR, "log file process failed." );
|
||||
}
|
||||
|
||||
// DoWork가 한번 이상 수행 되면 아래이 시간 되어야 한다.
|
||||
bFirst = false;
|
||||
|
||||
// 새벽 4~7시 사이...
|
||||
m_TimeScope.begin = TIME_SCOPE_BEGIN;
|
||||
m_TimeScope.end = TIME_SCOPE_END;
|
||||
/// 작업이 끝나면 작업의 성공 여부에 상관 없이 상태를 LFP_DONE로 변경한다.
|
||||
LOG( LDEV1, "call SetStatus( LFP_DONE )" );
|
||||
SetStatus( LFP_DONE );
|
||||
}
|
||||
|
||||
LOG(LERR, "Thread Terminated...");
|
||||
}
|
||||
|
||||
void* CLogFileProcessThread::EntryPoint(void* arg)
|
||||
{
|
||||
CLogFileProcessThread* pObject = reinterpret_cast<CLogFileProcessThread *>(arg);
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
pObject->Execute();
|
||||
|
||||
pObject->m_threadHandle = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CLogFileProcessThread::Start()
|
||||
{
|
||||
int nRet = ::pthread_create(&m_threadHandle, 0, CLogFileProcessThread::EntryPoint, this);
|
||||
|
||||
if( nRet )
|
||||
{
|
||||
LOG(LERR, "Thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
LOG(LDBG, "Thread create succeed");
|
||||
sleep(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/***************************************************************************
|
||||
Log File Process Base Trhead
|
||||
-----------------------------------------
|
||||
begin : 2015/10/07
|
||||
copyright : (C) 2010 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2010 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __CASH_GENERATOR_H__
|
||||
#define __CASH_GENERATOR_H__
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include "Logger.h"
|
||||
#include "Signal_handle.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/// @brief
|
||||
class CLogFileProcessThread
|
||||
{
|
||||
public:
|
||||
/// @brief 생성자
|
||||
CLogFileProcessThread(string myname);
|
||||
~CLogFileProcessThread();
|
||||
|
||||
/// @brief Thread를 생성하고, 이를 시작한다.
|
||||
/// @param none
|
||||
/// @return 성공은 return true 실패는 return false
|
||||
bool Start();
|
||||
|
||||
/// @brief ProcessStatus 내의 RCDB 관련 설정값을 이용해 DB Connection을 한다.
|
||||
/// @param sighandle 쓰레드에서 signal에 따라 정상 종료하도록 signal handle을 전달한다.
|
||||
/// @param pshmemNetworStat 공유메모리 포인터
|
||||
/// @return 성공하면 return true 실패하면 return false
|
||||
bool ThreadInit(const sig_atomic_t *sighandle);
|
||||
|
||||
|
||||
|
||||
// Attributes
|
||||
private:
|
||||
// 쓰레드 핸들
|
||||
pthread_t m_threadHandle;
|
||||
|
||||
const sig_atomic_t *m_sighandle;
|
||||
|
||||
///@brief 작업 시간 구간을 저장하는 구조체.
|
||||
typedef struct LOG_FILE_PROCESS_TIME_SCOPE
|
||||
{
|
||||
int begin;
|
||||
int end;
|
||||
} LogFileProcessTimeScope;
|
||||
|
||||
///@brief 상태값.
|
||||
typedef enum LOG_FILE_PROCESS_STATUS
|
||||
{
|
||||
LFP_READY = 0,
|
||||
LFP_SLEEP,
|
||||
LFP_WORKING,
|
||||
LFP_DONE
|
||||
} LogFileProcessStatus;
|
||||
|
||||
///@brief 오늘 날자를 저장. struct tm 구조체의 tm_mday 값.(1~31)
|
||||
int m_nToday;
|
||||
|
||||
///@brief 현재 상태를 저장.
|
||||
LogFileProcessStatus m_nStatus;
|
||||
|
||||
///@brief 작업 시간 구간을 저장.
|
||||
LogFileProcessTimeScope m_TimeScope;
|
||||
|
||||
bool bFirst;
|
||||
|
||||
string m_szMyName;
|
||||
|
||||
// Operations
|
||||
private:
|
||||
///@brief 상태를 설정하는 함수.
|
||||
///@param status [in] 설정할 상태값.
|
||||
///@return none.
|
||||
void SetStatus( LogFileProcessStatus status );
|
||||
|
||||
///@brief 현재 상태를 얻는 함수.
|
||||
///@param none.
|
||||
///@return 현재 상태를 반환.
|
||||
LogFileProcessStatus GetStatus() { return m_nStatus; };
|
||||
|
||||
///@brief 정수형의 상태를 입력 받아서 문자열로 반환하는 함수.
|
||||
///@param status [in] 상태값.
|
||||
///@return status에 해당하는 문자열을 반환.
|
||||
/// "LFP_READY", "LFP_SLEEP", "LFP_WORKING", "LFP_DONE" , "UNKOWN" 중 하나.
|
||||
std::string GetStrStatus( LogFileProcessStatus status );
|
||||
|
||||
///@brief 작업 시작 여부를 판단하는 함수.
|
||||
///@param now [in] 현재 시각을 저장하고 있는 tm 구조체.
|
||||
///@return 현재 상태에 따라 아래의 값을 반환.
|
||||
/// - LFP_READY : 현재 시각이 작업 시간 구간에 있는지 확인해서 작업 시간 구간이면 true, 그렇지 않으면 false 반환.
|
||||
/// - LFP_DONE : false 반환
|
||||
/// - LFP_SLEEP : false 반환
|
||||
/// - LFP_WORKING : false 반환
|
||||
bool IsBeginWork( struct tm& now );
|
||||
|
||||
///@brief 주어진 시간이 작업 시간 구간인지 판단하는 함수.
|
||||
///@param hour [in] 시간값 (0~23)
|
||||
///@return 4 <= hour < 7이면 true, 그렇지 않으면 false 반환.
|
||||
bool IsInWorkTimeScope( int hour );
|
||||
|
||||
///@brief 날자가 변경 되었는지를 확인하는 함수.
|
||||
///@param day [in] 날자값 (1~31)
|
||||
///@return 주어진 day가 m_nToday와 같으면 false, 다르면 true 반환.
|
||||
bool IsChangedDay( int day );
|
||||
|
||||
///@brief 작업 시간 구간 내에서 실제로 작업을 시작할 때까지 대기할 수 있는 최대 시간을 초 단위로 계산하는 함수.
|
||||
///@param now [in] 현재 시각을 저장하고 있는 tm 구조체.
|
||||
///@return 주어진 시간에서 작업 시간 구간의 마지막 시간까지의 남은 초를 반환.
|
||||
/// 주어진 시간이 작업 구간 내에 있지 않거나 시간 정보가 올바르지 않으면 -1 반환.
|
||||
int GetMaxSleepSecond( struct tm& now );
|
||||
|
||||
///@brief 오늘 날자를 구하는 함수
|
||||
///@param none.
|
||||
///@return 오늘 날자를 반환한다.(1~31)
|
||||
int GetToday();
|
||||
|
||||
int Rand( uint32_t max, uint32_t key );
|
||||
// Functions
|
||||
private:
|
||||
// 쓰레드 시작 루틴이다.
|
||||
static void* EntryPoint(void* arg);
|
||||
|
||||
// 해당 함수의 내용은 수정하지 말것.
|
||||
void Execute();
|
||||
|
||||
protected:
|
||||
///@brief 실제 로그 파일을 처리하는 함수.
|
||||
///@ 가상 함수로 CLogFileProcessThread 클래스를 상속받는 자식 클래스에서 구현해야 한다.
|
||||
virtual bool DoWork() { return false; };
|
||||
|
||||
///@brief 주어진 경로가 디렉토리인지 아닌지를 판단하는 함수.
|
||||
///@param path [in] 경로.
|
||||
///@return path가 존재하지 않거나 파일이면 false, 그렇지 않으면 true 반환.
|
||||
bool IsDirectory( std::string path );
|
||||
|
||||
///@brief 파일을 unlink 시키는 함수.
|
||||
///@param filename [in] 삭제할 파일명
|
||||
///@return unlink 성공하면 true, 그렇지 않으면 false 반환.
|
||||
bool Unlink( std::string filename );
|
||||
|
||||
};
|
||||
#endif //__CASH_GENERATOR_H__
|
||||
@@ -0,0 +1,322 @@
|
||||
/***************************************************************************
|
||||
LogFileCleaner.cpp
|
||||
-----------------------------------------
|
||||
begin : 2011/11/09
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
#include "LogFileSender.h"
|
||||
#include "DaemonConfigs.h"
|
||||
#include "CcCollectdClientSocket.h"
|
||||
#include "Logger.h"
|
||||
#include "String.h"
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define SECONDS_CORRESPOND_TO_ONE_DAY 86400
|
||||
|
||||
//#define __HJ_TEST__
|
||||
|
||||
#define ACCESS_LOG_PRE_NAME "access_log_"
|
||||
#define ERROR_LOG_PRE_NAME "error_log_"
|
||||
|
||||
using namespace std;
|
||||
|
||||
CLogFileSender::CLogFileSender() : CLogFileProcessThread( "CLogFileSender" )
|
||||
{
|
||||
}
|
||||
|
||||
CLogFileSender::~CLogFileSender()
|
||||
{
|
||||
}
|
||||
|
||||
bool CLogFileSender::DoWork()
|
||||
{
|
||||
std::vector< std::string > vecSearchingDirList = CDeamonConfig::GetInstance()->GetSearchingDirList();
|
||||
std::vector< std::string >::iterator it;
|
||||
|
||||
for (it=vecSearchingDirList.begin(); it<vecSearchingDirList.end(); it++)
|
||||
{
|
||||
std::string szSearchingDir = *it;
|
||||
// 하위 폴더를 재귀 탐색 하면서 파일을 전송한다.
|
||||
SendFiles( szSearchingDir);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogFileSender::SendFiles( std::string path)
|
||||
{
|
||||
/// 디렉토리 open.
|
||||
DIR* pDir = opendir( path.c_str() );
|
||||
|
||||
if( pDir == NULL )
|
||||
{
|
||||
//_LOG( LINF, "can't send files because opendir(%s) is failed.", path.c_str() );
|
||||
_LOG( LINF, "[SEND] directory [%s] not exist.", path.c_str() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string fullname;
|
||||
struct dirent* pDirEnt;
|
||||
|
||||
/// 디렉토리 내의 파일들을 검색.
|
||||
while( ( pDirEnt = readdir( pDir ) ) != NULL )
|
||||
{
|
||||
if( pDirEnt->d_name[0] == '.' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/// 파일의 전체 경로 만들기.
|
||||
fullname = path + "/" + string( pDirEnt->d_name );
|
||||
|
||||
if( IsDirectory( fullname ) == true )
|
||||
{
|
||||
/// 디렉토리이면 재귀 호출.
|
||||
SendFiles( fullname );
|
||||
}
|
||||
else
|
||||
{
|
||||
/// 로그 파일이 아니면 skip.
|
||||
// 아파치 로그파일 여부까지 확인한다.
|
||||
if( IsLogFile( fullname ) == false )
|
||||
{
|
||||
LOG( LDEV, "%s is not log file.", fullname.c_str() );
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// 파일이면 CInode 정보를 가지고 온다.
|
||||
CInode inode;
|
||||
if( inode.LoadInfo( fullname ) == false )
|
||||
{
|
||||
/// 파일 정보를 가지고 오지 못 하면 skip.
|
||||
LOG( LWAR, "inode info loading is failed. file=%s", fullname.c_str() );
|
||||
continue;
|
||||
}
|
||||
|
||||
// 파일 접근 시간이 24시간이내면 당일 파일이라고 판단
|
||||
//if( (current - inode.GetATime() ) < SECONDS_CORRESPOND_TO_ONE_DAY )
|
||||
|
||||
if( IsTodayFile( fullname ) == true )
|
||||
{
|
||||
_LOG( LDBG, "[%s] is skip.. because today's file.", fullname.c_str() );
|
||||
continue;
|
||||
}
|
||||
|
||||
string szAppName;
|
||||
GetApplicationName(fullname, szAppName);
|
||||
|
||||
|
||||
// 파일을 전송한다.
|
||||
// 에러에 대한 체크는 체크는 하지 않는다.
|
||||
// 전송 실패 한 경우에 대해 logging 처리만하고.. skip한다.
|
||||
// 다음날 재전송 시도를 하기때문에...
|
||||
FileSending(szAppName, fullname);
|
||||
}
|
||||
}
|
||||
|
||||
/// 디렉토리 close.
|
||||
closedir( pDir );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogFileSender::IsTodayFile(string szFullName)
|
||||
{
|
||||
time_t timestamp;
|
||||
struct tm timeNow;
|
||||
|
||||
/// 현재 시각 확인
|
||||
timestamp = time( NULL );
|
||||
localtime_r( ×tamp, &timeNow );
|
||||
|
||||
|
||||
// 2017-03-23 CHG huibong
|
||||
// - #30594 의 내역 대로 Apache 로그 파일 형식은 access_log_20170322 와 같이 .log 확장자를 사용하지 않음.
|
||||
// - 따라서 이를 반영하기 위해 확장자 없이 파일명에 날짜 정보만 동일한지 체크하도록 수정 처리한다.
|
||||
//char timeStr[256];
|
||||
//snprintf( timeStr, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
|
||||
|
||||
char timeStr[32];
|
||||
snprintf( timeStr, (size_t)32, "%04d%02d%02d", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
|
||||
|
||||
|
||||
string szDate = timeStr;
|
||||
std::string::size_type pos = szFullName.rfind( szDate );
|
||||
|
||||
if( pos == std::string::npos )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 파일명에 오늘 날짜 정보가 들어 있는 경우.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 파일 전송처리하며... 실패하면 logging 처리만한다.
|
||||
void CLogFileSender::FileSending(string szAppName,string szFullName)
|
||||
{
|
||||
std::string szErrorMessage;
|
||||
unsigned long long uExistFileSize = 0;
|
||||
|
||||
string szServer = CDeamonConfig::GetInstance()->GetLogServer();
|
||||
int nServerPort = CDeamonConfig::GetInstance()->GetLogServerPort();
|
||||
|
||||
// 파일 Full 경로에서 파일명 추출 처리.
|
||||
std::string::size_type pos = szFullName.rfind( '/' );
|
||||
if( pos == std::string::npos )
|
||||
{
|
||||
// 찾지 못한 경우...
|
||||
LOG( LERR, "File path is FULL PATH use. [%s]\n", szFullName.c_str() );
|
||||
return ;
|
||||
}
|
||||
|
||||
// 전송할 파일 정보
|
||||
std::string strTargetDir = szFullName.substr( 0, pos );
|
||||
std::string strTragetFileName = szFullName.substr( pos+1 );
|
||||
|
||||
// 1. 전송 할 파일오픈
|
||||
// fd open
|
||||
int fd = open(szFullName.c_str(), O_RDONLY );
|
||||
if( fd == -1 )
|
||||
{
|
||||
int nErrNum = errno;
|
||||
LOG( LERR, "file[%s] open fail.[%d][%s]\n", szFullName.c_str(), nErrNum, strerror( errno ));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 전송 소켓 생성
|
||||
// socket 생성 및 연결
|
||||
CCcCollectdClientSocket serverSocket;
|
||||
if( serverSocket.ConnectTarget( szServer, nServerPort ) == false )
|
||||
{
|
||||
// 접속 실패시
|
||||
close( fd );
|
||||
|
||||
LOG( LERR, "cc_collectd connect fail. [%s][%d]", szServer.c_str(), nServerPort );
|
||||
return;
|
||||
}
|
||||
|
||||
// local file size 추출
|
||||
// 파일이면 CInode 정보를 가지고 온다.
|
||||
CInode inode;
|
||||
if( inode.LoadInfo( szFullName) == false )
|
||||
{
|
||||
LOG( LWAR, "inode info loading is failed. file=%s", szFullName.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long long uFileSize = inode.GetSize();
|
||||
|
||||
// 3. Log Backup 서버에 파일 존재여부 확인
|
||||
if( serverSocket.CheckFile( szAppName, strTragetFileName, uExistFileSize, szErrorMessage ) == false )
|
||||
{
|
||||
// 3-1. 파일 존재 여부확인이 에러가 나면 logging하고 skip 한다.
|
||||
close( fd );
|
||||
|
||||
LOG( LERR, "cc_collectd exist check fail.[%s][%llu] -> [%s]", strTragetFileName.c_str(), uFileSize, szErrorMessage.c_str() );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LDBG, "cc_collectd exist check OK.local[%s][%llu] remote[%llu]", strTragetFileName.c_str(), uFileSize, uExistFileSize );
|
||||
|
||||
// 3-2. 존재 하더라도 파일크기가 다른경우는 전송 처리한다.
|
||||
if( uFileSize == uExistFileSize )
|
||||
{
|
||||
LOG( LDBG, "cc_collectd same file exist. not send. local[%s][%llu] remote[%llu]", strTragetFileName.c_str(), uFileSize, uExistFileSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
_LOG( LINF, "[%s] log File sending... filename is [%s] ", szAppName.c_str(), szFullName.c_str() );
|
||||
// 파일 크기가 다른 경우에만 전송 처리.
|
||||
// Log 파일 전송 처리
|
||||
// CheckFile() 함수에서 파일이 존재하지 않을 경우 filesize를 0으로 리턴하므로 local의 log filesize가 '0'이 아니면 전송처리 됨.
|
||||
if( serverSocket.SendFile( szAppName, strTragetFileName, fd, uFileSize, szErrorMessage ) == false )
|
||||
{
|
||||
close( fd );
|
||||
|
||||
LOG( LERR, "cc_collectd send fail.[%s][%llu] -> [%s]", strTragetFileName.c_str(), uFileSize, szErrorMessage.c_str() );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LINF, "cc_collectd send OK.[%s][%llu]", strTragetFileName.c_str(), uFileSize );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 전송 소켓 close()는 CCcCollectdClientSocket 소멸자에 존재함
|
||||
// 5. fd close()
|
||||
close(fd);
|
||||
}
|
||||
|
||||
bool CLogFileSender::GetApplicationName(string szFullName, string& szAppName)
|
||||
{
|
||||
/// '/'을 구분자로한 토큰을 벡터에 넣는다.
|
||||
vector<string> tokens = CString::Tokenize( szFullName, "/" );
|
||||
|
||||
/// 벡터의 크기가 1이면 '.'이 없다는 말이다. 즉, 로그 파일이 아니다.
|
||||
if( tokens.size() < 2 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
szAppName = tokens[ tokens.size() - 2 ];
|
||||
|
||||
return true;
|
||||
}
|
||||
/// 파일의 확장자가 log이면 true 반환, 그렇지 않으면 false 반환.
|
||||
bool CLogFileSender::IsLogFile( std::string filename )
|
||||
{
|
||||
//!! 아파치 로그인지를 확인한다.
|
||||
int n1 = filename.find(ACCESS_LOG_PRE_NAME);
|
||||
int n2 = filename.find(ERROR_LOG_PRE_NAME);
|
||||
LOG( LDBG, "%s, %d, %d ", filename.c_str(), n1, n2 );
|
||||
|
||||
//if( filename.find(ACCESS_LOG_PRE_NAME) >= 0 || filename.find(ERROR_LOG_PRE_NAME) >=0 )
|
||||
if( n1 >= 0 || n2 >=0 )
|
||||
{
|
||||
LOG( LDBG, "%s is apache log file.", filename.c_str() );
|
||||
return true;
|
||||
}
|
||||
|
||||
/// '.'을 구분자로한 토큰을 벡터에 넣는다.
|
||||
vector<string> tokens = CString::Tokenize( filename, "." );
|
||||
|
||||
/// 벡터의 크기가 1이면 '.'이 없다는 말이다. 즉, 로그 파일이 아니다.
|
||||
if( tokens.size() == 1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 파일 이름에서 확장자를 가지고 온다.
|
||||
string extension = tokens[ tokens.size() - 1 ];
|
||||
|
||||
/// 확장자 비교.
|
||||
if( extension.compare( "log" ) != 0 )
|
||||
{
|
||||
/// 확장자가 'log'가 아님.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/***************************************************************************
|
||||
LogFileCleaner.h
|
||||
-----------------------------------------
|
||||
begin : 2011/11/09
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
소스 수정 히스토리
|
||||
|
||||
작성자 작성일 Revision 내용
|
||||
장희준 2011/11/09 ? ADD - 최초 등록
|
||||
***************************************************************************/
|
||||
#ifndef __LOGFILESENDER_H__
|
||||
#define __LOGFILESENDER_H__
|
||||
|
||||
#include "LogFileProcessThread.h"
|
||||
#include "Inode.h"
|
||||
|
||||
///@brief 로그 디렉토리에서 일정 시간이 지난 로그 파일 삭제
|
||||
class CLogFileSender : public CLogFileProcessThread
|
||||
{
|
||||
// Attributes
|
||||
private:
|
||||
///@brief 최상위 로그 디렉토리 경로 저장.
|
||||
std::string m_szLogRoot;
|
||||
|
||||
///@brief CLogFileSender을 테스트하는 클래스가 private에 접근할 수 있도록 하기 위함.
|
||||
friend class CLogFileSenderTest;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
|
||||
// Operations
|
||||
private:
|
||||
///@brief 경로 path와 path의 하위 디렉토리에서 log파일들을 제외한다. 단, 당일의 log는 제외
|
||||
///@param path [in] 최상위 로그 디렉토리 경로.
|
||||
///@param period [in] 로그 파일 보존 기간.
|
||||
///@return 경로 path가 존재하지 않거나 디렉토리가 아니면 false, 반환 그렇지 않으면 true 반환.
|
||||
bool SendFiles( std::string path);
|
||||
|
||||
///@brief 파일을 unlink 시키는 함수.
|
||||
///@param filename [in] 삭제할 파일명
|
||||
///@return unlink 성공하면 true, 그렇지 않으면 false 반환.
|
||||
// bool Unlink( std::string filename );
|
||||
|
||||
///@brief 파일이 로그 파일인지 여부를 판단하는 함수.
|
||||
/// 파일의 확장자가 ".log"이면 로그 파일로 판단한다.
|
||||
///@param filename [in] 파일명
|
||||
///@return filename이 디렉토리이거나 파일의 확장자가 ".log"이 아니면 false, 그렇지 않으면 true 반환.
|
||||
bool IsLogFile( std::string filename );
|
||||
|
||||
///@brief 해당 log 파일이 어느 데몬의 로그인지 얻는다.
|
||||
///@param szFullName [in] 파일명
|
||||
///@return szAppName [out] 데몬 명
|
||||
bool GetApplicationName(string szFullName, string& szAppName);
|
||||
|
||||
void FileSending(string szAppName,string szFullName);
|
||||
|
||||
bool IsTodayFile(string szFullName);
|
||||
|
||||
protected:
|
||||
///@brief 로그 파일을 삭제하는 메인 함수.
|
||||
/// 로그 파일의 보존 기간을 가지고 와서 m_szLogRoot와 m_szLogRoot의 하위 디렉토에서
|
||||
/// 보존 기간이 지난 로그 파일들을 삭제한다.
|
||||
///@param none.
|
||||
///@return m_szLogRoot이 유효한 디렉토리이면 true 반환, 그렇지 않으면 false 반환.
|
||||
bool DoWork();
|
||||
|
||||
public:
|
||||
///@brief 생성자.
|
||||
CLogFileSender();
|
||||
|
||||
///@brief 소멸자.
|
||||
virtual ~CLogFileSender();
|
||||
|
||||
///@brief 스레드가 시작하기 전에 초기화 작업을 하는 함수로 CProcessStatus의 초기화 여부와
|
||||
/// 최상위 로그 디렉토리의 유효성을 확인한다.
|
||||
/// CBaseThread로부터 상속 받음.
|
||||
///@param none.
|
||||
///@return CProcessStatus가 초기화 되지 않았거나 m_szLogRoot이 유효한 디렉토리가 아니면 false 반환,
|
||||
/// 그렇지 않으면 true 반환.
|
||||
// bool ThreadInit();
|
||||
};
|
||||
|
||||
#endif // __LOGFILESENDER_H__
|
||||
@@ -0,0 +1,426 @@
|
||||
/****************************************************************************
|
||||
Main ( main.cpp )
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/03/18
|
||||
copyright : (C) 2013 Solbox Inc.
|
||||
author : Development Team
|
||||
- 2015/04/23 - 1st dadamin
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.5
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "Logger.h"
|
||||
#include "Signal_handle.h"
|
||||
#include "ArgParser.h"
|
||||
#include "DaemonConfigs.h"
|
||||
#include "Process.h"
|
||||
#include "Worker.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static int _pid = -1;
|
||||
static bool _isDaemon = true;
|
||||
|
||||
// signal
|
||||
class SIGTerminate_Handler : public Event_Handler
|
||||
{
|
||||
public:
|
||||
SIGTerminate_Handler(void)
|
||||
: graceful_quit_(0) {}
|
||||
|
||||
// Hook method.
|
||||
virtual int handle_signal(int signum)
|
||||
{
|
||||
this->graceful_quit_ = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Accessor.
|
||||
sig_atomic_t graceful_quit(void)
|
||||
{
|
||||
return this->graceful_quit_;
|
||||
}
|
||||
|
||||
sig_atomic_t* get_signalhandel()
|
||||
{
|
||||
return &graceful_quit_;
|
||||
}
|
||||
|
||||
private:
|
||||
sig_atomic_t graceful_quit_;
|
||||
};
|
||||
|
||||
class SIGWorkerDead_Handler : public Event_Handler
|
||||
{
|
||||
public:
|
||||
SIGWorkerDead_Handler(void) {}
|
||||
|
||||
// Hook method.
|
||||
virtual int handle_signal(int signum)
|
||||
{
|
||||
pid_t deadpid;
|
||||
int nstatus;
|
||||
|
||||
while ((deadpid = waitpid(-1, &nstatus, WNOHANG)) > 0)
|
||||
{
|
||||
if (WIFEXITED(nstatus))
|
||||
{
|
||||
// 자식 프로세스가 정상적으로 종료되었는지 검사.
|
||||
LOG(LWAR, "Worker process [%d] killed by signal[SIGTERM]", deadpid);
|
||||
}
|
||||
else if (WIFSIGNALED(nstatus))
|
||||
{
|
||||
// 자식 프로세스가 Signal 에 의해 종료되었는지 검사.
|
||||
LOG(LWAR, "Worker process [%d] killed by signal[%d]", deadpid, WTERMSIG(nstatus));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LWAR, "Worker process [%d] killed. Not signal", deadpid);
|
||||
}
|
||||
|
||||
if (WEXITSTATUS(nstatus) == EXIT_FAILURE)
|
||||
{
|
||||
// Main 종료 시그널 발생
|
||||
raise(SIGTERM);
|
||||
continue;
|
||||
}
|
||||
|
||||
map<pid_t, CProcess*>::iterator it = m_child.find(deadpid);
|
||||
if ( it != m_child.end())
|
||||
{
|
||||
// find it
|
||||
CProcess *p = it->second;
|
||||
set_reprocess(p);
|
||||
m_child.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LERR, "Worker process [%d] not found it. and can't be recreated.", deadpid);
|
||||
}
|
||||
}
|
||||
|
||||
// 오류 발생시 해당 내역 로깅
|
||||
if (deadpid < 0)
|
||||
{
|
||||
LOG(LERR, "Main process error: SIG_CHLD receive but waitpid return error[%d][%s]", errno, strerror(errno));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void add_child(pid_t pid, CProcess *process)
|
||||
{
|
||||
m_child.insert(pair<pid_t, CProcess*>(pid, process));
|
||||
}
|
||||
|
||||
CProcess* get_reprocess()
|
||||
{
|
||||
|
||||
if (m_vecreprocess.empty())
|
||||
return NULL;
|
||||
|
||||
CProcess *p = m_vecreprocess.back();
|
||||
m_vecreprocess.pop_back();
|
||||
return p;
|
||||
}
|
||||
|
||||
void set_reprocess(CProcess *p)
|
||||
{
|
||||
m_vecreprocess.push_back(p);
|
||||
}
|
||||
|
||||
void show_all()
|
||||
{
|
||||
for (map<pid_t, CProcess*>::iterator it = m_child.begin(); it != m_child.end(); ++it)
|
||||
{
|
||||
LOG(LDEV2, "Child process[%d]", it->first);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void kill_child()
|
||||
{
|
||||
for (map<pid_t, CProcess*>::iterator it = m_child.begin(); it != m_child.end(); ++it)
|
||||
{
|
||||
while (waitpid(it->first, NULL, WNOHANG) == 0)
|
||||
{
|
||||
LOG(LDEV2, "Child kill process [%d]", it->first);
|
||||
kill(it->first, SIGTERM);
|
||||
usleep(5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear_reprocess()
|
||||
{
|
||||
m_vecreprocess.clear();
|
||||
}
|
||||
|
||||
void clear_all()
|
||||
{
|
||||
m_child.clear();
|
||||
m_vecreprocess.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
map<pid_t, CProcess*> m_child;
|
||||
vector<CProcess*> m_vecreprocess;
|
||||
};
|
||||
|
||||
// start log
|
||||
static void StartLog()
|
||||
{
|
||||
// Process 기동 관련 정보 기록 -> Log
|
||||
_LOG(LINF, "***********************************************************");
|
||||
_LOG(LINF, " %s Start. Version: %s", PROG_NAME, PROG_VERSION);
|
||||
_LOG(LINF, "***********************************************************");
|
||||
_LOG(LINF, "Config : %s", CDeamonConfig::GetInstance()->GetConfigFile());
|
||||
_LOG(LINF, "Log : %s/%s", CDeamonConfig::GetInstance()->GetAppLogRoot(), PROG_NAME);
|
||||
_LOG(LINF, "Log Bacup Server Host : %s", CDeamonConfig::GetInstance()->GetLogServer());
|
||||
_LOG(LINF, "Log Bacup Server Port : %d", CDeamonConfig::GetInstance()->GetLogServerPort());
|
||||
_LOG(LINF, "Log retention period : %d", CDeamonConfig::GetInstance()->GetAppLogPeriod());
|
||||
_LOG(LINF, "***********************************************************");
|
||||
|
||||
}
|
||||
|
||||
// print Version
|
||||
static void Version()
|
||||
{
|
||||
fprintf( stderr, "\n" );
|
||||
fprintf( stderr, PROG_NAME " version: " PROG_VERSION "\n\n" );
|
||||
|
||||
}
|
||||
|
||||
// print usage
|
||||
static void Usage()
|
||||
{
|
||||
fprintf( stderr, "\n" );
|
||||
|
||||
fprintf( stderr, "Usage: " PROG_NAME " [-h] [-v] [-D] [-c {file}] \n" );
|
||||
fprintf( stderr, "Options: \n" );
|
||||
fprintf( stderr, " -h Display help information \n" );
|
||||
fprintf( stderr, " -v Display version \n" );
|
||||
fprintf( stderr, " -D Run as console mode \n" );
|
||||
fprintf( stderr, " -c {file} Use {file} as config file \n" );
|
||||
fprintf( stderr, "\n" );
|
||||
|
||||
fprintf( stderr, PROG_NAME " is Solbox Cloud Storage module.\n" );
|
||||
fprintf( stderr, " - Log file transfer to log backup server(cc_collectd) \n" );
|
||||
fprintf( stderr, " - Log file delete \n\n" );
|
||||
|
||||
}
|
||||
|
||||
// main function
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
save_ps_display_args(argc, argv);
|
||||
|
||||
string strConfPath = DEFAULT_CONFIG_FILE;
|
||||
|
||||
// parse Input argument
|
||||
CArgParser argparser(argc, argv);
|
||||
|
||||
if (argparser.checkvalue("-v"))
|
||||
{
|
||||
Version();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (argparser.checkvalue("-h"))
|
||||
{
|
||||
Usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argparser.checkvalue("-D"))
|
||||
{
|
||||
_isDaemon = false;
|
||||
}
|
||||
|
||||
string val;
|
||||
if (argparser.checkvalue("-c", &val))
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
cout << "Change conf path " << strConfPath << " to " << val << endl;
|
||||
#endif // _DEBUG
|
||||
strConfPath = val;
|
||||
}
|
||||
|
||||
//check process
|
||||
if (CProcess::IsCurrentProcessRun(PROG_NAME))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
//initialized Config object
|
||||
if (CDeamonConfig::Init(PROG_NAME, strConfPath) == false)
|
||||
{
|
||||
cerr << "[ERR] Failed to initialize the config object." << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// load config
|
||||
if (CDeamonConfig::GetInstance()->LoadConf() == false)
|
||||
{
|
||||
cerr << "[ERR] Config load error." << CDeamonConfig::GetInstance()->GetErrMessage() << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (CDeamonConfig::GetInstance()->CheckValue() == false)
|
||||
{
|
||||
cerr << "[ERR] Config load error." << CDeamonConfig::GetInstance()->GetErrMessage() << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// initialized Log object
|
||||
if (CLogger::Init(PROG_NAME, CDeamonConfig::GetInstance()->GetAppLogRoot(),
|
||||
CDeamonConfig::GetInstance()->GetAppLogLevel()) == false)
|
||||
{
|
||||
cerr << "[ERR] Failed to initialize the log object." << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// set signal
|
||||
SIGTerminate_Handler terminate;
|
||||
SIGWorkerDead_Handler workerdead;
|
||||
|
||||
Signal_Handler::instance()->register_ignore(SIGPIPE);
|
||||
Signal_Handler::instance()->register_ignore(SIGHUP);
|
||||
Signal_Handler::instance()->register_ignore(SIGQUIT);
|
||||
|
||||
Signal_Handler::instance()->register_handler(SIGTERM, &terminate);
|
||||
Signal_Handler::instance()->register_handler(SIGINT, &terminate);
|
||||
|
||||
// daemonize
|
||||
if (_isDaemon && CProcess::Daemon() == false)
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
StartLog();
|
||||
|
||||
int exitcode = EXIT_SUCCESS;
|
||||
_pid = getpid();
|
||||
|
||||
// set work process
|
||||
// alive check dummy process create
|
||||
//CProcessDummy objAliveCheck;
|
||||
//objAliveCheck.SetPort(CDeamonConfig::GetInstance()->GetAliveCheckPort());
|
||||
//workerdead.set_reprocess(&objAliveCheck);
|
||||
|
||||
// CProcessDummy dummy1, dummy2, dummy3;
|
||||
// dummy1.SetPort(7777);
|
||||
// workerdead.set_reprocess(&dummy1);
|
||||
// dummy2.SetPort(8888);
|
||||
// workerdead.set_reprocess(&dummy2);
|
||||
// workerdead.set_reprocess(&dummy3);
|
||||
|
||||
// CProcessTest test;
|
||||
// workerdead.set_reprocess(&test);
|
||||
|
||||
// Worker
|
||||
CWorker worker;
|
||||
workerdead.set_reprocess(&worker);
|
||||
|
||||
// Run the main event loop.
|
||||
while (terminate.graceful_quit() == 0)
|
||||
{
|
||||
// make work process
|
||||
CProcess* p = NULL;
|
||||
while ((p = workerdead.get_reprocess()) != NULL )
|
||||
{
|
||||
p->Launcher(terminate.get_signalhandel());
|
||||
if (p->Getpid() > 0)
|
||||
{
|
||||
// main(parent) process
|
||||
if (p->Is_launched() == false)
|
||||
{
|
||||
exitcode = EXIT_FAILURE;
|
||||
// error
|
||||
cerr << "Worker Process create failed." << endl;
|
||||
LOG(LERR, "Worker Process create failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
workerdead.add_child(p->Getpid(), p);
|
||||
}
|
||||
else if (p->Getpid() == 0)
|
||||
{
|
||||
// work(child) process
|
||||
workerdead.clear_all();
|
||||
}
|
||||
else
|
||||
{
|
||||
// error
|
||||
exitcode = EXIT_FAILURE;
|
||||
cerr << "Worker Process create failed.(fork error)" << endl;
|
||||
LOG(LERR, "Worker Process create failed.(fork error)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (exitcode == EXIT_FAILURE)
|
||||
break;
|
||||
|
||||
if (_pid == getpid())
|
||||
{
|
||||
|
||||
// main(parent) process
|
||||
// wait
|
||||
set_ps_display("main [log manager process]", false);
|
||||
|
||||
Signal_Handler::instance()->register_handler(SIGCHLD, &workerdead);
|
||||
|
||||
pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
// work(child) process
|
||||
_pid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (exitcode == EXIT_SUCCESS)
|
||||
Signal_Handler::instance()->remove_handler(SIGCHLD);
|
||||
Signal_Handler::instance()->remove_handler(SIGTERM);
|
||||
Signal_Handler::instance()->remove_handler(SIGINT);
|
||||
|
||||
if (_pid > 0)
|
||||
{
|
||||
if (terminate.graceful_quit())
|
||||
{
|
||||
// KILL - Child
|
||||
//kill(0, SIGTERM);
|
||||
|
||||
// waitpid
|
||||
//while (waitpid(0, NULL, WNOHANG) > 0);
|
||||
workerdead.kill_child();
|
||||
}
|
||||
}
|
||||
|
||||
// end
|
||||
ostringstream msg;
|
||||
if (_pid == getpid())
|
||||
msg << "Main Process [" << getpid() << "] exit job end. Good Bye..";
|
||||
else
|
||||
msg << "Worker Process [" << getpid() << "] exit job end. Good Bye..";
|
||||
|
||||
_LOG(LINF, msg.str().c_str());
|
||||
cerr << msg.str() << endl;
|
||||
|
||||
CLogger::Exit();
|
||||
CDeamonConfig::Exit();
|
||||
|
||||
return exitcode;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#****************************************************************************
|
||||
# Makefile for logmngd
|
||||
# -----------------------------------------
|
||||
#
|
||||
# begin : 2013/04/23
|
||||
# copyright : (C) 2005 Solbox Inc.
|
||||
# author : Development Team (Storage Part)
|
||||
# email : storage.sd@solbox.com
|
||||
# version : 3.5
|
||||
#
|
||||
# CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or with out
|
||||
# modification, are not permitted in outside of Solbox Inc.
|
||||
#*****************************************************************************
|
||||
|
||||
|
||||
# Program info
|
||||
PROG_NAME = logmngd
|
||||
REVISION = 1513
|
||||
PROG_VERSION = 3.5.0.$(REVISION)-`date +%Y%m%d%H%M%S`
|
||||
|
||||
DEFAULT_CONFIG_FILE = /user/service/etc/fhs.conf
|
||||
#DEFAULT_CONFIG_FILE = /user/service/etc/rcts.conf
|
||||
#DEFAULT_CONFIG_FILE = /user/service/etc/gts.conf
|
||||
|
||||
INSTALL_BIN = /user/service/bin
|
||||
INSTALL_CONF = /user/service/etc
|
||||
|
||||
# Compiler info
|
||||
CC = /usr/bin/g++
|
||||
|
||||
CFLAGS = -Wall -O2 -g -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-fno-rtti -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DHAVE_NETINET_IN_H
|
||||
|
||||
LFLAGS =
|
||||
|
||||
# DEBUG or RELEASE Mode select
|
||||
#DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -D__TEST__
|
||||
DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
|
||||
|
||||
# Application Enviroment
|
||||
APP = $(PROG_NAME)
|
||||
|
||||
DIR_INCLUDE = -I../lib
|
||||
DIR_LIB = -L../lib
|
||||
|
||||
LIBS = -lpthread ../lib/libInterCommon.a
|
||||
|
||||
OBJ = ArgParser.o Signal_handle.o HostInfo.o String.o\
|
||||
ProcessRename.o Process.o DaemonConfigs.o\
|
||||
Main.o Worker.o Inode.o LogFileProcessThread.o LogFileCleaner.o LogFileSender.o CcCollectdClientSocket.o
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
|
||||
all:$(APP)
|
||||
sync
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
|
||||
$(PROG_NAME): $(OBJ)
|
||||
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
|
||||
|
||||
|
||||
clean:
|
||||
-rm -f *.o core.$(PROG_NAME).* $(PROG_NAME).core *.out *.log
|
||||
-rm -f $(APP)
|
||||
sync
|
||||
|
||||
|
||||
install : $(APP)
|
||||
-cp $(APP) $(INSTALL_BIN)/$(APP)
|
||||
sync
|
||||
|
||||
|
||||
# End of Makefile
|
||||
@@ -0,0 +1,423 @@
|
||||
// MersenneTwister.h
|
||||
// Mersenne Twister random number generator -- a C++ class MTRand
|
||||
// Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
|
||||
// Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com
|
||||
|
||||
// The Mersenne Twister is an algorithm for generating random numbers. It
|
||||
// was designed with consideration of the flaws in various other generators.
|
||||
// The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
|
||||
// are far greater. The generator is also fast; it avoids multiplication and
|
||||
// division, and it benefits from caches and pipelines. For more information
|
||||
// see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html
|
||||
|
||||
// Reference
|
||||
// M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
|
||||
// Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
|
||||
// Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
|
||||
|
||||
// Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
|
||||
// Copyright (C) 2000 - 2003, Richard J. Wagner
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of its contributors may not be used to endorse or promote
|
||||
// products derived from this software without specific prior written
|
||||
// permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// The original code included the following notice:
|
||||
//
|
||||
// When you use this, send an email to: matumoto@math.keio.ac.jp
|
||||
// with an appropriate reference to your work.
|
||||
//
|
||||
// It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu
|
||||
// when you write.
|
||||
|
||||
#ifndef MERSENNETWISTER_H
|
||||
#define MERSENNETWISTER_H
|
||||
|
||||
// Not thread safe (unless auto-initialization is avoided and each thread has
|
||||
// its own MTRand object)
|
||||
|
||||
#include <iostream>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
class MTRand {
|
||||
// Data
|
||||
public:
|
||||
typedef unsigned long uint32; // unsigned integer type, at least 32 bits
|
||||
|
||||
enum { N = 624 }; // length of state vector
|
||||
enum { SAVE = N + 1 }; // length of array for save()
|
||||
|
||||
protected:
|
||||
enum { M = 397 }; // period parameter
|
||||
|
||||
uint32 state[N]; // internal state
|
||||
uint32 *pNext; // next value to get from state
|
||||
int left; // number of values left before reload needed
|
||||
|
||||
|
||||
//Methods
|
||||
public:
|
||||
MTRand( const uint32& oneSeed ); // initialize with a simple uint32
|
||||
MTRand( uint32 *const bigSeed, uint32 const seedLength = N ); // or an array
|
||||
MTRand(); // auto-initialize with /dev/urandom or time() and clock()
|
||||
|
||||
// Do NOT use for CRYPTOGRAPHY without securely hashing several returned
|
||||
// values together, otherwise the generator state can be learned after
|
||||
// reading 624 consecutive values.
|
||||
|
||||
// Access to 32-bit random numbers
|
||||
double rand(); // real number in [0,1]
|
||||
double rand( const double& n ); // real number in [0,n]
|
||||
double randExc(); // real number in [0,1)
|
||||
double randExc( const double& n ); // real number in [0,n)
|
||||
double randDblExc(); // real number in (0,1)
|
||||
double randDblExc( const double& n ); // real number in (0,n)
|
||||
uint32 randInt(); // integer in [0,2^32-1]
|
||||
uint32 randInt( const uint32& n ); // integer in [0,n] for n < 2^32
|
||||
double operator()() { return rand(); } // same as rand()
|
||||
|
||||
// Access to 53-bit random numbers (capacity of IEEE double precision)
|
||||
double rand53(); // real number in [0,1)
|
||||
|
||||
// Access to nonuniform random number distributions
|
||||
double randNorm( const double& mean = 0.0, const double& variance = 0.0 );
|
||||
|
||||
// Re-seeding functions with same behavior as initializers
|
||||
void seed( const uint32 oneSeed );
|
||||
void seed( uint32 *const bigSeed, const uint32 seedLength = N );
|
||||
void seed();
|
||||
|
||||
// Saving and loading generator state
|
||||
void save( uint32* saveArray ) const; // to array of size SAVE
|
||||
void load( uint32 *const loadArray ); // from such array
|
||||
friend std::ostream& operator<<( std::ostream& os, const MTRand& mtrand );
|
||||
friend std::istream& operator>>( std::istream& is, MTRand& mtrand );
|
||||
|
||||
protected:
|
||||
void initialize( const uint32 oneSeed );
|
||||
void reload();
|
||||
uint32 hiBit( const uint32& u ) const { return u & 0x80000000UL; }
|
||||
uint32 loBit( const uint32& u ) const { return u & 0x00000001UL; }
|
||||
uint32 loBits( const uint32& u ) const { return u & 0x7fffffffUL; }
|
||||
uint32 mixBits( const uint32& u, const uint32& v ) const
|
||||
{ return hiBit(u) | loBits(v); }
|
||||
uint32 twist( const uint32& m, const uint32& s0, const uint32& s1 ) const
|
||||
{ return m ^ (mixBits(s0,s1)>>1) ^ (-loBit(s1) & 0x9908b0dfUL); }
|
||||
static uint32 hash( time_t t, clock_t c );
|
||||
};
|
||||
|
||||
|
||||
inline MTRand::MTRand( const uint32& oneSeed )
|
||||
{ seed(oneSeed); }
|
||||
|
||||
inline MTRand::MTRand( uint32 *const bigSeed, const uint32 seedLength )
|
||||
{ seed(bigSeed,seedLength); }
|
||||
|
||||
inline MTRand::MTRand()
|
||||
{ seed(); }
|
||||
|
||||
inline double MTRand::rand()
|
||||
{ return double(randInt()) * (1.0/4294967295.0); }
|
||||
|
||||
inline double MTRand::rand( const double& n )
|
||||
{ return rand() * n; }
|
||||
|
||||
inline double MTRand::randExc()
|
||||
{ return double(randInt()) * (1.0/4294967296.0); }
|
||||
|
||||
inline double MTRand::randExc( const double& n )
|
||||
{ return randExc() * n; }
|
||||
|
||||
inline double MTRand::randDblExc()
|
||||
{ return ( double(randInt()) + 0.5 ) * (1.0/4294967296.0); }
|
||||
|
||||
inline double MTRand::randDblExc( const double& n )
|
||||
{ return randDblExc() * n; }
|
||||
|
||||
inline double MTRand::rand53()
|
||||
{
|
||||
uint32 a = randInt() >> 5, b = randInt() >> 6;
|
||||
return ( a * 67108864.0 + b ) * (1.0/9007199254740992.0); // by Isaku Wada
|
||||
}
|
||||
|
||||
inline double MTRand::randNorm( const double& mean, const double& variance )
|
||||
{
|
||||
// Return a real number from a normal (Gaussian) distribution with given
|
||||
// mean and variance by Box-Muller method
|
||||
double r = sqrt( -2.0 * log( 1.0-randDblExc()) ) * variance;
|
||||
double phi = 2.0 * 3.14159265358979323846264338328 * randExc();
|
||||
return mean + r * cos(phi);
|
||||
}
|
||||
|
||||
inline MTRand::uint32 MTRand::randInt()
|
||||
{
|
||||
// Pull a 32-bit integer from the generator state
|
||||
// Every other access function simply transforms the numbers extracted here
|
||||
|
||||
if( left == 0 ) reload();
|
||||
--left;
|
||||
|
||||
register uint32 s1;
|
||||
s1 = *pNext++;
|
||||
s1 ^= (s1 >> 11);
|
||||
s1 ^= (s1 << 7) & 0x9d2c5680UL;
|
||||
s1 ^= (s1 << 15) & 0xefc60000UL;
|
||||
return ( s1 ^ (s1 >> 18) );
|
||||
}
|
||||
|
||||
inline MTRand::uint32 MTRand::randInt( const uint32& n )
|
||||
{
|
||||
// Find which bits are used in n
|
||||
// Optimized by Magnus Jonsson (magnus@smartelectronix.com)
|
||||
uint32 used = n;
|
||||
used |= used >> 1;
|
||||
used |= used >> 2;
|
||||
used |= used >> 4;
|
||||
used |= used >> 8;
|
||||
used |= used >> 16;
|
||||
|
||||
// Draw numbers until one is found in [0,n]
|
||||
uint32 i;
|
||||
do
|
||||
i = randInt() & used; // toss unused bits to shorten search
|
||||
while( i > n );
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
inline void MTRand::seed( const uint32 oneSeed )
|
||||
{
|
||||
// Seed the generator with a simple uint32
|
||||
initialize(oneSeed);
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
|
||||
{
|
||||
// Seed the generator with an array of uint32's
|
||||
// There are 2^19937-1 possible initial states. This function allows
|
||||
// all of those to be accessed by providing at least 19937 bits (with a
|
||||
// default seed length of N = 624 uint32's). Any bits above the lower 32
|
||||
// in each element are discarded.
|
||||
// Just call seed() if you want to get array from /dev/urandom
|
||||
initialize(19650218UL);
|
||||
register int i = 1;
|
||||
register uint32 j = 0;
|
||||
register int k = ( N > seedLength ? N : seedLength );
|
||||
for( ; k; --k )
|
||||
{
|
||||
state[i] =
|
||||
state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1664525UL );
|
||||
state[i] += ( bigSeed[j] & 0xffffffffUL ) + j;
|
||||
state[i] &= 0xffffffffUL;
|
||||
++i; ++j;
|
||||
if( i >= N ) { state[0] = state[N-1]; i = 1; }
|
||||
if( j >= seedLength ) j = 0;
|
||||
}
|
||||
for( k = N - 1; k; --k )
|
||||
{
|
||||
state[i] =
|
||||
state[i] ^ ( (state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL );
|
||||
state[i] -= i;
|
||||
state[i] &= 0xffffffffUL;
|
||||
++i;
|
||||
if( i >= N ) { state[0] = state[N-1]; i = 1; }
|
||||
}
|
||||
state[0] = 0x80000000UL; // MSB is 1, assuring non-zero initial array
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
inline void MTRand::seed()
|
||||
{
|
||||
// Seed the generator with an array from /dev/urandom if available
|
||||
// Otherwise use a hash of time() and clock() values
|
||||
|
||||
// First try getting an array from /dev/urandom
|
||||
FILE* urandom = fopen( "/dev/urandom", "rb" );
|
||||
if( urandom )
|
||||
{
|
||||
uint32 bigSeed[N];
|
||||
register uint32 *s = bigSeed;
|
||||
register int i = N;
|
||||
register bool success = true;
|
||||
while( success && i-- )
|
||||
success = fread( s++, sizeof(uint32), 1, urandom );
|
||||
fclose(urandom);
|
||||
if( success ) { seed( bigSeed, N ); return; }
|
||||
}
|
||||
|
||||
// Was not successful, so use time() and clock() instead
|
||||
seed( hash( time(NULL), clock() ) );
|
||||
}
|
||||
|
||||
|
||||
inline void MTRand::initialize( const uint32 _seed )
|
||||
{
|
||||
// Initialize generator state with seed
|
||||
// See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
|
||||
// In previous versions, most significant bits (MSBs) of the seed affect
|
||||
// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
|
||||
register uint32 *s = state;
|
||||
register uint32 *r = state;
|
||||
register int i = 1;
|
||||
*s++ = _seed & 0xffffffffUL;
|
||||
for( ; i < N; ++i )
|
||||
{
|
||||
*s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL;
|
||||
r++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void MTRand::reload()
|
||||
{
|
||||
// Generate N new values in state
|
||||
// Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
|
||||
register uint32 *p = state;
|
||||
register int i;
|
||||
for( i = N - M; i--; ++p )
|
||||
*p = twist( p[M], p[0], p[1] );
|
||||
for( i = M; --i; ++p )
|
||||
*p = twist( p[M-N], p[0], p[1] );
|
||||
*p = twist( p[M-N], p[0], state[0] );
|
||||
|
||||
left = N, pNext = state;
|
||||
}
|
||||
|
||||
|
||||
inline MTRand::uint32 MTRand::hash( time_t t, clock_t c )
|
||||
{
|
||||
// Get a uint32 from t and c
|
||||
// Better than uint32(x) in case x is floating point in [0,1]
|
||||
// Based on code by Lawrence Kirby (fred@genesis.demon.co.uk)
|
||||
|
||||
static uint32 differ = 0; // guarantee time-based seeds will change
|
||||
|
||||
uint32 h1 = 0;
|
||||
unsigned char *p = (unsigned char *) &t;
|
||||
for( size_t i = 0; i < sizeof(t); ++i )
|
||||
{
|
||||
h1 *= UCHAR_MAX + 2U;
|
||||
h1 += p[i];
|
||||
}
|
||||
uint32 h2 = 0;
|
||||
p = (unsigned char *) &c;
|
||||
for( size_t j = 0; j < sizeof(c); ++j )
|
||||
{
|
||||
h2 *= UCHAR_MAX + 2U;
|
||||
h2 += p[j];
|
||||
}
|
||||
return ( h1 + differ++ ) ^ h2;
|
||||
}
|
||||
|
||||
|
||||
inline void MTRand::save( uint32* saveArray ) const
|
||||
{
|
||||
register uint32 *sa = saveArray;
|
||||
register const uint32 *s = state;
|
||||
register int i = N;
|
||||
for( ; i--; *sa++ = *s++ ) {}
|
||||
*sa = left;
|
||||
}
|
||||
|
||||
|
||||
inline void MTRand::load( uint32 *const loadArray )
|
||||
{
|
||||
register uint32 *s = state;
|
||||
register uint32 *la = loadArray;
|
||||
register int i = N;
|
||||
for( ; i--; *s++ = *la++ ) {}
|
||||
left = *la;
|
||||
pNext = &state[N-left];
|
||||
}
|
||||
|
||||
|
||||
inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
|
||||
{
|
||||
register const MTRand::uint32 *s = mtrand.state;
|
||||
register int i = mtrand.N;
|
||||
for( ; i--; os << *s++ << "\t" ) {}
|
||||
return os << mtrand.left;
|
||||
}
|
||||
|
||||
|
||||
inline std::istream& operator>>( std::istream& is, MTRand& mtrand )
|
||||
{
|
||||
register MTRand::uint32 *s = mtrand.state;
|
||||
register int i = mtrand.N;
|
||||
for( ; i--; is >> *s++ ) {}
|
||||
is >> mtrand.left;
|
||||
mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
|
||||
return is;
|
||||
}
|
||||
|
||||
#endif // MERSENNETWISTER_H
|
||||
|
||||
// Change log:
|
||||
//
|
||||
// v0.1 - First release on 15 May 2000
|
||||
// - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
|
||||
// - Translated from C to C++
|
||||
// - Made completely ANSI compliant
|
||||
// - Designed convenient interface for initialization, seeding, and
|
||||
// obtaining numbers in default or user-defined ranges
|
||||
// - Added automatic seeding from /dev/urandom or time() and clock()
|
||||
// - Provided functions for saving and loading generator state
|
||||
//
|
||||
// v0.2 - Fixed bug which reloaded generator one step too late
|
||||
//
|
||||
// v0.3 - Switched to clearer, faster reload() code from Matthew Bellew
|
||||
//
|
||||
// v0.4 - Removed trailing newline in saved generator format to be consistent
|
||||
// with output format of built-in types
|
||||
//
|
||||
// v0.5 - Improved portability by replacing static const int's with enum's and
|
||||
// clarifying return values in seed(); suggested by Eric Heimburg
|
||||
// - Removed MAXINT constant; use 0xffffffffUL instead
|
||||
//
|
||||
// v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits
|
||||
// - Changed integer [0,n] generator to give better uniformity
|
||||
//
|
||||
// v0.7 - Fixed operator precedence ambiguity in reload()
|
||||
// - Added access for real numbers in (0,1) and (0,n)
|
||||
//
|
||||
// v0.8 - Included time.h header to properly support time_t and clock_t
|
||||
//
|
||||
// v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto
|
||||
// - Allowed for seeding with arrays of any length
|
||||
// - Added access for real numbers in [0,1) with 53-bit resolution
|
||||
// - Added access for real numbers from normal (Gaussian) distributions
|
||||
// - Increased overall speed by optimizing twist()
|
||||
// - Doubled speed of integer [0,n] generation
|
||||
// - Fixed out-of-range number generation on 64-bit machines
|
||||
// - Improved portability by substituting literal constants for long enum's
|
||||
// - Changed license from GNU LGPL to BSD
|
||||
@@ -0,0 +1,131 @@
|
||||
#include "Process.h"
|
||||
|
||||
bool CProcess::IS_DAEMON = false;
|
||||
|
||||
CProcess::CProcess()
|
||||
: m_pid(-1), m_launched(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CProcess::~CProcess()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CProcess::Daemon() {
|
||||
|
||||
if (IS_DAEMON == false && daemon(1, 0) == -1) {
|
||||
cerr << "Error detaching";
|
||||
return false;
|
||||
}
|
||||
|
||||
IS_DAEMON = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CProcess::IsProcessRun(const char* pname) {
|
||||
char tempBuffer[512];
|
||||
FILE * fd = NULL;
|
||||
bool bRun = false;
|
||||
|
||||
snprintf(tempBuffer, sizeof(tempBuffer), "pgrep -x %s | sort", pname);
|
||||
|
||||
fd = popen(tempBuffer, "r");
|
||||
if (fd == NULL)
|
||||
{
|
||||
|
||||
cerr << "[ERR] Process check failed. [popen error][" << strerror(errno) << "]" << endl;
|
||||
// 오류 발생시 true 반환하여 프로세스 실행 방지처리
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
void(*intsave)(int) = signal(SIGINT, SIG_IGN);
|
||||
void(*quitsave)(int) = signal(SIGTERM, SIG_IGN);
|
||||
void(*chldave)(int) = signal(SIGCHLD, SIG_IGN);
|
||||
|
||||
memset(tempBuffer, 0x00, sizeof(tempBuffer));
|
||||
while (fgets(tempBuffer, sizeof(tempBuffer) - 1, fd) != NULL)
|
||||
{
|
||||
string tempPid(tempBuffer);
|
||||
//Trim(tempPid);
|
||||
|
||||
pid_t pid = atoi(tempPid.c_str());
|
||||
if (pid > 0)
|
||||
{
|
||||
bRun = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
signal(SIGINT, intsave);
|
||||
signal(SIGTERM, quitsave);
|
||||
signal(SIGCHLD, chldave);
|
||||
|
||||
pclose(fd);
|
||||
return bRun;
|
||||
}
|
||||
}
|
||||
|
||||
bool CProcess::IsCurrentProcessRun(const char* pname) {
|
||||
char tempBuffer[512];
|
||||
FILE * fd = NULL;
|
||||
bool bRun = false;
|
||||
|
||||
snprintf(tempBuffer, sizeof(tempBuffer), "pgrep -x %s | sort", pname);
|
||||
|
||||
fd = popen(tempBuffer, "r");
|
||||
if (fd == NULL)
|
||||
{
|
||||
|
||||
cerr << "[ERR] Process duplication check failed. [popen error][" << strerror(errno) << "]"<< endl;
|
||||
// 오류 발생시 true 반환하여 프로세스 실행 방지처리
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(tempBuffer, 0x00, sizeof(tempBuffer));
|
||||
while (fgets(tempBuffer, sizeof(tempBuffer) - 1, fd) != NULL)
|
||||
{
|
||||
string tempPid(tempBuffer);
|
||||
//Trim(tempPid);
|
||||
|
||||
pid_t pid = atoi(tempPid.c_str());
|
||||
if (pid != getpid())
|
||||
{
|
||||
cerr << "[info] Process duplication found. pid[" << pid << "]" << endl;
|
||||
bRun = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pclose(fd);
|
||||
return bRun;
|
||||
}
|
||||
}
|
||||
|
||||
pid_t CProcess::Fork() {
|
||||
|
||||
m_pid = ::fork();
|
||||
if (m_pid >= 0) m_launched = true;
|
||||
|
||||
return m_pid;
|
||||
}
|
||||
|
||||
void CProcess::SetThreadSignal(int signum)
|
||||
{
|
||||
sigset_t sig, old;
|
||||
sigemptyset(&sig);
|
||||
sigaddset(&sig, signum);
|
||||
sigprocmask(SIG_BLOCK, &sig, &old);
|
||||
}
|
||||
|
||||
void CProcess::UnSetThreadSignal(int signum)
|
||||
{
|
||||
sigset_t sig, old;
|
||||
sigemptyset(&sig);
|
||||
sigaddset(&sig, signum);
|
||||
sigprocmask(SIG_UNBLOCK, &sig, &old);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/***************************************************************************
|
||||
Process functions
|
||||
-----------------------------------------
|
||||
begin : 2013/06/21
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev 1 Team
|
||||
email : dev1@solbox.com
|
||||
version : 3.2.0
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __PROCESS_H__
|
||||
#define __PROCESS_H__
|
||||
|
||||
#include <errno.h>
|
||||
#define _WITH_DPRINTF
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "Signal_handle.h"
|
||||
#include "ProcessRename.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CProcess {
|
||||
|
||||
public:
|
||||
static bool Daemon();
|
||||
static bool IS_DAEMON;
|
||||
static bool IsCurrentProcessRun(const char* pname);
|
||||
static bool IsProcessRun(const char* pname);
|
||||
|
||||
public:
|
||||
CProcess();
|
||||
virtual ~CProcess();
|
||||
|
||||
virtual pid_t Launcher(const sig_atomic_t *sighandle) = 0;
|
||||
|
||||
inline pid_t Getpid() { return m_pid; }
|
||||
inline bool Is_launched(){ return m_launched; }
|
||||
|
||||
protected:
|
||||
// return
|
||||
// 0> : error
|
||||
// 0 : child process
|
||||
// 0< : parent process
|
||||
pid_t Fork();
|
||||
|
||||
void SetThreadSignal(int signum);
|
||||
void UnSetThreadSignal(int signum);
|
||||
|
||||
pid_t m_pid;
|
||||
bool m_launched;
|
||||
};
|
||||
|
||||
|
||||
#endif // __PROCESS_H__
|
||||
@@ -0,0 +1,209 @@
|
||||
#include "ProcessRename.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
|
||||
void set_ps_display(const char *activity, bool force)
|
||||
{
|
||||
setproctitle("%s", activity);
|
||||
}
|
||||
|
||||
char ** save_ps_display_args(int argc, char **argv)
|
||||
{
|
||||
return argv;
|
||||
}
|
||||
|
||||
#else // linux
|
||||
|
||||
typedef size_t Size;
|
||||
#define LONG_ALIGN_MASK (sizeof(long) - 1)
|
||||
#define MEMSET_LOOP_LIMIT 1024
|
||||
#define MemSet(start, val, len) \
|
||||
do \
|
||||
{ \
|
||||
/* must be void* because we don't know if it is integer aligned yet */ \
|
||||
void *_vstart = (void *) (start); \
|
||||
int _val = (val); \
|
||||
Size _len = (len); \
|
||||
\
|
||||
if ((((long) _vstart) & LONG_ALIGN_MASK) == 0 && \
|
||||
(_len & LONG_ALIGN_MASK) == 0 && \
|
||||
_val == 0 && \
|
||||
_len <= MEMSET_LOOP_LIMIT && \
|
||||
/* \
|
||||
* If MEMSET_LOOP_LIMIT == 0, optimizer should find \
|
||||
* the whole "if" false at compile time. \
|
||||
*/ \
|
||||
MEMSET_LOOP_LIMIT != 0) \
|
||||
{ \
|
||||
long *_start = (long *) _vstart; \
|
||||
long *_stop = (long *) ((char *) _start + _len); \
|
||||
while (_start < _stop) \
|
||||
*_start++ = 0; \
|
||||
} \
|
||||
else \
|
||||
memset(_vstart, _val, _len); \
|
||||
} while (0)
|
||||
|
||||
#define PS_PADDING '\0'
|
||||
|
||||
extern char **environ;
|
||||
bool update_process_title = true;
|
||||
|
||||
static char *ps_buffer; /* will point to argv area */
|
||||
static size_t ps_buffer_size; /* space determined at run time */
|
||||
static size_t last_status_len; /* use to minimize length of clobber */
|
||||
static size_t ps_buffer_cur_len; /* nominal strlen(ps_buffer) */
|
||||
static size_t ps_buffer_fixed_size; /* size of the constant prefix */
|
||||
|
||||
static int save_argc;
|
||||
static char **save_argv;
|
||||
|
||||
size_t strlcpy(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0)
|
||||
{
|
||||
while (--n != 0)
|
||||
{
|
||||
if ((*d++ = *s++) == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0)
|
||||
{
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return (s - src - 1); /* count does not include NUL */
|
||||
}
|
||||
|
||||
|
||||
void set_ps_display(const char *activity, bool force)
|
||||
{
|
||||
char szTemp[256];
|
||||
strcpy(szTemp, PROG_NAME);
|
||||
strcat(szTemp, ": ");
|
||||
strcat(szTemp, activity);
|
||||
|
||||
set_ps_display_in(szTemp, force);
|
||||
}
|
||||
|
||||
void set_ps_display_in(const char *activity, bool force)
|
||||
{
|
||||
/* update_process_title=off disables updates, unless force = true */
|
||||
if (!force && !update_process_title)
|
||||
return;
|
||||
|
||||
/* no ps display for stand-alone backend */
|
||||
//if (!IsUnderPostmaster)
|
||||
// return;
|
||||
|
||||
/* If ps_buffer is a pointer, it might still be null */
|
||||
if (!ps_buffer)
|
||||
return;
|
||||
/* Update ps_buffer to contain both fixed part and activity */
|
||||
strlcpy(ps_buffer + ps_buffer_fixed_size, activity,
|
||||
ps_buffer_size - ps_buffer_fixed_size);
|
||||
ps_buffer_cur_len = strlen(ps_buffer);
|
||||
|
||||
/* pad unused memory; need only clobber remainder of old status string */
|
||||
if (last_status_len > ps_buffer_cur_len)
|
||||
MemSet(ps_buffer + ps_buffer_cur_len, PS_PADDING,
|
||||
last_status_len - ps_buffer_cur_len);
|
||||
last_status_len = ps_buffer_cur_len;
|
||||
|
||||
}
|
||||
|
||||
|
||||
char ** save_ps_display_args(int argc, char **argv)
|
||||
{
|
||||
save_argc = argc;
|
||||
save_argv = argv;
|
||||
|
||||
/*
|
||||
* If we're going to overwrite the argv area, count the available space.
|
||||
* Also move the environment to make additional room.
|
||||
*/
|
||||
{
|
||||
char *end_of_area = NULL;
|
||||
char **new_environ;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* check for contiguous argv strings
|
||||
*/
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
if (i == 0 || end_of_area + 1 == argv[i])
|
||||
end_of_area = argv[i] + strlen(argv[i]);
|
||||
}
|
||||
|
||||
if (end_of_area == NULL) /* probably can't happen? */
|
||||
{
|
||||
ps_buffer = NULL;
|
||||
ps_buffer_size = 0;
|
||||
return argv;
|
||||
}
|
||||
|
||||
/*
|
||||
* check for contiguous environ strings following argv
|
||||
*/
|
||||
for (i = 0; environ[i] != NULL; i++)
|
||||
{
|
||||
if (end_of_area + 1 == environ[i])
|
||||
end_of_area = environ[i] + strlen(environ[i]);
|
||||
}
|
||||
|
||||
ps_buffer = argv[0];
|
||||
last_status_len = ps_buffer_size = end_of_area - argv[0];
|
||||
|
||||
/*
|
||||
* move the environment out of the way
|
||||
*/
|
||||
new_environ = (char **) malloc((i + 1) * sizeof(char *));
|
||||
for (i = 0; environ[i] != NULL; i++)
|
||||
new_environ[i] = strdup(environ[i]);
|
||||
new_environ[i] = NULL;
|
||||
environ = new_environ;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're going to change the original argv[] then make a copy for
|
||||
* argument parsing purposes.
|
||||
*
|
||||
* (NB: do NOT think to remove the copying of argv[], even though
|
||||
* postmaster.c finishes looking at argv[] long before we ever consider
|
||||
* changing the ps display. On some platforms, getopt() keeps pointers
|
||||
* into the argv array, and will get horribly confused when it is
|
||||
* re-called to analyze a subprocess' argument string if the argv storage
|
||||
* has been clobbered meanwhile. Other platforms have other dependencies
|
||||
* on argv[].
|
||||
*/
|
||||
{
|
||||
char **new_argv;
|
||||
int i;
|
||||
|
||||
new_argv = (char **) malloc((argc + 1) * sizeof(char *));
|
||||
for (i = 0; i < argc; i++)
|
||||
new_argv[i] = strdup(argv[i]);
|
||||
new_argv[argc] = NULL;
|
||||
|
||||
argv = new_argv;
|
||||
}
|
||||
|
||||
return argv;
|
||||
|
||||
}
|
||||
|
||||
#endif //
|
||||
@@ -0,0 +1,38 @@
|
||||
/***************************************************************************
|
||||
Process rename functions
|
||||
-----------------------------------------
|
||||
begin : 2013/06/21
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev 1 Team
|
||||
email : dev1@solbox.com
|
||||
version : 3.2.0
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __PROCESS_RENAME_H__
|
||||
#define __PROCESS_RENAME_H__
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @brief Process Title을 변경
|
||||
void set_ps_display(const char *activity, bool force);
|
||||
void set_ps_display_in(const char *activity, bool force);
|
||||
|
||||
/// @brief main에 argv의 실제 위치를 기억하고 새로은 메모리 활당하여 반환
|
||||
char ** save_ps_display_args(int argc, char **argv);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif // __PROCESS_RENAME_H__
|
||||
@@ -0,0 +1,89 @@
|
||||
/***************************************************************************
|
||||
System signal Class ( signal_handle.cpp )
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/03/18
|
||||
copyright : (C) 2013 Solbox Inc.
|
||||
author : Development 1 Team
|
||||
- 2015/03/19 - 1st dadamin
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.5.0
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#include <cstddef>
|
||||
#include <string.h>
|
||||
#include "Signal_handle.h"
|
||||
|
||||
Signal_Handler *Signal_Handler::instance_ = NULL;
|
||||
Event_Handler *Signal_Handler::signal_handlers_[NSIG];
|
||||
|
||||
Signal_Handler::Signal_Handler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Signal_Handler::~Signal_Handler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Signal_Handler* Signal_Handler::instance()
|
||||
{
|
||||
if(!Signal_Handler::instance_)
|
||||
Signal_Handler::instance_ = new Signal_Handler();
|
||||
return Signal_Handler::instance_;
|
||||
}
|
||||
|
||||
Event_Handler * Signal_Handler::register_handler(int signum,
|
||||
Event_Handler *eh)
|
||||
{
|
||||
// Copy the <old_eh> from the <signum> slot in
|
||||
// the <signal_handlers_> table.
|
||||
Event_Handler *old_eh =
|
||||
Signal_Handler::signal_handlers_[signum];
|
||||
|
||||
// Store <eh> into the <signum> slot in the
|
||||
// <signal_handlers_> table.
|
||||
Signal_Handler::signal_handlers_[signum] = eh;
|
||||
|
||||
// Register the <dispatcher> to handle this
|
||||
// <signum>.
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = Signal_Handler::dispatcher;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction(signum, &sa, 0);
|
||||
|
||||
return old_eh;
|
||||
}
|
||||
|
||||
void Signal_Handler::dispatcher(int signum)
|
||||
{
|
||||
// Perform a sanity check...
|
||||
if (Signal_Handler::signal_handlers_[signum] != 0)
|
||||
// Dispatch the handler's hook method.
|
||||
Signal_Handler::signal_handlers_[signum]->handle_signal(signum);
|
||||
}
|
||||
|
||||
int Signal_Handler::remove_handler(int signum)
|
||||
{
|
||||
Signal_Handler::signal_handlers_[signum] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Signal_Handler::register_ignore(int signum)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
int retval = sigaction(signum, &sa, 0);
|
||||
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/***************************************************************************
|
||||
System signal Class Header ( signal_handle.h )
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/03/18
|
||||
copyright : (C) 2013 Solbox Inc.
|
||||
author : Development 1 Team
|
||||
- 2015/03/19 - 1st dadamin
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.5.0
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __CLASS_SIGNAL_HANDLER__
|
||||
#define __CLASS_SIGNAL_HANDLER__
|
||||
|
||||
// reference http://www.cs.wustl.edu/~schmidt/signal-patterns.html
|
||||
|
||||
#include </usr/include/sys/signal.h>
|
||||
#include <csignal>
|
||||
|
||||
class Event_Handler
|
||||
{
|
||||
public:
|
||||
// Hook method for the signal hook method.
|
||||
virtual int handle_signal(int signum) = 0;
|
||||
|
||||
// ... other hook methods for other types of
|
||||
// events such as timers, I/O, and
|
||||
// synchronization objects.
|
||||
};
|
||||
|
||||
class Signal_Handler
|
||||
{
|
||||
public:
|
||||
// Entry point.
|
||||
static Signal_Handler *instance();
|
||||
|
||||
// Register an event handler <eh> for <signum>
|
||||
// and return a pointer to any existing <Event_Handler>
|
||||
// that was previously registered to handle <signum>.
|
||||
Event_Handler *register_handler(int signum,
|
||||
Event_Handler *eh);
|
||||
|
||||
// Remove the <Event_Handler> for <signum>
|
||||
// by setting the slot in the <signal_handlers_>
|
||||
// table to NULL.
|
||||
int remove_handler(int signum);
|
||||
|
||||
// Register ignore signal
|
||||
int register_ignore(int signum);
|
||||
private:
|
||||
// Ensure we're a Singleton.
|
||||
Signal_Handler();
|
||||
~Signal_Handler();
|
||||
|
||||
// Singleton pointer.
|
||||
static Signal_Handler *instance_;
|
||||
|
||||
// Entry point adapter installed into <sigaction>
|
||||
// (must be a static method or a stand-alone
|
||||
// extern "C" function).
|
||||
static void dispatcher(int signum);
|
||||
|
||||
// Table of pointers to concrete <Event_Handler>s
|
||||
// registered by applications. NSIG is the number of
|
||||
// signals defined in </usr/include/sys/signal.h>.
|
||||
static Event_Handler *signal_handlers_[NSIG];
|
||||
};
|
||||
|
||||
#endif // __CLASS_SIGNAL_HANDLER__
|
||||
@@ -0,0 +1,179 @@
|
||||
/***************************************************************************
|
||||
String.cpp
|
||||
-----------------------------------------
|
||||
begin : 2011/01/07
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
#include "String.h"
|
||||
#include "Logger.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
CString::CString()
|
||||
{
|
||||
}
|
||||
|
||||
CString::~CString()
|
||||
{
|
||||
}
|
||||
|
||||
string CString::Quotation( const string str )
|
||||
{
|
||||
if( str.empty () )
|
||||
{
|
||||
return "''";
|
||||
}
|
||||
|
||||
return "'" + str + "'";
|
||||
}
|
||||
|
||||
string CString::IntToStr( int value )
|
||||
{
|
||||
char tmp[32];
|
||||
memset( tmp, 0, 32 );
|
||||
|
||||
sprintf( tmp, "%d", value );
|
||||
|
||||
return string( tmp );
|
||||
}
|
||||
|
||||
string CString::LongToStr( long long value )
|
||||
{
|
||||
char tmp[32];
|
||||
memset( tmp, 0, 32 );
|
||||
|
||||
sprintf( tmp, "%lld", value );
|
||||
|
||||
return string( tmp );
|
||||
}
|
||||
|
||||
std::string CString::DoubleToStr( double value, int point )
|
||||
{
|
||||
string format = "%." + IntToStr( point ) + "f";
|
||||
|
||||
char tmp[32];
|
||||
memset( tmp, 0, 32 );
|
||||
sprintf( tmp, format.c_str(), value );
|
||||
|
||||
return string( tmp );
|
||||
}
|
||||
|
||||
string CString::Replace( const string srcStr, const string targetStr, const string replacedStr )
|
||||
{
|
||||
size_t found;
|
||||
size_t pos = 0;
|
||||
|
||||
string::iterator it;
|
||||
|
||||
string originSrcString = srcStr;
|
||||
|
||||
for( it = originSrcString.begin(); it != originSrcString.end(); ++it)
|
||||
{
|
||||
found = originSrcString.find(targetStr, pos);
|
||||
|
||||
if( found == string::npos )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
originSrcString.replace( found, targetStr.length (), replacedStr );
|
||||
|
||||
pos = found + replacedStr.length();
|
||||
}
|
||||
|
||||
|
||||
return originSrcString;
|
||||
}
|
||||
|
||||
string CString::LTrim( const string srcString, char del )
|
||||
{
|
||||
string originSrcString = srcString;
|
||||
|
||||
string::iterator it = originSrcString.begin();
|
||||
|
||||
while( it != originSrcString.end() )
|
||||
{
|
||||
if( del != *it )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
originSrcString.erase( it );
|
||||
|
||||
}
|
||||
|
||||
return originSrcString;
|
||||
}
|
||||
|
||||
string CString::RTrim( const string srcString, char del )
|
||||
{
|
||||
string originSrcString = srcString;
|
||||
|
||||
string::iterator it = --(originSrcString.end());
|
||||
|
||||
while( it >= originSrcString.begin() )
|
||||
{
|
||||
if( del != *it )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
originSrcString.erase( it-- );
|
||||
}
|
||||
|
||||
return originSrcString;
|
||||
}
|
||||
|
||||
string CString::Trim( const string srcString )
|
||||
{
|
||||
return LTrim( RTrim( srcString ) );
|
||||
}
|
||||
|
||||
vector<string> CString::Tokenize( string srcString, string token )
|
||||
{
|
||||
size_t found;
|
||||
size_t pos = 0;
|
||||
|
||||
vector<string> vTokendStringList;
|
||||
string tokenizedString;
|
||||
size_t tokendStringSize = 0;
|
||||
|
||||
string::iterator it;
|
||||
|
||||
for( it = srcString.begin(); it != srcString.end(); ++it)
|
||||
{
|
||||
found = srcString.find( token, pos );
|
||||
|
||||
if( found == string::npos )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
tokendStringSize = found - pos;
|
||||
tokenizedString = Trim( srcString.substr( pos, tokendStringSize ) );
|
||||
vTokendStringList.push_back( tokenizedString );
|
||||
pos = found + token.length();
|
||||
}
|
||||
|
||||
if( pos != 0 )
|
||||
{
|
||||
tokendStringSize = srcString.length() - pos;
|
||||
tokenizedString = Trim( srcString.substr( pos, tokendStringSize ) );
|
||||
vTokendStringList.push_back( tokenizedString );
|
||||
}
|
||||
else
|
||||
{
|
||||
vTokendStringList.push_back( Trim( srcString ) );
|
||||
}
|
||||
|
||||
return vTokendStringList;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
String.h
|
||||
-----------------------------------------
|
||||
begin : 2011/01/07
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
소스 수정 히스토리
|
||||
|
||||
작성자 작성일 Revision 내용
|
||||
장희준 2011/01/07 ? ADD - 최초 등록
|
||||
***************************************************************************/
|
||||
#ifndef __STRING_H__
|
||||
#define __STRING_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class CString
|
||||
{
|
||||
// Attributes
|
||||
private:
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
// Operations
|
||||
private:
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
CString();
|
||||
virtual ~CString();
|
||||
|
||||
static std::string Quotation( const std::string str );
|
||||
static std::string IntToStr( int value );
|
||||
static std::string LongToStr( long long value );
|
||||
static std::string DoubleToStr( double value, int point );
|
||||
static std::string Replace( const std::string srcStr, const std::string targetStr, const std::string replacedStr );
|
||||
static std::string LTrim( const std::string srcString, char del = ' ' );
|
||||
static std::string RTrim( const std::string srcString, char del = ' ' );
|
||||
static std::string Trim( const std::string srcString );
|
||||
|
||||
static std::vector<std::string> Tokenize( const std::string srcStr, const std::string token );
|
||||
};
|
||||
|
||||
#endif// __STRING_H__
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "Worker.h"
|
||||
#include <sstream>
|
||||
|
||||
#include "Logger.h"
|
||||
#include "DaemonConfigs.h"
|
||||
|
||||
|
||||
|
||||
CWorker::CWorker()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CWorker::~CWorker()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
pid_t CWorker::Launcher(const sig_atomic_t *sighandle)
|
||||
{
|
||||
Fork();
|
||||
|
||||
if (m_pid == 0)
|
||||
{
|
||||
|
||||
while (*sighandle == 0)
|
||||
{
|
||||
// work
|
||||
set_ps_display("Worker [log management process]", false);
|
||||
do_work(sighandle);
|
||||
|
||||
// signal 받은 경우 wait 불필요
|
||||
if(*sighandle == 0)
|
||||
{
|
||||
pause();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO : 워커 종료시에 필요한 부분을 코딩하면 된다.
|
||||
// ....
|
||||
|
||||
m_launched = false;
|
||||
}
|
||||
|
||||
return m_pid;
|
||||
}
|
||||
|
||||
|
||||
void CWorker::do_work(const sig_atomic_t *sighandle)
|
||||
{
|
||||
SetThreadSignal(SIGINT);
|
||||
SetThreadSignal(SIGTERM);
|
||||
|
||||
if( m_objLogFileCleaner.ThreadInit(sighandle) == false )
|
||||
{
|
||||
UnSetThreadSignal(SIGINT);
|
||||
UnSetThreadSignal(SIGTERM);
|
||||
LOG(LERR, "Log Cleaner init failed.");
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
}
|
||||
if( m_objLogFileSender.ThreadInit(sighandle) == false )
|
||||
{
|
||||
UnSetThreadSignal(SIGINT);
|
||||
UnSetThreadSignal(SIGTERM);
|
||||
LOG(LERR, "Log Sender init failed.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if( m_objLogFileCleaner.Start() == false )
|
||||
{
|
||||
UnSetThreadSignal(SIGINT);
|
||||
UnSetThreadSignal(SIGTERM);
|
||||
LOG(LERR, "Log Cleaner startfailed.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if( m_objLogFileSender.Start() == false )
|
||||
{
|
||||
UnSetThreadSignal(SIGINT);
|
||||
UnSetThreadSignal(SIGTERM);
|
||||
LOG(LERR, "Log Sender startfailed.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
UnSetThreadSignal(SIGINT);
|
||||
UnSetThreadSignal(SIGTERM);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/***************************************************************************
|
||||
Process Test Class
|
||||
-----------------------------------------
|
||||
begin : 2015/10/03
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev 1 Team
|
||||
email : dev1@solbox.com
|
||||
version : 3.2.0
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __WROK_FHS_INFO_UPDATER_H__
|
||||
#define __WROK_FHS_INFO_UPDATER_H__
|
||||
|
||||
#include "Process.h"
|
||||
#include "LogFileCleaner.h"
|
||||
#include "LogFileSender.h"
|
||||
|
||||
class CWorker : public CProcess
|
||||
{
|
||||
public:
|
||||
CWorker();
|
||||
virtual ~CWorker();
|
||||
|
||||
pid_t Launcher(const sig_atomic_t *sighandle);
|
||||
|
||||
|
||||
private:
|
||||
void do_work(const sig_atomic_t *sighandle);
|
||||
CLogFileCleaner m_objLogFileCleaner;
|
||||
|
||||
CLogFileSender m_objLogFileSender;
|
||||
};
|
||||
|
||||
#endif // __WROK_FHS_INFO_UPDATER_H__
|
||||
|
||||
Reference in New Issue
Block a user