base
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
Revision 1440
|
||||
-------------------
|
||||
수정일 : 2018-02-26
|
||||
수정자 : 유희곤
|
||||
|
||||
- CHG: 공유메모리 접근 key path 변경 (#31703)
|
||||
- /tmp 폴더에 대한 자동 삭제 처리 문제로
|
||||
- 공유 메모리 접근 key path 를 /user/service 로 변경 처리
|
||||
|
||||
- CHG: FHS data 수신 관련 timeout 발생시 session 종료 처리 (#31703)
|
||||
- FHS Hang 상황시 TCP 세션이 그대로 유지되는 문제 발생
|
||||
- 기존에는 세션을 계속 유지했으나...
|
||||
- 여러 운영관련 오해 상황 발생 및 빠른 감지 처리를 위해
|
||||
- FHS 의 service, system 정보 수신 관련 timeout 발생시 세션 종료하도록 수정
|
||||
|
||||
- NEW: 서비스 상태 변경시 report 로깅 처리 (#31703)
|
||||
- 서비스 상태가 ok, read only -> diable, out 상태로 변경시 report 로깅
|
||||
- 서비스 상태가 disable, out -> ok, read only 로 변경시 report 로깅
|
||||
|
||||
- CHG: 메모리 사용률 감시 관련 conf 상의 default 값 99 -> 100 % 변경 (#31703)
|
||||
- 실제 메모리 사용률이 99% 수준인 RC 존재하여
|
||||
- conf 상의 값을 99 -> 100 으로 변경 처리
|
||||
|
||||
- CHG: r1435 에서 추가한 disk busy 상황시 자동 FHS out 처리 관련 기능 제거 (#31703)
|
||||
- 실제 서비스 적용 후 오탐 상황 발생
|
||||
- 즉 종종 disk queue 10, busy 90% 이상인 상황 발생했지만. FHS 는 정상 상태
|
||||
- 따라서 해당 기능 제거 처리, conf 상에서 해당 설정 제거
|
||||
- 다만 report 로깅 기능은 그대로 유지
|
||||
|
||||
- CHG: rc_show 개선 (#31703)
|
||||
- 실제 유효한 세션만 표시되도록 수정 처리
|
||||
- data 출력 포맷 조정 및 순서 조정
|
||||
- 예전 vmasd 관련 항목 제거
|
||||
|
||||
- CHG: 수정된 rcts.conf 등록
|
||||
- rcts.conf.in.R1440
|
||||
|
||||
|
||||
|
||||
Revision 1435
|
||||
-------------------
|
||||
수정일 : 2018-01-12
|
||||
수정자 : 유희곤
|
||||
|
||||
- NEW: FHS 메모리 사용량 report 로깅 기능 추가 (#31360, #31679)
|
||||
- FHS 의 memory usage % 정보가 conf 의 설정값 이상인 경우 report log 에 기록하도록 신규 기능 추가
|
||||
- 잦은 로깅 방지를 위해 분당 1회만 Check 수행.
|
||||
- conf 상에 설정값(REPORT_MEMORY_MAX_USAGE) 이 없는 경우 해당 기능 비활성화됨.
|
||||
|
||||
- NEW: FHS Disk hang 또는 이상 상황으로 disk busy 비정상 증가시 자동 FHS out 처리 (#31544, #31679 )
|
||||
- disk busy 90.0 %, disk queue 값이 연속으로 10 이상인 경우 FHS 자동 OUT 처리
|
||||
- conf 상 설정 값이 따라 FHS 자동 OUT 처리 여부 정의 (FHS_OUT_WHEN_DISK_BUSY)
|
||||
- 자동 FHS OUT 처리된 경우... csagentd 재기동 또는 수동 fhs.out 설정시 까지 상태 유지됨
|
||||
|
||||
- CHG: 3.4 버전 지원을 위한 vmasd 관련 기능 비활성화
|
||||
- 소스 확인 결과.. rcts.conf 상에 FHS_STATUS_BROADCAST_UDP_PORT 설정이 없는 경우
|
||||
- 관련 모듈들 비활성화 되므로... 해당 설정만 비활성화해서 패키징 하기로 결정
|
||||
|
||||
- CHG: 수정된 rcts.conf 등록
|
||||
- rcts.conf.in.R1435
|
||||
|
||||
|
||||
Revision 1349
|
||||
-------------------
|
||||
수정일 : 2016-04-07
|
||||
수정자 : 유희곤
|
||||
|
||||
- CHG: rc_show TCP 세션 출력 관련 수정
|
||||
- rc_show 의 TCP 세션 출력이 3 자리 설정된 상태이나..실서비스에서는 5자리 까지 출력 상황 발생
|
||||
- 이에 TCP 세션 출력이 5자리 처리되도록 수정
|
||||
|
||||
* 본 수정 내역은 중요 사항이 아니므로.. binary 생성 및 tagging 처리는 수행하지 않습니다.
|
||||
|
||||
|
||||
Revision 1279
|
||||
-------------------
|
||||
수정일 : 2015-11-03
|
||||
수정자 : 유희곤
|
||||
|
||||
- CHG: rc_show 기능 추가 (#24963)
|
||||
- help 기능 추가
|
||||
- 버전 표시 기능 추가
|
||||
- 인자값 옵션 처리 기능 추가
|
||||
- 버그 발생 관련 코드 수정
|
||||
|
||||
- CHG: Database.cpp 관련 다른 프로세스에서 발견된 중복 코드 수정.
|
||||
- PgDoExecParams() 함수의 m_pRes 중복 대입 코드 수정.
|
||||
|
||||
|
||||
Revision 1222
|
||||
-------------------
|
||||
수정일 : 2015-09-10
|
||||
수정자 : 유희곤
|
||||
|
||||
- CHG: Makefile install 스크립트 오류 수정
|
||||
- rc_show 모듈 설치 기능 추가
|
||||
|
||||
|
||||
Revision 1221
|
||||
-------------------
|
||||
수정일 : 2015-09-10
|
||||
수정자 : 유희곤
|
||||
|
||||
- NEW: SVN 신규 등록
|
||||
- 신규 rc_mond 에 대한 SVN 등록
|
||||
- 본 모듈 관련 자세한 사항은 redmine #22682 이슈 참고
|
||||
- 설계서: svn://svc1svn.solbox.com/document/01 양방향/02 설계서/25 FHS 상태 정보 수집&전송/rc_mond 설계서.vsdx
|
||||
- 통신 프로토콜: svn://svc1svn.solbox.com/document/01 양방향/02 설계서/25 FHS 상태 정보 수집&전송/[rc_mond] 통신프로토콜구조.xlsx
|
||||
|
||||
- NEW: 버전 정책 변경 내역 반영 (#22504)
|
||||
- 3.5.0 으로 적용.
|
||||
@@ -0,0 +1,37 @@
|
||||
#****************************************************************************
|
||||
# Makefile for rc_statd
|
||||
# -----------------------------------------
|
||||
#
|
||||
# begin : 2015/05/28
|
||||
# copyright : (C) 2005 Solbox.Inc
|
||||
# author : Dev Storage Team
|
||||
# email : huibong@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.
|
||||
#*****************************************************************************
|
||||
|
||||
SUBDIRS = lib src
|
||||
|
||||
.PHONY: all $(SUBDIRS)
|
||||
|
||||
|
||||
all: $(SUBDIRS)
|
||||
sync;
|
||||
|
||||
|
||||
$(SUBDIRS):
|
||||
$(MAKE) all -C $@
|
||||
|
||||
|
||||
install:
|
||||
@for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) install); done
|
||||
|
||||
|
||||
clean:
|
||||
@for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) clean); done
|
||||
|
||||
|
||||
# End of Makefile
|
||||
@@ -0,0 +1,595 @@
|
||||
#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>
|
||||
#include <time.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 fail.[%s][%d] [%d][%s]", szTarget.c_str(), nPort, 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 || errorNum == EPIPE )
|
||||
{
|
||||
// 2010-07-23 BUG huibong 잘못된 대입연산자를 비교연산자로 수정.
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
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 || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
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 || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
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 || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
|
||||
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 || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
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 || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
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)
|
||||
// - 따라서 오류 반환시 재시도하도록 기능 추가
|
||||
// CHG 2015-07-15 huibong
|
||||
// usleep 의 multi thread 상에서 block 발생 가능
|
||||
// - nanosleep 을 사용토록 변경 처리
|
||||
for( int count = 0 ; count < 3; count++ )
|
||||
{
|
||||
error = getaddrinfo( name, NULL, &hints, &result );
|
||||
|
||||
// 오류 발생시
|
||||
if( error != 0 )
|
||||
{
|
||||
if( result != NULL)
|
||||
{
|
||||
freeaddrinfo(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
// 잠시 대기 후 재시도 처리
|
||||
struct timespec sleep;
|
||||
sleep.tv_sec = 0;
|
||||
sleep.tv_nsec = 500000000; // 0.5 sec
|
||||
nanosleep( &sleep, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상 처리된 경우...
|
||||
// - loop 탈출
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 최종 오류 발생시
|
||||
if( error != 0 )
|
||||
{
|
||||
LOG( LERR, "name[%s] dns resolve fail. getaddrinfo return error [%d][%s]", name, error, gai_strerror(error) );
|
||||
return INADDR_NONE;
|
||||
}
|
||||
|
||||
struct sockaddr_in * addr = (struct sockaddr_in *)result->ai_addr;
|
||||
retval = (unsigned int)(addr->sin_addr.s_addr);
|
||||
|
||||
// DNS Resovle 결과 확인용 코드
|
||||
/*
|
||||
struct addrinfo *temp;
|
||||
for( temp = result; temp; temp = temp->ai_next )
|
||||
{
|
||||
addr = (struct sockaddr_in *)temp->ai_addr;
|
||||
printf ("getaddrinfo result = %s\n",inet_ntoa( addr->sin_addr));
|
||||
}
|
||||
*/
|
||||
|
||||
// getaddrinfo() 함수에서 생성한 메모리 영역 해제 처리.
|
||||
freeaddrinfo(result);
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/***************************************************************************
|
||||
BaseSocket ( Base Socket Class )
|
||||
-----------------------------------------
|
||||
begin : 2010/03/02
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __LIBRARY_BASE_SOCKET_H__
|
||||
#define __LIBRARY_BASE_SOCKET_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <string>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
#define SOCKET_NOT_VALID -1
|
||||
#define DEFAULT_DATA_RECEIVE_TIMEOUT 15 // sec
|
||||
|
||||
|
||||
class CBaseSocket
|
||||
{
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief socket descriptor
|
||||
int m_sock;
|
||||
|
||||
/// @brief socket 의 연결상태인지 여부를 저장하기 위한 변수.
|
||||
bool m_bConnected;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/// @brief 생성자.
|
||||
CBaseSocket( const int & socket );
|
||||
|
||||
/// @brief 소멸자.
|
||||
~CBaseSocket();
|
||||
|
||||
/// @brief 소켓의 Close 처리를 수행함.
|
||||
void Close(void);
|
||||
|
||||
/// @brief 전달받은 Target 으로 Socket 접속을 수행
|
||||
/// @param szTarget [in] 접속 대상 Host name 또는 IP
|
||||
/// @param nPort [in] 접속 Port
|
||||
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
|
||||
bool Connect( const std::string& szTarget, int nPort );
|
||||
|
||||
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
|
||||
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
|
||||
bool IsValidSocket(void);
|
||||
|
||||
/// @brief 멤버변수인 socket 의 접속 상태 여부를 설정하기 위한 함수.
|
||||
void SetConnectionStatus( bool bConnected) { m_bConnected = bConnected; }
|
||||
|
||||
/// @brief 현재 socket 의 접속 상태를 반환.
|
||||
bool GetConnectionStatus( void) { return m_bConnected; }
|
||||
|
||||
//void SetLogger( Logger * pLog ) { m_pLog = pLog; }
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief m_sock 로 부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t Read( void * vptr, size_t size );
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t ReadN( void * vptr, size_t size );
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
|
||||
ssize_t ReadNTimeout( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
|
||||
ssize_t ReadNTimeout2( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
|
||||
|
||||
public:
|
||||
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
|
||||
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
|
||||
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
|
||||
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
|
||||
/// @param size [in] write 하고자 하는 데이터의 크기.
|
||||
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t WriteN( const void * vptr, size_t size );
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief 문자열로 전달받은 정보를 검사하여 IP 접속 정보를 생성한다.
|
||||
unsigned int ConversionAddr( const char * name );
|
||||
|
||||
};
|
||||
|
||||
#endif /* __LIBRARY_BASE_SOCKET_H__ */
|
||||
@@ -0,0 +1,215 @@
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <boost/algorithm/string.hpp> // use boost
|
||||
|
||||
|
||||
Config::Config()
|
||||
: m_keyDelimiter( CONFIG_DEFAULT_KEY_DELIMITER )
|
||||
, m_valueDelimiter( CONFIG_DEFAULT_VALUE_DELIMITER )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// @brief destructor
|
||||
Config::~Config()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
|
||||
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::Open( const string path )
|
||||
{
|
||||
ifstream file;
|
||||
|
||||
// Config file open
|
||||
file.open( path.c_str());
|
||||
if( file.is_open() == false )
|
||||
{
|
||||
cerr << "[error] " << __FILE__<< ":" << __func__ << ": config file open failed.[" << path << "][" << strerror( errno ) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 기존 데이터가 존재하면 삭제 처리.
|
||||
if( m_configData.empty() == false )
|
||||
m_configData.clear();
|
||||
|
||||
// config file parsing
|
||||
string line;
|
||||
string section;
|
||||
vector< string > configs;
|
||||
|
||||
// 루프를 돌면서 Config 파일을 line 단위로 읽어들인당....
|
||||
while( std::getline( file, line ) )
|
||||
{
|
||||
// 앞뒤 공백 제거 처리
|
||||
boost::trim( line );
|
||||
|
||||
// 공백 or 주석처리 라인 검사
|
||||
if( line.empty() == true || boost::starts_with( line, string("#") ) == true || line == "\r" )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Section 여부 검사
|
||||
if( boost::starts_with( line, string("[") ) == true && boost::ends_with( line, string("]") ) == true )
|
||||
{
|
||||
// [] 로 정의된 section 의 문자열 값 추출
|
||||
line.erase( line.begin() );
|
||||
line.erase( line.end() -1 );
|
||||
boost::trim( line );
|
||||
|
||||
if( section.empty() == false && section != line )
|
||||
{
|
||||
// 이전 세션과 다른 신규 세션인 경우
|
||||
// 기존까지 저장했던 데이터를 멤버 변수에 입력 처리 후 내부변수 초기화 처리.
|
||||
|
||||
m_configData.insert( make_pair( section, configs ) );
|
||||
section.clear();
|
||||
configs.clear();
|
||||
}
|
||||
|
||||
// 신규 section 정보 저장처리.
|
||||
section = line;
|
||||
line.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Section 정보가 아닌 경우 => 실제 설정값 .. ^^
|
||||
configs.push_back( line );
|
||||
}
|
||||
}
|
||||
|
||||
// 마지막 세션 처리된 정보가 존재하는 경우 멤버 변수에 저장 처리.
|
||||
if( section.empty() == false )
|
||||
{
|
||||
m_configData.insert( make_pair( section, configs ) );
|
||||
}
|
||||
|
||||
// 종료 처리.
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
|
||||
/// @return void
|
||||
void Config::Clear()
|
||||
{
|
||||
m_configData.clear();
|
||||
}
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::GetConfig( const string section, const string key, string& value )
|
||||
{
|
||||
// Section 에 대한 임시 데이터 저장객체 생성
|
||||
vector< string > configs;
|
||||
|
||||
// 해당 Section 이 존재하지 않는 경우
|
||||
if( Find( section, configs ) == false )
|
||||
return false;
|
||||
|
||||
string line;
|
||||
string result;
|
||||
vector< string >::const_iterator it;
|
||||
|
||||
// 해당 Key 이 존재하는지 검사
|
||||
for( it = configs.begin(); it != configs.end(); it++)
|
||||
{
|
||||
line = *it;
|
||||
|
||||
// Line 상의 주석 제거
|
||||
string::size_type pos = line.find( '#' );
|
||||
if( pos != string::npos)
|
||||
{
|
||||
line = line.substr(0, pos);
|
||||
boost::trim( line );
|
||||
}
|
||||
|
||||
// key = value 에서 key 부분 추출
|
||||
pos = line.find( m_keyDelimiter );
|
||||
if( pos == string::npos )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = line.substr(0, pos);
|
||||
boost::trim( result );
|
||||
}
|
||||
|
||||
if( key == result )
|
||||
{
|
||||
// Key 값이 동일한 경우
|
||||
value = line.substr( pos+1 );
|
||||
boost::trim( value );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::GetConfig( const string section, const string key, vector< string >& value )
|
||||
{
|
||||
string result;
|
||||
vector< string > vec;
|
||||
|
||||
if( GetConfig( section, key, result ) == false )
|
||||
return false;
|
||||
|
||||
// 전달받은 result 값을 value delimiter 를 이용하여 parsing 처리
|
||||
boost::split( vec, result, boost::is_any_of( m_valueDelimiter ));
|
||||
if( vec.empty() == true )
|
||||
return false;
|
||||
|
||||
// 루프를 돌면서 trim 처리 후 결과값 저장처리.
|
||||
vector< string >::const_iterator it;
|
||||
for( it = vec.begin(); it != vec.end(); it++)
|
||||
{
|
||||
result = boost::trim_copy( *it );
|
||||
|
||||
if( result.empty() == false )
|
||||
value.push_back( result );
|
||||
}
|
||||
|
||||
if( value.empty() == true )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
|
||||
/// @param section [in] section 명
|
||||
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::Find( const string& section, vector<string>& configData )
|
||||
{
|
||||
map< string, vector< string > >::iterator it = m_configData.find( section );
|
||||
if( it != m_configData.end() )
|
||||
{
|
||||
// 해당 section 을 찾은 경우
|
||||
configData = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 해당 section 을 찾지 못한 경우
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/***************************************************************************
|
||||
Config File Parser Class
|
||||
-----------------------------------------
|
||||
begin : 2010/02/27
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __LIBRARY_CONFIG_H__
|
||||
#define __LIBRARY_CONFIG_H__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
#define CONFIG_DEFAULT_KEY_DELIMITER "="
|
||||
#define CONFIG_DEFAULT_VALUE_DELIMITER ","
|
||||
|
||||
|
||||
/// @brief Config class
|
||||
/// 1. config 파일의 내용을 파싱처리하여 각 Section, Key 에 해당하는 값을 반환처리
|
||||
/// 2. config 파일은 [section] 단위로 구분된다.
|
||||
/// 3. config 파일은 key=value 로 구분가능하며 이는 Delimiter 설정을 통해 변경가능하다.
|
||||
/// 4. value 값이 다중으로 존재하는 경우 "," 값을 통해 구분가능, Delimiter 변경시 다른 값도 사용가능함.
|
||||
/// 5. config 파일상에서 "#" 로 시작하는 문자열은 라인 끝까지 주석으로 처리된다.
|
||||
/// 6. 특정 Key 값에 대한 다중 value 값 조회는 vector<string> 을 통해 수행한다.
|
||||
/// 7. 만약 다중 value 값이 존재시 string 으로 반환받을 경우 해당 Row 가 통째로 반환된다.
|
||||
/// 8. 본 객체는 Open , Clear 함수가 호출되기전까지 이전 Config 정보가 저장된다.
|
||||
class Config
|
||||
{
|
||||
private:
|
||||
/// @brief config information saved variable
|
||||
// string : section data
|
||||
// vector<string> : key=value data
|
||||
map< string, vector< string> > m_configData;
|
||||
|
||||
/// @brief Key, Value 구분자 저장 변수
|
||||
string m_keyDelimiter;
|
||||
string m_valueDelimiter;
|
||||
|
||||
public:
|
||||
/// @brief constructor
|
||||
Config();
|
||||
|
||||
/// @brief destructor
|
||||
~Config();
|
||||
|
||||
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
|
||||
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Open( const string path );
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
|
||||
/// @return void
|
||||
void Clear();
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
|
||||
/// @return On success return true, otherwise return false
|
||||
bool GetConfig( const string section, const string key, string& value );
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool GetConfig( const string section, const string key, vector< string >& value );
|
||||
|
||||
/// @brief Key, Value Delimiter Get 함수
|
||||
/// @param key [out] key delimiter 값
|
||||
/// @param value [out] value delimiter 값
|
||||
void GetDelimiter( string& key, string& value )
|
||||
{
|
||||
key = m_keyDelimiter;
|
||||
value = m_valueDelimiter;
|
||||
}
|
||||
|
||||
// BUG 2010-12-06 huibong
|
||||
// string& value = CONFIG_DEFAULT_VALUE_DELIMITER 값은 문법상 오류 구문임.
|
||||
// gcc 3.4.6 버전에서는 Compile 되나 gcc 4.4.5 에서는 error 로 처리되어 수정처리함.
|
||||
|
||||
/// @brief Key, Value Delimiter Set 함수
|
||||
/// @param key [out] key delimiter 값
|
||||
/// @param value [out] value delimiter 값, 지정하지 않을 경우 Default 값이 사용됨.
|
||||
void SetDelimiter( string& key, string value = CONFIG_DEFAULT_VALUE_DELIMITER )
|
||||
{
|
||||
m_keyDelimiter = key;
|
||||
m_valueDelimiter = value;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
|
||||
/// @param section [in] section 명
|
||||
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Find( const string& section, vector<string>& configData );
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* __LIBRARY_CONFIG_H__ */
|
||||
@@ -0,0 +1,110 @@
|
||||
/***************************************************************************
|
||||
Fixed size Queue Class ( FixedQueue.cpp )
|
||||
-----------------------------------------
|
||||
begin : 2013/08/09
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Development 1 Team
|
||||
email : dev1@solbox.com
|
||||
version : 3.2
|
||||
|
||||
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 "FixedQueue.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
CMutexLock::CMutexLock(pthread_mutex_t * mutex)
|
||||
: m_plock(mutex)
|
||||
{
|
||||
pthread_mutex_lock(m_plock);
|
||||
}
|
||||
|
||||
CMutexLock::~CMutexLock()
|
||||
{
|
||||
pthread_mutex_unlock(m_plock);
|
||||
}
|
||||
|
||||
CFixedQueue::CFixedQueue(int bufferSize, int qSzie )
|
||||
: m_bufferSize(bufferSize), m_queueSize(qSzie)
|
||||
{
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
}
|
||||
|
||||
CFixedQueue::~CFixedQueue()
|
||||
{
|
||||
ReleaseAll();
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
}
|
||||
|
||||
void CFixedQueue::ReleaseAll()
|
||||
{
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
|
||||
while (!m_queue.empty())
|
||||
{
|
||||
FixedQueueData *d = m_queue.front();
|
||||
if(d) delete (FixedQueueData*) d;
|
||||
m_queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
int CFixedQueue::Push(char* buf, size_t buffersize)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if(buf == NULL)
|
||||
return -1;
|
||||
|
||||
if(buffersize > (size_t) m_bufferSize)
|
||||
return -2;
|
||||
|
||||
CMutexLock lock (&m_mutex);
|
||||
do
|
||||
{
|
||||
if( m_queue.size() >= std::queue<char*>::size_type(m_queueSize) )
|
||||
{
|
||||
r = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
FixedQueueData *d = new FixedQueueData;
|
||||
d->data_size = buffersize;
|
||||
d->data = new char [buffersize];
|
||||
memcpy(d->data, buf, buffersize);
|
||||
m_queue.push(d);
|
||||
r = 0;
|
||||
|
||||
}while (false);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int CFixedQueue::Pop(char* buf, size_t buffersize)
|
||||
{
|
||||
int r = 0;
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
memset(buf, 0, buffersize);
|
||||
CMutexLock lock (&m_mutex);
|
||||
do
|
||||
{
|
||||
if( m_queue.empty())
|
||||
{
|
||||
r = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
FixedQueueData *t = m_queue.front();
|
||||
memcpy(buf, t->data, t->data_size);
|
||||
delete (FixedQueueData *) t;
|
||||
m_queue.pop();
|
||||
r = 0;
|
||||
|
||||
} while (false);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/***************************************************************************
|
||||
Fixed size Queue Class Header ( FixedQueue.h )
|
||||
-----------------------------------------
|
||||
begin : 2013/08/09
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Development 1 Team
|
||||
email : dev1@solbox.com
|
||||
version : 3.2
|
||||
|
||||
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 __FIXED_SIZE_QUEUE_H__
|
||||
#define __FIXED_SIZE_QUEUE_H__
|
||||
|
||||
#include <pthread.h>
|
||||
#include <queue>
|
||||
|
||||
class CMutexLock
|
||||
{
|
||||
public:
|
||||
CMutexLock(pthread_mutex_t * mutex);
|
||||
~CMutexLock();
|
||||
|
||||
private:
|
||||
pthread_mutex_t* m_plock;
|
||||
};
|
||||
|
||||
class FixedQueueData
|
||||
{
|
||||
public:
|
||||
size_t data_size;
|
||||
char * data;
|
||||
|
||||
FixedQueueData ()
|
||||
: data_size(0), data(NULL) {};
|
||||
|
||||
~FixedQueueData () { if(data) delete [] data; }
|
||||
};
|
||||
|
||||
class CFixedQueue
|
||||
{
|
||||
public:
|
||||
///@brief 생성자.
|
||||
///@param bufferSize [in] 데이터 버퍼 크기
|
||||
///@param qSzie [in] 큐의 크기
|
||||
CFixedQueue (int bufferSize, int qSzie );
|
||||
|
||||
///@brief 소멸자.
|
||||
~CFixedQueue();
|
||||
|
||||
///@brief 데이터 삽입
|
||||
///@param buf [in] 데이터
|
||||
///@param buffersize [in] 데이터 크기
|
||||
///@return 0: 정상, 1:queue full, -1 : error
|
||||
int Push(char* buf, size_t buffersize);
|
||||
|
||||
///@brief 데이터 추출
|
||||
///@return 데이터 리턴(FIFO)
|
||||
///@param buf [in] 데이터
|
||||
///@param buffersize [in] 데이터 크기
|
||||
///@return 0: 정상, 1: queue empty 나머지 : error
|
||||
int Pop(char* buf, size_t buffersize);
|
||||
|
||||
|
||||
protected:
|
||||
///@brief 큐에 초기화
|
||||
void ReleaseAll();
|
||||
|
||||
private:
|
||||
int m_bufferSize;
|
||||
int m_queueSize;
|
||||
|
||||
pthread_mutex_t m_mutex;
|
||||
|
||||
std::queue<FixedQueueData *> m_queue;
|
||||
};
|
||||
|
||||
#endif // __FIXED_SIZE_QUEUE_H__
|
||||
@@ -0,0 +1,487 @@
|
||||
/***************************************************************************
|
||||
Logger.cpp
|
||||
-----------------------------------------
|
||||
begin : 2011/10/26
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
#include "Logger.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <iostream>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_BUFFER_SIZE 2048 // 임시 버퍼 최대 크기
|
||||
#define DEFAULT_LOG_LEVEL LINF
|
||||
|
||||
using namespace std;
|
||||
|
||||
CLogger* CLogger::m_pInstance = NULL;
|
||||
bool CLogger::m_bIsInitialized = false;
|
||||
pthread_mutex_t CLogger::m_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
|
||||
CLogger::CLogger( string programName, string logDir, int logLevel )
|
||||
{
|
||||
m_szProgramName = programName;
|
||||
m_szLogDir = logDir;
|
||||
|
||||
if( IsValidLogLevel( logLevel ) == true )
|
||||
{
|
||||
m_nLogLevel = logLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nLogLevel = DEFAULT_LOG_LEVEL;
|
||||
}
|
||||
|
||||
MakeLogLevelString();
|
||||
}
|
||||
|
||||
void CLogger::MakeLogLevelString()
|
||||
{
|
||||
m_vectorLogLevelString.push_back( "EMR" );
|
||||
m_vectorLogLevelString.push_back( "ALT" );
|
||||
m_vectorLogLevelString.push_back( "CRT" );
|
||||
m_vectorLogLevelString.push_back( "ERR" );
|
||||
m_vectorLogLevelString.push_back( "WAR" );
|
||||
m_vectorLogLevelString.push_back( "NOT" );
|
||||
m_vectorLogLevelString.push_back( "INF" );
|
||||
m_vectorLogLevelString.push_back( "DBG" );
|
||||
m_vectorLogLevelString.push_back( "DEV" );
|
||||
m_vectorLogLevelString.push_back( "DEV1" );
|
||||
m_vectorLogLevelString.push_back( "DEV2" );
|
||||
}
|
||||
|
||||
CLogger::~CLogger()
|
||||
{
|
||||
m_vectorLogLevelString.clear();
|
||||
}
|
||||
|
||||
bool CLogger::Init( string programName, string logDir, int logLevel )
|
||||
{
|
||||
if( m_bIsInitialized == true )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
pthread_mutex_lock( &m_mutex );
|
||||
|
||||
// 변수 유효성 검사.
|
||||
if( programName.empty() == true || logDir.empty() == true )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( MakeLogDir( programName, logDir ) == false )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( CLogger::m_pInstance != NULL )
|
||||
{
|
||||
delete CLogger::m_pInstance;
|
||||
CLogger::m_pInstance = NULL;
|
||||
}
|
||||
|
||||
CLogger::m_pInstance = new CLogger( programName, logDir, logLevel );
|
||||
m_bIsInitialized = true;
|
||||
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::IsValidLogLevel( int logLevel )
|
||||
{
|
||||
return ( ( logLevel < 0 || logLevel > MAX_LOG_LEVEL ) ? false : true );
|
||||
}
|
||||
|
||||
bool CLogger::SetLogLevel( int logLevel )
|
||||
{
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_nLogLevel = logLevel;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::MakeLogDir( string programName, string logDir )
|
||||
{
|
||||
string path = logDir + "/" + programName;
|
||||
|
||||
struct stat dirStat;
|
||||
|
||||
// 해당 이름을 가진 파일 또는 디렉토리가 존재하고
|
||||
if( lstat( path.c_str(), &dirStat ) == 0 )
|
||||
{
|
||||
// 해당 이름이 디렉토리인 경우
|
||||
if( S_ISDIR( dirStat.st_mode ) == true )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "exist file with the same name as log path(" << path << ")." << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 디렉토리 가 존재하지 않는 경우 디렉토리 생성 시도
|
||||
string cmd = "mkdir -p " + path;
|
||||
system( cmd.c_str() );
|
||||
|
||||
if( IsDirectory( path ) == false )
|
||||
{
|
||||
cerr << "can't make log directory. path=" << path << "." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::IsDirectory( string path )
|
||||
{
|
||||
struct stat dirStat;
|
||||
|
||||
if( lstat ( path.c_str(), &dirStat ) != 0 )
|
||||
{
|
||||
cerr << "Log path not valid. Check path [" << path << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 해당 정보가 Directory 가 아닌 경우
|
||||
if( S_ISDIR( dirStat.st_mode ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLogger::Exit()
|
||||
{
|
||||
if( m_bIsInitialized == false )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock( &m_mutex );
|
||||
|
||||
if( CLogger::m_pInstance != NULL )
|
||||
{
|
||||
delete CLogger::m_pInstance;
|
||||
CLogger::m_pInstance = NULL;
|
||||
m_bIsInitialized = false;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
}
|
||||
|
||||
CLogger* CLogger::GetInstance()
|
||||
{
|
||||
return CLogger::m_pInstance;
|
||||
}
|
||||
|
||||
string CLogger::GetLogFilename( struct tm &timeNow )
|
||||
{
|
||||
char timeStr[256];
|
||||
snprintf( timeStr, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
|
||||
|
||||
// Make File Name
|
||||
string filename = m_szLogDir + "/" + m_szProgramName + "/" + m_szProgramName + "_" + string( timeStr );
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool CLogger::Write( int logLevel, const char * fmt, ...)
|
||||
{
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return Write( logLevel, PREFIX_DATE, NULL, 0, buffer );
|
||||
}
|
||||
|
||||
bool CLogger::WriteNoPrefix( int logLevel, const char * fmt, ...)
|
||||
{
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return Write( logLevel, PREFIX_NONE, NULL, 0, buffer );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// CHG 2012-08-16 huibong
|
||||
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
|
||||
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
|
||||
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
|
||||
// 함수명 : Write -> WriteWithFunc 으로 변경 처리
|
||||
bool CLogger::WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
|
||||
{
|
||||
if( filename == NULL || funcname == NULL || lineNum < 0 || fmt == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
|
||||
char className[255];
|
||||
string funcPrefix = GetClassName( className, filename );
|
||||
funcPrefix += "::" + string( funcname ) + "()";
|
||||
|
||||
return Write( logLevel, PREFIX_FUNCTION, funcPrefix.c_str(), lineNum, buffer );
|
||||
}
|
||||
|
||||
const char* CLogger::GetClassName( char* className, const char* filename )
|
||||
{
|
||||
if( className == NULL )
|
||||
{
|
||||
cout << "[ERROR] The input argument 'className' is NULL." << endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( filename == NULL )
|
||||
{
|
||||
cout << "[ERROR] The input argument 'filename' is NULL." << endl;
|
||||
strcpy( className, "NULL" );
|
||||
return className;
|
||||
}
|
||||
|
||||
int filenameSize = strlen( filename );
|
||||
memcpy( className, filename, filenameSize );
|
||||
|
||||
// find end position
|
||||
char endCharacter = '.';
|
||||
int endPos = filenameSize - 1;
|
||||
for( ; endPos > 0; --endPos )
|
||||
{
|
||||
if( className[endPos] == endCharacter )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( endPos == 0 )
|
||||
{
|
||||
cout << "[ERROR] endPos=0" << endl;
|
||||
strcpy( className, "NULL" );
|
||||
return className;
|
||||
}
|
||||
|
||||
className[endPos] = '\0';
|
||||
|
||||
// find start position
|
||||
char startCharacter = '/';
|
||||
int startPos = endPos - 1;
|
||||
for( ; startPos > 0; --startPos )
|
||||
{
|
||||
if( className[startPos] == startCharacter )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( startPos != 0 )
|
||||
{
|
||||
startPos += 1;
|
||||
}
|
||||
|
||||
return (className + startPos );
|
||||
}
|
||||
|
||||
bool CLogger::Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log )
|
||||
{
|
||||
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
|
||||
if( logLevel > m_nLogLevel )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( log == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Current Data & Time
|
||||
time_t now = time( NULL );
|
||||
struct tm timeNow;
|
||||
localtime_r( &now, &timeNow );
|
||||
|
||||
string filename = GetLogFilename( timeNow );
|
||||
|
||||
// Log file open
|
||||
FILE* pFile = NULL;
|
||||
pFile = fopen( filename.c_str(), "a+" );
|
||||
|
||||
if( pFile == NULL )
|
||||
{
|
||||
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 시간 정보처리
|
||||
char timeStr[256];
|
||||
snprintf( timeStr, (size_t)256, "[%02d:%02d:%02d]"
|
||||
, timeNow.tm_hour, timeNow.tm_min, timeNow.tm_sec );
|
||||
|
||||
// Log Level 문자열 검색
|
||||
string szLevel = m_vectorLogLevelString[ logLevel ];
|
||||
|
||||
switch( logPrefix )
|
||||
{
|
||||
case PREFIX_DATE:
|
||||
/// 형식 예: [15:47:41] [DBG] sample log message.
|
||||
fprintf( pFile, "%s [%-4s] %s\n", timeStr, szLevel.c_str(), log );
|
||||
break;
|
||||
|
||||
case PREFIX_FUNCTION:
|
||||
if( functionName == NULL )
|
||||
{
|
||||
fclose( pFile );
|
||||
return false;
|
||||
}
|
||||
/// 형식 예: [15:47:41] [DBG] sample log message. [SomeClass::SomeFunction():12]
|
||||
fprintf( pFile, "%s [%-4s] %s [%s:%d]\n", timeStr, szLevel.c_str(), log, functionName, lineNum );
|
||||
break;
|
||||
|
||||
case PREFIX_NONE:
|
||||
/// 형식 예: sample log message.
|
||||
fprintf( pFile, "%s\n", log );
|
||||
break;
|
||||
}
|
||||
// Write to log file
|
||||
fflush( pFile );
|
||||
|
||||
// 종료 처리.
|
||||
fclose( pFile );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::WriteHex( int logLevel, const unsigned char* data, const int size )
|
||||
{
|
||||
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
|
||||
if( logLevel > m_nLogLevel )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( data == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( size <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Current Data & Time
|
||||
time_t now = time( NULL );
|
||||
struct tm timeNow;
|
||||
localtime_r( &now, &timeNow );
|
||||
|
||||
string filename = GetLogFilename( timeNow );
|
||||
|
||||
// Log file open
|
||||
FILE* pFile = NULL;
|
||||
pFile = fopen( filename.c_str(), "a+" );
|
||||
|
||||
if( pFile == NULL )
|
||||
{
|
||||
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for( int i = 0; i < size; ++i )
|
||||
{
|
||||
fprintf( pFile, "%02X", data[i] );
|
||||
|
||||
if( i == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( (i+1) % 8 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, " " );
|
||||
}
|
||||
|
||||
if( ( (i+1) % 16 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, " " );
|
||||
}
|
||||
|
||||
if( ( (i+1) % 32 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, "\n" );
|
||||
}
|
||||
}
|
||||
fprintf( pFile, "\n" );
|
||||
fflush( pFile );
|
||||
|
||||
// 종료 처리.
|
||||
fclose( pFile );
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
/***************************************************************************
|
||||
Logger.h
|
||||
-----------------------------------------
|
||||
begin : 2011/10/26
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 3.2.0.805
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
#ifndef __LOGGER_H__
|
||||
#define __LOGGER_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <pthread.h>
|
||||
|
||||
///@brief 로그 레벨 정의
|
||||
#define LEMR 0 /* system is or will be unusable if situation is not resolved */
|
||||
#define LALT 1 /* immediate action required */
|
||||
#define LCRT 2 /* critical situations */
|
||||
#define LERR 3 /* error conditions */
|
||||
#define LWAR 4 /* recoverable errors */
|
||||
#define LNOT 5 /* unusual situation that merits investigation */
|
||||
#define LINF 6 /* information messages */
|
||||
#define LDBG 7 /* verbose data for debugging */
|
||||
#define LDEV 8 /* verbose data for developer */
|
||||
#define LDEV1 9 /* start or end the function of application level */
|
||||
#define LDEV2 10 /* start or end the function of application level */
|
||||
|
||||
#define MAX_LOG_LEVEL LDEV2
|
||||
|
||||
|
||||
///@brief Log 정보를 파일로 저장하기 위한 Class.
|
||||
///1. 가변 format 으로 전달된 로그 관련 정보를 Log Level 에 따라 로그 파일에 아래의 4가지 형식으로 저장한다.
|
||||
///
|
||||
/// 1.1 Prefix로 [hh:mm:ss]와 [ClassName::FunctionName]이 추가된 로그
|
||||
/// LOG( level, format, ... ) 매크로 사용.
|
||||
/// 예) [17:43:40] [DBG] log level debug [LoggerTestTestLogger]
|
||||
///
|
||||
/// 1.2 Prefix로 [hh:mm:ss]이 추가된 로그
|
||||
/// _LOG( level, format, ... ) 매크로 사용
|
||||
/// 예) [17:43:40] [EMR] log level emergency
|
||||
///
|
||||
/// 1.3 Prefix가 없는 로그
|
||||
/// _LOG_( level, format, ... ) 매크로 사용
|
||||
/// 예) log level emergency
|
||||
///
|
||||
/// 1.4 Hex 로그.
|
||||
/// LOG_HEX( level, data, size ) 매크로 사용
|
||||
/// 예) 00010203 04050607 08090A0B 0C0D0E0F
|
||||
///
|
||||
///2. Logger 객체 초기화시 전달된 Log Level 정보보다 전달받은 Log Level 정보가 큰 경우 해당 로그는 파일로 저장되지 않는다.
|
||||
///
|
||||
///3. 로그 파일은 매 일단위로 저장파일이 변경된다.
|
||||
///
|
||||
///4. 로그 저장을 위한 program 경로가 존재하지 않는 경우 자동 생성 처리된다.
|
||||
///
|
||||
///5. 로그 저장방식은 매 저장로그마다 open-close 로 처리된다.
|
||||
///
|
||||
///6. 파일로 기록시 Log Level 에 대한 정보도 함께 기록된다.
|
||||
///
|
||||
///7. 싱글톤으로 작성되었고, CLogger::Init(...)시에 쓰레드 안정성을 제공한다.
|
||||
///
|
||||
///8. 동적으로 로그 레벨을 변경할 수 있는 인터페이스를 제공한다.
|
||||
///
|
||||
class CLogger
|
||||
{
|
||||
// Attributes
|
||||
private:
|
||||
///@brief 싱글톤 객체 인트턴스.
|
||||
static CLogger* m_pInstance;
|
||||
|
||||
///@brief 싱글톤 객체 초기화 여부.
|
||||
static bool m_bIsInitialized;
|
||||
|
||||
///@brief 싱글톤 객체 초기화시 스레드 안정성을 위한 뮤텍스.
|
||||
static pthread_mutex_t m_mutex;
|
||||
|
||||
///@brief 프로그램 이름. 로그 파일 경로를 만들 때 사용.
|
||||
std::string m_szProgramName;
|
||||
|
||||
///@brief 공통 로그 디렉토리 이름. 로그 파일 경로를 만들 때 사용.
|
||||
std::string m_szLogDir;
|
||||
|
||||
///@brief 로그 레벨.
|
||||
int m_nLogLevel;
|
||||
|
||||
///@brief 로그 레벨에 대응되는 문자열 정보를 저장.
|
||||
std::vector<std::string> m_vectorLogLevelString;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
///@brief 로그 형식을 지정.
|
||||
typedef enum
|
||||
{
|
||||
PREFIX_NONE = 0, /// 클래스 설명의 1.3에 해당
|
||||
PREFIX_DATE, /// 클래스 설명의 1.2에 해당
|
||||
PREFIX_FUNCTION, /// 클래스 설명의 1.1에 해당
|
||||
} LOG_PREFIX;
|
||||
|
||||
// Operations
|
||||
private:
|
||||
///@brief 생성자.
|
||||
/// 프로그램 이름, 공통 로그 디렉토리, 로그 레벨을 저장하고
|
||||
/// 로그 레벨에 대응되는 문자열 정보를 만든다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@param logLevel [in] 로그 레벨
|
||||
CLogger( std::string programName, std::string logDir, int logLevel );
|
||||
|
||||
///@brief 소멸자.
|
||||
/// 로그 레벨에 대응되는 문자열 정보를 저장하고 있는
|
||||
/// 벡터 m_vectorLogLevelString을 clear 시킴.
|
||||
virtual ~CLogger();
|
||||
|
||||
///@brief 로그 레벨에 대응되는 문자열을 만든다.
|
||||
///@param none.
|
||||
///@return none.
|
||||
void MakeLogLevelString();
|
||||
|
||||
///@brief 로그 파일이 위치할 실제 로그 디렉토리를 생성한다.
|
||||
/// 생성할 디렉토리 경로는 'logDir/programName'이 된다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@return 디렉토리가 이미 존재하거나 생성 성공하면 true,
|
||||
/// 해당 경로가 존재하지만 디렉토리가 아니거나, 디렉토리 생성 실패하면 false 반환.
|
||||
static bool MakeLogDir( std::string programName, std::string logDir );
|
||||
|
||||
///@brief 해당 경로가 디렉토리 인지 아닌지 판단.
|
||||
///@param path [in] 디렉토리 인지 아닌지 판단할 경로.
|
||||
///@return 해당 경로가 디렉토이면 true,
|
||||
/// 경로가 존재하지 않거나 디렉토리가 아니면 false 반환.
|
||||
static bool IsDirectory( std::string path );
|
||||
|
||||
///@brief 로그 레벨이 올바른지 판별.
|
||||
///@param logLevel [in]
|
||||
///@return 올바른 로그 레벨이면 true, 그렇지 않으면 false 반환.
|
||||
static bool IsValidLogLevel( int logLevel );
|
||||
|
||||
///@brief 시간 정보를 입력 받아 로그 파일 이름을 만든다.
|
||||
/// 로그 파일 이름 형식 : 프로그램명_YYYYMMDD.log
|
||||
///param timeNow [in] 현재 시간 정보.
|
||||
///return 로그 파일 이름.
|
||||
std::string GetLogFilename( struct tm &timeNow );
|
||||
|
||||
///@brief 로그를 남기는는 클래스가 정의된 파일의 이름에서 클래스명을 추출한다.
|
||||
/// 쓰레드 안정성을 보장한다.
|
||||
///@param className [out] 파일 이름에서 추출된 클래스명
|
||||
///@param filename [in] 파일 이름.
|
||||
///@return 클래스명 추출이 성공하면 클래스명 문자열의 포인터, 추출 실패하면 NULL.
|
||||
const char* GetClassName( char* className, const char* filename );
|
||||
|
||||
///@brief 인자 logPrefix에 따라 적절한 형식으로 로그 파일에 로그를 저장한다.
|
||||
/// 인자 logLevel이 설정된 로그 레벨보다 높으면 로그를 출력하지 않는다.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param logPrefix [in] 로그 프리픽스 종류.
|
||||
///@functionName [in] ClassName::FunctionNmae() 형식의 문자열.
|
||||
///@lineNum [in] 라인 번호.
|
||||
///@log [in] 출력하고자 하는 로그 내용.
|
||||
bool Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log );
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
///@brief 싱글톤 객체 m_pInstance를 생성하고 인자 정보로 로그 디렉토리를 만든다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@return 로그 디렉토리를 만들고 싱글톤 객체를 생성했으면 true,
|
||||
/// 로그 디렉토리를 만들지 못 했거나 인자 값이 올바르지 않으면 false 반환.
|
||||
static bool Init( std::string programName, std::string logDir, int logLevel );
|
||||
|
||||
///@brief 싱글톤 객체 m_pInstance를 delete 한다.
|
||||
///@param none.
|
||||
///@return none.
|
||||
static void Exit();
|
||||
|
||||
///@brief 싱글톤 객체 m_pInstance를 반환한다.
|
||||
///@param none.
|
||||
///@return CLogger 객체의 인스턴스.
|
||||
static CLogger* GetInstance();
|
||||
|
||||
///@brief Prefix로 [hh:mm:ss]이 추가된 형식으로 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool Write( int logLevel, const char * fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
///@brief Prefix가 없는 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool WriteNoPrefix( int logLevel, const char * fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
|
||||
// CHG 2012-08-16 huibong
|
||||
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
|
||||
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
|
||||
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
|
||||
|
||||
///@brief Prefix로 [hh:mm:ss]와 [ClassName::FunctionName:line]이 추가된 형식으로 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param filename [in] 파일 이름
|
||||
///@param funcname [in] 함수 이름
|
||||
///@param lineNum [in] 라인 번호
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
|
||||
__attribute__((format(printf, 6, 7)));
|
||||
|
||||
///@brief 로그를 hex 형식으로 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param data [in] hex 형식으로 출력할 데이터.
|
||||
///@pram size [in] data의 크기.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool WriteHex( int logLevel, const unsigned char* data, const int size );
|
||||
|
||||
///@brief 로그을 설정한다. 인자 logLevel이 적절한 값이면 새로운 값으로 변경하고
|
||||
/// 적절한 값이 아니면 로그 레벨을 변경하지 않는다.
|
||||
///@param logLevel [in] 설정할 로그 레벨
|
||||
///@return none.
|
||||
bool SetLogLevel( int logLevel );
|
||||
|
||||
inline int GetLogLevel() { return m_nLogLevel; };
|
||||
inline std::string GetLogDir() { return m_szLogDir + "/" + m_szProgramName; };
|
||||
};
|
||||
|
||||
#define LOG( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->WriteWithFunc( level, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->Write( level, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG_( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->WriteNoPrefix( level, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG_HEX_( level, data, size ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->WriteHex( level, (const unsigned char*)data, size ); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define FUNC_BEGIN() LOG( LDEV1, "begin" )
|
||||
#define FUNC_END() LOG( LDEV1, "end" )
|
||||
|
||||
#define FRM_BEGIN() LOG( LDEV2, "begin" )
|
||||
#define FRM_END() LOG( LDEV2, "end" )
|
||||
|
||||
#endif // __LOGGER_H__
|
||||
@@ -0,0 +1,69 @@
|
||||
#****************************************************************************
|
||||
# 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 FixedQueue.o ProcessRename.o ReportLog.o
|
||||
|
||||
# Compiler info
|
||||
CC = /usr/bin/g++
|
||||
AR = /usr/bin/ar
|
||||
|
||||
DIR_INCLUDE = -I/usr/local/include
|
||||
ifeq ($(DEBUG), yes)
|
||||
CFLAGS = -Wall -O0 -g -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-D_REENTRANT -D_THREAD_SAFE -D_PTHREADS
|
||||
LFLAGS =
|
||||
DFLAGS =
|
||||
else
|
||||
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-D_REENTRANT -D_THREAD_SAFE -D_PTHREADS
|
||||
LFLAGS =
|
||||
DFLAGS =
|
||||
endif
|
||||
############################
|
||||
|
||||
all:$(LIB)
|
||||
sync
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
|
||||
$(LIB): $(OBJS)
|
||||
$(AR) crsv $@ $^
|
||||
|
||||
|
||||
clean:
|
||||
-rm -f *.o core *.out *.log
|
||||
-rm -f $(LIB)
|
||||
sync
|
||||
|
||||
|
||||
install :
|
||||
sync
|
||||
|
||||
|
||||
# End of Makefile
|
||||
@@ -0,0 +1,185 @@
|
||||
#include "ProcessRename.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/***************************************************************************
|
||||
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 linux의 Process Title을 변경
|
||||
void set_ps_display(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,152 @@
|
||||
#include "ReportLog.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#define REPORT_LOG_NAME "report" // Report Log 폴더 및 파일 명칭 지정자..
|
||||
#define MAX_BUFFER_SIZE 2048 // 임시 버퍼 최대 크기
|
||||
|
||||
|
||||
// 생성자..
|
||||
CReportLog::CReportLog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// 소멸자..
|
||||
CReportLog::~CReportLog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CReportLog::Init( const char * szPath )
|
||||
{
|
||||
// 멤버 변수 초기화.
|
||||
m_strFullPath.clear();
|
||||
m_strLastError.clear();
|
||||
|
||||
// 변수 유효성 검사.
|
||||
if( szPath == NULL || strlen( szPath ) == 0 )
|
||||
{
|
||||
m_strLastError = "Log path empty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log Path check...
|
||||
struct stat dirStat;
|
||||
if( lstat ( szPath, &dirStat ) != 0)
|
||||
{
|
||||
//m_strLastError = "Log path not valid. Check path [" + szPath + "][" + strerror(errno) + "]" ;
|
||||
m_strLastError = "Log path not valid. Check path [";
|
||||
m_strLastError.append( szPath );
|
||||
m_strLastError.append( "][" );
|
||||
m_strLastError.append( strerror(errno) );
|
||||
m_strLastError.append( "]" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// 해당 정보가 Directory 가 아닌 경우
|
||||
if( S_ISDIR( dirStat.st_mode ) == 0 )
|
||||
{
|
||||
if( S_ISLNK( dirStat.st_mode ) == 0 )
|
||||
{
|
||||
//m_strLastError = "Log path not directory or link. Check path [" + szPath + "]";
|
||||
m_strLastError = "Log path not directory or link. Check path [" ;
|
||||
m_strLastError.append( szPath );
|
||||
m_strLastError.append ( "]" );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//m_strLastError = "Log path is symbolic link. path [" + szPath + "]";
|
||||
m_strLastError = "Log path is symbolic link. path [";
|
||||
m_strLastError.append( szPath );
|
||||
m_strLastError.append( "]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 멤버 변수 정보 설정.
|
||||
m_strFullPath = szPath;
|
||||
m_strFullPath.append( "/" );
|
||||
m_strFullPath.append( REPORT_LOG_NAME );
|
||||
|
||||
// 디렉토리 정보 검사
|
||||
if( lstat ( m_strFullPath.c_str(), &dirStat ) == 0)
|
||||
{
|
||||
// 해당 이름을 가진 파일 또는 디렉토리가 존재하고
|
||||
if( S_ISDIR( dirStat.st_mode ) != 0 )
|
||||
{
|
||||
// 해당 이름이 디렉토리인 경우
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 최종 경로에 대한 Directory 가 존재하지 않는 경우 Directory 생성 시도
|
||||
// 2013-11-27 report 로그는 fluentd 에 의해 감시, 분석되어야 하는데.. root 계정이 아닌 다른 td-agent 계정을 사용함.
|
||||
// 이로 인해 fluentd 에서 report 폴더에 접근할 수 있도록 폴더 권한 설정을 777 로 해야 함.
|
||||
if( mkdir( m_strFullPath.c_str(), 0777 ) != 0 )
|
||||
{
|
||||
m_strLastError = "Log directory create failed. Check path [" + m_strFullPath + "][" + strerror(errno) + "]";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CReportLog::Write( const char * szLevel, const char * fmt, ...)
|
||||
{
|
||||
// Get Current Data & Time
|
||||
char szTimeString[256];
|
||||
time_t now = time( NULL );
|
||||
struct tm timeNow;
|
||||
localtime_r( &now, &timeNow );
|
||||
|
||||
// Make File Name
|
||||
std::string fileName = m_strFullPath + "/" + REPORT_LOG_NAME + "_";
|
||||
snprintf( szTimeString, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
|
||||
fileName.append( szTimeString );
|
||||
|
||||
|
||||
// Log file open
|
||||
FILE * pFile = NULL;
|
||||
pFile = fopen( fileName.c_str(), "a+" );
|
||||
if( pFile == NULL )
|
||||
{
|
||||
m_strLastError = "Log file open fail.[" + fileName + "][" + strerror(errno) + "]";
|
||||
return false;
|
||||
}
|
||||
|
||||
// 시간 정보처리
|
||||
snprintf( szTimeString, (size_t)256, "[%04d-%02d-%02d %02d:%02d:%02d]"
|
||||
, timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday
|
||||
, timeNow.tm_hour, timeNow.tm_min, timeNow.tm_sec );
|
||||
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char szBuffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( szBuffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
fclose( pFile );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
|
||||
// Write to log file
|
||||
fprintf( pFile, "%s [%s] %s\n", szTimeString, szLevel, szBuffer );
|
||||
fflush( pFile );
|
||||
|
||||
// 종료 처리.
|
||||
fclose( pFile );
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
Report 로그 처리용 Class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2013/11/25
|
||||
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 __REPORT_LOG_H__
|
||||
#define __REPORT_LOG_H__
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
|
||||
|
||||
/// @brief CReportLog
|
||||
/// 본 클래스는 전달받은 경로 하위 report 폴더 상에...
|
||||
/// 운영자들에게 전달할 report 관련 log 를 기록하기 위한 클래스임.
|
||||
/// lib 에 존재하는 CLogger Class 가 프로세스에 대해 singleton 방식으로 동작하므로... 해당 Class 를 사용하기는 어려움.
|
||||
/// 따라서 report 관련 로그만 전담하여 처리하기 위한 로그 Class 를 추가함.
|
||||
class CReportLog
|
||||
{
|
||||
public:
|
||||
|
||||
// constructor
|
||||
CReportLog();
|
||||
|
||||
// destructor
|
||||
~CReportLog();
|
||||
|
||||
// 초기화..
|
||||
bool Init( const char * szPath );
|
||||
|
||||
// log wirte
|
||||
bool Write( const char * szLevel, const char * fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
// Get last error log
|
||||
void GetLastError( std::string & errorMessage ) { errorMessage = m_strLastError; return; }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Log Full Path
|
||||
std::string m_strFullPath;
|
||||
|
||||
// last Error String
|
||||
std::string m_strLastError;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* __REPORT_LOG_H__ */
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
[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
|
||||
LOG_LEVEL = 7
|
||||
|
||||
# RC ID
|
||||
RC_ID = bd16
|
||||
|
||||
# RCDB Access Information
|
||||
RCDB_IP = 10.3.0.3
|
||||
RCDB_PORT = 6543
|
||||
RCDB_DB_NAME = localdb
|
||||
RCDB_ACCT = syshost
|
||||
RCDB_ACCT_PW = alfkzmf!?{}
|
||||
|
||||
# FHS status broadcasting UDP port ( vmasd broadcasting udp port )
|
||||
# 0 : Not use.
|
||||
#FHS_STATUS_BROADCAST_UDP_PORT = 13201
|
||||
|
||||
#-----------------------------------------------#
|
||||
[rc_mond]
|
||||
|
||||
# FHS csagentd send data(system, service check info) receiving TCP port
|
||||
PORT_TCP_LISTEN_SYSTEM_STAT = 14003
|
||||
PORT_TCP_LISTEN_CHECK_STAT = 14004
|
||||
|
||||
# FHS fimngd communication TCP port
|
||||
# - alive fhs list....
|
||||
PORT_TCP_LISTEN_SEND_INFO = 14005
|
||||
|
||||
# GMS (new_sh_statusd)
|
||||
GMS_SERVER = cc-gms.ktsh.co.kr
|
||||
GMS_PORT_STAT = 13109
|
||||
|
||||
# Max storage usage(%) for prevent content upload
|
||||
# range : 0 ~ 100
|
||||
STORAGE_MAX_USAGE_TO_DISABLE = 98
|
||||
|
||||
# Check FHS memory max usage percent and report (range: 0 ~ 100 )
|
||||
# use default 0 (not check) when not config
|
||||
REPORT_MEMORY_MAX_USAGE = 100
|
||||
|
||||
#-----------------------------------------------#
|
||||
@@ -0,0 +1,143 @@
|
||||
#include "AliveFhsCacheThread.h"
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// alive fhs 정보의 cache 갱신 주기 ( sec )
|
||||
#define ALIVE_FHS_CACHE_INTERVAL 1
|
||||
|
||||
|
||||
// 공유메모리 FHS 정보가 기동초기 완전하지 않아...
|
||||
// 지정된 시간(sec) 동안 skip 처리 하기 위한 define.
|
||||
#define ALIVE_FHS_SKIP_TIME 6
|
||||
|
||||
|
||||
// 생성자
|
||||
CAliveFhsCacheThread::CAliveFhsCacheThread( CShmManager * pShmManager )
|
||||
: m_pShmManager( pShmManager )
|
||||
{
|
||||
// Thread handle 초기화
|
||||
m_threadHandle = 0;
|
||||
|
||||
// vector 객체에 대한 포인터 초기화.
|
||||
m_vecAliveFhs1.clear();
|
||||
m_vecAliveFhs2.clear();
|
||||
m_pCurrent = &( m_vecAliveFhs1 );
|
||||
m_pOld = &( m_vecAliveFhs2 );
|
||||
|
||||
// Skip flag 는 기동 초기 설정 처리.
|
||||
m_bResultSkip = true;
|
||||
}
|
||||
|
||||
// 소멸자
|
||||
CAliveFhsCacheThread::~CAliveFhsCacheThread()
|
||||
{
|
||||
// Thread 가 동작 중인 경우 Thread 동작 정지 처리.
|
||||
if( m_threadHandle != 0 )
|
||||
{
|
||||
pthread_cancel( m_threadHandle );
|
||||
}
|
||||
}
|
||||
|
||||
// Thread 를 생성하여 cache 작업 수행
|
||||
bool CAliveFhsCacheThread::Start( void )
|
||||
{
|
||||
int nResult = pthread_create( &m_threadHandle, NULL, CAliveFhsCacheThread::threadFunc, this );
|
||||
if( nResult != 0 )
|
||||
{
|
||||
// Thread 생성 실패시...
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "AliveFhsCacheThread: Thread create failed.[%d][%s]", errorNum, strerror( errorNum ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Thread 함수
|
||||
void * CAliveFhsCacheThread::threadFunc( void * arg )
|
||||
{
|
||||
CAliveFhsCacheThread * pObject = reinterpret_cast<CAliveFhsCacheThread *>( arg );
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
// SKIP 상태 해지를 판단하기 위한 변수.
|
||||
int nSkipCount = 0;
|
||||
|
||||
// 주기적으로 alive FHS cache 갱신 처리.
|
||||
while( 1 )
|
||||
{
|
||||
pthread_testcancel();
|
||||
pObject->Execute();
|
||||
pthread_testcancel();
|
||||
|
||||
// 지정된 횟수를 초과하면 Skip 처리를 해제한다.
|
||||
if( pObject->m_bResultSkip == true )
|
||||
{
|
||||
if( nSkipCount > ALIVE_FHS_SKIP_TIME )
|
||||
{
|
||||
pObject->m_bResultSkip = false;
|
||||
|
||||
_LOG( LINF, "AliveFhsCacheThread: alive FHS SKIP mode end. ");
|
||||
}
|
||||
else
|
||||
{
|
||||
++nSkipCount;
|
||||
//_LOG( LDBG, "AliveFhsCacheThread: Alive FHS SKIP..." );
|
||||
}
|
||||
}
|
||||
|
||||
// 지정된 주기마다 cache 갱신.
|
||||
sleep( ALIVE_FHS_CACHE_INTERVAL );
|
||||
}
|
||||
|
||||
// Thread 종료시 Handle 초기화
|
||||
pObject->m_threadHandle = 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// 실제 cache 처리를 담당하는 함수.
|
||||
void CAliveFhsCacheThread::Execute()
|
||||
{
|
||||
// 이전 정보를 저장한 vector 초기화.
|
||||
m_pOld->clear();
|
||||
|
||||
// 공유메모리로부터 Alive FHS 정보 저장 처리
|
||||
m_pShmManager->GetAliveFhsList( *m_pOld );
|
||||
|
||||
// 최신 Alive FHS 정보를 사용하도록 포인터 정보 변경 처리.
|
||||
m_pTemp = m_pCurrent;
|
||||
m_pCurrent = m_pOld;
|
||||
m_pOld = m_pTemp;
|
||||
|
||||
// SKIP 모드가 아닌 상태에서 Alive FHS 정보가 유효하지 않은 경우만 로깅 처리.
|
||||
if( m_pCurrent->size() == 0 && m_bResultSkip == false )
|
||||
{
|
||||
_LOG( LWAR, "AliveFhsCacheThread: Alive FHS not exist. [%zu]", m_pCurrent->size());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Alive FHS 목록 제공을 위한 interface 함수.
|
||||
// param vecResult [out] alive fhs 결과 정보를 저장하기 위한 변수.
|
||||
// return -1 : FHS 정보가 아직 불안전하니 SKIP 처리하라는 의미
|
||||
// 그 외 : alive fhs 갯수.
|
||||
int CAliveFhsCacheThread::GetAliveFhs( std::vector<struct FhsServiceStatInfo> & vecResult )
|
||||
{
|
||||
// skip flag 가 설정된 경우...
|
||||
if( m_bResultSkip == true )
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
// 정상 상황인 경우...
|
||||
vecResult = *( m_pCurrent );
|
||||
|
||||
return m_pCurrent->size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/****************************************************************************
|
||||
Alive FHS list cache thread class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/17
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __ALIVE_FHS_CACHE_THREAD_H__
|
||||
#define __ALIVE_FHS_CACHE_THREAD_H__
|
||||
|
||||
|
||||
#include "ShmDefine.h"
|
||||
#include "ShmManager.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
// 공유메모리 상에서 Alive FHS 정보를 주기적으로 조회하여 저장하고...
|
||||
// interface 함수를 통해 해당 정보를 전달 처리하기 위한 Thread Class.
|
||||
class CAliveFhsCacheThread
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// 생성 및 소멸자.
|
||||
CAliveFhsCacheThread( CShmManager * pShmManager );
|
||||
~CAliveFhsCacheThread();
|
||||
|
||||
// Thread 를 생성하여 cache 작업 수행
|
||||
bool Start( void );
|
||||
|
||||
// Alive FHS 목록 제공을 위한 interface 함수.
|
||||
// param vecResult [out] alive fhs 결과 정보를 저장하기 위한 변수.
|
||||
// return -1 : FHS 정보가 아직 불안전하니 SKIP 처리하라는 의미
|
||||
// 그 외 : alive fhs 갯수.
|
||||
int GetAliveFhs( std::vector<struct FhsServiceStatInfo> & vecResult );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// 공유메모리에서 Alive FHS 목록 추출시 사용할 공유메모리 inferface 객체 (생성자를 통해 전달받음)
|
||||
CShmManager * m_pShmManager;
|
||||
|
||||
// 쓰레드 핸들
|
||||
pthread_t m_threadHandle;
|
||||
|
||||
|
||||
// Thread 기동 후 지정된 시간 동안 공유메모리 FHS 정보가 완전하지 않아.. SKIP 하라는 flag
|
||||
bool m_bResultSkip;
|
||||
|
||||
// Alive FHS 목록을 저장할 Vector 객체
|
||||
// - struct FhsServiceStatInfo 는 ShmManager.h 에 정의되어 있음.
|
||||
// - 2개의 list 를 이용하여 목록을 교차하여 갱신처리.
|
||||
std::vector<struct FhsServiceStatInfo> m_vecAliveFhs1;
|
||||
std::vector<struct FhsServiceStatInfo> m_vecAliveFhs2;
|
||||
|
||||
// lock 처리를 최소화하기 위해 포인터를 이용하여 구현.
|
||||
std::vector<struct FhsServiceStatInfo> * m_pCurrent;
|
||||
std::vector<struct FhsServiceStatInfo> * m_pOld;
|
||||
std::vector<struct FhsServiceStatInfo> * m_pTemp;
|
||||
|
||||
private:
|
||||
|
||||
// Thread function....
|
||||
static void * threadFunc( void * arg );
|
||||
|
||||
// 실제 cache 처리를 담당하는 함수.
|
||||
void Execute( void );
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* __ALIVE_FHS_CACHE_THREAD_H__ */
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/***************************************************************************
|
||||
Database Class
|
||||
-----------------------------------------
|
||||
begin : 2010/03/09
|
||||
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.
|
||||
***************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
#include "Database.h"
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
DataBase::~DataBase()
|
||||
{
|
||||
if(m_PGconn != NULL) {
|
||||
PgCloseDB();
|
||||
}
|
||||
}
|
||||
|
||||
PGconn *DataBase::PgOpenDB(string &strHost, int Port, string &strDBName, string &strAcct, string &strPasswd, int timeout)
|
||||
{
|
||||
ostringstream conninfo;
|
||||
|
||||
// CHG 2014-10-29 huibong
|
||||
// application_name add to logging RCDB
|
||||
|
||||
conninfo << "host=" << strHost << " port=" << Port << " dbname=" << strDBName <<
|
||||
" user=" << strAcct << " password=" << strPasswd << " connect_timeout=" << timeout <<
|
||||
" application_name=" << PROG_NAME;
|
||||
|
||||
#ifdef _USE_LIBPQ_KEEPALIVE
|
||||
// This option is supported by at least 9.1.2. and Currently supports Linux systems.
|
||||
conninfo <<" keepalives=1";
|
||||
#endif // _USE_LIBPQ_KEEPALIVE
|
||||
//m_PGconn = PQsetdbLogin(strHost.c_str(), szPort, NULL, NULL, strDBName.c_str(), strAcct.c_str(), strPasswd.c_str());
|
||||
m_PGconn = PQconnectdb(conninfo.str().c_str());
|
||||
if(PQstatus(m_PGconn) == CONNECTION_BAD) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_PGconn;
|
||||
}
|
||||
|
||||
PGconn *DataBase::PgOpenDB(const char *pszDBName)
|
||||
{
|
||||
m_PGconn = PQsetdb(NULL, NULL, NULL, NULL, pszDBName);
|
||||
if(PQstatus(m_PGconn) == CONNECTION_BAD) {
|
||||
return NULL;
|
||||
}
|
||||
return m_PGconn;
|
||||
}
|
||||
|
||||
void DataBase::PgCloseDB()
|
||||
{
|
||||
if(m_PGconn != NULL)
|
||||
{
|
||||
PQfinish(m_PGconn);
|
||||
m_PGconn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int DataBase::PgResult(CFLAG flag)
|
||||
{
|
||||
int fRet = 0;
|
||||
int Result;
|
||||
|
||||
Result = PQresultStatus(m_pRes);
|
||||
switch(Result) {
|
||||
case PGRES_EMPTY_QUERY :
|
||||
fRet = -1;
|
||||
break;
|
||||
case PGRES_BAD_RESPONSE :
|
||||
fRet = -2;
|
||||
break;
|
||||
case PGRES_NONFATAL_ERROR :
|
||||
fRet = -3;
|
||||
break;
|
||||
case PGRES_FATAL_ERROR :
|
||||
fRet = -4;
|
||||
break;
|
||||
case PGRES_TUPLES_OK :
|
||||
fRet = 1;
|
||||
break;
|
||||
case PGRES_COMMAND_OK :
|
||||
fRet = 2;
|
||||
break;
|
||||
}
|
||||
if(fRet < 0) {
|
||||
m_ErrorMessage = PQresultErrorMessage(m_pRes);
|
||||
}
|
||||
m_ResultCode = Result;
|
||||
if(flag == CLEAR && m_pRes) {
|
||||
PQclear(m_pRes);
|
||||
m_pRes = NULL;
|
||||
}
|
||||
return fRet;
|
||||
}
|
||||
|
||||
string &DataBase::GetErrorMessage()
|
||||
{
|
||||
return m_ErrorMessage;
|
||||
}
|
||||
|
||||
int DataBase::GetCmdTuples()
|
||||
{
|
||||
//fprintf(stderr, "DataBase::GetCmdTuples PQcmdTuples %s\n", PQcmdTuples(m_pRes));
|
||||
return (int)atoi(PQcmdTuples(m_pRes));
|
||||
}
|
||||
|
||||
int DataBase::GetNoTuples()
|
||||
{
|
||||
return PQntuples(m_pRes);
|
||||
}
|
||||
|
||||
int DataBase::GetNoFields()
|
||||
{
|
||||
return PQnfields(m_pRes);
|
||||
}
|
||||
|
||||
PGresult *DataBase::GetRes()
|
||||
{
|
||||
return m_pRes;
|
||||
}
|
||||
|
||||
void DataBase::PgClear()
|
||||
{
|
||||
if(m_pRes)
|
||||
{
|
||||
PQclear(m_pRes);
|
||||
m_pRes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *DataBase::GetValue(int tuple, int field)
|
||||
{
|
||||
return PQgetvalue(m_pRes, tuple, field);
|
||||
}
|
||||
|
||||
int DataBase::PgDoExec(char *pszQuery)
|
||||
{
|
||||
return this->PgDoExec(pszQuery, NOT_CLEAR);
|
||||
}
|
||||
|
||||
int DataBase::PgDoExec(string &strQuery)
|
||||
{
|
||||
return this->PgDoExec((char *)strQuery.c_str(), NOT_CLEAR);
|
||||
}
|
||||
|
||||
int DataBase::PgDoExec(char *pszQuery, CFLAG flag)
|
||||
{
|
||||
if(m_PGconn == NULL) return -1;
|
||||
if(PQstatus(m_PGconn) != CONNECTION_OK) return -2;
|
||||
m_pRes = PQexec(m_PGconn, pszQuery);
|
||||
int r = PgResult(flag);
|
||||
return r;
|
||||
}
|
||||
|
||||
int DataBase::PgDoExecParams(char *pszQuery, int nParamCnt, const char * const *paramValues ,CFLAG flag)
|
||||
{
|
||||
if(m_PGconn == NULL) return -1;
|
||||
if(PQstatus(m_PGconn) != CONNECTION_OK) return -2;
|
||||
m_pRes = PQexecParams(m_PGconn, pszQuery, nParamCnt, NULL, paramValues, NULL, NULL, 0);
|
||||
int r = PgResult(flag);
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
int DataBase::PgEscapeString(char *to, const char *from, size_t length)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
//PQescapeStringConn(m_PGconn, to, from, length, &retval);
|
||||
PQescapeString(to, from, length);
|
||||
return retval;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
Database Class
|
||||
-----------------------------------------
|
||||
begin : 2010/03/11
|
||||
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 __DATABASE_H__
|
||||
#define __DATABASE_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "libpq-fe.h"
|
||||
#define MaxSizeOfDBQuery 1024*9
|
||||
|
||||
using namespace std;
|
||||
class DataBase
|
||||
{
|
||||
public:
|
||||
enum CFLAG { CLEAR = 1, NOT_CLEAR };
|
||||
DataBase() { m_PGconn = NULL; m_pRes = NULL;}
|
||||
~DataBase();
|
||||
PGconn *PgOpenDB(string &strHost, int Port, string &strDBName, string &strAcct, string &strPasswd, int timeout = 10);
|
||||
PGconn *PgOpenDB(const char *pszDBName);
|
||||
void PgCloseDB();
|
||||
int PgResult(CFLAG flag);
|
||||
PGconn *GetPgConn(){ return m_PGconn;}
|
||||
PGresult *GetRes();
|
||||
void SetRes(PGresult * v) {m_pRes = v;}
|
||||
int GetCmdTuples();
|
||||
int GetNoTuples();
|
||||
int GetNoFields();
|
||||
int GetResultCode() { return m_ResultCode; }
|
||||
char *GetValue(int tuple, int field);
|
||||
void PgClear();
|
||||
int PgDoExec(string &strQuery);
|
||||
int PgDoExec(char *pszQuery);
|
||||
int PgDoExec(char *pszQuery, CFLAG flag);
|
||||
int PgDoExecParams(char *pszQuery, int nParamCnt, const char * const *paramValues ,CFLAG flag = NOT_CLEAR);
|
||||
int PgEscapeString(char *to, const char *from, size_t length);
|
||||
string &GetErrorMessage();
|
||||
private:
|
||||
int m_ResultCode;
|
||||
PGconn *m_PGconn;
|
||||
PGresult *m_pRes;
|
||||
string m_ErrorMessage;
|
||||
};
|
||||
|
||||
#endif // ~__DATABASE_H__
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "GarbageCleanThread.h"
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
// Expire 처리를 위한 시간( sec )
|
||||
// - vmasd 정보는 6 sec 마다 전송되므로... 기존에도 20 sec expire 처리했음.
|
||||
// - csagentd 는 4 sec 마다 전송하지만.. tcp 세션(timeout 6 sec)이라.. 정상적인 상황이라면 정리할 필요 없음.
|
||||
#define CLIENT_SHM_EXPIRE_TIME 20
|
||||
|
||||
// 작업 수행 주기 ( sec )
|
||||
// - 빠른 판단으로 clean 처리를 해야.. FHS, RCDB 에 잘못된 정보가 전달되지 않음
|
||||
// - 2018-02-22 #31703 일감에서 각 FHS 에서 정보 수신 timeout 발생시 대기가 아닌 세션을 종료하도록 수정
|
||||
// 이로 인해 기존과 같이 빠른 garbage 처리가 필요하지 않아.. 동작 주기를 2 sec -> 4 sec 로 수정.
|
||||
#define CLEAN_JOB_INTERVAL 4
|
||||
|
||||
|
||||
// 생성자
|
||||
CGarbageCleanThread::CGarbageCleanThread( CShmManager * pShmManager )
|
||||
: m_pShmManager( pShmManager )
|
||||
{
|
||||
// Thread handle 초기화
|
||||
m_threadHandle = 0;
|
||||
}
|
||||
|
||||
// 소멸자
|
||||
CGarbageCleanThread::~CGarbageCleanThread()
|
||||
{
|
||||
// Thread 가 동작 중인 경우 Thread 동작 정지 처리.
|
||||
if( m_threadHandle != 0 )
|
||||
{
|
||||
pthread_cancel( m_threadHandle );
|
||||
}
|
||||
}
|
||||
|
||||
// Thread 를 생성하여 cache 작업 수행
|
||||
bool CGarbageCleanThread::Start( void )
|
||||
{
|
||||
int nResult = pthread_create( &m_threadHandle, NULL, CGarbageCleanThread::threadFunc, this );
|
||||
if( nResult != 0 )
|
||||
{
|
||||
// Thread 생성 실패시...
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "GarbageCleanThread: Thread create failed.[%d][%s]", errorNum, strerror( errorNum ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Thread 함수
|
||||
void * CGarbageCleanThread::threadFunc( void * arg )
|
||||
{
|
||||
CGarbageCleanThread * pObject = reinterpret_cast<CGarbageCleanThread *>( arg );
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
// 주기적으로 공유메모리 clean 작업 수행
|
||||
while( 1 )
|
||||
{
|
||||
pthread_testcancel();
|
||||
pObject->Execute();
|
||||
pthread_testcancel();
|
||||
|
||||
// 지정된 주기마다...
|
||||
sleep( CLEAN_JOB_INTERVAL );
|
||||
}
|
||||
|
||||
// Thread 종료시 Handle 초기화
|
||||
pObject->m_threadHandle = 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// 실제 공유메모리 clean 처리를 담당하는 함수.
|
||||
void CGarbageCleanThread::Execute()
|
||||
{
|
||||
// expire 시간 정보
|
||||
time_t expireTime;
|
||||
|
||||
// 현재 시간 정보 추출.
|
||||
// - 시간 동기화 오차보정 관련 방어를 위해 clock_gettime(CLOCK_MONOTONIC) 로 추출된 정보와
|
||||
// - 공유메모리 service.update_time_clock_sec 항목을 비교토록 처리.
|
||||
struct timespec currentClock;
|
||||
memset( ¤tClock, 0x00, sizeof( struct timespec ) );
|
||||
|
||||
clock_gettime( CLOCK_MONOTONIC, ¤tClock );
|
||||
|
||||
// expire 처리할 시간 계산.
|
||||
if( currentClock.tv_sec <= CLIENT_SHM_EXPIRE_TIME )
|
||||
{
|
||||
// 추출된 시간 정보가 너무 작은 경우...
|
||||
// - 이럴 경우는 거의 없지만.. 혹시나 해서...
|
||||
LOG( LWAR, "GarbageCleanThread: expire clock value[%lu] too low. clean job skip.", currentClock.tv_sec );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
int result;
|
||||
|
||||
expireTime = currentClock.tv_sec - CLIENT_SHM_EXPIRE_TIME;
|
||||
//_LOG( LDBG, "GarbageCleanThread: expire clock value[%lu]", expireTime );
|
||||
|
||||
// 공유메모리에 expire 처리 요청.
|
||||
result= m_pShmManager->ExpireClient( expireTime );
|
||||
|
||||
if( result > 0 )
|
||||
{
|
||||
_LOG( LINF, "GarbageCleanThread: client expire count[%d] expire_clock[%lu]", result, expireTime );
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/****************************************************************************
|
||||
shared memory garbage client info clean thread class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/23
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __GARBAGE_CLEAN_THREAD_H__
|
||||
#define __GARBAGE_CLEAN_THREAD_H__
|
||||
|
||||
|
||||
#include "ShmDefine.h"
|
||||
#include "ShmManager.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
// Shared memory 상의 garbage client 정보를 확인하여 정리 작업을 수행하기 위한 Thread class
|
||||
// - vmasd 종료, csagentd 의 이상 동작 등으로 인해
|
||||
// - 공유메모리에 저장된 client 정보가 갱신되지 않고 오랫동안 유지되는 경우...
|
||||
// - 잘못된 FHS 정보가 FHS, RCDB 상에 전달될 수 있으므로....
|
||||
// - 이를 방지하기 위해 주기적으로 공유메모리의 client 정보를 확인하여... 유효하지 않은 정보는 정리 처리해 준다.
|
||||
class CGarbageCleanThread
|
||||
{
|
||||
public:
|
||||
|
||||
// 생성 및 소멸자.
|
||||
CGarbageCleanThread( CShmManager * pShmManager );
|
||||
~CGarbageCleanThread();
|
||||
|
||||
// Thread 를 생성하여 작업 수행
|
||||
bool Start( void );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// 공유메모리 접근을 위한 inferface 객체 (생성자를 통해 전달받음)
|
||||
CShmManager * m_pShmManager;
|
||||
|
||||
// 쓰레드 핸들
|
||||
pthread_t m_threadHandle;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Thread function....
|
||||
static void * threadFunc( void * arg );
|
||||
|
||||
// 실제 작업 처리를 담당하는 함수.
|
||||
void Execute( void );
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* __GARBAGE_CLEAN_THREAD_H__ */
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
#include "GmsSendThread.h"
|
||||
#include "Logger.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
// GMS 전송 주기 (sec)
|
||||
// rc_vrcd : 8 sec
|
||||
// rc_statd : 10 sec ( sqlite 의 SQLITE_BUSY 발생 최소화 목적 )
|
||||
// rc_mond : 10 sec ( FHS csagentd 로 부터 10 sec 단위로 시스템 정보를 수신하므로.. )
|
||||
#define GMS_SEND_INTERVAL 10
|
||||
|
||||
|
||||
// 생성자..
|
||||
CGmsSendThread::CGmsSendThread( CShmManager * pShmManager )
|
||||
: m_pShmManager( pShmManager)
|
||||
{
|
||||
// Thread Handle 초기화
|
||||
m_threadHandle = 0;
|
||||
|
||||
// 저장 객체 초기화 및 빠른 처리를 위한 예약 처리.
|
||||
m_vecSystemInfo.clear();
|
||||
|
||||
// 1024 개 까지 저장가능토록... (640 * 1024 = 640 KByte)
|
||||
m_vecSystemInfo.reserve( MAX_CLIENT_COUNT );
|
||||
|
||||
}
|
||||
|
||||
// 소멸자..
|
||||
CGmsSendThread::~CGmsSendThread()
|
||||
{
|
||||
// Thread 가 동작 중인 경우 Thread 동작 정지 처리.
|
||||
if( m_threadHandle != 0 )
|
||||
pthread_cancel(m_threadHandle);
|
||||
}
|
||||
|
||||
|
||||
// Thread 를 생성하여 작업을 시작한다...
|
||||
bool CGmsSendThread::Start()
|
||||
{
|
||||
int nResult = pthread_create( &m_threadHandle, NULL, CGmsSendThread::threadFunc, this );
|
||||
if( nResult != 0 )
|
||||
{
|
||||
// Thread 생성 실패시...
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "GmsSendThread: Thread create failed.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Thread 함수...
|
||||
void * CGmsSendThread::threadFunc( void * arg )
|
||||
{
|
||||
CGmsSendThread * pObject = reinterpret_cast<CGmsSendThread *>(arg);
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
// 초기 기동시...FHS 상태 정보가 아직 수집되지 않은 상태이므로...
|
||||
// 잠시 sleep 했다가.. 작업을 시작한다.
|
||||
sleep( GMS_SEND_INTERVAL );
|
||||
|
||||
// 주기적으로 GMS 에 전송 처리
|
||||
while( 1 )
|
||||
{
|
||||
pthread_testcancel();
|
||||
pObject->Execute();
|
||||
pthread_testcancel();
|
||||
|
||||
sleep( GMS_SEND_INTERVAL );
|
||||
}
|
||||
|
||||
// Thread 종료시 Handle 초기화
|
||||
pObject->m_threadHandle = 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// 실제 GMS 로 RC 상태 정보 전송 작업을 수행한다...
|
||||
void CGmsSendThread::Execute()
|
||||
{
|
||||
|
||||
// 공유메모리의 RC 정보를 멤버변수 m_vecSystemInfo 에 저장 처리.
|
||||
m_vecSystemInfo.clear();
|
||||
m_pShmManager->GetGmsSendList( m_vecSystemInfo );
|
||||
|
||||
// 멤버 변수 m_vecSystemInfo 에 저장된 RC 정보를 GMS 로 전송 처리.
|
||||
// => 전송할 정보가 없을 경우에는 전송하지 않는다.
|
||||
// => GMS Web 상에는 이전에 수신된 정보로 표시됨.
|
||||
if( m_vecSystemInfo.empty() == false )
|
||||
{
|
||||
/*
|
||||
// Debug 목적..
|
||||
for( unsigned int i = 0; i < m_vecSystemInfo.size(); ++i )
|
||||
{
|
||||
_LOG( LDBG, "GmsSendThread: vector result [%s][%lu] [%d][%lu][%u] "
|
||||
, m_vecSystemInfo[i].domain, m_vecSystemInfo[i].stamp
|
||||
, m_vecSystemInfo[i].manual_disable, m_vecSystemInfo[i].free, m_vecSystemInfo[i].traffic_ob );
|
||||
}
|
||||
*/
|
||||
|
||||
// GMS 로 전송 처리..
|
||||
// 전송 결과는 본 Thread 에서는 중요하지 않으므로.. 반환값 검사 안함.
|
||||
unsigned int nSendSize = sizeof( struct PacketDataGms ) * m_vecSystemInfo.size();
|
||||
m_socketGms.SendData( m_vecSystemInfo.size(), (char *)( &m_vecSystemInfo[0] ), nSendSize );
|
||||
|
||||
// 로깅
|
||||
_LOG( LINF, "GmsSendThread: GMS send data. count [%zu]", m_vecSystemInfo.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// GMS 로 전송할 Data 가 없는 경우.. 로깅 처리..
|
||||
_LOG( LINF, "GmsSendThread: GMS send data empty. not send.." );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/****************************************************************************
|
||||
GMS Send Thread Class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/27
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __GMS_SEND_THREAD_H__
|
||||
#define __GMS_SEND_THREAD_H__
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "ProtocolGms.h"
|
||||
#include "SocketGms.h"
|
||||
#include "ShmManager.h"
|
||||
|
||||
|
||||
/// @brief CGmsSendThread
|
||||
/// 본 클래스는 Thread 클래스로서...
|
||||
/// FHS 등의 상태 정보를 주기적으로 GMS 에 전송 처리한다.
|
||||
class CGmsSendThread
|
||||
{
|
||||
public:
|
||||
|
||||
// 생성 및 소멸자.
|
||||
CGmsSendThread( CShmManager * pShmManager );
|
||||
~CGmsSendThread();
|
||||
|
||||
// GMS 로 전송 작업을 시작
|
||||
bool Start( void );
|
||||
|
||||
private:
|
||||
|
||||
// Thread function....
|
||||
static void * threadFunc( void * arg );
|
||||
|
||||
// 실제 GMS 로 정보 전송을 담당하는 함수...
|
||||
void Execute( void );
|
||||
|
||||
private:
|
||||
|
||||
// 쓰레드 핸들
|
||||
pthread_t m_threadHandle;
|
||||
|
||||
// 공유메모리 접근을 위한 inferface 객체 (생성자를 통해 전달받음)
|
||||
CShmManager * m_pShmManager;
|
||||
|
||||
|
||||
// FHS 등의 상태 정보를 저장할 Vector 객체
|
||||
std::vector<struct PacketDataGms> m_vecSystemInfo;
|
||||
|
||||
// GMS 로 Data 전송을 담당할 Socket 처리 Class.
|
||||
CSocketGms m_socketGms;
|
||||
|
||||
};
|
||||
|
||||
#endif /* __GMS_SEND_THREAD_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
||||
/****************************************************************************
|
||||
Main.h for rc_mond
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/06/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __RC_MOND_MAIN_H__
|
||||
#define __RC_MOND_MAIN_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @brief 사용 방법을 화면에 표시하기 위한 함수.
|
||||
void PrintUsage( void );
|
||||
|
||||
/// @brief Version 정보를 화면에 표시하기 위한 함수
|
||||
void PrintVersion( void );
|
||||
|
||||
/// @brief 현재 Process가 기동중인지 여부를 판단하기 위한 함수( 프로세스 중복 실행 체크)
|
||||
/// @return 이미 해당 프로세스가 기동 중인 경우 true 반환, 그렇지 않으면 false 반환.
|
||||
bool IsCurrentProcessRun( void );
|
||||
|
||||
/// @brief std 상에 trim 함수가 없어서 직접 구현 아니면 boost/algorithm/string.hpp 상의 boost::trim 함수 사용
|
||||
/// @param str [in/out] Trim 할 문자열을 저장한 String 참조변수.
|
||||
/// @return void
|
||||
void Trim( std::string & str );
|
||||
|
||||
/// @brief 프로세스 종료에 따른 반복적인 종료 관련 작업을 수행하기 위한 함수.
|
||||
void ReadyToExit( void );
|
||||
|
||||
/// @brief Main 프로세스 signal 처리 설정을 위한 함수
|
||||
/// @return void
|
||||
void SetSignalMain( void );
|
||||
|
||||
/// @brief vmasd 가 전송하는 시스템 정보 수신을 담당할 Worker 프로세스 생성.
|
||||
/// @return 생성 성공시 true, 실패시 false
|
||||
bool MakeWorkerRecvVmasd();
|
||||
|
||||
/// @brief csagentd 가 전송하는 FHS system 상태 정보 수신을 담당할 Worker 프로세스 생성.
|
||||
/// @return 생성 성공시 true, 실패시 false
|
||||
bool MakeWorkerRecvSystem();
|
||||
|
||||
/// @brief csagentd 가 전송하는 FHS check 상태 정보 수신을 담당할 Worker 프로세스 생성.
|
||||
/// @return 생성 성공시 true, 실패시 false
|
||||
bool MakeWorkerRecvCheck();
|
||||
|
||||
/// @brief 각 Client 의 요청을 수신하여.. Alive FHS 목록 등의 정보 전달을 담당할 Worker 프로세스 생성.
|
||||
/// @return 생성 성공시 true, 실패시 false
|
||||
bool MakeWorkerSendInfo();
|
||||
|
||||
/// @brief 각 FHS 정보의 GMS 전송, Top FHS 정보의 RCDB 업데이트 등을 수행할 Worker 프로세스 생성.
|
||||
/// @return 생성 성공시 true, 실패시 false
|
||||
bool MakeWorkerControl();
|
||||
|
||||
// FHS vmasd 로 부터 Broadcast 되는 FHS 상태 정보 수신을 위한 UDP Receive Socket 생성
|
||||
bool MakeVmasdRecvSocket( void );
|
||||
|
||||
// FHS csagentd 가 전송하는 시스템 상태 정보 수신을 위한 TCP listen socket 생성
|
||||
bool MakeSystemRecvSocket( void );
|
||||
|
||||
// FHS csagentd 가 전송하는 서비스 상태 체크 정보 수신을 위한 TCP listen socket 생성
|
||||
bool MakeCheckRecvSocket( void );
|
||||
|
||||
// fimngd 등과 같은 외부 모듈과 통신을 통해 정보를 전달하기 위한 TCP listen socket 생성
|
||||
bool MakeInfoSendSocket( void );
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __RC_MOND_MAIN_H__ */
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#****************************************************************************
|
||||
# Makefile for rc_mond
|
||||
# -----------------------------------------
|
||||
#
|
||||
# begin : 2015/06/02
|
||||
# copyright : (C) 2005 Solbox Inc.
|
||||
# author : Dev Storage Team
|
||||
# email : huibong@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 = rc_mond
|
||||
REVISION = 1440
|
||||
PROG_VERSION = 3.5.0.$(REVISION)-`date +%Y%m%d%H%M%S`
|
||||
|
||||
|
||||
DEFAULT_CONFIG_FILE = /user/service/etc/rcts.conf
|
||||
MAX_CLIENT_COUNT = 1024
|
||||
|
||||
INSTALL_BIN = /user/service/bin
|
||||
INSTALL_CONF = /user/service/etc
|
||||
|
||||
# Compiler info
|
||||
CC = /usr/bin/g++
|
||||
|
||||
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized \
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual \
|
||||
-fno-rtti -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
|
||||
LFLAGS =
|
||||
|
||||
DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -DMAX_CLIENT_COUNT=$(MAX_CLIENT_COUNT)
|
||||
|
||||
# Application Enviroment
|
||||
APP = $(PROG_NAME) rc_show
|
||||
|
||||
DIR_INCLUDE = -I../lib -I/user/db/pgsql/include
|
||||
DIR_LIB = -L../lib
|
||||
|
||||
|
||||
OBJ = ProcessConfig.o ShmManager.o ShmClientInfo.o SocketCsagentd.o \
|
||||
AliveFhsCacheThread.o SocketSendInfo.o \
|
||||
GarbageCleanThread.o SocketGms.o GmsSendThread.o Database.o RcdbInfo.o TopFhsUpdateThread.o \
|
||||
WorkerRecvVmasd.o WorkerRecvSystem.o WorkerRecvCheck.o WorkerSendInfo.o WorkerControl.o \
|
||||
Main.o
|
||||
|
||||
LIBS = ../lib/libInterCommon.a -lpthread -lrt /user/db/pgsql/lib/libpq.a
|
||||
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
|
||||
all:$(APP)
|
||||
sync
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
|
||||
$(PROG_NAME): $(OBJ)
|
||||
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
|
||||
|
||||
|
||||
rc_show: ShmMonitor.o
|
||||
$(CC) -o $@ $^
|
||||
|
||||
|
||||
clean:
|
||||
-rm -f *.o core.* *.out *.log
|
||||
-rm -f $(APP)
|
||||
sync
|
||||
|
||||
|
||||
install : $(APP)
|
||||
-cp $(PROG_NAME) $(INSTALL_BIN)/$(PROG_NAME)
|
||||
-cp rc_show $(INSTALL_BIN)/rc_show
|
||||
sync
|
||||
|
||||
|
||||
# End of Makefile
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
#include "ProcessConfig.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
// static 변수 초기화
|
||||
CProcessConfig * CProcessConfig::m_pInstance = NULL;
|
||||
|
||||
|
||||
// 생성자
|
||||
CProcessConfig::CProcessConfig()
|
||||
{
|
||||
// default 값 설정.
|
||||
|
||||
// FHS_STATUS_BROADCAST_UDP_PORT
|
||||
// 설정값 0 이거나 미 존재시...해당 수신 프로세스 기동하지 않도록 하기 위함.
|
||||
m_nFhsBroadcastRecvPort = 0;
|
||||
|
||||
// REPORT_MEMORY_MAX_USAGE
|
||||
// 설정값이 0 또는 미존재시... 해당 기능을 사용하지 않도록 하기 위해 default 0 값 설정 처리
|
||||
m_nReportMemoryMaxUsage = 0;
|
||||
|
||||
}
|
||||
|
||||
// 소멸자
|
||||
CProcessConfig::~CProcessConfig()
|
||||
{
|
||||
// 객체 소멸시...
|
||||
// 만약 static GetInstance() 함수가 가르키는 객체가 자기 자신이라면...
|
||||
// 소멸 처리에 의해 문제가 발생할 수 있으므로... 이에 대한 처리를 해 준다.
|
||||
if( CProcessConfig::GetInstance() == this )
|
||||
{
|
||||
CProcessConfig::m_pInstance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CProcessConfig::Init( const std::string strProgramName, const std::string & strConfFileName, std::string & strErrorMessage )
|
||||
{
|
||||
|
||||
// 1. 임시 처리용 Instance 를 생성한다.
|
||||
CProcessConfig * pTempInstance = new CProcessConfig();
|
||||
|
||||
// 2. 전달 받은 Config 정보를 임시 Instance 로 로딩한다.
|
||||
// - 만약 로딩이 실패할 경우... 임시 Instance 객체를 삭제 처리한다.
|
||||
if( pTempInstance->Load( strProgramName, strConfFileName, strErrorMessage ) == false )
|
||||
{
|
||||
delete pTempInstance;
|
||||
pTempInstance = NULL;
|
||||
|
||||
return false; // 생성 실패 사유는 Error String 관련 함수를 사용하여 확인.
|
||||
}
|
||||
|
||||
// 3. 전달받은 Conf 정보 로딩에 성공한 경우...
|
||||
// - 기존 Instance 객체가 존재하는 경우.. 교체 처리..
|
||||
// - 기존 Instance 객체가 없는 경우는 신규 Instance 사용토록 처리.
|
||||
if( CProcessConfig::GetInstance() == NULL )
|
||||
{
|
||||
CProcessConfig::m_pInstance = pTempInstance;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Instance replace...
|
||||
CProcessConfig * pPreviosInstance = CProcessConfig::m_pInstance;
|
||||
CProcessConfig::m_pInstance = pTempInstance;
|
||||
|
||||
delete pPreviosInstance;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
CProcessConfig * CProcessConfig::GetInstance()
|
||||
{
|
||||
return CProcessConfig::m_pInstance;
|
||||
}
|
||||
|
||||
|
||||
bool CProcessConfig::Load( const std::string & strProgramName, const std::string & strConfFileName, std::string & strErrorMessage )
|
||||
{
|
||||
// 변수 유효성 확인
|
||||
if( strProgramName.size() <= 0 )
|
||||
{
|
||||
strErrorMessage = "Config Program Name[" + strProgramName + "] not valid.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Config class (lib 하위) 를 이용하여 config 파일 상의 정보를 로딩 처리
|
||||
Config conf;
|
||||
|
||||
if( conf.Open( strConfFileName ) == false )
|
||||
{
|
||||
strErrorMessage = "Config file[" + strConfFileName + "] open failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Config 모듈에 로딩된 정보 중 필요한 정보만 가져온다...
|
||||
// - 만약 오류가 발생할 경우... 해당 내역은 Error String 에 저장 처리...
|
||||
|
||||
std::string strValue;
|
||||
//std::vector< std::string > vecValue;
|
||||
|
||||
|
||||
// DEFAULT_LOG_DIR
|
||||
if( GetConfigValue( conf, strProgramName, "DEFAULT_LOG_DIR", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strLogPath = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// LOG_LEVEL
|
||||
if( GetConfigValue( conf, strProgramName, "LOG_LEVEL", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_nLogLevel = atoi(strValue.c_str());
|
||||
if( m_nLogLevel < 0 || m_nLogLevel > MAX_LOG_LEVEL )
|
||||
{
|
||||
strErrorMessage = "Config [LOG_LEVEL] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RCID
|
||||
if( GetConfigValue( conf, strProgramName, "RC_ID", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strRcId = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RCDB IP
|
||||
if( GetConfigValue( conf, strProgramName, "RCDB_IP", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strRcdbIp = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RCDB PORT
|
||||
if( GetConfigValue( conf, strProgramName, "RCDB_PORT", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_nRcdbPort = atoi( strValue.c_str() );
|
||||
|
||||
if( m_nRcdbPort <= 0 || m_nRcdbPort > 65535 )
|
||||
{
|
||||
strErrorMessage = "Config [RCDB_PORT] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RCDB DB NAME
|
||||
if( GetConfigValue( conf, strProgramName, "RCDB_DB_NAME", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strRcdbName = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RCDB ACCOUNT
|
||||
if( GetConfigValue( conf, strProgramName, "RCDB_ACCT", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strRcdbAcct = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RCDB ACCOUNT PASSWORD
|
||||
if( GetConfigValue( conf, strProgramName, "RCDB_ACCT_PW", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strRcdbAcctPw = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// FHS_STATUS_BROADCAST_UDP_PORT
|
||||
// - vmasd 의 FHS 상태 정보 수신을 위한 Port.
|
||||
// - 생략 또는 0 으로 설정 가능.
|
||||
if( GetConfigValue( conf, strProgramName, "FHS_STATUS_BROADCAST_UDP_PORT", strValue, strErrorMessage ) == false )
|
||||
{
|
||||
// 해당 항목이 존재하지 않는 경우.. 0 으로 설정 처리.
|
||||
m_nFhsBroadcastRecvPort = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nFhsBroadcastRecvPort = atoi( strValue.c_str() );
|
||||
|
||||
// 0 으로 설정된 경우.. 미사용 표시이므로.. Range 검사시 허용 처리함.
|
||||
if( m_nFhsBroadcastRecvPort < 0 || m_nFhsBroadcastRecvPort > 65535 )
|
||||
{
|
||||
strErrorMessage = "Config [FHS_STATUS_BROADCAST_UDP_PORT] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// PORT_TCP_LISTEN_SYSTEM_STAT
|
||||
if( GetConfigValue( conf, strProgramName, "PORT_TCP_LISTEN_SYSTEM_STAT", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_nTcpListenPortSystemStat = atoi( strValue.c_str() );
|
||||
|
||||
if( m_nTcpListenPortSystemStat <= 0 || m_nTcpListenPortSystemStat > 65535 )
|
||||
{
|
||||
strErrorMessage = "Config [PORT_TCP_LISTEN_SYSTEM_STAT] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// PORT_TCP_LISTEN_CHECK_STAT
|
||||
if( GetConfigValue( conf, strProgramName, "PORT_TCP_LISTEN_CHECK_STAT", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_nTcpListenPortCheckStat = atoi( strValue.c_str() );
|
||||
|
||||
if( m_nTcpListenPortCheckStat <= 0 || m_nTcpListenPortCheckStat > 65535 )
|
||||
{
|
||||
strErrorMessage = "Config [PORT_TCP_LISTEN_CHECK_STAT] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// PORT_TCP_LISTEN_SEND_INFO
|
||||
if( GetConfigValue( conf, strProgramName, "PORT_TCP_LISTEN_SEND_INFO", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_nTcpListenPortSendInfo = atoi( strValue.c_str() );
|
||||
|
||||
if( m_nTcpListenPortSendInfo <= 0 || m_nTcpListenPortSendInfo > 65535 )
|
||||
{
|
||||
strErrorMessage = "Config [PORT_TCP_LISTEN_SEND_INFO] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// GMS_SERVER
|
||||
if( GetConfigValue( conf, strProgramName, "GMS_SERVER", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strGmsServer = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// GMS_PORT_STAT -> 각 RC 의 상태 정보를 GMS 로 전송하기 위한 통신 port
|
||||
if( GetConfigValue( conf, strProgramName, "GMS_PORT_STAT", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_nGmsPortStat = atoi( strValue.c_str() );
|
||||
|
||||
if( m_nGmsPortStat <= 0 || m_nGmsPortStat > 65535 )
|
||||
{
|
||||
strErrorMessage = "Config [GMS_PORT_STAT] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// STORAGE_MAX_USAGE_TO_DISABLE
|
||||
if( GetConfigValue( conf, strProgramName, "STORAGE_MAX_USAGE_TO_DISABLE", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_nStorageMaxUsageToDisable = atoi( strValue.c_str() );
|
||||
if( m_nStorageMaxUsageToDisable < 0 || m_nStorageMaxUsageToDisable > 100 )
|
||||
{
|
||||
strErrorMessage = "Config [STORAGE_MAX_USAGE_TO_DISABLE] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// REPORT_MEMORY_MAX_USAGE
|
||||
// - FHS memory usage 값이 지정된 값 이상을 경우 report 로깅 처리
|
||||
// - 생략 또는 0 으로 설정 가능
|
||||
if( GetConfigValue( conf, strProgramName, "REPORT_MEMORY_MAX_USAGE", strValue, strErrorMessage ) == false )
|
||||
{
|
||||
// 해당 항목이 존재하지 않는 경우.. 0 으로 설정 처리
|
||||
m_nReportMemoryMaxUsage = 0 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nReportMemoryMaxUsage = atoi( strValue.c_str() );
|
||||
|
||||
// 0 인 경우 미사용 설정이므르.. Range 검사시 허용 처리
|
||||
if( m_nReportMemoryMaxUsage < 0 || m_nReportMemoryMaxUsage > 100 )
|
||||
{
|
||||
strErrorMessage = "Config [REPORT_MEMORY_MAX_USAGE] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// conf 정보 로딩이 모두 정상적으로 완료된 경우... 마지막으로 전달받은 config 명, section 정보를 저장한다.
|
||||
m_strConfigFileName = strConfFileName;
|
||||
m_strProgramName = strProgramName;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CProcessConfig::GetConfigValue( Config & conf, const std::string & strProgramName, const std::string strKey, std::string & strValue, std::string & strErrorMessage )
|
||||
{
|
||||
// conf get value
|
||||
if( conf.GetConfig( strProgramName, strKey, strValue) == false )
|
||||
{
|
||||
if( conf.GetConfig( "COMMON", strKey, strValue) == false )
|
||||
{
|
||||
strErrorMessage = "Config [" + strKey + "] value is not exist";
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// value check.
|
||||
if( strValue.empty() == true )
|
||||
{
|
||||
strErrorMessage = "Config [" + strKey + "] value is not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/****************************************************************************
|
||||
rc_mond config processing module
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/06/03
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __PROCESS_CONFIG_H__
|
||||
#define __PROCESS_CONFIG_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
// 본 모듈은 conf 파일의 정보를 read 하여... 본 프로세스 관련 설정 정보를 저장한다.
|
||||
// 본 모듈은 singleton 으로 동작시켜 Main 프로세스 및 Worker 프로세스에서도 접근이 가능토록 한다.
|
||||
// conf 파일에 대한 파싱 및 설정 정보 추출은 lib 하위의 Config 클래스를 이용한다.
|
||||
// 본 객체는 singleton 객체이므로 상속받아 사용하지 않도록 한다. ( 상속받아 사용할 수 없도록 private 처리함 )
|
||||
class CProcessConfig
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
// sigleton 객체 생성을 위해 생성자를 public 으로 처리하지 않음.
|
||||
CProcessConfig();
|
||||
|
||||
// 소멸자
|
||||
virtual ~CProcessConfig();
|
||||
|
||||
static CProcessConfig * m_pInstance;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// 객체 초기화 처리용 Function.
|
||||
// 본 함수 호출시 Instance 생성 후 입력 받은 Config 파일 load.
|
||||
// 따라서 본 함수를 호출하지 않을 경우.. GetInstance() 함수는 NULL 을 반환
|
||||
// 본 함수를 객체가 생성된 상태에서 재 호출할 경우
|
||||
// - 주어진 Conf 파일 정보가 정확하다면.. conf 정보를 다시 load 함.
|
||||
// - 주어진 conf 파일 정보가 부정확하다면... 이전 conf 를 계속 사용함.
|
||||
static bool Init( const std::string strProgramName, const std::string & strConfFileName, std::string & strErrorMessage );
|
||||
|
||||
// Singleton 객체 접근 메소드
|
||||
static CProcessConfig * GetInstance();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// 전달받은 conf 파일에서 해당 config 정보를 로드하여 멤버 변수에 저장한다.
|
||||
// 만약 반환값이 false 인 경우 해당 오류 관련 내역은 strErrorMessage 변수에 저장된다.
|
||||
bool Load( const std::string & strProgramName, const std::string & strConfFileName, std::string & strErrorMessage );
|
||||
|
||||
|
||||
// Config 객체로 부터 지정된 strKey 정보를 가져와 유효성 여부를 판단.
|
||||
// 반환값이 false 인 경우 strErrorMessage 상에 오류 내역이 저장된다.
|
||||
bool GetConfigValue( Config & conf, const std::string & strProgramName, const std::string strKey, std::string & strValue, std::string & strErrorMessage );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// 객체 초기화시 전달받은 정보
|
||||
std::string m_strConfigFileName; // 설정 파일 정보
|
||||
std::string m_strProgramName; // 프로그램 명 (conf 상에서 해당 프로그램의 설정 정보를 가져올 때 사용)
|
||||
|
||||
|
||||
// 기본 설정 정보.
|
||||
std::string m_strLogPath; // 로그 저장 Path (/user/service/logs)
|
||||
int m_nLogLevel; // 로그 기록 Level
|
||||
|
||||
std::string m_strRcId; // RC ID
|
||||
|
||||
std::string m_strRcdbIp; // RCDB IP
|
||||
unsigned int m_nRcdbPort; // RCDB Port
|
||||
std::string m_strRcdbName; // RCDB DB Name
|
||||
std::string m_strRcdbAcct; // RCDB 접근 계정
|
||||
std::string m_strRcdbAcctPw; // RCDB 접근 Password.
|
||||
|
||||
// FHS 의 vmasd 에서 Broadcasting 하는 UDP Data 수신을 위한 UDP Port = 13201
|
||||
// 0 일 경우.. Broadcasting recv 기능을 사용하지 않는 것으로 판단한다.
|
||||
unsigned int m_nFhsBroadcastRecvPort;
|
||||
|
||||
|
||||
// 프로세스 설정 정보
|
||||
|
||||
// FHS csagentd 가 전송하는 FHS system 상태 정보 수신을 위한 TCP port = 14003
|
||||
unsigned int m_nTcpListenPortSystemStat;
|
||||
|
||||
// FHS csagentd 가 전송하는 FHS service check 상태 정보 수신을 위한 TCP port = 14004
|
||||
unsigned int m_nTcpListenPortCheckStat;
|
||||
|
||||
// fimngd 등의 Client 요청에 대해 Alive FHS 목록 등의 결과 전달을 위한 listen 할 TCP port = 14005
|
||||
unsigned int m_nTcpListenPortSendInfo;
|
||||
|
||||
std::string m_strGmsServer; // GMS new_sh_statusd server domain
|
||||
unsigned int m_nGmsPortStat; // GMS new_sh_statusd server tcp port
|
||||
|
||||
// 업로드 방지 처리 관련 Storage 최대 사용량 설정값. (%)
|
||||
int m_nStorageMaxUsageToDisable;
|
||||
|
||||
// 2018-01-11 NEW huibong 메모리 사용량 초과시 report 기능 추가 (#31360, #31679)
|
||||
// - FHS memory 사용량(%) check 를 위한 설정값 (%)
|
||||
int m_nReportMemoryMaxUsage;
|
||||
|
||||
|
||||
public: // 멤버 변수에 대한 Get 함수 선언 및 정의
|
||||
|
||||
const char * GetConfigFileName() { return m_strConfigFileName.c_str(); }
|
||||
const char * GetProgramName() { return m_strProgramName.c_str(); }
|
||||
|
||||
const char * GetLogPath() { return m_strLogPath.c_str(); }
|
||||
int GetLogLevel() { return m_nLogLevel; }
|
||||
|
||||
const char * GetRcId() { return m_strRcId.c_str(); }
|
||||
|
||||
const char * GetRcdbIp() { return m_strRcdbIp.c_str(); }
|
||||
unsigned int GetRcdbPort() { return m_nRcdbPort; }
|
||||
const char * GetRcdbName() { return m_strRcdbName.c_str(); }
|
||||
const char * GetRcdbAcct() { return m_strRcdbAcct.c_str(); }
|
||||
const char * GetRcdbAcctPw() { return m_strRcdbAcctPw.c_str(); }
|
||||
|
||||
unsigned int GetFhsBroadcastRecvPort() { return m_nFhsBroadcastRecvPort; }
|
||||
|
||||
unsigned int GetPortRecvSystem() { return m_nTcpListenPortSystemStat; }
|
||||
unsigned int GetPortRecvCheck() { return m_nTcpListenPortCheckStat; }
|
||||
|
||||
unsigned int GetPortSendInfo() { return m_nTcpListenPortSendInfo; }
|
||||
|
||||
const char * GetGmsServer() { return m_strGmsServer.c_str(); }
|
||||
unsigned int GetGmsPortStat() { return m_nGmsPortStat; }
|
||||
|
||||
int GetStorageMaxUsageToDisable() { return m_nStorageMaxUsageToDisable; }
|
||||
|
||||
int GetReportMemoryMaxUsage() { return m_nReportMemoryMaxUsage; }
|
||||
|
||||
};
|
||||
|
||||
#endif /* __PROCESS_CONFIG_H__ */
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/****************************************************************************
|
||||
csagentd 와의 통신 관련 protocol 정의
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __PROTOCOL_CSAGENTD_H__
|
||||
#define __PROTOCOL_CSAGENTD_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Packet Header stx 코드
|
||||
#define HEADER_STX_CODE_CSAGENTD 0x05
|
||||
|
||||
// Packet Header type 구분코드
|
||||
#define HEADER_TYPE_REQUEST 0x00
|
||||
#define HEADER_TYPE_RESPONSE 0x01
|
||||
|
||||
// Packet Header command 구분 코드.
|
||||
#define COMMAND_TRANSFER_SYSTEM 0x01 // system 수집 정보 전송.
|
||||
#define COMMAND_TRANSFER_SERVICE 0x02 // service 상태 check 정보 전송.
|
||||
|
||||
// 기타 정보
|
||||
#define LENGTH_FIELD_SIZE 4 // 가변데이터 형식 사용시 Length 필드의 메모리 크기 (unsigned int)
|
||||
|
||||
|
||||
// FHS csagentd 와 통신시 사용할 통신 Header
|
||||
// - 계산상 크기는 16Byte 이지만...
|
||||
// - 통신상 sizeof() : 20Byte ( 64Bit OS )
|
||||
struct PacketHeaderCsagentd {
|
||||
|
||||
char stx; // Packet 유효성 관리 코드
|
||||
char type; // Request or Response 여부 ( 0x00: Request, 0x01: Response )
|
||||
char command[4]; // Command Code ( 4 Byte) : 0th csagent-rc_mond 만 사용.
|
||||
char result[4]; // Result Code ( 4 Byte )
|
||||
unsigned int data_length; // Packet Data 부분의 길이값 ( Network Byte Order 사용)
|
||||
|
||||
// 2015-05-15 huibong
|
||||
// Protocol version 정보 추가로 인해... extend_code 2Byte 중 1Byte 사용.
|
||||
//char extend_code[2]; // 확장 및 Padding bits ( 2 Byte )
|
||||
|
||||
char protocol_version; // Packet Data 의 Protocol Version 정보. (1 Byte)
|
||||
char extend_code; // 확장 및 Padding bits ( 1 Byte )
|
||||
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
||||
// RC ID 최대 길이.
|
||||
#define CSAGENTD_RC_ID_MAX_LENGTH 31
|
||||
|
||||
// hostname 최대 길이.
|
||||
#define CSAGENTD_HOST_NAME_MAX_LENGTH 63
|
||||
|
||||
|
||||
// FHS csagentd 에서 수신될 system 수집 data 구조체 protocol version 중 처리 가능한 최대 Version 정보.
|
||||
// - 최초 버전이므로 0x00 으로 설정.
|
||||
#define PARSE_MAX_PROTOCOL_VERSION_SYSTEM 0x00
|
||||
|
||||
// FHS csagentd 에서 수신될 system 수집정보 data 구조체
|
||||
// - 전송할 항목이 많아... struct 형식으로 전송 처리.
|
||||
// - protocol version : 0x00
|
||||
// - 공유메모리 SystemInfo 구조체를 사용하도록 처리할 수 있지만...
|
||||
// -- 공유메모리 구조 변경시.. 통신 오류 발생 가능..
|
||||
// -- 따라서 복잡하더라고.. 공유메모리 구조체와 통신 구조체를 별도로 분리 처리함.
|
||||
struct PacketDataSystem_V00 {
|
||||
|
||||
char rcid[CSAGENTD_RC_ID_MAX_LENGTH + 1]; // RCID 정보, 최대 31 자까지만 허용.
|
||||
char hostname[CSAGENTD_HOST_NAME_MAX_LENGTH + 1]; // hostname, key 값으로 사용, 최대 63자까지만 허용.
|
||||
|
||||
double load_avg[3]; // load average.
|
||||
|
||||
uint64_t memory_total; // Total memory size (byte 단위)
|
||||
uint64_t memory_free; // Free memory size (byte 단위)
|
||||
int memory_usage; // memory 사용률 (%)
|
||||
|
||||
uint64_t swap_total; // Total swap size (byte 단위)
|
||||
uint64_t swap_used; // Used swap size (byte 단위)
|
||||
int swap_usage; // swap 사용률 (%)
|
||||
|
||||
uint64_t storage_total; // Total Storage size (byte 단위)
|
||||
uint64_t storage_avail; // Available Storage size (byte 단위)
|
||||
int storage_max_usage; // Storage 중 최대 사용률 (%)
|
||||
|
||||
uint64_t disk_max_queue; // Disk 상태 정보 중 Max Queue Length
|
||||
double disk_max_busy; // Disk 상태 정보 중 Max busy(%)
|
||||
|
||||
uint64_t network_packet_in; // Network inbound packet count (단위 시간내의 count)
|
||||
uint64_t network_packet_out; // Network outbound packet count (단위 시간내의 count)
|
||||
uint64_t network_traffic_in; // Network inbound 평균 traffic (Byte/sec)
|
||||
uint64_t network_traffic_out; // Network outbound 평균 traffic (Byte/sec)
|
||||
|
||||
unsigned int tcp_total; // TCP 세션 total count
|
||||
unsigned int tcp_80; // TCP 세션 중 local 80 port 를 사용하는 세션 count
|
||||
unsigned int tcp_80_establish; // TCP 세션 중 local 80 port 를 사용하고.. ESTABLISH 상태인 세션 count
|
||||
|
||||
};
|
||||
|
||||
// FHS csagentd 에서 수신될 service 상태 data 구조체 protocol version 중 처리 가능한 최대 version 정보.
|
||||
// - 최초 버전이므로 0x00 으로 설정.
|
||||
#define PARSE_MAX_PROTOCOL_VERSION_SERVICE 0x00
|
||||
|
||||
// FHS csagentd 에서 수신될 service 상태 data 구조체
|
||||
// - protocol version : 0x00
|
||||
struct PacketDataService_V00 {
|
||||
|
||||
char rcid[CSAGENTD_RC_ID_MAX_LENGTH + 1]; // RCID 정보, 최대 31 자까지만 허용.
|
||||
char hostname[CSAGENTD_HOST_NAME_MAX_LENGTH + 1]; // hostname, key 값으로 사용, 최대 63자까지만 허용.
|
||||
|
||||
int service_stat; // Service 상태 정보, csagentd ShmDefine.h 정의 참고.
|
||||
int storage_max_usage; // Storage 최대 사용률(%), csagentd ShmDefine.h 정의 참고.
|
||||
};
|
||||
|
||||
|
||||
#endif /* __PROTOCOL_CSAGENTD_H__ */
|
||||
@@ -0,0 +1,91 @@
|
||||
/****************************************************************************
|
||||
GMS 와의 통신 관련 protocol 정의
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/07
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __PROTOCOL_GMS_H__
|
||||
#define __PROTOCOL_GMS_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// GMS 로 전송시 Header 의 ulmode 값
|
||||
#define GMS_MSG_MODE_VRCD_STATUSD_RTS_STATUS 0x0a01
|
||||
|
||||
// GMS 로 전송시 Header 의 ulResult 값
|
||||
#define GMS_OK_ALL_PASSED 0x1000
|
||||
|
||||
|
||||
// GMS 로 Data 전송 관련 Header 구조체..
|
||||
// 본 Header 의 크기는 32bit, 64Bit OS 모두 동일하게 320 Byte 임.
|
||||
struct PacketHeaderGms {
|
||||
|
||||
char szTransactionID[52];
|
||||
uint32_t ulMode; // Network Byte Order
|
||||
char szIssuer[128];
|
||||
char szServiceID[128];
|
||||
uint32_t ulResult; // Network Byte Order
|
||||
uint32_t ulBodyLength; // Network Byte Order
|
||||
};
|
||||
|
||||
|
||||
|
||||
// GMS 로 전달할 각 장비의 상태 정보를 저장하기 위한 구조체...
|
||||
// - GMS 장비가 64 Bit 인 경우에만 사용. ( 32Bit 는 현재 사용하지 않지만.. GMS 가 32Bit 인 경우.. time_t 형 size 문제로 통신 오류 발생함. )
|
||||
struct PacketDataGms {
|
||||
|
||||
time_t stamp; // stamp 값은 broadcast 를 수신한 시간정보 값임.
|
||||
// GMS 가 64Bit 장비인 경우 time_t 의 size 가 8 Byte, 만약 GMS 장비가 32 Bit 인 경우.. time_t 의 size 가 4Byte 이므로...
|
||||
// 아래 코드를 사용할 것
|
||||
// #pragma pack(4)
|
||||
// int stamp;
|
||||
// #pragma pack()
|
||||
|
||||
char domain[512]; // vmasd.conf에 설정된 SERVER_NAME=sb-01-fhs001.solbox.com 정보 사용
|
||||
// 해당 정보는 FHS 패키징 설치시 hostname 정보를 추출하여 자동 설정 처리하므로..
|
||||
// hostname 정보와 동일하다.
|
||||
|
||||
uint64_t total; // 저장 경로로 지정된 Mount 의 총 Disk Size ( 각 mount statfs 의 f_blocks * f_bsize 합산 결과 )
|
||||
uint64_t free; // 저장 경로로 지정된 Mount 의 총 Disk Free Size ( 각 mount statfs 의 f_blocks * f_bavail 합산 결과 )
|
||||
// 본 total, free 값은 /stg/node0.disable 설정에는 영향받지 않음.
|
||||
|
||||
int manual_disable; // 2 : fsck_ufs 프로세스가 동작 중인 경우..
|
||||
// 1 : /user/service/vmasd.disable 파일이 존재할 경우..
|
||||
// .disable 설정이 되지 않은 유효 Mount 중.. 가장 큰 Free Disk 용량(f_bfree) 이 0 인 경우...
|
||||
// 0 : 그 외..
|
||||
|
||||
int upload_level; // 본 구조체 항목 중 (disk_backlog/10) + (connection_established/50) 의 계산 값... ( vmasd 소스 참고)
|
||||
|
||||
int disk_backlog; // 저장 경로 Mount 들의 Disk Queue 평균 대기 transaction 수
|
||||
// 세부 내역은 devstat_compute_statistics 의 DSM_QUEUE_LENGTH 참고
|
||||
|
||||
int disk_percent; // 저장 경로 Mount 들의 평균 Busy 율 ( devstat_compute_statistics 의 DSM_BUSY_PCT 참고 )
|
||||
|
||||
int connection_established; // TCP 80 Port 에 연결된 세션 수..
|
||||
int connection_total; // TCP 80 전체 세션 수.
|
||||
|
||||
uint32_t traffic_ip; // 평균 inbound packet count
|
||||
uint32_t traffic_ib; // 평균 inbound traffic ( byte/s )
|
||||
uint32_t traffic_op; // 평균 outbound packet count
|
||||
uint32_t traffic_ob; // 평균 outbound traffic ( byte/s )
|
||||
|
||||
char hostname[64]; // 장비 hostname (gethostname 함수로 추출)
|
||||
// domain[512] 와 동일 data 임.
|
||||
// 만약 domain 정보와 hostname 정보가 다른 경우는 패키징 설치 후 장비 hostname 을 임의로 변경한 경우임.
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* __PROTOCOL_GMS_H__ */
|
||||
@@ -0,0 +1,96 @@
|
||||
/****************************************************************************
|
||||
SendInfo Worker 프로세스의 통신 관련 protocol 정의
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/16
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __PROTOCOL_SEND_INFO_H__
|
||||
#define __PROTOCOL_SEND_INFO_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Packet Header stx 코드
|
||||
#define HEADER_STX_CODE_SEND_INFO 0x05
|
||||
|
||||
// Packet Header type 구분코드
|
||||
#define HEADER_TYPE_REQUEST 0x00
|
||||
#define HEADER_TYPE_RESPONSE 0x01
|
||||
|
||||
// Packet Header command 구분 코드.
|
||||
// 현재는 0th 미사용, 1th 항목만 사용.
|
||||
#define COMMAND_ALIVE_FHS 0x01 // fimngd 의 Alive FHS 목록 요청 (0x00 0x01 0x00 0x00)
|
||||
|
||||
|
||||
// Packet Header result 구분 코드.
|
||||
// - fimngd 와 통신시 0th, 1th, 2th 미사용, 3th 만 사용.
|
||||
#define RESULT_ALIVE_FHS_OK 0x00 // Alive FHS 목록 요청에 대해 정상 결과 전송시 (0x00 0x00 0x00 0x00)
|
||||
#define RESULT_ALIVE_FHS_ERROR 0x01 // Alive FHS 목록 요청에 대해 오류 결과 전송시 (0x00 0x00 0x00 0x01)
|
||||
#define RESULT_ALIVE_FHS_SKIP 0x02 // Alive FHS 목록 요청에 관련 목록이 아직 유효하지 않은 경우.. 대기 의미로 SKIP 결과 전달. (0x00 0x00 0x00 0x02)
|
||||
|
||||
// 기타 정보
|
||||
#define LENGTH_FIELD_SIZE 4 // 가변데이터 형식 사용시 Length 필드의 메모리 크기 (unsigned int)
|
||||
|
||||
|
||||
// SendInfo Worker 에서 통신시 사용할 통신 Header
|
||||
// - 계산상 크기는 16Byte 이지만...
|
||||
// - 통신상 sizeof() : 20Byte ( 64Bit OS )
|
||||
struct PacketHeaderSendInfo {
|
||||
|
||||
char stx; // Packet 유효성 관리 코드
|
||||
char type; // Request or Response 여부 ( 0x00: Request, 0x01: Response )
|
||||
char command[4]; // Command Code ( 4 Byte) : 0th 미사용, 1th fimngd-rc_mond 에서 사용)
|
||||
char result[4]; // Result Code ( 4 Byte )
|
||||
unsigned int data_length; // Packet Data 부분의 길이값 ( Network Byte Order 사용)
|
||||
|
||||
// 2015-05-15 huibong
|
||||
// Protocol version 정보 추가로 인해... extend_code 2Byte 중 1Byte 사용.
|
||||
//char extend_code[2]; // 확장 및 Padding bits ( 2 Byte )
|
||||
|
||||
char protocol_version; // Packet Data 의 Protocol Version 정보. (1 Byte)
|
||||
char extend_code; // 확장 및 Padding bits ( 1 Byte )
|
||||
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Alive FHS 요청 및 결과 전송 관련 Data 항목 및 구조체.
|
||||
|
||||
|
||||
// RC ID 최대 길이.
|
||||
#define FIMNGD_RC_ID_MAX_LENGTH 31
|
||||
|
||||
// hostname 최대 길이.
|
||||
#define FIMNGD_HOST_NAME_MAX_LENGTH 63
|
||||
|
||||
|
||||
// FHS fimngd 와 통신 관련 Alive FHS 요청, 응답 처리 protocol version 중 처리 가능한 최대 Version 정보.
|
||||
// - 최초 버전이므로 0x00 으로 설정.
|
||||
#define PARSE_MAX_PROTOCOL_VERSION_ALIVE_FHS 0x00
|
||||
|
||||
// FHS fimngd 에서 수신할 Alive FHS 목록 요청 관련 data 구조체
|
||||
struct PacketDataRequestAliveFhs_V00 {
|
||||
|
||||
char rcid[FIMNGD_RC_ID_MAX_LENGTH + 1]; // RCID 정보, 최대 31 자까지만 허용.
|
||||
char hostname[FIMNGD_HOST_NAME_MAX_LENGTH + 1]; // hostname, 최대 63자까지만 허용.
|
||||
};
|
||||
|
||||
// FHS fimngd 에 전송할 Alive FHS 목록 관련 개별 항목 구조체.
|
||||
struct PacketDataResponseAliveFhs_V00 {
|
||||
|
||||
char hostname[FIMNGD_HOST_NAME_MAX_LENGTH + 1]; // hostname, 최대 63자까지만 허용.
|
||||
int service_stat; // Service 상태 code. ( 정상 or Read only 장비만.)
|
||||
};
|
||||
|
||||
#endif /* __PROTOCOL_SEND_INFO_H__ */
|
||||
@@ -0,0 +1,92 @@
|
||||
/****************************************************************************
|
||||
Broadcast Message Header for rc_mond
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/06/05
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __PROTOCOL_VMASD_H__
|
||||
#define __PROTOCOL_VMASD_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// 본 Header 파일은 FHS 의 vmasd 가 전송하는 UDP Broadcasting Message Protocol 을 정의하기 위한 header 이다.
|
||||
// FHS vmasd 에 정의된 Protocol 형식이 향후 변경될 수 있으므로.. 다음과 같이 특정하여 처리한다.
|
||||
// sizeof( struct vmasd_broadcast_message_header ) => 352 (64Bit OS)
|
||||
|
||||
struct vmasd_broadcast_message_header {
|
||||
|
||||
char szTransactionID[52]; // 20130802181203-4ef48917f7-4381644055 ( 세션 ID 정보 )
|
||||
uint32_t ulMode; // 256 (MODE 정보, network byte odrer, 0x0100 만 사용)
|
||||
char szIssuer[128]; // vmasd (프로세스명)
|
||||
char szServiceID[128]; // 미사용
|
||||
char szRCID[32]; // bd16 (RC ID)
|
||||
uint32_t ulResult; // 4096 (처리결과, network byte odrer)
|
||||
uint32_t ulBodyLength; // 640 (Body Size , network byte odrer)
|
||||
|
||||
};
|
||||
|
||||
// vmasd 가 전송한 UDP Broadcast 메시지 중....
|
||||
// vmasd_broadcast_message_header 구조체에서 ntohl(ulMode) == MSG_MODE_VMA_APACHE_DISKSIZE 정보만 처리한다.
|
||||
#define MSG_MODE_VMA_APACHE_DISKSIZE 0x0100
|
||||
|
||||
// rc_vrcd share.h 에 정의된 struct disk_usage 구조체 및 vmasd 소스 참고함.
|
||||
// 구조체 명은 변경 처리함.
|
||||
// sizeof( struct vmasd_broadcast_message_body ) => 640 (64Bit OS)
|
||||
// 각 항목에 대한 설명 내역은 vmasd 소스 Revision 0551 을 기준으로 한 분석 내역임.
|
||||
struct vmasd_broadcast_message_body {
|
||||
|
||||
char domain[512]; // vmasd.conf에 설정된 SERVER_NAME=sb-01-fhs001.solbox.com 정보 사용
|
||||
// 해당 정보는 FHS 패키징 설치시 hostname 정보를 추출하여 자동 설정 처리하므로..
|
||||
// hostname 정보와 동일하다.
|
||||
|
||||
uint64_t total; // 저장 경로로 지정된 Mount 의 총 Disk Size ( 각 mount statfs 의 f_blocks * f_bsize 합산 결과 )
|
||||
uint64_t free; // 저장 경로로 지정된 Mount 의 총 Disk Free Size ( 각 mount statfs 의 f_blocks * f_bavail 합산 결과 )
|
||||
// 본 total, free 값은 /stg/node0.disable 설정에는 영향받지 않음.
|
||||
|
||||
int manual_disable; // 2 : fsck_ufs 프로세스가 동작 중인 경우..
|
||||
// 1 : /user/service/vmasd.disable 파일이 존재할 경우..
|
||||
// .disable 설정이 되지 않은 유효 Mount 중.. 가장 큰 Free Disk 용량(f_bfree) 이 0 인 경우...
|
||||
// 0 : 그 외..
|
||||
|
||||
int upload_level; // 본 구조체 항목 중 (disk_backlog/10) + (connection_established/50) 의 계산 값... ( vmasd 소스 참고)
|
||||
|
||||
int disk_backlog; // 저장 경로 Mount의 Disk Queue 평균 대기 transaction 수
|
||||
// 실제로는 평균이 아니라.. N개 mount 중 마지막 mount 의 추출 값임.
|
||||
// 세부 내역은 devstat_compute_statistics 의 DSM_QUEUE_LENGTH 참고
|
||||
|
||||
int disk_percent; // 저장 경로 Mount 들의 평균 Busy 율 ( devstat_compute_statistics 의 DSM_BUSY_PCT 참고 )
|
||||
|
||||
int connection_established; // TCP 80 Port 사용, ESTABLISH 상태인 세션 수..
|
||||
int connection_total; // TCP 80 Port 전체 세션 수.
|
||||
|
||||
uint32_t traffic_ip; // 평균 inbound packet count
|
||||
uint32_t traffic_ib; // 평균 inbound traffic ( byte/s )
|
||||
uint32_t traffic_op; // 평균 outbound packet count
|
||||
uint32_t traffic_ob; // 평균 outbound traffic ( byte/s )
|
||||
|
||||
char hostname[64]; // 장비 hostname (gethostname 함수로 추출)
|
||||
// domain[512] 와 동일 data 임.
|
||||
// 만약 domain 정보와 hostname 정보가 다른 경우는 패키징 설치 후 장비 hostname 을 임의로 변경한 경우임.
|
||||
|
||||
uint64_t large_block; // 저장 경로로 지정된 Mount 중.... disable 설정(/stg/node0.disable)이 안되고..
|
||||
// 가장 큰 Free Size 를 가지는 Mount 의 Disk Free 용량임.
|
||||
// 본 값은 해당 FHS 에서 저장 가능한 가장 큰 Content Size 를 의미한다.
|
||||
// 본 항목은 송신측인 vmasd 에만 정의되어 있으며.. 수신측인 rc_vrcd 에는 정의되어 있지 않음.
|
||||
// 따라서.. GMS 로 본 항목은 전송하지 않는다. (전송하면 파싱 오류 발생 할 듯 )
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* __PROTOCOL_VMASD_H__ */
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "RcdbInfo.h"
|
||||
#include "ProcessConfig.h"
|
||||
|
||||
// 생성자..
|
||||
CRcdbInfo::CRcdbInfo()
|
||||
{
|
||||
}
|
||||
|
||||
// 소멸자..
|
||||
CRcdbInfo::~CRcdbInfo()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// CServiceConfig Class 에 저장된 RCDB 접속 정보를 가져와 멤버 변수에 저장한다.
|
||||
void CRcdbInfo::Load()
|
||||
{
|
||||
// CProcessConfig Class 에서 기본적인 설정값에 대해 검사를 수행하므로...
|
||||
// 본 Class 에서 다시 유효성 검사를 할 필요는 없다.. ( 어차피 유효성 검사 방법이 동일하므로.. )
|
||||
|
||||
// RCDB IP
|
||||
m_strRcdbIp = CProcessConfig::GetInstance()->GetRcdbIp();
|
||||
|
||||
// RCDB Port
|
||||
m_nRcdbPort = CProcessConfig::GetInstance()->GetRcdbPort();
|
||||
|
||||
// RCDB DB Name
|
||||
m_strRcdbName = CProcessConfig::GetInstance()->GetRcdbName();
|
||||
|
||||
// RCDB 접근 계정
|
||||
m_strRcdbAcct = CProcessConfig::GetInstance()->GetRcdbAcct();
|
||||
|
||||
// RCDB 접근 Password.
|
||||
m_strRcdbAcctPw = CProcessConfig::GetInstance()->GetRcdbAcctPw();
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/****************************************************************************
|
||||
RCDB 접속 정보 저장 처리 Class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2013/11/13
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __RCDB_INFO_H__
|
||||
#define __RCDB_INFO_H__
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
|
||||
|
||||
/// @brief CRcdbInfo
|
||||
/// 본 클래스는 conf 파일에 저장된 RCDB 접속 관련 정보를 저장하기 위한 공용 Class...
|
||||
/// 본 클래스를 사용하지 않고... CServiceConfig class 의 Get 함수를 이용하여 RCDB 접속 정보를 처리해도 된다..
|
||||
/// 하지만... RCDB 접속 처리 Class 함수의 string type 변수 사용으로 인해... 여러 모듈에서 반복적인 동일 코드 처리 작업을 수행해야 하므로...
|
||||
/// 본 Class 를 통해 코드를 단순화 시킬 목적으로 사용한다.
|
||||
class CRcdbInfo
|
||||
{
|
||||
public:
|
||||
|
||||
// 생성 및 소멸자.
|
||||
CRcdbInfo();
|
||||
~CRcdbInfo();
|
||||
|
||||
// CServiceConfig class 에 저장된 RCDB 접속 정보를 멤버 변수에 저장처리한다.
|
||||
void Load( void );
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// 멤버 변수들은 DB 접속을 처리하는 객체에서 직접 Access 해서 사용할 수 있도록 public 으로 구성. ( 편의성 제공 목적)
|
||||
std::string m_strRcdbIp; // RCDB IP
|
||||
unsigned int m_nRcdbPort; // RCDB Port
|
||||
std::string m_strRcdbName; // RCDB DB Name
|
||||
std::string m_strRcdbAcct; // RCDB 접근 계정
|
||||
std::string m_strRcdbAcctPw; // RCDB 접근 Password.
|
||||
|
||||
};
|
||||
|
||||
#endif /* __RCDB_INFO_H__ */
|
||||
@@ -0,0 +1,338 @@
|
||||
#include "ShmClientInfo.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "ProcessConfig.h"
|
||||
#include "ReportLog.h"
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// 2018-02-22 CHG huibong FHS Disk busy 상황시 report 로깅을 위한 기준값
|
||||
#define REPORT_MAX_DISK_QUEUE 10 // disk queue 값이 해당 정의 값 이상인 경우
|
||||
#define REPORT_MAX_DISK_BUSY 90.0 // disk busy 값이 해당 정의 값 이상인 경우
|
||||
|
||||
|
||||
// 생성자
|
||||
CShmClientInfo::CShmClientInfo( struct ClientInfo * p )
|
||||
: m_pClient( p )
|
||||
{
|
||||
// 서비스 상태 code 에 대한 문자열 정보를 저장하기 위한 멤버 변수 설정.
|
||||
// - may 객체이므로.. key - value 형식으로 저장 처리
|
||||
m_mapServiceStatString[SERVICE_STAT_NOT_DEFINE] = "Not Define";
|
||||
m_mapServiceStatString[SERVICE_STAT_OK] = "OK";
|
||||
m_mapServiceStatString[SERVICE_STAT_OUT] = "Out";
|
||||
m_mapServiceStatString[SERVICE_STAT_DISABLE] = "Disable";
|
||||
m_mapServiceStatString[SERVICE_STAT_RONLY] = "Read-only";
|
||||
|
||||
// NEW 2018-01-11 huibong 메모리 사용량 초과시 report 기능 추가 (#31360, #31679)
|
||||
// check 여부 판단을 위한 변수 초기화
|
||||
if( CProcessConfig::GetInstance()->GetReportMemoryMaxUsage() > 0 )
|
||||
m_bReportMemoryMaxUsage = true;
|
||||
else
|
||||
m_bReportMemoryMaxUsage = false;
|
||||
|
||||
m_iShmSystemUpdateCount = 0;
|
||||
|
||||
}
|
||||
|
||||
// 소멸자
|
||||
CShmClientInfo::~CShmClientInfo()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Service 상태 정보에 대한 문자열 반환.
|
||||
const char * CShmClientInfo::GetServiceStatString( const int & stat )
|
||||
{
|
||||
std::map< int, std::string >::iterator pos;
|
||||
|
||||
pos = m_mapServiceStatString.find( stat );
|
||||
if( pos != m_mapServiceStatString.end() )
|
||||
{
|
||||
// 해당 항목 존재시
|
||||
return pos->second.c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 해당 항목이 존재하지 않는 경우.
|
||||
return m_mapServiceStatString[SERVICE_STAT_NOT_DEFINE].c_str();
|
||||
}
|
||||
}
|
||||
|
||||
// 현재 Service 상태 정보에 대한 문자열 반환.
|
||||
const char * CShmClientInfo::GetServiceStatString()
|
||||
{
|
||||
std::map< int, std::string >::iterator pos;
|
||||
|
||||
pos = m_mapServiceStatString.find( m_pClient->service.service_stat);
|
||||
if( pos != m_mapServiceStatString.end() )
|
||||
{
|
||||
// 해당 항목 존재시
|
||||
return pos->second.c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 해당 항목이 존재하지 않는 경우.
|
||||
return m_mapServiceStatString[SERVICE_STAT_NOT_DEFINE].c_str();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 공유 메모리 상태가 유효하지 여부 판단.
|
||||
bool CShmClientInfo::IsValid( const char * pClientAddress ) const
|
||||
{
|
||||
if( m_pClient == NULL )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
// 해당 공유메모리가 미사용 중으로 마킹된 경우...
|
||||
if( m_pClient->use == 0 )
|
||||
return false;
|
||||
|
||||
// 해당 공유메모리의 client IP 가 서로 다른 경우...
|
||||
if( strcmp( pClientAddress, m_pClient->client_ip ) != 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// serviceinfo 정보를 공유메모리에 저장 처리.
|
||||
// return false : 공유메모리가 유효하지 않은 경우...
|
||||
bool CShmClientInfo::UpdateServiceInfo( std::string & strHostname, int iServiceStat )
|
||||
{
|
||||
// 공유메모리가 유효하지 않은 경우..
|
||||
if( m_pClient == NULL || m_pClient->use == 0 )
|
||||
return false;
|
||||
|
||||
int iPreviousServiceStat = 0;
|
||||
|
||||
// 현재 시간 정보 추출.
|
||||
time_t currentTime = time( 0 );
|
||||
|
||||
struct timespec currentClock;
|
||||
memset( ¤tClock, 0x00, sizeof( struct timespec ) );
|
||||
clock_gettime( CLOCK_MONOTONIC, ¤tClock );
|
||||
|
||||
// 정보 설정.
|
||||
if( m_pClient->valid == 1 )
|
||||
{
|
||||
// hostname 정보 설정.
|
||||
// - 기존 값과 비교하여 변경된 경우.. 관련 내역 로깅.
|
||||
if( strcmp( m_pClient->hostname, strHostname.c_str() ) != 0 )
|
||||
{
|
||||
LOG( LWAR, "client [%s] hostname changed [%s] -> [%s].", m_pClient->client_ip, m_pClient->hostname, strHostname.c_str() );
|
||||
|
||||
// hostname 정보 복사
|
||||
strncpy( m_pClient->hostname, strHostname.c_str(), HOST_NAME_LENGTH );
|
||||
}
|
||||
|
||||
// 이전 서비스 상태 정보 저장
|
||||
iPreviousServiceStat = m_pClient->service.service_stat;
|
||||
|
||||
// 서비스 상태 정보 변경 여부 관련 내역 로깅
|
||||
if( iPreviousServiceStat != iServiceStat )
|
||||
{
|
||||
_LOG( LINF, "client[%s] hostname[%s] service stat changed. [%s] -> [%s]."
|
||||
, m_pClient->client_ip, m_pClient->hostname, GetServiceStatString( iPreviousServiceStat ), GetServiceStatString( iServiceStat ) );
|
||||
|
||||
// 서비스 상태 정보 업데이트
|
||||
m_pClient->service.service_stat = iServiceStat;
|
||||
}
|
||||
|
||||
// update 시간 설정
|
||||
m_pClient->service.update_time = currentTime;
|
||||
m_pClient->service.update_time_clock_sec = currentClock.tv_sec;
|
||||
|
||||
// apllication 정보 설정.
|
||||
m_pClient->client_app = 0;
|
||||
|
||||
// 2018-02-22 NEW huibong (#31703)
|
||||
// - 운영 편의성을 위해 다음 상황을 report 로깅 처리한다.
|
||||
// - 1. 서비스 상태가 OK , Read only 상태에서 Disable, OUT 상황으로 변경되는 경우
|
||||
// - 2. 서비스 상태가 비정상 상황(disable, out) 상황에서 정상( ok, read only) 상황으로 변경되는 경우
|
||||
|
||||
// 서비스 상태가 변경된 경우 - 대부분 상태 변경은 잘 일어나지 않으므로.. 빠른 로직 검사를 위해 불필요해도 넣어 둠
|
||||
if( iPreviousServiceStat != iServiceStat )
|
||||
{
|
||||
// 현재 상태가 비정상 상황인 경우
|
||||
if( iServiceStat == SERVICE_STAT_OUT || iServiceStat == SERVICE_STAT_DISABLE )
|
||||
{
|
||||
// 이전 상황은 정상인 경우
|
||||
if( iPreviousServiceStat != SERVICE_STAT_OUT && iPreviousServiceStat != SERVICE_STAT_DISABLE )
|
||||
{
|
||||
// report 로깅 객체 생성
|
||||
CReportLog reportLog;
|
||||
std::string strErrorMessage;
|
||||
strErrorMessage.clear();
|
||||
|
||||
if( reportLog.Init( CProcessConfig::GetInstance()->GetLogPath() ) == false )
|
||||
{
|
||||
reportLog.GetLastError( strErrorMessage );
|
||||
LOG( LERR, "client[%s] service stat change log init failed.[%s]", strHostname.c_str(), strErrorMessage.c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
reportLog.Write( "WAR", "[%s] [ %s, service stat changed. %s -> %s. check FHS status.]"
|
||||
, PROG_NAME, strHostname.c_str()
|
||||
, GetServiceStatString( iPreviousServiceStat ), GetServiceStatString( iServiceStat ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 현재 상태가 OK, Read only 의 정상 상황인 경우
|
||||
// 이전 상태가 비정상 상황인 경우
|
||||
if( iPreviousServiceStat == SERVICE_STAT_OUT || iPreviousServiceStat == SERVICE_STAT_DISABLE )
|
||||
{
|
||||
// report 로깅 객체 생성
|
||||
CReportLog reportLog;
|
||||
std::string strErrorMessage;
|
||||
strErrorMessage.clear();
|
||||
|
||||
if( reportLog.Init( CProcessConfig::GetInstance()->GetLogPath() ) == false )
|
||||
{
|
||||
reportLog.GetLastError( strErrorMessage );
|
||||
LOG( LERR, "client[%s] service stat change log init failed.[%s]", strHostname.c_str(), strErrorMessage.c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
reportLog.Write( "INF", "[%s] [ %s, service stat changed. %s -> %s. ]"
|
||||
, PROG_NAME, strHostname.c_str()
|
||||
, GetServiceStatString( iPreviousServiceStat ), GetServiceStatString( iServiceStat ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// hostname 정보 설정.
|
||||
strncpy( m_pClient->hostname, strHostname.c_str(), HOST_NAME_LENGTH );
|
||||
|
||||
// 서비스 상태 정보 설정.
|
||||
m_pClient->service.service_stat = iServiceStat;
|
||||
|
||||
// update 시간 설정
|
||||
m_pClient->service.update_time = currentTime;
|
||||
m_pClient->service.update_time_clock_sec = currentClock.tv_sec;
|
||||
|
||||
// apllication 정보 설정.
|
||||
m_pClient->client_app = 0;
|
||||
|
||||
// Data 유효 여부 설정.
|
||||
m_pClient->valid = 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// systeminfo 정보를 공유메모리에 저장 처리.
|
||||
// return false : 공유메모리가 유효하지 않거나... valid 가 유효하지 않거나.. hostname 이 동일하지 않은 경우.
|
||||
bool CShmClientInfo::UpdateSystemInfo( std::string & strHostname, struct SystemInfo * pData )
|
||||
{
|
||||
// 공유메모리가 유효하지 않은 경우..
|
||||
if( m_pClient == NULL || m_pClient->use == 0 )
|
||||
return false;
|
||||
|
||||
// 현재 시간 정보 추출.
|
||||
time_t currentTime = time( 0 );
|
||||
|
||||
// valid 설정값이 유효하지 않은 경우..
|
||||
// - service info 정보가 먼저 기록되지 않은 상태인 경우....
|
||||
// - 정보를 기록하지 않는다.
|
||||
if( m_pClient->valid == 0 )
|
||||
{
|
||||
LOG( LWAR, "client [%s] hostname[%s] info not valid. [%d].", m_pClient->client_ip, m_pClient->hostname, m_pClient->valid );
|
||||
return false;
|
||||
}
|
||||
|
||||
// hostname 정보가 동일한지 검사.
|
||||
if( strcmp( m_pClient->hostname, strHostname.c_str() ) != 0 )
|
||||
{
|
||||
LOG( LWAR, "client [%s] hostname[%s] not match. [%s].", m_pClient->client_ip, m_pClient->hostname, strHostname.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
// 정보가 동일한 경우.... copy 처리
|
||||
memcpy( &(m_pClient->system), pData, sizeof( struct SystemInfo ) );
|
||||
m_pClient->system.update_time = currentTime;
|
||||
|
||||
// 2018-02-22 CHG huibong (#31703)
|
||||
// - 2018-01-12 #31544, #31679 에 의해 추가된 다음 기능 제거
|
||||
// -- FHS Disk hang 또는 이상 상황으로 disk busy 비정상 증가시 자동 FHS out 처리
|
||||
// - 사유
|
||||
// -- Disk Hang 이 아닌 상황에서도 기준값(queue 10 & busy 90%)을 초과하는 Disk Busy 상황 발생으로 잘못된 서비스 OUT 발생 가능
|
||||
// - 기타
|
||||
// -- Disk busy 상황시 Report 로깅 처리 기능은 유지
|
||||
// -- Disk busy 판단 기준값은 그대로 유지 queue 10, busy 90%
|
||||
// -- 참고로 FHS 는 queue 7, busy 50% 이상인 경우 자동으로 read only 로 변경 처리됨
|
||||
// --- FHS 와 같은 기준값을 사용하지 않은 이유는 FHS 기준값은 순간적인 응답지연을 막기 위한 최소한의 기준값이기 때문.
|
||||
|
||||
// 현재 상태가 out, disable 상태가 아닌 정상 상황인 경우
|
||||
if( m_pClient->service.service_stat != SERVICE_STAT_OUT && m_pClient->service.service_stat != SERVICE_STAT_DISABLE )
|
||||
{
|
||||
// system 상태가 정보가 disk busy 상황인 경우
|
||||
if( pData->disk_max_queue >= REPORT_MAX_DISK_QUEUE && pData->disk_max_busy >= REPORT_MAX_DISK_BUSY )
|
||||
{
|
||||
// report 로깅 객체 생성
|
||||
CReportLog reportLog;
|
||||
std::string strErrorMessage;
|
||||
strErrorMessage.clear();
|
||||
|
||||
if( reportLog.Init( CProcessConfig::GetInstance()->GetLogPath() ) == false )
|
||||
{
|
||||
reportLog.GetLastError( strErrorMessage );
|
||||
LOG( LERR, "client[%s] disk busy report log init failed.[%s]", strHostname.c_str(), strErrorMessage.c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
reportLog.Write( "WAR", "[%s] [ %s, disk busy too high. busy %4.1lf%% , queue %ju. check FHS status.]"
|
||||
, PROG_NAME, strHostname.c_str(), pData->disk_max_busy, pData->disk_max_queue );
|
||||
|
||||
_LOG( LWAR, "client[%s] disk busy[%4.1lf %%] too high. queue[%ju]. report logging."
|
||||
, strHostname.c_str(), pData->disk_max_busy, pData->disk_max_queue );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NEW 2018-01-11 huibong 메모리 사용량 초과시 report 기능 추가 (#31360, #31679)
|
||||
// - FHS memory 사용량이 지정된 값 이상인 경우 report 로깅 처리
|
||||
// - FHS system 정보가 10 sec 마다 전송되므로.. 잦은 로깅 발생 가능
|
||||
// - 따라서 분당 1회만 check 하도록 한다 (최초 요청은 기동시 초기화 이슈 있으므로.. 버리고.. 3번째 요청부터 체크)
|
||||
if( m_bReportMemoryMaxUsage == true && m_iShmSystemUpdateCount % 6 == 2)
|
||||
{
|
||||
// FHS memory 사용률이 conf 설정값 이상인 경우.
|
||||
if( pData->memory_usage >= CProcessConfig::GetInstance()->GetReportMemoryMaxUsage() )
|
||||
{
|
||||
CReportLog reportLog;
|
||||
std::string strErrorMessage;
|
||||
strErrorMessage.clear();
|
||||
|
||||
if( reportLog.Init( CProcessConfig::GetInstance()->GetLogPath() ) == false )
|
||||
{
|
||||
reportLog.GetLastError( strErrorMessage );
|
||||
LOG( LERR, "client[%s] memory usage report log init failed.[%s]", strHostname.c_str(), strErrorMessage.c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
reportLog.Write( "WAR", "[%s] [FHS (%s) memory usage too high = %d%%. total=%ju byte. free=%ju byte. check FHS status.]"
|
||||
, PROG_NAME, strHostname.c_str(), pData->memory_usage, pData->memory_total, pData->memory_free );
|
||||
|
||||
_LOG( LWAR, "client[%s] memory usage[%d %%] too high. total[%ju] free[%ju]. report logging."
|
||||
, strHostname.c_str(), pData->memory_usage, pData->memory_total, pData->memory_free );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// system 관련 shared memory update count 증가 처리
|
||||
// - 10 sec 마다 업데이트 되므로.. 일 단위 count reset
|
||||
m_iShmSystemUpdateCount++;
|
||||
if( m_iShmSystemUpdateCount > 8640 )
|
||||
m_iShmSystemUpdateCount = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/****************************************************************************
|
||||
shared memory date management class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/09
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SHM_CLIENT_INFO_H__
|
||||
#define __SHM_CLIENT_INFO_H__
|
||||
|
||||
#include "ShmDefine.h"
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
|
||||
// 공유메모리 영역 중 Client 영역에 대한 접근 처리 관련 인터페이스를 제공하기 위한 클래스
|
||||
class CShmClientInfo
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
// 공유메모리 영역 중 client 영역에 대한 포인터
|
||||
struct ClientInfo * const m_pClient;
|
||||
|
||||
// 서비스 상태 code 에 대한 문자열 정보를 저장하기 위한 변수.
|
||||
std::map<int, std::string> m_mapServiceStatString;
|
||||
|
||||
// NEW 2018-01-11 huibong 메모리 사용량 초과시 report 기능 추가 (#31360, #31679)
|
||||
// 기능 check 여부 판단을 위한 변수
|
||||
bool m_bReportMemoryMaxUsage;
|
||||
|
||||
// system shared memory update count
|
||||
// - 잦은 report 로깅 방지를 위한 count 처리 목적
|
||||
int m_iShmSystemUpdateCount;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// 생성자
|
||||
CShmClientInfo( struct ClientInfo * p );
|
||||
|
||||
// 소멸자
|
||||
~CShmClientInfo();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// 공유 메모리 상태가 유효하지 여부 판단.
|
||||
bool IsValid( const char * pClientAddress ) const;
|
||||
|
||||
// Service 상태 정보에 대한 문자열 반환.
|
||||
const char * GetServiceStatString( const int & stat );
|
||||
|
||||
// 현재 Service 상태 정보에 대한 문자열 반환.
|
||||
const char * GetServiceStatString();
|
||||
|
||||
|
||||
// serviceinfo 정보를 공유메모리에 저장 처리.
|
||||
// return false : 공유메모리가 유효하지 않은 경우...
|
||||
bool UpdateServiceInfo( std::string & strHostname, int iServiceStat );
|
||||
|
||||
|
||||
// systeminfo 정보를 공유메모리에 저장 처리.
|
||||
// return false : 공유메모리가 유효하지 않거나... valid 가 유효하지 않거나.. hostname 이 동일하지 않은 경우.
|
||||
bool UpdateSystemInfo( std::string & strHostname, struct SystemInfo * pData );
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* __SHM_CLIENT_INFO_H__ */
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
/***************************************************************************
|
||||
rc_mond shared memory template header
|
||||
-----------------------------------------
|
||||
begin : 2015/06/15
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : huibong@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.
|
||||
***************************************************************************/
|
||||
|
||||
// 본 코드는 시스템 공유메모리 생성, 접근, 해제, 삭제 처리를 수행하기 위한 코드로서
|
||||
// template 코드 방식으로 구성
|
||||
|
||||
#ifndef __SHM_CONTROL_H__
|
||||
#define __SHM_CONTROL_H__
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/shm.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*----------- MODE Flag ---------------
|
||||
SHM_R 0400 read by user
|
||||
SHM_W 0200 write by user
|
||||
SHM_R >> 3 0040 read by group
|
||||
SHM_W >> 3 0020 write by group
|
||||
SHM_R >> 6 0004 read by others
|
||||
SHM_W >> 6 0002 write by others
|
||||
-------------------------------------*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief ShmControl 공유메모리 관련 Template Class
|
||||
template <typename T>
|
||||
class CShmControl
|
||||
{
|
||||
public:
|
||||
/// @brief 생성자
|
||||
CShmControl();
|
||||
/// @brief 소멸자
|
||||
~CShmControl();
|
||||
|
||||
|
||||
/// @brief 공유메모리 생성, 접근 또는 기존 공유메모리 접근.
|
||||
/// @param iShmKey 공유메모리 접근을 위한 키
|
||||
/// @param iSize 접근하고자 하는 공유메모리의 크기
|
||||
/// @param iSize 공유메모리 생성및 접근시 권한
|
||||
/// @return return true or false
|
||||
bool Create( key_t iShmKey, size_t iSize, int iModeFlag = SHM_R | SHM_W );
|
||||
|
||||
/// @brief 기존 공유메모리 접근.
|
||||
/// @param iShmKey 공유메모리 접근을 위한 키
|
||||
/// @param iSize 접근하고자 하는 공유메모리의 크기
|
||||
/// @param iSize 공유메모리 접근시 권한
|
||||
/// @return return true or false
|
||||
bool Attach( key_t iShmKey, size_t iSize, int iModeFlag = SHM_R | SHM_W );
|
||||
|
||||
/// @brief 기존 접근한 공유메모리와의 연결을 해제
|
||||
/// @return return true or false
|
||||
bool Detach( void );
|
||||
|
||||
/// @brief 기존 접근한 공유메모리와의 연결을 해제 및 삭제
|
||||
/// @return return true or false
|
||||
bool Remove( void );
|
||||
|
||||
/// @brief 공유메모리에 대한 포인터를 반환
|
||||
/// @return 생성 및 접근한 공유메모리에 대한 포인터 또는 오류 발생시 NULL
|
||||
T * GetShmPtr(void) const { return m_pShm; }
|
||||
|
||||
/// @brief 접근한 공유메모리의 ID 값을 반환
|
||||
/// @return 생성 및 접근한 공유메모리 ID Value에 대한 참조.
|
||||
int GetShmId(void) const { return m_iShmId; }
|
||||
|
||||
private:
|
||||
///< m_pShm 공유메모리에 대한 포인터
|
||||
T * m_pShm;
|
||||
///< m_pShmId 접근한 공유메모리의 ID Value
|
||||
int m_iShmId;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 기본 멤버변수 초기화.
|
||||
template < typename T >
|
||||
inline CShmControl<T>::CShmControl()
|
||||
: m_pShm(NULL)
|
||||
, m_iShmId(-1)
|
||||
{
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
inline CShmControl<T>::~CShmControl()
|
||||
{
|
||||
// 생성된 공유메모리를 종료시 다른 프로세스들이 사용한다면.. 맘대로 삭제해서는 안되며...
|
||||
// 이럴 경우 detach 처리만 해야 한다.
|
||||
// Detach();
|
||||
|
||||
// 이와 반대로.. 다른 프로세스에서 더이상 해당 공유메모리를 사용하지 않을 경우.. remove 처리한다.
|
||||
Remove();
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 해당 공유메모리를 생성한다. 만약 기존에 생성된 것이 있다면 그놈을 사용하도록 한다.
|
||||
template < typename T >
|
||||
inline bool CShmControl<T>::Create( key_t iShmKey, size_t iSize, int iModeFlag )
|
||||
{
|
||||
// 우선 공유 메모리를 생성해 봅니다.
|
||||
m_iShmId = shmget( iShmKey, iSize, IPC_CREAT | IPC_EXCL | iModeFlag );
|
||||
// 생성에 실패한 경우.
|
||||
if( m_iShmId == -1)
|
||||
{
|
||||
// 이미 기존에 생성된 놈이 있는지 확인해 봅시다.
|
||||
return Attach( iShmKey, iSize, iModeFlag);
|
||||
}
|
||||
// 생성에 성공한 경우.
|
||||
else
|
||||
{
|
||||
// 생성된 공유 메모리의 포인터를 받아옵니다.
|
||||
m_pShm = (T *)shmat( m_iShmId, 0, 0 );
|
||||
|
||||
// 받아온 공유 메모리 포인터 값이 정확하면
|
||||
if( reinterpret_cast<long>(m_pShm) != -1)
|
||||
{
|
||||
// 원래 시스템에서 생성시 자동으로 초기화됨 => 그렇지만 새로이 생성을 하였으므로 확인 사살 초기화 ^^
|
||||
memset( m_pShm, 0x00, iSize);
|
||||
return true;
|
||||
}
|
||||
// 받아온 공유 메모리 포인터를 가져오는데 실패한 경우
|
||||
// => 만든놈이 삭제해 버립시다.
|
||||
else
|
||||
{
|
||||
Remove();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 기존에 생성된 것 공유 메모리에 접근하기 위해서 사용한다..
|
||||
// 키값과 크기값을 정확히 알고 있어야 ( 혹시 다른데서 사용하는 놈으로 붙을까봐 ) 접근할 수 있도록 한다.
|
||||
template < typename T >
|
||||
inline bool CShmControl<T>::Attach( key_t iShmKey, size_t iSize, int iModeFlag )
|
||||
{
|
||||
// 기존 연결은 해제 시켜 버린다. => 그냥 놓은 상태에서 다시 접속할 경우 메모리 사용량이 올라감.
|
||||
Detach();
|
||||
|
||||
m_iShmId = shmget( iShmKey, iSize, iModeFlag);
|
||||
if( m_iShmId == -1 )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
// 우선 기존에 있는 것과 크기가 동일한지 검사한다.
|
||||
struct shmid_ds shmInfo;
|
||||
memset(&shmInfo, 0x00, sizeof(struct shmid_ds));
|
||||
|
||||
shmctl( m_iShmId, IPC_STAT, &shmInfo);
|
||||
|
||||
// shm_segsz 정의 관련 참고사항
|
||||
// - FreeBSD 6.X : int type으로 정의되어.. 컴파일시 waring 발생
|
||||
// - FreeBSD 10.X : size_t type
|
||||
// - CentOS 6.4 : size_t type
|
||||
if( shmInfo.shm_segsz != iSize)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
|
||||
m_pShm = (T *)shmat( m_iShmId, 0, 0 );
|
||||
|
||||
// reinterpret_cast 을 사용한 것은 운영체제마다 포인터 형이 다를수가 있다고 참고한 라이브러리에 나와있어서 함.
|
||||
if( reinterpret_cast<long>(m_pShm) == -1)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 접근한 공유메모리로 부터 분리시킨다. ( 접근시 설정된 멤버 변수 이용)
|
||||
template < typename T >
|
||||
inline bool CShmControl<T>::Detach()
|
||||
{
|
||||
if( m_pShm > 0 )
|
||||
{
|
||||
if( shmdt( m_pShm) == 0)
|
||||
{
|
||||
m_iShmId = -1;
|
||||
m_pShm = NULL;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
// 공유메모리를 삭제한다. 이 작업을 하기 위해서는 먼저 공유 메모리를 생성 또는 접근을 해야하며
|
||||
// 이때 설정된 멤버 변수를 가지고 삭제 작업을 수행한다.
|
||||
// 공유 메모리는 여러 Process 들이 사용가능하기 때문에 삭제시 신중을 기할 것.
|
||||
template < typename T >
|
||||
inline bool CShmControl<T>::Remove()
|
||||
{
|
||||
if( m_iShmId > -1)
|
||||
{
|
||||
if( shmctl( m_iShmId, IPC_RMID, NULL) == -1)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_iShmId = -1;
|
||||
m_pShm = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif /* __SHM_CONTROL_H__ */
|
||||
@@ -0,0 +1,124 @@
|
||||
/****************************************************************************
|
||||
Shared memory define for rc_mond
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/06/09
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SHM_DEFINE_H__
|
||||
#define __SHM_DEFINE_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
// hostname 최대 길이.
|
||||
#define HOST_NAME_LENGTH 63
|
||||
|
||||
// client ip 주소 저장을 위한 최대 크기값
|
||||
// - NULL 포함 40자까지, IPv6 지원 목적
|
||||
#define IP_ADDR_LENGTH 40
|
||||
|
||||
|
||||
// Service 상태 코드 정의
|
||||
#define SERVICE_STAT_OK 0 // 정상 상태
|
||||
#define SERVICE_STAT_OUT 1 // 수동 중지 상태
|
||||
#define SERVICE_STAT_DISABLE 2 // 서비스 불가 상태
|
||||
#define SERVICE_STAT_RONLY 3 // Read Only 상태
|
||||
|
||||
// ShmDefine.h 에서 정의된 서비스 상태 코드 외에 미정의된 코드 처리를 위한 정의
|
||||
#define SERVICE_STAT_NOT_DEFINE -1
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// 각 Client 로 부터 수신된 정보를 저장하기 위한 공유메모리 정의 파일
|
||||
// - 공유메모리 관련 상세 내역은 rc_mond 설계서 의 공유메모리 구조 항목을 참고할 것.
|
||||
|
||||
|
||||
// Service 상태 정보
|
||||
struct ServiceInfo {
|
||||
|
||||
time_t update_time; // 최종 update 시간 (local time, 시간동기화 영향 받음)
|
||||
int service_stat; // Service 상태 code. ( -1: 정보 미수신 상태, 그외 csagentd 설정과 동일)
|
||||
|
||||
time_t update_time_clock_sec; // clock_gettime(CLOCK_MONOTONIC) 을 통해 추출된 sec 정보. expire 여부 판단을 위해 사용.
|
||||
};
|
||||
|
||||
|
||||
// System 상태 정보
|
||||
struct SystemInfo {
|
||||
|
||||
time_t update_time; // 최종 update 시간
|
||||
|
||||
double load_avg[3]; // load average.
|
||||
|
||||
uint64_t memory_total; // Total memory size (byte 단위)
|
||||
uint64_t memory_free; // Free memory size (byte 단위)
|
||||
int memory_usage; // memory 사용률 (%)
|
||||
|
||||
uint64_t swap_total; // Total swap size (byte 단위)
|
||||
uint64_t swap_used; // Used swap size (byte 단위)
|
||||
int swap_usage; // swap 사용률 (%)
|
||||
|
||||
uint64_t storage_total; // Total Storage size (byte 단위)
|
||||
uint64_t storage_avail; // Available Storage size (byte 단위)
|
||||
int storage_max_usage; // Storage 중 최대 사용률 (%)
|
||||
|
||||
uint64_t disk_max_queue; // Disk 상태 정보 중 Max Queue Length
|
||||
double disk_max_busy; // Disk 상태 정보 중 Max busy(%)
|
||||
|
||||
uint64_t network_packet_in; // Network inbound packet 평균 count (count/sec)
|
||||
uint64_t network_packet_out; // Network outbound packet 평균 count (count/sec)
|
||||
uint64_t network_traffic_in; // Network inbound 평균 traffic (Byte/sec)
|
||||
uint64_t network_traffic_out; // Network outbound 평균 traffic (Byte/sec)
|
||||
|
||||
unsigned int tcp_total; // TCP 세션 total count
|
||||
unsigned int tcp_80; // TCP 세션 중 local 80 port 를 사용하는 세션 count
|
||||
unsigned int tcp_80_establish; // TCP 세션 중 local 80 port 를 사용하고.. ESTABLISH 상태인 세션 count
|
||||
};
|
||||
|
||||
// Shared momory 상의 각 slot 구성 정보.
|
||||
struct ClientInfo {
|
||||
|
||||
int use; // 해당 공유메모리 slot 사용 여부 (0 : 미사용, 1 : 사용 중)
|
||||
int valid; // 해당 공유메모리에 저장된 data 의 유효성 여부, (0 : 유효 안함, 1 : 유효)
|
||||
|
||||
char client_ip[IP_ADDR_LENGTH]; // Client IP 주소, NULL 포함 40자까지, IPv6 지원 목적
|
||||
int client_app; // 해당 공유메모리 slot 의 Data 가 어느 프로그램에서 수신되었는지 정의 (0 : csagentd, 1 : vmasd)
|
||||
|
||||
char hostname[HOST_NAME_LENGTH + 1]; // hostname, NULL 포함 최대 64자까지만 허용. 각 장비를 구분하는 Key 값으로 사용.
|
||||
|
||||
struct ServiceInfo service; // 수신된 서비스 상태 정보 저장
|
||||
struct SystemInfo system; // 수신된 System 상태 정보 저장
|
||||
};
|
||||
|
||||
// Shared Memory 전체 구조
|
||||
struct RcInfo {
|
||||
|
||||
int client_max_index; // FHS Client 정보 중 유효한 slot 의 최대 Index 정보.
|
||||
|
||||
struct ClientInfo client[MAX_CLIENT_COUNT]; // 각 FHS Client 정보.
|
||||
|
||||
// 향후 RCDB, RCTS 는 수집 항목이 다르므로.. 아래에 새로 정의하여 확장 처리한다.
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __SHM_DEFINE_H__ */
|
||||
@@ -0,0 +1,648 @@
|
||||
#include "ShmManager.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "ProcessConfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
|
||||
// 생성자
|
||||
CShmManager::CShmManager( struct RcInfo * p )
|
||||
: m_pShm( p )
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 소멸자
|
||||
CShmManager::~CShmManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// 멤버 변수인 공유메모리에 대한 포인터가 유효하지 여부를 판단하기 위한 함수.
|
||||
bool CShmManager::IsValid() const
|
||||
{
|
||||
if( m_pShm != NULL )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// 공유메모리 전체 영역을 초기화하기 위한 함수.
|
||||
void CShmManager::ClearAll() const
|
||||
{
|
||||
if( m_pShm != NULL )
|
||||
{
|
||||
memset( m_pShm, 0x00, sizeof( struct RcInfo ) );
|
||||
|
||||
// 각 Client Slot 의 서비스 상태 정보는 SERVICE_STAT_NOT_DEFINE 로 설정 처리
|
||||
for( int i = 0; i < MAX_CLIENT_COUNT; i++ )
|
||||
{
|
||||
m_pShm->client[i].service.service_stat = SERVICE_STAT_NOT_DEFINE;
|
||||
}
|
||||
|
||||
// client index 정보는 -1 로 초기화.
|
||||
m_pShm->client_max_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 공유메모리 상의 Client index 을 할당
|
||||
// - 전달 받은 IP 정보를 기반으로 이미 존재하는 경우.. 해당 index 반환.
|
||||
// - 존재하지 않는 경우.. 적합한 index 정보를 할당하여 전달 처리.
|
||||
// return 오류 발생시 -1, 그 외 client index
|
||||
// 본 함수는 업무 flow 상 동시 call을 하지 않아.. lock 을 사용하지 않음.
|
||||
// - 만약 동시 call 할 경우.. lock 기능 추가 필요.
|
||||
int CShmManager::AllocateClientIndex( const char * pClientAddress ) const
|
||||
{
|
||||
// 기존에 이미 할당된 slot 이 존재하는지 확인.
|
||||
int i;
|
||||
int nMaxIndex = m_pShm->client_max_index;
|
||||
for( i = 0 ; i <= nMaxIndex; i++ )
|
||||
{
|
||||
// 해당 slot 이 사용 중이고...
|
||||
if( m_pShm->client[i].use == 1 )
|
||||
{
|
||||
// client IP 정보가 동일한 경우...
|
||||
if( strcmp( pClientAddress, m_pShm->client[i].client_ip ) == 0 )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 할당된 slot 이 존재하지 않는 경우....
|
||||
// 모든 slot 을 대상으로 할당 가능한 slot 이 존재하는지 확인 후
|
||||
// slot 할당 및 index 정보 업데이트 처리.
|
||||
int index = -1;
|
||||
for( index = 0; index < MAX_CLIENT_COUNT; index++ )
|
||||
{
|
||||
// 해당 slot 이 미사용 중인 경우...
|
||||
if( m_pShm->client[index].use == 0 )
|
||||
{
|
||||
// 초기화...
|
||||
memset( &( m_pShm->client[index] ), 0x00, sizeof( struct ClientInfo ) );
|
||||
m_pShm->client[index].service.service_stat = SERVICE_STAT_NOT_DEFINE;
|
||||
|
||||
// 사용 여부 설정.
|
||||
m_pShm->client[index].use = 1;
|
||||
|
||||
// IP 정보 복사
|
||||
memcpy( m_pShm->client[index].client_ip, pClientAddress, IP_ADDR_LENGTH );
|
||||
|
||||
// 최대 client index 조정.
|
||||
if( index > m_pShm->client_max_index )
|
||||
{
|
||||
m_pShm->client_max_index = index;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
// 적합한 index 를 찾지 못한 경우...
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 공유메모리 상의 Client index 조회
|
||||
// - 전달 받은 IP 정보를 기반으로 이미 존재하는 경우.. 해당 index 반환.
|
||||
// - 존재하지 않을 경우.. -1 반환.
|
||||
// return 오류 발생시 -1, 그 외 client index
|
||||
// 본 함수는 업무 flow 상 동시 call을 하지 않아.. lock 을 사용하지 않음.
|
||||
// - 만약 동시 call 할 경우.. lock 기능 추가 필요.
|
||||
int CShmManager::FindClientIndex( const char * pClientAddress ) const
|
||||
{
|
||||
// 기존에 이미 할당된 slot 이 존재하는지 확인.
|
||||
int i;
|
||||
int nMaxIndex = m_pShm->client_max_index;
|
||||
for( i = 0; i <= nMaxIndex; i++ )
|
||||
{
|
||||
// 해당 slot 이 사용 중이고...
|
||||
if( m_pShm->client[i].use == 1 )
|
||||
{
|
||||
// client IP 정보가 동일한 경우...
|
||||
if( strcmp( pClientAddress, m_pShm->client[i].client_ip ) == 0 )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 해당 index 를 찾지 못한 경우...
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// 공유메모리 상의 Client index 해제 처리.
|
||||
void CShmManager::ReleaseClientIndex( int index ) const
|
||||
{
|
||||
// 잘못된 index 정보인 경우.. 그냥 무시
|
||||
if( index < 0 || index >= MAX_CLIENT_COUNT )
|
||||
return;
|
||||
|
||||
// 정상 index 인 경우...
|
||||
m_pShm->client[index].use = 0;
|
||||
|
||||
// 최대 client index 조정.
|
||||
if( m_pShm->client_max_index == index )
|
||||
{
|
||||
UpdateClientMaxIndex();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 공유메모리 상의 Client Max index 를 다시 조사하여 설정 처리.
|
||||
void CShmManager::UpdateClientMaxIndex() const
|
||||
{
|
||||
for( int i = (MAX_CLIENT_COUNT - 1); i >= 0; --i )
|
||||
{
|
||||
// 해당 slot 이 미사용 중인 경우...
|
||||
if( m_pShm->client[i].use == 1 )
|
||||
{
|
||||
m_pShm->client_max_index = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 만약 유효한 slot 이 없는 경우....
|
||||
// client index 정보는 -1 로 초기화.
|
||||
m_pShm->client_max_index = -1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 공유메모리 상의 Client index 에 해당하는 client 영역을 반환.
|
||||
struct ClientInfo * CShmManager::GetClientPtr( int index ) const
|
||||
{
|
||||
// 잘못된 index 정보인 경우.. 그냥 무시
|
||||
if( index < 0 || index >= MAX_CLIENT_COUNT )
|
||||
return NULL;
|
||||
|
||||
return &(m_pShm->client[index]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// vmasd 에서 받은 정보를 공유메모리에 저장 처리
|
||||
// - 실제 오류 상황인 경우에만.. false 반환.
|
||||
// - 그외 이미 존재하는 상황 등인 경우에는 정상 처리된 것으로 반환 처리한다.
|
||||
// return false
|
||||
bool CShmManager::SetVmasdData( struct vmasd_broadcast_message_body * pBody ) const
|
||||
{
|
||||
int index = -1;
|
||||
|
||||
// 기존에 이미 할당된 slot 이 존재하는지 확인.
|
||||
int nMaxIndex = m_pShm->client_max_index;
|
||||
for( int i = 0; i <= nMaxIndex; i++ )
|
||||
{
|
||||
// 해당 slot 이 이미 사용 중이고...
|
||||
if( m_pShm->client[i].use == 1 && m_pShm->client[i].valid == 1 )
|
||||
{
|
||||
// csagnetd 의 경우. client ip 를 비교했지만...
|
||||
// vmasd 는 hostname 을 비교해야 함.
|
||||
// - csagentd 는 공인, 사설망을 사용할 수 있어.. 사설망만을 사용하는 vmasd 와 동시 동작시 ip 가 다를 수 있다.
|
||||
|
||||
// hostname 이 동일한 경우...
|
||||
if( strcmp( pBody->hostname, m_pShm->client[i].hostname ) == 0 )
|
||||
{
|
||||
// client_app 이 vmasd 인 경우...
|
||||
if( m_pShm->client[i].client_app == 1 )
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// csagentd 정보와 충돌인 경우... csagentd 의 정보를 우선 사용토록 처리한다.
|
||||
_LOG( LINF, "vmasd shm update skip. csagentd data exist. [%s][%s]", pBody->domain, pBody->hostname );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 기존에 할당된 slot 이 존재하지 않는 경우....
|
||||
// 모든 slot 을 대상으로 할당 가능한 slot 이 존재하는지 확인 후
|
||||
// slot 할당 및 index 정보 업데이트 처리.
|
||||
if( index == -1 )
|
||||
{
|
||||
for( int j = 0; j < MAX_CLIENT_COUNT; j++ )
|
||||
{
|
||||
// 해당 slot 이 미사용 중인 경우...
|
||||
if( m_pShm->client[j].use == 0 )
|
||||
{
|
||||
index = j;
|
||||
|
||||
// 초기화...
|
||||
memset( &( m_pShm->client[j] ), 0x00, sizeof( struct ClientInfo ) );
|
||||
m_pShm->client[j].service.service_stat = SERVICE_STAT_NOT_DEFINE;
|
||||
|
||||
// 사용 여부 설정.
|
||||
m_pShm->client[j].use = 1;
|
||||
|
||||
// IP 정보 복사
|
||||
strcpy( m_pShm->client[j].client_ip, pBody->domain );
|
||||
|
||||
// hostname 정보 복사.
|
||||
strcpy( m_pShm->client[j].hostname, pBody->hostname );
|
||||
|
||||
// client_app 을 vmasd 로 설정.
|
||||
m_pShm->client[j].client_app = 1;
|
||||
|
||||
// 최대 client index 조정.
|
||||
if( j > m_pShm->client_max_index )
|
||||
{
|
||||
m_pShm->client_max_index = j;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( index == -1 )
|
||||
{
|
||||
LOG( LERR, "vmasd shm update fail. shm allocate fail.[%s][%s]", pBody->domain, pBody->hostname );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct ClientInfo * pClient = &( m_pShm->client[index] );
|
||||
|
||||
// Body 정보를 저장 처리.
|
||||
|
||||
// vmasd storage 용량 정보 처리 관련...
|
||||
pClient->system.storage_total = pBody->total;
|
||||
pClient->system.storage_avail = pBody->free;
|
||||
if( pClient->system.storage_avail == 0 )
|
||||
{
|
||||
if( pClient->system.storage_total == 0 )
|
||||
{
|
||||
// 1. total = 0, free = 0 인 경우
|
||||
// - 공인 IP 정보 추출 실패, 공인 IP 를 통한 Apache 접속 테스트 실패, DNS resolve 체크 실패시...
|
||||
// - 서비스 불가 (SERVICE_STAT_DISABLE) 상태로 처리.
|
||||
pClient->service.service_stat = SERVICE_STAT_DISABLE;
|
||||
|
||||
// storage 최대 사용량 정보는 0 으로 설정 처리.
|
||||
pClient->system.storage_max_usage = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2. total = 정상, free = 0 인 경우
|
||||
// - free 용량이 total 보다 큰 경우
|
||||
// - Read Only (SERVICE_STAT_RONLY) 상태로 처리한다.
|
||||
pClient->service.service_stat = SERVICE_STAT_RONLY;
|
||||
|
||||
// storage 최대 사용량 정보는 100 % 으로 설정 처리.
|
||||
pClient->system.storage_max_usage = 100;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// free 용량 정보는 정상...
|
||||
if( pClient->system.storage_total == 0 )
|
||||
{
|
||||
// total 정보가 0 인 경우...
|
||||
// - 추출 관련 오류 발생 상황으로 판단되며...
|
||||
// - Read Only (SERVICE_STAT_RONLY) 상태로 처리한다.
|
||||
pClient->service.service_stat = SERVICE_STAT_RONLY;
|
||||
|
||||
// storage 최대 사용량 정보는 100 % 으로 설정 처리.
|
||||
pClient->system.storage_max_usage = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
// total, free 정보가 모두 정상인 경우...
|
||||
|
||||
// 평균 사용량 정보를 추출한다.
|
||||
int usage = (int)ceil( (double)( pClient->system.storage_total - pClient->system.storage_avail ) / pClient->system.storage_total * 100.0 );
|
||||
|
||||
// 원래는 최대 storage 사용량 의미이지만.. vmasd 는 평균 사용량으로 밖에 처리할 수 없음.
|
||||
pClient->system.storage_max_usage = usage;
|
||||
|
||||
// pBody->manual_disable
|
||||
// 2 : fsck_ufs 프로세스가 동작 중인 경우.. --> SERVICE_STAT_RONLY 로 설정.
|
||||
// 1 : /user/service/vmasd.disable 파일이 존재할 경우..
|
||||
// .disable 설정이 되지 않은 유효 Mount 중.. 가장 큰 Free Disk 용량(f_bfree) 이 0 인 경우... --> SERVICE_STAT_RONLY 로 설정.
|
||||
// 0 : 그 외..
|
||||
|
||||
if( pBody->manual_disable == 0 )
|
||||
{
|
||||
// 정상인 상태에서...
|
||||
// storeage 사용량이 conf 에 정의된 설정값 이상인 경우... 강제로 read-only 로 설정 처리한다.
|
||||
if( usage >= CProcessConfig::GetInstance()->GetStorageMaxUsageToDisable() )
|
||||
{
|
||||
_LOG( LINF, "vmasd client[%s] hostname[%s] storage max usage over [%d/%d]. set read only stat."
|
||||
, pBody->domain, pBody->hostname, usage, CProcessConfig::GetInstance()->GetStorageMaxUsageToDisable() );
|
||||
|
||||
pClient->service.service_stat = SERVICE_STAT_RONLY;
|
||||
}
|
||||
else
|
||||
pClient->service.service_stat = SERVICE_STAT_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
pClient->service.service_stat = SERVICE_STAT_RONLY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// vmasd 는 평균 busy 율 사용, csagentd 는 Max busy 율 사용.
|
||||
// 따라서 값의 의미가 정확히 일치하지는 않지만.. 그래도 저장 처리한다.
|
||||
pClient->system.disk_max_busy = pBody->disk_percent;
|
||||
|
||||
// vmasd 는 마지막 disk 의 queue length. csagent 는 disk 의 최대 queue length
|
||||
// 따라서 값의 의미가 정확히 일치하지는 않지만.. 그래도 저장 처리한다.
|
||||
pClient->system.disk_max_queue = pBody->disk_backlog;
|
||||
|
||||
pClient->system.tcp_80 = pBody->connection_total;
|
||||
pClient->system.tcp_80_establish = pBody->connection_established;
|
||||
|
||||
pClient->system.network_packet_in = pBody->traffic_ip;
|
||||
pClient->system.network_packet_out = pBody->traffic_op;
|
||||
pClient->system.network_traffic_in = pBody->traffic_ib;
|
||||
pClient->system.network_traffic_out = pBody->traffic_ob;
|
||||
|
||||
|
||||
// 현재 시간 정보 추출 및 업데이트
|
||||
time_t currentTime = time( 0 );
|
||||
|
||||
struct timespec currentClock;
|
||||
memset( ¤tClock, 0x00, sizeof( struct timespec ) );
|
||||
clock_gettime( CLOCK_MONOTONIC, ¤tClock );
|
||||
|
||||
pClient->service.update_time = currentTime;
|
||||
pClient->service.update_time_clock_sec = currentClock.tv_sec;
|
||||
pClient->system.update_time = currentTime;
|
||||
|
||||
// Data 유효 여부 설정.
|
||||
pClient->valid = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Alive (상태가 OK, Read-only) 인 FHS 목록 정보 조회 요청
|
||||
// param vecResult [out] 추출된 alive fhs 목록을 저장하기 위한 vector 참조.
|
||||
// return 목록 갯수
|
||||
int CShmManager::GetAliveFhsList( std::vector<struct FhsServiceStatInfo> & vecResult ) const
|
||||
{
|
||||
int nMaxIndex = m_pShm->client_max_index;
|
||||
int nResult = 0;
|
||||
|
||||
struct FhsServiceStatInfo stFhs;
|
||||
memset( &stFhs, 0x00, sizeof( struct FhsServiceStatInfo ) );
|
||||
|
||||
// 결과를 저장할 vector 는 초기화 하지 않음.
|
||||
// - 이미 다른 목적으로 data 를 저장하여 전달할 수 있으므로.. 초기화하지 않음.
|
||||
|
||||
// Max index 까지 루프를 돌면서... 검색
|
||||
for( int i = 0; i <= nMaxIndex; i++ )
|
||||
{
|
||||
// slot 할당되어 있고.. data 가 유효한 경우...
|
||||
if( m_pShm->client[i].use == 1 && m_pShm->client[i].valid == 1 )
|
||||
{
|
||||
// 서비스 상태가 OK, read only 인 경우...
|
||||
if( m_pShm->client[i].service.service_stat == SERVICE_STAT_OK
|
||||
|| m_pShm->client[i].service.service_stat == SERVICE_STAT_RONLY )
|
||||
{
|
||||
// update 처리가 오래된 garbage 데이터는 control 모듈에서 정리 처리하므로...
|
||||
// 여기서는 체크하지 않는다.
|
||||
|
||||
// hostname 정보가 유효한지 확인 후...
|
||||
if( strlen( m_pShm->client[i].hostname ) > 0 )
|
||||
{
|
||||
// hostname 정보 복사.
|
||||
strncpy( stFhs.hostname, m_pShm->client[i].hostname, HOST_NAME_LENGTH );
|
||||
|
||||
// 서비스 상태 정보 설정.
|
||||
stFhs.service_stat = m_pShm->client[i].service.service_stat;
|
||||
|
||||
// vector 에 결과 저장
|
||||
vecResult.push_back( stFhs );
|
||||
|
||||
nResult += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
|
||||
// 공유메모리에 저장된 client 정보 중 갱신되지 않는 오래된 client 정보를 정리한다.
|
||||
// param expireTime [in] 공유메모리 update_time_clock_sec 정보와 expire 처리 여부를 비교하기 위한 기준값.
|
||||
// return expire 처리된 client 수.
|
||||
int CShmManager::ExpireClient( time_t expireTime ) const
|
||||
{
|
||||
int nExpireCount = 0;
|
||||
|
||||
// Max Index 에 오류가 있을 수도 있으므로..... 전체 slot 을 모두 검사한다.
|
||||
for( int i = 0; i < MAX_CLIENT_COUNT; i++ )
|
||||
{
|
||||
// 해당 slot 이 사용 중이고.. data 정보가 유효한 경우...
|
||||
if( m_pShm->client[i].use == 1 && m_pShm->client[i].valid == 1 && m_pShm->client[i].service.update_time_clock_sec != 0 )
|
||||
{
|
||||
// 최종 update clock 정보와 전달받은 expire 정보를 비교...
|
||||
if( m_pShm->client[i].service.update_time_clock_sec < expireTime )
|
||||
{
|
||||
// 전달받은 expire 시간보다 오래된 client 인 경우....
|
||||
// - 로깅 후 expire 처리한다.
|
||||
|
||||
struct tm timeLast;
|
||||
localtime_r( &(m_pShm->client[i].service.update_time), &timeLast );
|
||||
|
||||
_LOG( LWAR, "client[%s] stat[%d] app[%d] expired. last update time[%04d-%02d-%02d %02d:%02d:%02d]"
|
||||
, m_pShm->client[i].hostname, m_pShm->client[i].service.service_stat, m_pShm->client[i].client_app
|
||||
, timeLast.tm_year + 1900, timeLast.tm_mon + 1, timeLast.tm_mday
|
||||
, timeLast.tm_hour, timeLast.tm_min, timeLast.tm_sec
|
||||
);
|
||||
|
||||
// 해제 처리 시작
|
||||
// vmasd 인 경우.. valid, use 까지 reset 처리.
|
||||
// csagent 인 경우.. valid 만 reset 처리 ( 이래야 세션이 살아 있는 중에 재할당을 방지하고.. 세션이 끊어지면서.. use 를 0으로 처리함)
|
||||
if( m_pShm->client[i].client_app == 1 )
|
||||
{
|
||||
// vmasd 인 경우..
|
||||
m_pShm->client[i].valid = 0;
|
||||
m_pShm->client[i].use = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// csagent 인 경우...
|
||||
m_pShm->client[i].valid = 0;
|
||||
}
|
||||
|
||||
// count 증가 처리
|
||||
++nExpireCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// expire 처리된 client 가 존재하는 경우.... Max Index 재설정 처리.
|
||||
if( nExpireCount > 0 )
|
||||
{
|
||||
UpdateClientMaxIndex();
|
||||
}
|
||||
|
||||
return nExpireCount;
|
||||
}
|
||||
|
||||
// GMS 로 전송할 RC 상태 정보 요청
|
||||
// param vecResult [out] 추출된 목록을 저장하기 위한 vector 참조.
|
||||
// return 목록 갯수
|
||||
int CShmManager::GetGmsSendList( std::vector<struct PacketDataGms> & vecResult ) const
|
||||
{
|
||||
|
||||
struct PacketDataGms stSystem;
|
||||
int nResult = 0;
|
||||
int nMaxIndex = m_pShm->client_max_index;
|
||||
|
||||
// 결과를 저장할 vector 는 초기화 하지 않음.
|
||||
// - 이미 다른 목적으로 data 를 저장하여 전달할 수 있으므로.. 초기화하지 않음.
|
||||
|
||||
// Max index 까지 루프를 돌면서... 검색
|
||||
for( int i = 0; i <= nMaxIndex; i++ )
|
||||
{
|
||||
// slot 할당되어 있고.. data 가 유효한 경우...
|
||||
if( m_pShm->client[i].use == 1 && m_pShm->client[i].valid == 1 )
|
||||
{
|
||||
// 임시 객체 초기화.
|
||||
memset( &stSystem, 0x00, sizeof( struct PacketDataGms ) );
|
||||
|
||||
// 저장할 정보 변환 처리.
|
||||
strncpy( stSystem.domain, m_pShm->client[i].hostname, 511 );
|
||||
|
||||
stSystem.total = m_pShm->client[i].system.storage_total;
|
||||
stSystem.free = m_pShm->client[i].system.storage_avail;
|
||||
|
||||
// 정상 상태인 경우.. system 업데이트 시간 사용..
|
||||
// ronly, disable, out 등의 상황인 경우.. service 업데이트 시간 사용.
|
||||
if( m_pShm->client[i].service.service_stat == SERVICE_STAT_OK )
|
||||
{
|
||||
stSystem.manual_disable = 0;
|
||||
stSystem.stamp = m_pShm->client[i].system.update_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
stSystem.stamp = m_pShm->client[i].service.update_time;
|
||||
|
||||
if( m_pShm->client[i].service.service_stat == SERVICE_STAT_RONLY )
|
||||
{
|
||||
stSystem.manual_disable = 1;
|
||||
}
|
||||
else if( m_pShm->client[i].service.service_stat == SERVICE_STAT_OUT)
|
||||
{
|
||||
stSystem.manual_disable = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
stSystem.manual_disable = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// (disk_backlog/10) + (connection_established/50) 의 계산 값... ( vmasd 소스 참고)
|
||||
stSystem.upload_level = ( m_pShm->client[i].system.disk_max_queue ) / 10 + (m_pShm->client[i].system.tcp_80_establish) / 50;
|
||||
|
||||
stSystem.disk_backlog = (int)( m_pShm->client[i].system.disk_max_queue );
|
||||
stSystem.disk_percent = m_pShm->client[i].system.disk_max_busy;
|
||||
|
||||
stSystem.connection_established = (int)( m_pShm->client[i].system.tcp_80_establish );
|
||||
stSystem.connection_total = (int)( m_pShm->client[i].system.tcp_80 );
|
||||
|
||||
stSystem.traffic_ip = (uint32_t)( m_pShm->client[i].system.network_packet_in );
|
||||
stSystem.traffic_ib = (uint32_t)( m_pShm->client[i].system.network_traffic_in );
|
||||
stSystem.traffic_op = (uint32_t)( m_pShm->client[i].system.network_packet_out );
|
||||
stSystem.traffic_ob = (uint32_t)( m_pShm->client[i].system.network_traffic_out );
|
||||
|
||||
strncpy( stSystem.hostname, m_pShm->client[i].hostname, 63 );
|
||||
|
||||
// vector 에 결과 저장
|
||||
vecResult.push_back( stSystem );
|
||||
|
||||
// result count 증가.
|
||||
nResult += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Top FHS 정보 추출
|
||||
// param vecResult [out] 추출된 목록을 저장하기 위한 vector 참조.
|
||||
// param dDiskMaxBusyWeight [in] score 항목 계산시 disk_max_busy 정보에 대한 가중치값.
|
||||
// return 목록 갯수
|
||||
int CShmManager::GetWritableFhsList( std::vector<struct WritableFhsInfo> & vecResult, double dDiskMaxBusyWeight ) const
|
||||
{
|
||||
struct WritableFhsInfo stWritableFhs;
|
||||
|
||||
int nResult = 0;
|
||||
int nMaxIndex = m_pShm->client_max_index;
|
||||
|
||||
// 결과를 저장할 vector 는 초기화 하지 않음.
|
||||
// - 이미 다른 목적으로 data 를 저장하여 전달할 수 있으므로.. 초기화하지 않음.
|
||||
|
||||
// FHS 의 시스템 정보 업데이트가 오래된 경우..
|
||||
// - GarbageClean Thread 가 지정된 시간( 20 sec ) 를 초과한 경우.. expire 처리하지만...
|
||||
// - 오류가 발생할 수 있고... FHS 상태가 이상할 경우.. 해당 장비는 선택하지 않는 것이 좋으므로...
|
||||
// - 업데이트가 비교적 최근에 발생한 FHS 정보만을 사용토록 한다.
|
||||
// - vmasd 는 6 sec 마다... csagentd 는 4(service), 10(system) sec 마다 정보 전송...
|
||||
// - 따라서.. 8 sec 초과된 정보는 사용하지 않도록 한다.
|
||||
// - local time 은 시간 동기화 영향 받으므로... update_time_clock_sec 항목을 사용하여 판단한다.
|
||||
time_t expireTime;
|
||||
struct timespec currentClock;
|
||||
memset( ¤tClock, 0x00, sizeof( struct timespec ) );
|
||||
clock_gettime( CLOCK_MONOTONIC, ¤tClock );
|
||||
|
||||
expireTime = currentClock.tv_sec - 8;
|
||||
|
||||
|
||||
// Max index 까지 루프를 돌면서... 검색
|
||||
for( int i = 0; i <= nMaxIndex; i++ )
|
||||
{
|
||||
// slot 할당되어 있고.. data 가 유효하고..
|
||||
// write 가능 상태인 경우..
|
||||
// system 상태 정보가 정상인 경우...( system 정보가 늦게 수신되므로.. 이를 반영 )
|
||||
if( m_pShm->client[i].use == 1
|
||||
&& m_pShm->client[i].valid == 1
|
||||
&& m_pShm->client[i].service.service_stat == SERVICE_STAT_OK
|
||||
&& m_pShm->client[i].system.update_time != 0 )
|
||||
{
|
||||
// 최종 update clock 정보와 전달받은 expire 정보를 비교...
|
||||
if( m_pShm->client[i].service.update_time_clock_sec >= expireTime )
|
||||
{
|
||||
// expire 시간보다 오래되지 않은 최근 업데이트된 FHS 인 경우..
|
||||
|
||||
// 임시 객체 초기화.
|
||||
memset( &stWritableFhs, 0x00, sizeof( struct WritableFhsInfo ) );
|
||||
|
||||
// hostname 저장.
|
||||
strncpy( stWritableFhs.hostname, m_pShm->client[i].hostname, HOST_NAME_LENGTH );
|
||||
|
||||
// write score 계산 처리.
|
||||
// - storage_max_usage 항목과
|
||||
// - disk_max_busy * 전달받은 가중치 값의 합.
|
||||
stWritableFhs.score = (double)( m_pShm->client[i].system.storage_max_usage )
|
||||
+ ( ( m_pShm->client[i].system.disk_max_busy ) * dDiskMaxBusyWeight );
|
||||
|
||||
// vector 에 결과 저장
|
||||
vecResult.push_back( stWritableFhs );
|
||||
|
||||
// result count 증가.
|
||||
nResult += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nResult;
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/****************************************************************************
|
||||
shared memory date management class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/06/15
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SHM_MANAGER_H__
|
||||
#define __SHM_MANAGER_H__
|
||||
|
||||
#include "ShmDefine.h"
|
||||
#include "ProtocolVmasd.h"
|
||||
#include "ProtocolGms.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
// 공유메모리에서 각 FHS 의 서비스 상태 정보 조회시 사용하기 위한 구조체
|
||||
// - interface 함수에서 사용하기 위해 정의함.
|
||||
struct FhsServiceStatInfo {
|
||||
|
||||
char hostname[HOST_NAME_LENGTH + 1]; // hostname, NULL 포함 최대 64자까지만 허용됨.
|
||||
int service_stat; // Service 상태 code.
|
||||
};
|
||||
|
||||
// 공유메모리에 저장된 각 FHS 정보 중 Write 가 가능한 FHS 정보를 추출하여 저장하기 위한 구조체
|
||||
// - Top FHS 선택 모듈에 FHS 정보를 추출하여 전달하기 위해 정의함.
|
||||
struct WritableFhsInfo {
|
||||
|
||||
char hostname[HOST_NAME_LENGTH + 1]; // hostname, NULL 포함 최대 64자까지만 허용됨.
|
||||
double score; // Write 관련 시스템 모니터링 항목을 이용하여 계산된 score, 작을수록 idle
|
||||
};
|
||||
|
||||
|
||||
// 공유메모리 영역 전체에 대한 접근 처리 관련 인터페이스를 제공하기 위한 클래스
|
||||
class CShmManager
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
// 공유메모리에 대한 포인터
|
||||
struct RcInfo * const m_pShm;
|
||||
|
||||
public:
|
||||
|
||||
// 생성자
|
||||
CShmManager( struct RcInfo * p );
|
||||
|
||||
// 소멸자
|
||||
~CShmManager();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// 함수 선언시 const 구문 사용 이유
|
||||
// - 멤버변수인 m_pShm 값이 변경될 경우...엉뚱한 메모리 영역을 참조하는 불상사 발생.
|
||||
// - 따라서 코딩시 m_pShm 값이 변경되지 않음을 선언하여....
|
||||
// - 컴파일시 문제가 없는지 확인하기 위한 목적으로 사용함.
|
||||
// - map 관련 멤버 변수 사용으로 인해.. 일부 함수에서는 사용하지 못함.
|
||||
|
||||
|
||||
// 멤버 변수인 공유메모리에 대한 포인터가 유효하지 여부를 판단하기 위한 함수.
|
||||
// return 유효한 경우 true, NULL 인 경우 false
|
||||
bool IsValid( void ) const;
|
||||
|
||||
// 공유메모리 전체 영역을 초기화하기 위한 함수.
|
||||
// return
|
||||
void ClearAll( void ) const;
|
||||
|
||||
// 공유메모리 상의 Client index 을 할당
|
||||
// - 전달 받은 IP 정보를 기반으로 이미 존재하는 경우.. 해당 index 반환.
|
||||
// - 존재하지 않는 경우.. 적합한 index 정보를 할당하여 전달 처리.
|
||||
// return 오류 발생시 -1, 그 외 client index
|
||||
// 본 함수는 업무 flow 상 동시 call을 하지 않아.. lock 을 사용하지 않음.
|
||||
// - 만약 동시 call 할 경우.. lock 기능 추가 필요.
|
||||
int AllocateClientIndex( const char * pClientAddress ) const;
|
||||
|
||||
// 공유메모리 상의 Client index 조회
|
||||
// - 전달 받은 IP 정보를 기반으로 이미 존재하는 경우.. 해당 index 반환.
|
||||
// - 존재하지 않을 경우.. -1 반환.
|
||||
// return 오류 발생시 -1, 그 외 client index
|
||||
// 본 함수는 업무 flow 상 동시 call을 하지 않아.. lock 을 사용하지 않음.
|
||||
// - 만약 동시 call 할 경우.. lock 기능 추가 필요.
|
||||
int FindClientIndex( const char * pClientAddress ) const;
|
||||
|
||||
|
||||
// 공유메모리 상의 Client index 해제 처리.
|
||||
void ReleaseClientIndex( int index ) const;
|
||||
|
||||
// 공유메모리 상의 Client Max index 를 다시 조사하여 설정 처리.
|
||||
void UpdateClientMaxIndex( void ) const;
|
||||
|
||||
|
||||
// 공유메모리 상의 Client index 에 해당하는 client 영역을 반환.
|
||||
struct ClientInfo * GetClientPtr( int index ) const;
|
||||
|
||||
// vmasd 에서 받은 정보를 공유메모리에 저장 처리
|
||||
// - 실제 오류 상황인 경우에만.. false 반환.
|
||||
// - 그외 이미 존재하는 상황 등인 경우에는 정상 처리된 것으로 반환 처리한다.
|
||||
// return false
|
||||
bool SetVmasdData( struct vmasd_broadcast_message_body * pBody ) const;
|
||||
|
||||
// Alive (상태가 OK, Read-only) 인 FHS 목록 정보 조회 요청
|
||||
// param vecResult [out] 추출된 alive fhs 목록을 저장하기 위한 vector 참조.
|
||||
// return 목록 갯수
|
||||
int GetAliveFhsList( std::vector<struct FhsServiceStatInfo> & vecResult ) const;
|
||||
|
||||
|
||||
// 공유메모리에 저장된 client 정보 중 갱신되지 않는 오래된 client 정보를 정리한다.
|
||||
// param expireTime [in] 공유메모리 update_time_clock_sec 정보와 expire 처리 여부를 비교하기 위한 기준값.
|
||||
// return expire 처리된 client 수.
|
||||
int ExpireClient( time_t expireTime ) const;
|
||||
|
||||
|
||||
// GMS 로 전송할 RC 상태 정보 요청
|
||||
// param vecResult [out] 추출된 목록을 저장하기 위한 vector 참조.
|
||||
// return 목록 갯수
|
||||
int GetGmsSendList( std::vector<struct PacketDataGms> & vecResult ) const;
|
||||
|
||||
|
||||
// Top FHS 정보 추출
|
||||
// param vecResult [out] 추출된 목록을 저장하기 위한 vector 참조.
|
||||
// param dDiskMaxBusyWeight [in] score 항목 계산시 disk_max_busy 정보에 대한 가중치값.
|
||||
// return 목록 갯수
|
||||
int GetWritableFhsList( std::vector<struct WritableFhsInfo> & vecResult, double dDiskMaxBusyWeight ) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* __SHM_MANAGER_H__ */
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
#include "ShmMonitor.h"
|
||||
|
||||
#include "ShmDefine.h"
|
||||
#include "ShmControl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
// 프로세스 name
|
||||
#define MONITOR_PROG_NAME "rc_show"
|
||||
|
||||
|
||||
// 화면 갱신 time (sec)
|
||||
#define DEFAULT_REFRESH_TIME 3
|
||||
|
||||
|
||||
// Shared memory key 파일.
|
||||
// 2018-02-21 CHG huibong /tmp 경로 대신 /user/service 하위에 생성되도록 경로 수정 (#31701)
|
||||
// - /tmp 경로 사용시 자동 clean 처리 모듈 동작으로 삭제되는 상황 발생하여 수정 처리.
|
||||
#define SHARED_MEMORY_KEY_FILE "/user/service/rc_mond.shm"
|
||||
|
||||
|
||||
// 공유메모리 생성, 삭제 등의 Manager 객체에 대한 포인터.
|
||||
CShmControl< struct RcInfo > * g_pShmCtl = NULL;
|
||||
|
||||
|
||||
// CHG 2015-11-03 huibong
|
||||
// - 일감 #24963 에 따른 기능 추가 수행.
|
||||
|
||||
|
||||
// 사용방법 표시
|
||||
void PrintUsage()
|
||||
{
|
||||
fprintf( stderr, "\n" );
|
||||
fprintf( stderr, "Usage: " MONITOR_PROG_NAME " [OPTION] \n" );
|
||||
fprintf( stderr, "Options: \n" );
|
||||
|
||||
fprintf( stderr, " -i {sec} Set refresh interval (sec) \n" );
|
||||
fprintf( stderr, " -h Display help information \n" );
|
||||
fprintf( stderr, " -v Display version \n" );
|
||||
|
||||
fprintf( stderr, "\n" );
|
||||
fprintf( stderr, MONITOR_PROG_NAME " is Solbox Cloud Storage module.\n" );
|
||||
fprintf( stderr, " - Display shared memory info that FHS system, service status collected by %s.\n", PROG_NAME );
|
||||
fprintf( stderr, "\n" );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 버전 정보 표시
|
||||
void PrintVersion()
|
||||
{
|
||||
fprintf( stderr, "\n" );
|
||||
fprintf( stderr, MONITOR_PROG_NAME " version: " PROG_VERSION "\n\n" );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char * argv[] )
|
||||
{
|
||||
int iRefreshTime = DEFAULT_REFRESH_TIME;
|
||||
|
||||
if( argc >= 2 )
|
||||
{
|
||||
int opt;
|
||||
while( ( opt = getopt( argc, argv, "hvi:" ) ) != -1 ) // 옵션 끝까지 파싱처리
|
||||
{
|
||||
switch( opt )
|
||||
{
|
||||
case 'h':
|
||||
case '?': // 정의되지 않은 문자가 나타날 경우 getopt 에 자동반환. 도움말 표시 처리.
|
||||
PrintUsage();
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
case 'v':
|
||||
PrintVersion();
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
case 'i':
|
||||
iRefreshTime = atoi( optarg );
|
||||
break;
|
||||
|
||||
default: // 본 조건절은 getopt 특성상 동작하지 않지만...업무 Flow 이해(?)를 위해 유지한다.
|
||||
fprintf( stderr, "Unkonwn options[%c] used. program terminated.\n", opt );
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// iRefreshTime 정합성 검사
|
||||
// - atoi 에서 오류시 0 을 반환하므로... 무한 refresh 방지.
|
||||
if( iRefreshTime <= 0 )
|
||||
iRefreshTime = DEFAULT_REFRESH_TIME;
|
||||
|
||||
|
||||
// 공유메모리 접근 처리
|
||||
key_t iShmKey;
|
||||
|
||||
// 공유메모리 key 생성을 위한 임시 파일 생성 처리.
|
||||
FILE * pShmFile = fopen( SHARED_MEMORY_KEY_FILE, "r" );
|
||||
if( pShmFile != NULL )
|
||||
{
|
||||
// Key file 생성이 성공한 경우... 파일만 있으면 되니까.. close 처리한다.
|
||||
fclose( pShmFile );
|
||||
pShmFile = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Key file 생성에 실패한 경우...
|
||||
int errorNum = errno;
|
||||
fprintf(stderr, "Shared memory key file open fail[%s] [%d][%s]\n\n", SHARED_MEMORY_KEY_FILE, errorNum, strerror( errorNum ) );
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// 임시 파일로 부터 key 값 추출
|
||||
iShmKey = ftok( SHARED_MEMORY_KEY_FILE, 1 );
|
||||
if( iShmKey == (key_t)-1 )
|
||||
{
|
||||
// 공유메모리 Key 생성 실패시
|
||||
fprintf( stderr, "Shared memory key create failed. temp file [%s]\n\n", SHARED_MEMORY_KEY_FILE );
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// 공유메모리에 생성 담당 class 객체를 생성 및 공유메모리 생성 or attach
|
||||
CShmControl< struct RcInfo > shmCtl;
|
||||
if( shmCtl.Attach( iShmKey, sizeof( struct RcInfo ) ) == false )
|
||||
{
|
||||
fprintf( stderr, "Shared memory attach failed. key[%d] size[%lu].\n\n", iShmKey, sizeof( struct RcInfo ) );
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
g_pShmCtl = &shmCtl; // 전역 포인터에 대한 포인터 지정.
|
||||
|
||||
|
||||
// 종료 처리 관련 시그널 처리기
|
||||
signal( SIGINT, ProgramExit );
|
||||
|
||||
|
||||
struct RcInfo * pShm = shmCtl.GetShmPtr();
|
||||
struct ClientInfo * pClient = NULL;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
|
||||
// 중간에 rc_mond 가 종료되었는지 체크...
|
||||
pShmFile = fopen( SHARED_MEMORY_KEY_FILE, "r" );
|
||||
if( pShmFile == NULL )
|
||||
{
|
||||
// Key file open check 실패시..
|
||||
fprintf( stderr, "\nshared memory key file not found [%s]. program exit.\n\n", SHARED_MEMORY_KEY_FILE );
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// key 파일 정상인 경우...
|
||||
fclose( pShmFile );
|
||||
pShmFile = NULL;
|
||||
}
|
||||
|
||||
|
||||
system( "clear" );
|
||||
|
||||
printf( "refresh time : %3d sec\n", iRefreshTime );
|
||||
printf( "max client index : %3d\n", pShm->client_max_index );
|
||||
printf( "svc - 0:ok, 1:manual out, 2:service disable, 3:read only\n\n");
|
||||
//printf( "app - 0:csagentd, 1:vmasd\n\n" );
|
||||
|
||||
//printf( "shm\tvalid\tip\t\tapp\thost\t\t\tupdate\t\tsvc\tupdate\t\tload\t\tmem\tswap\tstg\tdisk\t\tnet\t\ttcp\n" );
|
||||
printf( "shm\tip\t\thost\t\t\t\tupdate\t\tsvc\tupdate\t load\t\tmem\tswap\tstg\tdisk\t\ttraffic\t\t tcp\n" );
|
||||
printf( "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n" );
|
||||
|
||||
for( int i = 0; i <= pShm->client_max_index; i++ )
|
||||
{
|
||||
pClient = &(pShm->client[i]);
|
||||
|
||||
// 2018-02-22 CHG huibong #31703
|
||||
// 유효하지 않은 세션이지만.. garbage clean thread 에 의해 처리되기 전까지 존재하는 FHS 항목 표시 안되록 수정.
|
||||
// 운영자들이 오해할 가능성 존재해서 정상적인 FHS 만 표시되도록 수정
|
||||
|
||||
if( pClient->use != 0 && pClient->valid != 0)
|
||||
{
|
||||
//printf( "%3d\t%d\t%s\t%d\t%s\t%10ld\t%d\t%10ld\t%.2lf %.2lf %.2lf\t%3d\t%3d\t%3d\t%3ju %4.1lf %10ju %10ju\t%5u %5u %5u\n"
|
||||
printf( "%3d\t%s\t%-31.30s\t%10ld\t%d\t%10ld %.2lf %.2lf %.2lf\t%3d\t%3d\t%3d\t%3ju %6.1lf %10ju %10ju %5u %5u %5u\n"
|
||||
, i, pClient->client_ip
|
||||
, pClient->hostname
|
||||
, pClient->service.update_time, pClient->service.service_stat
|
||||
, pClient->system.update_time
|
||||
, pClient->system.load_avg[0], pClient->system.load_avg[1], pClient->system.load_avg[2]
|
||||
, pClient->system.memory_usage
|
||||
, pClient->system.swap_usage
|
||||
, pClient->system.storage_max_usage
|
||||
, pClient->system.disk_max_queue, pClient->system.disk_max_busy
|
||||
, pClient->system.network_traffic_in, pClient->system.network_traffic_out
|
||||
, pClient->system.tcp_80_establish, pClient->system.tcp_80, pClient->system.tcp_total
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sleep( iRefreshTime );
|
||||
}
|
||||
|
||||
|
||||
g_pShmCtl = NULL;
|
||||
shmCtl.Detach();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ProgramExit( int iSigno )
|
||||
{
|
||||
if( g_pShmCtl != NULL )
|
||||
{
|
||||
g_pShmCtl->Detach();
|
||||
g_pShmCtl = NULL;
|
||||
}
|
||||
|
||||
fprintf( stderr, "\nrc monitoring end by user... goog bye ^^...\n\n" );
|
||||
|
||||
signal( SIGINT, SIG_DFL );
|
||||
exit( 0 );
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/****************************************************************************
|
||||
rc_mond shared momory monitoring tool
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/13
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SHM_MONITOR_H__
|
||||
#define __SHM_MONITOR_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// 사용 방법을 화면에 표시하기 위한 함수.
|
||||
void PrintUsage( void );
|
||||
|
||||
// Version 정보를 화면에 표시하기 위한 함수
|
||||
void PrintVersion( void );
|
||||
|
||||
|
||||
void ProgramExit( int iSigno );
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __SHM_MONITOR_H__ */
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
#include "SocketCsagentd.h"
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// 생성자
|
||||
// param [in] clientSocket client 와 통신 연결된 socket.
|
||||
// param [in] szRcid RC ID 정보.
|
||||
CSocketCsagentd::CSocketCsagentd( int clientSocket, const char * szRcid )
|
||||
: CBaseSocket( clientSocket )
|
||||
, m_iPacketHeaderLen( sizeof( m_packetHeader ) )
|
||||
, m_uPacketDataLen( 0 )
|
||||
{
|
||||
m_strRcId = szRcid;
|
||||
}
|
||||
|
||||
// 소멸자.
|
||||
CSocketCsagentd::~CSocketCsagentd()
|
||||
{
|
||||
// 소멸자 Socket 명시적 Close 처리.
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
// 수신된 Data 를 전달받은 인자에 설정하여 반환 처리.
|
||||
// param [out] strHostname 장비의 hostname 정보.
|
||||
// param [out] pData 수신된 data
|
||||
// param [in] timeout 대기 timeout (sec)
|
||||
// return -1 : Socket 오류 또는 잘못된 Data 수신시 ( RC ID 가 다른 경우 포함)
|
||||
// 0 : timeout 발생시
|
||||
// 1 : 정상
|
||||
int CSocketCsagentd::GetSystemInfo( std::string & strHostname, struct SystemInfo * pData, int timeout )
|
||||
{
|
||||
// Header 정보를 수신
|
||||
int nResult = GetPacketHeader( timeout );
|
||||
|
||||
if( nResult == -1 )
|
||||
{
|
||||
// Socket 끊김 또는 정의되지 않은 Data 수신시.
|
||||
return -1;
|
||||
}
|
||||
else if( nResult == 0 )
|
||||
{
|
||||
// timeout 발생시
|
||||
return 0;
|
||||
}
|
||||
|
||||
//_LOG( LDBG, "system info packet header OK. body size[%u]", m_uPacketDataLen );
|
||||
|
||||
|
||||
// Header Data 정상 수신시...
|
||||
// - command code 정보 확인
|
||||
if( m_packetHeader.command[0] != COMMAND_TRANSFER_SYSTEM )
|
||||
{
|
||||
// 미정의된 command code 인 경우
|
||||
LOG( LERR, "Not defined command code." );
|
||||
PrintHeaderToLog();
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// system 상태 정보를 수신한 경우....
|
||||
// - 수신된 protocol_version 정보를 확인하여 파싱 가능한지 검사.
|
||||
if( m_packetHeader.protocol_version > PARSE_MAX_PROTOCOL_VERSION_SYSTEM )
|
||||
{
|
||||
// 파싱 불가능한 통신 규격인 경우.....
|
||||
LOG( LERR, "Not support protocol version. [COMMAND_TRANSFER_SYSTEM] support[%02x] request[%02x]."
|
||||
, PARSE_MAX_PROTOCOL_VERSION_SYSTEM, m_packetHeader.protocol_version );
|
||||
|
||||
PrintHeaderToLog();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Data 부분 수신 처리.
|
||||
if( GetPacketBodySystem( strHostname, pData ) == false )
|
||||
{
|
||||
// body 수신 처리시 오류 발생
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 수신된 Data 를 전달받은 인자에 설정하여 반환 처리.
|
||||
// param [out] strHostname 장비의 hostname 정보.
|
||||
// param [out] iServiceStat 수신된 data
|
||||
// param [out] iStorageMaxUsage 수신된 data
|
||||
// param [in] timeout 대기 timeout (sec)
|
||||
// return -1 : Socket 오류 또는 잘못된 Data 수신시 ( RC ID 가 다른 경우 포함)
|
||||
// 0 : timeout 발생시
|
||||
// 1 : 정상
|
||||
int CSocketCsagentd::GetServiceInfo( std::string & strHostname, int & iServiceStat, int & iStorageMaxUsage, int timeout )
|
||||
{
|
||||
// Header 정보를 수신
|
||||
int nResult = GetPacketHeader( timeout );
|
||||
|
||||
if( nResult == -1 )
|
||||
{
|
||||
// Socket 끊김 또는 정의되지 않은 Data 수신시.
|
||||
return -1;
|
||||
}
|
||||
else if( nResult == 0 )
|
||||
{
|
||||
// timeout 발생시
|
||||
return 0;
|
||||
}
|
||||
|
||||
//_LOG( LDBG, "check info packet header OK. body size[%u]", m_uPacketDataLen );
|
||||
|
||||
|
||||
// Header Data 정상 수신시...
|
||||
// - command code 정보 확인
|
||||
if( m_packetHeader.command[0] != COMMAND_TRANSFER_SERVICE )
|
||||
{
|
||||
// 미정의된 command code 인 경우
|
||||
LOG( LERR, "Not defined command code." );
|
||||
PrintHeaderToLog();
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// system 상태 정보를 수신한 경우....
|
||||
// - 수신된 protocol_version 정보를 확인하여 파싱 가능한지 검사.
|
||||
if( m_packetHeader.protocol_version > PARSE_MAX_PROTOCOL_VERSION_SERVICE )
|
||||
{
|
||||
// 파싱 불가능한 통신 규격인 경우.....
|
||||
LOG( LERR, "Not support protocol version. [COMMAND_TRANSFER_SERVICE] support[%02x] request[%02x]."
|
||||
, PARSE_MAX_PROTOCOL_VERSION_SERVICE, m_packetHeader.protocol_version );
|
||||
|
||||
PrintHeaderToLog();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Data 부분 수신 처리.
|
||||
if( GetPacketBodyService( strHostname, iServiceStat, iStorageMaxUsage ) == false )
|
||||
{
|
||||
// body 수신 처리시 오류 발생
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Packet Header 정보를 Log 파일에 Logging 처리 ( Debug 처리를 위한 함수)
|
||||
void CSocketCsagentd::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_uPacketDataLen );
|
||||
_LOG( LINF, "protocol_version [%02x]", m_packetHeader.protocol_version );
|
||||
_LOG( LINF, "extend_code [%02x]", m_packetHeader.extend_code);
|
||||
_LOG( LINF, "------------------------------------" );
|
||||
}
|
||||
|
||||
|
||||
// Packet Header 부분의 수신 처리를 위한 함수
|
||||
// param timeout [in] 대기시간.
|
||||
// retrun 0 : timeout
|
||||
// 1 : 성공
|
||||
// -1 : socket 오류 또는 정의된 Data 가 아닌 경우.
|
||||
int CSocketCsagentd::GetPacketHeader( int timeout )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return -1;
|
||||
|
||||
// Socket 으로 부터 Packet Header 부분 수신.
|
||||
// 수신된 정보는 멤버변수에 저장처리.
|
||||
/// read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
|
||||
int nRead = ReadNTimeout( &m_packetHeader, m_iPacketHeaderLen, timeout );
|
||||
if( nRead == -2 )
|
||||
{
|
||||
// timeout 발생시
|
||||
return 0;
|
||||
}
|
||||
else if( nRead <= 0 )
|
||||
{
|
||||
// timeout 을 제외한 그 밖의 오류 발생시
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상 Data 수신시.
|
||||
|
||||
// STX code 검사.
|
||||
if( m_packetHeader.stx != HEADER_STX_CODE_CSAGENTD )
|
||||
{
|
||||
LOG( LERR, "Not valid stx code." );
|
||||
PrintHeaderToLog();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Type Code 검사
|
||||
if( m_packetHeader.type != HEADER_TYPE_REQUEST )
|
||||
{
|
||||
LOG( LERR, "Not valid type code." );
|
||||
PrintHeaderToLog();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Data Length 부분 값을 멤버 변수에 저장처리.
|
||||
m_uPacketDataLen = ntohl( m_packetHeader.data_length );
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// COMMAND_TRANSFER_SYSTEM 요청 관련 Packet Body 부분을 수신 처리
|
||||
bool CSocketCsagentd::GetPacketBodySystem( std::string & strHostname, struct SystemInfo * pData )
|
||||
{
|
||||
// 현재는 protocol 버전이 0x00 1개이므로.... 본 함수에 코딩...
|
||||
// 향후 버전이 추가되면... 버전별 파싱 함수 따로 분리하는 것이 좋을 듯.
|
||||
|
||||
// protocol_version == 0x00 인 경우.
|
||||
if( m_packetHeader.protocol_version == 0x00 )
|
||||
{
|
||||
// 수신된 Body 를 저장할 변수 생성.
|
||||
struct PacketDataSystem_V00 stBody;
|
||||
|
||||
// Body 부분 수신 처리.
|
||||
int nRead = ReadNTimeout( &stBody, m_uPacketDataLen, 15 );
|
||||
if( nRead == -2 )
|
||||
{
|
||||
// timeout 발생시
|
||||
// - 지정된 시간 동안 Header 에 기록된 Body 크기를 읽지 못했으므로. 오류로 처리
|
||||
LOG( LERR, "system info body[%u] read timeout.", m_uPacketDataLen );
|
||||
return false;
|
||||
}
|
||||
else if( nRead <= 0 )
|
||||
{
|
||||
// timeout 을 제외한 그 밖의 오류 발생시
|
||||
LOG( LERR, "system info body read error[%d]", nRead );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Body 부분 정상 수신시...
|
||||
// 1. RC ID 정보 비교 후. (대소문자 무시)
|
||||
// 2. 정상인 경우..수신된 Data 를 파싱하여 인자로 전달받은 data 에 저장 처리.
|
||||
if( strcasecmp( m_strRcId.c_str(), stBody.rcid ) != 0 )
|
||||
{
|
||||
LOG( LERR, "system info body error. RC ID[%s] not match. request[%s]"
|
||||
, m_strRcId.c_str(), stBody.rcid );
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x00 버전에 대한 data 파싱.
|
||||
strHostname = stBody.hostname;
|
||||
|
||||
pData->load_avg[0] = stBody.load_avg[0];
|
||||
pData->load_avg[1] = stBody.load_avg[1];
|
||||
pData->load_avg[2] = stBody.load_avg[2];
|
||||
|
||||
pData->memory_total = stBody.memory_total;
|
||||
pData->memory_free = stBody.memory_free;
|
||||
pData->memory_usage = stBody.memory_usage;
|
||||
|
||||
pData->swap_total = stBody.swap_total;
|
||||
pData->swap_used = stBody.swap_used;
|
||||
pData->swap_usage = stBody.swap_usage;
|
||||
|
||||
pData->storage_total = stBody.storage_total;
|
||||
pData->storage_avail = stBody.storage_avail;
|
||||
pData->storage_max_usage = stBody.storage_max_usage;
|
||||
|
||||
pData->disk_max_queue = stBody.disk_max_queue;
|
||||
pData->disk_max_busy = stBody.disk_max_busy;
|
||||
|
||||
pData->network_packet_in = stBody.network_packet_in;
|
||||
pData->network_packet_out = stBody.network_packet_out;
|
||||
pData->network_traffic_in = stBody.network_traffic_in;
|
||||
pData->network_traffic_out = stBody.network_traffic_out;
|
||||
|
||||
pData->tcp_total = stBody.tcp_total;
|
||||
pData->tcp_80 = stBody.tcp_80;
|
||||
pData->tcp_80_establish = stBody.tcp_80_establish;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// COMMAND_TRANSFER_SERVICE 요청 관련 Packet Body 부분을 수신 처리
|
||||
bool CSocketCsagentd::GetPacketBodyService( std::string & strHostname, int & iServiceStat, int & iStorageMaxUsage )
|
||||
{
|
||||
// 현재는 protocol 버전이 0x00 1개이므로.... 본 함수에 코딩...
|
||||
// 향후 버전이 추가되면... 버전별 파싱 함수 따로 분리하는 것이 좋을 듯.
|
||||
|
||||
// protocol_version == 0x00 인 경우.
|
||||
if( m_packetHeader.protocol_version == 0x00 )
|
||||
{
|
||||
// 수신된 Body 를 저장할 변수 생성.
|
||||
struct PacketDataService_V00 stBody;
|
||||
|
||||
// Body 부분 수신 처리.
|
||||
int nRead = ReadNTimeout( &stBody, m_uPacketDataLen, 15 );
|
||||
if( nRead == -2 )
|
||||
{
|
||||
// timeout 발생시
|
||||
// - 지정된 시간 동안 Header 에 기록된 Body 크기를 읽지 못했으므로. 오류로 처리
|
||||
LOG( LERR, "service info body[%u] read timeout.", m_uPacketDataLen );
|
||||
return false;
|
||||
}
|
||||
else if( nRead <= 0 )
|
||||
{
|
||||
// timeout 을 제외한 그 밖의 오류 발생시
|
||||
LOG( LERR, "service info body read error[%d]", nRead );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Body 부분 정상 수신시...
|
||||
// 1. RC ID 정보 비교 후. (대소문자 무시)
|
||||
// 2. 정상인 경우..수신된 Data 를 파싱하여 인자로 전달받은 data 에 저장 처리.
|
||||
if( strcasecmp( m_strRcId.c_str(), stBody.rcid ) != 0 )
|
||||
{
|
||||
LOG( LERR, "service info body error. RC ID[%s] not match. request[%s]"
|
||||
, m_strRcId.c_str(), stBody.rcid );
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x00 버전에 대한 data 파싱.
|
||||
strHostname = stBody.hostname;
|
||||
|
||||
iServiceStat = stBody.service_stat;
|
||||
iStorageMaxUsage = stBody.storage_max_usage;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/****************************************************************************
|
||||
csagentd socket class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SOCKET_CSAGENTD_H__
|
||||
#define __SOCKET_CSAGENTD_H__
|
||||
|
||||
#include "BaseSocket.h"
|
||||
#include "ShmDefine.h"
|
||||
#include "ProtocolCsagentd.h"
|
||||
|
||||
|
||||
// CSocketCsagentd
|
||||
// FHS csagentd 와의 TCP socket 통신을 관리하고... Data 수신 처리를 담당하는 class
|
||||
class CSocketCsagentd: public CBaseSocket
|
||||
{
|
||||
public:
|
||||
|
||||
// 생성자
|
||||
// param [in] clientSocket client 와 통신 연결된 socket.
|
||||
// param [in] szRcid RC ID 정보.
|
||||
CSocketCsagentd( int clientSocket, const char * szRcid );
|
||||
|
||||
// 소멸자
|
||||
~CSocketCsagentd();
|
||||
|
||||
|
||||
// 수신된 Data 를 전달받은 인자에 설정하여 반환 처리.
|
||||
// param [out] strHostname 장비의 hostname 정보.
|
||||
// param [out] pData 수신된 data
|
||||
// param [in] timeout 대기 timeout (sec)
|
||||
// return -1 : Socket 오류 또는 잘못된 Data 수신시 ( RC ID 가 다른 경우 포함)
|
||||
// 0 : timeout 발생시
|
||||
// 1 : 정상
|
||||
int GetSystemInfo( std::string & strHostname, struct SystemInfo * pData, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
|
||||
|
||||
// 수신된 Data 를 전달받은 인자에 설정하여 반환 처리.
|
||||
// param [out] strHostname 장비의 hostname 정보.
|
||||
// param [out] iServiceStat 수신된 data
|
||||
// param [out] iStorageMaxUsage 수신된 data
|
||||
// param [in] timeout 대기 timeout (sec)
|
||||
// return -1 : Socket 오류 또는 잘못된 Data 수신시 ( RC ID 가 다른 경우 포함)
|
||||
// 0 : timeout 발생시
|
||||
// 1 : 정상
|
||||
int GetServiceInfo( std::string & strHostname, int & iServiceStat, int & iStorageMaxUsage, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Packet Header 변수
|
||||
struct PacketHeaderCsagentd m_packetHeader;
|
||||
|
||||
// m_packetHeader 구조체의 크기를 저장하기 위한 상수
|
||||
const int m_iPacketHeaderLen;
|
||||
|
||||
// Packet Header 에 저장된 Data 부분의 길이 정보값.
|
||||
unsigned int m_uPacketDataLen;
|
||||
|
||||
// Packet Data 의 유효성을 검증할 RC ID 정보
|
||||
// - 생성자를 통해 전달받음.
|
||||
std::string m_strRcId;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Packet Header 정보를 Log 파일에 Logging 처리 ( Debug 처리를 위한 함수)
|
||||
void PrintHeaderToLog( void );
|
||||
|
||||
// Packet Header 부분의 수신 처리를 위한 함수
|
||||
// param timeout [in] 대기시간.
|
||||
// retrun 0 : timeout
|
||||
// 1 : 성공
|
||||
// -1 : socket 오류 또는 정의된 Data 가 아닌 경우.
|
||||
int GetPacketHeader( int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
|
||||
|
||||
// COMMAND_TRANSFER_SYSTEM 요청 관련 Packet Body 부분을 수신 처리
|
||||
bool GetPacketBodySystem( std::string & strHostname, struct SystemInfo * pData );
|
||||
|
||||
// COMMAND_TRANSFER_SERVICE 요청 관련 Packet Body 부분을 수신 처리
|
||||
bool GetPacketBodyService( std::string & strHostname, int & iServiceStat, int & iStorageMaxUsage );
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* __SOCKET_CSAGENTD_H__ */
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "SocketGms.h"
|
||||
#include "Logger.h"
|
||||
#include "ProcessConfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
CSocketGms::CSocketGms()
|
||||
: CBaseSocket( SOCKET_NOT_VALID )
|
||||
{
|
||||
// GMS 서버 정보 설정.
|
||||
m_strGmsServer = CProcessConfig::GetInstance()->GetGmsServer();
|
||||
m_nGmsPort = CProcessConfig::GetInstance()->GetGmsPortStat();
|
||||
|
||||
// 전송할 Message Header 정보 중 공통 부분 초기화.
|
||||
// 전송할 Header 초기화..
|
||||
memset( &m_stHeader, 0, sizeof( struct PacketHeaderGms ) );
|
||||
|
||||
// 전송 Header 조립..
|
||||
// szTransactionID 정보는 거의 사용하지 않으므로 빈값으로 전송한다.
|
||||
|
||||
// ulmode 는 GMS_MSG_MODE_VRCD_STATUSD_RTS_STATUS (0x0a01) 을 Network Byte order 로 변환하여 전송.
|
||||
m_stHeader.ulMode = htonl( GMS_MSG_MODE_VRCD_STATUSD_RTS_STATUS );
|
||||
|
||||
// szIssuer 값은 프로그램 명을 입력 처리.
|
||||
sprintf(m_stHeader.szIssuer, "%s", PROG_NAME );
|
||||
|
||||
// szServiceID 값은 사용하지 않음.
|
||||
|
||||
// ulResult 값은 GMS_OK_ALL_PASSED (0x1000) 을 Network Byte Order 로 변환하여 전송.
|
||||
m_stHeader.ulResult = htonl( GMS_OK_ALL_PASSED );
|
||||
}
|
||||
|
||||
|
||||
CSocketGms::~CSocketGms()
|
||||
{
|
||||
// 소멸자 Socket 명시적 Close 처리.
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
bool CSocketGms::SendData( unsigned int nCount, char * szBuffer, unsigned int nBufferSize )
|
||||
{
|
||||
// messae header 상의 ulBodyLength 는 FHS 갯수(int) 부분관 전송될 Body 부분 합 Size 임 ( Network Byte Order )
|
||||
m_stHeader.ulBodyLength = htonl( sizeof(int) + nBufferSize );
|
||||
|
||||
//_LOG( LDBG, "GmsSendSocket: GMS send header size..[%u], count[%u], buffersize[%u] body length[%u]"
|
||||
// , sizeof(struct gms_message_header), nCount, nBufferSize, sizeof(int) + nBufferSize );
|
||||
|
||||
// GMS 장비와 TCP 연결.
|
||||
if( Connect( m_strGmsServer, m_nGmsPort ) == false )
|
||||
{
|
||||
LOG( LERR, "CSocketGms: GMS connect fail.[%s][%d]", m_strGmsServer.c_str(), m_nGmsPort );
|
||||
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Message Header 부분을 전송...
|
||||
if( WriteN( &m_stHeader, sizeof( struct PacketHeaderGms ) ) != sizeof( struct PacketHeaderGms ) )
|
||||
{
|
||||
LOG( LERR, "CSocketGms: GMS message header send fail." );
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Message Body 부분 중.. 장비 수 부분을 전송한다.
|
||||
if( WriteN( &nCount, sizeof( int )) != sizeof(int) )
|
||||
{
|
||||
LOG( LERR, "CSocketGms: GMS message body count_info[%u] send fail.", nCount );
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Message Body 부분 전송.. (존재하는 경우만 )
|
||||
if( nBufferSize > 0 )
|
||||
{
|
||||
if( WriteN( szBuffer, nBufferSize) != nBufferSize )
|
||||
{
|
||||
LOG( LERR, "CSocketGms: GMS message body[%u] send fail.", nBufferSize );
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_LOG( LINF, "CSocketGms: FHS info[count: %u] send to GMS OK..GMS[%s] port[%d]", nCount, m_strGmsServer.c_str(), m_nGmsPort );
|
||||
|
||||
// 전송 완료 후 Connection 을 종료 처리한다. (기존 rc_vrcd 소스 확인시 전송시에만 접속 후 세션 종료 처리함 )
|
||||
Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/****************************************************************************
|
||||
Send data to GMS using tcp connection.
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/27
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SOCKET_GMS_H__
|
||||
#define __SOCKET_GMS_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "BaseSocket.h"
|
||||
#include "ProtocolGms.h"
|
||||
|
||||
|
||||
/// @brief CSocketGms
|
||||
/// 본 클래스는 GMS 와 TCP 연결을 수행한 후...
|
||||
/// 전달받은 정보를 GMS 로 통신 Protocol 에 맞도록 전송 처리하는 역활을 수행한다.
|
||||
class CSocketGms : public CBaseSocket
|
||||
{
|
||||
public:
|
||||
|
||||
CSocketGms();
|
||||
|
||||
~CSocketGms();
|
||||
|
||||
|
||||
bool SendData( unsigned int nCount, char * szBuffer, unsigned int nBufferSize );
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// GMS Server 정보.
|
||||
std::string m_strGmsServer;
|
||||
int m_nGmsPort;
|
||||
|
||||
// GMS 로 Data 전송시 사용할 Message Header 관련 멤버변수.
|
||||
struct PacketHeaderGms m_stHeader;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* __SOCKET_GMS_H__ */
|
||||
@@ -0,0 +1,365 @@
|
||||
#include "SocketSendInfo.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "ProcessConfig.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
|
||||
// 생성자
|
||||
// param [in] clientSocket client 와 통신 연결된 socket.
|
||||
|
||||
CSocketSendInfo::CSocketSendInfo( int clientSocket )
|
||||
: CBaseSocket( clientSocket )
|
||||
, m_iPacketHeaderLen( sizeof( m_packetHeader ) )
|
||||
, m_uPacketDataLen( 0 )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// 소멸자.
|
||||
CSocketSendInfo::~CSocketSendInfo()
|
||||
{
|
||||
// 소멸자 Socket 명시적 Close 처리.
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
// Packet Header 부분의 수신 처리를 위한 함수
|
||||
// param command [out] 수신된 command code
|
||||
// param timeout [in] 대기시간.
|
||||
// retrun 0 : timeout
|
||||
// 1 : 성공
|
||||
// -1 : socket 오류 또는 정의된 Data 가 아닌 경우.
|
||||
int CSocketSendInfo::GetPacketHeader( char & command, int timeout )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return -1;
|
||||
|
||||
// Socket 으로 부터 Packet Header 부분 수신.
|
||||
// 수신된 정보는 멤버변수에 저장처리.
|
||||
/// read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
|
||||
int nRead = ReadNTimeout( &m_packetHeader, m_iPacketHeaderLen, timeout );
|
||||
if( nRead == -2 )
|
||||
{
|
||||
// timeout 발생시
|
||||
return 0;
|
||||
}
|
||||
else if( nRead <= 0 )
|
||||
{
|
||||
// timeout 을 제외한 그 밖의 오류 발생시
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상 Data 수신시.
|
||||
|
||||
// STX code 검사.
|
||||
if( m_packetHeader.stx != HEADER_STX_CODE_SEND_INFO )
|
||||
{
|
||||
LOG( LERR, "Not valid stx code." );
|
||||
PrintHeaderToLog();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Type Code 검사
|
||||
if( m_packetHeader.type != HEADER_TYPE_REQUEST )
|
||||
{
|
||||
LOG( LERR, "Not valid type code." );
|
||||
PrintHeaderToLog();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Data Length 부분 값을 멤버 변수에 저장처리.
|
||||
m_uPacketDataLen = ntohl( m_packetHeader.data_length );
|
||||
|
||||
// command code 정보를 출력 param 에 저장 처리.
|
||||
// 통신 정의상 1th 항목만 사용.
|
||||
command = m_packetHeader.command[1];
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Packet Header 정보를 Log 파일에 Logging 처리 ( Debug 처리를 위한 함수)
|
||||
void CSocketSendInfo::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_uPacketDataLen );
|
||||
_LOG( LINF, "protocol_version [%02x]", m_packetHeader.protocol_version );
|
||||
_LOG( LINF, "extend_code [%02x]", m_packetHeader.extend_code );
|
||||
_LOG( LINF, "------------------------------------" );
|
||||
}
|
||||
|
||||
// COMMAND_ALIVE_FHS 요청에 대한 Body 수신 처리.
|
||||
// - protocol version 에 따른 처리 필요.
|
||||
// param strHostname [out] 수신된 hostname 정보.
|
||||
// return false socket 오류, 해당 protocol version 미지원, RC ID 불일치 등 비정상 상황.
|
||||
// 그외 true
|
||||
bool CSocketSendInfo::GetPacketBodyAliveFhs( std::string & strHostname )
|
||||
{
|
||||
// 지원 가능한 protocol version 인지 검사.
|
||||
if( m_packetHeader.protocol_version > PARSE_MAX_PROTOCOL_VERSION_ALIVE_FHS )
|
||||
{
|
||||
// 파싱 불가능한 버전인 경우...
|
||||
LOG( LERR, "Not support protocol version. [COMMAND_ALIVE_FHS] support[%02x] request[%02x]."
|
||||
, PARSE_MAX_PROTOCOL_VERSION_ALIVE_FHS, m_packetHeader.protocol_version );
|
||||
|
||||
PrintHeaderToLog();
|
||||
|
||||
std::string strErrorMessage = "Not support request protocol version.";
|
||||
SendResultAliveFhsError( strErrorMessage );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// protocol version 별 파싱 처리.
|
||||
if( m_packetHeader.protocol_version == 0x00 )
|
||||
{
|
||||
// 0x00 버전 지원.
|
||||
struct PacketDataRequestAliveFhs_V00 stBody;
|
||||
memset( &stBody, 0x00, sizeof( struct PacketDataRequestAliveFhs_V00 ) );
|
||||
|
||||
// Body 부분 크기가.. 수신 처리할 구조체 크기와 동일한지 체크...
|
||||
// - 안 할 경우.... body 크기가 저장 구조체 크기보다 큰 경우..
|
||||
// - 본 모듈이 memory overflow 로 죽으므로... 방어코드 적용.
|
||||
if( m_uPacketDataLen != sizeof( stBody ) )
|
||||
{
|
||||
LOG( LERR, "Invalid body size. [COMMAND_ALIVE_FHS] version[%02x] define[%zu] request_size[%u]"
|
||||
, m_packetHeader.protocol_version, sizeof( stBody ) , m_uPacketDataLen);
|
||||
|
||||
PrintHeaderToLog();
|
||||
|
||||
std::string strErrorMessage = "Not match request(alive fhs) protocol body size.";
|
||||
SendResultAliveFhsError( strErrorMessage );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Body 부분 수신 처리.
|
||||
int nRead = ReadNTimeout( &stBody, m_uPacketDataLen, 5 );
|
||||
if( nRead == -2 )
|
||||
{
|
||||
// timeout 발생시
|
||||
// - 지정된 시간 동안 Header 에 기록된 Body 크기를 읽지 못했으므로. 오류로 처리
|
||||
LOG( LERR, "alive fhs request body[%u] read timeout.", m_uPacketDataLen );
|
||||
return false;
|
||||
}
|
||||
else if( nRead <= 0 )
|
||||
{
|
||||
// timeout 을 제외한 그 밖의 오류 발생시
|
||||
LOG( LERR, "alive fhs request body read error[%d]", nRead );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Body 부분 정상 수신시...
|
||||
// 1. RC ID 정보 비교 후. (대소문자 무시)
|
||||
// 2. 정상인 경우..수신된 Data 를 파싱하여 인자로 전달받은 data 에 저장 처리.
|
||||
if( strcasecmp( CProcessConfig::GetInstance()->GetRcId(), stBody.rcid ) != 0 )
|
||||
{
|
||||
LOG( LERR, "alive fhs body error. RC ID not match. request [%s][%s]", stBody.rcid, stBody.hostname );
|
||||
|
||||
std::string strErrorMessage = "RC ID not match.";
|
||||
SendResultAliveFhsError( strErrorMessage );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 정상인 경우...
|
||||
strHostname = stBody.hostname;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 해당 버전에 대한 파싱 코드가 아직 없는 경우...
|
||||
LOG( LERR, "Not support protocol version parsing. [COMMAND_ALIVE_FHS] request[%02x].", m_packetHeader.protocol_version );
|
||||
|
||||
std::string strErrorMessage = "Not support request protocol version parsing.";
|
||||
SendResultAliveFhsError( strErrorMessage );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// COMMAND_ALIVE_FHS 요청 관련 error message 전송
|
||||
bool CSocketSendInfo::SendResultAliveFhsError( std::string & strMessage )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return false;
|
||||
|
||||
// 정보 전달을 위한 Packet Header 생성
|
||||
struct PacketHeaderSendInfo stHeader;
|
||||
memset( &stHeader, 0x00, sizeof( struct PacketHeaderSendInfo ) );
|
||||
|
||||
stHeader.stx = HEADER_STX_CODE_SEND_INFO;
|
||||
stHeader.type = HEADER_TYPE_RESPONSE;
|
||||
stHeader.command[1] = COMMAND_ALIVE_FHS;
|
||||
stHeader.result[3] = RESULT_ALIVE_FHS_ERROR;
|
||||
|
||||
// Data body length
|
||||
stHeader.data_length = htonl( strMessage.size() );
|
||||
|
||||
// Protocol version
|
||||
// - 수신된 protocol version 과 같도록
|
||||
stHeader.protocol_version = m_packetHeader.protocol_version;
|
||||
|
||||
// Packet Header 정보 전송
|
||||
if( WriteN( &stHeader, m_iPacketHeaderLen ) != m_iPacketHeaderLen )
|
||||
{
|
||||
LOG( LERR, "[COMMAND_ALIVE_FHS] error result send fail" );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// message 부분이 존재하는 경우.. 전송 처리.
|
||||
if( strMessage.empty() == false )
|
||||
{
|
||||
WriteN( strMessage.c_str(), strMessage.size() );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// COMMAND_ALIVE_FHS 요청 관련 SKIP result 전송
|
||||
bool CSocketSendInfo::SendResultAliveFhsSkip()
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return false;
|
||||
|
||||
// 정보 전달을 위한 Packet Header 생성
|
||||
struct PacketHeaderSendInfo stHeader;
|
||||
memset( &stHeader, 0x00, sizeof( struct PacketHeaderSendInfo ) );
|
||||
|
||||
stHeader.stx = HEADER_STX_CODE_SEND_INFO;
|
||||
stHeader.type = HEADER_TYPE_RESPONSE;
|
||||
stHeader.command[1] = COMMAND_ALIVE_FHS;
|
||||
stHeader.result[3] = RESULT_ALIVE_FHS_SKIP;
|
||||
|
||||
// Data body length
|
||||
stHeader.data_length = htonl( 0 );
|
||||
|
||||
// Protocol version
|
||||
// - 수신된 protocol version 과 같도록
|
||||
stHeader.protocol_version = m_packetHeader.protocol_version;
|
||||
|
||||
// Packet Header 정보 전송
|
||||
if( WriteN( &stHeader, m_iPacketHeaderLen ) != m_iPacketHeaderLen )
|
||||
{
|
||||
LOG( LERR, "[COMMAND_ALIVE_FHS] skip result send fail" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// 전송할 Body 는 없으므로.. pass.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// COMMAND_ALIVE_FHS 요청 관련 Alive FHS 목록 전송
|
||||
bool CSocketSendInfo::SendResultAliveFhs( std::vector< struct FhsServiceStatInfo > & vecAliveFhs )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return false;
|
||||
|
||||
// 정보 전달을 위한 Packet Header 생성
|
||||
struct PacketHeaderSendInfo stHeader;
|
||||
memset( &stHeader, 0x00, sizeof( struct PacketHeaderSendInfo ) );
|
||||
|
||||
stHeader.stx = HEADER_STX_CODE_SEND_INFO;
|
||||
stHeader.type = HEADER_TYPE_RESPONSE;
|
||||
stHeader.command[1] = COMMAND_ALIVE_FHS;
|
||||
stHeader.result[3] = RESULT_ALIVE_FHS_OK;
|
||||
|
||||
// Protocol version
|
||||
// - 수신된 protocol version 과 같도록
|
||||
stHeader.protocol_version = m_packetHeader.protocol_version;
|
||||
|
||||
// protocol vesion 에 따른 body 부분 처리
|
||||
if( m_packetHeader.protocol_version == 0x00 )
|
||||
{
|
||||
// 전달받은 결과 목록을 result 전송 형식에 맞도록 data 조립
|
||||
// - 0x00 버전에서는 data 구조가 동일하므로.. 그냥 전송 처리해도 되지만...
|
||||
// - 향후 버전 확장을 대비하여... data 조립하도록 코딩 처리함.
|
||||
|
||||
std::vector< struct PacketDataResponseAliveFhs_V00 > vecResponse;
|
||||
struct PacketDataResponseAliveFhs_V00 fhs;
|
||||
std::vector< struct FhsServiceStatInfo >::iterator it;
|
||||
|
||||
vecResponse.clear();
|
||||
|
||||
// 전달받은 Alive FHS 정보를 전송하기 위한 vector 에 저장 처리한다.
|
||||
// - 향후 통신 프로토콜 변경 대비 변환 처리 수행함.
|
||||
for( it = vecAliveFhs.begin(); it != vecAliveFhs.end(); ++it )
|
||||
{
|
||||
// hostname 정보 복사.
|
||||
strncpy( fhs.hostname, it->hostname, FIMNGD_HOST_NAME_MAX_LENGTH );
|
||||
|
||||
// 서비스 상태 정보 code
|
||||
fhs.service_stat = it->service_stat;
|
||||
|
||||
vecResponse.push_back( fhs );
|
||||
}
|
||||
|
||||
// Data 전송을 위한 Size 계산 및 Body 항목 조립
|
||||
|
||||
// 1. 목록 크기 계산.
|
||||
unsigned int nListSize = sizeof( struct PacketDataResponseAliveFhs_V00 ) * vecResponse.size();
|
||||
|
||||
// 2. Data body length 설정.
|
||||
unsigned int nTemp = 4 + nListSize; // count (int 4Byte) + PacketDataResponseAliveFhs_V00 list
|
||||
stHeader.data_length = htonl( nTemp );
|
||||
|
||||
// 3. body 정보 중 FHS count 정보는 network byte order 변환 후 전송 ( 전송 규약)
|
||||
nTemp = htonl( vecResponse.size() );
|
||||
|
||||
// Packet Header 정보 전송
|
||||
if( WriteN( &stHeader, m_iPacketHeaderLen ) != m_iPacketHeaderLen )
|
||||
{
|
||||
LOG( LERR, "[COMMAND_ALIVE_FHS] result header send fail." );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Body 부분 전송 처리.
|
||||
|
||||
// 1. FHS Count ( Network byte order )
|
||||
WriteN( &nTemp, 4 );
|
||||
|
||||
// 2. Alive FHS 목록 정보.
|
||||
if( vecResponse.empty() == false )
|
||||
{
|
||||
if( WriteN( &( vecResponse[0] ), nListSize ) != nListSize )
|
||||
{
|
||||
LOG( LERR, "[COMMAND_ALIVE_FHS] result body send fail. count[%zu] size[%u]", vecResponse.size(), nListSize );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 전송 protocol 규약을 지원하지 못하는 경우....
|
||||
LOG( LERR, "Not support protocol version to send resutl [COMMAND_ALIVE_FHS]. request[%02x].", m_packetHeader.protocol_version );
|
||||
|
||||
std::string strErrorMessage = "Not support request protocol version.";
|
||||
SendResultAliveFhsError( strErrorMessage );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/****************************************************************************
|
||||
SendInfo Worker 에서 data 송수신을 담당할 socket class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/16
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SOCKET_SEND_INFO_H__
|
||||
#define __SOCKET_SEND_INFO_H__
|
||||
|
||||
#include "BaseSocket.h"
|
||||
#include "ProtocolSendInfo.h"
|
||||
#include "ShmManager.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
// CSocketSendInfo
|
||||
// Worker SendInfo 에서 TCP 통신 및 data 송수신을 담당할 class.
|
||||
class CSocketSendInfo: public CBaseSocket
|
||||
{
|
||||
public:
|
||||
|
||||
// 생성자
|
||||
// param [in] clientSocket client 와 통신 연결된 socket.
|
||||
CSocketSendInfo( int clientSocket );
|
||||
|
||||
// 소멸자
|
||||
~CSocketSendInfo();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Packet Header 변수
|
||||
struct PacketHeaderSendInfo m_packetHeader;
|
||||
|
||||
// m_packetHeader 구조체의 크기를 저장하기 위한 상수
|
||||
const int m_iPacketHeaderLen;
|
||||
|
||||
// Packet Header 에 저장된 Data 부분의 길이 정보값.
|
||||
unsigned int m_uPacketDataLen;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Packet Header 부분의 수신 처리를 위한 함수
|
||||
// param command [out] 수신된 command code
|
||||
// param timeout [in] 대기시간.
|
||||
// retrun 0 : timeout
|
||||
// 1 : 성공
|
||||
// -1 : socket 오류 또는 정의된 Data 가 아닌 경우.
|
||||
int GetPacketHeader( char & command, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
|
||||
|
||||
// Packet Header 정보를 Log 파일에 Logging 처리 ( Debug 처리를 위한 함수)
|
||||
void PrintHeaderToLog( void );
|
||||
|
||||
// COMMAND_ALIVE_FHS 요청에 대한 Body 수신 처리.
|
||||
// - protocol version 에 따른 처리 필요.
|
||||
// param strHostname [out] 수신된 hostname 정보.
|
||||
// return false socket 오류, 해당 protocol version 미지원, RC ID 불일치 등 비정상 상황.
|
||||
// 그외 true
|
||||
bool GetPacketBodyAliveFhs( std::string & strHostname );
|
||||
|
||||
// COMMAND_ALIVE_FHS 요청 관련 error message 전송
|
||||
bool SendResultAliveFhsError( std::string & strMessage );
|
||||
|
||||
// COMMAND_ALIVE_FHS 요청 관련 SKIP result 전송
|
||||
bool SendResultAliveFhsSkip( void );
|
||||
|
||||
// COMMAND_ALIVE_FHS 요청 관련 Alive FHS 목록 전송
|
||||
bool SendResultAliveFhs( std::vector< struct FhsServiceStatInfo > & vecAliveFhs );
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* __SOCKET_SEND_INFO_H__ */
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
#include "TopFhsUpdateThread.h"
|
||||
#include "Logger.h"
|
||||
#include "ProcessConfig.h"
|
||||
#include "ReportLog.h"
|
||||
#include "Database.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm> // vector sort 사용 목적
|
||||
|
||||
|
||||
// Top FHS 정보를 RCDB 에 업데이트 하는 주기 ( sec )
|
||||
// - 2015-07-29 현재 다른 모듈들은 30 sec 단위로 해당 정보를 조회하는 중.
|
||||
#define TOP_FHS_UPDATE_INTERVAL 28
|
||||
|
||||
// RCDB 에 저장할 Top FHS 의 최대 갯수.
|
||||
#define MAX_TOP_FHS_COUNT 8
|
||||
|
||||
|
||||
// Top FHS 추출을 위한 score 계산시... disk_max_busy 항목에 부여할 가중치 정보.
|
||||
// - 파트 협의에 따라.. storage_max_usage : disk_max_busy = 1 : 4 로 계산하여 처리하기로 함.
|
||||
#define DISK_MAX_BUSY_WEIGHT 4.0
|
||||
|
||||
|
||||
|
||||
// 생성자..
|
||||
CTopFhsUpdateThread::CTopFhsUpdateThread( CShmManager * pShmManager )
|
||||
: m_pShmManager( pShmManager)
|
||||
{
|
||||
// Thread Handle 초기화
|
||||
m_threadHandle = 0;
|
||||
}
|
||||
|
||||
// 소멸자..
|
||||
CTopFhsUpdateThread::~CTopFhsUpdateThread()
|
||||
{
|
||||
// Thread 가 동작 중인 경우 Thread 동작 정지 처리.
|
||||
if( m_threadHandle != 0 )
|
||||
pthread_cancel(m_threadHandle);
|
||||
}
|
||||
|
||||
|
||||
// Thread 를 생성하여 작업을 시작한다...
|
||||
bool CTopFhsUpdateThread::Start()
|
||||
{
|
||||
// RCDB 연결을 위한 접속 정보 load
|
||||
m_rcdbInfo.Load();
|
||||
|
||||
// 처리 Thread 생성
|
||||
int nResult = pthread_create( &m_threadHandle, NULL, CTopFhsUpdateThread::threadFunc, this );
|
||||
if( nResult != 0 )
|
||||
{
|
||||
// Thread 생성 실패시...
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "TopFhsUpdateThread: Thread create failed.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Thread 함수...
|
||||
void * CTopFhsUpdateThread::threadFunc( void * arg )
|
||||
{
|
||||
CTopFhsUpdateThread * pObject = reinterpret_cast<CTopFhsUpdateThread *>( arg );
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
// 초기 기동시...FHS 상태 정보가 아직 수집되지 않은 상태이므로...
|
||||
// 잠시 sleep 했다가.. 작업을 시작한다.
|
||||
sleep( 10 );
|
||||
|
||||
// 주기적으로 RCDB 에 업데이트 처리 수행.
|
||||
while( 1 )
|
||||
{
|
||||
pthread_testcancel();
|
||||
pObject->Execute();
|
||||
pthread_testcancel();
|
||||
|
||||
sleep( TOP_FHS_UPDATE_INTERVAL );
|
||||
}
|
||||
|
||||
// Thread 종료시 Handle 초기화
|
||||
pObject->m_threadHandle = 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool FhsScoreSort( const struct WritableFhsInfo & fhs1, const struct WritableFhsInfo & fhs2 )
|
||||
{
|
||||
return ( fhs1.score < fhs2.score );
|
||||
}
|
||||
|
||||
|
||||
// 공유메모리에 저장된 정보 중 Top FHS 정보를 추출하여 RCDB 에 저장 처리한다.
|
||||
void CTopFhsUpdateThread::Execute()
|
||||
{
|
||||
// 공유메모리로 부터 write 가능한 FHS 정보를 받아온다.
|
||||
m_vecTopFhs.clear();
|
||||
m_pShmManager->GetWritableFhsList( m_vecTopFhs, DISK_MAX_BUSY_WEIGHT );
|
||||
|
||||
// Top FHS 정보가 존재하지 않는 경우...
|
||||
if( m_vecTopFhs.empty() == true )
|
||||
{
|
||||
_LOG( LWAR, "TopFhsUpdateThread: Top FHS is empty. rcdb update skip.." );
|
||||
|
||||
|
||||
// 관련 내역을 report 로그에 기록하여 운영자가 확인할 수 있도록 처리.(#21020)
|
||||
CReportLog reportLog;
|
||||
std::string strErrorMessage;
|
||||
strErrorMessage.clear();
|
||||
|
||||
if( reportLog.Init( CProcessConfig::GetInstance()->GetLogPath() ) == false )
|
||||
{
|
||||
reportLog.GetLastError( strErrorMessage );
|
||||
LOG( LERR, "TopFhsUpdateThread: report log init failed.[%s]", strErrorMessage.c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
reportLog.Write( "WAR", "[%s] [Top FHS not exist. RCDB update skip.]", PROG_NAME );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 추출된 writable FHS 가 RCDB 에 업데이트할 MAX FHS 수 보다 많은 경우...
|
||||
if( m_vecTopFhs.size() > MAX_TOP_FHS_COUNT )
|
||||
{
|
||||
// idle 한 순으로 정렬 처리
|
||||
// - score 점수가 낮은 FHS 가 idle 한 FHS 이므로...
|
||||
// - score 점수가 낮은 순서대로 정렬 처리한다.
|
||||
std::sort( m_vecTopFhs.begin(), m_vecTopFhs.end(), FhsScoreSort );
|
||||
|
||||
// debug
|
||||
/*
|
||||
std::vector<struct WritableFhsInfo>::iterator it;
|
||||
for( it = m_vecTopFhs.begin(); it != m_vecTopFhs.end(); ++it )
|
||||
{
|
||||
_LOG( LDBG, "TopFhsUpdateThread: top fhs sort [%s] [%.1lf]" , it->hostname, it->score );
|
||||
}
|
||||
*/
|
||||
|
||||
// 정렬 작업 후... RCDB 에 업데이트 할 MAX FHS 수 만큼만 저장하도록 처리.
|
||||
m_vecTopFhs.resize( MAX_TOP_FHS_COUNT );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Top FHS 수가 RCDB 에 업데이트할 MAX FHS 수 이하인 경우...
|
||||
// - 최근 RC 운영 특성상 FHS 용량은 커지고.. FHS 수는 줄고 있는 상황.
|
||||
// - 이로 인해 실제 부하를 받는 FHS 까지 Top FHS 에 포함될 가능성이 높아짐.
|
||||
// - 따라서 이를 최소화하기 위해 다음과 같이 처리한다.
|
||||
// -- FHS 수가 MAX FHS 수의 50% 이하인 경우... 기존과 같이 그대로 업데이트 처리.
|
||||
// -- FHS 수가 MAX FHS 수의 50% 를 초과하는 경우...
|
||||
// --- idle 순서대로 정렬한 후
|
||||
// --- 초과된 FHS 의 절반만 등록...
|
||||
// ---- 5 개인 경우... MAX 50% 인 4개 기본 + 나머지 1대의 50% 인 0 개 = 최종 4대 FHS
|
||||
// ---- 6 개인 경우... MAX 50% 인 4개 기본 + 나머지 2대의 50% 인 1 개 = 최종 5대 FHS
|
||||
// ---- 7 개인 경우... MAX 50% 인 4개 기본 + 나머지 3대의 50% 인 1 개 = 최종 5대 FHS
|
||||
// ---- 8 개인 경우... MAX 50% 인 4개 기본 + 나머지 4대의 50% 인 2 개 = 최종 6대 FHS
|
||||
|
||||
// FHS 수가 MAX FHS 수의 50% 를 초과하는 경우...
|
||||
if( m_vecTopFhs.size() > MAX_TOP_FHS_COUNT / 2 )
|
||||
{
|
||||
unsigned int uSelectCount = 0;
|
||||
|
||||
// idle 한 순으로 정렬 처리
|
||||
// - score 점수가 낮은 FHS 가 idle 한 FHS 이므로...
|
||||
// - score 점수가 낮은 순서대로 정렬 처리한다.
|
||||
std::sort( m_vecTopFhs.begin(), m_vecTopFhs.end(), FhsScoreSort );
|
||||
|
||||
// MAX 값의 절반만큼 기본 등록한 후
|
||||
// 나머지 FHS 의 50% 만큼만 등록 처리.
|
||||
uSelectCount = ( MAX_TOP_FHS_COUNT / 2 ) + (( m_vecTopFhs.size() - ( MAX_TOP_FHS_COUNT / 2) ) / 2 );
|
||||
|
||||
m_vecTopFhs.resize( uSelectCount );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// RCDB 업데이트 작업 수행.
|
||||
|
||||
// RCDB 처리를 수행할 객체 생성
|
||||
// RCDB 와 연결은 필요시마다 연결 후 해제 처리한다. (세션 유지 않도록...)
|
||||
DataBase rcdb;
|
||||
|
||||
// RCDB 와 연결을 시도한다.
|
||||
if( rcdb.PgOpenDB( m_rcdbInfo.m_strRcdbIp, m_rcdbInfo.m_nRcdbPort, m_rcdbInfo.m_strRcdbName, m_rcdbInfo.m_strRcdbAcct, m_rcdbInfo.m_strRcdbAcctPw )
|
||||
== NULL )
|
||||
{
|
||||
// 연결 실패시...
|
||||
LOG( LERR, "TopFhsUpdateThread: RCDB connection failed. Top FHS update fail." );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// RCDB 연결 성공시...
|
||||
char szQuery[1024];
|
||||
int index = 0;
|
||||
std::vector<struct WritableFhsInfo>::iterator it;
|
||||
|
||||
// Top FHS 정보를 RCDB 에 업데이트 처리한다.
|
||||
for( it = m_vecTopFhs.begin(); it != m_vecTopFhs.end(); ++it )
|
||||
{
|
||||
// index 정보는 1부터 시작..
|
||||
++index;
|
||||
|
||||
// 업데이트 Query 조립.
|
||||
snprintf( szQuery, 1023,
|
||||
"UPDATE t_fhs_top_status SET fhs_hostname='%s', lastupdate=now() "
|
||||
"WHERE fhs_top = %d"
|
||||
, it->hostname, index );
|
||||
|
||||
//_LOG( LDBG, "TopFhsUpdateThread: Query[%s]", szQuery);
|
||||
|
||||
// update query 수행.
|
||||
rcdb.PgDoExec( szQuery );
|
||||
|
||||
// 적용된 Row 수가 1 row 가 아닌 경우 인서트 처리를 해야한다.
|
||||
if( rcdb.GetCmdTuples() != 1 )
|
||||
{
|
||||
_LOG( LDBG, "TopFhsUpdateThread: RCDB update nothing.... try insert [%d][%s]", index, it->hostname );
|
||||
|
||||
// 기존 Update 관련 RCDB 결과 Set 을 Clear 처리한 후
|
||||
rcdb.PgClear();
|
||||
|
||||
// RCDB update 작업이 실패한 경우.... insert 를 시도한다.
|
||||
snprintf( szQuery, 1023,
|
||||
"INSERT INTO t_fhs_top_status (fhs_top, fhs_hostname, lastupdate) "
|
||||
"VALUES ( %d, '%s', now())"
|
||||
, index, it->hostname );
|
||||
|
||||
//_LOG( LDBG, "TopFhsUpdateThread: Query[%s]", szQuery);
|
||||
|
||||
// insert query 수행.
|
||||
rcdb.PgDoExec( szQuery );
|
||||
if( rcdb.PgResult( DataBase::CLEAR ) < 0 )
|
||||
{
|
||||
// RCDB insert query 실패시...
|
||||
LOG( LERR, "TopFhsUpdateThread: RCDB insert query failed.[%s][%s]", rcdb.GetErrorMessage().c_str(), szQuery );
|
||||
|
||||
// Top FHS 업데이트 관련 작업을 우선 중지하고 다음 interval 후에 다시 시도한다.
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update 처리 정상 수행시... RCDB 결과 Set 을 Clear 처리한다.
|
||||
rcdb.PgClear();
|
||||
}
|
||||
|
||||
_LOG( LDBG, "TopFhsUpdateThread: RCDB update/insert OK. [%d][%s] score [%.1lf]", index, it->hostname, it->score );
|
||||
|
||||
|
||||
} // Top FHS 의 RCDB update loop
|
||||
|
||||
_LOG( LINF, "TopFhsThread: RCDB Top FHS update/insert [%d] rows.", index );
|
||||
|
||||
// RCDB 와의 연결을 명시적으로 해제 처리한다.
|
||||
rcdb.PgCloseDB();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/****************************************************************************
|
||||
Top FHS update Thread Class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/07/28
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __TOP_FHS_UPDATE_THREAD_H__
|
||||
#define __TOP_FHS_UPDATE_THREAD_H__
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "ShmManager.h"
|
||||
#include "RcdbInfo.h"
|
||||
|
||||
|
||||
/// @brief CTopFhsUpdateThread
|
||||
/// 본 클래스는 Thread 클래스로서...
|
||||
/// 주기적으로 공유메모리에 저장된 정보 중 FHS 정보를 추출하여 Top FHS 를 선정한 후
|
||||
/// 해당 정보를 RCDB 에 업데이트 한다.
|
||||
/// - RCDB 와 세션은 필요시 연결 후 해제 처리.
|
||||
class CTopFhsUpdateThread
|
||||
{
|
||||
public:
|
||||
|
||||
// 생성 및 소멸자.
|
||||
CTopFhsUpdateThread( CShmManager * pShmManager );
|
||||
~CTopFhsUpdateThread();
|
||||
|
||||
// 작업 시작
|
||||
bool Start( void );
|
||||
|
||||
private:
|
||||
|
||||
// Thread function....
|
||||
static void * threadFunc( void * arg );
|
||||
|
||||
// 실제 작업을 담당하는 함수.
|
||||
void Execute( void );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// 쓰레드 핸들
|
||||
pthread_t m_threadHandle;
|
||||
|
||||
// 공유메모리 접근을 위한 inferface 객체 (생성자를 통해 전달받음)
|
||||
CShmManager * m_pShmManager;
|
||||
|
||||
// Top FHS 정보를 저장하기 위한 vector
|
||||
// - struct WritableFhsInfo 구조체는 ShmManager.h 에 정의되어 있으며...
|
||||
// - score 점수가 낮은 FHS 가 writable, idle 한 FHS 임.
|
||||
std::vector<struct WritableFhsInfo> m_vecTopFhs;
|
||||
|
||||
// RCDB 연결 관련 접속 정보를 저장하기 위한 객체
|
||||
CRcdbInfo m_rcdbInfo;
|
||||
|
||||
};
|
||||
|
||||
#endif /* __TOP_FHS_UPDATE_THREAD_H__ */
|
||||
@@ -0,0 +1,189 @@
|
||||
#include "WorkerControl.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "ProcessRename.h"
|
||||
#include "ShmManager.h"
|
||||
#include "ProcessConfig.h"
|
||||
#include "GarbageCleanThread.h"
|
||||
#include "GmsSendThread.h"
|
||||
#include "TopFhsUpdateThread.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern CShmManager * g_pShmManager;
|
||||
|
||||
// FHS 의 vmasd 가 Broadcasting 하는 각 FHS 의 상태 정보를 수신받기 위한 UDP Socket....
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockVmasdRecv;
|
||||
|
||||
// FHS csagentd 가 전송하는 시스템 상태 정보 수신을 위한 TCP Socket
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockSystemRecv;
|
||||
|
||||
// FHS csagentd 가 전송하는 서비스 상태 체크 정보 수신을 위한 TCP Socket
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockCheckRecv;
|
||||
|
||||
// fimngd 등과 같은 외부 모듈과 통신을 통해 정보를 전달하기 위한 TCP Socket 생성.
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockInfoSend;
|
||||
|
||||
|
||||
|
||||
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
|
||||
void ReadyToExitWorkerControl()
|
||||
{
|
||||
// Logger 객체 종료 처리.
|
||||
CLogger::Exit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Worker Control 프로세스에 대한 대한 종료 처리 수신시.
|
||||
static void SignalWorkerControlTerminate( int nSignalNumber )
|
||||
{
|
||||
// Signal Number 에 따른 로깅처리.
|
||||
if( nSignalNumber == SIGTERM )
|
||||
{
|
||||
_LOG( LINF, "[Control:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LWAR, "[Control:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
|
||||
}
|
||||
|
||||
ReadyToExitWorkerControl();
|
||||
|
||||
// 종료전 잠시 대기
|
||||
struct timespec sleep;
|
||||
sleep.tv_sec = 0;
|
||||
sleep.tv_nsec = 500000000; // 0.5 sec
|
||||
nanosleep( &sleep, NULL );
|
||||
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
// Worker::Control Process 의 signal 처리기...
|
||||
void SetWorkerControlSignalHandler()
|
||||
{
|
||||
sigset_t set;
|
||||
struct sigaction act;
|
||||
|
||||
memset( &act, 0x00, sizeof( act ) );
|
||||
sigfillset( &set );
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
sigfillset( &act.sa_mask );
|
||||
|
||||
// 무시 처리 signal
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
|
||||
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
|
||||
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
|
||||
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
|
||||
|
||||
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGCHLD, &act, NULL );
|
||||
|
||||
/* 각종 에러나 사용자의 종료 신호 처리 */
|
||||
act.sa_handler = SignalWorkerControlTerminate;
|
||||
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
|
||||
|
||||
// 나머지 신호는 default 처리.
|
||||
|
||||
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Worker::Control 프로세스의 Main 역활을 수행하기 위한 함수.
|
||||
int WorkerControlMain()
|
||||
{
|
||||
// 전역 변수로 설정된 socket 중 해당 worker 에서 사용하지 않는 socket 은 close 처리한다.
|
||||
if( g_sockVmasdRecv != -1 )
|
||||
{
|
||||
close( g_sockVmasdRecv );
|
||||
g_sockVmasdRecv = -1;
|
||||
}
|
||||
if( g_sockSystemRecv != -1 )
|
||||
{
|
||||
close( g_sockSystemRecv );
|
||||
g_sockSystemRecv = -1;
|
||||
}
|
||||
if( g_sockCheckRecv != -1 )
|
||||
{
|
||||
close( g_sockCheckRecv );
|
||||
g_sockCheckRecv = -1;
|
||||
}
|
||||
if( g_sockInfoSend != -1 )
|
||||
{
|
||||
close( g_sockInfoSend );
|
||||
g_sockInfoSend = -1;
|
||||
}
|
||||
|
||||
|
||||
// Process Rename..
|
||||
set_ps_display( PROG_NAME": Control", false );
|
||||
|
||||
// Set Signal Handler
|
||||
SetWorkerControlSignalHandler();
|
||||
|
||||
|
||||
// 사용할 객체 초기화 처리
|
||||
|
||||
// 1. 공유메모리 상의 garbage 정보를 정리하기 위한 Thread
|
||||
CGarbageCleanThread threadGarbageClean( g_pShmManager );
|
||||
if( threadGarbageClean.Start() == false )
|
||||
{
|
||||
_LOG( LWAR, "[Control:%d] garbage clean thread create failed. => Process Exit", getpid() );
|
||||
|
||||
ReadyToExitWorkerControl();
|
||||
return EXIT_FAILURE; // EXIT_FAILURE 를 반환하여 재생성 처리 방지...
|
||||
}
|
||||
|
||||
// 2. GMS 로 RC 정보 전달 처리 Thread
|
||||
CGmsSendThread threadGmsSend( g_pShmManager );
|
||||
if( threadGmsSend.Start() == false )
|
||||
{
|
||||
_LOG( LWAR, "[Control:%d] gms send thread create failed. => Process Exit", getpid() );
|
||||
|
||||
ReadyToExitWorkerControl();
|
||||
return EXIT_FAILURE; // EXIT_FAILURE 를 반환하여 재생성 처리 방지...
|
||||
}
|
||||
|
||||
|
||||
// 3. RCDB 상에 Top FHS 정보 갱신 처리 Thread.
|
||||
CTopFhsUpdateThread threadTopFhsUpdate( g_pShmManager );
|
||||
if( threadTopFhsUpdate.Start() == false )
|
||||
{
|
||||
_LOG( LWAR, "[Control:%d] top fhs rcdb update thread create failed. => Process Exit", getpid() );
|
||||
|
||||
ReadyToExitWorkerControl();
|
||||
return EXIT_FAILURE; // EXIT_FAILURE 를 반환하여 재생성 처리 방지...
|
||||
}
|
||||
|
||||
|
||||
// 대기
|
||||
while( 1 )
|
||||
{
|
||||
// 할일 없어서.. 시그널 수신까지 대기 한다.
|
||||
pause();
|
||||
}
|
||||
|
||||
|
||||
// 종료시 정리 작업 수행
|
||||
ReadyToExitWorkerControl();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/****************************************************************************
|
||||
Worker::Control process main
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/06/03
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __WORKER_CONTROL_H__
|
||||
#define __WORKER_CONTROL_H__
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Worker::Control 프로세스의 Main 역활을 수행하기 위한 함수.
|
||||
int WorkerControlMain( void );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __WORKER_CONTROL_H__ */
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
#include "WorkerRecvCheck.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "ProcessRename.h"
|
||||
#include "ShmManager.h"
|
||||
#include "ProcessConfig.h"
|
||||
#include "SocketCsagentd.h"
|
||||
#include "ShmClientInfo.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern CShmManager * g_pShmManager;
|
||||
|
||||
// FHS 의 vmasd 가 Broadcasting 하는 각 FHS 의 상태 정보를 수신받기 위한 UDP Socket....
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockVmasdRecv;
|
||||
|
||||
// FHS csagentd 가 전송하는 시스템 상태 정보 수신을 위한 TCP Socket
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockSystemRecv;
|
||||
|
||||
// FHS csagentd 가 전송하는 서비스 상태 체크 정보 수신을 위한 TCP Socket
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockCheckRecv;
|
||||
|
||||
// fimngd 등과 같은 외부 모듈과 통신을 통해 정보를 전달하기 위한 TCP Socket 생성.
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockInfoSend;
|
||||
|
||||
|
||||
// 각 Client 를 처리할 Thread 에 전달할 구조체
|
||||
struct stRecvCheckThreadArg {
|
||||
|
||||
// client socket descriptor
|
||||
int clientSocketDesc;
|
||||
|
||||
// Client 의 IP 주소 정보를 저장한 변수
|
||||
// - 공유메모리 client_ip 항목 크기와 동일한 크기로 설정.
|
||||
char szClientAddress[IP_ADDR_LENGTH];
|
||||
|
||||
// client 의 공유메모리 index 정보.
|
||||
int iClientShmIndex;
|
||||
};
|
||||
|
||||
|
||||
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
|
||||
void ReadyToExitWorkerRecvCheck()
|
||||
{
|
||||
// open 된 socket 관련 Close 처리
|
||||
if( g_sockCheckRecv != -1 )
|
||||
close( g_sockCheckRecv );
|
||||
|
||||
|
||||
// Logger 객체 종료 처리.
|
||||
CLogger::Exit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Worker RecvCheck 프로세스에 대한 대한 종료 처리 수신시.
|
||||
static void SignalWorkerRecvCheckTerminate( int nSignalNumber )
|
||||
{
|
||||
// Signal Number 에 따른 로깅처리.
|
||||
if( nSignalNumber == SIGTERM )
|
||||
{
|
||||
_LOG( LINF, "[RecvCheck:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LWAR, "[RecvCheck:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
|
||||
}
|
||||
|
||||
ReadyToExitWorkerRecvCheck();
|
||||
|
||||
// 종료전 잠시 대기
|
||||
struct timespec sleep;
|
||||
sleep.tv_sec = 0;
|
||||
sleep.tv_nsec = 500000000; // 0.5 sec
|
||||
nanosleep( &sleep, NULL );
|
||||
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
// Worker::RecvCheck Process 의 signal 처리기...
|
||||
void SetWorkerRecvCheckSignalHandler()
|
||||
{
|
||||
sigset_t set;
|
||||
struct sigaction act;
|
||||
|
||||
memset( &act, 0x00, sizeof( act ) );
|
||||
sigfillset( &set );
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
sigfillset( &act.sa_mask );
|
||||
|
||||
// 무시 처리 signal
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
|
||||
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
|
||||
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
|
||||
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
|
||||
|
||||
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGCHLD, &act, NULL );
|
||||
|
||||
/* 각종 에러나 사용자의 종료 신호 처리 */
|
||||
act.sa_handler = SignalWorkerRecvCheckTerminate;
|
||||
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
|
||||
|
||||
// 나머지 신호는 default 처리.
|
||||
|
||||
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
}
|
||||
|
||||
// Worker::RecvCheck 에서 각 Client 에 대한 처리를 수행하기 위한 Thread.
|
||||
void * WorkerRecvCheckClientThread( void * arg )
|
||||
{
|
||||
// 전달받은 변수를 내부 변수에 저장 처리.
|
||||
|
||||
// client socket 관련 처리 변수 생성
|
||||
CSocketCsagentd clientSocket( ( ( struct stRecvCheckThreadArg * ) arg )->clientSocketDesc, CProcessConfig::GetInstance()->GetRcId() );
|
||||
|
||||
// client 주소 처리 관련
|
||||
char szClientAddress[IP_ADDR_LENGTH];
|
||||
memcpy( szClientAddress, ( ( struct stRecvCheckThreadArg * ) arg )->szClientAddress, IP_ADDR_LENGTH );
|
||||
|
||||
// client shared memory index, object
|
||||
int iClientShmIndex = ( ( struct stRecvCheckThreadArg * ) arg )->iClientShmIndex;
|
||||
CShmClientInfo clientShm( g_pShmManager->GetClientPtr( iClientShmIndex ) );
|
||||
|
||||
// malloc 로 생성된 변수 해제 처리
|
||||
free( arg );
|
||||
|
||||
|
||||
// 본 thead 는 client 연결 상태에 따라 종료되므로.. process 에서 분리 처리
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
_LOG( LINF, "[RecvCheck:%d] client thread start. [%s] shm_index [%d]", getpid(), szClientAddress, iClientShmIndex );
|
||||
|
||||
|
||||
// socket 수신 대기
|
||||
int nRead;
|
||||
|
||||
std::string strHostname;
|
||||
int iServiceStat;
|
||||
int iStorageMaxUsage;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
// 2018-02-22 CHG huibong (#31703)
|
||||
// - FHS 가 Hang 상황으로 서비스 상태 정보 전송 불가한 상황인 경우....
|
||||
// - GarbageCleanThread 가 있어서.. 정리 처리를 하지만.... 운영자가 이런 flow 를 잘 모르고 오해하는 경우 있음.
|
||||
// - 따라서 지정된 시간 동안 Data 를 수신하지 못하는 경우... 기존 재시도 대신 연결을 종료 처리한다.
|
||||
// - 대신 timeout 시간은 기존 6 sec -> 10 sec 로 조정 한다.
|
||||
|
||||
// Data 수신
|
||||
nRead = clientSocket.GetServiceInfo( strHostname, iServiceStat, iStorageMaxUsage, 10 );
|
||||
if( nRead == 0 )
|
||||
{
|
||||
// timeout 발생시
|
||||
// - 대기가 아닌 종료 처리 수행한다.
|
||||
if( clientShm.IsValid( szClientAddress ) == true )
|
||||
{
|
||||
g_pShmManager->ReleaseClientIndex( iClientShmIndex );
|
||||
}
|
||||
|
||||
_LOG( LINF, "[RecvCheck:%d] client session timeout. session closed. [%s]", getpid(), szClientAddress );
|
||||
break;
|
||||
|
||||
}
|
||||
else if( nRead < 0 )
|
||||
{
|
||||
// Socket 오류 발생시
|
||||
// - 관련 로그는 해당 모듈에서 다 찍었으므로.. 여기서는 루프 종료 처리.
|
||||
|
||||
// 할당된 공유메모리 해제.
|
||||
// - 본 프로세스에서 할당 처리 했으므로.. 해제 처리.
|
||||
if( clientShm.IsValid( szClientAddress ) == true )
|
||||
g_pShmManager->ReleaseClientIndex( iClientShmIndex );
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상 Data 수신시
|
||||
// RC ID 검사는 socket 수신 처리시 수행했음.
|
||||
|
||||
// shared memory 유효성 검사
|
||||
// - 유효하지 않은 경우.. 종료 처리한다.
|
||||
if( clientShm.IsValid( szClientAddress ) == false )
|
||||
{
|
||||
LOG( LERR, "client[%s] recv check: shared memory[%d] not valid. session close."
|
||||
, szClientAddress, iClientShmIndex );
|
||||
break;
|
||||
}
|
||||
|
||||
// 수신된 iStorageMaxUsage 값이... conf 에 정의된 STORAGE_MAX_USAGE_TO_DISABLE 값 이상이면.. read only 상태로 처리한다.
|
||||
if( iServiceStat == SERVICE_STAT_OK )
|
||||
{
|
||||
if( iStorageMaxUsage >= CProcessConfig::GetInstance()->GetStorageMaxUsageToDisable() )
|
||||
{
|
||||
_LOG( LINF, "client[%s] hostname[%s] storage max usage over [%d/%d]. set read only stat."
|
||||
, szClientAddress, strHostname.c_str(), iStorageMaxUsage, CProcessConfig::GetInstance()->GetStorageMaxUsageToDisable() );
|
||||
|
||||
iServiceStat = SERVICE_STAT_RONLY;
|
||||
}
|
||||
}
|
||||
|
||||
// 공유메모리에 관련 정보를 기록한다.
|
||||
if( clientShm.UpdateServiceInfo( strHostname, iServiceStat ) == false )
|
||||
{
|
||||
// shared memory 정보가 유효하지 않은 경우..
|
||||
// - 종료 처리.
|
||||
LOG( LERR, "client[%s] recv [%s] chk: shm update fail. session close. stat[%s] storage_max_usage[%d] "
|
||||
, szClientAddress, strHostname.c_str(), clientShm.GetServiceStatString( iServiceStat ), iStorageMaxUsage );
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LDBG, "client[%s] recv [%s] chk: shm update. stat[%s] storage_max_usage[%d]"
|
||||
, szClientAddress, strHostname.c_str(), clientShm.GetServiceStatString( iServiceStat ), iStorageMaxUsage );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// client 와 연결 종료 처리.
|
||||
_LOG( LINF, "[RecvCheck:%d] client connection closed. [%s]", getpid(), szClientAddress );
|
||||
clientSocket.Close();
|
||||
|
||||
// Thread 종료 관련 처리.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Worker::RecvCheck 프로세스의 Main 역활을 수행하기 위한 함수.
|
||||
int WorkerRecvCheckMain()
|
||||
{
|
||||
// 전역 변수로 설정된 socket 중 해당 worker 에서 사용하지 않는 socket 은 close 처리한다.
|
||||
if( g_sockVmasdRecv != -1 )
|
||||
{
|
||||
close( g_sockVmasdRecv );
|
||||
g_sockVmasdRecv = -1;
|
||||
}
|
||||
if( g_sockSystemRecv != -1 )
|
||||
{
|
||||
close( g_sockSystemRecv );
|
||||
g_sockSystemRecv = -1;
|
||||
}
|
||||
if( g_sockInfoSend != -1 )
|
||||
{
|
||||
close( g_sockInfoSend );
|
||||
g_sockInfoSend = -1;
|
||||
}
|
||||
|
||||
|
||||
// Process Rename..
|
||||
set_ps_display( PROG_NAME": RecvCheck", false );
|
||||
|
||||
// Set Signal Handler
|
||||
SetWorkerRecvCheckSignalHandler();
|
||||
|
||||
|
||||
// 사용할 객체 초기화 처리
|
||||
int clientSock;
|
||||
struct sockaddr_in clientSockAddr;
|
||||
socklen_t clientSockLen = sizeof( clientSockAddr );
|
||||
|
||||
pthread_t clientThreadId;
|
||||
struct stRecvCheckThreadArg * pThreadArg = NULL;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
clientSock = accept( g_sockCheckRecv, ( struct sockaddr * ) &clientSockAddr, &clientSockLen );
|
||||
|
||||
if( clientSock == -1 )
|
||||
{
|
||||
// 오류 발생시.... 해당 내역 로깅 처리.
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "[RecvCheck:%d] client accept failed [%d][%s]", getpid(), errorNum, strerror( errorNum ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상적인 Client 인 경우...
|
||||
// Thread 로 전달할 변수를 malloc 로 생성 처리
|
||||
pThreadArg = ( struct stRecvCheckThreadArg * ) malloc( sizeof( struct stRecvCheckThreadArg ) );
|
||||
if( pThreadArg == NULL )
|
||||
{
|
||||
int errorNum = errno;
|
||||
close( clientSock ); // client 접속 종료 처리.
|
||||
|
||||
char tempBuffer[IP_ADDR_LENGTH];
|
||||
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
|
||||
if( inet_ntop( AF_INET, &( clientSockAddr.sin_addr ), tempBuffer, sizeof( tempBuffer ) ) != NULL )
|
||||
{
|
||||
LOG( LERR, "[RecvCheck:%d] client[%s] thread malloc failed [%d][%s]", getpid(), tempBuffer, errorNum, strerror( errorNum ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "[RecvCheck:%d] client thread malloc failed [%d][%s] and inet_ntop error[%d][%s]"
|
||||
, getpid(), errorNum, strerror( errorNum ), errno, strerror( errno ) );
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 인자로 전달할 변수정보 설정.
|
||||
pThreadArg->clientSocketDesc = clientSock;
|
||||
|
||||
char tempBuffer[IP_ADDR_LENGTH];
|
||||
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
|
||||
if( inet_ntop( AF_INET, &( clientSockAddr.sin_addr ), tempBuffer, sizeof( tempBuffer ) ) != NULL )
|
||||
{
|
||||
memcpy( pThreadArg->szClientAddress, tempBuffer, sizeof( tempBuffer ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// inet_ntop 오류 발생시
|
||||
// client ip 를 공유메모리 할당 관련 key 값으로 사용하므로.....
|
||||
// ip 가 불분명할 경우.. 잘못된 공유메모리 할당으로 인해 문제 발생 가능.
|
||||
// 따라서 관련 상세 내역 로깅 후.. 세션 종료 처리한다.
|
||||
//snprintf( pThreadArg->szClientAddress, IP_ADDR_LENGTH - 1, "0.0.0.0" );
|
||||
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "[RecvCheck:%d] client ip not valid. connection closed. inet_ntop error[%d][%s]", getpid(), errorNum, strerror( errorNum ) );
|
||||
|
||||
close( clientSock );
|
||||
free( pThreadArg );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// 공유메모리상에 해당 client slot 이 존재하는지 확인 및 할당 처리.
|
||||
// - 만약 존재하지 않을 경우....할당 처리.
|
||||
// - 조회/할당 실패시 connection 을 close 처리하고.. 다음에 다시 접속하도록 한다.
|
||||
pThreadArg->iClientShmIndex = g_pShmManager->AllocateClientIndex( pThreadArg->szClientAddress );
|
||||
if( pThreadArg->iClientShmIndex == -1 )
|
||||
{
|
||||
LOG( LERR, "[RecvCheck:%d] client[%s] shared memory allocated fail. connection close.", getpid(), pThreadArg->szClientAddress );
|
||||
|
||||
close( clientSock );
|
||||
free( pThreadArg );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Client 처리를 담당할 Thread 생성 처리
|
||||
if( pthread_create( &clientThreadId, NULL, WorkerRecvCheckClientThread, (void *)pThreadArg ) != 0 )
|
||||
{
|
||||
// 생성 실패시...
|
||||
// - 로깅
|
||||
// - client socket close
|
||||
// - malloc 로 생성된 전달 변수 free 처리.
|
||||
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "[RecvCheck:%d] client[%s] thread create failed [%d][%s]"
|
||||
, getpid(), pThreadArg->szClientAddress, errorNum, strerror( errorNum ) );
|
||||
|
||||
// 할당된 공유메모리 해제.
|
||||
// - 본 프로세스에서 할당 처리 했으므로.. 해제 처리.
|
||||
g_pShmManager->ReleaseClientIndex( pThreadArg->iClientShmIndex );
|
||||
|
||||
close( clientSock );
|
||||
free( pThreadArg );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LDBG, "[RecvCheck:%d] client[%s] accept & client thread create ok.", getpid(), pThreadArg->szClientAddress );
|
||||
}
|
||||
}
|
||||
}
|
||||
} // while(1)
|
||||
|
||||
|
||||
// 종료시 정리 작업 수행
|
||||
ReadyToExitWorkerRecvCheck();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/****************************************************************************
|
||||
Worker::RecvCheck process main
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/06/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __WORKER_RECV_CHECK_H__
|
||||
#define __WORKER_RECV_CHECK_H__
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Worker::RecvCheck 프로세스의 Main 역활을 수행하기 위한 함수.
|
||||
int WorkerRecvCheckMain( void );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __WORKER_RECV_CHECK_H__ */
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
#include "WorkerRecvSystem.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "ProcessRename.h"
|
||||
#include "ShmManager.h"
|
||||
#include "ProcessConfig.h"
|
||||
#include "SocketCsagentd.h"
|
||||
#include "ShmClientInfo.h"
|
||||
#include "ReportLog.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern CShmManager * g_pShmManager;
|
||||
|
||||
// FHS 의 vmasd 가 Broadcasting 하는 각 FHS 의 상태 정보를 수신받기 위한 UDP Socket....
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockVmasdRecv;
|
||||
|
||||
// FHS csagentd 가 전송하는 시스템 상태 정보 수신을 위한 TCP Socket
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockSystemRecv;
|
||||
|
||||
// FHS csagentd 가 전송하는 서비스 상태 체크 정보 수신을 위한 TCP Socket
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockCheckRecv;
|
||||
|
||||
// fimngd 등과 같은 외부 모듈과 통신을 통해 정보를 전달하기 위한 TCP Socket 생성.
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockInfoSend;
|
||||
|
||||
|
||||
// 각 Client 를 처리할 Thread 에 전달할 구조체
|
||||
struct stRecvSystemThreadArg {
|
||||
|
||||
// client socket descriptor
|
||||
int clientSocketDesc;
|
||||
|
||||
// Client 의 IP 주소 정보를 저장한 변수
|
||||
// - 공유메모리 client_ip 항목 크기와 동일한 크기로 설정.
|
||||
char szClientAddress[IP_ADDR_LENGTH];
|
||||
|
||||
// client 의 공유메모리 index 정보.
|
||||
int iClientShmIndex;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
|
||||
void ReadyToExitWorkerRecvSystem()
|
||||
{
|
||||
// open 된 socket 관련 Close 처리
|
||||
if( g_sockSystemRecv != -1 )
|
||||
close( g_sockSystemRecv );
|
||||
|
||||
|
||||
// Logger 객체 종료 처리.
|
||||
CLogger::Exit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Worker RecvSystem 프로세스에 대한 대한 종료 처리 수신시.
|
||||
static void SignalWorkerRecvSystemTerminate( int nSignalNumber )
|
||||
{
|
||||
// Signal Number 에 따른 로깅처리.
|
||||
if( nSignalNumber == SIGTERM )
|
||||
{
|
||||
_LOG( LINF, "[RecvSystem:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LWAR, "[RecvSystem:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
|
||||
}
|
||||
|
||||
ReadyToExitWorkerRecvSystem();
|
||||
|
||||
// 종료전 잠시 대기
|
||||
struct timespec sleep;
|
||||
sleep.tv_sec = 0;
|
||||
sleep.tv_nsec = 500000000; // 0.5 sec
|
||||
nanosleep( &sleep, NULL );
|
||||
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
// Worker::RecvSystem Process 의 signal 처리기...
|
||||
void SetWorkerRecvSystemSignalHandler()
|
||||
{
|
||||
sigset_t set;
|
||||
struct sigaction act;
|
||||
|
||||
memset( &act, 0x00, sizeof( act ) );
|
||||
sigfillset( &set );
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
sigfillset( &act.sa_mask );
|
||||
|
||||
// 무시 처리 signal
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
|
||||
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
|
||||
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
|
||||
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
|
||||
|
||||
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGCHLD, &act, NULL );
|
||||
|
||||
/* 각종 에러나 사용자의 종료 신호 처리 */
|
||||
act.sa_handler = SignalWorkerRecvSystemTerminate;
|
||||
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
|
||||
|
||||
// 나머지 신호는 default 처리.
|
||||
|
||||
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Worker::RecvSystem 에서 각 Client 에 대한 처리를 수행하기 위한 Thread.
|
||||
void * WorkerRecvSystemClientThread( void * arg )
|
||||
{
|
||||
// 전달받은 변수를 내부 변수에 저장 처리.
|
||||
|
||||
// client socket 관련 처리 변수 생성
|
||||
CSocketCsagentd clientSocket( ( ( struct stRecvSystemThreadArg * ) arg )->clientSocketDesc, CProcessConfig::GetInstance()->GetRcId() );
|
||||
|
||||
// client 주소 처리 관련
|
||||
char szClientAddress[IP_ADDR_LENGTH];
|
||||
memcpy( szClientAddress, ( ( struct stRecvSystemThreadArg * ) arg )->szClientAddress, IP_ADDR_LENGTH );
|
||||
|
||||
// client shared memory index
|
||||
int iClientShmIndex = (( struct stRecvSystemThreadArg * ) arg )->iClientShmIndex;
|
||||
CShmClientInfo clientShm( g_pShmManager->GetClientPtr( iClientShmIndex ) );
|
||||
|
||||
// malloc 로 생성된 변수 해제 처리
|
||||
free( arg );
|
||||
|
||||
// 본 thead 는 client 연결 상태에 따라 종료되므로.. process 에서 분리 처리
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
_LOG( LINF, "[RecvSystem:%d] client thread start. [%s] shm_index [%d]", getpid(), szClientAddress, iClientShmIndex );
|
||||
|
||||
|
||||
// socket 수신 대기
|
||||
int nRead;
|
||||
|
||||
std::string strHostname;
|
||||
struct SystemInfo data;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
// 2018-02-22 CHG huibong (#31703)
|
||||
// - FHS 가 Hang 상황으로 system 상태 정보 전송 불가한 상황인 경우....
|
||||
// - GarbageCleanThread 가 있어서.. 정리 처리를 하지만.... 운영자가 이런 flow 를 잘 모르고 오해하는 경우 있음.
|
||||
// - 따라서 지정된 시간 동안 Data 를 수신하지 못하는 경우... 기존 재시도 대신 연결을 종료 처리한다.
|
||||
// - 대신 timeout 시간은 기존 13 sec -> 15 sec 로 조정 한다.
|
||||
|
||||
// Data 수신
|
||||
nRead = clientSocket.GetSystemInfo( strHostname, &data, 15 );
|
||||
if( nRead == 0 )
|
||||
{
|
||||
// timeout 발생시
|
||||
_LOG( LINF, "[RecvSystem:%d] client session timeout. session closed. [%s]", getpid(), szClientAddress );
|
||||
|
||||
break;
|
||||
}
|
||||
else if( nRead < 0 )
|
||||
{
|
||||
// Socket 오류 발생시
|
||||
// - 관련 로그는 해당 모듈에서 다 찍었으므로.. 여기서는 루프 종료 처리.
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상 Data 수신시
|
||||
// RC ID 검사는 socket 수신 처리시 수행했음.
|
||||
|
||||
// shared memory 유효성 검사
|
||||
// - 유효하지 않은 경우.. 종료 처리한다.
|
||||
if( clientShm.IsValid( szClientAddress ) == false )
|
||||
{
|
||||
LOG( LERR, "client[%s] recv system: shared memory[%d] not valid. session closed."
|
||||
, szClientAddress, iClientShmIndex );
|
||||
break;
|
||||
}
|
||||
|
||||
// shared memory 에 정보 저장 처리.
|
||||
if( clientShm.UpdateSystemInfo( strHostname, &data ) == false )
|
||||
{
|
||||
// shared memory 정보가 유효하지 않은 경우...
|
||||
// - 종료 처리.
|
||||
LOG( LERR, "client[%s] recv [%s] sys: shm update fail. session close.", szClientAddress, strHostname.c_str() );
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LDBG, "client[%s] recv [%s] sys: shm update. load5[%.2lf] mem[%d] swap[%d] storage[%d] busy[%.1lf] tcp80[%u of %u]"
|
||||
, szClientAddress, strHostname.c_str()
|
||||
, data.load_avg[1], data.memory_usage, data.swap_usage, data.storage_max_usage, data.disk_max_busy
|
||||
, data.tcp_80_establish, data.tcp_80 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// client 와 연결 종료 처리.
|
||||
_LOG( LINF, "[RecvSystem:%d] client connection closed. [%s]", getpid(), szClientAddress );
|
||||
clientSocket.Close();
|
||||
|
||||
// Thread 종료 관련 처리.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Worker::RecvSystem 프로세스의 Main 역활을 수행하기 위한 함수.
|
||||
int WorkerRecvSystemMain()
|
||||
{
|
||||
// 전역 변수로 설정된 socket 중 해당 worker 에서 사용하지 않는 socket 은 close 처리한다.
|
||||
if( g_sockVmasdRecv != -1 )
|
||||
{
|
||||
close( g_sockVmasdRecv );
|
||||
g_sockVmasdRecv = -1;
|
||||
}
|
||||
if( g_sockCheckRecv != -1 )
|
||||
{
|
||||
close( g_sockCheckRecv );
|
||||
g_sockCheckRecv = -1;
|
||||
}
|
||||
if( g_sockInfoSend != -1 )
|
||||
{
|
||||
close( g_sockInfoSend );
|
||||
g_sockInfoSend = -1;
|
||||
}
|
||||
|
||||
|
||||
// Process Rename..
|
||||
set_ps_display( PROG_NAME": RecvSystem", false );
|
||||
|
||||
// Set Signal Handler
|
||||
SetWorkerRecvSystemSignalHandler();
|
||||
|
||||
|
||||
// 사용할 객체 초기화 처리
|
||||
int clientSock;
|
||||
struct sockaddr_in clientSockAddr;
|
||||
socklen_t clientSockLen = sizeof( clientSockAddr );
|
||||
|
||||
pthread_t clientThreadId;
|
||||
struct stRecvSystemThreadArg * pThreadArg = NULL;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
clientSock = accept( g_sockSystemRecv, ( struct sockaddr * ) &clientSockAddr, &clientSockLen );
|
||||
|
||||
if( clientSock == -1 )
|
||||
{
|
||||
// 오류 발생시.... 해당 내역 로깅 처리.
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "[RecvSystem:%d] client accept failed [%d][%s]", getpid(), errorNum, strerror( errorNum ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상적인 Client 인 경우...
|
||||
// Thread 로 전달할 변수를 malloc 로 생성 처리
|
||||
pThreadArg = ( struct stRecvSystemThreadArg * ) malloc( sizeof( struct stRecvSystemThreadArg ) );
|
||||
if( pThreadArg == NULL )
|
||||
{
|
||||
int errorNum = errno;
|
||||
close( clientSock ); // client 접속 종료 처리.
|
||||
|
||||
char tempBuffer[IP_ADDR_LENGTH];
|
||||
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
|
||||
if( inet_ntop( AF_INET, &( clientSockAddr.sin_addr ), tempBuffer, sizeof( tempBuffer ) ) != NULL )
|
||||
{
|
||||
LOG( LERR, "[RecvSystem:%d] client[%s] thread malloc failed [%d][%s]", getpid(), tempBuffer, errorNum, strerror( errorNum ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "[RecvSystem:%d] client thread malloc failed [%d][%s] and inet_ntop error[%d][%s]"
|
||||
,getpid(), errorNum, strerror( errorNum ), errno, strerror( errno ) );
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 인자로 전달할 변수정보 설정.
|
||||
pThreadArg->clientSocketDesc = clientSock;
|
||||
|
||||
char tempBuffer[IP_ADDR_LENGTH];
|
||||
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
|
||||
if( inet_ntop( AF_INET, &( clientSockAddr.sin_addr ), tempBuffer, sizeof( tempBuffer ) ) != NULL )
|
||||
{
|
||||
memcpy( pThreadArg->szClientAddress, tempBuffer, sizeof( tempBuffer ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// inet_ntop 오류 발생시
|
||||
// client ip 를 공유메모리 할당 관련 key 값으로 사용하므로.....
|
||||
// ip 가 불분명할 경우.. 잘못된 공유메모리 할당으로 인해 문제 발생 가능.
|
||||
// 따라서 관련 상세 내역 로깅 후.. 세션 종료 처리한다.
|
||||
//snprintf( pThreadArg->szClientAddress, IP_ADDR_LENGTH-1, "0.0.0.0" );
|
||||
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "[RecvSystem:%d] client ip not valid. connection closed. inet_ntop error[%d][%s]", getpid(), errorNum, strerror( errorNum ) );
|
||||
|
||||
close( clientSock );
|
||||
free( pThreadArg );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// 공유메모리상에 해당 client slot 이 존재하는지 확인한다.
|
||||
// - 만약 존재하지 않을 경우....
|
||||
// - service check 관련 정보가 아직 수신되지 않은 상태이므로..... connection 을 close 처리하고.. 다음에 다시 접속하도록 한다.
|
||||
pThreadArg->iClientShmIndex = g_pShmManager->FindClientIndex( pThreadArg->szClientAddress );
|
||||
if( pThreadArg->iClientShmIndex == -1 )
|
||||
{
|
||||
LOG( LERR, "[RecvSystem:%d] client[%s] shared memory not allocated. connection close.", getpid(), pThreadArg->szClientAddress );
|
||||
|
||||
close( clientSock );
|
||||
free( pThreadArg );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Client 처리를 담당할 Thread 생성 처리
|
||||
if( pthread_create( &clientThreadId, NULL, WorkerRecvSystemClientThread, (void *)pThreadArg ) != 0 )
|
||||
{
|
||||
// 생성 실패시...
|
||||
// - 로깅
|
||||
// - client socket close
|
||||
// - malloc 로 생성된 전달 변수 free 처리.
|
||||
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "[RecvSystem:%d] client[%s] thread create failed [%d][%s]"
|
||||
, getpid(), pThreadArg->szClientAddress, errorNum, strerror( errorNum ) );
|
||||
|
||||
// 할당된 공유메모리 해제
|
||||
// - WorkerRecvCheck 에서 할당했음로.. 그 쪽에서 해제 권한 가짐.
|
||||
|
||||
close( clientSock );
|
||||
free( pThreadArg );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LDBG, "[RecvSystem:%d] client[%s] accept & client thread create ok.", getpid(), pThreadArg->szClientAddress );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // while(1)
|
||||
|
||||
|
||||
// 종료시 정리 작업 수행
|
||||
ReadyToExitWorkerRecvSystem();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/****************************************************************************
|
||||
Worker::RecvSystem process main
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/06/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __WORKER_RECV_SYSTEM_H__
|
||||
#define __WORKER_RECV_SYSTEM_H__
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Worker::RecvSystem 프로세스의 Main 역활을 수행하기 위한 함수.
|
||||
int WorkerRecvSystemMain( void );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __WORKER_RECV_SYSTEM_H__ */
|
||||
|
||||
@@ -0,0 +1,416 @@
|
||||
#include "WorkerRecvVmasd.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "ProcessRename.h"
|
||||
#include "ShmManager.h"
|
||||
#include "FixedQueue.h"
|
||||
#include "ProtocolVmasd.h"
|
||||
#include "ProcessConfig.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
|
||||
// vmasd broadcast message 를 수신하기 위한 buffer size
|
||||
// - vmasd 는 Header 352 Byte, Body 640 Byte => 총 992 Byte 전달함 (BroadcastMessage.h 참고)
|
||||
// - 따라서 향후 확장으로 고려하여 기존 rc_vrcd 9216 Byte -> 1024 Byte 로 변경함.
|
||||
#define MAX_SOCKET_BUFFER_SIZE 1024
|
||||
|
||||
// vmasd 로 부터 전달받은 Data 를 파싱 thread 에 전달시 사용할 Queue 의 최대 갯수
|
||||
#define MAX_DATA_QUEUE_COUNT 3000
|
||||
|
||||
// 수신 처리를 담당할 Thread 의 수
|
||||
#define MAX_THREAD_RECEIVER 10
|
||||
|
||||
|
||||
// vmasd 수신 시작 delay time (sec)
|
||||
#define RECV_START_DELAY_SEC 5
|
||||
|
||||
|
||||
|
||||
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern CShmManager * g_pShmManager;
|
||||
|
||||
// FHS 의 vmasd 가 Broadcasting 하는 각 FHS 의 상태 정보를 수신받기 위한 UDP Socket....
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockVmasdRecv;
|
||||
|
||||
// FHS csagentd 가 전송하는 시스템 상태 정보 수신을 위한 TCP Socket
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockSystemRecv;
|
||||
|
||||
// FHS csagentd 가 전송하는 서비스 상태 체크 정보 수신을 위한 TCP Socket
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockCheckRecv;
|
||||
|
||||
// fimngd 등과 같은 외부 모듈과 통신을 통해 정보를 전달하기 위한 TCP Socket 생성.
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockInfoSend;
|
||||
|
||||
// Data 수신부와 이를 파싱하여 처리할 Thread 객체간에 Data 전달을 위한 Queue 객체 생성
|
||||
CFixedQueue * g_pStatDataQueue = NULL;
|
||||
|
||||
|
||||
|
||||
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
|
||||
void ReadyToExitWorkerRecvVmasd()
|
||||
{
|
||||
// open 된 socket 관련 close 처리
|
||||
if( g_sockVmasdRecv != -1 )
|
||||
close( g_sockVmasdRecv );
|
||||
|
||||
// Queue 객체 해제
|
||||
if( g_pStatDataQueue != NULL )
|
||||
{
|
||||
CFixedQueue * temp = g_pStatDataQueue;
|
||||
|
||||
g_pStatDataQueue = NULL;
|
||||
delete temp;
|
||||
}
|
||||
|
||||
// Logger 객체 종료 처리.
|
||||
CLogger::Exit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Worker RecvVmasd 프로세스에 대한 대한 종료 처리 수신시.
|
||||
static void SignalWorkerRecvVmasdTerminate( int nSignalNumber )
|
||||
{
|
||||
// Signal Number 에 따른 로깅처리.
|
||||
if( nSignalNumber == SIGTERM )
|
||||
{
|
||||
_LOG( LINF, "[RecvVmasd:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LWAR, "[RecvVmasd:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
|
||||
}
|
||||
|
||||
ReadyToExitWorkerRecvVmasd();
|
||||
|
||||
// 종료전 잠시 대기
|
||||
struct timespec sleep;
|
||||
sleep.tv_sec = 0;
|
||||
sleep.tv_nsec = 500000000; // 0.5 sec
|
||||
nanosleep( &sleep, NULL );
|
||||
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
// Worker::RecvVmasd Process 의 signal 처리기...
|
||||
void SetWorkerRecvVmasdSignalHandler()
|
||||
{
|
||||
sigset_t set;
|
||||
struct sigaction act;
|
||||
|
||||
memset( &act, 0x00, sizeof( act ) );
|
||||
sigfillset( &set );
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
sigfillset( &act.sa_mask );
|
||||
|
||||
// 무시 처리 signal
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
|
||||
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
|
||||
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
|
||||
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
|
||||
|
||||
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGCHLD, &act, NULL );
|
||||
|
||||
/* 각종 에러나 사용자의 종료 신호 처리 */
|
||||
act.sa_handler = SignalWorkerRecvVmasdTerminate;
|
||||
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
|
||||
|
||||
// 나머지 신호는 default 처리.
|
||||
|
||||
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
}
|
||||
|
||||
// 전역 Queue 에 저장된 vmasd 수신 data 를 파싱하여 공유 메모리에 저장 처리를 담당하는 Thread
|
||||
void * WorkerRecvVmasdSaveThread( void * arg )
|
||||
{
|
||||
// 메인 함수에서 이 스레드가 종료되기를 기다리지 않게 분리
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
|
||||
_LOG( LINF, "[RecvVmasd:%d] SaveThread: start...", getpid() );
|
||||
|
||||
|
||||
// Queue pop data 저장 관련 변수 초기화.
|
||||
int pop_result;
|
||||
char szTempBuffer[MAX_SOCKET_BUFFER_SIZE];
|
||||
|
||||
//struct vmasd_broadcast_message_header * pHeader = (struct vmasd_broadcast_message_header *)szTempBuffer;
|
||||
struct vmasd_broadcast_message_body * pBody = ( struct vmasd_broadcast_message_body * )( szTempBuffer + sizeof( struct vmasd_broadcast_message_header ) ); // sizeof 값은 352 Byte (64Bit OS )
|
||||
|
||||
|
||||
// 본 Thread 는 main 에서 vmasd 정보를 수신한 후 동작해야 하므로... 5 sec 정도 기다린 후 동작시킨다.
|
||||
sleep( RECV_START_DELAY_SEC );
|
||||
|
||||
|
||||
// 루프를 돌면서... Queue 에 저장된 vmasd 수신 정보를 POP -> 파싱하여.. 저장 처리한다.
|
||||
// g_pStatDataQueue 값은 프로세스 종료 처리시 NULL 로 변경된다.. 따라서 본 Thread 가 종료될 수 있도록 처리한다.
|
||||
while( g_pStatDataQueue != NULL )
|
||||
{
|
||||
// Queue 에서 Data 를 Pop 한다..
|
||||
// Queue 객체 자체에서 인자값을 전달한 버퍼를 memset 하므로.. 따로 수행하지 않는다.
|
||||
pop_result = g_pStatDataQueue->Pop( szTempBuffer, MAX_SOCKET_BUFFER_SIZE );
|
||||
|
||||
if( pop_result == 0 ) // Pop 성공시..
|
||||
{
|
||||
/*
|
||||
_LOG( LDBG, "[RecvVmasd:%d] SaveThread: header [%s][0x%04x][%s][%s][%s][%d][%d]", getpid()
|
||||
, pHeader->szTransactionID, ntohl( pHeader->ulMode ), pHeader->szIssuer, pHeader->szServiceID, pHeader->szRCID
|
||||
, ntohl( pHeader->ulResult ), ntohl( pHeader->ulBodyLength ) );
|
||||
|
||||
_LOG( LDBG, "[RecvVmasd:%d] SaveThread: body [%s] [%lu][%lu] [%d][%d] [%d][%d] [%d][%d] [%u][%u][%u][%u] [%s] [%lu]" , getpid()
|
||||
, pBody->domain
|
||||
, pBody->total, pBody->free
|
||||
, pBody->manual_disable, pBody->upload_level
|
||||
, pBody->disk_backlog, pBody->disk_percent
|
||||
, pBody->connection_established, pBody->connection_total
|
||||
, pBody->traffic_ip, pBody->traffic_ib, pBody->traffic_op, pBody->traffic_ob, pBody->hostname
|
||||
, pBody->large_block );
|
||||
*/
|
||||
|
||||
|
||||
// RC ID 검사는 앞의 수신 처리부에서 했으므로..... pass
|
||||
// body 부분 중 domain 항목은 client ip 정보로.. 수신 모듈에서 대체처리 했음.
|
||||
|
||||
// 수신된 정보를 공유메모리에 저장 처리한다.
|
||||
if( g_pShmManager->SetVmasdData( pBody ) == false )
|
||||
{
|
||||
LOG( LERR, "[RecvVmasd:%d] SaveThread: shm update fail.[%s][%s]", getpid(), pBody->domain, pBody->hostname );
|
||||
}
|
||||
|
||||
}
|
||||
else if( pop_result == 1 ) // Queue 가 empty 인 경우..
|
||||
{
|
||||
// pop 할 data 가 없으므로.. 잠시 쉰다.. ( 0.5 sec 정도 )
|
||||
//_LOG( LDBG, "RecvVmasd[%d]:SaveThread: queue empty. sleep", getpid());
|
||||
struct timespec sleep;
|
||||
sleep.tv_sec = 0;
|
||||
sleep.tv_nsec = 500000000; // 0.5 sec
|
||||
nanosleep( &sleep, NULL );
|
||||
|
||||
}
|
||||
else // 나머지 상황은 오류..
|
||||
{
|
||||
LOG( LERR, "[RecvVmasd:%d] SaveThread: queue pop unknown error.[%d]", getpid(), pop_result );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Thread 종료 관련 처리.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Worker::RecvVmasd 에서 vmasd 정보를 수신처리하기 위한 Thread.
|
||||
void * WorkerRecvVmasdClientThread( void * arg )
|
||||
{
|
||||
// 메인 함수에서 이 스레드가 종료되기를 기다리지 않게 분리
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
_LOG( LINF, "[RecvVmasd:%d] ReceiveThread: start...", getpid() );
|
||||
|
||||
// vmasd broadcast data 수신을 위한 준비
|
||||
struct sockaddr_in clientSocketAddr;
|
||||
socklen_t clientSocketAddrLen = sizeof( clientSocketAddr );
|
||||
|
||||
char szClientAddress[INET_ADDRSTRLEN];
|
||||
memset( szClientAddress, 0x00, sizeof( szClientAddress ) );
|
||||
|
||||
char szSocketBuffer[MAX_SOCKET_BUFFER_SIZE];
|
||||
int nRead;
|
||||
int nResult;
|
||||
|
||||
struct vmasd_broadcast_message_header * pHeader = NULL;
|
||||
struct vmasd_broadcast_message_body * pBody = NULL;
|
||||
|
||||
// vmasd broadcast 정보 수신 대기
|
||||
while( 1 )
|
||||
{
|
||||
// vmasd 로부터 수신된 Data read 대기
|
||||
nRead = recvfrom( g_sockVmasdRecv, &szSocketBuffer, MAX_SOCKET_BUFFER_SIZE, 0, ( struct sockaddr * )&clientSocketAddr, &clientSocketAddrLen );
|
||||
|
||||
// 수신 오류 발생시
|
||||
if( nRead < 0 )
|
||||
{
|
||||
LOG( LWAR, "RecvVmasd socket recvfrom error[%d][%s]", errno, strerror( errno ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( inet_ntop( AF_INET, &( clientSocketAddr.sin_addr ), szClientAddress, sizeof( szClientAddress ) ) == NULL )
|
||||
{
|
||||
LOG( LERR, "RecvVmasd inet_ntop error[%d][%s]", errno, strerror( errno ) );
|
||||
}
|
||||
|
||||
// 로그 기록 목적으로 로깅처리
|
||||
_LOG( LDBG, "VmasdReceiver[%d][%lu]: vmasd[%s] received. length[%d]", getpid(), pthread_self(), szClientAddress, nRead );
|
||||
|
||||
// 1. vmasd message 의 경우 broadcasting message 이므로.. 사설 네트워크 구간이 분리되지 않은 경우... 다른 RC 의 메시지가 수신될 확률이 높다.
|
||||
// 따라서. 동일 RC 에서 전달된 메시지인지 먼저 확인한다.
|
||||
pHeader = ( struct vmasd_broadcast_message_header * )szSocketBuffer;
|
||||
if( strcasecmp( pHeader->szRCID, CProcessConfig::GetInstance()->GetRcId() ) != 0 )
|
||||
{
|
||||
// 다른 RC 로 부터 vmasd 메시지를 수신한 경우... 수신 Data 는 그냥 버린다.
|
||||
LOG( LWAR, "RecvVmasd: Not match RCID[%s][%s]", pHeader->szRCID, szClientAddress );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Debug 목적으로 Data 파싱 처리 후 출력...
|
||||
/*
|
||||
_LOG( LDBG, "BroadcastReceiver[%d]: vmasd [%s][0x%04x][%s][%s][%s][%d][%d]", getpid()
|
||||
, pHeader->szTransactionID, ntohl(pHeader->ulMode), pHeader->szIssuer, pHeader->szServiceID, pHeader->szRCID
|
||||
, ntohl(pHeader->ulResult), ntohl(pHeader->ulBodyLength) );
|
||||
*/
|
||||
|
||||
|
||||
// 2. 기존 rc_vrcd 소스 코드를 참조하여...
|
||||
// 수신된 메시시 값 중 ntohl(stHeader->ulMode) == MSG_MODE_VMA_APACHE_DISKSIZE ( 0x0100 ) 인 경우에만 처리..
|
||||
// 그외 메시지에 대해서는 Invalid Protocol 로 처리한다.
|
||||
if( ntohl( pHeader->ulMode ) != MSG_MODE_VMA_APACHE_DISKSIZE ) // #define MSG_MODE_VMA_APACHE_DISKSIZE 0x0100
|
||||
{
|
||||
LOG( LWAR, "RecvVmasd: Invalid protocol received.[0x%04x][%s]", ntohl( pHeader->ulMode ), szClientAddress );
|
||||
}
|
||||
else if( nRead != ( sizeof( struct vmasd_broadcast_message_header ) + sizeof( struct vmasd_broadcast_message_body ) ) )
|
||||
{
|
||||
// 수신된 packet 크기는 64Bit OS 에서 992 Byte 이어야 함
|
||||
// - sizeof( struct vmasd_broadcast_message_header ) => 352 (64Bit OS)
|
||||
// - sizeof( struct vmasd_broadcast_message_body ) => 640 (64Bit OS)
|
||||
|
||||
LOG( LWAR, "RecvVmasd: Invalid packet length [%s]. receive[%d]. normal[%lu] "
|
||||
, szClientAddress, nRead
|
||||
, ( sizeof( struct vmasd_broadcast_message_header ) + sizeof( struct vmasd_broadcast_message_body ) ) );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Data 를 Queue 에 저장하기 전에.. IP 정보를 전달해야 하지만... 저장할 공간이 없으므로...
|
||||
// 수신된 body 중 domain, hostname 항목이 중복되지만... domain 항목은 사용하지 않는 항목이므로....
|
||||
// domain 항목에 수신된 IP 정보를 기록처리한다.
|
||||
pBody = ( struct vmasd_broadcast_message_body * )( szSocketBuffer + sizeof( struct vmasd_broadcast_message_header ) ); // sizeof 값은 352 Byte (64Bit OS )
|
||||
memcpy( pBody->domain, szClientAddress, sizeof( szClientAddress ) );
|
||||
|
||||
// Data 를 Queue 에 저장.
|
||||
if( g_pStatDataQueue != NULL )
|
||||
{
|
||||
nResult = g_pStatDataQueue->Push( szSocketBuffer, nRead );
|
||||
|
||||
// Push 처리시 반환값
|
||||
// -1 : 전달 인자값에 NULL 존재
|
||||
// -2 : Queue 생성시 설정한 Data 크기보다 더 큰 nRead 값을 전달한 경우.
|
||||
// 1 : Queue 생성시 설정한 최대 Queue 갯수를 초과한 경우..
|
||||
// 0 : 정상 처리
|
||||
if( nResult != 0 )
|
||||
{
|
||||
LOG( LWAR, "RecvVmasd: queue push error[%d]", nResult );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // while(1)
|
||||
|
||||
|
||||
// Thread 종료 관련 처리.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Worker::RecvVmasd 프로세스의 Main 역활을 수행하기 위한 함수.
|
||||
int WorkerRecvVmasdMain()
|
||||
{
|
||||
// 전역 변수로 설정된 socket 중 해당 worker 에서 사용하지 않는 socket 은 close 처리한다.
|
||||
if( g_sockSystemRecv != -1 )
|
||||
{
|
||||
close( g_sockSystemRecv );
|
||||
g_sockSystemRecv = -1;
|
||||
}
|
||||
if( g_sockCheckRecv != -1 )
|
||||
{
|
||||
close( g_sockCheckRecv );
|
||||
g_sockCheckRecv = -1;
|
||||
}
|
||||
if( g_sockInfoSend != -1 )
|
||||
{
|
||||
close( g_sockInfoSend );
|
||||
g_sockInfoSend = -1;
|
||||
}
|
||||
|
||||
|
||||
// Process Rename..
|
||||
set_ps_display( PROG_NAME": RecvVmasd", false );
|
||||
|
||||
// Set Signal Handler
|
||||
SetWorkerRecvVmasdSignalHandler();
|
||||
|
||||
|
||||
// 사용할 객체 초기화 처리
|
||||
// Data 전달을 담당할 Queue 객체 생성
|
||||
g_pStatDataQueue = new CFixedQueue( MAX_SOCKET_BUFFER_SIZE, MAX_DATA_QUEUE_COUNT );
|
||||
if( g_pStatDataQueue == NULL )
|
||||
{
|
||||
// 객체 생성 실패시
|
||||
LOG( LERR, "[RecvVmasd:%d] data queue create failed. process exit", getpid() );
|
||||
|
||||
ReadyToExitWorkerRecvVmasd();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Queue 로 전달된 Data 를 파싱하여 공유메모리에 저장 처리를 담당할 Thread 를 생성한다.
|
||||
pthread_t workerSaveThreadId;
|
||||
if( pthread_create( &workerSaveThreadId, NULL, WorkerRecvVmasdSaveThread, NULL ) != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
|
||||
LOG( LERR, "[RecvVmasd:%d] save thread create failed[%d][%s]. process exit", getpid(), errorNum, strerror( errorNum ) );
|
||||
|
||||
ReadyToExitWorkerRecvVmasd();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// csagentd 수신 처리 모듈이 먼저 기동되어야.. 공유메모리 동시 write 문제를 회피할 수 있다.
|
||||
sleep( RECV_START_DELAY_SEC );
|
||||
|
||||
// vmasd 로 부터 UDP broadcasting 정보를 수신 처리할 Thread 생성 처리.
|
||||
pthread_t workerReceiveThreadId;
|
||||
for( int i = 0; i < MAX_THREAD_RECEIVER; i++ )
|
||||
{
|
||||
if( pthread_create( &workerReceiveThreadId, NULL, WorkerRecvVmasdClientThread, NULL ) != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
|
||||
LOG( LERR, "[RecvVmasd:%d] receive thread create failed[%d][%s]. process exit", getpid(), errorNum, strerror( errorNum ) );
|
||||
|
||||
ReadyToExitWorkerRecvVmasd();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
sleep( 1 );
|
||||
_LOG( LINF, "[RecvVmasd:%d] receive thread count[%d] create success.", getpid(), MAX_THREAD_RECEIVER );
|
||||
|
||||
|
||||
// 대기
|
||||
while( 1 )
|
||||
{
|
||||
// 할일 없어서.. 시그널 수신까지 대기 한다.
|
||||
pause();
|
||||
}
|
||||
|
||||
|
||||
// 종료시 정리 작업 수행
|
||||
ReadyToExitWorkerRecvVmasd();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/****************************************************************************
|
||||
Worker::RecvVmasd process main
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/06/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __WORKER_RECV_VMASD_H__
|
||||
#define __WORKER_RECV_VMASD_H__
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Worker::RecvVmasd 프로세스의 Main 역활을 수행하기 위한 함수.
|
||||
int WorkerRecvVmasdMain( void );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __WORKER_RECV_VMASD_H__ */
|
||||
|
||||
@@ -0,0 +1,389 @@
|
||||
#include "WorkerSendInfo.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "ProcessRename.h"
|
||||
#include "ShmManager.h"
|
||||
#include "ProcessConfig.h"
|
||||
#include "AliveFhsCacheThread.h"
|
||||
#include "SocketSendInfo.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
// 요청 수신 관련 최대 대기 시간. (sec)
|
||||
#define MAX_REQUEST_TIMEOUT 60
|
||||
|
||||
|
||||
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern CShmManager * g_pShmManager;
|
||||
|
||||
// FHS 의 vmasd 가 Broadcasting 하는 각 FHS 의 상태 정보를 수신받기 위한 UDP Socket....
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockVmasdRecv;
|
||||
|
||||
// FHS csagentd 가 전송하는 시스템 상태 정보 수신을 위한 TCP Socket
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockSystemRecv;
|
||||
|
||||
// FHS csagentd 가 전송하는 서비스 상태 체크 정보 수신을 위한 TCP Socket
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockCheckRecv;
|
||||
|
||||
// fimngd 등과 같은 외부 모듈과 통신을 통해 정보를 전달하기 위한 TCP Socket 생성.
|
||||
// Main.cpp 에 전역변수로 정의 되어 있다.
|
||||
extern int g_sockInfoSend;
|
||||
|
||||
|
||||
// Alive FHS Cache Thread 객체 대한 포인터.
|
||||
CAliveFhsCacheThread * g_pThreadAliveFhs = NULL;
|
||||
|
||||
|
||||
// 각 Client 를 처리할 Thread 에 전달할 구조체
|
||||
struct stSendInfoThreadArg {
|
||||
|
||||
// client socket descriptor
|
||||
int clientSocketDesc;
|
||||
|
||||
// Client 의 IP 주소 정보를 저장한 변수
|
||||
// - 공유메모리 client_ip 항목 크기와 동일한 크기로 설정.
|
||||
char szClientAddress[IP_ADDR_LENGTH];
|
||||
};
|
||||
|
||||
|
||||
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
|
||||
void ReadyToExitWorkerSendInfo()
|
||||
{
|
||||
// open 된 socket 관련 Close 처리
|
||||
if( g_sockInfoSend != -1 )
|
||||
close( g_sockInfoSend );
|
||||
|
||||
// Logger 객체 종료 처리.
|
||||
CLogger::Exit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Worker SendInfo 프로세스에 대한 대한 종료 처리 수신시.
|
||||
static void SignalWorkerSendInfoTerminate( int nSignalNumber )
|
||||
{
|
||||
// Signal Number 에 따른 로깅처리.
|
||||
if( nSignalNumber == SIGTERM )
|
||||
{
|
||||
_LOG( LINF, "[SendInfo:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LWAR, "[SendInfo:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
|
||||
}
|
||||
|
||||
ReadyToExitWorkerSendInfo();
|
||||
|
||||
// 종료전 잠시 대기
|
||||
struct timespec sleep;
|
||||
sleep.tv_sec = 0;
|
||||
sleep.tv_nsec = 500000000; // 0.5 sec
|
||||
nanosleep( &sleep, NULL );
|
||||
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
// Worker::SendInfo Process 의 signal 처리기...
|
||||
void SetWorkerSendInfoSignalHandler()
|
||||
{
|
||||
sigset_t set;
|
||||
struct sigaction act;
|
||||
|
||||
memset( &act, 0x00, sizeof( act ) );
|
||||
sigfillset( &set );
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
sigfillset( &act.sa_mask );
|
||||
|
||||
// 무시 처리 signal
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
|
||||
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
|
||||
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
|
||||
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
|
||||
|
||||
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGCHLD, &act, NULL );
|
||||
|
||||
/* 각종 에러나 사용자의 종료 신호 처리 */
|
||||
act.sa_handler = SignalWorkerSendInfoTerminate;
|
||||
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
|
||||
|
||||
// 나머지 신호는 default 처리.
|
||||
|
||||
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
}
|
||||
|
||||
// Worker::SendInfo 에서 각 Client 에 대한 처리를 수행하기 위한 Thread.
|
||||
void * WorkerSendInfoClientThread( void * arg )
|
||||
{
|
||||
// 전달받은 변수를 내부 변수에 저장 처리.
|
||||
|
||||
// client socket 관련 처리 변수 생성
|
||||
CSocketSendInfo clientSocket( ( ( struct stSendInfoThreadArg * ) arg )->clientSocketDesc );
|
||||
|
||||
// client 주소 처리 관련
|
||||
char szClientAddress[IP_ADDR_LENGTH];
|
||||
memcpy( szClientAddress, ( ( struct stSendInfoThreadArg * ) arg )->szClientAddress, IP_ADDR_LENGTH );
|
||||
|
||||
// malloc 로 생성된 변수 해제 처리
|
||||
free( arg );
|
||||
|
||||
|
||||
// 본 thead 는 client 연결 상태에 따라 종료되므로.. process 에서 분리 처리
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
_LOG( LINF, "[SendInfo:%d] client thread start. [%s]", getpid(), szClientAddress );
|
||||
|
||||
// 송수신 처리 관련 변수
|
||||
int nResult;
|
||||
char command;
|
||||
|
||||
// hostname 수신 정보를 저장하기 위한 변수.
|
||||
std::string strHostname;
|
||||
|
||||
// Alive FHS 목록정보 저장 처리를 위한 vector
|
||||
std::vector<struct FhsServiceStatInfo> vecAliveFhs;
|
||||
|
||||
// socket 수신 대기
|
||||
while( 1 )
|
||||
{
|
||||
// 요청 수신 대기
|
||||
nResult = clientSocket.GetPacketHeader( command, MAX_REQUEST_TIMEOUT );
|
||||
|
||||
if( nResult == 0 )
|
||||
{
|
||||
// timeout 발생시...
|
||||
// - server 모드로 동작하므로... 지정된 시간동안 요청이 없는 경우 세션을 종료 처리한다.
|
||||
_LOG( LINF, "[SendInfo:%d] client[%s] request timeout[%d]. session close.", getpid(), szClientAddress, MAX_REQUEST_TIMEOUT );
|
||||
|
||||
break;
|
||||
}
|
||||
else if( nResult < 0 )
|
||||
{
|
||||
// Socket 종료, 오류 또는 정의되지 않은 형식의 패킷 header 수신시...
|
||||
// 오류 내역은 socket 모듈에서 로깅하므로... 그냥 종료 처리.
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상 header 수신시.
|
||||
// - 수신된 command 에 따른 처리.
|
||||
|
||||
if( command == COMMAND_ALIVE_FHS )
|
||||
{
|
||||
// Alive FHS 목록 요청인 경우..
|
||||
|
||||
|
||||
// Body 부분에 대한 처리.
|
||||
// - 각 protocol version 별 처리.
|
||||
if( clientSocket.GetPacketBodyAliveFhs( strHostname ) == false )
|
||||
{
|
||||
// Data 수신 실패, 지원하지 않는 protocol version 또는 RC ID 정보가 다른 경우....
|
||||
// - 세션 종료 처리.
|
||||
// - 오류 내역은 위의 해당 함수에서 client 로 전송 처리함.
|
||||
LOG( LERR, "[SendInfo:%d] client[%s] alive fhs request body fail. session close.", getpid(), szClientAddress );
|
||||
break;
|
||||
}
|
||||
|
||||
// Alive FHS 목록 조회.
|
||||
vecAliveFhs.clear();
|
||||
if( g_pThreadAliveFhs->GetAliveFhs( vecAliveFhs ) == -1 )
|
||||
{
|
||||
// 공유메모리의 FHS 정보가 아직 불완전하여 SKIP 처리해야 하는 경우.
|
||||
if( clientSocket.SendResultAliveFhsSkip() == false )
|
||||
{
|
||||
// 전송 실패 발생시.
|
||||
LOG( LERR, "[SendInfo:%d] client[%s][%s] alive fhs skip send error. session close."
|
||||
, getpid(), szClientAddress, strHostname.c_str() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Alive FHS 목록 전송 처리.
|
||||
if( clientSocket.SendResultAliveFhs( vecAliveFhs ) == false )
|
||||
{
|
||||
// 전송 실패 발생시.
|
||||
LOG( LERR, "[SendInfo:%d] client[%s][%s] alive fhs send error. session close."
|
||||
, getpid(), szClientAddress, strHostname.c_str() );
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 전송 성공시
|
||||
_LOG( LDBG, "[SendInfo:%d] client[%s][%s] alive fhs send ok. fhs count[%zu]"
|
||||
, getpid(), szClientAddress, strHostname.c_str(), vecAliveFhs.size() );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정의되지 않은 command 인 경우..
|
||||
// - 오류 로깅 후 세션 종료 처리.
|
||||
LOG( LERR, "[SendInfo:%d] client[%s] request type not defined. session close.", getpid(), szClientAddress );
|
||||
clientSocket.PrintHeaderToLog();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// client 와 연결 종료 처리.
|
||||
clientSocket.Close();
|
||||
_LOG( LINF, "[SendInfo:%d] client connection closed. [%s]", getpid(), szClientAddress );
|
||||
|
||||
// Thread 종료 관련 처리.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Worker::SendInfo 프로세스의 Main 역활을 수행하기 위한 함수.
|
||||
int WorkerSendInfoMain()
|
||||
{
|
||||
// 전역 변수로 설정된 socket 중 해당 worker 에서 사용하지 않는 socket 은 close 처리한다.
|
||||
if( g_sockVmasdRecv != -1 )
|
||||
{
|
||||
close( g_sockVmasdRecv );
|
||||
g_sockVmasdRecv = -1;
|
||||
}
|
||||
if( g_sockSystemRecv != -1 )
|
||||
{
|
||||
close( g_sockSystemRecv );
|
||||
g_sockSystemRecv = -1;
|
||||
}
|
||||
if( g_sockCheckRecv != -1 )
|
||||
{
|
||||
close( g_sockCheckRecv );
|
||||
g_sockCheckRecv = -1;
|
||||
}
|
||||
|
||||
|
||||
// Process Rename..
|
||||
set_ps_display( PROG_NAME": SendInfo", false );
|
||||
|
||||
// Set Signal Handler
|
||||
SetWorkerSendInfoSignalHandler();
|
||||
|
||||
|
||||
// 사용할 객체 초기화 처리
|
||||
|
||||
// Alive FHS 목록을 주기적으로 추출할 Thread 모듈 초기화 및 기동 처리.
|
||||
CAliveFhsCacheThread threadAliveFhsCache( g_pShmManager );
|
||||
if( threadAliveFhsCache.Start() == false )
|
||||
{
|
||||
_LOG( LWAR, "[SendInfo:%d] alive fhs cache thread create failed. => Process Exit", getpid() );
|
||||
|
||||
ReadyToExitWorkerSendInfo();
|
||||
return EXIT_FAILURE; // EXIT_FAILURE 를 반환하여 재생성 처리 방지...
|
||||
}
|
||||
// 각 Client thread 에서 해당 객체 접근이 가능토록 전역 포인터에 저장 처리.
|
||||
g_pThreadAliveFhs = &threadAliveFhsCache;
|
||||
|
||||
|
||||
|
||||
// 접속 Client 에 대한 처리.
|
||||
int clientSock;
|
||||
struct sockaddr_in clientSockAddr;
|
||||
socklen_t clientSockLen = sizeof( clientSockAddr );
|
||||
|
||||
pthread_t clientThreadId;
|
||||
struct stSendInfoThreadArg * pThreadArg = NULL;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
clientSock = accept( g_sockInfoSend, ( struct sockaddr * ) &clientSockAddr, &clientSockLen );
|
||||
|
||||
if( clientSock == -1 )
|
||||
{
|
||||
// 오류 발생시.... 해당 내역 로깅 처리.
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "[SendInfo:%d] client accept failed [%d][%s]", getpid(), errorNum, strerror( errorNum ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상적인 Client 인 경우...
|
||||
// 처리 Thread 로 전달할 변수를 malloc 로 생성 처리
|
||||
pThreadArg = ( struct stSendInfoThreadArg * ) malloc( sizeof( struct stSendInfoThreadArg ) );
|
||||
if( pThreadArg == NULL )
|
||||
{
|
||||
int errorNum = errno;
|
||||
close( clientSock ); // client 접속 종료 처리.
|
||||
|
||||
char tempBuffer[IP_ADDR_LENGTH];
|
||||
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
|
||||
if( inet_ntop( AF_INET, &( clientSockAddr.sin_addr ), tempBuffer, sizeof( tempBuffer ) ) != NULL )
|
||||
{
|
||||
LOG( LERR, "[SendInfo:%d] client[%s] thread malloc failed [%d][%s]", getpid(), tempBuffer, errorNum, strerror( errorNum ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "[SendInfo:%d] client thread malloc failed [%d][%s] and inet_ntop error[%d][%s]"
|
||||
, getpid(), errorNum, strerror( errorNum ), errno, strerror( errno ) );
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 인자로 전달할 변수정보 설정.
|
||||
pThreadArg->clientSocketDesc = clientSock;
|
||||
|
||||
char tempBuffer[IP_ADDR_LENGTH];
|
||||
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
|
||||
if( inet_ntop( AF_INET, &( clientSockAddr.sin_addr ), tempBuffer, sizeof( tempBuffer ) ) != NULL )
|
||||
{
|
||||
memcpy( pThreadArg->szClientAddress, tempBuffer, sizeof( tempBuffer ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// inet_ntop 오류 발생시
|
||||
// - IP 정보는 그냥 로깅 목적등으로 전달되는 정보이므로.. 0.0.0.0 으로 설정 처리한다.
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "[SendInfo:%d] client ip not valid. inet_ntop error[%d][%s]", getpid(), errorNum, strerror( errorNum ) );
|
||||
snprintf( pThreadArg->szClientAddress, IP_ADDR_LENGTH - 1, "0.0.0.0" );
|
||||
}
|
||||
|
||||
// Client 처리를 담당할 Thread 생성 처리
|
||||
if( pthread_create( &clientThreadId, NULL, WorkerSendInfoClientThread, (void *)pThreadArg ) != 0 )
|
||||
{
|
||||
// 생성 실패시...
|
||||
// - 로깅
|
||||
// - client socket close
|
||||
// - malloc 로 생성된 전달 변수 free 처리.
|
||||
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "[SendInfo:%d] client[%s] thread create failed [%d][%s]"
|
||||
, getpid(), pThreadArg->szClientAddress, errorNum, strerror( errorNum ) );
|
||||
|
||||
close( clientSock );
|
||||
free( pThreadArg );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LDBG, "[SendInfo:%d] client[%s] accept & client thread create ok.", getpid(), pThreadArg->szClientAddress );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // while(1)
|
||||
|
||||
|
||||
// 종료시 정리 작업 수행
|
||||
ReadyToExitWorkerSendInfo();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/****************************************************************************
|
||||
Worker::SendInfo process main
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2015/06/03
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev Storage Team
|
||||
email : huibong@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.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __WORKER_SEND_INFO_H__
|
||||
#define __WORKER_SEND_INFO_H__
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Worker::SendInfo 프로세스의 Main 역활을 수행하기 위한 함수.
|
||||
int WorkerSendInfoMain( void );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __WORKER_SEND_INFO_H__ */
|
||||
|
||||
Reference in New Issue
Block a user