base
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
|
||||
Revision 1513
|
||||
-------------------
|
||||
수정일 : 2020-11-09
|
||||
수정자 : 유희곤
|
||||
|
||||
- CHG: lib/Makefile 수정 (#33297)
|
||||
- 컴파일 warning 발생 관련 미지원 -Wimplicit 구문 항목 제거
|
||||
|
||||
- CHG: FreeBSD 12.2 컴파일시 오류 발생 관련 header 추가 (#33297)
|
||||
- src/ArgParser.cpp 의 _exit() 사용 컴파일 오류 발생 관련 #include <unistd.h> 구문 추가
|
||||
- src/LogFileProcessThread.cpp 의 unlink(), sleep() 사용 컴파일 오류 발생 관련 #include <unistd.h> 구문 추가
|
||||
|
||||
- CHG: src/Makefile 수정
|
||||
- 컴파일 최적화 옵션 O3 -> O2 로 변경
|
||||
-- 최적화 관련 FreeBSD core 파일 생성 이슈가 있어 기본 최적화 옵션 변경 처리함
|
||||
- pgsql 관련 INCLUDE, LIBS 항목 제거
|
||||
-- pgsql 모듈 미사용하는데.. Makefile 상에 포함되어 있어 제거 처리함.
|
||||
|
||||
- CHG: 소스 파일 인코딩을 cp949 -> UTF-8 로 변경 처리
|
||||
- 최근 개발 장비들 인코딩을 UTF-8 로 구성 중이라서 이에 적합하도록
|
||||
- 모든 소스 파일을 UTF-8 로 변환 처리함.
|
||||
|
||||
|
||||
Revision 1414
|
||||
-------------------
|
||||
수정일 : 2017-03-29
|
||||
수정자 : 유희곤
|
||||
|
||||
- BUG: Apache 로그 전송시 당일 로그까지 전송 (#30594)
|
||||
- 로그 파일명에서 날짜 정보 비교시 .log 확장자까지 비교하여...
|
||||
- Apache 로그가 전송되는 상황 발생.
|
||||
- 수정내역: LogFileSender.cpp 의 IsTodayFile() 함수 수정
|
||||
|
||||
- CHG: src/Makefile 수정
|
||||
- 불필요한 APACHE 설정 정보 제거
|
||||
|
||||
- CHG: 기타
|
||||
- 잘못된 문구, 주석 내역 수정
|
||||
- help 및 버전 표시 내역 가독성 향상
|
||||
- 로그 메시지 가독성 향상.
|
||||
|
||||
|
||||
Revision 1288
|
||||
-------------------
|
||||
수정일 : 2015-11-06
|
||||
수정자 : 김오종
|
||||
|
||||
- CHG: unix용 set_ps_display() 수정
|
||||
- 확인 결과 set_ps_display()함수에서 프로그램 명을 별도로 추가하지 않는 것을 확인
|
||||
- ProcessRename.cpp ProcessRename.h 소스를 수정하여 동일하게 표시되도록 수정 완료
|
||||
|
||||
|
||||
Revision 1262
|
||||
-------------------
|
||||
수정일 : 2015-10-13
|
||||
수정자 : 김오종
|
||||
|
||||
- NEW: SVN 신규 등록
|
||||
- Version 3.5.1262 요구 사항을 반영한 logmngd 소스 등록
|
||||
@@ -0,0 +1,37 @@
|
||||
#****************************************************************************
|
||||
# Makefile for fimngd ( FHS Internal Management Daemon )
|
||||
# -----------------------------------------
|
||||
#
|
||||
# begin : 2015/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.
|
||||
#*****************************************************************************
|
||||
|
||||
SUBDIRS = lib src
|
||||
|
||||
.PHONY: all $(SUBDIRS)
|
||||
|
||||
|
||||
all: $(SUBDIRS)
|
||||
sync;
|
||||
|
||||
|
||||
$(SUBDIRS):
|
||||
$(MAKE) all -C $@
|
||||
|
||||
|
||||
install:
|
||||
@for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) install); done
|
||||
|
||||
|
||||
clean:
|
||||
@for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) clean); done
|
||||
|
||||
|
||||
# End of Makefile
|
||||
@@ -0,0 +1,580 @@
|
||||
#include "BaseSocket.h"
|
||||
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#define SOCKET_NOT_VALID -1
|
||||
#define MAX_SEND_RETRY_COUNT 10 // Socket send 실패시 최대 재전송 시도 횟수.
|
||||
|
||||
|
||||
/// @brief 생성자.
|
||||
/// @param socket [in] 처리할 socket descriptor
|
||||
CBaseSocket::CBaseSocket( const int& socket )
|
||||
: m_sock( socket )
|
||||
{
|
||||
if( m_sock < 0 )
|
||||
{
|
||||
m_sock = SOCKET_NOT_VALID;
|
||||
m_bConnected = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 소멸자
|
||||
CBaseSocket::~CBaseSocket()
|
||||
{
|
||||
// 소멸자 Socket 명시적 Close 처리.
|
||||
Close();
|
||||
}
|
||||
|
||||
/// @brief 소켓의 Close 처리를 수행함.
|
||||
void CBaseSocket::Close()
|
||||
{
|
||||
m_bConnected = false;
|
||||
|
||||
if( m_sock != SOCKET_NOT_VALID )
|
||||
{
|
||||
close( m_sock );
|
||||
m_sock = SOCKET_NOT_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 전달받은 Target 으로 Socket 접속을 수행
|
||||
/// @param szTarget [in] 접속 대상 Host name 또는 IP
|
||||
/// @param nPort [in] 접속 Port
|
||||
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
|
||||
bool CBaseSocket::Connect( const std::string& szTarget, int nPort )
|
||||
{
|
||||
// 기존 접속을 Close 처리
|
||||
Close();
|
||||
|
||||
unsigned int nHost = ConversionAddr( szTarget.c_str() );
|
||||
if( nHost == INADDR_NONE )
|
||||
{
|
||||
LOG( LERR, "target host name resolve fail. [%s]->INADDR_NONE", szTarget.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in stTargetAddr;
|
||||
|
||||
m_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if( m_sock == -1 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
|
||||
LOG( LERR, "socket create failed.[%d][%s] Target:[%s]", errorNum, strerror(errorNum), szTarget.c_str() );
|
||||
|
||||
m_sock = SOCKET_NOT_VALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
stTargetAddr.sin_family = AF_INET;
|
||||
stTargetAddr.sin_addr.s_addr = nHost;
|
||||
stTargetAddr.sin_port = htons( nPort );
|
||||
|
||||
// NEW 2012-05-18 huibong
|
||||
// Connnection 종료시 많은 TIME_WAIT 상태 발생으로 인해 .. 이를 제거하기 위해 SO_LINGER 옵션을 설정처리한다.
|
||||
struct linger opt_linger;
|
||||
opt_linger.l_onoff = 1; /* LINGER ON */
|
||||
|
||||
// CHG 2014-05-27 huibong
|
||||
// 아래와 같이 No Wait 로 처리할 경우... Server 역활 수행 중 Close 신호를 받지 못하는 경우가 발생 가능함.
|
||||
// 따라서 5 sec 정도 대기하도록 수정 처리한다.
|
||||
//opt_linger.l_linger = 0; /* No Wait => 0 for abortive disconnect */
|
||||
opt_linger.l_linger = 5; // 5 sec 대기
|
||||
|
||||
int result = setsockopt( m_sock, SOL_SOCKET, SO_LINGER, &opt_linger, sizeof(opt_linger));
|
||||
if( result != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "setsockopt func SO_LINGER set fail.[%d][%s]", errorNum, strerror(errorNum));
|
||||
|
||||
}
|
||||
|
||||
/* Send Timeout 설정. */
|
||||
struct timeval tv_timeo = { 5, 0 };
|
||||
|
||||
result = setsockopt( m_sock, SOL_SOCKET, SO_SNDTIMEO, &tv_timeo, sizeof(tv_timeo));
|
||||
if( result != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "setsockopt func SO_SNDTIMEO set fail.[%d][%s]", errorNum, strerror(errorNum));
|
||||
|
||||
}
|
||||
|
||||
if(connect(m_sock, (struct sockaddr *)&stTargetAddr, sizeof(stTargetAddr)) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "connect [%s] fail.[%d][%s]", szTarget.c_str(), errorNum, strerror(errorNum));
|
||||
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bConnected = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
|
||||
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
|
||||
bool CBaseSocket::IsValidSocket()
|
||||
{
|
||||
if( m_sock != SOCKET_NOT_VALID && m_bConnected == true )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief m_sock 으로부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t CBaseSocket::Read( void * vptr, size_t size )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
while( (nRead = read( m_sock, vptr, size )) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if( errorNum == ECONNRESET ) // 2010-07-23 BUG huibong 잘못된 대입연산자를 비교연산자로 수정.
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return nRead;
|
||||
}
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t CBaseSocket::ReadN( void * vptr, size_t size )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
size_t nLeft = size;
|
||||
char * ptr = (char *)vptr;
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
if( (nRead = read( m_sock, ptr, nLeft )) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if( errorNum == ECONNRESET )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류 , -2: Timeout
|
||||
ssize_t CBaseSocket::ReadNTimeout( void * vptr, size_t size, int timeout )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
size_t nLeft = size;
|
||||
char * ptr = (char *)vptr;
|
||||
|
||||
struct timeval timeOver;
|
||||
int result;
|
||||
|
||||
fd_set selectFds;
|
||||
FD_ZERO( &selectFds );
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
timeOver.tv_sec = timeout;
|
||||
timeOver.tv_usec = 0;
|
||||
FD_SET( m_sock, &selectFds );
|
||||
|
||||
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
|
||||
|
||||
if( result > 0 )
|
||||
{
|
||||
if( FD_ISSET( m_sock, &selectFds ))
|
||||
{
|
||||
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if(errorNum == ECONNRESET)
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
}
|
||||
|
||||
}
|
||||
else if( result == 0 ) // Timeout
|
||||
{
|
||||
//LOG( LDBG, "read timeout");
|
||||
return -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
|
||||
ssize_t CBaseSocket::ReadNTimeout2( void * vptr, size_t size, int timeout )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
size_t nLeft = size;
|
||||
char * ptr = (char *)vptr;
|
||||
int errorNum;
|
||||
|
||||
// 우선은 읽기 시도.
|
||||
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
|
||||
{
|
||||
errorNum = errno;
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nRead = 0;
|
||||
}
|
||||
else if( errorNum == ECONNRESET )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
|
||||
// 만약 더 받을 데이터가 존재한다면.
|
||||
if( nLeft > 0 )
|
||||
{
|
||||
struct timeval timeOver;
|
||||
int result;
|
||||
|
||||
fd_set selectFds;
|
||||
FD_ZERO( &selectFds );
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
timeOver.tv_sec = timeout;
|
||||
timeOver.tv_usec = 0;
|
||||
FD_SET( m_sock, &selectFds );
|
||||
|
||||
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
|
||||
|
||||
if( result > 0 )
|
||||
{
|
||||
if( FD_ISSET( m_sock, &selectFds ))
|
||||
{
|
||||
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
|
||||
{
|
||||
errorNum = errno;
|
||||
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if(errorNum == ECONNRESET)
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
}
|
||||
}
|
||||
else if( result == 0 ) // Timeout
|
||||
{
|
||||
//LOG( LDBG, "read timeout");
|
||||
return -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorNum = errno;
|
||||
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
|
||||
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
|
||||
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
|
||||
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
|
||||
/// @param size [in] write 하고자 하는 데이터의 크기.
|
||||
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t CBaseSocket::WriteN( const void * vptr, size_t size )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
size_t nLeft;
|
||||
ssize_t nWrite;
|
||||
|
||||
const char * ptr = (const char *)vptr;
|
||||
nLeft = size;
|
||||
|
||||
int nTryCount = 0;
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
if( (nWrite = send( m_sock, ptr, nLeft, 0 )) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nWrite = 0;
|
||||
++nTryCount;
|
||||
}
|
||||
else if( errorNum == ECONNRESET )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "send func fail.[%d][%s]", errorNum, strerror(errorNum));
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nWrite == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( nTryCount > MAX_SEND_RETRY_COUNT )
|
||||
{
|
||||
LOG( LERR, "send func failure due to exceeding count of retry[%d/%d]", nTryCount, MAX_SEND_RETRY_COUNT );
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
nLeft -= nWrite;
|
||||
ptr += nWrite;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// CHG 2011-05-03 huibong
|
||||
// gethostbyname() 함수가 Thread Safe 하지 않기 때문에
|
||||
// DNS resolve 처리시 잘못된 정보를 반환할 가능성이 존재
|
||||
// 이에 따라 본 함수를 수정처리함.
|
||||
/*
|
||||
unsigned int CBaseSocket::ConversionAddr( const char * name )
|
||||
{
|
||||
struct hostent *he;
|
||||
int max;
|
||||
unsigned int retval;
|
||||
|
||||
if ((retval = inet_addr(name)) != INADDR_NONE)
|
||||
return retval;
|
||||
|
||||
he = gethostbyname(name);
|
||||
if (he == NULL)
|
||||
return INADDR_NONE;
|
||||
|
||||
for (max = 0; he->h_addr_list[max]; max++) ;
|
||||
if (max == 1)
|
||||
return *((unsigned int *)(he->h_addr_list[0]));
|
||||
else
|
||||
return *((unsigned int *)(he->h_addr_list[random() % max]));
|
||||
}
|
||||
*/
|
||||
|
||||
unsigned int CBaseSocket::ConversionAddr( const char * name )
|
||||
{
|
||||
unsigned int retval;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result = NULL;
|
||||
int error;
|
||||
|
||||
|
||||
// 전달받은 정보가 IP 주소인 경우...
|
||||
// - DNS resolve 할 필요 없이 변환시킨 값을 그대로 사용한다.
|
||||
if( (retval = inet_addr(name)) != INADDR_NONE )
|
||||
return retval;
|
||||
|
||||
// getaddrinfo() 함수 호출을 위한 Hint 설정
|
||||
memset( &hints, 0x00, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
// Thread Safe 한 DNS Resolve 처리함수 호출
|
||||
// int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
|
||||
|
||||
// CHG 2014-11-14 huibong
|
||||
// getaddrinfo 호출시 종종 EAI_NONAME 오류가 반환됨. (#20783)
|
||||
// - 따라서 오류 반환시 재시도하도록 기능 추가
|
||||
for( int count = 0 ; count < 3; count++ )
|
||||
{
|
||||
error = getaddrinfo( name, NULL, &hints, &result );
|
||||
|
||||
// 오류 발생시
|
||||
if( error != 0 )
|
||||
{
|
||||
if( result != NULL)
|
||||
{
|
||||
freeaddrinfo(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
// 잠시 대기 후 재시도 처리
|
||||
usleep(500000);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상 처리된 경우...
|
||||
// - loop 탈출
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 최종 오류 발생시
|
||||
if( error != 0 )
|
||||
{
|
||||
LOG( LERR, "name[%s] dns resolve fail. getaddrinfo return error [%d][%s]", name, error, gai_strerror(error) );
|
||||
return INADDR_NONE;
|
||||
}
|
||||
|
||||
struct sockaddr_in * addr = (struct sockaddr_in *)result->ai_addr;
|
||||
retval = (unsigned int)(addr->sin_addr.s_addr);
|
||||
|
||||
// DNS Resovle 결과 확인용 코드
|
||||
/*
|
||||
struct addrinfo *temp;
|
||||
for( temp = result; temp; temp = temp->ai_next )
|
||||
{
|
||||
addr = (struct sockaddr_in *)temp->ai_addr;
|
||||
printf ("getaddrinfo result = %s\n",inet_ntoa( addr->sin_addr));
|
||||
}
|
||||
*/
|
||||
|
||||
// getaddrinfo() 함수에서 생성한 메모리 영역 해제 처리.
|
||||
freeaddrinfo(result);
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/***************************************************************************
|
||||
BaseSocket ( Base Socket Class )
|
||||
-----------------------------------------
|
||||
begin : 2010/03/02
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
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.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __LIBRARY_BASE_SOCKET_H__
|
||||
#define __LIBRARY_BASE_SOCKET_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <string>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
#define SOCKET_NOT_VALID -1
|
||||
#define DEFAULT_DATA_RECEIVE_TIMEOUT 15 // sec
|
||||
|
||||
|
||||
class CBaseSocket
|
||||
{
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief socket descriptor
|
||||
int m_sock;
|
||||
|
||||
/// @brief socket 의 연결상태인지 여부를 저장하기 위한 변수.
|
||||
bool m_bConnected;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/// @brief 생성자.
|
||||
CBaseSocket( const int & socket );
|
||||
|
||||
/// @brief 소멸자.
|
||||
~CBaseSocket();
|
||||
|
||||
/// @brief 소켓의 Close 처리를 수행함.
|
||||
void Close(void);
|
||||
|
||||
/// @brief 전달받은 Target 으로 Socket 접속을 수행
|
||||
/// @param szTarget [in] 접속 대상 Host name 또는 IP
|
||||
/// @param nPort [in] 접속 Port
|
||||
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
|
||||
bool Connect( const std::string& szTarget, int nPort );
|
||||
|
||||
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
|
||||
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
|
||||
bool IsValidSocket(void);
|
||||
|
||||
/// @brief 멤버변수인 socket 의 접속 상태 여부를 설정하기 위한 함수.
|
||||
void SetConnectionStatus( bool bConnected) { m_bConnected = bConnected; }
|
||||
|
||||
/// @brief 현재 socket 의 접속 상태를 반환.
|
||||
bool GetConnectionStatus( void) { return m_bConnected; }
|
||||
|
||||
//void SetLogger( Logger * pLog ) { m_pLog = pLog; }
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief m_sock 로 부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t Read( void * vptr, size_t size );
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t ReadN( void * vptr, size_t size );
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
|
||||
ssize_t ReadNTimeout( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
|
||||
ssize_t ReadNTimeout2( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
|
||||
|
||||
public:
|
||||
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
|
||||
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
|
||||
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
|
||||
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
|
||||
/// @param size [in] write 하고자 하는 데이터의 크기.
|
||||
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t WriteN( const void * vptr, size_t size );
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief 문자열로 전달받은 정보를 검사하여 IP 접속 정보를 생성한다.
|
||||
unsigned int ConversionAddr( const char * name );
|
||||
|
||||
};
|
||||
|
||||
#endif /* __LIBRARY_BASE_SOCKET_H__ */
|
||||
@@ -0,0 +1,215 @@
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <boost/algorithm/string.hpp> // use boost
|
||||
|
||||
|
||||
Config::Config()
|
||||
: m_keyDelimiter( CONFIG_DEFAULT_KEY_DELIMITER )
|
||||
, m_valueDelimiter( CONFIG_DEFAULT_VALUE_DELIMITER )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// @brief destructor
|
||||
Config::~Config()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
|
||||
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::Open( const string path )
|
||||
{
|
||||
ifstream file;
|
||||
|
||||
// Config file open
|
||||
file.open( path.c_str());
|
||||
if( file.is_open() == false )
|
||||
{
|
||||
cerr << "[error] " << __FILE__<< ":" << __func__ << ": config file open failed.[" << path << "][" << strerror( errno ) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 기존 데이터가 존재하면 삭제 처리.
|
||||
if( m_configData.empty() == false )
|
||||
m_configData.clear();
|
||||
|
||||
// config file parsing
|
||||
string line;
|
||||
string section;
|
||||
vector< string > configs;
|
||||
|
||||
// 루프를 돌면서 Config 파일을 line 단위로 읽어들인당....
|
||||
while( std::getline( file, line ) )
|
||||
{
|
||||
// 앞뒤 공백 제거 처리
|
||||
boost::trim( line );
|
||||
|
||||
// 공백 or 주석처리 라인 검사
|
||||
if( line.empty() == true || boost::starts_with( line, string("#") ) == true || line == "\r" )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Section 여부 검사
|
||||
if( boost::starts_with( line, string("[") ) == true && boost::ends_with( line, string("]") ) == true )
|
||||
{
|
||||
// [] 로 정의된 section 의 문자열 값 추출
|
||||
line.erase( line.begin() );
|
||||
line.erase( line.end() -1 );
|
||||
boost::trim( line );
|
||||
|
||||
if( section.empty() == false && section != line )
|
||||
{
|
||||
// 이전 세션과 다른 신규 세션인 경우
|
||||
// 기존까지 저장했던 데이터를 멤버 변수에 입력 처리 후 내부변수 초기화 처리.
|
||||
|
||||
m_configData.insert( make_pair( section, configs ) );
|
||||
section.clear();
|
||||
configs.clear();
|
||||
}
|
||||
|
||||
// 신규 section 정보 저장처리.
|
||||
section = line;
|
||||
line.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Section 정보가 아닌 경우 => 실제 설정값 .. ^^
|
||||
configs.push_back( line );
|
||||
}
|
||||
}
|
||||
|
||||
// 마지막 세션 처리된 정보가 존재하는 경우 멤버 변수에 저장 처리.
|
||||
if( section.empty() == false )
|
||||
{
|
||||
m_configData.insert( make_pair( section, configs ) );
|
||||
}
|
||||
|
||||
// 종료 처리.
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
|
||||
/// @return void
|
||||
void Config::Clear()
|
||||
{
|
||||
m_configData.clear();
|
||||
}
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::GetConfig( const string section, const string key, string& value )
|
||||
{
|
||||
// Section 에 대한 임시 데이터 저장객체 생성
|
||||
vector< string > configs;
|
||||
|
||||
// 해당 Section 이 존재하지 않는 경우
|
||||
if( Find( section, configs ) == false )
|
||||
return false;
|
||||
|
||||
string line;
|
||||
string result;
|
||||
vector< string >::const_iterator it;
|
||||
|
||||
// 해당 Key 이 존재하는지 검사
|
||||
for( it = configs.begin(); it != configs.end(); it++)
|
||||
{
|
||||
line = *it;
|
||||
|
||||
// Line 상의 주석 제거
|
||||
string::size_type pos = line.find( '#' );
|
||||
if( pos != string::npos)
|
||||
{
|
||||
line = line.substr(0, pos);
|
||||
boost::trim( line );
|
||||
}
|
||||
|
||||
// key = value 에서 key 부분 추출
|
||||
pos = line.find( m_keyDelimiter );
|
||||
if( pos == string::npos )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = line.substr(0, pos);
|
||||
boost::trim( result );
|
||||
}
|
||||
|
||||
if( key == result )
|
||||
{
|
||||
// Key 값이 동일한 경우
|
||||
value = line.substr( pos+1 );
|
||||
boost::trim( value );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::GetConfig( const string section, const string key, vector< string >& value )
|
||||
{
|
||||
string result;
|
||||
vector< string > vec;
|
||||
|
||||
if( GetConfig( section, key, result ) == false )
|
||||
return false;
|
||||
|
||||
// 전달받은 result 값을 value delimiter 를 이용하여 parsing 처리
|
||||
boost::split( vec, result, boost::is_any_of( m_valueDelimiter ));
|
||||
if( vec.empty() == true )
|
||||
return false;
|
||||
|
||||
// 루프를 돌면서 trim 처리 후 결과값 저장처리.
|
||||
vector< string >::const_iterator it;
|
||||
for( it = vec.begin(); it != vec.end(); it++)
|
||||
{
|
||||
result = boost::trim_copy( *it );
|
||||
|
||||
if( result.empty() == false )
|
||||
value.push_back( result );
|
||||
}
|
||||
|
||||
if( value.empty() == true )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
|
||||
/// @param section [in] section 명
|
||||
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::Find( const string& section, vector<string>& configData )
|
||||
{
|
||||
map< string, vector< string > >::iterator it = m_configData.find( section );
|
||||
if( it != m_configData.end() )
|
||||
{
|
||||
// 해당 section 을 찾은 경우
|
||||
configData = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 해당 section 을 찾지 못한 경우
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/***************************************************************************
|
||||
Config File Parser Class
|
||||
-----------------------------------------
|
||||
begin : 2010/02/27
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
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.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __LIBRARY_CONFIG_H__
|
||||
#define __LIBRARY_CONFIG_H__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
#define CONFIG_DEFAULT_KEY_DELIMITER "="
|
||||
#define CONFIG_DEFAULT_VALUE_DELIMITER ","
|
||||
|
||||
|
||||
/// @brief Config class
|
||||
/// 1. config 파일의 내용을 파싱처리하여 각 Section, Key 에 해당하는 값을 반환처리
|
||||
/// 2. config 파일은 [section] 단위로 구분된다.
|
||||
/// 3. config 파일은 key=value 로 구분가능하며 이는 Delimiter 설정을 통해 변경가능하다.
|
||||
/// 4. value 값이 다중으로 존재하는 경우 "," 값을 통해 구분가능, Delimiter 변경시 다른 값도 사용가능함.
|
||||
/// 5. config 파일상에서 "#" 로 시작하는 문자열은 라인 끝까지 주석으로 처리된다.
|
||||
/// 6. 특정 Key 값에 대한 다중 value 값 조회는 vector<string> 을 통해 수행한다.
|
||||
/// 7. 만약 다중 value 값이 존재시 string 으로 반환받을 경우 해당 Row 가 통째로 반환된다.
|
||||
/// 8. 본 객체는 Open , Clear 함수가 호출되기전까지 이전 Config 정보가 저장된다.
|
||||
class Config
|
||||
{
|
||||
private:
|
||||
/// @brief config information saved variable
|
||||
// string : section data
|
||||
// vector<string> : key=value data
|
||||
map< string, vector< string> > m_configData;
|
||||
|
||||
/// @brief Key, Value 구분자 저장 변수
|
||||
string m_keyDelimiter;
|
||||
string m_valueDelimiter;
|
||||
|
||||
public:
|
||||
/// @brief constructor
|
||||
Config();
|
||||
|
||||
/// @brief destructor
|
||||
~Config();
|
||||
|
||||
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
|
||||
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Open( const string path );
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
|
||||
/// @return void
|
||||
void Clear();
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
|
||||
/// @return On success return true, otherwise return false
|
||||
bool GetConfig( const string section, const string key, string& value );
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool GetConfig( const string section, const string key, vector< string >& value );
|
||||
|
||||
/// @brief Key, Value Delimiter Get 함수
|
||||
/// @param key [out] key delimiter 값
|
||||
/// @param value [out] value delimiter 값
|
||||
void GetDelimiter( string& key, string& value )
|
||||
{
|
||||
key = m_keyDelimiter;
|
||||
value = m_valueDelimiter;
|
||||
}
|
||||
|
||||
// BUG 2010-12-06 huibong
|
||||
// string& value = CONFIG_DEFAULT_VALUE_DELIMITER 값은 문법상 오류 구문임.
|
||||
// gcc 3.4.6 버전에서는 Compile 되나 gcc 4.4.5 에서는 error 로 처리되어 수정처리함.
|
||||
|
||||
/// @brief Key, Value Delimiter Set 함수
|
||||
/// @param key [out] key delimiter 값
|
||||
/// @param value [out] value delimiter 값, 지정하지 않을 경우 Default 값이 사용됨.
|
||||
void SetDelimiter( string& key, string value = CONFIG_DEFAULT_VALUE_DELIMITER )
|
||||
{
|
||||
m_keyDelimiter = key;
|
||||
m_valueDelimiter = value;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
|
||||
/// @param section [in] section 명
|
||||
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Find( const string& section, vector<string>& configData );
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* __LIBRARY_CONFIG_H__ */
|
||||
@@ -0,0 +1,487 @@
|
||||
/***************************************************************************
|
||||
Logger.cpp
|
||||
-----------------------------------------
|
||||
begin : 2011/10/26
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
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 "Logger.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <iostream>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_BUFFER_SIZE 2048 // 임시 버퍼 최대 크기
|
||||
#define DEFAULT_LOG_LEVEL LINF
|
||||
|
||||
using namespace std;
|
||||
|
||||
CLogger* CLogger::m_pInstance = NULL;
|
||||
bool CLogger::m_bIsInitialized = false;
|
||||
pthread_mutex_t CLogger::m_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
|
||||
CLogger::CLogger( string programName, string logDir, int logLevel )
|
||||
{
|
||||
m_szProgramName = programName;
|
||||
m_szLogDir = logDir;
|
||||
|
||||
if( IsValidLogLevel( logLevel ) == true )
|
||||
{
|
||||
m_nLogLevel = logLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nLogLevel = DEFAULT_LOG_LEVEL;
|
||||
}
|
||||
|
||||
MakeLogLevelString();
|
||||
}
|
||||
|
||||
void CLogger::MakeLogLevelString()
|
||||
{
|
||||
m_vectorLogLevelString.push_back( "EMR" );
|
||||
m_vectorLogLevelString.push_back( "ALT" );
|
||||
m_vectorLogLevelString.push_back( "CRT" );
|
||||
m_vectorLogLevelString.push_back( "ERR" );
|
||||
m_vectorLogLevelString.push_back( "WAR" );
|
||||
m_vectorLogLevelString.push_back( "NOT" );
|
||||
m_vectorLogLevelString.push_back( "INF" );
|
||||
m_vectorLogLevelString.push_back( "DBG" );
|
||||
m_vectorLogLevelString.push_back( "DEV" );
|
||||
m_vectorLogLevelString.push_back( "DEV1" );
|
||||
m_vectorLogLevelString.push_back( "DEV2" );
|
||||
}
|
||||
|
||||
CLogger::~CLogger()
|
||||
{
|
||||
m_vectorLogLevelString.clear();
|
||||
}
|
||||
|
||||
bool CLogger::Init( string programName, string logDir, int logLevel )
|
||||
{
|
||||
if( m_bIsInitialized == true )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
pthread_mutex_lock( &m_mutex );
|
||||
|
||||
// 변수 유효성 검사.
|
||||
if( programName.empty() == true || logDir.empty() == true )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( MakeLogDir( programName, logDir ) == false )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( CLogger::m_pInstance != NULL )
|
||||
{
|
||||
delete CLogger::m_pInstance;
|
||||
CLogger::m_pInstance = NULL;
|
||||
}
|
||||
|
||||
CLogger::m_pInstance = new CLogger( programName, logDir, logLevel );
|
||||
m_bIsInitialized = true;
|
||||
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::IsValidLogLevel( int logLevel )
|
||||
{
|
||||
return ( ( logLevel < 0 || logLevel > MAX_LOG_LEVEL ) ? false : true );
|
||||
}
|
||||
|
||||
bool CLogger::SetLogLevel( int logLevel )
|
||||
{
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_nLogLevel = logLevel;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::MakeLogDir( string programName, string logDir )
|
||||
{
|
||||
string path = logDir + "/" + programName;
|
||||
|
||||
struct stat dirStat;
|
||||
|
||||
// 해당 이름을 가진 파일 또는 디렉토리가 존재하고
|
||||
if( lstat( path.c_str(), &dirStat ) == 0 )
|
||||
{
|
||||
// 해당 이름이 디렉토리인 경우
|
||||
if( S_ISDIR( dirStat.st_mode ) == true )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "exist file with the same name as log path(" << path << ")." << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 디렉토리 가 존재하지 않는 경우 디렉토리 생성 시도
|
||||
string cmd = "mkdir -p " + path;
|
||||
system( cmd.c_str() );
|
||||
|
||||
if( IsDirectory( path ) == false )
|
||||
{
|
||||
cerr << "can't make log directory. path=" << path << "." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::IsDirectory( string path )
|
||||
{
|
||||
struct stat dirStat;
|
||||
|
||||
if( lstat ( path.c_str(), &dirStat ) != 0 )
|
||||
{
|
||||
cerr << "Log path not valid. Check path [" << path << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 해당 정보가 Directory 가 아닌 경우
|
||||
if( S_ISDIR( dirStat.st_mode ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLogger::Exit()
|
||||
{
|
||||
if( m_bIsInitialized == false )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock( &m_mutex );
|
||||
|
||||
if( CLogger::m_pInstance != NULL )
|
||||
{
|
||||
delete CLogger::m_pInstance;
|
||||
CLogger::m_pInstance = NULL;
|
||||
m_bIsInitialized = false;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
}
|
||||
|
||||
CLogger* CLogger::GetInstance()
|
||||
{
|
||||
return CLogger::m_pInstance;
|
||||
}
|
||||
|
||||
string CLogger::GetLogFilename( struct tm &timeNow )
|
||||
{
|
||||
char timeStr[256];
|
||||
snprintf( timeStr, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
|
||||
|
||||
// Make File Name
|
||||
string filename = m_szLogDir + "/" + m_szProgramName + "/" + m_szProgramName + "_" + string( timeStr );
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool CLogger::Write( int logLevel, const char * fmt, ...)
|
||||
{
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return Write( logLevel, PREFIX_DATE, NULL, 0, buffer );
|
||||
}
|
||||
|
||||
bool CLogger::WriteNoPrefix( int logLevel, const char * fmt, ...)
|
||||
{
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return Write( logLevel, PREFIX_NONE, NULL, 0, buffer );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// CHG 2012-08-16 huibong
|
||||
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
|
||||
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
|
||||
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
|
||||
// 함수명 : Write -> WriteWithFunc 으로 변경 처리
|
||||
bool CLogger::WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
|
||||
{
|
||||
if( filename == NULL || funcname == NULL || lineNum < 0 || fmt == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
|
||||
char className[255];
|
||||
string funcPrefix = GetClassName( className, filename );
|
||||
funcPrefix += "::" + string( funcname ) + "()";
|
||||
|
||||
return Write( logLevel, PREFIX_FUNCTION, funcPrefix.c_str(), lineNum, buffer );
|
||||
}
|
||||
|
||||
const char* CLogger::GetClassName( char* className, const char* filename )
|
||||
{
|
||||
if( className == NULL )
|
||||
{
|
||||
cout << "[ERROR] The input argument 'className' is NULL." << endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( filename == NULL )
|
||||
{
|
||||
cout << "[ERROR] The input argument 'filename' is NULL." << endl;
|
||||
strcpy( className, "NULL" );
|
||||
return className;
|
||||
}
|
||||
|
||||
int filenameSize = strlen( filename );
|
||||
memcpy( className, filename, filenameSize );
|
||||
|
||||
// find end position
|
||||
char endCharacter = '.';
|
||||
int endPos = filenameSize - 1;
|
||||
for( ; endPos > 0; --endPos )
|
||||
{
|
||||
if( className[endPos] == endCharacter )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( endPos == 0 )
|
||||
{
|
||||
cout << "[ERROR] endPos=0" << endl;
|
||||
strcpy( className, "NULL" );
|
||||
return className;
|
||||
}
|
||||
|
||||
className[endPos] = '\0';
|
||||
|
||||
// find start position
|
||||
char startCharacter = '/';
|
||||
int startPos = endPos - 1;
|
||||
for( ; startPos > 0; --startPos )
|
||||
{
|
||||
if( className[startPos] == startCharacter )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( startPos != 0 )
|
||||
{
|
||||
startPos += 1;
|
||||
}
|
||||
|
||||
return (className + startPos );
|
||||
}
|
||||
|
||||
bool CLogger::Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log )
|
||||
{
|
||||
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
|
||||
if( logLevel > m_nLogLevel )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( log == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Current Data & Time
|
||||
time_t now = time( NULL );
|
||||
struct tm timeNow;
|
||||
localtime_r( &now, &timeNow );
|
||||
|
||||
string filename = GetLogFilename( timeNow );
|
||||
|
||||
// Log file open
|
||||
FILE* pFile = NULL;
|
||||
pFile = fopen( filename.c_str(), "a+" );
|
||||
|
||||
if( pFile == NULL )
|
||||
{
|
||||
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 시간 정보처리
|
||||
char timeStr[256];
|
||||
snprintf( timeStr, (size_t)256, "[%02d:%02d:%02d]"
|
||||
, timeNow.tm_hour, timeNow.tm_min, timeNow.tm_sec );
|
||||
|
||||
// Log Level 문자열 검색
|
||||
string szLevel = m_vectorLogLevelString[ logLevel ];
|
||||
|
||||
switch( logPrefix )
|
||||
{
|
||||
case PREFIX_DATE:
|
||||
/// 형식 예: [15:47:41] [DBG] sample log message.
|
||||
fprintf( pFile, "%s [%-4s] %s\n", timeStr, szLevel.c_str(), log );
|
||||
break;
|
||||
|
||||
case PREFIX_FUNCTION:
|
||||
if( functionName == NULL )
|
||||
{
|
||||
fclose( pFile );
|
||||
return false;
|
||||
}
|
||||
/// 형식 예: [15:47:41] [DBG] sample log message. [SomeClass::SomeFunction():12]
|
||||
fprintf( pFile, "%s [%-4s] %s [%s:%d]\n", timeStr, szLevel.c_str(), log, functionName, lineNum );
|
||||
break;
|
||||
|
||||
case PREFIX_NONE:
|
||||
/// 형식 예: sample log message.
|
||||
fprintf( pFile, "%s\n", log );
|
||||
break;
|
||||
}
|
||||
// Write to log file
|
||||
fflush( pFile );
|
||||
|
||||
// 종료 처리.
|
||||
fclose( pFile );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::WriteHex( int logLevel, const unsigned char* data, const int size )
|
||||
{
|
||||
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
|
||||
if( logLevel > m_nLogLevel )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( data == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( size <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Current Data & Time
|
||||
time_t now = time( NULL );
|
||||
struct tm timeNow;
|
||||
localtime_r( &now, &timeNow );
|
||||
|
||||
string filename = GetLogFilename( timeNow );
|
||||
|
||||
// Log file open
|
||||
FILE* pFile = NULL;
|
||||
pFile = fopen( filename.c_str(), "a+" );
|
||||
|
||||
if( pFile == NULL )
|
||||
{
|
||||
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for( int i = 0; i < size; ++i )
|
||||
{
|
||||
fprintf( pFile, "%02X", data[i] );
|
||||
|
||||
if( i == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( (i+1) % 8 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, " " );
|
||||
}
|
||||
|
||||
if( ( (i+1) % 16 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, " " );
|
||||
}
|
||||
|
||||
if( ( (i+1) % 32 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, "\n" );
|
||||
}
|
||||
}
|
||||
fprintf( pFile, "\n" );
|
||||
fflush( pFile );
|
||||
|
||||
// 종료 처리.
|
||||
fclose( pFile );
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
/***************************************************************************
|
||||
Logger.h
|
||||
-----------------------------------------
|
||||
begin : 2011/10/26
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 3.2.0.805
|
||||
|
||||
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.
|
||||
***************************************************************************/
|
||||
#ifndef __LOGGER_H__
|
||||
#define __LOGGER_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <pthread.h>
|
||||
|
||||
///@brief 로그 레벨 정의
|
||||
#define LEMR 0 /* system is or will be unusable if situation is not resolved */
|
||||
#define LALT 1 /* immediate action required */
|
||||
#define LCRT 2 /* critical situations */
|
||||
#define LERR 3 /* error conditions */
|
||||
#define LWAR 4 /* recoverable errors */
|
||||
#define LNOT 5 /* unusual situation that merits investigation */
|
||||
#define LINF 6 /* information messages */
|
||||
#define LDBG 7 /* verbose data for debugging */
|
||||
#define LDEV 8 /* verbose data for developer */
|
||||
#define LDEV1 9 /* start or end the function of application level */
|
||||
#define LDEV2 10 /* start or end the function of application level */
|
||||
|
||||
#define MAX_LOG_LEVEL LDEV2
|
||||
|
||||
|
||||
///@brief Log 정보를 파일로 저장하기 위한 Class.
|
||||
///1. 가변 format 으로 전달된 로그 관련 정보를 Log Level 에 따라 로그 파일에 아래의 4가지 형식으로 저장한다.
|
||||
///
|
||||
/// 1.1 Prefix로 [hh:mm:ss]와 [ClassName::FunctionName]이 추가된 로그
|
||||
/// LOG( level, format, ... ) 매크로 사용.
|
||||
/// 예) [17:43:40] [DBG] log level debug [LoggerTestTestLogger]
|
||||
///
|
||||
/// 1.2 Prefix로 [hh:mm:ss]이 추가된 로그
|
||||
/// _LOG( level, format, ... ) 매크로 사용
|
||||
/// 예) [17:43:40] [EMR] log level emergency
|
||||
///
|
||||
/// 1.3 Prefix가 없는 로그
|
||||
/// _LOG_( level, format, ... ) 매크로 사용
|
||||
/// 예) log level emergency
|
||||
///
|
||||
/// 1.4 Hex 로그.
|
||||
/// LOG_HEX( level, data, size ) 매크로 사용
|
||||
/// 예) 00010203 04050607 08090A0B 0C0D0E0F
|
||||
///
|
||||
///2. Logger 객체 초기화시 전달된 Log Level 정보보다 전달받은 Log Level 정보가 큰 경우 해당 로그는 파일로 저장되지 않는다.
|
||||
///
|
||||
///3. 로그 파일은 매 일단위로 저장파일이 변경된다.
|
||||
///
|
||||
///4. 로그 저장을 위한 program 경로가 존재하지 않는 경우 자동 생성 처리된다.
|
||||
///
|
||||
///5. 로그 저장방식은 매 저장로그마다 open-close 로 처리된다.
|
||||
///
|
||||
///6. 파일로 기록시 Log Level 에 대한 정보도 함께 기록된다.
|
||||
///
|
||||
///7. 싱글톤으로 작성되었고, CLogger::Init(...)시에 쓰레드 안정성을 제공한다.
|
||||
///
|
||||
///8. 동적으로 로그 레벨을 변경할 수 있는 인터페이스를 제공한다.
|
||||
///
|
||||
class CLogger
|
||||
{
|
||||
// Attributes
|
||||
private:
|
||||
///@brief 싱글톤 객체 인트턴스.
|
||||
static CLogger* m_pInstance;
|
||||
|
||||
///@brief 싱글톤 객체 초기화 여부.
|
||||
static bool m_bIsInitialized;
|
||||
|
||||
///@brief 싱글톤 객체 초기화시 스레드 안정성을 위한 뮤텍스.
|
||||
static pthread_mutex_t m_mutex;
|
||||
|
||||
///@brief 프로그램 이름. 로그 파일 경로를 만들 때 사용.
|
||||
std::string m_szProgramName;
|
||||
|
||||
///@brief 공통 로그 디렉토리 이름. 로그 파일 경로를 만들 때 사용.
|
||||
std::string m_szLogDir;
|
||||
|
||||
///@brief 로그 레벨.
|
||||
int m_nLogLevel;
|
||||
|
||||
///@brief 로그 레벨에 대응되는 문자열 정보를 저장.
|
||||
std::vector<std::string> m_vectorLogLevelString;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
///@brief 로그 형식을 지정.
|
||||
typedef enum
|
||||
{
|
||||
PREFIX_NONE = 0, /// 클래스 설명의 1.3에 해당
|
||||
PREFIX_DATE, /// 클래스 설명의 1.2에 해당
|
||||
PREFIX_FUNCTION, /// 클래스 설명의 1.1에 해당
|
||||
} LOG_PREFIX;
|
||||
|
||||
// Operations
|
||||
private:
|
||||
///@brief 생성자.
|
||||
/// 프로그램 이름, 공통 로그 디렉토리, 로그 레벨을 저장하고
|
||||
/// 로그 레벨에 대응되는 문자열 정보를 만든다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@param logLevel [in] 로그 레벨
|
||||
CLogger( std::string programName, std::string logDir, int logLevel );
|
||||
|
||||
///@brief 소멸자.
|
||||
/// 로그 레벨에 대응되는 문자열 정보를 저장하고 있는
|
||||
/// 벡터 m_vectorLogLevelString을 clear 시킴.
|
||||
virtual ~CLogger();
|
||||
|
||||
///@brief 로그 레벨에 대응되는 문자열을 만든다.
|
||||
///@param none.
|
||||
///@return none.
|
||||
void MakeLogLevelString();
|
||||
|
||||
///@brief 로그 파일이 위치할 실제 로그 디렉토리를 생성한다.
|
||||
/// 생성할 디렉토리 경로는 'logDir/programName'이 된다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@return 디렉토리가 이미 존재하거나 생성 성공하면 true,
|
||||
/// 해당 경로가 존재하지만 디렉토리가 아니거나, 디렉토리 생성 실패하면 false 반환.
|
||||
static bool MakeLogDir( std::string programName, std::string logDir );
|
||||
|
||||
///@brief 해당 경로가 디렉토리 인지 아닌지 판단.
|
||||
///@param path [in] 디렉토리 인지 아닌지 판단할 경로.
|
||||
///@return 해당 경로가 디렉토이면 true,
|
||||
/// 경로가 존재하지 않거나 디렉토리가 아니면 false 반환.
|
||||
static bool IsDirectory( std::string path );
|
||||
|
||||
///@brief 로그 레벨이 올바른지 판별.
|
||||
///@param logLevel [in]
|
||||
///@return 올바른 로그 레벨이면 true, 그렇지 않으면 false 반환.
|
||||
static bool IsValidLogLevel( int logLevel );
|
||||
|
||||
///@brief 시간 정보를 입력 받아 로그 파일 이름을 만든다.
|
||||
/// 로그 파일 이름 형식 : 프로그램명_YYYYMMDD.log
|
||||
///param timeNow [in] 현재 시간 정보.
|
||||
///return 로그 파일 이름.
|
||||
std::string GetLogFilename( struct tm &timeNow );
|
||||
|
||||
///@brief 로그를 남기는는 클래스가 정의된 파일의 이름에서 클래스명을 추출한다.
|
||||
/// 쓰레드 안정성을 보장한다.
|
||||
///@param className [out] 파일 이름에서 추출된 클래스명
|
||||
///@param filename [in] 파일 이름.
|
||||
///@return 클래스명 추출이 성공하면 클래스명 문자열의 포인터, 추출 실패하면 NULL.
|
||||
const char* GetClassName( char* className, const char* filename );
|
||||
|
||||
///@brief 인자 logPrefix에 따라 적절한 형식으로 로그 파일에 로그를 저장한다.
|
||||
/// 인자 logLevel이 설정된 로그 레벨보다 높으면 로그를 출력하지 않는다.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param logPrefix [in] 로그 프리픽스 종류.
|
||||
///@functionName [in] ClassName::FunctionNmae() 형식의 문자열.
|
||||
///@lineNum [in] 라인 번호.
|
||||
///@log [in] 출력하고자 하는 로그 내용.
|
||||
bool Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log );
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
///@brief 싱글톤 객체 m_pInstance를 생성하고 인자 정보로 로그 디렉토리를 만든다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@return 로그 디렉토리를 만들고 싱글톤 객체를 생성했으면 true,
|
||||
/// 로그 디렉토리를 만들지 못 했거나 인자 값이 올바르지 않으면 false 반환.
|
||||
static bool Init( std::string programName, std::string logDir, int logLevel );
|
||||
|
||||
///@brief 싱글톤 객체 m_pInstance를 delete 한다.
|
||||
///@param none.
|
||||
///@return none.
|
||||
static void Exit();
|
||||
|
||||
///@brief 싱글톤 객체 m_pInstance를 반환한다.
|
||||
///@param none.
|
||||
///@return CLogger 객체의 인스턴스.
|
||||
static CLogger* GetInstance();
|
||||
|
||||
///@brief Prefix로 [hh:mm:ss]이 추가된 형식으로 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool Write( int logLevel, const char * fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
///@brief Prefix가 없는 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool WriteNoPrefix( int logLevel, const char * fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
|
||||
// CHG 2012-08-16 huibong
|
||||
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
|
||||
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
|
||||
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
|
||||
|
||||
///@brief Prefix로 [hh:mm:ss]와 [ClassName::FunctionName:line]이 추가된 형식으로 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param filename [in] 파일 이름
|
||||
///@param funcname [in] 함수 이름
|
||||
///@param lineNum [in] 라인 번호
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
|
||||
__attribute__((format(printf, 6, 7)));
|
||||
|
||||
///@brief 로그를 hex 형식으로 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param data [in] hex 형식으로 출력할 데이터.
|
||||
///@pram size [in] data의 크기.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool WriteHex( int logLevel, const unsigned char* data, const int size );
|
||||
|
||||
///@brief 로그을 설정한다. 인자 logLevel이 적절한 값이면 새로운 값으로 변경하고
|
||||
/// 적절한 값이 아니면 로그 레벨을 변경하지 않는다.
|
||||
///@param logLevel [in] 설정할 로그 레벨
|
||||
///@return none.
|
||||
bool SetLogLevel( int logLevel );
|
||||
|
||||
inline int GetLogLevel() { return m_nLogLevel; };
|
||||
inline std::string GetLogDir() { return m_szLogDir + "/" + m_szProgramName; };
|
||||
};
|
||||
|
||||
#define LOG( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->WriteWithFunc( level, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->Write( level, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG_( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->WriteNoPrefix( level, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG_HEX_( level, data, size ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->WriteHex( level, (const unsigned char*)data, size ); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define FUNC_BEGIN() LOG( LDEV1, "begin" )
|
||||
#define FUNC_END() LOG( LDEV1, "end" )
|
||||
|
||||
#define FRM_BEGIN() LOG( LDEV2, "begin" )
|
||||
#define FRM_END() LOG( LDEV2, "end" )
|
||||
|
||||
#endif // __LOGGER_H__
|
||||
@@ -0,0 +1,71 @@
|
||||
#****************************************************************************
|
||||
# Makefile for Cloud Storage Common Libaray
|
||||
# -----------------------------------------
|
||||
#
|
||||
# begin : 2013/06/04
|
||||
# copyright : (C) 2013 Solbox Inc.
|
||||
# author : Development 1 Team
|
||||
# - 2013/06/04 - 1st dadamin
|
||||
# email : dev1@solbox.com
|
||||
# version : 3.3.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.
|
||||
#*****************************************************************************
|
||||
|
||||
# Library info
|
||||
|
||||
LIB_NAME = InterCommon
|
||||
|
||||
LIB = lib$(LIB_NAME).a
|
||||
|
||||
OBJS = Config.o Logger.o BaseSocket.o
|
||||
|
||||
# Compiler info
|
||||
CC = /usr/bin/g++
|
||||
AR = /usr/bin/ar
|
||||
|
||||
DIR_INCLUDE = -I/usr/local/include
|
||||
|
||||
ifeq ($(DEBUG), yes)
|
||||
CFLAGS = -Wall -O0 -g -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-D_REENTRANT -D_THREAD_SAFE -D_PTHREADS
|
||||
LFLAGS =
|
||||
DFLAGS =
|
||||
else
|
||||
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-D_REENTRANT -D_THREAD_SAFE -D_PTHREADS
|
||||
LFLAGS =
|
||||
DFLAGS =
|
||||
endif
|
||||
|
||||
############################
|
||||
|
||||
all:$(LIB)
|
||||
sync
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
|
||||
$(LIB): $(OBJS)
|
||||
$(AR) crsv $@ $^
|
||||
|
||||
|
||||
clean:
|
||||
-rm -f *.o core *.out *.log
|
||||
-rm -f $(LIB)
|
||||
sync
|
||||
|
||||
|
||||
install :
|
||||
sync
|
||||
|
||||
|
||||
# End of Makefile
|
||||
@@ -0,0 +1,31 @@
|
||||
[COMMON]
|
||||
# Log Directory path
|
||||
DEFAULT_LOG_DIR = /user/service/logs
|
||||
|
||||
# Log write level: 7:debug 6:info(Default) 5:notice 4:warning 3:error 2:critical 1:alert 0:emergency
|
||||
LOG_LEVEL = 6
|
||||
|
||||
[logmngd]
|
||||
# Log Directory path
|
||||
# DEFAULT_LOG_DIR = /user/service/logs
|
||||
|
||||
# Log write level: 7:debug 6:info(Default) 5:notice 4:warning 3:error 2:critical 1:alert 0:emergency
|
||||
#LOG_LEVEL = 7
|
||||
|
||||
#log server ip list
|
||||
## Domain name
|
||||
LOG_SERVER_HOST = ##LOG_SERVER_LIST##
|
||||
#log server port
|
||||
LOG_SERVER_PORT = ##LOG_SERVER_PORT##
|
||||
|
||||
# application logfile retention period(unit : day)
|
||||
# Default : 7 days
|
||||
# boundary : 3~30days
|
||||
APP_LOG_PERIOD = 7
|
||||
|
||||
# searching direcotory list
|
||||
# default :
|
||||
# SEARCHING_DIR_LIST = /user/service/logs, /user/service/log
|
||||
# adding log direcotries
|
||||
# ex) SEARCHING_DIR_LIST = /user/service/logs, /user/service/log, /etc/log
|
||||
SEARCHING_DIR_LIST = /user/service/logs, /user/service/log
|
||||
@@ -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