This commit is contained in:
biosvos
2026-08-07 17:38:18 +09:00
commit 873193a243
9613 changed files with 2755992 additions and 0 deletions
+699
View File
@@ -0,0 +1,699 @@
#include "AccountUpdateThread.h"
#include "DaemonConfigs.h"
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef __FreeBSD__
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#else // Linux
#include <mntent.h>
#include <sys/vfs.h>
#endif
using namespace std;
#define DEFAULT_QUERY_BUFFER_SIZE 1024
#define QUERY_LIMIT_COUNT 2000
static void string_lower2(char *buf)
{
int i;
for (i = 0; *(buf + i) != '\0'; i++) {
if (*(buf + i) >= 'A' && *(buf + i) <= 'Z') {
*(buf + i) = *(buf + i) + ('a' - 'A');
}
}
}
CAccountUpdateThread::CAccountUpdateThread()
{
m_pPgSQL = NULL;
// 멤버 변수 초기화
m_threadHandle = 0;
}
CAccountUpdateThread::~CAccountUpdateThread()
{
DbClose();
}
/// @brief DB 연결 함수.
bool CAccountUpdateThread::DbConnect()
{
if( m_pPgSQL != NULL )
{
DbClose();
}
m_pPgSQL = new DataBase;
if( m_pPgSQL == NULL )
{
LOG(LERR, "Creating new Database has failed.");
return false;
}
if( m_pPgSQL->PgOpenDB(m_szHost, m_nPort, m_szDBName, m_szAcct, m_szPasswd) == NULL )
{
LOG(LERR, "Connecting to Database has failed.");
DbClose();
return false;
}
return true;
}
/// @breif DB close 함수.
void CAccountUpdateThread::DbClose()
{
if( m_pPgSQL != NULL )
{
m_pPgSQL->PgClear();
delete m_pPgSQL;
m_pPgSQL = NULL;
}
}
bool CAccountUpdateThread::ThreadInit(const sig_atomic_t *sighandle, CSharedMem* pShmemAccount)
{
m_sighandle = sighandle;
m_pShmemAccount = pShmemAccount;
m_szHost = CDeamonConfig::GetInstance()->GetDBInfo().m_szRcdbIp;
m_nPort = CDeamonConfig::GetInstance()->GetDBInfo().m_nRcdbPort;
m_szDBName = CDeamonConfig::GetInstance()->GetDBInfo().m_szRcdbName;
m_szAcct = CDeamonConfig::GetInstance()->GetDBInfo().m_szRcdbAcct;
m_szPasswd = CDeamonConfig::GetInstance()->GetDBInfo().m_szRcdbAcctPw;
m_szStorageRoot = CDeamonConfig::GetInstance()->GetFileStorageRoot();
// 최초 초기화 시에는 DB연결 정보들이 제대로 되는것인지에 대한
// 확인만 처리 한다.
if (DbConnect() == false )
{
LOG(LERR, "Connecting to Database has failed. Check your configuration or RCDB.");
return false;
}
// 접속 성공한 경우...
LOG( LINF, "RCDB connection ok..." );
// DB연결 test 후 정리 한다.
DbClose();
return true;
}
void CAccountUpdateThread::printShredMemory()
{
struct account* pSharedHeader = (struct account*)m_pShmemAccount->GetData();
int nMaxAccout = CDeamonConfig::GetInstance()->GetMaxAccount();
for(int i = 0; i < nMaxAccout; i++ )
{
// shared memory의 끝이면 종료...
if( (pSharedHeader + i)->id[0] == '\0' )
{
LOG(LDBG, "Account Shared Memory End. [index: %d, %d]", i, (int)m_mapAccount.size() );
break;
}
struct account* pCurAccount = (pSharedHeader + i);
printac(pCurAccount);
}
}
void CAccountUpdateThread::printac(struct account *pAc)
{
LOG(LDBG, "xxxxx Account Shared Memory xxxxx");
_LOG(LDBG, " seq: %s", pAc->seq);
_LOG(LDBG, " id: %s", pAc->id);
_LOG(LDBG, " svc_id: %s", pAc->svc_id);
_LOG(LDBG, " pass: %s", pAc->pass);
_LOG(LDBG, " tran_id: %s", pAc->tran_id);
_LOG(LDBG, " iv: %s", pAc->iv);
_LOG(LDBG, " pk : %s", pAc->pk);
_LOG(LDBG, " tc_percentx: %d", pAc->tc_percent);
_LOG(LDBG, " tc_session: %d", pAc->tc_session);
_LOG(LDBG, " nFlag: %d", pAc->nFlag);
}
bool CAccountUpdateThread::GetData()
{
char szQuery[DEFAULT_QUERY_BUFFER_SIZE];
bool is_user_auth = false, is_referer_chk = false;
m_mapAccount.clear();
if( m_pPgSQL == NULL )
{
LOG(LWAR, "PgSQL is not initialized.");
return false;
}
snprintf(szQuery, DEFAULT_QUERY_BUFFER_SIZE - 1,
"SELECT a.sp_user_seq, b.sp_svc_tran_id, a.sp_user_password, b.initial_vector, b.private_key, "
"a.sp_user_id, b.validate_sp_session_id_yn, b.bandwidth_ctrl_yn, b.referer_chk_yn, b.sp_svc_id, b.uri_ignore_case, "
"c.auth_server, c.auth_path, c.auth_port, c.bill_server, c.bill_path, c.bill_port, c.auth_timeout, "
"c.bill_timeout, c.mode, c.referer_chk_url, c.referer_chk_filetype "
"FROM t_sms_sp_user AS a "
"INNER JOIN t_sms_sp_svc_product AS b "
"ON a.sp_user_seq = b.sp_user_seq "
"LEFT JOIN t_sms_sp_svc_product_val c "
"ON b.sp_svc_tran_id = c.sp_svc_tran_id "
);
// Query 실행
if( m_pPgSQL->PgDoExec(szQuery) < 0)
{
// 재연결 되도록 조치 해야한다.
LOG( LERR, "RCDB error.[%s][%s]", m_pPgSQL->GetErrorMessage().c_str(), szQuery );
return false;
}
// RCDB로부터 얻은 정보들을 Map에 등록한다.
for( int i = 0; i < m_pPgSQL->GetNoTuples(); i++ )
{
struct account ac;
memset(&ac, 0x00, sizeof(ac));
strncpy(ac.seq, m_pPgSQL->GetValue(i, 0), MaxSizeOfUserSeq - 1);
strncpy(ac.tran_id, m_pPgSQL->GetValue(i, 1), MaxSizeOfUserTranID - 1);
strncpy(ac.pass, m_pPgSQL->GetValue(i, 2), MaxSizeOfUserPassword - 1);
string_lower2(ac.pass);
strncpy(ac.iv, m_pPgSQL->GetValue(i, 3), MaxSizeOfUserIV - 1);
strncpy(ac.pk, m_pPgSQL->GetValue(i, 4), MaxSizeOfUserPK - 1);
strncpy(ac.id, m_pPgSQL->GetValue(i, 5), MaxSizeOfUserID - 1);
is_user_auth = (*((char *)m_pPgSQL->GetValue(i, 6)) == 'Y');
//is_band_ctrl = (*((char *)m_pPgSQL->GetValue(i, 7)) == 'Y');
is_referer_chk = (*((char *)m_pPgSQL->GetValue(i, 8)) == 'Y');
strncpy(ac.svc_id, (char *)m_pPgSQL->GetValue(i, 9), MaxSizeOfSvcID - 1);
ac.is_ignorecase = (*((char *)m_pPgSQL->GetValue(i, 10)) == 'Y');
if (is_user_auth)
{
strncpy(ac.auth_addr, m_pPgSQL->GetValue(i, 11),
MaxSizeOfUserAuthAddr - 1);
ac.auth_addr[MaxSizeOfUserAuthAddr - 1] = '\0';
strncpy(ac.auth_uri, m_pPgSQL->GetValue(i, 12),
MaxSizeOfUserAuthUri - 1);
ac.auth_uri[MaxSizeOfUserAuthUri - 1] = '\0';
ac.auth_port = atoi(m_pPgSQL->GetValue(i, 13));
strncpy(ac.bill_addr, m_pPgSQL->GetValue(i, 14),
MaxSizeOfUserAuthAddr - 1);
ac.bill_addr[MaxSizeOfUserAuthAddr - 1] = '\0';
strncpy(ac.bill_uri, m_pPgSQL->GetValue(i, 15),
MaxSizeOfUserAuthUri - 1);
ac.bill_uri[MaxSizeOfUserAuthUri - 1] = '\0';
ac.bill_port = atoi(m_pPgSQL->GetValue(i, 16));
ac.auth_timeout = atoi(m_pPgSQL->GetValue(i, 17));
ac.bill_timeout = atoi(m_pPgSQL->GetValue(i, 18));
strncpy(ac.mode, m_pPgSQL->GetValue(i, 19),
MaxSizeOfUserAuthMode - 1);
ac.mode[MaxSizeOfUserAuthMode - 1] = '\0';
if (is_referer_chk) {
strncpy(ac.permitted_referer,
m_pPgSQL->GetValue(i, 20),
MaxSizeOfPermittedReferer - 1);
ac.permitted_referer[MaxSizeOfPermittedReferer - 1] = '\0';
strncpy(ac.permitted_extend,
m_pPgSQL->GetValue(i, 21),
MaxSizeOfPermittedReferer - 1);
ac.permitted_extend[MaxSizeOfPermittedReferer - 1] = '\0';
}
}
// 모든 데이타를 수집했으므로...
// Map에 등록 처리 한다.
ac.nFlag = 0;
string szSeq = ac.seq;
string szTranId = ac.tran_id;
string szMapKey = szSeq + szTranId;
m_mapAccount.insert( std::pair<string, struct account>( szMapKey, ac) );
}
m_pPgSQL->PgClear();
std::map<string, struct account>::iterator it;
for (it=m_mapAccount.begin(); it!=m_mapAccount.end(); ++it)
{
struct account *pAc = &(it->second);
m_pPgSQL->PgClear();
snprintf(szQuery, DEFAULT_QUERY_BUFFER_SIZE - 1,
"SELECT sb.volume_bandwidth_control_current, "
"sb.session_bandwidth_limit, s.bandwidth_ctrl_yn "
"FROM t_sms_sp_svc_product_band AS sb "
" LEFT JOIN t_sms_sp_svc_product AS s ON s.sp_svc_tran_id = sb.sp_svc_tran_id "
"WHERE sb.sp_svc_tran_id = %s ", pAc->tran_id );
// Query 실행
if( m_pPgSQL->PgDoExec(szQuery) < 0)
{
// 재연결 되도록 조치 해야한다.
LOG( LERR, "RCDB error.[%s][%s]", m_pPgSQL->GetErrorMessage().c_str(), szQuery );
return false;
}
if( m_pPgSQL->GetNoTuples() > 1)
{
// 두 개이상의 tuple이 있어서는 안된다.
LOG( LWAR, "Check your t_sms_sp_svc_product_band table.[TranID: %s]", pAc->tran_id);
}
else if( m_pPgSQL->GetNoTuples() == 1 )
{
if( *((char *)m_pPgSQL->GetValue(0, 2)) == 'N')
{
pAc->tc_percent = pAc->tc_session = 0;
}
else
{
pAc->tc_percent = atoi( m_pPgSQL->GetValue(0, 0) );
pAc->tc_session = atoi( m_pPgSQL->GetValue(0, 1) ) / 8;
}
}
else
{
pAc->tc_percent = pAc->tc_session = 0;
}
}
m_pPgSQL->PgClear();
return true;
}
bool CAccountUpdateThread::GetSystmeMountInfo()
{
// 추출된 Mount 정보 저장 객체 초기화.
std::string szMountName;
m_vecMount.clear();
// statfs 구조체 정보.
// struct statfs {
// char f_mntonname[88]; /* directory on which mounted */
// int64_t f_bavail; /* free blocks avail to non-superuser */
// uint64_t f_bsize; /* filesystem fragment size */
// ..
// }
// => uint64_t = unsigned long long => 0 ~ 18,446,744,073,709,551,615 범위 가짐.
// FreeBSD 에서만.. getmntinfo 함수를 지원..
// 향후 Linux Migration 을 대비하기 위해 OS 별 코드 추가한다.
#ifdef __FreeBSD__
// Mount 정보를 추출하기 위한 변수 초기화.
int nMountCount = 0;
struct statfs * pStatFsBuf = NULL;
// Mount 정보 추출...
// getmntinfo 특성상.. 할당된 메모리를 application 에서 해제시키면 안되므로 주의할 것.
nMountCount = getmntinfo( &pStatFsBuf, MNT_WAIT );
if( nMountCount == 0 )
{
// Mount 정보 추출 실패시.. 오류 처리한다.
int errorNum = errno;
LOG( LERR, "system getmntinfo function return failed. [%d][%s]", errorNum, strerror(errorNum) );
return false;
}
for( int i = 0 ; i < nMountCount ; i++ )
{
szMountName = pStatFsBuf[i].f_mntonname;
m_vecMount.push_back( szMountName );
// 시스템에서 Mount 정보 추출시 유효 용량에 대한 임계치 검사를 수행할 경우....
// 아래 코드에서 운영자가 설정한 Mount 정보 추출이 실패.. 잘못된 경로상에 Content 저장이 발생할 수 있으므로.. 임계치 검사를 수해하지 않는다.
}
#else // Linux 인 경우...
FILE * fp = NULL;
struct mntent stMnt;
struct mntent * pMnt;
char tempBuf[512];
fp = setmntent( "/etc/mtab", "r");
if( fp != NULL )
{
while( (pMnt = getmntent_r( fp, &stMnt, tempBuf, sizeof(tempBuf))) != NULL )
{
struct statfs statFsBuf;
if( (stMnt.mnt_dir != NULL) && (statfs( stMnt.mnt_dir, &statFsBuf ) == 0 ) )
{
szMountName = stMnt.mnt_dir;
m_vecMount.push_back( szMountName );
}
}
// open 된 fp close 처리.
endmntent( fp );
}
#endif
// 추출된 결과 확인...
if( m_vecMount.empty() == true )
{
// 추출된 system Mount 정보가 없는 경우..
LOG( LERR, "system mount info empty. check mount info." );
return false;
}
return true;
}
std::vector<std::string> CAccountUpdateThread::GetMountNodeInfo()
{
std::vector<std::string> vecTempMount;
std::vector<std::string>::iterator it;
for( it = m_vecMount.begin(); it < m_vecMount.end(); it++ )
{
std::string szMountName = *it;
if( strcmp( m_szStorageRoot.c_str(), szMountName.c_str() ) == 0 )
{
LOG(LDBG, "Mount Name : %s, %s", szMountName.c_str(), m_szStorageRoot.c_str() );
vecTempMount.push_back( szMountName );
}
}
if( vecTempMount.empty() == true )
{
// 최초 비교시에는 원래 정보를 가지고 부분 비교처리.. (/stg 등으로 설정된 경우를 위해)
std::string strPreviousPath = m_szStorageRoot;
std::string strCurrentPath = m_szStorageRoot;
do
{
// 수정된 경로 정보만을 가지고 부분 비교를 수행....
for( it = m_vecMount.begin(); it < m_vecMount.end(); it++ )
{
std::string szMountName = *it;
// 부분 비교 처리
if( strncmp( strCurrentPath.c_str(), szMountName.c_str(), strlen(strCurrentPath.c_str()) ) == 0 )
{
LOG(LDEV, "Mount Name : %s", szMountName.c_str() );
vecTempMount.push_back( szMountName );
}
}
// 위에서 정보 추출이 실패한 경우..상위 Path 정보를 추출한다. ( /user2/dav_storage, /stg/node0/aa/bb 등으로 설정된 경우를 위해 )
if( vecTempMount.empty() == true )
{
GetUpperPath( strPreviousPath, strCurrentPath );
if( strCurrentPath.empty() == true )
{
break;
}
strPreviousPath = strCurrentPath;
}
} while( vecTempMount.empty() == true );
}
return vecTempMount;
}
// 전달받은 경로로부터.. 상위 Path 정보를 추출하여 전달한다.
// 오류 발생시 [out] 값인 strUpperPath 가 empty 된다.
void CAccountUpdateThread::GetUpperPath( const std::string & strSourcePath, std::string & strUpperPath )
{
// 인자로 전달되는 strSourcePath 끝에.. '/' 가 이미 제거되었다고 판단하고 작업을 수행한다.
std::string::size_type pos = strSourcePath.rfind( '/' );
if( pos == std::string::npos )
{
// 찾지 못한 경우...
// out 값을 empty 처리시킨다.
LOG( LNOT, "upper path not found. source[%s]", strSourcePath.c_str());
strUpperPath.clear();
return;
}
// 찾은 경우..
strUpperPath = strSourcePath.substr(0, pos);
// 추출된 경로가... 최상위 '/' 인 경우.. 유효하지 않으므로 오류로 처리한다.
if( strcmp( strUpperPath.c_str(), "/") == 0 )
{
LOG( LNOT, "upper path not vaild that root path. [%s]", strUpperPath.c_str() );
strUpperPath.clear();
}
return;
}
void CAccountUpdateThread::MakeServiceFolder()
{
std::vector<std::string>::iterator itM;
std::map<std::string, struct account>::iterator itT;
// 수정된 경로 정보만을 가지고 부분 비교를 수행....
for( itM = m_vecMountNodeInfo.begin(); itM != m_vecMountNodeInfo.end(); itM++ )
{
std::string szMountName = *itM;
for( itT = m_mapAccount.begin(); itT != m_mapAccount.end(); itT++ )
{
std::string szServiceID= itT->second.tran_id;
LOG( LDEV, "ServiceID [%s]", szServiceID.c_str() );
std::string szServicePath = szMountName + '/' + szServiceID;
if ((mkdir(szServicePath.c_str(), 0777)) == 0 )
{
_LOG( LINF, "Created service path [%s]", szServicePath.c_str() );
chown(szServicePath.c_str(), 65534, 65534);
}
else
{
// 기존에 존재해서 나는 에러는 제외 하고 ERR로 처리 한다.
if ( errno != 17 )
{
LOG( LERR, "[%s] is make failed. %d, %s", szServicePath.c_str(), errno, strerror(errno) );
}
}
}
}
_LOG( LINF, "Complete service folder creation and verification");
}
void CAccountUpdateThread::UpdateSharedMemory()
{
struct account* pSharedHeader = (struct account*)m_pShmemAccount->GetData();
int nIndex = 0;
int nMaxAccout = CDeamonConfig::GetInstance()->GetMaxAccount();
// 공유 메모리 기준으로
// Maxcount는 설정 값에서 갖고 온다.
_LOG(LINF, "xxxxx Account Shared Memory xxxxx");
for(int i = 0; i < nMaxAccout; i++ )
{
// 끝이면???
if( (pSharedHeader + i)->id[0] == '\0' )
{
LOG(LDBG, "Account Shared Memory End. [index: %d, %d]", i, (int)m_mapAccount.size() );
// 맵에 데이터가 남을 경우 해당 인덱스부터 추가해 주기 위해 저장한다.
nIndex = i;
break;
}
struct account* pCurAccount = (pSharedHeader + i);
// 맵 키 생성
string szSeq = pCurAccount->seq;
string szTranId = pCurAccount->tran_id;
string szMapKey = szSeq + szTranId;
// 맵에서 해당 데이터를 찾는다.
std::map<string, struct account>::iterator it;
it = m_mapAccount.find(szMapKey);
if( it == m_mapAccount.end() )
{
// 맵에서 데이터를 못찾았다면, 삭제된 서비스라고 판단한다.
pCurAccount->nFlag = 1;
_LOG(LNOT, "%s@%s is deleted.", pCurAccount->svc_id, pCurAccount->id);
continue;
}
struct account ac = it->second;
memcpy(pCurAccount, &ac, sizeof(struct account));
_LOG(LINF, "id: %s, svc_id: %s, tran_id: %s "
, (pSharedHeader + i)->id, (pSharedHeader + i)->svc_id, (pSharedHeader + i)->tran_id );
_LOG(LINF, " tc_percentx: %d, tc_session: %d, nFlag: %d", (pSharedHeader + i)->tc_percent, (pSharedHeader + i)->tc_session, (pSharedHeader + i)->nFlag);
// 맵에서 삭제
m_mapAccount.erase(it);
}
// 맵에 데이터가 남았는지 체크 한다.
if( m_mapAccount.size() <= 0 )
return;
// 맵에 데이터가 남았다면... 신규로 개통된 서비스가 있다는 뜻이므로 이를 shared 메모리에 등록한다.
// shared 메모리의 맨 마지막 인덱스(nIndex)부터 사용한다.
std::map<string, struct account>::iterator it;
for (it=m_mapAccount.begin(); it!=m_mapAccount.end(); ++it, ++nIndex)
{
if( nIndex >= nMaxAccout )
{
LOG(LWAR, "Account shared memory is full.[MaxCount: %d]", nMaxAccout);
break;
}
struct account ac = it->second;
_LOG(LINF, "Account Add [Index: %d] [id: %s][svc: %s]", nIndex, ac.id, ac.svc_id);
memcpy((pSharedHeader + nIndex), &ac, sizeof(struct account));
}
m_mapAccount.clear();
}
///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CAccountUpdateThread::Execute()
{
// 최초라서 실패 하더라도 아래 로직에서 reconnect가 진행 됨.
DbConnect();
// 최초 구동시 한번은 갱신 되도록 하기위한 변수
bool bFirst = true;
time_t currentTime; // 현재 시간 정보를 저장하기 위한 변수..
unsigned long nowTimestamp;
unsigned long lastUpdateTimestamp = 0; // shard memory 마지막 갱신 timestamp 값 (5분단위)
int nRetryCount = 0;
while (*m_sighandle == 0)
{
// 현재 시간 정보 추출..
currentTime = time(0);
// 현재 timestamp 값을 계산한다...
// (20초마다 갱신위해)19 sec 보정 처리하여 5분 단위 timestamp 값을 추출한다.
nowTimestamp = (currentTime - 19 + 299) / 300;
// 시간 동기화 이상으로 reset 처리된 경우... lastSendTimestamp = 0
if (!bFirst && lastUpdateTimestamp == 0)
{
lastUpdateTimestamp = nowTimestamp;
sleep(1);
continue;
}
// 마지막 timestamp 값과 현재 timestamp 계산 값이 같은 경우...
// 이미 갱신 것으로 판단하고.. 쉰다.
if (nowTimestamp == lastUpdateTimestamp)
{
sleep(1);
continue;
}
// 만약 lastSendTimestamp > nowTimestamp 인 경우...
// - 시간 동기화 이상으로 이전에 계산된 timestamp 값이 잘못된 경우.... 보정처리..
if (nowTimestamp < lastUpdateTimestamp)
{
_LOG(LWAR, "Account Update Thread : Last timestamp not valid. skip and reset. now[%lu] last[%lu]", nowTimestamp, lastUpdateTimestamp);
lastUpdateTimestamp = 0;
sleep(10);
continue;
}
bFirst = false;
if ( GetData() )
{
do
{
// 마운트 정보를 정상적으로 가져온 경우만 서비스 폴더 생성
if (GetSystmeMountInfo() == false)
{
break;
}
m_vecMountNodeInfo = GetMountNodeInfo();
if (m_vecMountNodeInfo.empty() == true)
{
LOG(LERR, "Not found file storage root. conf path[%s]", m_szStorageRoot.c_str());
break;
}
MakeServiceFolder();
} while (0);
UpdateSharedMemory();
lastUpdateTimestamp = nowTimestamp;
printShredMemory();
}
else
{
DbConnect();
// 3회 재시도...
nRetryCount++;
if (nRetryCount >= 3)
{
lastUpdateTimestamp = nowTimestamp;
nRetryCount = 0;
}
// 5초 후 재시도
if (*m_sighandle == 0)
sleep(5);
}
nRetryCount = 0;
}
// 쓰레드 종료 될 때 DB 세션 정리 한다.
DbClose();
}
void* CAccountUpdateThread::EntryPoint(void* arg)
{
CAccountUpdateThread* pObject = reinterpret_cast<CAccountUpdateThread *>(arg);
pthread_detach( pthread_self() );
pObject->Execute();
// Thread 종료시 m_threadHandle 값을 초기화 처리.
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
pObject->m_threadHandle = 0;
return 0;
}
bool CAccountUpdateThread::Start()
{
int nRet = ::pthread_create(&m_threadHandle, 0, CAccountUpdateThread::EntryPoint, this);
if( nRet )
{
LOG(LERR, "Account thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Account thread create succeed");
sleep(0);
return true;
}
+99
View File
@@ -0,0 +1,99 @@
/***************************************************************************
Replicate Work Class
-----------------------------------------
begin : 2012/10/14
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 __ACCOUNT_UPDATE_THREAD__
#define __ACCOUNT_UPDATE_THREAD__
#include </usr/include/sys/signal.h>
#include <csignal>
#include <pthread.h>
#include <string>
#include <map>
#include "Logger.h"
#include "Database.h"
#include "FimngdData.h"
#include "SharedMemAPR.h"
// 시스템에서 추출된 Mount 정보를 저장하기 위한 struct...
struct systme_mount_info {
std::string mount_name; // Mount Name..
unsigned long long available_byte; // available byte
};
/// @brief
class CAccountUpdateThread
{
public:
/// @brief 생성자
/// @param [in] pLogger 로깅을 위한 클래스.
CAccountUpdateThread();
~CAccountUpdateThread();
void printac(struct account *pAc);
void printShredMemory();
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공은 return true 실패는 return false
bool Start();
bool DbConnect();
void DbClose();
bool GetData();
void MakeServiceFolder();
void UpdateSharedMemory();
/// @brief ProcessStatus 내의 RCDB 관련 설정값을 이용해 DB Connection을 한다.
/// @param sighandle 쓰레드에서 signal에 따라 정상 종료하도록 signal handle을 전달한다.
/// @param pShmemAccount 공유메모리 포인터
/// @return 성공하면 return true 실패하면 return false
bool ThreadInit(const sig_atomic_t *sighandle, CSharedMem* pShmemAccount);
// 서비스 폴더 생성을 위한 함수와 변수들
private:
bool GetSystmeMountInfo();
void GetUpperPath( const std::string & strSourcePath, std::string & strUpperPath );
std::vector<std::string> GetMountNodeInfo();
// systme 에서 추출된 mount 상태 정보를 저장하기 위한 vector 변수
std::vector<std::string> m_vecMount;
std::vector<std::string> m_vecMountNodeInfo;
std::string m_szStorageRoot;
// Attributes
private:
DataBase* m_pPgSQL;
std::string m_szHost;
int m_nPort;
std::string m_szDBName;
std::string m_szAcct;
std::string m_szPasswd;
// 쓰레드 핸들
pthread_t m_threadHandle;
const sig_atomic_t *m_sighandle;
CSharedMem* m_pShmemAccount;
std::map<std::string, struct account> m_mapAccount;
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
// 해당 함수의 내용은 수정하지 말것.
void Execute();
};
#endif //__ACCOUNT_UPDATE_THREAD__
+272
View File
@@ -0,0 +1,272 @@
#include "AnonyUpdateThread.h"
#include "DaemonConfigs.h"
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <sys/time.h>
using namespace std;
#define DEFAULT_QUERY_BUFFER_SIZE 1024
#define QUERY_LIMIT_COUNT 2000
#define UPDATE_TERM 180
#define ANONY_SEPARATOR "@"
CAnonyUpdateThread::CAnonyUpdateThread()
{
m_pPgSQL = NULL;
// 멤버 변수 초기화
m_threadHandle = 0;
}
CAnonyUpdateThread::~CAnonyUpdateThread()
{
DbClose();
}
/// @brief DB 연결 함수.
bool CAnonyUpdateThread::DbConnect()
{
if( m_pPgSQL != NULL )
{
DbClose();
}
m_pPgSQL = new DataBase;
if( m_pPgSQL == NULL )
{
LOG(LERR, "Creating new Database has failed.");
return false;
}
if( m_pPgSQL->PgOpenDB(m_szHost, m_nPort, m_szDBName, m_szAcct, m_szPasswd) == NULL )
{
LOG(LERR, "Connecting to Database has failed.");
DbClose();
return false;
}
return true;
}
/// @breif DB close 함수.
void CAnonyUpdateThread::DbClose()
{
if( m_pPgSQL != NULL )
{
m_pPgSQL->PgClear();
delete m_pPgSQL;
m_pPgSQL = NULL;
}
}
bool CAnonyUpdateThread::ThreadInit(const sig_atomic_t *sighandle, CSharedMem* pShmemAnony)
{
m_sighandle = sighandle;
m_pShmemAnony = pShmemAnony;
m_szHost = CDeamonConfig::GetInstance()->GetDBInfo().m_szRcdbIp;
m_nPort = CDeamonConfig::GetInstance()->GetDBInfo().m_nRcdbPort;
m_szDBName = CDeamonConfig::GetInstance()->GetDBInfo().m_szRcdbName;
m_szAcct = CDeamonConfig::GetInstance()->GetDBInfo().m_szRcdbAcct;
m_szPasswd = CDeamonConfig::GetInstance()->GetDBInfo().m_szRcdbAcctPw;
// 최초 초기화 시에는 DB연결 정보들이 제대로 되는것인지에 대한
// 확인만 처리 한다.
if (DbConnect() == false )
{
LOG(LERR, "Connecting to Database has failed. Check your configuration or RCDB.");
return false;
}
// 접속 성공한 경우...
_LOG( LINF, "CAnonyUpdate... RCDB connection ok..." );
// DB연결 test 후 정리 한다.
DbClose();
return true;
}
bool CAnonyUpdateThread::GetData()
{
char szQuery[DEFAULT_QUERY_BUFFER_SIZE];
if( m_pPgSQL == NULL )
{
LOG(LWAR, "PgSQL is not initialized.");
return false;
}
snprintf(szQuery, DEFAULT_QUERY_BUFFER_SIZE - 1,
"SELECT a.sp_svc_id, b.uri "
"FROM t_dav_anonymous AS b "
"INNER JOIN t_sms_sp_svc_product AS a "
"ON b.sp_svc_tran_id = a.sp_svc_tran_id "
);
// Query 실행
if( m_pPgSQL->PgDoExec(szQuery) < 0)
{
// 재연결 되도록 조치 해야한다.
LOG( LERR, "RCDB error.[%s][%s]", m_pPgSQL->GetErrorMessage().c_str(), szQuery );
return false;
}
// RCDB로부터 얻은 정보들을 Map에 등록한다.
for( int i = 0; i < m_pPgSQL->GetNoTuples(); i++ )
{
struct anonymous stAnony;
memset(&stAnony, 0x00, sizeof(stAnony));
strncpy(stAnony.domain, m_pPgSQL->GetValue(i, 0), DOMAIN_SIZE - 1);
strncpy(stAnony.uri, m_pPgSQL->GetValue(i, 1), URI_SIZE_MAX - 1);
// 2016.01.18 dadamin
// 다른 서비스 간 동일한 디렉토리 무인증 설정 지원
string skey = stAnony.domain;
skey += ANONY_SEPARATOR;
skey += stAnony.uri;
// 맵에 등록 처리
m_mapAnony.insert(std::pair<string, struct anonymous>(skey, stAnony));
}
m_pPgSQL->PgClear();
return true;
}
void CAnonyUpdateThread::UpdateSharedMemory()
{
struct anonymous* pSharedHeader = (struct anonymous*)m_pShmemAnony->GetData();
int nIndex = 0;
int nMax = CDeamonConfig::GetInstance()->GetMaxAnonyMous();
// 공유 메모리 기준으로
// Maxcount는 설정 값에서 갖고 온다.
for(int i = 0; i < nMax; i++ )
{
// 끝이면???
if( (pSharedHeader + i)->uri[0] == '\0' )
{
LOG(LDBG, "Shared Memory End. [index: %d, %d]", i, (int)m_mapAnony.size());
// 맵에 데이터가 남을 경우 해당 인덱스부터 추가해 주기 위해 저장한다.
nIndex = i;
break;
}
struct anonymous* pCurAnony = (pSharedHeader + i);
// 2016.01.18 dadamin
// 다른 서비스 간 동일한 디렉토리 무인증 설정 지원
string skey = pCurAnony->domain;
skey += ANONY_SEPARATOR;
skey += pCurAnony->uri;
// 맵에서 해당 데이터를 찾는다.
std::map<string, struct anonymous>::iterator it;
it = m_mapAnony.find(skey);
if( it == m_mapAnony.end() )
{
// 맵에서 데이터를 못찾았다면, 무인증에서 인증으로 변경된 것이라고 판단한다.
pCurAnony->nFlag = 1;
continue;
}
struct anonymous anony = it->second;
memcpy(pCurAnony, &anony, sizeof(struct anonymous));
_LOG(LINF, "Anony update [Service: %s] [uri: %s] ", anony.domain, anony.uri);
// 맵에서 삭제
m_mapAnony.erase(it);
}
// 맵에 데이터가 남았는지 체크 한다.
if( m_mapAnony.size() <= 0 )
return;
// 맵에 데이터가 남았다면... 신규로 추가된 무인증 폴더가 있다는 뜻이므로 이를 shared 메모리에 등록한다.
// shared 메모리의 맨 마지막 인덱스(nIndex)부터 사용한다.
std::map<string, struct anonymous>::iterator it;
for (it=m_mapAnony.begin(); it!=m_mapAnony.end(); ++it, ++nIndex)
{
if( nIndex >= nMax )
{
LOG(LWAR, "Anony shared memory is full.[MaxCount: %d]", nMax);
break;
}
struct anonymous anony = it->second;
_LOG(LINF, "Anony Add [Service: %s] [uri: %s] ", anony.domain, anony.uri);
memcpy((pSharedHeader + nIndex), &anony, sizeof(struct anonymous));
}
m_mapAnony.clear();
}
///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CAnonyUpdateThread::Execute()
{
// 최초라서 실패 하더라도 아래 로직에서 reconnect가 진행 됨.
DbConnect();
int nCount = 0;
while (*m_sighandle == 0)
{
// job을 실행한다.
if( GetData() == false )
{
DbConnect();
// 3회 재시도...
nCount++;
if( nCount >= 3 )
{
nCount = 0;
}
// 5초 후 재시도
if (*m_sighandle == 0)
sleep(5);
continue;
}
UpdateSharedMemory();
nCount = 0;
sleep(UPDATE_TERM);
}
// 쓰레드 종료 될 때 DB 세션 정리 한다.
DbClose();
LOG(LINF, "Thread end...");
}
void* CAnonyUpdateThread::EntryPoint(void* arg)
{
CAnonyUpdateThread* pObject = reinterpret_cast<CAnonyUpdateThread *>(arg);
pthread_detach( pthread_self() );
pObject->Execute();
// Thread 종료시 m_threadHandle 값을 초기화 처리.
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
pObject->m_threadHandle = 0;
return 0;
}
bool CAnonyUpdateThread::Start()
{
int nRet = ::pthread_create(&m_threadHandle, 0, CAnonyUpdateThread::EntryPoint, this);
if( nRet )
{
LOG(LERR, "Anony thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Anony thread create succeed");
sleep(0);
return true;
}
+76
View File
@@ -0,0 +1,76 @@
/***************************************************************************
Replicate Work Class
-----------------------------------------
begin : 2012/10/14
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 __ANONY_UPDATE_THREAD__
#define __ANONY_UPDATE_THREAD__
#include <pthread.h>
#include <string>
#include <map>
#include "Logger.h"
#include "Database.h"
#include "FimngdData.h"
#include "SharedMemAPR.h"
/// @brief
class CAnonyUpdateThread
{
public:
/// @brief 생성자
CAnonyUpdateThread();
~CAnonyUpdateThread();
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공은 return true 실패는 return false
bool Start();
bool DbConnect();
void DbClose();
bool GetData();
/// @brief ProcessStatus 내의 RCDB 관련 설정값을 이용해 DB Connection을 한다.
/// @param sighandle 쓰레드에서 signal에 따라 정상 종료하도록 signal handle을 전달한다.
/// @param pShmemAnony 공유메모리 포인터
/// @return 성공하면 return true 실패하면 return false
bool ThreadInit(const sig_atomic_t *sighandle, CSharedMem* pShmemAnony);
void UpdateSharedMemory();
// Attributes
private:
DataBase* m_pPgSQL;
std::string m_szHost;
int m_nPort;
std::string m_szDBName;
std::string m_szAcct;
std::string m_szPasswd;
// 쓰레드 핸들
pthread_t m_threadHandle;
const sig_atomic_t *m_sighandle;
CSharedMem* m_pShmemAnony;
std::map<std::string, struct anonymous> m_mapAnony;
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
// 해당 함수의 내용은 수정하지 말것.
void Execute();
};
#endif //__ANONY_UPDATE_THREAD__
+169
View File
@@ -0,0 +1,169 @@
/***************************************************************************
Argument Parser Class (ArgParser.cpp)
-----------------------------------------
begin : 2013/02/13
copyright : (C) 2013 Solbox Inc.
author : Development 1 Team
- 2013/02/13 - 1st dadamin
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "ArgParser.h"
#include <unistd.h>
CArgParser::CArgParser(int argc, char** argv)
{
for (int i=1; i<argc; i++)
{
#ifdef _DEBUG
cout << "arg i = " << i << "," << argv[i] << endl;
#endif // _DEBUG
m_args.push_back(argv[i]);
}
}
CArgParser::~CArgParser()
{
m_args.clear();
}
void CArgParser::dashes2underscores(const char *input, char *output)
{
char c = 0;
char *o = output;
const char *i = input;
// first two characters are copied as-is
*o = *i++;
if (*o++ == '\0')
return;
*o = *i++;
if (*o++ == '\0')
return;
for (; ((c = *i)); ++i)
{
if (c == '=')
{
strcpy(o, i);
return;
}
if (c == '-')
*o++ = '_';
else
*o++ = c;
}
*o++ = '\0';
}
bool CArgParser::parsewitharg(vector<char*>::iterator &i, std::string *ret, va_list ap)
{
const char *first = *i;
char tmp[strlen(first)+1];
dashes2underscores(first, tmp);
first = tmp;
const char *a;
int strlen_a;
// does this argument match any of the possibilities?
while (1)
{
a = va_arg(ap, char*);
if (a == NULL)
return false;
strlen_a = strlen(a);
char a2[strlen_a+1];
dashes2underscores(a, a2);
if (strncmp(a2, first, strlen(a2)) == 0)
{
if (first[strlen_a] == '=')
{
*ret = first + strlen_a + 1;
i = m_args.erase(i);
return true;
}
else if (first[strlen_a] == '\0')
{
// find second part (or not)
if (i+1 == m_args.end())
{
cerr << "[error] Option " << *i << " requires an argument." << std::endl;
_exit(EXIT_FAILURE);
}
i = m_args.erase(i);
*ret = *i;
i = m_args.erase(i);
return true;
}
}
}
return false;
}
bool CArgParser::argparseflag(vector<char*>::iterator &i, ...)
{
const char *first = *i;
char tmp[strlen(first)+1];
dashes2underscores(first, tmp);
first = tmp;
const char *a;
va_list ap;
va_start(ap, i);
while (1)
{
a = va_arg(ap, char*);
if (a == NULL)
{
va_end(ap);
return false;
}
char a2[strlen(a)+1];
dashes2underscores(a, a2);
if (strcmp(a2, first) == 0)
{
i = m_args.erase(i);
va_end(ap);
return true;
}
}
return false;
}
bool CArgParser::argparsewitharg(vector<char*>::iterator &i, string *ret, ...)
{
bool r;
va_list ap;
va_start(ap, ret);
r = parsewitharg(i, ret, ap);
va_end(ap);
return r;
}
bool CArgParser::checkvalue(const char *c, string *ret/* = NULL*/)
{
for (vector<char*>::iterator i = m_args.begin(); i != m_args.end(); ++i)
{
if(ret)
{
if(argparsewitharg(i,ret, c, (char*)NULL))
return true;
}
else
{
if(argparseflag(i,c, (char*)NULL))
return true;
}
}
return false;
}
+50
View File
@@ -0,0 +1,50 @@
/***************************************************************************
Argument Parser Class Header ( ArgParser.h )
-----------------------------------------
begin : 2013/02/13
copyright : (C) 2013 Solbox Inc.
author : Development 1 Team
- 2013/02/13 - 1st dadamin
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __ARGUMENT_PARSER_H__
#define __ARGUMENT_PARSER_H__
#include <sys/types.h>
#include <stdarg.h>
#include <string.h>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class CArgParser
{
public:
CArgParser(int argc, char** argv);
~CArgParser();
bool argparseflag(vector<char*>::iterator &i, ...);
bool argparsewitharg(vector<char*>::iterator &i, string *ret, ...);
bool checkvalue(const char *c, string *ret = NULL);
inline bool empty() { return m_args.empty(); }
protected:
void dashes2underscores(const char *input, char *output);
bool parsewitharg(vector<char*>::iterator &i, std::string *ret, va_list ap);
private:
vector<char*> m_args;
};
#endif // __ARGUMENT_PARSER_H__
+178
View File
@@ -0,0 +1,178 @@
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <sys/time.h>
#include "CacheGeneratorThread.h"
#include "DaemonConfigs.h"
#include "SocketControl.h"
using namespace std;
#define SEND_REPLICATION_INTERVAL 10 // sec
#define OK_ALL_PASSED 0x1000
CCacheGeneratorThread::CCacheGeneratorThread()
{
// 멤버 변수 초기화
m_threadHandle = 0;
}
CCacheGeneratorThread::~CCacheGeneratorThread()
{
}
bool CCacheGeneratorThread::ThreadInit(const sig_atomic_t *sighandle)
{
m_sighandle = sighandle;
// rc_rmcd로 접근 함
m_szHost = CDeamonConfig::GetInstance()->GetRctsServer();
m_nPort = CDeamonConfig::GetInstance()->GetHotContentPort();
return true;
}
uint64_t CCacheGeneratorThread::GetFileSize(std::string szFileName)
{
off_t totalSize = 0;
// 파일 크기 검사.
FILE * pFile = fopen( szFileName.c_str(), "r+" );
if( pFile == NULL )
{
//source file open fail.
return totalSize;
}
else
{
fseeko( pFile, 0, SEEK_END );
totalSize = ftello( pFile );
rewind( pFile );
fclose( pFile ); // 열려진 descriptor close
}
return totalSize;
}
bool CCacheGeneratorThread::Request()
{
CSocketControl objSocket;
int nCount = 0;
// GMS 장비와 TCP 연결.
if( objSocket.ConnectTarget( m_szHost, m_nPort ) == false )
{
LOG( LERR, "CacheGeneratorThread: RCTS connection fail.[%s][%d]", m_szHost.c_str(), m_nPort );
objSocket.Close();
return false;
}
nCount = 0;
while(nCount < 30)
{
// 1. Data가 존재 하는가?
if( m_cacheReqList.GetSize() <= 0 )
{
LOG(LDBG, "ReplicationReqQueue queue is no have data.");
// 카운트 증가 후 1초 딜레이...
nCount++;
sleep(1);
continue;
}
nCount = 0;
// pop
// 2. DataPop()
struct replication_info objReplicaInfo = m_cacheReqList.Pop();
// get rcid
std::string szRCID = CDeamonConfig::GetInstance()->GetRCID();
// get hostname
char szHostname[HOSTNAME_LEN_FOR_RMCD];
if( gethostname( szHostname, HOSTNAME_LEN_FOR_RMCD ) != 0 )
{
LOG(LWAR, "gethostname() failed." );
continue;
}
// get filesize
uint64_t nFileSize = GetFileSize(objReplicaInfo.szFileName_hash);
if( nFileSize <= 0 )
{
LOG(LWAR, "get file size error[%s]", objReplicaInfo.szFileName_hash.c_str() );
continue;
}
// internal cache 요청
if ( objSocket.SendIntenalCache(szRCID
, objReplicaInfo.szFileName_hash
, szHostname
, objReplicaInfo.nServiceID
, nFileSize
, objReplicaInfo.szFDCount) == false )
{
// SendIntenalCache() 함수 내부에서 로깅처리 됨.
break;
}
}
objSocket.Close();
return true;
}
///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CCacheGeneratorThread::Execute()
{
while (*m_sighandle == 0)
{
// ReplicationReqQueue List에서 값을 가져오기 전에 개수를 확인한다.
if( m_cacheReqList.GetSize() <= 0 )
{
LOG( LDEV, "ReplicationReqQueue queue is empty.");
sleep( SEND_REPLICATION_INTERVAL );
continue;
}
// 아래 함수에서 return false 가 되더라도 무시한다.
if( Request() == false ){;}
sleep( SEND_REPLICATION_INTERVAL );
}
LOG(LERR, "Thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
}
void* CCacheGeneratorThread::EntryPoint(void* arg)
{
CCacheGeneratorThread* pObject = reinterpret_cast<CCacheGeneratorThread *>(arg);
pthread_detach( pthread_self() );
pObject->Execute();
// Thread 종료시 m_threadHandle 값을 초기화 처리.
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
pObject->m_threadHandle = 0;
return 0;
}
bool CCacheGeneratorThread::Start()
{
int nRet = ::pthread_create(&m_threadHandle, 0, CCacheGeneratorThread::EntryPoint, this);
if( nRet )
{
LOG(LERR, "Thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Thread create succeed");
sleep(0);
return true;
}
+72
View File
@@ -0,0 +1,72 @@
/***************************************************************************
Replicate Work Class
-----------------------------------------
begin : 2012/10/14
copyright : (C) 2010 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2010 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __CASH_GENERATOR_H__
#define __CASH_GENERATOR_H__
#include <pthread.h>
#include <string>
#include <map>
#include "Logger.h"
#include "Database.h"
#include "FimngdData.h"
#include "CacheRequestList.h"
#include "SharedMemAPR.h"
/// @brief
class CCacheGeneratorThread
{
public:
/// @brief 생성자
CCacheGeneratorThread();
~CCacheGeneratorThread();
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공은 return true 실패는 return false
bool Start();
/// @brief ProcessStatus 내의 RCDB 관련 설정값을 이용해 DB Connection을 한다.
/// @param sighandle 쓰레드에서 signal에 따라 정상 종료하도록 signal handle을 전달한다.
/// @param pshmemNetworStat 공유메모리 포인터
/// @return 성공하면 return true 실패하면 return false
bool ThreadInit(const sig_atomic_t *sighandle);
CCacheRequestList * GetReqList() { return &m_cacheReqList; }
// Attributes
private:
// 쓰레드 핸들
pthread_t m_threadHandle;
const sig_atomic_t *m_sighandle;
CCacheRequestList m_cacheReqList;
// rc_rmcd host & port info
std::string m_szHost;
int m_nPort;
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
// 해당 함수의 내용은 수정하지 말것.
void Execute();
// rc_rmcd로 internal cache를 요청한다.
bool Request();
uint64_t GetFileSize(std::string szFileName);
};
#endif //__CASH_GENERATOR_H__
+72
View File
@@ -0,0 +1,72 @@
/***************************************************************************
ContentList.cpp
-----------------------------------------
begin : 2015/05/29
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "CacheRequestList.h"
#include "MutexLock.hpp"
////////////////////////////////////////////////////////////////////////////
//
// CCacheRequestList Class
//
////////////////////////////////////////////////////////////////////////////
CCacheRequestList::CCacheRequestList()
{
pthread_mutex_init(&m_mutex, NULL);
}
CCacheRequestList::~CCacheRequestList()
{
ProtectedMutex mutex(m_mutex);
pthread_mutex_destroy(&m_mutex);
}
void CCacheRequestList::Push( std::string szFileName_hash, uint32_t nServiceID, int szFDCount)
{
ProtectedMutex mutex(m_mutex);
replication_info objReplicationInfo;
objReplicationInfo.szFileName_hash = szFileName_hash;
objReplicationInfo.nServiceID = nServiceID;
objReplicationInfo.szFDCount = szFDCount;
m_ReplicationInfoQueue.push( objReplicationInfo );
}
struct replication_info CCacheRequestList::Pop()
{
ProtectedMutex mutex(m_mutex);
struct replication_info data;
// 큐가 비었으면 빈 데이터 반환.
if( m_ReplicationInfoQueue.empty() == true )
{
LOG( LDBG, "no element in the queue of TransferStatDataList." );
return data;
}
data = m_ReplicationInfoQueue.front();
m_ReplicationInfoQueue.pop();
return data;
}
unsigned int CCacheRequestList::GetSize()
{
ProtectedMutex mutex(m_mutex);
return (unsigned int)m_ReplicationInfoQueue.size();
}
void CCacheRequestList::Clear()
{
ProtectedMutex mutex(m_mutex);
while( m_ReplicationInfoQueue.size() > 0 )
{
m_ReplicationInfoQueue.pop();
}
}
+64
View File
@@ -0,0 +1,64 @@
/***************************************************************************
Process Dummy Class
-----------------------------------------
begin : 2015/05/28
copyright : (C) 2005 Solbox Inc.
author : Dev 1 Team
email : storage.sd@solbox.com
version : 3.5.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __CACHE_REQUEST_LIST_H__
#define __CACHE_REQUEST_LIST_H__
#include <queue>
#include <string.h>
#include <pthread.h>
#include "Logger.h"
#include "FimngdData.h"
#include "TransferStatData.h"
struct replication_info
{
std::string szFileName_hash;
uint32_t nServiceID;
int szFDCount;
};
class CCacheRequestList
{
public:
CCacheRequestList();
virtual ~CCacheRequestList();
///@brief replication_info 큐에 데이터를 삽입하는 함수.
///@param logData [in] replication_info 레퍼런스.
///@return none
void Push( std::string szFileName_hash, uint32_t nServiceID, int szFDCount);
///@brief replication_info 큐에서 데이터를 얻는 함수.
/// 반환된 데이터는 큐에서 삭제된다.
///@param none.
///@return replication_info 객체
struct replication_info Pop();
///@brief replication_info 큐의 크기를 얻는 함수.
///@param none.
///@return replication_info 큐의 크기를 반환.
unsigned int GetSize();
///@brief 큐의 모든 데이터를 삭제하는 함수.
///@param none.
///@param none.
void Clear();
private:
std::queue<struct replication_info> m_ReplicationInfoQueue;
pthread_mutex_t m_mutex;
};
#endif //__CACHE_REQUEST_LIST_H__
+514
View File
@@ -0,0 +1,514 @@
/***************************************************************************
Config Class (DaemonConfigs.cpp)
-----------------------------------------
begin : 2015/04/28
copyright : (C) 2013 Solbox Inc.
author : Development Team
email : storage.sd@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "DaemonConfigs.h"
#include <cstdlib>
#include <iostream>
#include "Config.h"
CDeamonConfig *CDeamonConfig::m_pInstance = NULL;
CCommonConfig::CCommonConfig( string szFilename, string szProgramName )
: m_szConfigFile(szFilename), m_szProgramName(szProgramName)
{
m_nAliveCheckPort = 0;
}
CCommonConfig::~CCommonConfig()
{
}
bool CCommonConfig::LoadConf()
{
#ifdef _DEBUG
cout << "CCommonConfig::LoadConf() =>" << endl;
#endif // _DEBUG
string szValue;
// Config 처리를 위한 객체 생성
Config conf;
// Config File open
if( conf.Open( m_szConfigFile ) == false )
{
m_szErrMessage = "Config file open failed.[" + m_szConfigFile + "]";
return false;
}
// log path
if( conf.GetConfig( "COMMON", "DEFAULT_LOG_DIR", szValue ) )
{
m_szAppLogRoot = szValue;
}
// log level
if( conf.GetConfig( "COMMON", "LOG_LEVEL", szValue ) )
{
m_nLogLevel = atoi( szValue.c_str() );
}
// RCDB Access Information
if( conf.GetConfig( "COMMON", "RCDB_IP", szValue ) )
{
m_cDatabaseInfo.m_szRcdbIp = szValue;
}
if( conf.GetConfig( "COMMON", "RCDB_PORT", szValue ) )
{
m_cDatabaseInfo.m_nRcdbPort = atoi( szValue.c_str() );
}
if( conf.GetConfig( "COMMON", "RCDB_DB_NAME", szValue ) )
{
m_cDatabaseInfo.m_szRcdbName = szValue;
}
if( conf.GetConfig( "COMMON", "RCDB_ACCT", szValue ) )
{
m_cDatabaseInfo.m_szRcdbAcct = szValue;
}
if( conf.GetConfig( "COMMON", "RCDB_ACCT_PW", szValue ) )
{
m_cDatabaseInfo.m_szRcdbAcctPw = szValue;
}
// RC ID
if (conf.GetConfig("COMMON", "RCID", szValue))
{
m_szRcid = szValue;
}
// RCTS SERVER
if (conf.GetConfig("COMMON", "RCTS_SERVER", szValue))
{
m_szRctsServer = szValue;
}
// FHS fimngd alive check port
if (conf.GetConfig("COMMON", "FHS_PORT_MNGCHECK", szValue))
{
m_nAliveCheckPort = atoi(szValue.c_str());
}
// File save directory path
if (conf.GetConfig("COMMON", "FILE_STORAGE_ROOT", szValue))
{
m_szFileStorageRoot = szValue;
}
// Internal communication NIC name
if (conf.GetConfig("COMMON", "INTERNAL_NIC_NAME", szValue))
{
m_szInternalNicName = szValue;
}
#ifdef _DEBUG
PrintValue();
#endif // _DEBUG
return true;
}
bool CCommonConfig::CheckValue()
{
if(m_szAppLogRoot.empty())
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->DEFAULT_LOG_DIR";
return false;
}
if( m_nLogLevel <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->LOG_LEVEL";
return false;
}
if(m_cDatabaseInfo.m_szRcdbIp.empty())
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->RCDB_IP";
return false;
}
if( m_cDatabaseInfo.m_nRcdbPort <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->RCDB_PORT";
return false;
}
if(m_cDatabaseInfo.m_szRcdbName.empty())
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->RCDB_DB_NAME";
return false;
}
if(m_cDatabaseInfo.m_szRcdbAcct.empty())
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->RCDB_ACCT";
return false;
}
if(m_cDatabaseInfo.m_szRcdbAcctPw.empty())
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->RCDB_ACCT_PW";
return false;
}
if (m_szRcid.empty())
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->RCID";
return false;
}
if (m_szRctsServer.empty())
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->RCTS_SERVERR";
return false;
}
if (m_nAliveCheckPort <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->FHS_PORT_MNGCHECK";
return false;
}
if (m_szFileStorageRoot.empty())
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->FILE_STORAGE_ROOT";
return false;
}
if (m_szInternalNicName.empty())
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->FILE_STORAGE_ROOT";
return false;
}
return true;
}
void CCommonConfig::PrintValue()
{
cout << "Log Value : " << m_szAppLogRoot << "," << m_nLogLevel << endl;
cout << "RC Value : " << m_szRcid << endl;
cout << "RCTS Value : " << m_szRctsServer << endl;
cout << "FHS Value : " << m_szInternalNicName << "," << m_szFileStorageRoot << endl;
cout << "RCDB Value : " << m_cDatabaseInfo.m_szRcdbIp << ","
<< m_cDatabaseInfo.m_nRcdbPort << "," << m_cDatabaseInfo.m_szRcdbName
<< "," << m_cDatabaseInfo.m_szRcdbAcct << "," << m_cDatabaseInfo.m_szRcdbAcctPw << endl;
}
CDeamonConfig::CDeamonConfig(string szFilename, string szProgramName)
: CCommonConfig(szFilename, szProgramName)
{
m_nHotContentPort = 0;
m_nTransferStatPort = 0;
m_nFhsInfoPort = 0;
m_nMaxFhs = 0;
m_nMaxAccount = 0;
m_nMaxAnonyMous = 0;
m_nQueueCount = 0;
m_nMaxIPCQueueSize = 0;
}
CDeamonConfig::~CDeamonConfig()
{
}
bool CDeamonConfig::LoadConf()
{
CCommonConfig::LoadConf();
#ifdef _DEBUG
cout << "CMyConfig::LoadConf() =>" << endl;
#endif // _DEBUG
string szValue;
// Config 처리를 위한 객체 생성
Config conf;
// Config File open
if( conf.Open( m_szConfigFile ) == false )
{
m_szErrMessage = "Config file open failed.[" + m_szConfigFile + "]";
return false;
}
// Config File open
if( conf.GetConfig( m_szProgramName, "DEFAULT_LOG_DIR", szValue ) )
{
m_szAppLogRoot = szValue;
}
// log level
if( conf.GetConfig( m_szProgramName, "LOG_LEVEL", szValue ) )
{
m_nLogLevel = atoi( szValue.c_str() );
}
// RCDB Access Information
if( conf.GetConfig( m_szProgramName, "RCDB_IP", szValue ) )
{
m_cDatabaseInfo.m_szRcdbIp = szValue;
}
if( conf.GetConfig( m_szProgramName, "RCDB_PORT", szValue ) )
{
m_cDatabaseInfo.m_nRcdbPort = atoi(szValue.c_str() );
}
if( conf.GetConfig( m_szProgramName, "RCDB_DB_NAME", szValue ) )
{
m_cDatabaseInfo.m_szRcdbName = szValue;
}
if( conf.GetConfig( m_szProgramName, "RCDB_ACCT", szValue ) )
{
m_cDatabaseInfo.m_szRcdbAcct = szValue;
}
if( conf.GetConfig( m_szProgramName, "RCDB_ACCT_PW", szValue ) )
{
m_cDatabaseInfo.m_szRcdbAcctPw = szValue;
}
// RC ID
if (conf.GetConfig(m_szProgramName, "RCID", szValue))
{
m_szRcid = szValue;
}
// RCTS SERVER
if (conf.GetConfig(m_szProgramName, "RCTS_SERVER", szValue))
{
m_szRctsServer = szValue;
}
// FHS fimngd alive check port
if (conf.GetConfig("COMMON", "FHS_PORT_MNGCHECK", szValue))
{
m_nAliveCheckPort = atoi(szValue.c_str());
}
// File save directory path
if (conf.GetConfig(m_szProgramName, "FILE_STORAGE_ROOT", szValue))
{
m_szFileStorageRoot = szValue;
}
// Internal communication NIC name
if (conf.GetConfig(m_szProgramName, "INTERNAL_NIC_NAME", szValue))
{
m_szInternalNicName = szValue;
}
// fimngd 전용 config
//Hot content request tcp port
if (conf.GetConfig(m_szProgramName, "HOT_CONTENT_REQUEST_TCP_PORT", szValue))
{
m_nHotContentPort = atoi( szValue.c_str() );
}
// Transfer status send port
if (conf.GetConfig(m_szProgramName, "TRANSFER_STAT_SEND_PORT", szValue))
{
m_nTransferStatPort = atoi( szValue.c_str() );
}
// Fhs info request port
if (conf.GetConfig(m_szProgramName, "FHS_INFO_REQUEST_PORT", szValue))
{
m_nFhsInfoPort = atoi( szValue.c_str() );
}
// FHS maximum number within an RC
if (conf.GetConfig(m_szProgramName, "MAX_FHS", szValue))
{
m_nMaxFhs = atoi( szValue.c_str() );
}
// The maximum volume within one RC
if (conf.GetConfig(m_szProgramName, "MAX_ACCOUNT", szValue))
{
m_nMaxAccount = atoi( szValue.c_str() );
}
// No authentication maximum number of folders
if (conf.GetConfig(m_szProgramName, "MAX_ANONYMOUS", szValue))
{
m_nMaxAnonyMous = atoi( szValue.c_str() );
}
// No authentication maximum number of folders
if (conf.GetConfig(m_szProgramName, "IPC_QUEUE_COUNT", szValue))
{
m_nQueueCount = atoi( szValue.c_str() );
}
// No authentication maximum number of folders
if (conf.GetConfig(m_szProgramName, "IPC_QUEUE_MAX_SIZE", szValue))
{
m_nMaxIPCQueueSize = atoi( szValue.c_str() );
}
// config 파일에 직접 노출 하진 않지만 conf 파일에 설정 가능 하도록 숨김
// fd count
szValue.clear();
if (conf.GetConfig(m_szProgramName, "FD_COUNT", szValue) == false)
{
m_nFdCount = FD_COUNT;
}
else
{
m_nFdCount = atoi( szValue.c_str() );
}
szValue.clear();
// CHG 2020-07-20 huibong internal cache 관련 fd 감시 on/off 관련 기능 개선 (#33112)
// - IS_FD_COUNT -> EXTRACT_FD_COUNT 으로 항목명 변경
// - default 는 0 (false) 이며.. 그외 정수는 true 로 판단 처리됨.
if (conf.GetConfig(m_szProgramName, "EXTRACT_FD_COUNT", szValue) == false)
{
// CHG 2020-07-20 huibong internal cache 관련 fd 감시 on/off 관련 기능 개선 (#33112)
// - queue pop 처리한 content 에 대해 fd count 정보 추출 여부를 판단하는 변수
// - true 인 경우 fd count 정보 수집 처리, default false
// - 설정값이 존재하지 않는 경우.. true -> false 로 수정 처리
m_bExtractContentFdCount = false;
}
else
{
// 0 인 경우에는 false, 그 외에는 true
m_bExtractContentFdCount = atoi(szValue.c_str()) ? true : false ;
}
szValue.clear();
if (conf.GetConfig(m_szProgramName, "FD_COUNT_CMD", szValue) == false)
{
m_szFdCntCMD = DEFAULT_CNT_CMD;
}
else
{
m_szFdCntCMD = szValue;
}
// hot content expire time
szValue.clear();
if (conf.GetConfig(m_szProgramName, "CONTENT_EXPIRE_SEC", szValue) == false)
{
m_nContentExpireSec = CONTENT_EXPIRE_SEC;
}
else
{
m_nContentExpireSec = atoi( szValue.c_str() );
}
// hot content info max saved count
szValue.clear();
if (conf.GetConfig(m_szProgramName, "CONTENT_INFO_MAX", szValue) == false)
{
m_nContentInofMax = CONTENT_INFO_MAX;
}
else
{
m_nContentInofMax = atoi(szValue.c_str());
}
#ifdef _DEBUG
PrintValue();
#endif // _DEBUG
return true;
}
bool CDeamonConfig::CheckValue()
{
if (CCommonConfig::CheckValue() == false)
return false;
if( m_nHotContentPort <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->HOT_CONTENT_REQUEST_TCP_PORT";
return false;
}
if( m_nTransferStatPort <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->TRANSFER_STAT_SEND_PORT ";
return false;
}
if( m_nFhsInfoPort <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->FHS_INFO_REQUEST_PORT ";
return false;
}
if( m_nMaxFhs <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->MAX_FHS";
return false;
}
if( m_nMaxAccount <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->MAX_ACCOUNT";
return false;
}
if( m_nMaxAnonyMous <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->MAX_ANONYMOUS";
return false;
}
if( m_nQueueCount <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->IPC_QUEUE_COUNT";
return false;
}
if( m_nMaxIPCQueueSize <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->IPC_QUEUE_MAX_SIZE";
return false;
}
// 값들의 최대 최소 설정.
// 1 < queue count <= 20
if( m_nQueueCount > 20 )
{
m_nQueueCount = 20;
}
// 500 <= queue size <= 5000
if( m_nMaxIPCQueueSize < 500 )
{
m_nMaxIPCQueueSize = 500;
}
if( m_nMaxIPCQueueSize > 5000 )
{
m_nMaxIPCQueueSize = 5000;
}
return true;
}
void CDeamonConfig::PrintValue()
{
CCommonConfig::PrintValue();
}
bool CDeamonConfig::Init(string szProgramName, string szFilename)
{
if (CDeamonConfig::m_pInstance == NULL)
{
CDeamonConfig::m_pInstance = new CDeamonConfig(szFilename, szProgramName);
}
return true;
}
void CDeamonConfig::Exit()
{
if (CDeamonConfig::m_pInstance != NULL)
{
delete CDeamonConfig::m_pInstance;
CDeamonConfig::m_pInstance = NULL;
}
}
CDeamonConfig* CDeamonConfig::GetInstance()
{
return CDeamonConfig::m_pInstance;
}
+170
View File
@@ -0,0 +1,170 @@
/***************************************************************************
Config Class Header ( DaemonConfigs.h )
-----------------------------------------
begin : 2015/04/28
copyright : (C) 2013 Solbox Inc.
author : Development Team
email : storage.sd@solbox.com
version : 3.5.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __DAEMON_CONFIGS_H__
#define __DAEMON_CONFIGS_H__
#include <string>
using namespace std;
// fimngd 에서 캐시파일 조건을 약하게해서 요청하고 rc_rmcd의 최종 설정 값으로 조정하도록 한다.
#define FD_COUNT 3 /// fd count
// 오픈된 fd를 찾는 쉘 스크립트 디폴트 설정값
#define DEFAULT_CNT_CMD "/user/service/etc/fdcnt.sh"
#define CONTENT_EXPIRE_SEC 300 /// hot content expire (sec)
#define CONTENT_INFO_MAX 10000
class CDatabaseInfo
{
public:
CDatabaseInfo() : m_nRcdbPort(0) {}
~CDatabaseInfo() {}
public:
string m_szRcdbIp;
int m_nRcdbPort;
string m_szRcdbName;
string m_szRcdbAcct;
string m_szRcdbAcctPw;
};
class CCommonConfig
{
public:
CCommonConfig( string szFilename, string szProgramName );
virtual ~CCommonConfig();
bool LoadConf();
bool CheckValue();
void PrintValue();
inline const char * GetErrMessage() { return m_szErrMessage.c_str(); }
inline const char * GetConfigFile() { return m_szConfigFile.c_str(); }
inline const char * GetAppLogRoot() { return m_szAppLogRoot.c_str(); }
inline int GetAppLogLevel() { return m_nLogLevel; }
inline CDatabaseInfo GetDBInfo() { return m_cDatabaseInfo; }
inline const char* GetRCID() { return m_szRcid.c_str(); }
inline const char* GetInternalNicName() { return m_szInternalNicName.c_str(); }
inline const char* GetFileStorageRoot() { return m_szFileStorageRoot.c_str(); }
inline const char* GetRctsServer() { return m_szRctsServer.c_str(); }
inline int GetAliveCheckPort() { return m_nAliveCheckPort; }
protected:
string m_szConfigFile;
string m_szProgramName;
string m_szErrMessage;
// log
string m_szAppLogRoot;
int m_nLogLevel;
// RCDB
CDatabaseInfo m_cDatabaseInfo;
// RCID
string m_szRcid;
// RCTS IP
string m_szRctsServer;
// RCTS IP
int m_nAliveCheckPort;
// Internal communication NIC name
string m_szInternalNicName;
// File save directory path
string m_szFileStorageRoot;
private:
};
class CDeamonConfig : public CCommonConfig
{
public:
static bool Init( string szProgramName, string szFilename );
static void Exit();
static CDeamonConfig* GetInstance();
inline int GetHotContentPort() { return m_nHotContentPort; }
inline int GetTransferStatPort() { return m_nTransferStatPort; }
inline int GetFhsInfoPort() { return m_nFhsInfoPort; }
inline int GetMaxFhs() { return m_nMaxFhs; }
inline int GetMaxAccount() { return m_nMaxAccount; }
inline int GetMaxAnonyMous() { return m_nMaxAnonyMous; }
inline int GetIPCQueueCount() { return m_nQueueCount; }
inline int GetMaxIPCQueueSize() { return m_nMaxIPCQueueSize; }
// config 파일에 직접 노출 하진 않지만 conf 파일에 설정 가능 하도록 숨김
unsigned int GetFdCount(){return m_nFdCount; }
// CHG 2020-07-20 huibong internal cache 관련 fd 감시 on/off 관련 기능 개선 (#33112)
// - 변수명 변경에 따라.. 함수명을 IsFdCount -> IsExtractContentFdCount 으로 변경 처리.
// - content 에 대한 fd count 정보를 수집할지 여부를 반환
// - true 인 경우 fd count 정보 수집.
bool IsExtractContentFdCount(){ return m_bExtractContentFdCount; }
std::string GetFdCntCMD(){return m_szFdCntCMD; }
unsigned int GetContentExpireSec(){return m_nContentExpireSec; }
unsigned int GetContentMaxInfo(){ return m_nContentInofMax; }
private:
static CDeamonConfig* m_pInstance;
public:
bool LoadConf();
bool CheckValue();
void PrintValue();
protected:
CDeamonConfig(string szFilename, string szProgramName);
virtual ~CDeamonConfig();
protected:
private:
int m_nHotContentPort;
int m_nTransferStatPort;
int m_nFhsInfoPort;
int m_nMaxFhs;
int m_nMaxAccount;
int m_nMaxAnonyMous;
int m_nQueueCount;
int m_nMaxIPCQueueSize;
// config 파일에 직접 노출 하진 않지만 conf 파일에 설정 가능 하도록 숨김
unsigned int m_nContentExpireSec;
unsigned int m_nContentInofMax;
unsigned int m_nFdCount;
// CHG 2020-07-20 huibong internal cache 관련 fd 감시 on/off 관련 기능 개선 (#33112)
// - 변수명을 m_isFdCnt -> m_bExtractContentFdCount 으로 변경 처리
// - queue pop 처리한 content 에 대해 fd count 정보 추출 여부를 판단하는 변수
// - true 인 경우 fd count 정보 수집 처리, default false
bool m_bExtractContentFdCount;
// fd count 정보 추출 관련 script 정보
string m_szFdCntCMD;
};
#endif // __RC_MNGD_CONFIG_H__
+184
View File
@@ -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;
}
+56
View File
@@ -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__
+264
View File
@@ -0,0 +1,264 @@
#include "FhsStatUpdateThread.h"
#include "DaemonConfigs.h"
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <sys/time.h>
using namespace std;
#define DEFAULT_QUERY_BUFFER_SIZE 1024
#define QUERY_LIMIT_COUNT 2000
#define UPDATE_TERM 5
int random(int nRange)
{
return rand() % nRange;
}
CFhsStatUpdateThread::CFhsStatUpdateThread()
{
// 멤버 변수 초기화
m_threadHandle = 0;
m_myindex = -1;
memset(m_szHostname, 0, HOSTNAME_LEN);
}
CFhsStatUpdateThread::~CFhsStatUpdateThread()
{
}
bool CFhsStatUpdateThread::ThreadInit(const sig_atomic_t *sighandle, CSharedMem* pShmemFhsStat, CSharedMem* pShmemFhsCount)
{
srand(time(NULL));
m_sighandle = sighandle;
m_pShmemFhsStat = pShmemFhsStat;
m_pShmemFhsCount = pShmemFhsCount;
m_szHost = CDeamonConfig::GetInstance()->GetRctsServer();
m_nPort = CDeamonConfig::GetInstance()->GetFhsInfoPort();
GetMyHostname();
// 연결이 안되더라도... rc_mond가 구동 되면 소켓연결 하도록 처리되어있으므로...
// warning 메시지만 로깅하고 넘어간다.
if( m_objSocket.ConnectTarget( m_szHost, m_nPort ) == false )
{
LOG( LWAR, "CFhsStatUpdateThread: Connected to the monitor server failed. [%s][%d]", m_szHost.c_str(), m_nPort );
}
return true;
}
void CFhsStatUpdateThread::UpdateSharedMemory()
{
struct fhs_stat* pSharedHeader = (struct fhs_stat*)m_pShmemFhsStat->GetData();
int *pFhsCount = (int*)m_pShmemFhsCount->GetData();
int nIndex = 0;
int nMax = CDeamonConfig::GetInstance()->GetMaxFhs();
_LOG(LINF, "FHS stat updated [fhs count: %zu] ", m_mapFhsStat.size());
// 공유 메모리 기준으로
// Maxcount는 설정 값에서 갖고 온다.
for(int i = 0; i < nMax; i++ )
{
// 끝이면???:147
if( (pSharedHeader + i)->szHostname[0] == '\0' )
{
LOG(LDEV, "Shared Memory End. [index: %d, %d]", i, (int)m_mapFhsStat.size());
// 맵에 데이터가 남을 경우 해당 인덱스부터 추가해 주기 위해 저장한다.
nIndex = i;
break;
}
struct fhs_stat* pCurFhsStat = (pSharedHeader + i);
if (strcmp(pCurFhsStat->szHostname, m_szHostname) == 0)
m_myindex = i;
// 맵에서 해당 데이터를 찾는다.
std::map<string, struct fhs_stat>::iterator it;
it = m_mapFhsStat.find(pCurFhsStat->szHostname);
if( it == m_mapFhsStat.end() )
{
if (pCurFhsStat->nActionCode != -1 )
_LOG(LNOT, "!!!! FHS dead. [%s]", pCurFhsStat->szHostname);
// 맵에서 데이터를 못찾았다면, 유효하지 않은 장비라고 판단한다.
pCurFhsStat->nActionCode = -1;
continue;
}
struct fhs_stat fhsStat = it->second;
memcpy(pCurFhsStat, &fhsStat, sizeof(struct fhs_stat));
// 맵에서 삭제
m_mapFhsStat.erase(it);
}
int nFhsCount = nIndex;
// 맵에 데이터가 남았는지 체크 한다.
if( m_mapFhsStat.size() <= 0 )
{
*pFhsCount = nFhsCount;
return;
}
// 신규 등록되는 장비들이 shared memory에 random하게 등록 되도록 처리 함
std::vector<struct fhs_stat> vecAliveFhs;
std::map<string, struct fhs_stat>::iterator it;
for (it=m_mapFhsStat.begin(); it!=m_mapFhsStat.end(); ++it)
{
struct fhs_stat stFhsStat = it->second;
vecAliveFhs.push_back( stFhsStat );
}
m_mapFhsStat.clear();
// vercot 목록에서 random하게 shared memory에 기록한다.
while( vecAliveFhs.size() != 0 )
{
int nResult = random( vecAliveFhs.size() );
struct fhs_stat stFhsStat = vecAliveFhs[nResult];
LOG(LDBG, "host : %s, Action Code : %d index : %d",stFhsStat.szHostname, stFhsStat.nActionCode, nIndex);
memcpy((pSharedHeader + nIndex), &stFhsStat, sizeof(struct fhs_stat));
if (strcmp(stFhsStat.szHostname, m_szHostname) == 0)
m_myindex = nIndex;
vecAliveFhs.erase(vecAliveFhs.begin()+nResult);
nIndex++;
nFhsCount++;
}
}
bool CFhsStatUpdateThread::GetFhsStat()
{
// 1. socket이 유효한지 판단한다.
// 1-1. 유효하지 않다면 connect를 다시한다.
// 1-2. 연결 실패 시 return false;
if ( m_objSocket.IsValidSocket() == false )
{
if( m_objSocket.ConnectTarget( m_szHost, m_nPort ) == false )
{
LOG( LWAR, "CFhsStatUpdateThread: Connected to the monitor server failed.[%s][%d]", m_szHost.c_str(), m_nPort );
return false;
}
}
// 2. 유효한 fhs 목록 요청
// get hostname
if (GetMyHostname() == false)
{
LOG(LWAR, "gethostname() failed." );
return false;
}
if (m_objSocket.SendAliveFhs(CDeamonConfig::GetInstance()->GetRCID(), m_szHostname) == false)
{
// SendAliveFhs() 함수 내부에서 로깅처리 됨.
m_objSocket.Close();
return false;
}
// 3. 목록 수신
if( m_objSocket.GetAliveFhs(m_mapFhsStat) == false )
{
// GetAliveFhs() 함수 내부에서 로깅처리 됨.
m_objSocket.Close();
return false;
}
return true;
}
bool CFhsStatUpdateThread::GetMyHostname()
{
if (strlen(m_szHostname) > 0)
return true;
if (gethostname(m_szHostname, HOSTNAME_LEN) != 0)
{
memset(m_szHostname, 0, HOSTNAME_LEN);
LOG(LWAR, "gethostname() failed.");
return false;
}
if (m_szHostname == NULL || strlen(m_szHostname) <= 0)
{
LOG(LWAR, "m_szHostname is NULL.");
return false;
}
LOG(LDBG, "My Hostname is %s", m_szHostname);
return true;
}
void CFhsStatUpdateThread::SetSelfDead()
{
if ( m_myindex != -1 )
{
struct fhs_stat* pSharedHeader = (struct fhs_stat*)m_pShmemFhsStat->GetData();
(pSharedHeader + m_myindex)->nActionCode = -1;
_LOG(LNOT, "Set myself Dead.[%s]", (pSharedHeader + m_myindex)->szHostname);
}
}
///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CFhsStatUpdateThread::Execute()
{
// socket control object 생성 및 소켓 연결
while (*m_sighandle == 0)
{
// rc_statd로 부터 이웃의 FHS 상태정보를 취한다.
if( GetFhsStat() == false )
{
m_objSocket.Close();
// 5초 후 재시도
if (*m_sighandle == 0)
sleep(UPDATE_TERM);
LOG(LDBG, "Retry...");
continue;
}
UpdateSharedMemory();
sleep(UPDATE_TERM);
}
_LOG(LINF, "CFhsStatUpdateThread Thread end.: errno:%d errmsg:%s", errno, strerror(errno));
}
void* CFhsStatUpdateThread::EntryPoint(void* arg)
{
CFhsStatUpdateThread* pObject = reinterpret_cast<CFhsStatUpdateThread *>(arg);
pthread_detach( pthread_self() );
pObject->Execute();
// Thread 종료시 m_threadHandle 값을 초기화 처리.
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
//pObject->m_threadHandle = 0;
return 0;
}
bool CFhsStatUpdateThread::Start()
{
int nRet = ::pthread_create(&m_threadHandle, 0, CFhsStatUpdateThread::EntryPoint, this);
if( nRet )
{
LOG(LERR, "Thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Thread create succeed");
sleep(0);
return true;
}
+80
View File
@@ -0,0 +1,80 @@
/***************************************************************************
Replicate Work Class
-----------------------------------------
begin : 2012/10/14
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 __FHS_STAT_UPDATE_THREAD__
#define __FHS_STAT_UPDATE_THREAD__
#include <pthread.h>
#include <string>
#include <map>
#include "Logger.h"
#include "Database.h"
#include "FimngdData.h"
#include "SharedMemAPR.h"
#include "SocketControl.h"
/// @brief
class CFhsStatUpdateThread
{
public:
/// @brief 생성자
CFhsStatUpdateThread();
~CFhsStatUpdateThread();
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공은 return true 실패는 return false
bool Start();
/// @brief ProcessStatus 내의 RCDB 관련 설정값을 이용해 DB Connection을 한다.
/// @param sighandle 쓰레드에서 signal에 따라 정상 종료하도록 signal handle을 전달한다.
/// @param pShmemFhsStat 공유메모리 포인터
/// @return 성공하면 return true 실패하면 return false
bool ThreadInit(const sig_atomic_t *sighandle, CSharedMem* pShmemFhsStat, CSharedMem* pShmemFhsCount);
// 자신의 상태를 OUT으로 만듦
void SetSelfDead();
// Attributes
private:
// 쓰레드 핸들
pthread_t m_threadHandle;
const sig_atomic_t *m_sighandle;
CSocketControl m_objSocket;
// rc_mond host & port info
std::string m_szHost;
int m_nPort;
CSharedMem* m_pShmemFhsStat;
CSharedMem* m_pShmemFhsCount;
std::map<std::string, struct fhs_stat> m_mapFhsStat;
char m_szHostname[HOSTNAME_LEN];
int m_myindex;
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
// 해당 함수의 내용은 수정하지 말것.
void Execute();
bool GetFhsStat();
void UpdateSharedMemory();
bool GetMyHostname();
};
#endif //__FHS_STAT_UPDATE_THREAD__
+123
View File
@@ -0,0 +1,123 @@
/***************************************************************************
Database Class
-----------------------------------------
begin : 2015/05/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.
***************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#ifndef __FIMNGD_DATA_H__
#define __FIMNGD_DATA_H__
#define MaxSizeOfPermittedReferer 4096
#define MaxSizeOfSvcID 33
#define MaxSizeOfUserID 256
#define MaxSizeOfUserPassword 256
#define MaxSizeOfUserSeq 40
#define MaxSizeOfUserTranID 40
#define KEY_LENGTH 24
#define MaxSizeOfUserIV (KEY_LENGTH + 2)
#define MaxSizeOfUserPK (KEY_LENGTH + 2)
#define MaxSizeOfUserAuthUri 256
#define MaxSizeOfUserAuthAddr 256
#define MaxSizeOfUserAuthMode 10
#define URI_SIZE_MAX 2048
#define DOMAIN_SIZE 512
#define FILENAME_HASH_SIZE 128
#define HOST_NAME_SIZE 64
////////////////////// shared memory를 위한 구조체들 /////////////////////
// /tmp/opendav.shared.account.shm
struct account {
//flag
// DB조회 결과에서 해당 서비스가 없다면 nFlag를 '1'로 설정
// 값이 1이면 RCDB 조회결과 해당 서비스가 없다는 의미이다.
int nFlag; // 0 : 서비스 존재, 1: 서비스 없음
// authorized related
char id[MaxSizeOfUserID];
char svc_id[MaxSizeOfSvcID];
char pass[MaxSizeOfUserPassword];
char seq[MaxSizeOfUserSeq];
char tran_id[MaxSizeOfUserTranID];
char iv[MaxSizeOfUserIV];
char pk[MaxSizeOfUserPK];
//uri ignore case : 1 - ignore case, 0 - Not ignore case
int is_ignorecase;
// authenticate related - user identify
char auth_uri[MaxSizeOfUserAuthUri];
char auth_addr[MaxSizeOfUserAuthAddr];
short auth_port;
int auth_timeout;
/* billing related - for SP */
char bill_uri[MaxSizeOfUserAuthUri];
char bill_addr[MaxSizeOfUserAuthAddr];
short bill_port;
int bill_timeout;
// auth and bill mode
char mode[MaxSizeOfUserAuthMode];
//traffic control value
int tc_percent;
int tc_session;
/* Elenoa: 2007. 5. 9: add referer check */
char permitted_referer[MaxSizeOfPermittedReferer];
char permitted_extend[MaxSizeOfPermittedReferer];
};
// /tmp/opendav.shared.anony.shm
struct anonymous {
char uri[URI_SIZE_MAX];
char domain[DOMAIN_SIZE];
int nFlag;
};
// /tmp/opendav.shared.fhsstat.shm
struct fhs_stat
{
char szHostname[64];
int nActionCode;
};
// /tmp/opendav.shared.networkstat.shm
// rc_statd와 통신을 할 때도 사용 된다.
struct service_network_stat {
int nServiceSeq;
int nUserSeq;
uint32_t timestamp; // 5분 단위 1씩 증가.
uint64_t down_content_size; // 누적시 down content size 누적
uint64_t up_content_size; // 누적시 up contents size 누적
uint64_t down_traffic; // 누적시 (down_content_size * 1.1)를 누적
uint64_t up_traffic; // 누적시 (up_traffic * 1.1)를 누적
};
////////////////////// IPC Message 큐를 위한 구조체 /////////////////////
// IPC Msg Queue 용 전달 구조체.
struct Transfer_stat {
long mtype; // 고정으로 1 :>> Message Queue를 활용 할 때 항상 mtype은 있어야 한다.
uint32_t timestamp; // opendav에서 정보를 생성한 시간
short int nInOut; // Outboud : 0 Inboud: non zero
int nUserSeq;
int nServiceSeq;
uint64_t sizeTransfer;
char filename_hash[FILENAME_HASH_SIZE];
};
#endif // __FIMNGD_DATA_H__
+78
View File
@@ -0,0 +1,78 @@
/***************************************************************************
FstatHandler.cpp
-----------------------------------------
begin : 2011/12/06
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 <stdio.h>
#include <stdlib.h>
#include "FstatHandler.h"
#include "Logger.h"
#include "DaemonConfigs.h"
CFstatHandler::CFstatHandler()
{
}
void CFstatHandler::Trim( string & str )
{
if( str.length() == 0 )
return ;
// 문자열 뒤의 공백, TAB, CR 등의 문자 제거처리.
string::size_type pos = str.find_last_not_of(" \a\b\f\n\r\t\v");
if( pos != string::npos )
str.erase( pos + 1 );
// 문자열 앞의 공백, TAB, CR 등의 문자 제거처리.
pos = str.find_first_not_of(" \a\b\f\n\r\t\v");
if( pos != string::npos )
str.erase( 0, pos );
}
int CFstatHandler::GetFdCountOnSystem( std::string szFileName )
{
char szCmd[1024];
FILE *fp;
char szResult[1024];
int r = 0;
if( CDeamonConfig::GetInstance() == NULL )
{
LOG( LERR, "Log: CDeamonConfig::GetInstance() is NULL.");
return 0;
}
// commnad 생성.
sprintf( szCmd, "%s %s", CDeamonConfig::GetInstance()->GetFdCntCMD().c_str(), szFileName.c_str() );
LOG( LDEV, "CMD : %s", szCmd);
// cmd 구동.
fp = popen( szCmd, "r" );
if( fp == NULL )
{
LOG( LWAR, "Log: popen failed. cmd=%s", szCmd );
return 0;
}
while( fgets( szResult, sizeof(szResult) -1, fp) != NULL )
{
LOG( LDEV, "%s", szResult);
r = atoi(szResult);
break;
}
pclose( fp );
LOG( LDEV, "FD Count : %d", r);
return r;
}
+59
View File
@@ -0,0 +1,59 @@
/***************************************************************************
FstatHandler.h
-----------------------------------------
begin : 2011/12/06
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 _FSTAT_HANDLER_H_
#define _FSTAT_HANDLER_H_
#include <string>
#include <list>
using namespace std;
class CFstatInfo
{
private:
public:
CFstatInfo(){};
~CFstatInfo(){};
std::string m_szPid;
std::string m_szFdNum;
std::string m_szRW;
};
class CFstatHandler
{
// Attributes
private:
protected:
public:
// Operations
private:
void Trim( string & str );
protected:
public:
CFstatHandler();
~CFstatHandler(){};
int GetFdCountOnSystem( std::string szFileName );
};
#endif // _FSTAT_HANDLER_H_
+201
View File
@@ -0,0 +1,201 @@
#include "HotContentDetectThread.h"
#include "DaemonConfigs.h"
#include "FstatHandler.h"
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <sys/time.h>
using namespace std;
#define HOT_CONTENT_DETECT_INTERVAL 5 // sec
#define HOT_CONTENT_INFO_CLEAR_TERM 100 // count
CHotContentDetectThread::CHotContentDetectThread()
:m_threadHandle(0), m_pReqCacheList(NULL), m_pHotContentInfoMap(NULL)
{
}
CHotContentDetectThread::~CHotContentDetectThread()
{
}
bool CHotContentDetectThread::ThreadInit(const sig_atomic_t *sighandle, CCacheRequestList * pReqCacheList /* = NULL */, CHotContentInfoMap * pHotContentInfoMap /* = NULL */)
{
m_sighandle = sighandle;
m_pReqCacheList = pReqCacheList;
m_pHotContentInfoMap = pHotContentInfoMap;
return true;
}
unsigned int CHotContentDetectThread::GetBaselineOver(std::string filenamehash)
{
// CHG 2020-07-20 huibong internal cache 관련 fd 감시 on/off 관련 기능 개선 (#33112)
// - fhs.conf 상에서 EXTRACT_FD_COUNT 항목을 명시적으로 1 로 설정해야 fd count 정보 추출기능 동작
// - 그 외에는 fd count 정보 추출 기능 동작 안함.
if( CDeamonConfig::GetInstance()->IsExtractContentFdCount() == false )
{
//LOG( LINF, "checkpoint: fd count extract setting disabled. [%s]", filenamehash.c_str() );
return 0;
}
else
{
CFstatHandler objFstatHandler;
// fstat을 활용해서 해당 파일의 현재 fd count를 얻어온다.
unsigned int nFdCount = objFstatHandler.GetFdCountOnSystem( filenamehash );
if( CDeamonConfig::GetInstance()->GetFdCount() > nFdCount )
{
//LOG( LDEV, "Fdcount : %d", nFdCount );
return 0;
}
//LOG( LDEV, "Fdcount : %d", nFdCount );
return nFdCount;
}
}
bool CHotContentDetectThread::Detector()
{
CTransferStatData data;
vector<CTransferStatData> dataList;
while (*m_sighandle == 0)
{
// Download List에서 값을 가져오기 전에 개수를 확인한다.
if (m_Transfer.GetSize() <= 0)
{
//LOG( LDEV, "TransferStatData queue is empty.");
break;
}
CTransferStatData dataTransferLog;
{
m_Transfer.Pop(dataTransferLog);
LOG(LDBG, "Dowload File Info : %s", dataTransferLog.GetFilenameHash().c_str());
// hot content replication 수행.
CHotContentData* pObjContentInfo = m_pHotContentInfoMap->GetData(dataTransferLog.GetFilenameHash());
if (pObjContentInfo == NULL)
{
// 기준선 이상 이면 카운트를 가지고 옴
unsigned int nCnt = GetBaselineOver(dataTransferLog.GetFilenameHash());
if (nCnt <= 0) continue;
// 존재 하지 않는다면.
// 1. hot content replication queue에 추가한다.
m_pReqCacheList->Push(dataTransferLog.GetFilenameHash(), (uint32_t)dataTransferLog.GetServiceSeq(), nCnt);
//LOG(LDEV, "Add File : %s", dataTransferLog.GetFilenameHash().c_str());
// 2. Hot Content Info Map에 등록
m_pHotContentInfoMap->AddData(dataTransferLog.GetFilenameHash(), nCnt);
continue;
}
else
{
// 2. 요청시간이 지정시간 이상 경과되었는가?
if (pObjContentInfo->IsReqTimeOver() == false)
{
// 경과하지 않았다면...
// 2-1. 정보 업데이트 후 진행..
//pObjContentInfo->UpdateInfo(nCnt);;
continue;
}
// 기준선 이상 이면 카운트를 가지고 옴
unsigned int nCnt = GetBaselineOver(dataTransferLog.GetFilenameHash());
if (nCnt <= 0) continue;
// 존재한다면
// 1. 증가 추이 인지 확인한다.
if (pObjContentInfo->IsIncrease(nCnt) == false)
{
// 증가 추이가 아니라면...
// 1-1. 요청이 있었으므로.. 정보 업데이트
pObjContentInfo->UpdateInfo(nCnt);
continue;
}
// 3. replication 요청 후..
// 1. hot content replication queue에 추가한다.
_LOG(LINF, "ReplicationReq state - Hash Name : %s, FdCount : %d ", dataTransferLog.GetFilenameHash().c_str(), nCnt);
m_pReqCacheList->Push(dataTransferLog.GetFilenameHash(), (uint32_t)dataTransferLog.GetServiceSeq(), nCnt);
// Hot Content Info Map Update
pObjContentInfo->UpdateInfo(nCnt);
pObjContentInfo->UpdateRequestTime();
continue;
}
}
}
FUNC_END();
return true;
}
///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CHotContentDetectThread::Execute()
{
if ( m_pReqCacheList == NULL )
{
LOG( LERR, "failed to push to download list because the instance of CCacheRequestList is NULL." );
return;
}
if( m_pHotContentInfoMap == NULL )
{
LOG( LERR, "failed to push to download list because the instance of CHotContentInfoMap is NULL." );
return;
}
while (*m_sighandle == 0)
{
// 아래 함수에서 return false 가 되더라도 무시한다.
if( Detector() == false ){;}
// 일정 시간이 지난 정보를 정리한다.
m_pHotContentInfoMap->Arrangement();
sleep( HOT_CONTENT_DETECT_INTERVAL );
}
LOG(LINF, "Thread end...");
}
void* CHotContentDetectThread::EntryPoint(void* arg)
{
CHotContentDetectThread* pObject = reinterpret_cast<CHotContentDetectThread *>(arg);
pthread_detach( pthread_self() );
pObject->Execute();
// Thread 종료시 m_threadHandle 값을 초기화 처리.
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
//pObject->m_threadHandle = 0;
return 0;
}
bool CHotContentDetectThread::Start()
{
int nRet = ::pthread_create(&m_threadHandle, 0, CHotContentDetectThread::EntryPoint, this);
if( nRet )
{
LOG(LERR, "Thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Thread create succeed");
sleep(0);
return true;
}
+74
View File
@@ -0,0 +1,74 @@
/***************************************************************************
Replicate Work Class
-----------------------------------------
begin : 2012/10/14
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 __HOT_CONTENT_DTECT_THREAD_H__
#define __HOT_CONTENT_DTECT_THREAD_H__
#include </usr/include/sys/signal.h>
#include <csignal>
#include <pthread.h>
#include <string>
#include <map>
#include <vector>
#include "Logger.h"
#include "FimngdData.h"
#include "IPCMsgQueue.h"
#include "TransferStatDataList.h"
#include "CacheRequestList.h"
#include "HotContentInfoMap.h"
/// @brief
class CHotContentDetectThread
{
public:
/// @brief 생성자
CHotContentDetectThread();
~CHotContentDetectThread();
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공은 return true 실패는 return false
bool Start();
/// @brief ProcessStatus 내의 RCDB 관련 설정값을 이용해 DB Connection을 한다.
/// @param sighandle 쓰레드에서 signal에 따라 정상 종료하도록 signal handle을 전달한다.
/// @param objMsgQueue IPC Message Queue 객체
/// @return 성공하면 return true 실패하면 return false
bool ThreadInit(const sig_atomic_t *sighandle, CCacheRequestList * pReqCacheList = NULL, CHotContentInfoMap * pHotContentInfoMap = NULL);
CTransferStatDataList* GetTransferList() { return &m_Transfer; }
// Attributes
private:
// 쓰레드 핸들
pthread_t m_threadHandle;
const sig_atomic_t *m_sighandle;
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
// 해당 함수의 내용은 수정하지 말것.
void Execute();
bool Detector();
unsigned int GetBaselineOver(std::string filenamehash);
CTransferStatDataList m_Transfer;
CCacheRequestList * m_pReqCacheList;
CHotContentInfoMap * m_pHotContentInfoMap;
};
#endif //__HOT_CONTENT_DTECT_THREAD_H__
+193
View File
@@ -0,0 +1,193 @@
/***************************************************************************
HotContentInfo.cpp
-----------------------------------------
begin : 2011/11/24
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 "HotContentInfoMap.h"
#include "Logger.h"
#include "DaemonConfigs.h"
#include "MutexLock.hpp"
#define REQUEST_TIME_OVER_SEC 180
////////////////////////////////////////////////////////////////////////////
// CHotContentData Class
////////////////////////////////////////////////////////////////////////////
CHotContentData::CHotContentData( std::string filename, int nFdCount )
{
m_szFilename = filename;
m_timeLastReq = time(0);
m_timeLastUpdate = m_timeLastReq;
m_nFdCount = nFdCount;
m_updateExpire = CDeamonConfig::GetInstance()->GetContentExpireSec();
pthread_mutex_init(&m_mutex, NULL);
}
CHotContentData::~CHotContentData()
{
ProtectedMutex mutex(m_mutex);
pthread_mutex_destroy(&m_mutex);
}
void CHotContentData::UpdateRequestTime()
{
ProtectedMutex mutex(m_mutex);
/// 요청 시간 변경.
m_timeLastReq = time(0);
}
void CHotContentData::UpdateInfo(int nFdCount)
{
ProtectedMutex mutex(m_mutex);
/// 수정 시간 변경.
m_timeLastUpdate = time(0);
m_nFdCount = nFdCount;
}
bool CHotContentData::IsIncrease(int nFdCount)
{
ProtectedMutex mutex(m_mutex);
return (m_nFdCount < nFdCount) ? true : false;
}
bool CHotContentData::IsExipireTimeout()
{
ProtectedMutex mutex(m_mutex);
/// m_timeLastUpdate 기준으로 timeout을 정한다.
if ((time(0) - m_timeLastUpdate) > m_updateExpire)
{
LOG( LDBG, "Hot content data timeout. file=%s", GetFilename().c_str() );
return true;
}
return false;
}
bool CHotContentData::IsReqTimeOver()
{
ProtectedMutex mutex(m_mutex);
/// m_timeLastUpdate 기준으로 timeout을 정한다.
if( ( time(0) - m_timeLastReq ) > REQUEST_TIME_OVER_SEC )
{
LOG( LDBG, "Not rquest timeout. file=%s", GetFilename().c_str() );
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////
// CHotContentInfoMap Class
////////////////////////////////////////////////////////////////////////////
CHotContentInfoMap::CHotContentInfoMap()
{
// CHG 2020-07-20 huibong internal cache 관련 fd 감시 on/off 관련 기능 개선 (#33112)
// - 설정 관련 잘못 맵핑된 버그 수정
//m_nMaxSize = CDeamonConfig::GetInstance()->GetContentExpireSec();
m_nMaxSize = CDeamonConfig::GetInstance()->GetContentMaxInfo();
pthread_mutex_init(&m_mutex, NULL);
}
CHotContentInfoMap::~CHotContentInfoMap()
{
ProtectedMutex mutex(m_mutex);
m_mapHotContentInfo.clear();
pthread_mutex_destroy(&m_mutex);
}
bool CHotContentInfoMap::IsOverflow()
{
ProtectedMutex mutex(m_mutex);
bool r = ((int)m_mapHotContentInfo.size() >= m_nMaxSize) ? true : false;
return r;
}
CHotContentData* CHotContentInfoMap::GetData( std::string szFilename )
{
FUNC_BEGIN();
ProtectedMutex mutex(m_mutex);
if( szFilename.empty() == true )
{
LOG( LWAR, "Input parameter filename is empty." );
FUNC_END();
return NULL;
}
map<string, CHotContentData>::iterator it;
it = m_mapHotContentInfo.find( szFilename );
if( it == m_mapHotContentInfo.end() )
{
LOG( LDBG, "No have this file information. filename=[%s]", szFilename.c_str() );
FUNC_END();
return NULL;
}
FUNC_END();
return &(it->second);
}
bool CHotContentInfoMap::AddData( std::string szFileName, int nFdCount )
{
FUNC_BEGIN();
CHotContentData data(szFileName, nFdCount);
// 1. 지정한 maxsize 보다 큰가?
if( IsOverflow() == true )
{
_LOG(LWAR, "Add failed. Because this map is full. Currunt MapSize = %zu, MaxSize = %d Filename=%s",
m_mapHotContentInfo.size(), m_nMaxSize, data.GetFilename().c_str() );
FUNC_END();
return false;
}
ProtectedMutex mutex(m_mutex);
// 2. 맵에 추가한다.
pair< map<string, CHotContentData>::iterator, bool > itRet;
itRet = m_mapHotContentInfo.insert( map<string, CHotContentData>::value_type( data.GetFilename(), data ) );
if( itRet.second == false )
{
_LOG( LWAR, "Add failed. May be already exist this file. filename = %s", data.GetFilename().c_str() );
FUNC_END();
return false;
}
_LOG( LINF, "Added this file = %s", data.GetFilename().c_str() );
FUNC_END();
return true;
}
void CHotContentInfoMap::Arrangement()
{
FUNC_BEGIN();
ProtectedMutex mutex(m_mutex);
map<string, CHotContentData>::iterator it;
for( it = m_mapHotContentInfo.begin(); it != m_mapHotContentInfo.end(); )
{
if( it->second.IsExipireTimeout() == true )
{
_LOG( LINF, "Arrangement(Delete) data. file=%s", it->second.GetFilename().c_str() );
m_mapHotContentInfo.erase( it++ );
}
else
{
++it;
}
}
FUNC_END();
}
+82
View File
@@ -0,0 +1,82 @@
/***************************************************************************
HotContentInfo.h
-----------------------------------------
begin : 2011/11/24
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 __HOT_CONTENT_INFO_MAP_H__
#define __HOT_CONTENT_INFO_MAP_H__
#include <string>
#include <map>
#include <time.h>
#include <pthread.h>
class CHotContentData
{
// Attributes
private:
std::string m_szFilename; // 파일명
time_t m_timeLastReq; // 최종 Rep 요청 시간
time_t m_timeLastUpdate; // 정보 최종 갱신 시간
int m_nFdCount; // 이전 fd count
uint32_t m_updateExpire;
pthread_mutex_t m_mutex;
protected:
public:
// Operations
private:
protected:
public:
CHotContentData( std::string filename, int nFdCount );
~CHotContentData();
void UpdateInfo(int nFdCount);
void UpdateRequestTime();
bool IsExipireTimeout();
bool IsReqTimeOver();
bool IsIncrease(int nFdCount);
inline std::string GetFilename() { return m_szFilename; };
};
class CHotContentInfoMap
{
private:
// Attributes
std::map<std::string, CHotContentData> m_mapHotContentInfo;
int m_nMaxSize;
pthread_mutex_t m_mutex;
// Operations
bool IsOverflow();
protected:
public:
CHotContentInfoMap();
virtual ~CHotContentInfoMap();
CHotContentData* GetData( std::string filename );
bool AddData( std::string szFileName, int nFdCount );
// 지정시간 이상 변경이 없는 데이터 정리.
void Arrangement();
bool IsExist() { return (m_mapHotContentInfo.size() > 0) ? true : false; }
};
#endif // __HOT_CONTENT_INFO_MAP_H__
+178
View File
@@ -0,0 +1,178 @@
#include "IPCMsgQueue.h"
#include <pwd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "Logger.h"
#define MSG_NOT_VALID -1
CIPCMsgQueue::CIPCMsgQueue()
: m_msqid(MSG_NOT_VALID), m_key(MSG_NOT_VALID)
{
}
CIPCMsgQueue::CIPCMsgQueue(key_t qkey, int msgflg /* = IPC_CREAT | 0644 */, const char* user /* = "nobody" */, uint32_t qsize /* = 0 */)
: m_msqid(MSG_NOT_VALID), m_key(qkey), m_msgflg(msgflg), m_user(user), m_qsize(qsize)
{
}
CIPCMsgQueue::~CIPCMsgQueue()
{
}
bool CIPCMsgQueue::Create()
{
bool r = true;
if (m_key == MSG_NOT_VALID)
{
LOG(LERR, "Key message has not been set.");
cerr << "Key message has not been set." << endl;
return false;
}
m_msqid = msgget(m_key, m_msgflg);
if (m_msqid == MSG_NOT_VALID)
{
LOG(LERR, "cannot create [%s]", strerror(errno));
cerr << "cannot create [" << strerror(errno) << "]" << endl;
r = false;
}
r = CtlOperations(IPC_SET);
return r;
}
bool CIPCMsgQueue::Create(key_t qkey, int msgflg /* = IPC_CREAT | 0644 */, const char* user /* = "nobody" */, uint32_t qsize /* = 0 */)
{
if (m_key != MSG_NOT_VALID)
{
LOG(LERR, "Got the message key is set, you can not use that function.");
cerr << "Got the message key is set, you can not use that function." << endl;
return false;
}
return ChangeQueue(qkey, msgflg, user, qsize);
}
bool CIPCMsgQueue::ChangeQueue(key_t qkey, int msgflg /* = IPC_CREAT | 0644 */, const char* user /* = "nobody" */, uint32_t qsize /* = 0 */)
{
m_msqid = MSG_NOT_VALID;
m_key = qkey;
m_msgflg = msgflg;
m_user = user;
m_qsize = qsize;
return Create();
}
bool CIPCMsgQueue::Remove()
{
return CtlOperations(IPC_RMID);
}
bool CIPCMsgQueue::CtlOperations(int cmd)
{
struct msqid_ds msginfo;
struct passwd *pwd = NULL;
if (m_msqid == MSG_NOT_VALID)
{
LOG(LERR, "A message queue could not be created.");
cerr << "A message queue could not be created." << endl;
return false;
}
if (m_user.size())
{
if ((pwd = getpwnam(m_user.c_str())) == NULL)
{
LOG(LERR, "cannot find user '%s'", m_user.c_str());
cerr << "cannot find user '" << m_user << "'" << endl;
return false;
}
}
if (msgctl(m_msqid, IPC_STAT, &msginfo) == -1)
{
LOG(LERR, "cannot get status [%s]", strerror(errno));
cerr << "cannot get status [" << strerror(errno) << "]" << endl;
return false;
}
if (m_qsize > 0)
msginfo.msg_qbytes = m_qsize;
if (pwd) {
msginfo.msg_perm.uid = pwd->pw_uid;
msginfo.msg_perm.gid = pwd->pw_gid;
}
if (msgctl(m_msqid, cmd, &msginfo) == -1)
{
LOG(LERR, "cannot set status [%s]", strerror(errno));
cerr << "cannot set status [" << strerror(errno) << "]" << endl;
return false;
}
return true;
}
int CIPCMsgQueue::Pop(void * data, size_t maxmsgsz, int flags /* = IPC_NOWAIT */, long msgtype /* = 0 */)
{
if (m_msqid == MSG_NOT_VALID)
{
LOG(LERR, "A message queue could not be created.");
cerr << "A message queue could not be created." << endl;
return -2;
}
ssize_t msglen = msgrcv(m_msqid, data, maxmsgsz, msgtype, flags);
if (msglen == -1)
{
int err = errno;
if (err != ENOMSG)
{
LOG(LERR, "can't pop data to ipc message queue because msgrcv() fail. [%s(%d)].", strerror(err), err);
cerr << "can't pop data to ipc message queue because msgrcv() fail. [" << strerror(err) << "(" << err << ")]" << endl;
return -1;
}
else
{
if (flags != IPC_NOWAIT)
{
LOG(LWAR, "There is no message of the requested type available on the message queue.");
cerr << "There is no message of the requested type available on the message queue." << endl;
}
return 0;
}
}
return msglen;
}
int CIPCMsgQueue::Push(void * data, size_t maxmsgsz, int flags /* = IPC_NOWAIT */)
{
if (m_msqid == MSG_NOT_VALID)
{
LOG(LERR, "A message queue could not be created.");
cerr << "A message queue could not be created." << endl;
return -2;
}
if (msgsnd(m_msqid, data, maxmsgsz, flags) == -1)
{
int err = errno;
LOG(LERR, "can't push data to ipc message queue because msgsnd() fail.[%s(%d)]", strerror(err),err);
cerr << "can't push data to ipc message queue because msgsnd() fail. [" << strerror(err) << "(" << err<< ")]" << endl;
return -1;
}
return (maxmsgsz);
}
+72
View File
@@ -0,0 +1,72 @@
/***************************************************************************
System V IPC message queue class
-----------------------------------------
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.
*****************************************************************************/
// FreeBSD limit : ipcs -Q
#ifndef __IPC_MESSAGE_QUEUE__
#define __IPC_MESSAGE_QUEUE__
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string>
#include <iostream>
using namespace std;
class CIPCMsgQueue
{
public:
CIPCMsgQueue();
CIPCMsgQueue(key_t qkey, int msgflg = IPC_CREAT | 0644, const char* user = "nobody", uint32_t qsize = 0);
~CIPCMsgQueue();
// 메세지 큐 생성
bool Create();
bool Create(key_t qkey, int msgflg = IPC_CREAT | 0644, const char* user = "nobody", uint32_t qsize = 0);
// 메세지 큐 변경
bool ChangeQueue(key_t qkey, int msgflg = IPC_CREAT | 0644, const char* user = "nobody", uint32_t qsize = 0);
// 메세지 큐 삭제
bool Remove();
// 큐 데이터 pop
// IPC_NOWAIT : 비동기화
// return
// 0 < : 비정상
// 0 : 큐 비워있음
// 0 > : 해당 큐에 읽음 데이터 size
int Pop(void * data, size_t maxmsgsz, int flags = IPC_NOWAIT, long msgtype = 0);
// 큐 데이터 push
// IPC_NOWAIT : 비동기화
// return
// 0 > : 비정상
// 0 =< : 성공
int Push(void * data, size_t maxmsgsz, int flags = IPC_NOWAIT);
private:
bool CtlOperations(int cmd);
int m_msqid;
key_t m_key;
int m_msgflg;
string m_user;
uint32_t m_qsize;
};
#endif // __IPC_MESSAGE_QUEUE__
+441
View File
@@ -0,0 +1,441 @@
/****************************************************************************
Main ( main.cpp )
-----------------------------------------
begin : 2015/03/18
copyright : (C) 2013 Solbox Inc.
author : Development Team
- 2015/04/23 - 1st dadamin
email : storage.sd@solbox.com
version : 3.5
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#include <cstdlib>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <map>
#include <sstream>
#include <apr.h>
#include <apr_general.h>
#include "Logger.h"
#include "Signal_handle.h"
#include "ArgParser.h"
#include "DaemonConfigs.h"
#include "Process.h"
#include "ProcessDummy.h"
#include "WorkerServiceInfoUpdater.h"
#include "WorkerFhsInfoUpdater.h"
#include "WorkerNetworkStatSender.h"
#include "WorkerMessageQueueControl.h"
using namespace std;
static int _pid = -1;
static bool _isDaemon = true;
// signal
class SIGTerminate_Handler : public Event_Handler
{
public:
SIGTerminate_Handler(void)
: graceful_quit_(0) {}
// Hook method.
virtual int handle_signal(int signum)
{
this->graceful_quit_ = 1;
return 0;
}
// Accessor.
sig_atomic_t graceful_quit(void)
{
return this->graceful_quit_;
}
sig_atomic_t* get_signalhandel()
{
return &graceful_quit_;
}
private:
sig_atomic_t graceful_quit_;
};
class SIGWorkerDead_Handler : public Event_Handler
{
public:
SIGWorkerDead_Handler(void) {}
// Hook method.
virtual int handle_signal(int signum)
{
pid_t deadpid;
int nstatus;
while ((deadpid = waitpid(-1, &nstatus, WNOHANG)) > 0)
{
if (WIFEXITED(nstatus))
{
// 자식 프로세스가 정상적으로 종료되었는지 검사.
LOG(LWAR, "Worker process [%d] killed by signal[SIGTERM]", deadpid);
}
else if (WIFSIGNALED(nstatus))
{
// 자식 프로세스가 Signal 에 의해 종료되었는지 검사.
LOG(LWAR, "Worker process [%d] killed by signal[%d]", deadpid, WTERMSIG(nstatus));
}
else
{
LOG(LWAR, "Worker process [%d] killed. Not signal", deadpid);
}
if (WEXITSTATUS(nstatus) == EXIT_FAILURE)
{
// Main 종료 시그널 발생
raise(SIGTERM);
continue;
}
map<pid_t, CProcess*>::iterator it = m_child.find(deadpid);
if ( it != m_child.end())
{
// find it
CProcess *p = it->second;
set_reprocess(p);
m_child.erase(it);
}
else
{
LOG(LERR, "Worker process [%d] not found it. and can't be recreated.", deadpid);
}
}
// 오류 발생시 해당 내역 로깅
if (deadpid < 0)
{
LOG(LERR, "Main process error: SIG_CHLD receive but waitpid return error[%d][%s]", errno, strerror(errno));
}
return 0;
}
void add_child(pid_t pid, CProcess *process)
{
m_child.insert(pair<pid_t, CProcess*>(pid, process));
}
CProcess* get_reprocess()
{
if (m_vecreprocess.empty())
return NULL;
CProcess *p = m_vecreprocess.back();
m_vecreprocess.pop_back();
return p;
}
void set_reprocess(CProcess *p)
{
m_vecreprocess.push_back(p);
}
void show_all()
{
for (map<pid_t, CProcess*>::iterator it = m_child.begin(); it != m_child.end(); ++it)
{
LOG(LDEV2, "Child process[%d]", it->first);
}
}
void kill_child()
{
for (map<pid_t, CProcess*>::iterator it = m_child.begin(); it != m_child.end(); ++it)
{
while (waitpid(it->first, NULL, WNOHANG) == 0)
{
LOG(LDEV2, "Child kill process [%d]", it->first);
kill(it->first, SIGTERM);
// 잠시 대기 후 재시도 처리
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 5000000; // 0.005 sec
nanosleep(&sleep, NULL);
}
}
}
void clear_reprocess()
{
m_vecreprocess.clear();
}
void clear_all()
{
m_child.clear();
m_vecreprocess.clear();
}
private:
map<pid_t, CProcess*> m_child;
vector<CProcess*> m_vecreprocess;
};
// start log
static void StartLog()
{
// Process 기동 관련 정보 기록 -> Log
_LOG(LINF, "***********************************************************");
_LOG(LINF, " %s Start. Version: %s", PROG_NAME, PROG_VERSION);
_LOG(LINF, "***********************************************************");
_LOG(LINF, "Config : %s", CDeamonConfig::GetInstance()->GetConfigFile());
_LOG(LINF, "Log : %s/%s", CDeamonConfig::GetInstance()->GetAppLogRoot(), PROG_NAME);
_LOG(LINF, "Log level : %d", CDeamonConfig::GetInstance()->GetAppLogLevel());
_LOG(LINF, "RC ID : %s", CDeamonConfig::GetInstance()->GetRCID());
_LOG(LINF, "RCDB : %s %u %s %s", CDeamonConfig::GetInstance()->GetDBInfo().m_szRcdbIp.c_str()
, CDeamonConfig::GetInstance()->GetDBInfo().m_nRcdbPort
, CDeamonConfig::GetInstance()->GetDBInfo().m_szRcdbAcct.c_str()
, CDeamonConfig::GetInstance()->GetDBInfo().m_szRcdbAcctPw.c_str());
_LOG(LINF, "Max FHS : %d", CDeamonConfig::GetInstance()->GetMaxFhs());
_LOG(LINF, "Max Account : %d", CDeamonConfig::GetInstance()->GetMaxAccount());
_LOG(LINF, "Max Anonymous : %d", CDeamonConfig::GetInstance()->GetMaxAnonyMous());
_LOG(LINF, "Extract fd count : %s", ( CDeamonConfig::GetInstance()->IsExtractContentFdCount() == true ? "on" : "off") );
_LOG(LINF, "***********************************************************");
}
// print Version
static void Version()
{
cerr << "Version : " PROG_NAME " " PROG_VERSION << endl;
}
// print usage
static void Usage()
{
cerr << "usage: " PROG_NAME " [-c file]" << endl;
cerr << " [-v] [-h] [-D]" << endl;
cerr << " -v : show version number" << endl;
cerr << " -h : list available command line options (this page)" << endl;
cerr << " -D : run console mode" << endl;
cerr << " -c file : process directive reading config files" << endl;
cerr << endl << endl;
cerr << PROG_NAME << " is FHS Internal Management daemon." << endl;
}
// main function
int main(int argc, char * argv[])
{
apr_initialize();
save_ps_display_args(argc, argv);
string strConfPath = DEFAULT_CONFIG_FILE;
// parse Input argument
CArgParser argparser(argc, argv);
if (argparser.checkvalue("-v"))
{
Version();
return EXIT_SUCCESS;
}
if (argparser.checkvalue("-h"))
{
Usage();
return EXIT_FAILURE;
}
if (argparser.checkvalue("-D"))
{
_isDaemon = false;
}
string val;
if (argparser.checkvalue("-c", &val))
{
#ifdef _DEBUG
cout << "Change conf path " << strConfPath << " to " << val << endl;
#endif // _DEBUG
strConfPath = val;
}
//check process
if (CProcess::IsCurrentProcessRun(PROG_NAME))
return EXIT_FAILURE;
//initialized Config object
if (CDeamonConfig::Init(PROG_NAME, strConfPath) == false)
{
cerr << "[ERR] Failed to initialize the config object." << endl;
return EXIT_FAILURE;
}
// load config
if (CDeamonConfig::GetInstance()->LoadConf() == false)
{
cerr << "[ERR] Config load error." << CDeamonConfig::GetInstance()->GetErrMessage() << endl;
return EXIT_FAILURE;
}
if (CDeamonConfig::GetInstance()->CheckValue() == false)
{
cerr << "[ERR] Config load error." << CDeamonConfig::GetInstance()->GetErrMessage() << endl;
return EXIT_FAILURE;
}
// initialized Log object
if (CLogger::Init(PROG_NAME, CDeamonConfig::GetInstance()->GetAppLogRoot(),
CDeamonConfig::GetInstance()->GetAppLogLevel()) == false)
{
cerr << "[ERR] Failed to initialize the log object." << endl;
return EXIT_FAILURE;
}
// set signal
SIGTerminate_Handler terminate;
SIGWorkerDead_Handler workerdead;
Signal_Handler::instance()->register_ignore(SIGPIPE);
Signal_Handler::instance()->register_ignore(SIGHUP);
Signal_Handler::instance()->register_ignore(SIGQUIT);
Signal_Handler::instance()->register_handler(SIGTERM, &terminate);
Signal_Handler::instance()->register_handler(SIGINT, &terminate);
// daemonize
if (_isDaemon && CProcess::Daemon() == false)
{
return EXIT_FAILURE;
}
StartLog();
int exitcode = EXIT_SUCCESS;
_pid = getpid();
// set work process
// alive check dummy process create
CProcessDummy objAliveCheck;
objAliveCheck.SetPort(CDeamonConfig::GetInstance()->GetAliveCheckPort());
workerdead.set_reprocess(&objAliveCheck);
// Service Info Updater Worker
CWorkerServiceInfoUpdater workerServiceInfoUpdater;
workerdead.set_reprocess(&workerServiceInfoUpdater);
// fhs status info updater worker
CWorkerFhsInfoUpdater workerFhsInfoUpdater;
workerdead.set_reprocess(&workerFhsInfoUpdater);
// Service network stat sender
CWorkerNetworkStatSender workerNetworkStatSender;
workerdead.set_reprocess(&workerNetworkStatSender);
// Meesage Queue Controler
CWorkerMessageQueueControl workerMessageQueueControl;
workerdead.set_reprocess(&workerMessageQueueControl);
// Run the main event loop.
while (terminate.graceful_quit() == 0)
{
// make work process
CProcess* p = NULL;
while ((p = workerdead.get_reprocess()) != NULL )
{
p->Launcher(terminate.get_signalhandel());
if (p->Getpid() > 0)
{
// main(parent) process
if (p->Is_launched() == false)
{
exitcode = EXIT_FAILURE;
// error
cerr << "Worker Process create failed." << endl;
LOG(LERR, "Worker Process create failed.");
break;
}
workerdead.add_child(p->Getpid(), p);
}
else if (p->Getpid() == 0)
{
// work(child) process
workerdead.clear_all();
}
else
{
// error
exitcode = EXIT_FAILURE;
cerr << "Worker Process create failed.(fork error)" << endl;
LOG(LERR, "Worker Process create failed.(fork error)");
break;
}
}
if (exitcode == EXIT_FAILURE)
break;
if (_pid == getpid())
{
// main(parent) process
// wait
set_ps_display("main [monitor worker process]", false);
Signal_Handler::instance()->register_handler(SIGCHLD, &workerdead);
pause();
}
else
{
// work(child) process
_pid = 0;
}
}
if (exitcode == EXIT_SUCCESS)
Signal_Handler::instance()->remove_handler(SIGCHLD);
Signal_Handler::instance()->remove_handler(SIGTERM);
Signal_Handler::instance()->remove_handler(SIGINT);
if (_pid > 0)
{
if (terminate.graceful_quit())
{
// KILL - Child
//kill(0, SIGTERM);
// waitpid
//while (waitpid(0, NULL, WNOHANG) > 0);
workerdead.kill_child();
}
}
if (CProcess::IsProcessRun("httpd") == false)
apr_terminate();
// end
ostringstream msg;
if (_pid == getpid())
msg << "Main Process [" << getpid() << "] exit job end. Good Bye..";
else
msg << "Worker Process [" << getpid() << "] exit job end. Good Bye..";
_LOG(LINF, msg.str().c_str());
cerr << msg.str() << endl;
CLogger::Exit();
CDeamonConfig::Exit();
return exitcode;
}
+89
View File
@@ -0,0 +1,89 @@
#****************************************************************************
# Makefile for fimngd
# -----------------------------------------
#
# begin : 2013/04/23
# copyright : (C) 2005 Solbox Inc.
# author : Development Team (Storage Part)
# email : storage.sd@solbox.com
# version : 3.5
#
# CopyRight(C) 2005 Solbox Inc. All Rights reserved.
# Redistribution and use in source and binary forms, with or with out
# modification, are not permitted in outside of Solbox Inc.
#*****************************************************************************
# Program info
PROG_NAME = fimngd
REVISION = 1501
PROG_VERSION = 3.5.0.$(REVISION)-`date +%Y%m%d%H%M%S`
DEFAULT_CONFIG_FILE = /user/service/etc/fhs.conf
APACHE_DIR = /user/service/httpd
APACHE_INCLUDES = $(APACHE_DIR)/include
APACHE_LIB= $(APACHE_DIR)/lib
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 =
# DEBUG or RELEASE Mode select
#DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -D__TEST__
DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
# Application Enviroment
APP = $(PROG_NAME)
DIR_INCLUDE = -I../lib -I/user/db/pgsql/include -I $(APACHE_INCLUDES)
DIR_LIB = -L../lib -L$(APACHE_LIB)
LIBS = -lpthread /user/db/pgsql/lib/libpq.a ../lib/libInterCommon.a $(APACHE_LIB)/libapr-1.a
#LIBS = -lpthread /user/db/pgsql/lib/libpq.a ../lib/libInterCommon.a ./libapr-1.a
OBJ = ArgParser.o Signal_handle.o SharedMemAPR.o IPCMsgQueue.o Database.o\
ProcessRename.o Process.o\
DaemonConfigs.o\
ProcessDummy.o Main.o\
WorkerServiceInfoUpdater.o AccountUpdateThread.o AnonyUpdateThread.o \
WorkerFhsInfoUpdater.o FhsStatUpdateThread.o \
WorkerMessageQueueControl.o MsgQueuePopThread.o TransferStatData.o TransferStatDataList.o CacheRequestList.o CacheGeneratorThread.o \
FstatHandler.o HotContentDetectThread.o HotContentInfoMap.o \
WorkerNetworkStatSender.o NetworkStatSendThread.o \
SocketControl.o
#---------------------------------------------------------------------#
all:$(APP)
sync
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
$(PROG_NAME): $(OBJ)
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
clean:
-rm -f *.o core.$(PROG_NAME).* $(PROG_NAME).core *.out *.log
-rm -f $(APP)
sync
install : $(APP)
-cp $(APP) $(INSTALL_BIN)/$(APP)
sync
# End of Makefile
+153
View File
@@ -0,0 +1,153 @@
#include "MsgQueuePopThread.h"
#include "DaemonConfigs.h"
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <sys/time.h>
using namespace std;
#define DEFAULT_QUERY_BUFFER_SIZE 1024
#define QUERY_LIMIT_COUNT 2000
#define UPDATE_TERM 180
#define CONTENT_QUEUE_SLEEP 100000 // 0.1sec
CMsgQueuePopThread::CMsgQueuePopThread()
:m_threadHandle(0), m_pTransfer(NULL)
{
}
CMsgQueuePopThread::~CMsgQueuePopThread()
{
}
bool CMsgQueuePopThread::ThreadInit(const sig_atomic_t *sighandle, std::vector<CIPCMsgQueue> &vecContentQueue, CTransferStatDataList *pTransfer /* = NULL */)
{
m_sighandle = sighandle;
m_vecContentQueue = vecContentQueue;
m_pTransfer = pTransfer;
return true;
}
bool CMsgQueuePopThread::ThreadInit(const sig_atomic_t *sighandle, CIPCMsgQueue &cContentQueue, CTransferStatDataList *pTransfer /* = NULL */)
{
m_sighandle = sighandle;
m_vecContentQueue.push_back(cContentQueue);
m_pTransfer = pTransfer;
return true;
}
void CMsgQueuePopThread::Pop()
{
int nResult = 0;
for( vector<CIPCMsgQueue>::size_type i = 0; i < m_vecContentQueue.size(); ++i )
{
// 2016.03.19 dadamin
// 잘못된 메모리 참조 오류 발생
struct Transfer_stat ipcmsg = {0};
CTransferStatData data;
nResult = m_vecContentQueue[i].Pop(&ipcmsg, sizeof(struct Transfer_stat), IPC_NOWAIT, 0);
data.SetTransferStatData(ipcmsg);
switch(nResult)
{
// 큐가 생성 되지 않은 경우
case -2 :
{
LOG(LERR, "A message queue could not be created.");
continue;
}
// 큐가 유효하지 않은 경우
case -1:
{
LOG(LERR, "Message queue pop fail. [%s(%d)].", strerror(errno), errno);
continue;
}
// Queue에 가져올 데이터가 없는경우
case 0:
{
LOG(LDEV, "Message queue no have data.");
continue;
}
default:
{
if (nResult > 0)
{
// GET 요청에 대한 정보이면 CTransferStatDataListList에 등록한다.
if ((data.GetDirection() == 0) && (data.GetFilenameHash().size() > 0))
{
if (m_pTransfer) m_pTransfer->Push(data);
}
--i;
}
}
}
}
}
///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CMsgQueuePopThread::Execute()
{
// CTransferStatDataListinstance 생성을 체크 한다.
if( m_pTransfer == NULL )
{
LOG( LERR, "failed to push to download list because the instance of CTransferStatDataListList is NULL." );
return;
}
while (*m_sighandle == 0)
{
/// 연결 된 Qeue에서 5개의 메시지 큐에서 데이터를 하나씩 pop한 리스트를 가지고 온다.
Pop();
/// 큐가 비어 있는 상태이기 때문에 대기한다.
if (*m_sighandle == 0)
{
//usleep( CONTENT_QUEUE_SLEEP );
struct timespec sleep;
sleep.tv_sec = 0;
//sleep.tv_nsec = CONTENT_QUEUE_SLEEP * 1000 ; // 0.1 sec
sleep.tv_nsec = 100000000; // 0.1 sec
nanosleep(&sleep, NULL);
}
}
LOG(LINF, "Thread end...");
}
void* CMsgQueuePopThread::EntryPoint(void* arg)
{
CMsgQueuePopThread* pObject = reinterpret_cast<CMsgQueuePopThread *>(arg);
pthread_detach( pthread_self() );
pObject->Execute();
// Thread 종료시 m_threadHandle 값을 초기화 처리.
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
//pObject->m_threadHandle = 0;
return 0;
}
bool CMsgQueuePopThread::Start()
{
int nRet = ::pthread_create(&m_threadHandle, 0, CMsgQueuePopThread::EntryPoint, this);
if( nRet )
{
LOG(LERR, "Thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Thread create succeed");
sleep(0);
return true;
}
+68
View File
@@ -0,0 +1,68 @@
/***************************************************************************
Replicate Work Class
-----------------------------------------
begin : 2012/10/14
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 __MSG_QUEUE_POP_THREAD__
#define __MSG_QUEUE_POP_THREAD__
#include </usr/include/sys/signal.h>
#include <csignal>
#include <pthread.h>
#include <string>
#include <map>
#include <vector>
#include "Logger.h"
#include "FimngdData.h"
#include "IPCMsgQueue.h"
#include "TransferStatDataList.h"
/// @brief
class CMsgQueuePopThread
{
public:
/// @brief 생성자
CMsgQueuePopThread();
~CMsgQueuePopThread();
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공은 return true 실패는 return false
bool Start();
/// @brief ProcessStatus 내의 RCDB 관련 설정값을 이용해 DB Connection을 한다.
/// @param sighandle 쓰레드에서 signal에 따라 정상 종료하도록 signal handle을 전달한다.
/// @param objMsgQueue IPC Message Queue 객체
/// @return 성공하면 return true 실패하면 return false
bool ThreadInit(const sig_atomic_t *sighandle, std::vector<CIPCMsgQueue> &vecContentQueue, CTransferStatDataList *pTransfer = NULL);
bool ThreadInit(const sig_atomic_t *sighandle, CIPCMsgQueue &cContentQueue, CTransferStatDataList *pTransfer = NULL);
// Attributes
private:
// 쓰레드 핸들
pthread_t m_threadHandle;
const sig_atomic_t *m_sighandle;
std::vector<CIPCMsgQueue> m_vecContentQueue;
CTransferStatDataList * m_pTransfer;
void Pop();
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
// 해당 함수의 내용은 수정하지 말것.
void Execute();
};
#endif //__MSG_QUEUE_POP_THREAD__
+37
View File
@@ -0,0 +1,37 @@
/***************************************************************************
Mutex lock class
-----------------------------------------
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 __MUTEX_LOCK_CALSS__
#define __MUTEX_LOCK_CALSS__
#include <pthread.h>
class ProtectedMutex
{
pthread_mutex_t &mutex;
public:
ProtectedMutex(pthread_mutex_t &m)
: mutex(m)
{
pthread_mutex_lock(&mutex);
}
~ProtectedMutex()
{
pthread_mutex_unlock(&mutex);
}
};
#endif // __MUTEX_LOCK_CALSS__
+244
View File
@@ -0,0 +1,244 @@
#include "NetworkStatSendThread.h"
#include "DaemonConfigs.h"
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <sys/time.h>
using namespace std;
#define STAT_STAMP(a) (((a) + 299) / 300) // 5분 단위 stamp를 얻기 위한 정의
#define STAT_LOC(a) ((a) - (((a) >> 1) << 1)) // 입력값이 짝수인지 홀수인지 판단하기 위함 --> 실제로
#define RESP_TIMEOUT 2 // 응답 수신 타임 아웃 (sec)
CNetworkStatSendThread::CNetworkStatSendThread()
{
// 멤버 변수 초기화
m_threadHandle = 0;
}
CNetworkStatSendThread::~CNetworkStatSendThread()
{
}
bool CNetworkStatSendThread::ThreadInit(const sig_atomic_t *sighandle, CSharedMem* pshmemNetworStat)
{
m_sighandle = sighandle;
m_pshmemNetworStat = pshmemNetworStat;
m_szHost = CDeamonConfig::GetInstance()->GetRctsServer();
m_nPort = CDeamonConfig::GetInstance()->GetTransferStatPort();
// 연결이 안되더라도... rc_mond가 구동 되면 소켓연결 하도록 처리되어있으므로...
// warning 메시지만 로깅하고 넘어간다.
if( m_objSocket.ConnectTarget( m_szHost, m_nPort ) == false )
{
LOG( LWAR, "CFhsStatUpdateThread: rc_sscd connect fail.[%s][%d]", m_szHost.c_str(), m_nPort );
}
return true;
}
void CNetworkStatSendThread::printNetworkStat(struct service_network_stat* pobjNetstat)
{
LOG(LDBG, "xxxxx printNetworkStatxxxxx");
_LOG(LDBG, " nServiceSeq: %d", pobjNetstat->nServiceSeq);
_LOG(LDBG, " nUserSeq: %d", pobjNetstat->nUserSeq);
_LOG(LDBG, " timestamp: %d", pobjNetstat->timestamp);
_LOG(LDBG, " down_content_size: %ld", pobjNetstat->down_content_size);
_LOG(LDBG, " up_content_size: %ld", pobjNetstat->up_content_size);
_LOG(LDBG, " down_traffic: %ld", pobjNetstat->down_traffic);
_LOG(LDBG, " up_traffic: %ld", pobjNetstat->up_traffic);
}
void CNetworkStatSendThread::GetNetworkStat()
{
struct service_network_stat* pSharedHeader = (struct service_network_stat*)m_pshmemNetworStat->GetData();
int nMaxVolume = CDeamonConfig::GetInstance()->GetMaxAccount();
time_t t = time(0);
// 현재 시간대의 직전에 해당하는 값을 가져오기 위해 -1을 해준다.
unsigned int stamp = STAT_STAMP(t) -1;
for(int i = 0; i < nMaxVolume; i++ )
{
LOG(LDEV, "xxxxxxxxxxxxstamp: %d, index : %d]", stamp, (i << 1) + STAT_LOC(stamp) );
struct service_network_stat* pCurNetworkStat = (pSharedHeader + (i << 1) + STAT_LOC(stamp));
// nServiceSeq 값이 없는 경우는 shared 메모리의 마지막이라고 판단 함
if( pCurNetworkStat->nServiceSeq == 0 )
{
LOG(LDBG, "Shared Memory End. [index: %d]", i );
// 맵에 데이터가 남을 경우 해당 인덱스부터 추가해 주기 위해 저장한다.
break;
}
printNetworkStat(pCurNetworkStat);
struct service_network_stat objNetworkStat = *pCurNetworkStat;
if( stamp != objNetworkStat.timestamp )
{
LOG(LDEV, "[cur stamp: %d, shared stamp: %d ]", stamp, objNetworkStat.timestamp);
continue;
}
if( objNetworkStat.down_content_size == 0 && objNetworkStat.up_content_size == 0 )
{
continue;
}
m_vecNetworkStat.push_back(objNetworkStat);
}
}
bool CNetworkStatSendThread::NetworkStatSend()
{
// 1. socket이 유효한지 판단한다.
// 1-1. 유효하지 않다면 connect를 다시한다.
// 1-2. 연결 실패 시 return false;
if ( m_objSocket.IsValidSocket() == false )
{
if( m_objSocket.ConnectTarget( m_szHost, m_nPort ) == false )
{
LOG( LWAR, "CFhsStatUpdateThread: rc_sscd connect fail.[%s][%d]", m_szHost.c_str(), m_nPort );
return false;
}
}
// 2. vector에 있는 data를 rc_sscd로 보낸다.
char szHostname[HOSTNAME_LEN];
if( gethostname( szHostname, HOSTNAME_LEN ) != 0 )
{
LOG(LWAR, "gethostname() failed." );
return false;
}
if( m_objSocket.SendNetworkStat(CDeamonConfig::GetInstance()->GetRCID(), szHostname, m_vecNetworkStat) == false )
{
// SendNetworkStat() 함수 내부에서 로깅처리 됨.
LOG(LINF, "The number of data to send the network state is [%d].", (int)m_vecNetworkStat.size() );
m_objSocket.Close();
return false;
}
if (m_objSocket.GetNetworkStatResult(RESP_TIMEOUT) == false)
{
// SendNetworkStat() 함수 내부에서 로깅처리 됨.
LOG(LINF, "The number of data to send the network state is [%d].", (int)m_vecNetworkStat.size());
m_objSocket.Close();
return false;
}
m_vecNetworkStat.clear();
_LOG(LINF, "Network Stat Send OK!! " );
return true;
}
///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CNetworkStatSendThread::Execute()
{
time_t currentTime; // 현재 시간 정보를 저장하기 위한 변수..
unsigned long nowTimestamp;
unsigned long lastSendTimestamp = 0; // rcts 로 전송 시도한 마지막 timestamp 값 (5분단위)
unsigned long lastPopTimestamp = 0; // shard memory 에서 마지막 pop한 timestamp 값 (5분단위)
while (*m_sighandle == 0)
{
// 1. 현재 시간 정보 추출..
currentTime = time(0);
// 2. 현재 timestamp 값을 계산한다...
// (5초마다 전송위해)4 sec 보정 처리하여 5분 단위 timestamp 값을 추출한다.
nowTimestamp = (currentTime - 4 + 299) / 300;
// 3. 최초 기동 또는 시간 동기화 이상으로 reset 처리된 경우... lastSendTimestamp = 0
if (lastSendTimestamp == 0)
{
lastSendTimestamp = nowTimestamp;
sleep(1);
continue;
}
// 4. 마지막 timestamp 값과 현재 timestamp 계산 값이 같은 경우...
// 이미 전송한 것으로 판단하고.. 쉰다.
if (nowTimestamp == lastSendTimestamp)
{
sleep(1);
continue;
}
// 만약 lastSendTimestamp > nowTimestamp 인 경우...
// - 시간 동기화 이상으로 이전에 계산된 timestamp 값이 잘못된 경우.... 보정처리..
if (nowTimestamp < lastSendTimestamp)
{
_LOG(LWAR, "Network Stat Send : Last timestamp not valid. skip and reset. now[%lu] last[%lu]", nowTimestamp, lastSendTimestamp);
lastSendTimestamp = 0;
sleep(10);
continue;
}
if (lastPopTimestamp < nowTimestamp)
{
lastPopTimestamp = nowTimestamp;
GetNetworkStat();
}
// 보낼 data가 있을 경우
if (m_vecNetworkStat.size() > 0)
{
// 함수내에서 logging 처리 함.
NetworkStatSend();
if (m_vecNetworkStat.empty())
{
lastSendTimestamp = nowTimestamp;
}
else
{
// 재시도
sleep(5);
}
}
else {
sleep(1);
}
}
LOG(LINF, "Thread end.");
}
void* CNetworkStatSendThread::EntryPoint(void* arg)
{
CNetworkStatSendThread* pObject = reinterpret_cast<CNetworkStatSendThread *>(arg);
pthread_detach( pthread_self() );
pObject->Execute();
// Thread 종료시 m_threadHandle 값을 초기화 처리.
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
pObject->m_threadHandle = 0;
return 0;
}
bool CNetworkStatSendThread::Start()
{
int nRet = ::pthread_create(&m_threadHandle, 0, CNetworkStatSendThread::EntryPoint, this);
if( nRet )
{
LOG(LERR, "Thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Thread create succeed");
sleep(0);
return true;
}
+73
View File
@@ -0,0 +1,73 @@
/***************************************************************************
Replicate Work Class
-----------------------------------------
begin : 2012/10/14
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 __NETWORK_STAT_SEND_THREAD__
#define __NETWORK_STAT_SEND_THREAD__
#include <pthread.h>
#include <string>
#include <vector>
#include "Logger.h"
#include "Database.h"
#include "FimngdData.h"
#include "SharedMemAPR.h"
#include "SocketControl.h"
/// @brief
class CNetworkStatSendThread
{
public:
/// @brief 생성자
CNetworkStatSendThread();
~CNetworkStatSendThread();
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공은 return true 실패는 return false
bool Start();
/// @brief ProcessStatus 내의 RCDB 관련 설정값을 이용해 DB Connection을 한다.
/// @param sighandle 쓰레드에서 signal에 따라 정상 종료하도록 signal handle을 전달한다.
/// @param pshmemNetworStat 공유메모리 포인터
/// @return 성공하면 return true 실패하면 return false
bool ThreadInit(const sig_atomic_t *sighandle, CSharedMem* pshmemNetworStat);
// Attributes
private:
// 쓰레드 핸들
pthread_t m_threadHandle;
CSocketControl m_objSocket;
// rc_sscd host & port info
std::string m_szHost;
int m_nPort;
const sig_atomic_t *m_sighandle;
CSharedMem* m_pshmemNetworStat;
std::vector<struct service_network_stat> m_vecNetworkStat;
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
// 해당 함수의 내용은 수정하지 말것.
void Execute();
void GetNetworkStat();
bool NetworkStatSend();
void printNetworkStat(struct service_network_stat* pobjNetstat);
};
#endif //__NETWORK_STAT_SEND_THREAD__
+131
View File
@@ -0,0 +1,131 @@
#include "Process.h"
bool CProcess::IS_DAEMON = false;
CProcess::CProcess()
: m_pid(-1), m_launched(false)
{
}
CProcess::~CProcess()
{
}
bool CProcess::Daemon() {
if (IS_DAEMON == false && daemon(1, 0) == -1) {
cerr << "Error detaching";
return false;
}
IS_DAEMON = true;
return true;
}
bool CProcess::IsProcessRun(const char* pname) {
char tempBuffer[512];
FILE * fd = NULL;
bool bRun = false;
snprintf(tempBuffer, sizeof(tempBuffer), "pgrep -x %s | sort", pname);
fd = popen(tempBuffer, "r");
if (fd == NULL)
{
cerr << "[ERR] Process check failed. [popen error][" << strerror(errno) << "]" << endl;
// 오류 발생시 true 반환하여 프로세스 실행 방지처리
return true;
}
else
{
void(*intsave)(int) = signal(SIGINT, SIG_IGN);
void(*quitsave)(int) = signal(SIGTERM, SIG_IGN);
void(*chldave)(int) = signal(SIGCHLD, SIG_IGN);
memset(tempBuffer, 0x00, sizeof(tempBuffer));
while (fgets(tempBuffer, sizeof(tempBuffer) - 1, fd) != NULL)
{
string tempPid(tempBuffer);
//Trim(tempPid);
pid_t pid = atoi(tempPid.c_str());
if (pid > 0)
{
bRun = true;
break;
}
}
signal(SIGINT, intsave);
signal(SIGTERM, quitsave);
signal(SIGCHLD, chldave);
pclose(fd);
return bRun;
}
}
bool CProcess::IsCurrentProcessRun(const char* pname) {
char tempBuffer[512];
FILE * fd = NULL;
bool bRun = false;
snprintf(tempBuffer, sizeof(tempBuffer), "pgrep -x %s | sort", pname);
fd = popen(tempBuffer, "r");
if (fd == NULL)
{
cerr << "[ERR] Process duplication check failed. [popen error][" << strerror(errno) << "]"<< endl;
// 오류 발생시 true 반환하여 프로세스 실행 방지처리
return true;
}
else
{
memset(tempBuffer, 0x00, sizeof(tempBuffer));
while (fgets(tempBuffer, sizeof(tempBuffer) - 1, fd) != NULL)
{
string tempPid(tempBuffer);
//Trim(tempPid);
pid_t pid = atoi(tempPid.c_str());
if (pid != getpid())
{
cerr << "[info] Process duplication found. pid[" << pid << "]" << endl;
bRun = true;
break;
}
}
pclose(fd);
return bRun;
}
}
pid_t CProcess::Fork() {
m_pid = ::fork();
if (m_pid >= 0) m_launched = true;
return m_pid;
}
void CProcess::SetThreadSignal(int signum)
{
sigset_t sig, old;
sigemptyset(&sig);
sigaddset(&sig, signum);
sigprocmask(SIG_BLOCK, &sig, &old);
}
void CProcess::UnSetThreadSignal(int signum)
{
sigset_t sig, old;
sigemptyset(&sig);
sigaddset(&sig, signum);
sigprocmask(SIG_UNBLOCK, &sig, &old);
}
+63
View File
@@ -0,0 +1,63 @@
/***************************************************************************
Process functions
-----------------------------------------
begin : 2013/06/21
copyright : (C) 2005 Solbox Inc.
author : Dev 1 Team
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __PROCESS_H__
#define __PROCESS_H__
#include <errno.h>
#define _WITH_DPRINTF
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include "Signal_handle.h"
#include "ProcessRename.h"
using namespace std;
class CProcess {
public:
static bool Daemon();
static bool IS_DAEMON;
static bool IsCurrentProcessRun(const char* pname);
static bool IsProcessRun(const char* pname);
public:
CProcess();
virtual ~CProcess();
virtual pid_t Launcher(const sig_atomic_t *sighandle) = 0;
inline pid_t Getpid() { return m_pid; }
inline bool Is_launched(){ return m_launched; }
protected:
// return
// 0> : error
// 0 : child process
// 0< : parent process
pid_t Fork();
void SetThreadSignal(int signum);
void UnSetThreadSignal(int signum);
pid_t m_pid;
bool m_launched;
};
#endif // __PROCESS_H__
+327
View File
@@ -0,0 +1,327 @@
#include "ProcessDummy.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sstream>
#include "Logger.h"
#define DEFAULT_ACCEPT_WAIT_COUNT 30
#define ACCEPT_TIMEOUT 60
CProcessDummy::CProcessDummy()
: m_port(-1), m_ipv6(false), m_listenfd(-1)
{
}
CProcessDummy::~CProcessDummy()
{
}
pid_t CProcessDummy::Launcher(const sig_atomic_t *sighandle)
{
Fork();
if (m_pid == 0)
{
if (m_port > 0)
{
if (TCPListen() == -1)
{
m_launched = false;
exit(EXIT_FAILURE);
return -1;
}
}
ostringstream msg;
bool running = false;
while (*sighandle == 0)
{
// work
if (m_port > 0)
{
if (!running)
{
msg.str("");
msg << "Worker [dummy TCP : " << m_port << ", PID : " << getpid() << "]";
set_ps_display(msg.str().c_str(), false);
_LOG(LINF, "%s", msg.str().c_str());
running = true;
}
int n = TCPAccept();
if (n > 0)
{
sleep(1);
::close(n);
}
}
else
{
if (!running)
{
msg.str("");
msg << "Worker [dummy, PID : " << getpid() << "]";
set_ps_display(msg.str().c_str(), false);
_LOG(LINF, "%s", msg.str().c_str());
running = true;
}
pause();
}
}
if (m_port > 0)
Close();
m_launched = false;
}
return m_pid;
}
int CProcessDummy::SetOption()
{
ostringstream msg;
int result = 0;
// Socket Port Reuse Option Set
int opt = 1;
result = ::setsockopt(m_listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (result != 0)
{
msg << "Listen socket option[SO_REUSEADDR] set failed. [" << errno
<< "][" << strerror(errno) << "][Port : " << m_port << "]";
LOG(LERR, msg.str().c_str());
return -1;
}
// Keep Alive Option set
opt = 1;
result = ::setsockopt(m_listenfd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
if (result != 0)
{
msg << "Listen socket option[SO_KEEPALIVE] set failed. [" << errno
<< "][" << strerror(errno) << "]";
LOG(LERR, msg.str().c_str());
return -1;
}
// Recv Timeout 설정
// 만일 리스너 소켓에 SO_RCVTIMEO를 지정하면, accept(2) 호출시에 지정된 타임아웃 동안 새로운 접속이 없으면
// recv(2)처럼 EAGAIN에러로 리턴된다.
struct timeval tv_timeo = { ACCEPT_TIMEOUT, 0 };
result = ::setsockopt(m_listenfd, SOL_SOCKET, SO_RCVTIMEO, &tv_timeo, sizeof(tv_timeo));
if (result != 0)
{
int errorNum = errno;
LOG(LERR, "SO_RCVTIMEO set error.[%d][%s]", errorNum, strerror(errorNum));
return -1;
}
// IPv6로 IPv4 지원을 위한 설정
#ifdef IPV6_V6ONLY
int v6only = 0;
if (m_ipv6 && setsockopt(m_listenfd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) < 0) {
int errorNum = errno;
LOG(LERR, "IPV6_V6ONLY set error.[%d][%s]", errorNum, strerror(errorNum));
return -1;
}
#endif // IPV6_V6ONLY
return 0;
}
int CProcessDummy::TCPListen()
{
int result = 0;
Close();
#ifdef AF_INET6
result = Listenv6();
if (m_ipv6 == false)
#endif // AF_INET6
result = Listen();
return result;
}
int CProcessDummy::Listen()
{
int result = 0;
ostringstream msg;
m_listenfd = ::socket(AF_INET, SOCK_STREAM, 0);
if (m_listenfd == -1)
{
msg << "Listen socket create failed.[" << errno << "]["
<< strerror(errno) << "] [Port : " << m_port << "]";
LOG(LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
return -1;
}
if (SetOption() != 0)
return -1;
struct sockaddr_in listenSockAddr;
socklen_t listenSockLen = 0;
bzero(&listenSockAddr, sizeof(listenSockAddr));
listenSockAddr.sin_family = AF_INET;
listenSockAddr.sin_port = htons(m_port);
listenSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
listenSockLen = sizeof(listenSockAddr);
// Socket Bind
result = ::bind(m_listenfd, (struct sockaddr *)&listenSockAddr, listenSockLen);
if (result != 0)
{
msg << "Listen socket bind failed. [" << errno << "][" << strerror(errno)
<< "][Port : " << m_port << "]";
LOG(LERR, msg.str().c_str());
cerr << msg.str() << endl;
return -1;
}
// Socket Listen
result = ::listen(m_listenfd, DEFAULT_ACCEPT_WAIT_COUNT);
if (result != 0)
{
msg << "Listen socket listen failed. [" << errno << "][" << strerror(errno)
<< "][Port : " << m_port << "]";
LOG(LERR, msg.str().c_str());
cerr << msg.str() << endl;
return -1;
}
return 0;
}
int CProcessDummy::Listenv6()
{
int result = 0;
ostringstream msg;
#ifdef AF_INET6
m_listenfd = ::socket(AF_INET6, SOCK_STREAM, 0);
if (m_listenfd > 0)
{
msg << "Enable IPv6 Socket.[Port :" << m_port << "]";
_LOG(LINF, msg.str().c_str());
msg.str("");
m_ipv6 = true;
}
if (m_listenfd == -1)
{
msg << "Listen socket create failed.[" << errno << "]["
<< strerror(errno) << "] [Port : " << m_port << "]";
LOG(LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
return -1;
}
if (SetOption() != 0)
return -1;
struct sockaddr_in6 listenSockAddrv6;
socklen_t listenSockLen = 0;
memset(&listenSockAddrv6, 0x00, sizeof(listenSockAddrv6));
listenSockAddrv6.sin6_family = AF_INET6;
listenSockAddrv6.sin6_flowinfo = 0;
listenSockAddrv6.sin6_port = htons(m_port);
listenSockAddrv6.sin6_addr = in6addr_any;
listenSockLen = sizeof(listenSockAddrv6);
// Socket Bind
result = ::bind(m_listenfd, (struct sockaddr *)&listenSockAddrv6, listenSockLen);
if (result != 0)
{
msg << "Listen socket bind failed. [" << errno << "][" << strerror(errno)
<< "][Port : " << m_port << "]";
LOG(LERR, msg.str().c_str());
cerr << msg.str() << endl;
return -1;
}
// Socket Listen
result = ::listen(m_listenfd, DEFAULT_ACCEPT_WAIT_COUNT);
if (result != 0)
{
msg << "Listen socket listen failed. [" << errno << "][" << strerror(errno)
<< "][Port : " << m_port << "]";
LOG(LERR, msg.str().c_str());
cerr << msg.str() << endl;
return -1;
}
#else
return -1;
#endif // AF_INET6
return 0;
}
int CProcessDummy::TCPAccept()
{
#ifdef AF_INET6
if(m_ipv6)
return Acceptv6();
else
#endif // AF_INET6
return Accept();
}
int CProcessDummy::Accept()
{
// 접속 요청을 변수 생성 및 초기화.
int nClientfd;
struct sockaddr_in clientSockAddr;
socklen_t clientSockLen = sizeof(clientSockAddr);
nClientfd = ::accept(m_listenfd, (struct sockaddr *) &clientSockAddr, &clientSockLen);
return nClientfd;
}
int CProcessDummy::Acceptv6()
{
#ifdef AF_INET6
// 접속 요청을 변수 생성 및 초기화.
int nClientfd;
struct sockaddr_in6 clientSockAddr;
socklen_t clientSockLen = sizeof(clientSockAddr);
nClientfd = ::accept(m_listenfd, (struct sockaddr *) &clientSockAddr, &clientSockLen);
#else
return -1;
#endif //AF_INET6
return nClientfd;
}
void CProcessDummy::Close()
{
if (m_listenfd > 0)
{
::close(m_listenfd);
m_listenfd = -1;
}
}
+49
View File
@@ -0,0 +1,49 @@
/***************************************************************************
Process Dummy Class
-----------------------------------------
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_DUMMY_H__
#define __PROCESS_DUMMY_H__
#include "Process.h"
class CProcessDummy : public CProcess
{
public:
CProcessDummy();
virtual ~ CProcessDummy();
pid_t Launcher(const sig_atomic_t *sighandle);
int TCPListen();
int TCPAccept();
inline void SetPort(int port) { m_port = port; }
private:
int Accept();
int Listen();
int Acceptv6();
int Listenv6();
int SetOption();
void Close();
int m_port;
bool m_ipv6;
int m_listenfd;
};
#endif // __PROCESS_DUMMY_H__
+199
View File
@@ -0,0 +1,199 @@
#include "ProcessRename.h"
#include <stdlib.h>
#include <string.h>
#if defined(__FreeBSD__)
void set_ps_display(const char *activity, bool force)
{
setproctitle("%s", activity);
}
char ** save_ps_display_args(int argc, char **argv)
{
return argv;
}
#else // linux
typedef size_t Size;
#define LONG_ALIGN_MASK (sizeof(long) - 1)
#define MEMSET_LOOP_LIMIT 1024
#define MemSet(start, val, len) \
do \
{ \
/* must be void* because we don't know if it is integer aligned yet */ \
void *_vstart = (void *) (start); \
int _val = (val); \
Size _len = (len); \
\
if ((((long) _vstart) & LONG_ALIGN_MASK) == 0 && \
(_len & LONG_ALIGN_MASK) == 0 && \
_val == 0 && \
_len <= MEMSET_LOOP_LIMIT && \
/* \
* If MEMSET_LOOP_LIMIT == 0, optimizer should find \
* the whole "if" false at compile time. \
*/ \
MEMSET_LOOP_LIMIT != 0) \
{ \
long *_start = (long *) _vstart; \
long *_stop = (long *) ((char *) _start + _len); \
while (_start < _stop) \
*_start++ = 0; \
} \
else \
memset(_vstart, _val, _len); \
} while (0)
#define PS_PADDING '\0'
extern char **environ;
bool update_process_title = true;
static char *ps_buffer; /* will point to argv area */
static size_t ps_buffer_size; /* space determined at run time */
static size_t last_status_len; /* use to minimize length of clobber */
static size_t ps_buffer_cur_len; /* nominal strlen(ps_buffer) */
static size_t ps_buffer_fixed_size; /* size of the constant prefix */
static int save_argc;
static char **save_argv;
size_t strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0)
{
while (--n != 0)
{
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0)
{
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return (s - src - 1); /* count does not include NUL */
}
void set_ps_display(const char *activity, bool force)
{
/* update_process_title=off disables updates, unless force = true */
if (!force && !update_process_title)
return;
/* no ps display for stand-alone backend */
//if (!IsUnderPostmaster)
// return;
/* If ps_buffer is a pointer, it might still be null */
if (!ps_buffer)
return;
/* Update ps_buffer to contain both fixed part and activity */
strlcpy(ps_buffer + ps_buffer_fixed_size, activity,
ps_buffer_size - ps_buffer_fixed_size);
ps_buffer_cur_len = strlen(ps_buffer);
/* pad unused memory; need only clobber remainder of old status string */
if (last_status_len > ps_buffer_cur_len)
MemSet(ps_buffer + ps_buffer_cur_len, PS_PADDING,
last_status_len - ps_buffer_cur_len);
last_status_len = ps_buffer_cur_len;
}
char ** save_ps_display_args(int argc, char **argv)
{
save_argc = argc;
save_argv = argv;
/*
* If we're going to overwrite the argv area, count the available space.
* Also move the environment to make additional room.
*/
{
char *end_of_area = NULL;
char **new_environ;
int i;
/*
* check for contiguous argv strings
*/
for (i = 0; i < argc; i++)
{
if (i == 0 || end_of_area + 1 == argv[i])
end_of_area = argv[i] + strlen(argv[i]);
}
if (end_of_area == NULL) /* probably can't happen? */
{
ps_buffer = NULL;
ps_buffer_size = 0;
return argv;
}
/*
* check for contiguous environ strings following argv
*/
for (i = 0; environ[i] != NULL; i++)
{
if (end_of_area + 1 == environ[i])
end_of_area = environ[i] + strlen(environ[i]);
}
ps_buffer = argv[0];
last_status_len = ps_buffer_size = end_of_area - argv[0];
/*
* move the environment out of the way
*/
new_environ = (char **) malloc((i + 1) * sizeof(char *));
for (i = 0; environ[i] != NULL; i++)
new_environ[i] = strdup(environ[i]);
new_environ[i] = NULL;
environ = new_environ;
}
/*
* If we're going to change the original argv[] then make a copy for
* argument parsing purposes.
*
* (NB: do NOT think to remove the copying of argv[], even though
* postmaster.c finishes looking at argv[] long before we ever consider
* changing the ps display. On some platforms, getopt() keeps pointers
* into the argv array, and will get horribly confused when it is
* re-called to analyze a subprocess' argument string if the argv storage
* has been clobbered meanwhile. Other platforms have other dependencies
* on argv[].
*/
{
char **new_argv;
int i;
new_argv = (char **) malloc((argc + 1) * sizeof(char *));
for (i = 0; i < argc; i++)
new_argv[i] = strdup(argv[i]);
new_argv[argc] = NULL;
argv = new_argv;
}
return argv;
}
#endif //
+37
View File
@@ -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 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__
+88
View File
@@ -0,0 +1,88 @@
/****************************************************************************
*
* Opendisk daemon common protocol header
*
* CopyRight(C) 2005 Netomi Inc. All Rights reserved.
* Author : Elenoa Lazyfake (elenoa@netomi.co.kr)
*
* $Id: protocol.h,v 1.2 2006/08/01 04:43:42 sean Exp $
*
* Redistribution and use in source and binary forms, with or with out
* modification, are not permitted in outside of Netomi, SolutionBox Inc.
*
*****************************************************************************/
#ifndef __PROTOCOL_H__
#define __PROTOCOL_H__
#define MAX_ID_SIZE 32
#define FNAME_HASH_LEN 1024
#define HOSTNAME_LEN 64
#define HOSTNAME_LEN_FOR_RMCD 128
// Packet Header stx 코드
// rmcd와 통신 할 때 사용
#define RC_RMCD_HEADER_STX_CODE 0x02
// RCTS의 rc_mond, rc_sscd 모두 STX_CODE는 0x05이다.
#define RC_MOND_HEADER_STX_CODE 0x05
#define RC_SSCD_HEADER_STX_CODE 0x05
// Packet Header type 구분코드
#define HEADER_TYPE_REQUEST 0x00
#define HEADER_TYPE_RESPONSE 0x01
// internal cache 요청 -> rc_rmcd로 요청시
#define CONTROL_FILE_CACHE 0x01
// FHS 상태 정보 요청 -> rc_mond로 요청시
#define ALIVE_FHS_REQUEST 0x01
// FHS 네트워크 상태 정보 전송 -> rc_sscd로 요청시
#define FHS_NETWORK_STAT_SEND 0x02
// Packet Result : type이 Reponse 인 경우에만 세팅됨.( 첫번째 Byte 만 사용시 )
#define HEADER_RESULT_SUCCESS 0x00
#define HEADER_RESULT_ERROR 0x01
#define HEADER_READY_YET 0x02
struct FileTransferPacketHeader{
char stx; // Packet 유효성 관리 코드
char type; // Request or Response 여부 ( 0x00: Request, 0x01: Response )
char command[4]; // Command Code ( 4 Byte) : 0th control-ftsd, 1th ftsd-ftsd 사용.
char result[4]; // Result Code ( 4 Byte )
unsigned int data_length; // Packet Data 부분의 길이값 ( Network Byte Order 사용)
char proto_version; // 프로토콜 버전 ( 1 Byte )
char extend_code; // 확장 및 Padding bits ( 1 Byte )
};
struct internal_cache_body {
char szRCID[MAX_ID_SIZE];
char szFileNameHash[FNAME_HASH_LEN];
char szHostname[HOSTNAME_LEN_FOR_RMCD];
char szServiceID[MAX_ID_SIZE];
char szContentLength[32];
char szFDCount[4];
};
struct alive_fhs_request_body {
char szRCID[MAX_ID_SIZE];
char szHostname[HOSTNAME_LEN];
};
struct network_stat_body_head {
char szRCID[MAX_ID_SIZE];
char szHostname[HOSTNAME_LEN];
int nCount;
};
struct fhs_stat_body
{
char szHostname[HOSTNAME_LEN];
int nActionCode;
};
#endif
+149
View File
@@ -0,0 +1,149 @@
/***************************************************************************
Shared Memory (using ARP) Class ( SharedMemAPR.cpp )
-----------------------------------------
begin : 2015/03/18
copyright : (C) 2013 Solbox Inc.
author : Development 1 Team
- 2015/03/18 - 1st dadamin
email : storage.sd@solbox.com
version : 3.5.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "SharedMemAPR.h"
#include "Logger.h"
CSharedMem::CSharedMem()
: is_attach(false), m_mem(NULL), m_shm(NULL), m_pool(NULL)
{
}
CSharedMem::~CSharedMem()
{
}
bool CSharedMem::Create(const char *filename, int allocSize, apr_pool_t *pool)
{
ostringstream msg;
if (Attach(filename, allocSize, pool, false))
return true;
// Delete shared memory files generated during abnormal termination.
apr_shm_remove(filename, pool);
apr_status_t sts = apr_shm_create(&m_shm, allocSize, filename, pool);
if (sts != APR_SUCCESS)
{
msg << "cannot attach & create shared memory [" << filename << "]";
LOG(LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
return false;
}
if (!EqualAllocSize(allocSize))
{
apr_shm_detach(m_shm);
msg << "size not match(create). request size " << allocSize << " alloced size "
<< apr_shm_size_get(m_shm) << " [" << filename << "]";
LOG(LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
return false;
}
m_mem = apr_shm_baseaddr_get(m_shm);
if (m_mem == NULL)
{
msg << "cannot find shared memory address(create) [" << filename << "]";
LOG(LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
return false;
}
Clear();
m_shm_key = filename;
return true;
}
bool CSharedMem::Attach(const char *filename, int allocSize, apr_pool_t *pool, bool outlog)
{
ostringstream msg;
apr_status_t sts = apr_shm_attach(&m_shm, filename, pool);
if (sts != APR_SUCCESS)
{
if (outlog)
{
msg << "cannot attach shared memory [" << filename << "]";
LOG(LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
}
return false;
}
if (!EqualAllocSize(allocSize))
{
apr_shm_detach(m_shm);
if (outlog)
{
msg << "size not match(attach). request size " << allocSize << " alloced size "
<< apr_shm_size_get(m_shm) << " [" << filename << "]";
LOG(LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
}
return false;
}
m_mem = apr_shm_baseaddr_get(m_shm);
if (m_mem == NULL)
{
apr_shm_detach(m_shm);
if (outlog)
{
msg << "cannot find shared memory address(attach) [" << filename << "]";
LOG(LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
}
return false;
}
m_shm_key = filename;
return true;
}
bool CSharedMem::Attach(const char *filename, int allocSize, apr_pool_t *pool)
{
return Attach(filename, allocSize, pool, true);
}
void CSharedMem::Detach()
{
if (m_shm)
apr_shm_detach(m_shm);
}
void CSharedMem::Destroy()
{
if (m_shm)
apr_shm_destroy(m_shm);
}
int CSharedMem::GetSize()
{
return (int)apr_shm_size_get(m_shm);
}
bool CSharedMem::EqualAllocSize(int allocSize)
{
return ((int)apr_shm_size_get(m_shm) == allocSize);
}
void CSharedMem::Clear()
{
if( m_mem != NULL)
memset(m_mem, 0, apr_shm_size_get(m_shm));
}
+78
View File
@@ -0,0 +1,78 @@
/***************************************************************************
Shared Memory (using ARP) Class Header ( SharedMemAPR.h )
-----------------------------------------
begin : 2015/03/18
copyright : (C) 2013 Solbox Inc.
author : Development 1 Team
- 2015/03/18 - 1st dadamin
email : dev1@solbox.com
version : 3.5.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __SHARED_MEMORY_WITH_APR_H__
#define __SHARED_MEMORY_WITH_APR_H__
#include <string>
#include <iostream>
#include <sstream>
#include "apr_errno.h"
#include "apr_general.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include "apr_thread_proc.h"
#include "apr_time.h"
#include "apr_pools.h"
#include "apr_shm.h"
#include "apr.h"
using namespace std;
class CSharedMem
{
public:
CSharedMem();
~CSharedMem();
// 공유메모리 생성
// 새롭게 생성하며, 데이터 초기화
// filename 존재 : 자동 attach되며, 데이터 초기화 하지 않음
bool Create(const char *filename, int allocSize, apr_pool_t *pool);
// 존재하는 공유 메모리로 attach
// 데이터 초기화 하지 않음
bool Attach(const char *filename, int allocSize, apr_pool_t *pool);
// 공유 메모리로 detach
void Detach();
// 공유 메모리 해제(자동 삭제됨)
void Destroy();
// 공유 메모리 할당된 size
int GetSize();
// 공유 메모리 포인터
inline void* GetData() { return m_mem; }
// 할당된 사이즈와 비교
bool EqualAllocSize(int allocSize);
// 데이터 초기화
void Clear();
private:
bool Attach(const char *filename, int allocSize, apr_pool_t *pool, bool outlog);
private:
bool is_attach;
void *m_mem;
apr_shm_t *m_shm;
apr_pool_t *m_pool;
string m_shm_key;
};
#endif // __SHARED_MEMORY_WITH_APR_H__
+89
View File
@@ -0,0 +1,89 @@
/***************************************************************************
System signal Class ( signal_handle.cpp )
-----------------------------------------
begin : 2015/03/18
copyright : (C) 2013 Solbox Inc.
author : Development 1 Team
- 2015/03/19 - 1st dadamin
email : storage.sd@solbox.com
version : 3.5.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include <cstddef>
#include <string.h>
#include "Signal_handle.h"
Signal_Handler *Signal_Handler::instance_ = NULL;
Event_Handler *Signal_Handler::signal_handlers_[NSIG];
Signal_Handler::Signal_Handler()
{
}
Signal_Handler::~Signal_Handler()
{
}
Signal_Handler* Signal_Handler::instance()
{
if(!Signal_Handler::instance_)
Signal_Handler::instance_ = new Signal_Handler();
return Signal_Handler::instance_;
}
Event_Handler * Signal_Handler::register_handler(int signum,
Event_Handler *eh)
{
// Copy the <old_eh> from the <signum> slot in
// the <signal_handlers_> table.
Event_Handler *old_eh =
Signal_Handler::signal_handlers_[signum];
// Store <eh> into the <signum> slot in the
// <signal_handlers_> table.
Signal_Handler::signal_handlers_[signum] = eh;
// Register the <dispatcher> to handle this
// <signum>.
struct sigaction sa;
sa.sa_handler = Signal_Handler::dispatcher;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(signum, &sa, 0);
return old_eh;
}
void Signal_Handler::dispatcher(int signum)
{
// Perform a sanity check...
if (Signal_Handler::signal_handlers_[signum] != 0)
// Dispatch the handler's hook method.
Signal_Handler::signal_handlers_[signum]->handle_signal(signum);
}
int Signal_Handler::remove_handler(int signum)
{
Signal_Handler::signal_handlers_[signum] = 0;
return 0;
}
int Signal_Handler::register_ignore(int signum)
{
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
int retval = sigaction(signum, &sa, 0);
return retval;
}
+74
View File
@@ -0,0 +1,74 @@
/***************************************************************************
System signal Class Header ( signal_handle.h )
-----------------------------------------
begin : 2015/03/18
copyright : (C) 2013 Solbox Inc.
author : Development 1 Team
- 2015/03/19 - 1st dadamin
email : storage.sd@solbox.com
version : 3.5.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __CLASS_SIGNAL_HANDLER__
#define __CLASS_SIGNAL_HANDLER__
// reference http://www.cs.wustl.edu/~schmidt/signal-patterns.html
#include </usr/include/sys/signal.h>
#include <csignal>
class Event_Handler
{
public:
// Hook method for the signal hook method.
virtual int handle_signal(int signum) = 0;
// ... other hook methods for other types of
// events such as timers, I/O, and
// synchronization objects.
};
class Signal_Handler
{
public:
// Entry point.
static Signal_Handler *instance();
// Register an event handler <eh> for <signum>
// and return a pointer to any existing <Event_Handler>
// that was previously registered to handle <signum>.
Event_Handler *register_handler(int signum,
Event_Handler *eh);
// Remove the <Event_Handler> for <signum>
// by setting the slot in the <signal_handlers_>
// table to NULL.
int remove_handler(int signum);
// Register ignore signal
int register_ignore(int signum);
private:
// Ensure we're a Singleton.
Signal_Handler();
~Signal_Handler();
// Singleton pointer.
static Signal_Handler *instance_;
// Entry point adapter installed into <sigaction>
// (must be a static method or a stand-alone
// extern "C" function).
static void dispatcher(int signum);
// Table of pointers to concrete <Event_Handler>s
// registered by applications. NSIG is the number of
// signals defined in </usr/include/sys/signal.h>.
static Event_Handler *signal_handlers_[NSIG];
};
#endif // __CLASS_SIGNAL_HANDLER__
+401
View File
@@ -0,0 +1,401 @@
#include "SocketControl.h"
#include "FimngdData.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <iterator>
#include <iostream>
#include <stdio.h>
using namespace std;
/// @brief 생성자.
CSocketControl::CSocketControl( )
: CBaseSocket( SOCKET_NOT_VALID )
, m_nPacketHeaderLen ( sizeof(m_packetHeader))
, m_nPacketDataLen( 0 )
{
}
/// @brief 소멸자
CSocketControl::~CSocketControl()
{
// 소멸자 Socket 명시적 Close 처리.
Close();
}
/// @brief 전달받은 Target 으로 Socket 접속을 수행
/// @param szTarget [in] 접속 대상 Host name 또는 IP
/// @param nPort [in] 접속 Port
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool CSocketControl::ConnectTarget( const std::string& szTarget, int nPort )
{
return Connect( szTarget, nPort );
}
/// @brief Packet Header 정보를 Log 파일에 Logging 처리
void CSocketControl::PrintHeaderToLog(struct FileTransferPacketHeader packetHeader)
{
m_packetHeader = packetHeader;
_LOG( LINF, "------------------------------------" );
_LOG( LINF, "stx [%02x]", m_packetHeader.stx );
_LOG( LINF, "type [%02x]", m_packetHeader.type );
_LOG( LINF, "command [%02x][%02x][%02x][%02x]" , m_packetHeader.command[0], m_packetHeader.command[1] , m_packetHeader.command[2], m_packetHeader.command[3] );
_LOG( LINF, "result [%02x][%02x][%02x][%02x]" , m_packetHeader.result[0], m_packetHeader.result[1] , m_packetHeader.result[2], m_packetHeader.result[3] );
_LOG( LINF, "data_length [%u]", m_nPacketDataLen );
_LOG( LINF, "protocol version [%02x]", m_packetHeader.proto_version );
_LOG( LINF, "extend_code [%02x]", m_packetHeader.extend_code );
_LOG( LINF, "------------------------------------" );
}
bool CSocketControl::SendIntenalCache(const std::string& szRCID,
const std::string& szFileName,
const std::string& szHostName,
uint32_t nServiceID,
uint64_t nFileSize,
int nFDCount)
{
if( IsValidSocket() == false )
return false;
// 정보 요청을 위한 Packet Header 생성.
struct FileTransferPacketHeader stHeader;
memset(&stHeader, 0x00, sizeof(struct FileTransferPacketHeader));
stHeader.stx = RC_RMCD_HEADER_STX_CODE;
stHeader.type = HEADER_TYPE_REQUEST;
stHeader.command[2] = CONTROL_FILE_CACHE;
stHeader.data_length = htonl( sizeof(struct internal_cache_body) );
stHeader.proto_version = 0x00;
struct internal_cache_body stBody;
memset(&stBody, 0x00, sizeof(struct internal_cache_body));
snprintf(stBody.szRCID ,sizeof(stBody.szRCID)-1 ,"%s", szRCID.c_str());
snprintf(stBody.szFileNameHash ,sizeof(stBody.szFileNameHash)-1 ,"%s", szFileName.c_str());
snprintf(stBody.szHostname ,sizeof(stBody.szHostname)-1 ,"%s", szHostName.c_str());
snprintf(stBody.szServiceID ,sizeof(stBody.szServiceID)-1 ,"%d", nServiceID);
snprintf(stBody.szContentLength ,sizeof(stBody.szContentLength)-1 ,"%ld", nFileSize );
snprintf(stBody.szFDCount ,sizeof(stBody.szFDCount)-1 ,"%d", nFDCount);
_LOG( LDBG, "------------------------------------" );
_LOG( LDBG, "szRCID : %s", stBody.szRCID );
_LOG( LDBG, "szFileNameHash : %s", stBody.szFileNameHash ) ;
_LOG( LDBG, "szHostname : %s", stBody.szHostname ) ;
_LOG( LDBG, "szServiceID : %s", stBody.szServiceID ) ;
_LOG( LDBG, "szContentLength : %s", stBody.szContentLength ) ;
_LOG( LDBG, "szFDCount : %s", stBody.szFDCount ) ;
_LOG( LDBG, "------------------------------------" );
// Packet Header 정보 전송
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
{
LOG( LERR, "File Replication request send failed.");
PrintHeaderToLog( stHeader );
return false;
}
// Packet Data 부분 전송
if( WriteN( &stBody, sizeof(struct internal_cache_body) ) != sizeof(struct internal_cache_body) )
{
LOG( LERR, "File Replication request send failed.");
return false;
}
return true;
}
bool CSocketControl::SendAliveFhs(const std::string& szRCID, const std::string& szHostName)
{
if( IsValidSocket() == false )
return false;
// 정보 요청을 위한 Packet Header 생성.
struct FileTransferPacketHeader stHeader;
memset(&stHeader, 0x00, sizeof(struct FileTransferPacketHeader));
stHeader.stx = RC_MOND_HEADER_STX_CODE;
stHeader.type = HEADER_TYPE_REQUEST;
stHeader.command[1] = ALIVE_FHS_REQUEST;
stHeader.data_length = htonl( sizeof(struct alive_fhs_request_body) );
stHeader.proto_version = 0x00;
struct alive_fhs_request_body stBody;
memset(&stBody, 0x00, sizeof(struct alive_fhs_request_body));
snprintf(stBody.szRCID ,sizeof(stBody.szRCID)-1 ,"%s", szRCID.c_str());
snprintf(stBody.szHostname ,sizeof(stBody.szHostname)-1 ,"%s", szHostName.c_str());
LOG( LDEV, "------------------------------------" );
_LOG( LDEV, " szRCID : %s", stBody.szRCID );
_LOG( LDEV, " szHostname : %s", stBody.szHostname ) ;
LOG( LDEV, "------------------------------------" );
// Packet Header 정보 전송
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
{
LOG( LERR, "Alive FHS request send failed.");
PrintHeaderToLog( stHeader );
return false;
}
// Packet Data 부분 전송
if( WriteN( &stBody, sizeof(struct alive_fhs_request_body) ) != sizeof(struct alive_fhs_request_body) )
{
LOG( LERR, "Alive FHS request send failed.");
return false;
}
return true;
}
bool CSocketControl::GetAliveFhs(std::map<std::string, struct fhs_stat> &mapFhsStat)
{
unsigned int nFhsCount = 0;
BYTE tempBuffer[4];
// Packet Header를 읽는다.
if( GetPacketHeader( RC_MOND_HEADER_STX_CODE, HEADER_TYPE_RESPONSE, DEFAULT_DATA_RECEIVE_TIMEOUT) <= 0 )
{
return false;
}
// 전면 수정.... 필요...
// Data의 크기는 최소 4byte여야 한다.
if( m_nPacketDataLen >= 4 )
{
int nRead = ReadNTimeout( &tempBuffer, 4);
// 오류 발생시
if( nRead <= 0 )
{
LOG( LERR, "FHS Count Read Fail.");
return false;
}
unsigned int * pInt = (unsigned int *) tempBuffer;
nFhsCount = ntohl(*pInt);
} else
{
LOG( LERR, "Response packet body size not valid.");
return false;
}
// Data 부분 size를 체크한다.
if( m_nPacketDataLen != (sizeof( struct fhs_stat_body ) * nFhsCount) + 4 )
{
LOG( LERR, "Response packet body size not valid.[%u]/[%lu]"
, m_nPacketDataLen, (sizeof( struct fhs_stat_body ) * nFhsCount) + 4 );
return false;
}
// fhs count 만큼 loop를 돌며 map 에 추가한다.
for( unsigned int i = 0; i < nFhsCount; i++ )
{
// 통신 프로토콜로 읽을 구조체...
struct fhs_stat_body stFhsStatbody;
struct fhs_stat stFhsStat;
int nRead = ReadNTimeout( &stFhsStatbody, sizeof(struct fhs_stat_body) );
// 오류 발생시
if( nRead <= 0 )
{
LOG( LERR, "Alive FHS Read Fail.");
mapFhsStat.clear();
return false;
}
string szHostName = stFhsStatbody.szHostname;
// socket 통신 하는 구조체와 내부 로직에서 사용되는 구조체간에 값을 복사 하기 위함.
strncpy(stFhsStat.szHostname, stFhsStatbody.szHostname, HOSTNAME_LEN);
stFhsStat.nActionCode = stFhsStatbody.nActionCode;
mapFhsStat.insert( std::pair<string, struct fhs_stat>( szHostName, stFhsStat ) );
}
return true;
}
// Packet Header 부분의 수신 처리를 위한 함수
// @param timeout [in] 대기시간.
// @retrun 0 : timeout
// 1 : 성공
// -1 : socket 오류 또는 정의된 Data 가 아닌 경우.
// -2 : result 가 정상이 아닌경우
int CSocketControl::GetPacketHeader( char stxCode, char typeCode, int timeout )
{
BYTE tempBuffer[128];
if( IsValidSocket() == false )
return -1;
// Socket 으로 부터 Packet Header 부분 수신.
// 수신된 정보는 멤버변수에 저장처리.
/// read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
int nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, timeout );
if( nRead == -2 )
{
// timeout 발생시
LOG( LERR, "Socket Read timeout.." );
return 0;
}
else if( nRead <= 0 )
{
// timeout 을 제외한 그 밖의 오류 발생시
// ReadNTimeout() 내에서 로깅 처리 확인
return -1;
}
// 정상 Data 수신시.
// STX code 검사.
if( m_packetHeader.stx != stxCode )
{
LOG( LERR, "Not valid stx code. [%x]", m_packetHeader.stx);
PrintHeaderToLog( m_packetHeader );
return -1;
}
// Type Code 검사
if( m_packetHeader.type != typeCode )
{
LOG( LERR, "Not valid type code. [%x]", m_packetHeader.type );
PrintHeaderToLog( m_packetHeader );
return -1;
}
// 경우에 따라 data_length는 0이 될 수도 있다.
// ex) 에러메세지가 없는 에러인 경우...
// Data Length 부분 값을 멤버 변수에 저장처리.
m_nPacketDataLen = ntohl( m_packetHeader.data_length );
// result 검사 후 정상적이지 않을 경우 결과 메세지를 출력한다.
if( m_packetHeader.result[3] != HEADER_RESULT_SUCCESS )
{
// rc_mond가 전달 할 준비가 안된경우...
if( m_packetHeader.result[3] == HEADER_READY_YET )
{
LOG( LWAR, "rc_mond ready yet. :[%x]",m_packetHeader.result[3]);
return -2;
}
if( m_nPacketDataLen != 0 )
{
nRead = ReadNTimeout( &tempBuffer, m_nPacketDataLen);
if( nRead == -2 )
{
// timeout 발생시
LOG( LERR, "Socket Read timeout.." );
return 0;
}
// 오류 발생시
if( nRead <= 0 )
{
LOG( LERR, "Socket Read Fail.");
return -1;
}
// 에러메세지가 있는 경우는 로깅 한다.
string szErrmsg = (char*)tempBuffer;
LOG( LWAR, "Result code :[%x] %s",m_packetHeader.result[3], szErrmsg.c_str());
} else
{
// 없으면 결과 코드만 로깅한다.
LOG( LWAR, "Result code :[%x]",m_packetHeader.result[3]);
}
return -2;
}
return 1;
}
bool CSocketControl::SendNetworkStat(const std::string& szRCID, const std::string& szHostName, std::vector<struct service_network_stat> &vecNetworkStat)
{
//
int data_length = 0;
if( IsValidSocket() == false )
return false;
// 정보 요청을 위한 Packet Header 생성.
struct FileTransferPacketHeader stHeader;
memset(&stHeader, 0x00, sizeof(struct FileTransferPacketHeader));
stHeader.stx = RC_SSCD_HEADER_STX_CODE;
stHeader.type = HEADER_TYPE_REQUEST;
stHeader.command[1] = FHS_NETWORK_STAT_SEND;
// !!webting body size 구해야 함
data_length = sizeof(struct network_stat_body_head) + (sizeof(struct service_network_stat) * vecNetworkStat.size() ) ;
_LOG( LDBG, "body length : %d, cnt: %d", data_length, (int)vecNetworkStat.size() );
stHeader.data_length = htonl( data_length );
stHeader.proto_version = 0x01;
struct network_stat_body_head stBodyHead;
memset(&stBodyHead, 0x00, sizeof(struct network_stat_body_head));
snprintf(stBodyHead.szRCID ,sizeof(stBodyHead.szRCID)-1 ,"%s", szRCID.c_str());
snprintf(stBodyHead.szHostname ,sizeof(stBodyHead.szHostname)-1 ,"%s", szHostName.c_str());
stBodyHead.nCount = htonl(vecNetworkStat.size());
LOG( LDBG, "------------------------------------" );
LOG( LDBG, "szRCID : %s", stBodyHead.szRCID );
LOG( LDBG, "szHostname : %s", stBodyHead.szHostname ) ;
LOG( LDBG, "nCount : %d", (int)vecNetworkStat.size() ) ;
LOG( LDBG, "------------------------------------" );
// Packet Header 정보 전송
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
{
LOG( LERR, "Network Stat header send failed.");
PrintHeaderToLog(stHeader);
return false;
}
// Packet Data 부분 전송의 헤더 부분을 전송한다.
if( WriteN( &stBodyHead, sizeof(struct network_stat_body_head) ) != sizeof(struct network_stat_body_head) )
{
LOG( LERR, "Network Stat body_header send failed.");
return false;
}
std::vector<struct service_network_stat> tmpvec;
// body의 나머지 부분을 전송한다.
std::vector<struct service_network_stat>::iterator it;
for (it=vecNetworkStat.begin(); it<vecNetworkStat.end(); it++)
{
struct service_network_stat objNetStat = *it;
if( WriteN( &objNetStat, sizeof( struct service_network_stat) ) != sizeof( struct service_network_stat) )
{
LOG(LERR, "Network Stat body send failed.[t:%d, T:%d]", objNetStat.timestamp, objNetStat.nServiceSeq);
return false;
}
}
return true;
}
bool CSocketControl::GetNetworkStatResult(int nTimeout)
{
// Packet Header를 읽는다.
if (GetPacketHeader(RC_SSCD_HEADER_STX_CODE, HEADER_TYPE_RESPONSE, nTimeout) <= 0)
{
LOG(LERR, "Network Stat response code reception failed.");
return false;
}
return true;
}
+118
View File
@@ -0,0 +1,118 @@
/***************************************************************************
ftsd control interface ( File Replication & Cache & Move & Delete Control) Header ( FtsdSocketControl.h )
-----------------------------------------
begin : 2010/03/09
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.2.0.R0811
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 __FIMNGD_SOCKET_CONTROL_H__
#define __FIMNGD_SOCKET_CONTROL_H__
#include "BaseSocket.h"
#include "Protocol.h"
#include <iostream>
#include <vector>
#include <map>
///< BYTE 타입 정의
#ifndef _BYTE_DEFINED
#define _BYTE_DEFINED
typedef unsigned char BYTE;
#endif // _BYTE_DEFINED
#define DEFAULT_SOCKET_TEMP_BUFFER_SIZE 1024 // SocketControl 에서 사용할 임시버퍼 크기.
class CSocketControl : public CBaseSocket
{
private:
/// @brief Packet Header 변수
struct FileTransferPacketHeader m_packetHeader;
/// @brief m_packetHeader 구조체의 크기를 저장하기 위한 상수
const int m_nPacketHeaderLen;
/// @brief Packet Header 에 저장된 Data 부분의 길이 정보값.
unsigned int m_nPacketDataLen;
/// @brief Packet Data 부분의 수신처리시 임시로 사용할 버퍼.
BYTE m_tempBuffer[DEFAULT_SOCKET_TEMP_BUFFER_SIZE];
public:
/// @brief 생성자.
CSocketControl();
/// @brief 소멸자.
~CSocketControl();
/// @brief 전달받은 Target 으로 Socket 접속을 수행
/// @param szTarget [in] 접속 대상 Host name 또는 IP
/// @param nPort [in] 접속 Port
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool ConnectTarget( const std::string& szTarget, int nPort );
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 File Replication 명령 전송.
/// @param szRCID [in] 속한 RCID
/// @param szFileName [in] 복제할 파일명 (/stg/node0/186/abcde..)
/// @param nServiceID [in] 서비스 ID
/// @param nFileSize [in] 복제할 파일의 local 크기.
/// @param nFDCount [in] 복제할 원본 파일의 file description count
bool SendIntenalCache(const std::string& szRCID,
const std::string& szFileName,
const std::string& szHostName,
uint32_t nServiceID,
uint64_t nFileSize,
int nFDCount);
bool SendAliveFhs(const std::string& szRCID, const std::string& szHostName);
bool SendNetworkStat(const std::string& szRCID, const std::string& szHostName, std::vector<struct service_network_stat> &vecNetworkStat);
bool GetNetworkStatResult(int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT);
/// @brief Packet Header 정보를 Log 파일에 Logging 처리 ( Debug 처리를 위한 함수)
void PrintHeaderToLog(struct FileTransferPacketHeader packetHeader);
bool GetAliveFhs(std::map<std::string, struct fhs_stat> &mapFhsStat);
protected:
/// @brief Packet Header 부분의 수신 처리를 위한 함수. Alive Check 요청 패킷은 자동으로 무시처리함.
/// @param timeout [in] 대기시간.
/// @retrun 성공시 true, 오류 발생및 실패시 fasle 반환.
int GetPacketHeader(char stxCode, char typeCode, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT);
/// @brief socket 에서 지정된 크기만큼의 데이터를 읽어 출력변수에 저장처리.
/// @param size [in] read 할 데이터 크기
/// @param value [out] 읽은 데이터를 저장할 string 변수
/// @return On success return true, otherwise return false.
bool GetPacketData( unsigned int& size, std::string& value );
/// @brief socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
/// @param size [in] read 할 데이터 크기
/// @return On success return true, otherwise return false.
bool GetPacketData( unsigned int size );
/// @brief pValue 에 저장된 데이터를 unsigned int 형으로 변환처리 및 Endian 변환
unsigned int GetDataToUInt( BYTE * pValue, bool bConvertEndian = true );
/// @brief pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리.
unsigned long long GetDataToUInt64( BYTE * pValue );
};
#endif /* __FIMNGD_SOCKET_CONTROL_H__ */
+29
View File
@@ -0,0 +1,29 @@
#include "TransferStatData.h"
CTransferStatData::CTransferStatData()
{
memset( &m_tsData, 0x00, sizeof( struct Transfer_stat ) );
}
CTransferStatData::CTransferStatData(const CTransferStatData& other)
{
*this = other;
}
CTransferStatData::~CTransferStatData()
{
}
const CTransferStatData& CTransferStatData::operator= (const CTransferStatData& other)
{
if (this == &other) return *this;
SetTransferStatData(other.GetData());
return *this;
}
void CTransferStatData::SetTransferStatData( struct Transfer_stat tsData)
{
memset( &m_tsData, 0x00, sizeof(struct Transfer_stat) );
memcpy( &m_tsData, &tsData, sizeof(struct Transfer_stat) );
}
+51
View File
@@ -0,0 +1,51 @@
/***************************************************************************
Process Dummy Class
-----------------------------------------
begin : 2015/05/28
copyright : (C) 2005 Solbox Inc.
author : Dev 1 Team
email : storage.sd@solbox.com
version : 3.5.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __TRANSFER_STAT_DATA_H__
#define __TRANSFER_STAT_DATA_H__
#include <string.h>
#include "Logger.h"
#include "FimngdData.h"
class CTransferStatData
{
public:
CTransferStatData();
CTransferStatData(const CTransferStatData& other);
virtual ~CTransferStatData();
const CTransferStatData& operator=(const CTransferStatData& other);
inline void* GetPtr() { return &m_tsData; };
inline static int GetSize() { return (int)sizeof( struct Transfer_stat ); };
inline Transfer_stat GetData() const { return m_tsData; };
inline unsigned int GetUserSeq() { return m_tsData.nUserSeq; };
inline unsigned int GetServiceSeq() { return m_tsData.nServiceSeq; };
inline std::string GetFilenameHash() { return std::string( m_tsData.filename_hash ); };
// return value GET : 0 , PUT : non zero
inline short int GetDirection() { return m_tsData.nInOut; };
void SetTransferStatData( struct Transfer_stat tsData);
private:
struct Transfer_stat m_tsData;
};
#endif // __TRANSFER_STAT_DATA_H__
+73
View File
@@ -0,0 +1,73 @@
/***************************************************************************
ContentList.cpp
-----------------------------------------
begin : 2015/05/29
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "TransferStatDataList.h"
#include "MutexLock.hpp"
////////////////////////////////////////////////////////////////////////////
//
// CTransferStatDataList Class
//
////////////////////////////////////////////////////////////////////////////
CTransferStatDataList::CTransferStatDataList()
{
pthread_mutex_init(&m_mutex, NULL);
}
CTransferStatDataList::~CTransferStatDataList()
{
ProtectedMutex mutex(m_mutex);
pthread_mutex_destroy(&m_mutex);
}
void CTransferStatDataList::Push( CTransferStatData& statData )
{
ProtectedMutex mutex(m_mutex);
// 동일한 파일에 대해서 insert 방지 및 메모리 절약 목적으로 map 사용
m_TransferStatMap.insert(std::map< std::string, CTransferStatData>::value_type(statData.GetFilenameHash(), CTransferStatData(statData)));
}
void CTransferStatDataList::Pop(CTransferStatData & data)
{
ProtectedMutex mutex(m_mutex);
//CTransferStatData data;
// 큐가 비었으면 빈 데이터 반환.
if (m_TransferStatMap.empty() == true)
{
LOG( LDBG, "no element in the queue of TransferStatDataList." );
return;
}
std::map< std::string, CTransferStatData>::iterator it = m_TransferStatMap.begin();
data.SetTransferStatData( it->second.GetData());
m_TransferStatMap.erase(it);
return;
}
unsigned int CTransferStatDataList::GetSize()
{
ProtectedMutex mutex(m_mutex);
unsigned int r = 0;
r = m_TransferStatMap.size();
return r;
}
void CTransferStatDataList::Clear()
{
ProtectedMutex mutex(m_mutex);
while (m_TransferStatMap.size() > 0)
{
m_TransferStatMap.erase(m_TransferStatMap.begin());
}
}
+60
View File
@@ -0,0 +1,60 @@
/***************************************************************************
Process Dummy Class
-----------------------------------------
begin : 2015/05/28
copyright : (C) 2005 Solbox Inc.
author : Dev 1 Team
email : storage.sd@solbox.com
version : 3.5.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __TRANSFER_STAT_DATA__LIST_H__
#define __TRANSFER_STAT_DATA__LIST_H__
#include <map>
#include <string.h>
#include <pthread.h>
#include "Logger.h"
#include "FimngdData.h"
#include "TransferStatData.h"
class CTransferStatDataList
{
public:
CTransferStatDataList();
virtual ~CTransferStatDataList();
///@brief TransferStatData 큐에 데이터를 삽입하는 함수.
///@param logData [in] TransferLogData 레퍼런스.
///@return 큐에 삽입 성공하면 true, 그렇지 않으면 false 반환.
/// 큐의 최대 크기는 100,000개이다.
/// 그러므로 현재 큐의 크기가 100,000개이면 false를 반환한다.
void Push( CTransferStatData& statData );
///@brief TransferStatData 큐에서 데이터를 얻는 함수.
/// 반환된 데이터는 큐에서 삭제된다.
///@param none.
///@return TransferStatData 객체
void Pop(CTransferStatData & data);
///@brief TransferStatData 큐의 크기를 얻는 함수.
///@param none.
///@return TransferStatData 큐의 크기를 반환.
unsigned int GetSize();
///@brief 큐의 모든 데이터를 삭제하는 함수.
///@param none.
///@param none.
void Clear();
private:
std::map< std::string, CTransferStatData> m_TransferStatMap;
pthread_mutex_t m_mutex;
};
#endif //__TRANSFER_STAT_DATA__LIST_H__
+101
View File
@@ -0,0 +1,101 @@
#include "WorkerFhsInfoUpdater.h"
#include <sstream>
#include "Logger.h"
#include "DaemonConfigs.h"
CWorkerFhsInfoUpdater::CWorkerFhsInfoUpdater()
{
}
CWorkerFhsInfoUpdater::~CWorkerFhsInfoUpdater()
{
}
pid_t CWorkerFhsInfoUpdater::Launcher(const sig_atomic_t *sighandle)
{
Fork();
if (m_pid == 0)
{
while (*sighandle == 0)
{
// work
set_ps_display("Worker [Fhs Info Updater]", false);
do_work(sighandle);
// signal 받은 경우 wait 불필요
if(*sighandle == 0)
{
pause();
}
}
// httpd 구동 여부에 따라 Detache or Destroy를 결정함
if(IsProcessRun("httpd") == true)
{
m_objFhsStat.SetSelfDead();
m_shmemFhsStat.Detach();
m_shmemFhsCount.Detach();
LOG(LDBG, "m_shmemFhsStat.Detach()");
}
else
{
m_shmemFhsStat.Destroy();
m_shmemFhsCount.Destroy();
LOG(LDBG, "m_shmemFhsStat.Destroy()");
}
m_launched = false;
}
return m_pid;
}
void CWorkerFhsInfoUpdater::do_work(const sig_atomic_t *sighandle)
{
apr_pool_t *p;
apr_pool_create(&p, NULL);
// fhsstat shared memory 생성
int nMaxFhs = CDeamonConfig::GetInstance()->GetMaxFhs();
int nMaxFhsMemSize = (sizeof(struct fhs_stat) * nMaxFhs);
if (m_shmemFhsStat.Create("/tmp/opendav.shared.fhsstat.shm", nMaxFhsMemSize , p) == false)
{
LOG(LERR, "FHS stat shared memory create failed.");
exit(EXIT_FAILURE);
}
if (m_shmemFhsCount.Create("/tmp/opendav.shared.fhscount.shm", 4 , p) == false)
{
LOG(LERR, "FHS stat shared memory create failed.");
exit(EXIT_FAILURE);
}
if( m_objFhsStat.ThreadInit(sighandle, &m_shmemFhsStat, &m_shmemFhsCount ) == false )
{
LOG(LERR, "Fhs stat update thread create failed.");
exit(EXIT_FAILURE);
}
SetThreadSignal(SIGINT);
SetThreadSignal(SIGTERM);
if( m_objFhsStat.Start() == false )
{
UnSetThreadSignal(SIGINT);
UnSetThreadSignal(SIGTERM);
LOG(LERR, "Fhs stat update thread create failed.");
exit(EXIT_FAILURE);
}
UnSetThreadSignal(SIGINT);
UnSetThreadSignal(SIGTERM);
}
+44
View File
@@ -0,0 +1,44 @@
/***************************************************************************
Process Test Class
-----------------------------------------
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 __WROK_FHS_INFO_UPDATER_H__
#define __WROK_FHS_INFO_UPDATER_H__
#include "Process.h"
#include "SharedMemAPR.h"
#include "FhsStatUpdateThread.h"
#include "FimngdData.h"
class CWorkerFhsInfoUpdater : public CProcess
{
public:
CWorkerFhsInfoUpdater();
virtual ~CWorkerFhsInfoUpdater();
pid_t Launcher(const sig_atomic_t *sighandle);
CFhsStatUpdateThread m_objFhsStat;
private:
void do_work(const sig_atomic_t *sighandle);
// 서비스 볼륨별 account 관리를 위한 shared memory 객체
CSharedMem m_shmemFhsStat;
// m_shmemFhsStat에 실제로 fhs 개수를 저장하는 shared memory 객체
CSharedMem m_shmemFhsCount;
};
#endif // __WROK_FHS_INFO_UPDATER_H__
@@ -0,0 +1,146 @@
#include "WorkerMessageQueueControl.h"
#include <sstream>
#include "Logger.h"
#include "DaemonConfigs.h"
#include "TransferStatDataList.h"
#include "CacheRequestList.h"
#define MESSAGE_QUEUE_KEY 642656000
/// class CMessageQueueJob
CMessageQueueJob::CMessageQueueJob()
{
}
CMessageQueueJob::~CMessageQueueJob()
{
}
bool CMessageQueueJob::ThreadInit(const sig_atomic_t *sighandle, CIPCMsgQueue& msgqueu, CCacheRequestList *pCacheReqList, CHotContentInfoMap * photContentinfoMap)
{
m_objHotContentDetectThread.ThreadInit(sighandle, pCacheReqList, photContentinfoMap);
m_objQueuePopThread.ThreadInit(sighandle, msgqueu, m_objHotContentDetectThread.GetTransferList());
return true;
}
bool CMessageQueueJob::Start()
{
if ( m_objHotContentDetectThread.Start() && m_objQueuePopThread.Start() )
return true;
return false;
}
/// class CWorkerMessageQueueControl
CWorkerMessageQueueControl::CWorkerMessageQueueControl()
{
}
CWorkerMessageQueueControl::~CWorkerMessageQueueControl()
{
m_vecContentQueue.clear();
m_vecJobTread.clear();
}
pid_t CWorkerMessageQueueControl::Launcher(const sig_atomic_t *sighandle)
{
Fork();
if (m_pid == 0)
{
while (*sighandle == 0)
{
// work
set_ps_display("Worker [Message Queue Control]", false);
do_work(sighandle);
// signal 받은 경우 wait 불필요
if(*sighandle == 0)
{
pause();
}
}
// httpd 구동 여부에 따라 Detache or Destroy를 결정함
if(IsProcessRun("httpd") == false)
{
LOG(LDBG, "xxxx IPCS QUEUE remove.");
for( std::vector<CIPCMsgQueue>::size_type i = 0; i < m_vecContentQueue.size(); ++i )
{
if( m_vecContentQueue[i].Remove() == false )
{
LOG(LWAR, "CIPCMsgQueue remove failed.");
}
}
}
m_launched = false;
}
return m_pid;
}
void CWorkerMessageQueueControl::do_work(const sig_atomic_t *sighandle)
{
// conf의 값 참조하여 queue 개수 만큼 생성
int nQueueCount = CDeamonConfig::GetInstance()->GetIPCQueueCount();
int nMaxIPCQueueSize = CDeamonConfig::GetInstance()->GetMaxIPCQueueSize();
uint32_t nQueueSize = sizeof(struct Transfer_stat) * nMaxIPCQueueSize / nQueueCount;
// 재구동 시 기존 정보 있을 경우 삭제 처리함
m_vecContentQueue.clear();
m_vecJobTread.clear();
for( int i = 0; i < nQueueCount; i++)
{
// 설정값에 개수를...
LOG(LDBG, "********CMsgQueuePopThread SIZE %d ", nQueueSize);
// Msg Queue 객체 생성 및 vector에 등록
m_vecContentQueue.push_back(CIPCMsgQueue());
m_vecJobTread.push_back(CMessageQueueJob());
}
// 실제 Queue 를 생성 처리 한다.
for( std::queue<CIPCMsgQueue>::size_type i = 0; i < m_vecContentQueue.size(); ++i )
{
m_vecContentQueue[i].Create(MESSAGE_QUEUE_KEY + i, IPC_CREAT | 0644, "nobody", nQueueSize);
}
SetThreadSignal(SIGINT);
SetThreadSignal(SIGTERM);
m_objCacheGeneratorThread.ThreadInit(sighandle);
if (m_objCacheGeneratorThread.Start() == false)
{
UnSetThreadSignal(SIGINT);
UnSetThreadSignal(SIGTERM);
LOG(LERR, "CacheGenerator Thread start failed.");
exit(EXIT_FAILURE);
}
for (std::queue<CMessageQueueJob>::size_type i = 0; i < m_vecJobTread.size(); ++i)
{
m_vecJobTread[i].ThreadInit(sighandle, m_vecContentQueue[i], m_objCacheGeneratorThread.GetReqList(), &m_hotContentinfoMap);
if (m_vecJobTread[i].Start() == false)
{
UnSetThreadSignal(SIGINT);
UnSetThreadSignal(SIGTERM);
LOG(LERR, "Pop Threads start failed.");
exit(EXIT_FAILURE);
}
}
///////////////
UnSetThreadSignal(SIGINT);
UnSetThreadSignal(SIGTERM);
}
@@ -0,0 +1,68 @@
/***************************************************************************
Process Test Class
-----------------------------------------
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 __MESSAGE_QUEUE_CONTROL_H__
#define __MESSAGE_QUEUE_CONTROL_H__
#include <vector>
#include <list>
#include "Process.h"
#include "FimngdData.h"
#include "IPCMsgQueue.h"
#include "MsgQueuePopThread.h"
#include "HotContentDetectThread.h"
#include "CacheGeneratorThread.h"
#include "HotContentInfoMap.h"
class CMessageQueueJob
{
public:
CMessageQueueJob();
~CMessageQueueJob();
bool ThreadInit(const sig_atomic_t *sighandle, CIPCMsgQueue& msgqueu, CCacheRequestList *pCacheReqList, CHotContentInfoMap * photContentinfoMap);
bool Start();
private:
// Message Queue 에서 데이터를 pop하는 쓰레드
CMsgQueuePopThread m_objQueuePopThread;
// hot content를 찾는 역할을 하는 쓰레드
CHotContentDetectThread m_objHotContentDetectThread;
};
class CWorkerMessageQueueControl : public CProcess
{
public:
CWorkerMessageQueueControl();
virtual ~CWorkerMessageQueueControl();
pid_t Launcher(const sig_atomic_t *sighandle);
private:
void do_work(const sig_atomic_t *sighandle);
std::vector<CIPCMsgQueue> m_vecContentQueue;
std::vector<CMessageQueueJob> m_vecJobTread;
// rc_rmcd로 internal cache 생성을 요청하는 쓰레드
CCacheGeneratorThread m_objCacheGeneratorThread;
CHotContentInfoMap m_hotContentinfoMap;
};
#endif // __MESSAGE_QUEUE_CONTROL_H__
@@ -0,0 +1,95 @@
#include "WorkerNetworkStatSender.h"
#include <sstream>
#include "Logger.h"
#include "DaemonConfigs.h"
#define MESSAGE_QUEUE_KEY 642656000
CWorkerNetworkStatSender::CWorkerNetworkStatSender()
{
}
CWorkerNetworkStatSender::~CWorkerNetworkStatSender()
{
}
pid_t CWorkerNetworkStatSender::Launcher(const sig_atomic_t *sighandle)
{
Fork();
if (m_pid == 0)
{
while (*sighandle == 0)
{
// work
set_ps_display("Worker [Network stat sender]", false);
do_work(sighandle);
// signal 받은 경우 wait 불필요
if(*sighandle == 0)
{
pause();
}
}
// httpd 구동 여부에 따라 Detache or Destroy를 결정함
if(IsProcessRun("httpd") == true)
{
m_shmemNetworStat.Detach();
LOG(LDBG, "m_shmemNetworStat.Detach()");
}
else
{
m_shmemNetworStat.Destroy();
LOG(LDBG, "m_shmemNetworStat.Destroy()");
}
m_launched = false;
}
return m_pid;
}
void CWorkerNetworkStatSender::do_work(const sig_atomic_t *sighandle)
{
apr_pool_t *p;
apr_pool_create(&p, NULL);
// account shared memory 생성
int nMaxAccount = CDeamonConfig::GetInstance()->GetMaxAccount();
int nNeworkStatSize = (sizeof(struct service_network_stat) * nMaxAccount * 2);
if (m_shmemNetworStat.Create("/tmp/opendav.shared.networkstat.shm", nNeworkStatSize, p) == false)
{
LOG(LERR, "Networkstat shared memory create failed.");
exit(EXIT_FAILURE);
}
SetThreadSignal(SIGINT);
SetThreadSignal(SIGTERM);
if( m_objNetworkStatSendThread.ThreadInit(sighandle, &m_shmemNetworStat ) == false )
{
UnSetThreadSignal(SIGINT);
UnSetThreadSignal(SIGTERM);
LOG(LERR, "Network stat send thread create failed.");
exit(EXIT_FAILURE);
}
if( m_objNetworkStatSendThread.Start() == false )
{
UnSetThreadSignal(SIGINT);
UnSetThreadSignal(SIGTERM);
LOG(LERR, "Network stat send thread start failed.");
exit(EXIT_FAILURE);
}
UnSetThreadSignal(SIGINT);
UnSetThreadSignal(SIGTERM);
}
+42
View File
@@ -0,0 +1,42 @@
/***************************************************************************
Process Test Class
-----------------------------------------
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 __WORKER_NETWORK_STAT_SENDER_H__
#define __WORKER_NETWORK_STAT_SENDER_H__
#include <list>
#include <map>
#include "Process.h"
#include "FimngdData.h"
#include "NetworkStatSendThread.h"
class CWorkerNetworkStatSender : public CProcess
{
public:
CWorkerNetworkStatSender();
virtual ~CWorkerNetworkStatSender();
pid_t Launcher(const sig_atomic_t *sighandle);
private:
void do_work(const sig_atomic_t *sighandle);
CNetworkStatSendThread m_objNetworkStatSendThread;
CSharedMem m_shmemNetworStat;
};
#endif // __WORKER_NETWORK_STAT_SENDER_H__
+116
View File
@@ -0,0 +1,116 @@
#include "WorkerServiceInfoUpdater.h"
#include <sstream>
#include "Logger.h"
#include "DaemonConfigs.h"
CWorkerServiceInfoUpdater::CWorkerServiceInfoUpdater()
{
}
CWorkerServiceInfoUpdater::~CWorkerServiceInfoUpdater()
{
}
pid_t CWorkerServiceInfoUpdater::Launcher(const sig_atomic_t *sighandle)
{
Fork();
if (m_pid == 0)
{
while (*sighandle == 0)
{
// work
set_ps_display("Worker [Service Info Updater]", false);
do_work(sighandle);
// signal 받은 경우 wait 불필요
if(*sighandle == 0)
{
pause();
}
}
// httpd 구동 여부에 따라 Detache or Destroy를 결정함
if(IsProcessRun("httpd") == true)
{
m_shmemAccount.Detach();
m_shmemAnoymous.Detach();
LOG(LDBG, " m_shmemAccount.Detach()");
}
else
{
m_shmemAccount.Destroy();
m_shmemAnoymous.Destroy();
LOG(LERR, "m_shmemAccount.Destroy()");
}
m_launched = false;
}
return m_pid;
}
void CWorkerServiceInfoUpdater::do_work(const sig_atomic_t *sighandle)
{
apr_pool_t *p;
apr_pool_create(&p, NULL);
// account shared memory 생성
int nMaxAccount = CDeamonConfig::GetInstance()->GetMaxAccount();
int nAccountMemSize = (sizeof(struct account) * nMaxAccount);
if (m_shmemAccount.Create("/tmp/opendav.shared.account.shm", nAccountMemSize, p) == false)
{
LOG(LERR, "Account shared memory create failed.");
exit(EXIT_FAILURE);
}
// anony shared memory 생성
int nMaxAnony = CDeamonConfig::GetInstance()->GetMaxAnonyMous();
int nAnonyMemSize = (sizeof(struct anonymous) * nMaxAnony);
if (m_shmemAnoymous.Create("/tmp/opendav.shared.anony.shm", nAnonyMemSize, p) == false)
{
LOG(LERR, "Anony shared memory create failed.");
exit(EXIT_FAILURE);
}
if( m_objAccount.ThreadInit(sighandle, &m_shmemAccount ) == false )
{
LOG(LERR, "CAccountUpdate Thread create failed.");
exit(EXIT_FAILURE);
}
if( m_objAnony.ThreadInit(sighandle, &m_shmemAnoymous ) == false )
{
LOG(LERR, "CAnonyUpdate Thread create failed.");
exit(EXIT_FAILURE);
}
SetThreadSignal(SIGINT);
SetThreadSignal(SIGTERM);
if( m_objAccount.Start() == false )
{
UnSetThreadSignal(SIGINT);
UnSetThreadSignal(SIGTERM);
LOG(LERR, "CAccountUpdate Thread start failed.");
exit(EXIT_FAILURE);
}
if( m_objAnony.Start() == false )
{
UnSetThreadSignal(SIGINT);
UnSetThreadSignal(SIGTERM);
LOG(LERR, "CAnony Thread start failed.");
exit(EXIT_FAILURE);
}
UnSetThreadSignal(SIGINT);
UnSetThreadSignal(SIGTERM);
}
+45
View File
@@ -0,0 +1,45 @@
/***************************************************************************
Process Test Class
-----------------------------------------
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 __SERVICE_INFO_UPDATER_H__
#define __SERVICE_INFO_UPDATER_H__
#include "Process.h"
#include "SharedMemAPR.h"
#include "AccountUpdateThread.h"
#include "AnonyUpdateThread.h"
#include "FimngdData.h"
class CWorkerServiceInfoUpdater : public CProcess
{
public:
CWorkerServiceInfoUpdater();
virtual ~CWorkerServiceInfoUpdater();
pid_t Launcher(const sig_atomic_t *sighandle);
CAccountUpdateThread m_objAccount;
CAnonyUpdateThread m_objAnony;
private:
void do_work(const sig_atomic_t *sighandle);
// 서비스 볼륨별 account 관리를 위한 shared memory 객체
CSharedMem m_shmemAccount;
// 무인증 폴더 관리를 위한 shared moemory 객체
CSharedMem m_shmemAnoymous;
};
#endif // __SERVICE_INFO_UPDATER_H__