This commit is contained in:
biosvos
2026-08-07 17:38:18 +09:00
commit 873193a243
9613 changed files with 2755992 additions and 0 deletions
+60
View File
@@ -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 소스 등록
+37
View File
@@ -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
+580
View File
@@ -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;
}
+119
View File
@@ -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__ */
+215
View File
@@ -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;
}
+114
View File
@@ -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__ */
+487
View File
@@ -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;
}
+273
View File
@@ -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__
+71
View File
@@ -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
+31
View File
@@ -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
+172
View File
@@ -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;
}
+50
View File
@@ -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__
+46
View File
@@ -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__ */
+230
View File
@@ -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;
}
+91
View File
@@ -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__
+140
View File
@@ -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 );
}
+97
View File
@@ -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__
+79
View File
@@ -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;
}
+107
View File
@@ -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__
+202
View File
@@ -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;
}
+82
View File
@@ -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( &timestamp, &now );
return now.tm_mday;
}
///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CLogFileProcessThread::Execute()
{
time_t timestamp;
struct tm now;
while (*m_sighandle == 0)
{
/// 현재 시각 확인
timestamp = time( NULL );
localtime_r( &timestamp, &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__
+322
View File
@@ -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( &timestamp, &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;
}
+94
View File
@@ -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__
+426
View File
@@ -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;
}
+78
View File
@@ -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
+423
View File
@@ -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
+131
View File
@@ -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);
}
+63
View File
@@ -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__
+209
View File
@@ -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 //
+38
View File
@@ -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;
}
+74
View File
@@ -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__
+179
View File
@@ -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;
}
+56
View File
@@ -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__
+88
View File
@@ -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);
}
+39
View File
@@ -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__