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
+415
View File
@@ -0,0 +1,415 @@
#include "ArecaWrapper.h"
#include <vector>
#include <time.h>
#define MAX_EVENT_BUFF_SIZE 512
#define UNKNOWN_EVT_STR "Unknown Event"
CArecaWrapper::CArecaWrapper(int nEventLevel)
: m_nEventLevel( nEventLevel )
{
pthread_mutex_init(&mutex_lock, NULL);
}
CArecaWrapper::~CArecaWrapper()
{
pthread_mutex_destroy(&mutex_lock);
int nInterfaceIndex;
CArclib *ctrl;
for (nInterfaceIndex =0; nInterfaceIndex < m_nTotalCtrl; nInterfaceIndex++)
{
ctrl = &m_Arc[nInterfaceIndex];
LinuxIoctlInterface *out = (LinuxIoctlInterface*)ctrl->ArcGetInterface();
delete out;
}
}
// libacrlib에서 사용하는 pSYS_TIME 타입의 값을 time_t로 변환한다.
time_t CArecaWrapper::GetTime_t(pSYS_TIME evtTime)
{
/*
tm tmpTime;
tmpTime.tm_year = evtTime->u.tmYear+100;
tmpTime.tm_mon = evtTime->u.tmMonth-1;
tmpTime.tm_mday = evtTime->u.tmDate;
tmpTime.tm_hour = evtTime->u.tmHour;
tmpTime.tm_min = evtTime->u.tmMinute;
tmpTime.tm_sec = evtTime->u.tmSecond;
return mktime(&tmpTime);
*/
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = gmtime ( &rawtime );
timeinfo->tm_year = evtTime->u.tmYear+100;
timeinfo->tm_mon = evtTime->u.tmMonth-1;
timeinfo->tm_mday = evtTime->u.tmDate;
timeinfo->tm_hour = evtTime->u.tmHour;
timeinfo->tm_min = evtTime->u.tmMinute;
timeinfo->tm_sec = evtTime->u.tmSecond;
timeinfo->tm_isdst = 0; // disable daylight saving time
time_t ret = mktime ( timeinfo );
return ret;
}
/*
bool CArecaWrapper::DisableUpload()
{
system( "touch /user/service/vmasd.disable" );
struct stat st;
if( lstat( "/user/service/vmasd.disable", &st ) != 0 )
{
ERROR_LOG( "can't touch vmasd.disable" );
return false;
}
INFO_LOG( "disable upload." );
return true;
}
bool CArecaWrapper::IsDisableUpload( int eventCategory, int eventId )
{
switch( eventCategory )
{
case EVENT_DEVICE: // device event
/// The meaning of eventId
/// 0 : Device Inserted
/// 1 : Device Removed
/// 2 : Reading Error
/// 3 : Writing Error
/// 4 : ATA Ecc Error
/// 5 : Change ATA Mode
/// 6 : Time Out Error
/// 7 : Device Failed
/// 8 : PCI Parity Error
/// 9 : Dev Fail (SMART)
/// 10 : Pass
case EVENT_VOLUMESET: // volumeset event
case EVENT_RAIDSET: // raidset event
}
}
*/
//int CArecaWrapper::GetEvent(int nEventFlag, char *pszResult)
bool CArecaWrapper::GetEvent(int nEventFlag, list<CEventData>& listRet)
{
CArclib *ctrl;
ARC_STATUS stat = ARC_SUCCESS;
bool gotEvent = false;
int nCount = 0; // total number of event objects we got
int i;
int nCurEvtLevel = EVT_SERIOUS;
sSYSTEM_INFO sysInfo;
BYTE ptr1[64];
char tmpStr[64];
char eventStrBuf[MAX_EVENT_BUFF_SIZE];
int eventCategory = 0;
int eventId = 0;
//the time event occurred, defined in arclib.h
pSYS_TIME evtTime = (pSYS_TIME)new sSYS_TIME;
pthread_mutex_lock(&mutex_lock);
if (m_nTotalCtrl == 0) {
LOG(LERR, "No Raild controller was found.");
pthread_mutex_unlock(&mutex_lock);
if( evtTime )
{
delete evtTime;
}
return false;
}
ctrl = &m_Arc[0];
memset(ptr1, 0, sizeof(ptr1));
memset(tmpStr, 0, sizeof(tmpStr));
memset(eventStrBuf, 0, sizeof(eventStrBuf));
// event object defined in arclib.h
pEVENT_DATA pEventObject = (pEVENT_DATA)new sEVENT_DATA;
stat = ctrl->ArcGetSysInfo(&sysInfo);
if( stat != ARC_SUCCESS )
{
LOG(LERR, "ArcGetSysInfo Failed: %d",stat);
pthread_mutex_unlock(&mutex_lock);
if( pEventObject )
{
delete pEventObject;
}
if( evtTime )
{
delete evtTime;
}
return false;
}
/* We should call ArcSetTime() to correct the raid-subsystem time
Call ArcGetReqEventPage() to get the required event page from raid subsystem.
There are 4 event pages reside in the raid subsystem and each contains 16 event objects.
*/
memset(pEventObject, 0, sizeof(sEVENT_DATA));
stat = ctrl->ArcGetReqEventPage(nEventFlag, &nCount);
if (stat == ARC_SUCCESS)
{
if (nCount != 0)
{
for ( i = nCount - 1; i >= 0; i--)
{
// Call ArcGetEventObject function to extract the individual event object from event page
if (ctrl->ArcGetEventObject( i, pEventObject ))
{
::memset(eventStrBuf, 0, MAX_EVENT_BUFF_SIZE);
eventCategory = (int)pEventObject->evtCategory;
eventId = pEventObject->evtType;
*((LONG *)evtTime) = pEventObject->evtTime;
// Parse the event object we got
switch ((int)pEventObject->evtCategory)
{
/*
The member "evtStr" of event object structure contains the string to indicate
which raidset owns this event object
*/
case EVENT_RAIDSET: // raidset event
nCurEvtLevel = pEventObject->evtType;
memcpy(tmpStr, pEventObject->evtStr, 16);
if ( nCurEvtLevel > RS_EVT_NO_EVENT )
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmRaidEvent[pEventObject->evtType]);
}
sprintf((char *)eventStrBuf, "Controller#%d: %s %s",1, tmpStr, ptr1);
gotEvent = true;
break;
/*
The member "evtStr" of event object structure contains the string to indicate
which volumeset owns this event object
*/
case EVENT_VOLUMESET: // volumeset event
nCurEvtLevel = pEventObject->evtType;
memcpy(tmpStr, pEventObject->evtStr, 16);
if ( nCurEvtLevel >= VS_EVT_TOTALS)
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmVolEvent[pEventObject->evtType]);
}
sprintf((char *)eventStrBuf, "Controller#%d: %s %s", 1, tmpStr, ptr1);
gotEvent = true;
break;
case EVENT_DEVICE: // device event
nCurEvtLevel = pEventObject->evtType;
if( sysInfo.gsiTargetType == TARGET_SAS )
{
memcpy(tmpStr, pEventObject->evtStr, 16);
}
else
{
sprintf(tmpStr, "IDE Channel #%2d", pEventObject->evtChannel + 1);
}
if ( nCurEvtLevel >= DEV_EVT_TOTALS)
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmDevEvent[pEventObject->evtType]);
}
sprintf((char *)eventStrBuf, "Controller#%d: %s %s", 1
, tmpStr, ptr1 );
gotEvent = true;
break;
case EVENT_HOST: // host event
//this is Host SCSI events
nCurEvtLevel = pEventObject->evtType;
if ( sysInfo.gsiScsiHostChannels)
{
if ( nCurEvtLevel >= SCSI_EVT_TOTALS )
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmScsiHostEvent[pEventObject->evtType]);
}
} else {
if ( nCurEvtLevel >= SCSI_EVT_TOTALS )
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmIdeHostEvent[pEventObject->evtType]);
}
}
// CHG 2020-10-05 huibong FreeBSD 12.x 컴파일시 발생하는 warning 코드 수정 (#33225)
// - FreeBSD 12.x 의 gcc 9.3 컴파일시 sprintf 사용 관련 buffer size 문제로 warning 발생
// - flow 상으로는 buffer overflow 발생 가능성 없음
// - 하지만.. 컴파일시마다 warning 발생하므로.. 수정 결정
sprintf((char *)eventStrBuf, "Controller#%d: %s %s", 1, eventCat[pEventObject->evtCategory], ptr1 );
gotEvent = true;
break;
case EVENT_HW_MONITOR: // hardware monitor event
nCurEvtLevel = pEventObject->evtType;
memcpy(tmpStr, eventCat[pEventObject->evtCategory], 16);
if ( nCurEvtLevel >= HW_EVT_TOTALS )
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmHwMonEvent[pEventObject->evtType]);
}
sprintf((char *)eventStrBuf, "Controller#%d: %s %s", 1
, tmpStr, ptr1 );
gotEvent = true;
break;
case EVENT_NEW_83782D:
memcpy(tmpStr, pEventObject->evtStr, 16);
if ( pEventObject->evtType >= GHM_TOTALS )
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmNewEventStr[pEventObject->evtType]);
}
sprintf((char *)eventStrBuf, "Controller#%d: %s %s",1
, tmpStr, ptr1 );
gotEvent = true;
break;
case EVENT_NO_EVENT:
// 이벤트가 없는 경우
gotEvent = true;
default:
continue;
}// end switch
}// end if
// 모든 이벤트를 결과 list에 추가필요 수정 2015-06-26
CEventData objEvent;
objEvent.m_evtTime = GetTime_t(evtTime);
objEvent.m_szEventData = eventStrBuf;
objEvent.SetEventType( eventCategory, eventId );
listRet.push_back(objEvent);
}// end for
} else {
_LOG(LWAR, "Event empty.");
gotEvent = true;
}
}// end if
if (pEventObject) {
delete pEventObject;
}
if (evtTime) {
delete evtTime;
}
pthread_mutex_unlock(&mutex_lock);
return gotEvent;
}
int CArecaWrapper::DiscoveryDevice(void)
{
dev_t dev;
char buf[64];
mode_t mode = 0666;
unsigned int nTotalCtrl = 0;
ARC_STATUS stat = ARC_SUCCESS;
sSYSTEM_INFO sysInfo;
mode |= S_IFCHR;
for (int i = 0; i < 4; i++) {
memset(buf, 0, sizeof(buf));
sprintf(buf,"/dev/arcmsr%d", i);
unlink(buf);
}
for (int mymajor = 255; mymajor > 161; mymajor--)
{
for (int myminor = 0; myminor < 4; myminor++)
{
LinuxIoctlInterface *out = new LinuxIoctlInterface();
memset(buf, 0, sizeof(buf));
sprintf(buf,"/dev/arcmsr%d", nTotalCtrl);
dev = makedev(mymajor, myminor);
mknod(buf, mode, dev);
if (out->init(nTotalCtrl)) {
stat = m_Arc[nTotalCtrl++].ArcInitSession(out);
if (stat != ARC_SUCCESS) {
_LOG(LERR, "ArcInitSession Failed : %d",stat);
if( out )
{
delete out;
out = NULL;
}
unlink(buf);
return 0;
}
} else {
delete out;
out = NULL;
unlink(buf);
}
}
if (nTotalCtrl) {
break;
}
}
return nTotalCtrl;
}
int CArecaWrapper::InitArecaControllers(void)
{
int nCount = 0;
int nInterfaceIndex = 0;
m_nTotalCtrl = DiscoveryDevice();
_LOG(LDBG, "Total Count: %d", m_nTotalCtrl);
if(m_nTotalCtrl == 0)
{
return -1;
}
for (nInterfaceIndex =0; nInterfaceIndex < m_nTotalCtrl; nInterfaceIndex++)
{
m_Arc[nInterfaceIndex].ArcGetReqEventPage(FLAG_ALL, &nCount);
}
return m_nTotalCtrl;
}
+94
View File
@@ -0,0 +1,94 @@
/***************************************************************************
Areca Wrapper Class
-----------------------------------------
begin : 2010/05/19
copyright : (C) 2010 SolutionBox Inc.
author : svc1
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 __ARECA_WRAPPER__
#define __ARECA_WRAPPER__
#include <algorithm>
#include <iostream>
// 가장 중요하고 핵심적인 헤더 파일
#include "arclib.h"
#include "ethernet.h"
#include "EventData.h"
#include <list>
#include "Logger.h"
using namespace std;
// 필요한 인터페이스에 대한 헤더파일
#if defined(__linux__) || defined(__FreeBSD__)
#include "linux_comm.h"
#include "linux_ioctl.h"
#if defined(__linux__)
#include "linux_scsi.h"
#include "linux_pass_ioctl.h"
#else
#include "freebsd_scsi.h"
#endif
#endif
// 정보를 조회할 최대 컨트롤 수.
#define MAX_CONTROLLER_SUPPORTED 64
// for GetEvent()'s first param
#define GET_EVENT_ALL 0
#define GET_EVENT_ONE 1
class CArecaWrapper
{
public:
/// @brief 생성자.
/// @param nEventLevel [in] 필터 할 이벤트 레벨을 지정한다. conf를 통해 받아오게 되며, 레벨은 아래와 같다.
///< -------- EVENT LEVEL ---------
///< 0: Not to report
///< 1: Serious Error Notification
///< 2: Error Notification
///< 3: Warning Notification
///< 4: Information Notification
///< ------------------------------
CArecaWrapper(int nEventLevel);
/// @brief 소멸자.
~CArecaWrapper();
/// @brief Areca Controller의 정보를 얻을 준비를 한다.
// @return Areca Controller의 개수를 리턴한다. 없을 경우 -1을 리턴한다.
int InitArecaControllers(void);
/// @brief Areca Controller의 정보를 얻을 준비를 한다.
/// @param nFlag [in] 이벤트 받을 형태를 지정한다.
//< GET_EVENT_ALL : 저장된 모든 이벤트 데이터를 수신한다.
//< GET_EVENT_ONE : 최근 1개의 이벤트 데이터를 수신한다.
/// @param listRet [out] Areca Library를 통해 얻은 데이터를 저장한다. 데이터의 타입은 CEventData 형태이다.
/// @return 성공시 true, 실패시 false 를 리턴한다.
bool GetEvent(int nFlag, list<CEventData>& listRet);
private:
CArclib m_Arc[MAX_CONTROLLER_SUPPORTED];
pthread_mutex_t mutex_lock;
int DiscoveryDevice(void);
time_t GetTime_t(pSYS_TIME evtTime);
int m_nEventLevel;
int m_nTotalCtrl;
//bool IsDisableUpload( int eventCategory, int eventId );
//bool DisableUpload();
};
#endif // __ARECA_WRAPPER__
+127
View File
@@ -0,0 +1,127 @@
/***************************************************************************
AutoDisableUpload.cpp
-----------------------------------------
begin : 2011/07/26
copyright : (C) 2010 SolutionBox Inc.
author : svc1
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 "AutoDisableUpload.h"
using namespace std;
CAutoDisableUpload::CAutoDisableUpload()
{
}
CAutoDisableUpload::~CAutoDisableUpload()
{
}
void CAutoDisableUpload::DoProcess( int eventCategory, int eventId )
{
if( IsDisableUpload( eventCategory, eventId ) == false )
{
return;
}
system( "touch /user/service/vmasd.disable" );
struct stat st;
if( lstat( "/user/service/vmasd.disable", &st ) != 0 )
{
LOG(LERR, "can't touch vmasd.disable. event category = %s, event name = %s",
m_szEventCategory.c_str(), m_szEventName.c_str() );
return;
}
_LOG(LINF, "disable upload. event category = %s, event name = %s",
m_szEventCategory.c_str(), m_szEventName.c_str() );
}
bool CAutoDisableUpload::IsDisableUpload( int eventCategory, int eventId )
{
switch( eventCategory )
{
case EVENT_DEVICE:
/// The meaning of eventId.
/// 0(DEV_EVT_ADDED) - Device Inserted
/// 1(DEV_EVT_REMOVED) - Device Removed
/// 2(DEV_EVT_READ_ERROR) - Reading Error
/// 3(DEV_EVT_WRITE_ERROR) - Writing Error
/// 4(DEV_EVT_ATA_ECC_ERROR) - ATA Ecc Error
/// 5(DEV_EVT_ATA_CHANGE_MODE) - Change ATA Mode
/// 6(DEV_EVT_TIMEOUT) - Time Out Error
/// 7(DEV_EVT_MARK_FAILED) - Device Failed
/// 8(DEV_EVT_PCI_ERROR) - PCI Parity Error
/// 9(DEV_EVT_SMART_FAILED) - Dev Fail (SMART)
/// 10(DEV_EVT_CREATE_PASS) - Pass Through Disk Created
/// 11(DEV_EVT_MODIFY_PASS) - Pass Through Disk Modified
/// 12(DEV_EVT_DELETE_PASS) - Pass Through Disk Deleted
m_szEventCategory = "Device Event";
m_szEventName = htmDevEvent[ eventId ];
return ( eventId == DEV_EVT_MARK_FAILED ? true : false );
case EVENT_VOLUMESET:
/// The meaning of eventId.
/// 0(VS_EVT_INITIALIZING) - Start Initialize
/// 1(VS_EVT_REBUILDING) - Start Rebuilding
/// 2(VS_EVT_MIGRATING) - Start Migrating
/// 3(VS_EVT_CHECKING) - Start Checking
/// 4(VS_EVT_COMPLETE_INIT) - Complete Init
/// 5(VS_EVT_COMPLETE_REBUILD) - Complete Rebuild
/// 6(VS_EVT_COMPLETE_MIGRATING) - Complete Migrate
/// 7(VS_EVT_COMPLETE_CHECKING) - Complete Check
/// 8(VS_EVT_CREATE) - Create Volume
/// 9(VS_EVT_DELETE) - Delete Volume
/// 10(VS_EVT_MODIFY) - Modify Volume
/// 11(VS_EVT_DEGRADED) - Volume Degraded
/// 12(VS_EVT_FAILED) - Volume Failed
/// 13(VS_EVT_REVIVED) - Failed Volume Revived
/// 14(VS_EVT_ABORT_INIT) - Abort Initialization
/// 15(VS_EVT_ABORT_REBUILD) - Abort Rebuilding
/// 16(VS_EVT_ABORT_MIGRATING) - Abort Migration
/// 17(VS_EVT_ABORT_CHECKING) - Abort Checking
/// 18(VS_EVT_STOP_INIT) - Stop Initialization
/// 19(VS_EVT_STOP_REBUILD) - Stop Rebuilding
/// 20(VS_EVT_STOP_MIGRATING) - Stop Migration
/// 21(VS_EVT_STOP_CHECKING) - Stop Checking
m_szEventCategory = "VolumeSet Event";
m_szEventName = htmVolEvent[ eventId ];
return ( ( eventId == VS_EVT_REBUILDING ) || ( eventId == VS_EVT_DEGRADED ) ? true : false );
case EVENT_RAIDSET:
/// The meaning of eventId
/// 0(RS_EVT_CREATE) - Create RaidSet
/// 1(RS_EVT_DELETE) - Delete RaidSet
/// 2(RS_EVT_EXPAND) - Expand RaidSet
/// 3(RS_EVT_REBUILD) - Rebuild RaidSet
/// 4(RS_EVT_DEGRADED) - RaidSet Degraded
m_szEventCategory = "RaidSet Event";
m_szEventName = htmRaidEvent[ eventId ];
return ( ( eventId == RS_EVT_REBUILD ) || ( eventId == RS_EVT_DEGRADED ) ? true : false );
/// for test code
///case EVENT_NEW_83782D:
/// m_szEventCategory = "New Events";
/// m_szEventName = htmNewEventStr[ eventId ];
/// return ( eventId == GHM_GUI_LOGIN ? true : false );
default:
m_szEventCategory = "";
m_szEventName = "";
}
return false;
}
+57
View File
@@ -0,0 +1,57 @@
/***************************************************************************
AutoDisableUpload.h
-----------------------------------------
begin : 2011/07/26
copyright : (C) 2010 SolutionBox Inc.
author : svc1
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 __AUTODISABLEUPLOAD_H__
#define __AUTODISABLEUPLOAD_H__
#include "arclib.h"
#include "Logger.h"
#include <string>
class CAutoDisableUpload
{
// Attributes
private:
std::string m_szEventCategory;
std::string m_szEventName;
protected:
public:
// Operations
private:
/// @brief 업로드 방지 이벤트 발생 여부 확인.
/// @param eventCategory [in] 이벤트 카테고리
/// @param eventId [in] 이벤트 카테고리별 이벤트 아이디
/// @return 업로드 방지 이벤트면 true, 그렇지 않으면 false.
bool IsDisableUpload( int eventCategory, int eventId );
protected:
public:
CAutoDisableUpload();
virtual ~CAutoDisableUpload();
/// @brief 업로드 방지 이벤트가 발생했으면 /user/service/vmasd.disable 파일을 생성해서
/// 업로드가 방지 되도록 한다.
/// @param eventCategory [in] 이벤트 카테고리
/// @param eventId [in] 이벤트 카테고리별 이벤트 아이디
/// @return 없음.
void DoProcess( int eventCategory, int eventId );
};
#endif // __AUTODISABLEUPLOAD_H__
+257
View File
@@ -0,0 +1,257 @@
#include "fhs_raidmond.h"
#include "Child.h"
#include "SmsSender.h"
#include "ArecaWrapper.h"
#include "UdpListener.h"
#include "EventDataManager.h"
#include "AutoDisableUpload.h"
#define MAXSIZEOFSTR 128
/// @brief child Process 종료 Signal 을 전달받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigTermChild( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
_LOG( LWAR, "Child Process[%d] exit job start by user signal [SIGTERM]", getpid() );
}
else
{
_LOG(LWAR, "Child Process[%d] exit job start by abnormal signal [%d]", getpid(), nSignalNumber );
}
_LOG(LWAR, "Child Process[%d] exit job end. Good Bye..", getpid());
usleep(500000);
exit( EXIT_SUCCESS );
}
/// @brief child Process 에서 Core 생성 관련 Signal 을 받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigCoreChild( int nSignalNumber )
{
_LOG(LERR, "Child Process[%d] abnoraml exit. Check Core file. Receive signal [%d]", getpid(), nSignalNumber );
//ERROR_LOG( "Core file path : [%s/%s.core]", g_envConfig.szLogDir.c_str(), PROG_NAME );
// Process 종료관련 작업 추가
// Log Directory 상에 Core 파일 생성처리.
chdir( g_envConfig.szLogDir.c_str() );
signal( nSignalNumber, SIG_DFL );
// Core dump 생성을 위한 신호 발생처리.=> ?
raise( nSignalNumber );
}
/// @brief child process signal 처리 설정을 위한 함수
/// @return void
static void SetSignalChild( void )
{
sigset_t set;
struct sigaction act;
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
memset( &act, 0x00, sizeof(act) );
sigfillset( &act.sa_mask );
/* 무시할 신호 목록 */
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL); /* 파이프 디스크립터 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP , &act, NULL); /* Process를 기동시킨 관리자의 로그아웃시 발생 시그널 */
sigaction( SIGINT , &act, NULL); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
// Child 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
sigaction( SIGCHLD, &act, NULL);
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SigTermChild;
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
/* Core 관련 signal 처리 : 오류 처리 및 Debug(core dump) 목적 */
// dadamin : 팀 기준 적용
//act.sa_handler = SigCoreChild;
//sigaction( SIGILL , &act, NULL); /* Illegal instruction */
//sigaction( SIGFPE , &act, NULL); /* Erroneout arithmetic operation */
//sigaction( SIGBUS , &act, NULL); /* Access to undefined portion of a memory object */
//sigaction( SIGSEGV, &act, NULL); /* Invalid memory reference */
//sigaction( SIGSYS , &act, NULL); /* Bad System Call */
//sigaction( SIGXCPU, &act, NULL); /* CPU-time limit exceeded */
//sigaction( SIGXFSZ, &act, NULL); /* File-size limit exceeded */
sigemptyset(&set); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask(SIG_SETMASK, &set, NULL);
}
/// @brief Child Process 의 main 함수
int ChildMain(void)
{
bool bRet = false;
int nFailCnt = 0;
// set child signal
SetSignalChild();
#if defined(__FreeBSD__)
setproctitle( "Child [initialize process]");
#endif
char szTime[MAXSIZEOFSTR];
time_t ltime;
struct tm *pTm = NULL;
char szHostname[MAXSIZEOFSTR];
// ** SMS Sender 객체 생성 및 초기화
CSmsSender objSmsSender(g_envConfig.szSMSHost, g_envConfig.nSMSPort, g_envConfig.szSMSSendfile);
bRet = objSmsSender.Init();
if( bRet == false )
{
LOG(LERR, "Initializing SmsSender Object has failed.");
exit(EXIT_FAILURE);
}
// ** SMS Sender 객체 생성 및 초기화
// 2015-06-26 두 번째 파라메터는 더이상 의미가 없다.
CArecaWrapper objAreca(g_envConfig.nEventLevel);
if( objAreca.InitArecaControllers() < 0 )
{
LOG(LERR, "Initializing Areca RAID Controller has failed.");
exit(EXIT_FAILURE);
}
// ** EventDataManager 객체 생성 및 초기화
CEventDataManager objDataManager;
bRet = objDataManager.Init();
if( bRet == false )
{
LOG(LERR, "Initializing SmsSender Object has failed.");
exit(EXIT_FAILURE);
}
// ** Raid Event Monitor 객체 생성 및 초기화
// ** UDP Listener 객체 생성 및 초기화
CUdpListener udpObj(&objDataManager);
// report thread port :
bRet = udpObj.Init(g_envConfig.nReportPort);
if( bRet == false )
{
LOG(LERR, "Initializing UdpListener Object has failed.");
exit(EXIT_FAILURE);
}
udpObj.Start();
// 현재 hostname
// hostname이 변경되면 반영되지 않는다. 반영이 꼭필요하다면 while구문 안으로 넣으면 된다.
if( ::gethostname(szHostname, MAXSIZEOFSTR) < 0 )
{
_LOG(LWAR, "gethostname failed. : %s", szHostname);
::snprintf(szHostname, MAXSIZEOFSTR, "%s", "error.hostname.com");
}
nFailCnt = 0;
while( 1 )
{
list<CEventData> listRet;
if( objAreca.GetEvent(GET_EVENT_ALL, listRet) == false )
{
if( nFailCnt < 3 )
{
nFailCnt++;
_LOG(LWAR, "Get RAID Event Data Failed.");
}
else
{
LOG(LERR, "Get RAID Event Data Failed. %d(th). Send SMS.",nFailCnt);
nFailCnt = 0;
// 현재 시각 설정
time((time_t *)&ltime);
pTm = ::localtime((time_t *)&ltime);
::memset(szTime, 0, sizeof(szTime));
::snprintf(szTime, MAXSIZEOFSTR, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
pTm->tm_year+1900, pTm->tm_mon +1, pTm->tm_mday,
pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
objSmsSender.SendToWebServ(szHostname, szTime ,"Can NOT Receive Data From RAID Controller!");
}
sleep(g_envConfig.nCheckTerm);
continue;
}
nFailCnt = 0; // 성공하면 실패 카운트를 리셋한다.
// 받아온 Raid Event 저장
bRet = objDataManager.SetCurrentData(listRet);
if( bRet == false )
{
LOG(LERR, "SetCurrentData Failed. but it's Impossible. Check ArecaWrapper::GetEvent().");
sleep(g_envConfig.nCheckTerm);
continue;
}
// SMS 전송 목록
listRet.clear();
bRet = objDataManager.GetSmsEvent(listRet);
if( bRet == false )
{
LOG(LERR, "GetSmsEvent() failed.");
sleep(g_envConfig.nCheckTerm);
continue;
}
for (list<CEventData>::iterator it=listRet.begin(); it!=listRet.end(); it++)
{
// NEW 2019-09-16 huibong 불필요 "Battery Module Failed" event 는 전송하지 않는다. (#32795)
// - "Battery Module Failed" event 는 운영자가 수신해도 할 작업이 없음
// - 하지만 일 10~20 건 정도가 발생하여 운영자에게 불필요 event 가 전달됨
// - 이와 관련 KT 운영팀 윤철희 실장이 해당 event 는 무시하도록 처리해 달라고 해서...
// - 해당 메시지 발생시 운영자에게 event 전송하지 않도록 한다.
// - 실제로 CEventDataManager 모듈에서도 처리가능하지만...
// - 본 모듈에서 실제 event 전송을 담당하므로.. 본 모듈에서 무시 처리하도록 수정함.
// BUG 2020-01-10 huibong 불필요 "Battery Module Failed" event 미전송 관련 버그 수정 (#32911)
// - 실제로 Module 단어와 Failed 단어 사이에 공백이 3개 존재
// - 이로 인해 해당 event 가 계속 전송되는 상황 발견됨
// - 이에 Battery Module" check 후 Failed 문자열 check 하도록 수정
std::string::size_type find_result;
find_result = it->m_szEventData.find( "Battery Module" );
if( find_result != std::string::npos )
{
find_result = it->m_szEventData.find( "Fail" );
if( find_result != std::string::npos )
{
_LOG( LDBG, "Do not send event with operator requests [%s]", it->m_szEventData.c_str() );
continue;
}
}
pTm = ::localtime(&(it->m_evtTime));
::memset(szTime, 0, sizeof(szTime));
::snprintf(szTime, MAXSIZEOFSTR, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
pTm->tm_year+1900, pTm->tm_mon +1, pTm->tm_mday,
pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
_LOG(LWAR, "SMS Sent.[%s::%s:%s]",szHostname, szTime, it->m_szEventData.c_str());
//FIXME:호출하면 SMS가 발송된다... :많은사람에게 문자가 수신되므로 디버깅 때는 가급적 자제할것. please........
objSmsSender.SendToWebServ(szHostname, szTime ,it->m_szEventData.c_str());
/// 2011.07.26, 수정자 : 장희준
/// 업로드 자동 방지
CAutoDisableUpload autoDisableUpload;
autoDisableUpload.DoProcess( it->GetEventCategory(), it->GetEventId() );
}
sleep(g_envConfig.nCheckTerm);
}
// wait
while(1)
{
// 그냥 시그널 대기
pause();
}
//잠시 대기 후 종료처리.
usleep(500000);
// exit( EXIT_SUCCESS );
return EXIT_SUCCESS; // fork 를 수행한 함수에서 exit 함수 호출을 통한 종료처리
}
+32
View File
@@ -0,0 +1,32 @@
/***************************************************************************
fhs_raidmond Header ( Child.h )
-----------------------------------------
begin : 2010/03/09
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 __CHILD_PROCESS_H__
#define __CHILD_PROCESS_H__
#ifdef __cplusplus
extern "C" {
#endif
/// @brief Child Process ÀÇ main ÇÔ¼ö
/// @return
int ChildMain( void );
#ifdef __cplusplus
}
#endif
#endif /* __CHILD_PROCESS_H__ */
+131
View File
@@ -0,0 +1,131 @@
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <iostream>
using namespace std;
#define MaxRTTime 5
#define MaxRecvBuffSize (20 * 1024)
void handleAlarm(int signal)
{
return; // just return and interupt.
}
// main function
int main( int argc, char * argv[] )
{
if(argc != 4)
{
cerr << PROG_NAME << " Version :" << PROG_VERSION << endl;
cerr << "Usage: " << PROG_NAME << " server-ip port mode" << endl;
return EXIT_FAILURE;
}
static bool success = false;
// parse command line arguments
string host = argv[1];
int port = atoi(argv[2]);
string mode = argv[3];
//cout << "arguments : " << host << "," << port << "," << mode << endl;
int r = -1;
struct sockaddr_in cliaddr;
int addr_len = sizeof(cliaddr);
char recvbuf[MaxRecvBuffSize];
string result;
// socket initialize
int s = -1;
s = socket(AF_INET, SOCK_DGRAM, 0);
if(s < 0)
{
cerr << "Socket Create: errno:" << errno << " errmsg:" << strerror(errno) << endl;
return EXIT_FAILURE;
}
struct timeval timeout;
timeout.tv_sec = MaxRTTime;
timeout.tv_usec = 0;
int optlen = sizeof(timeout);
int errtimeout = -1;
if( setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, (socklen_t)optlen) < 0)
{
struct sigaction sigact, oldact;
sigact.sa_handler = handleAlarm;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
#ifdef SA_INTERRUPT
sigact.sa_flags |= SA_INTERRUPT;
#endif // SA_INTERRUPT
if(sigaction(SIGALRM, &sigact, &oldact) < 0)
{
cerr << "sigaction error: errno:" << errno << " errmsg:" << strerror(errno) << endl;
return EXIT_FAILURE;
}
errtimeout = EINTR;
}
else
errtimeout = EAGAIN;
struct sockaddr_in SocAddr;
SocAddr.sin_family = AF_INET;
SocAddr.sin_port = htons(port);
//SocAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (inet_aton(host.c_str(), &SocAddr.sin_addr)==0)
{
cerr << "inet_aton() failed: errno:" << errno << " errmsg:" << strerror(errno) << endl;
return EXIT_FAILURE;
}
// send
int len = mode.length();
if( sendto( s, mode.c_str(), mode.length(), 0, (struct sockaddr *)&SocAddr, sizeof(SocAddr) ) != len)
{
cerr << "sendto error : errno :"<< errno << " errmg:" << strerror(errno) << endl;
goto GOTO_END;
}
if( errtimeout == EINTR )
{
alarm(MaxRTTime);
}
// receive
do
{
memset(recvbuf, 0, MaxRecvBuffSize);
r = recvfrom( s, (char *)&recvbuf, (unsigned int)MaxRecvBuffSize, 0, (struct sockaddr *)&cliaddr, (socklen_t *)&addr_len );
//cerr << "nREAD = " << r << "," << errno << endl;
if(r >= 0)
result += recvbuf;
else
{
if( errno == errtimeout ) // timeout
{
cerr << "3:" << (long)time(NULL) << ":Disabled" << endl;
goto GOTO_END;
}
}
} while (r <= 0);
cout << result << endl;
if (result.size())
success = true;
GOTO_END:
close(s);
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
+60
View File
@@ -0,0 +1,60 @@
/***************************************************************************
Areca Library Event Data Class
-----------------------------------------
begin : 2010/05/21
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 __EVENT_DATA__
#define __EVENT_DATA__
#include <pthread.h>
#include <string>
#include <time.h>
/// @brief CEventData
/// EventData 는 Areca library로부터 받아오는 raid event 정보를 저장한다.
/// 내부적으로 Thread를 사용하고있다.
class CEventData
{
private:
int m_nEventCategory;
int m_nEventId;
public:
/// @brief Areca Library에서 얻어온 데이터의 시간값을 저장한다.
time_t m_evtTime;
std::string m_szEventData;
public:
/// @brief 생성자
CEventData(){};
/// @brief 소멸자
~CEventData(){};
inline void SetEventType( int eventCategory, int evnetId )
{
m_nEventCategory = eventCategory;
m_nEventId = evnetId;
}
inline int GetEventCategory() { return m_nEventCategory; };
inline int GetEventId() { return m_nEventId; };
/// @brief Areca Library에서 얻어온 이벤트 데이터를 저장한다.
///< 데이터의 형태로 반복여부를 확인하여 중복 반복시 최초 1개의 데이터만을 알림하도록 설계되었다.
inline bool operator==(const CEventData& t)
{
return ( (t.m_evtTime == m_evtTime) && (t.m_szEventData == m_szEventData) );
}
};
#endif // __EVENT_DATA__
+163
View File
@@ -0,0 +1,163 @@
#include <iostream>
#include <sstream>
#include "EventDataManager.h"
#include <stdlib.h>
#include <algorithm>
#define REPEAT_ALLOW_TIME 60*60
// 생성자
CEventDataManager::CEventDataManager()
{
pthread_mutex_init(&m_mutex, NULL);
}
// 소멸자
CEventDataManager::~CEventDataManager()
{
pthread_mutex_destroy(&m_mutex);
}
bool CEventDataManager::Init(void)
{
return true;
}
bool CEventDataManager::GetAllData(list<CEventData>& listRet)
{
pthread_mutex_lock( &m_mutex );
// SetCurrentData가 정상적으로 동작하였다면, m_Old.size()의 조건에 걸릴 수 없다.
if ( m_Current.size() < 1 || m_Old.size() < 1 )
{
pthread_mutex_unlock( &m_mutex );
_LOG(LINF, "Data have Nothing.");
return false;
}
listRet = m_Current;
pthread_mutex_unlock( &m_mutex );
return true;
}
int CEventDataManager::GetLatestData( CEventData& resData )
{
pthread_mutex_lock( &m_mutex );
// SetCurrentData가 정상적으로 동작하였다면, m_Old.size()의 조건에 걸릴 수 없다.
if ( m_Current.size() < 1 || m_Old.size() < 1 )
{
pthread_mutex_unlock( &m_mutex );
_LOG(LINF, "Data have Nothing.");
return -1;
}
if( m_Old.back().m_evtTime == m_Current.back().m_evtTime )
{ // ( 과거와 현재 최종 이벤트 시각이 동일하면 변화가 없는 것이다. )
resData = m_Current.back();
resData.m_szEventData = "NO EVENT";
pthread_mutex_unlock( &m_mutex );
return 0;
}
// 과거와 현재 최종 이벤트 시각이 다르면 이벤트가 추가된 것이다.
resData = m_Current.back();
pthread_mutex_unlock( &m_mutex );
return 1;
}
bool CEventDataManager::SetCurrentData(list<CEventData>& listRet)
{
pthread_mutex_lock( &m_mutex );
if( listRet.empty() )
{
pthread_mutex_unlock( &m_mutex );
_LOG(LINF, "EventData is empty.");
return false;
}
// 들어온 데이터는 모두 시간순으로 정렬한다. (오름차순)
// Old 데이터를 지운다.
m_Old.clear();
//현재 값이 비어있을 경우 (최초 실행으로 간주함)
if( m_Current.empty() == true)
{
m_Old = listRet;
}
else
{
m_Old = m_Current;
}
m_Current = listRet;
pthread_mutex_unlock( &m_mutex );
return true;
}
bool CEventDataManager::GetSmsEvent(list<CEventData>& listRet)
{
CEventData fetchedData;
CEventData lastDataOfOld;
list<CEventData> eventData = m_Current;
list<CEventData> listFindTemp;
pthread_mutex_lock( &m_mutex );
if( m_Current.size() == 0 )
{
LOG(LERR, "List have No Data");
pthread_mutex_unlock( &m_mutex );
return false;
}
// 과거의 최신 데이터를 저장한다.
m_SentOld = m_Old.back();
// 현재 리스트의 뒤쪽(최신)부터 동일 데이터를 찾는다.
// (데이터에 시간 값이 포함되어 있기 때문에 완전히 동일한 데이터는 없는 것으로 간주한다.)
// (있을 경우 무시해도 되지 않을까?)
listFindTemp.push_back(m_SentOld);
// find_end를 사용하기 위해서 원소가 1개인 리스트를 생성한다.
list<CEventData>::iterator it = find_end(m_Current.begin(), m_Current.end(), listFindTemp.begin(), listFindTemp.end());
// 뒤쪽부터 원소가 1개인 리스트(listFindTemp)를 찾는다.
// find_end()는 집합에 속하는 부분집합을 찾는다.
// 찾아낸 데이터의 뒤쪽 부분은 신규 데이터이다.
if( it == m_Current.end() )
{ // end()와 같다면, 끝까지 찾지 못한 것을 의미한다. (NOT FOUND)
// 찾지 못한 것은 전체가 다 새로운 것이다.
_LOG(LINF, "List has NEW Event perfectly.");
it = m_Current.begin();
}
else
{ // 찾아낸 데이터의 다음 데이터를 가리키도록 한다.
++it;
}
// 신규 데이터 목록 중 앞쪽(오래된)부터 중복된 데이터인지를 검사한다.
for( ; it != m_Current.end(); it++)
{
if( it->m_szEventData == m_SentOld.m_szEventData
&& it->m_evtTime - m_SentOld.m_evtTime < REPEAT_ALLOW_TIME
&& it->m_evtTime - m_SentOld.m_evtTime >= 0 )
{ // 내용이 중복되고 마지막 이벤트로부터 1시간 미만 차이나면?
// BUG: Areca bug로 시간이 역순할 수 있다. REPEAT_ALLOW_TIME보다 작은 음수 값이 나오게 되면 무시하면 안된다.
_LOG(LINF, "There is Repeted Event.[%s]",it->m_szEventData.c_str());
// 중복 되면 버린다.(과거 데이터를 우선한다)
continue;
}
// 중복 데이터가 아니면 결과에 추가 한다.(SMS발송 대상)
listRet.push_back(*it);
m_SentOld = *it;
_LOG(LDBG, "ADD : [%lu::%s]", it->m_evtTime, it->m_szEventData.c_str());
}
// SMS발송 대상이 없을 경우 디버깅 로그만 남긴다.
if( listRet.size() == 0 )
{
LOG(LDBG, "There is No New Event.");
}
pthread_mutex_unlock( &m_mutex );
return true;
}
+53
View File
@@ -0,0 +1,53 @@
/***************************************************************************
SMS Raid Event Data Manager Class
-----------------------------------------
begin : 2010/05/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 __EVENT_DATA_MANAGER__
#define __EVENT_DATA_MANAGER__
#include <pthread.h>
#include <string>
#include <time.h>
#include "Logger.h"
#include "EventData.h"
#include <list>
using namespace std;
/// @brief CEventDataManager
/// EventDataManager 는 Areca library로부터 받아오는 raid event 정보를 저장한다.
class CEventDataManager
{
public:
/// @brief 생성자
CEventDataManager();
/// @brief 소멸자
~CEventDataManager();
//TODO:
bool Init();
bool SetCurrentData(list<CEventData>& listRet);
bool GetSmsEvent(list<CEventData>& listRet);
int GetLatestData( CEventData& resData );
bool GetAllData(list<CEventData>& listRet);
private:
// TODO:
list<CEventData> m_Current;
list<CEventData> m_Old;
CEventData m_SentOld;
pthread_mutex_t m_mutex;
};
#endif // __EVENT_DATA_MANAGER__
+189
View File
@@ -0,0 +1,189 @@
#include "fhs_raidmond.h"
#include "Config.h"
#include "GetConfig.h"
/// @brief config value chech
/// @param szValue [in] value
/// @param conf [in] Config 객체
/// @param defsection [in] default section
/// @param defkey [in] default key
/// @return 성공시 true, 오류 발생시 false 를 반환.
static bool CheckValue(std::string& szValue, Config& conf, const std::string& defsection, const std::string& defkey)
{
if( szValue.size() > 0 )
return true;
if( defsection.size() <= 0 || defkey.size() <= 0 )
return false;
conf.GetConfig( defsection, defkey, szValue );
if( szValue.size() > 0 )
return true;
return false;
}
bool GetConfig( const std::string& szConfFile, struct st_config& stConfig, std::string& errorMessage )
{
bool ret = false;
// Config 처리를 위한 객체 생성
Config conf;
// Config File open
if( conf.Open( szConfFile) == false )
{
errorMessage = "Config file open failed.[" + szConfFile + "]";
return false;
}
std::string szValue;
szValue.clear();
// log path
if( conf.GetConfig( PROG_NAME, "DEFAULT_LOG_DIR", szValue ) == false )
{
if( !CheckValue(szValue, conf, "COMMON", "DEFAULT_LOG_DIR") )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->LOG_DIR";
return false;
}
}
stConfig.szLogDir = szValue;
szValue.clear();
// log level
if( conf.GetConfig( PROG_NAME, "LOG_LEVEL", szValue ) == false )
{
if( !CheckValue(szValue, conf, "COMMON", "LOG_LEVEL") )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->LOG_LEVEL";
return false;
}
}
stConfig.nLogLevel = atoi(szValue.c_str());
szValue.clear();
// check term
if( conf.GetConfig( PROG_NAME, "HEALTH_CHECK_TERM", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->HEALTH_CHECK_TERM";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->HEALTH_CHECK_TERM";
return false;
}
stConfig.nCheckTerm = atoi(szValue.c_str());
szValue.clear();
// report port
if( conf.GetConfig( PROG_NAME, "REPORT_THREAD_PORT", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->REPORT_THREAD_PORT";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->REPORT_THREAD_PORT";
return false;
}
stConfig.nReportPort = atoi(szValue.c_str());
szValue.clear();
//event level
if( conf.GetConfig( PROG_NAME, "EVENT_LEVEL", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->EVENT_LEVEL";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->EVENT_LEVEL";
return false;
}
stConfig.nEventLevel = atoi(szValue.c_str());
szValue.clear();
//sms send host
if( conf.GetConfig( PROG_NAME, "SMS_SEND_HOST", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_HOST";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_HOST";
return false;
}
stConfig.szSMSHost = szValue;
szValue.clear();
//sms send port
if( conf.GetConfig( PROG_NAME, "SMS_SEND_PORT", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_HOST";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_PORT";
return false;
}
stConfig.nSMSPort = atoi(szValue.c_str());
szValue.clear();
//sms send file
if( conf.GetConfig( PROG_NAME, "SMS_SEND_URI", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_FILE";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_FILE";
return false;
}
stConfig.szSMSSendfile = szValue;
szValue.clear();
ret = true;
return ret;
}
+37
View File
@@ -0,0 +1,37 @@
/***************************************************************************
rc_rmcd ( File Replication & Cache Control Daemon ) Header ( GetConfig.h )
-----------------------------------------
begin : 2010/03/03
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 __GET_CONFIG_H__
#define __GET_CONFIG_H__
#ifdef __cplusplus
extern "C" {
#endif
/// @brief config file parsing and save to stConfig function
/// @param szConfFile [in] Conf 파일에 대한 경로 및 파일 정보
/// @param stConfig [out] Conf 파일의 정보를 저장하기 위한 st_config 참조변수
/// @param errorMessage [out] 오류발생시 해당 오류 정보를 저장하여 반환하기 위한 참조변수
/// @return 성공시 true, 오류 발생시 false 를 반환. 상세한 오류 정보는 errorMessage 변수에 저장됨.
bool GetConfig( const std::string& szConfFile, struct st_config& stConfig, std::string& errorMessage);
#ifdef __cplusplus
}
#endif
#endif /* __GET_CONFIG_H__ */
+87
View File
@@ -0,0 +1,87 @@
#****************************************************************************
# Makefile for Arcmond
# -----------------------------------------
#
# begin : 2010/05/17
# copyright : (C) 2005 SolutionBox Inc.
# author : Service 1 Team
# email : svc1@solbox.com
# version : 3.0.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.
#*****************************************************************************
# Program info
PROG_NAME = arcmond
PROG_NAME_C = arcmond_client
#REVISION = `svnversion -n .`
REVISION = 1507
BUILD_DATE = `date +%Y%m%d%H%M%S`
PROG_VERSION = 3.5.0.$(REVISION)-$(BUILD_DATE)
DEFAULT_CONFIG_FILE = /user/service/etc/util.conf
INSTALL_BIN = /user/service/bin
OSBITS := $(shell getconf LONG_BIT)
# Compiler info
CC = /usr/bin/g++
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized \
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-fno-rtti -D_REENTRANT -Wno-unused -Wno-non-virtual-dtor
LFLAGS = -lpthread
# DEBUG or RELEASE Mode select
#DFLAGS = -D_DEBUG_ -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
# Application Enviroment
APP = $(PROG_NAME)
DIR_INCLUDE = -I./. -I../lib -I ../external/include #-I /user/db/pgsql/include -I../
DIR_LIB = -L../lib -L../external/bin/
OBJ = GetConfig.o Child.o main.o ArecaWrapper.o UdpListener.o SmsSender.o EventDataManager.o AutoDisableUpload.o
LIBS = ../lib/libInterCommon.a ../external/bin/libarclib${OSBITS}.a
ifeq ($(CLIENT), yes)
PROG_NAME = $(PROG_NAME_C)
OBJ = Client.o
LIBS =
endif
############################
all:$(APP)
#rm -f main.o
sync
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
test: $(OBJ)
$(CC) $(LFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
$(PROG_NAME): $(OBJ)
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
tael: $(OBJ) SmsSender.o
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
client:
$(MAKE) CLIENT="yes"
clean:
-rm -f *.o core *.out *.log
-rm -f $(APP)
sync
install : $(APP)
-cp $(APP) $(INSTALL_BIN)/$(APP)
sync
# End of Makefile
+256
View File
@@ -0,0 +1,256 @@
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "SmsSender.h"
#include <iterator>
#define DEFAULT_BUFFER_SIZE 9216
#define MaxSizeOfTRxBuffer 1024
string CSmsSender::RemoveBlankSpace(const char* pszData, size_t nLength)
{
char * szTemp = NULL;
string strReturn;
const char * src;
char * dest;
szTemp = (char*) ::malloc(sizeof(char) * nLength +1);
::memset(szTemp, 0 , sizeof(char)*nLength +1);
src = pszData;
dest = szTemp;
if( pszData == NULL )
{
strReturn.clear();
return strReturn;
}
if( *src == '\0' )
{
strReturn = src;
return strReturn;
}
// start with 2nd position
src++;
while ( src <= (pszData + nLength) && *(src-1) != '\0' )
{
if( *(src-1) == ' ' && *(src) == ' ' )
{ // 연속된 공백이 발견되면, 스킵한다.
src++;
continue;
}
*dest = *(src-1);
src++;
dest++;
}
// 종료표기
dest++;
*(dest) = '\0';
strReturn = szTemp;
if (szTemp != NULL)
{
free(szTemp);
szTemp = NULL;
}
return strReturn;
}
char hexchars[] = "0123456789ABCDEF";
string CSmsSender::PostDataEncode(const char *pszCommand, size_t length)
{
int i;
char tmpBuffer[MaxSizeOfTRxBuffer];
string strReturn;
if( pszCommand == NULL )
{
strReturn.clear();
return strReturn;
}
::memset(tmpBuffer, 0 , MaxSizeOfTRxBuffer);
i = 0;
while( *pszCommand != '\0' )
{
if( *pszCommand == ' ' )
{ // ' ' => '+'
tmpBuffer[i++] = '+';
pszCommand++;
}
else if(*pszCommand == '%')
{ // % => %%
tmpBuffer[i++] = '%';
tmpBuffer[i++] = '%';
pszCommand++;
}
else if( (*pszCommand < '0' && *pszCommand != '-' && *pszCommand != '.' )
|| (*pszCommand < 'A' && *pszCommand > '9' )
|| (*pszCommand > 'Z' && *pszCommand < 'a' && *pszCommand != '_' )
|| (*pszCommand > 'z' ) )
{
tmpBuffer[i++] = '%';
tmpBuffer[i++] = hexchars[(unsigned char)*pszCommand >> 4];
tmpBuffer[i++] = hexchars[(unsigned char)*pszCommand & 15];
pszCommand++;
}
else
{
tmpBuffer[i++] = *pszCommand++;
}
}
tmpBuffer[i] = '\0';
strReturn = tmpBuffer;
return strReturn;
}
CSmsSender::CSmsSender(const std::string& szHost, const int nPort, const std::string& szPath)
: CBaseSocket( SOCKET_NOT_VALID), m_szHost(szHost), m_nPort(nPort), m_szPath(szPath)
{
// 생성자
}
CSmsSender::~CSmsSender()
{
// 소멸자에 BaseSocket의 명시적 Close 처리를 한다.
Close();
}
bool CSmsSender::Init(void)
{
bool bRet = false;
// 데이터 체크
if( m_szHost.empty() || m_nPort < 0 || m_szPath.empty() )
{
LOG(LERR, "Invalid Parameter.");
return false;
}
return true;
}
bool CSmsSender::SendToWebServ(const string& pszHost, const string& pszTime, const string& pszMsg)
{
string szHost;
string szTime;
string szMsg;
char szSndBuffer[DEFAULT_BUFFER_SIZE];
char szRcvBuffer[DEFAULT_BUFFER_SIZE];
bool bRet = false;
int nRet = 0;
if( pszHost.empty() || pszMsg.empty() || pszTime.empty() )
{
LOG(LERR, "Invalid Parameter.");
Close();
return false;
}
// Connect
bRet = Connect(m_szHost, m_nPort);
if( bRet == false )
{
LOG(LERR, "Socket Connect Error.[%s:%d]", m_szHost.c_str(), m_nPort);
return false;
}
if( IsValidSocket() == false )
{
LOG(LERR, "Invalid Socket.");
Close();
return false;
}
::bzero(szSndBuffer, DEFAULT_BUFFER_SIZE);
::bzero(szRcvBuffer, DEFAULT_BUFFER_SIZE);
szHost = PostDataEncode(pszHost.c_str(), pszHost.size());
szTime = PostDataEncode(pszTime.c_str(), pszTime.size());
szMsg = RemoveBlankSpace(pszMsg.c_str(), pszMsg.size());
LOG(LDBG, "SMSMsg = [%s]", szMsg.c_str());
szMsg = PostDataEncode(szMsg.c_str(), szMsg.size());
// CHG 2019-09-16 huibong HTTP 관련 줄바꿈문자 LF->CR+LF 변경 (#32794)
// - CVE-2016-8743 이슈에 따라 Apache 2.2.32 버전부터 HTTP header 상에서
// - 줄바꿈문자가 CR+LF 가 아닌 경우 HTTP 400 응답 발생
// - 이를 해결하기 위해 기존 줄바꿈 문자 \n -> \r\n 으로 변경처리한다.
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "GET %s?host=%s&time=%s&msg=%s HTTP/1.0\r\n"\
"Content-Type: text/plain\r\n"\
"User-Agent: Arcmond\r\n"\
"Host: %s\r\n"\
"Connection: close\r\n"\
"Cache-Control: no-cache\r\n\r\n"
,m_szPath.c_str(), szHost.c_str(), szTime.c_str(), szMsg.c_str() ,m_szHost.c_str());
//DEBUG_LOG("%s", szSndBuffer);
//요청 전송 시작
nRet = WriteN(&szSndBuffer, ::strlen(szSndBuffer)+1);
// MAX_SEND_RETRY_COUNT 회수만큼 재시도 후 실패처리된다.
if( nRet == 0 )
{
LOG(LERR, "write socket closed.");
Close();
return false;
}
else if( nRet == -1 )
{
LOG(LERR, "write socket error.(%s)",strerror(errno));
Close();
return false;
}
// 응답 결과 받기.
nRet = ReadNTimeout(szRcvBuffer, DEFAULT_BUFFER_SIZE);
if( nRet == 0 )
{
// Remain이 0일 경우가 모두 받은 상황인데, 그것을 알 수 없다면,
// Ret==0일 때가 다 준 상황으로 판단해야 하지 않을까? 그렇다면 에러가 아니다.
LOG(LDBG, "read socket closed.");
}
else if( nRet == -1 )
{ // 단순 소켓 에러.
LOG(LERR, "read socket error.(%s)",strerror(errno));
Close();
return false;
}
else if( nRet == -2 )
{ // 타임아웃.
LOG(LERR, "read socket timed out.");
Close();
return false;
}
// 정상 결과는 아래와 같은 형태이다.
//----------------------------------------------------------------
// HTTP/1.1 200 OK
// Date: Thu, 10 Jun 2010 03:59:23 GMT
// Server: Apache/2.0.55 (Unix) DAV/2 PHP/5.2.1
// X-Powered-By: PHP/5.2.1
// Content-Length: 87
// Connection: close
// Content-Type: text/html; charset=EUC-KR
//
// [RAID:qcrts4.ktsh.co.kr]::2010-07-09 12:59:19:Controller#1: SW API Interface API Log In
//----------------------------------------------------------------
// 첫번째 라인만 출력하기 위해서 \n을 \0으로 바꾸고 출력한다.
char* pEnd = strchr(szRcvBuffer, '\n');
*pEnd = '\0';
LOG(LINF, "Result:%s", szRcvBuffer);
// Close()는 return값이 없음.
Close();
return true;
}
+59
View File
@@ -0,0 +1,59 @@
/***************************************************************************
SMS Sender Class
-----------------------------------------
begin : 2010/05/19
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 __SMS_SENDER__
#define __SMS_SENDER__
#include <pthread.h>
#include <string>
#include "Logger.h"
#include "BaseSocket.h"
using namespace std;
/// @brief CSmsSender
/// SmsSender는 지정된 포멧에 따라 php 웹 페이지를 호출한다.
///
class CSmsSender : public CBaseSocket
{
public:
/// @brief 생성자
/// @param [in] szHost SMS 전송 장비 호스트
/// @param [in] nPort SMS 전송 장비 접근 Port
/// @param [in] szPath SMS 전송 기능이 구현된 PHP 파일명.
CSmsSender(const string& szHost, const int nPort, const string& szPath);
~CSmsSender();
/// @brief Init 함수 클래스 환경이 정상적인지를 검사한다.
/// @return 성공: true, 실패: false
bool Init();
/// @brief PHP Web페이지를 통해 SMS발송 요청을 수행한다.
/// @return 성공: true, 실패: false
bool CallWebPage();
bool SendToWebServ(const string& pszHost, const string& pszTime, const string& pszMsg);
private:
// 로깅 파일
string PostDataEncode(const char *pszCommand, size_t length);
string RemoveBlankSpace(const char* pszData, size_t nLength);
string m_szHost;
int m_nPort;
string m_szPath;
string m_szMessage;
string m_szGroupId;
};
#endif // __SMS_SENDER__
+321
View File
@@ -0,0 +1,321 @@
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "UdpListener.h"
#define DEFAULT_BUFFER_SIZE 9216
#define MaxSizeOfTID 52
#define MaxSizeOfIssuer 128
#define MaxSizeOfSID 128
#define MaxSizeOfRCID 32
int CUdpListener::SendMsg(char * szSndBuffer,int size, struct sockaddr_in * cliaddr, socklen_t nAddrSize)
{
int SndBlockSize = 8196;
char szLineBuffer[SndBlockSize];
int nLeft = size;
char * pTmp = szSndBuffer;
int nWrite = 0;
do
{
int offset = 0;
::memset(szLineBuffer, 0, SndBlockSize);
if( nLeft < SndBlockSize )
SndBlockSize = nLeft;
while( offset < SndBlockSize )
szLineBuffer[offset++] = *pTmp++;
szLineBuffer[offset] = '\0';
//DEBUG_LOG("LINE : [%s]", szLineBuffer);
nWrite = ::sendto(m_nSocket, szLineBuffer, offset + 1, 0, (struct sockaddr *)cliaddr, nAddrSize);
if(nWrite < 0)
{ // error
LOG(LERR, "sendto socket(%d) error (%s)", m_nSocket, strerror(errno));
break;
}
else if(nWrite == 0)
{ // socket closed
break;
}
else
{
LOG(LDBG, "SEND MESSAGE %d, %d, %s", nWrite, offset+1, szLineBuffer);
}
nLeft -= nWrite;
} while ( nLeft > 0 );
return 0;
}
/// @brief 클라이언트로 부터 받아온 스트링 프로토콜을 정수 프로토콜로 변환한다.
/// @param [in] szProtocol 클라이언트로부터 전송받은 스트링 프로토콜.
/// @return 성공: 양의 정수의 프로토콜 값. 실패: -1
int CUdpListener::ParsingPacket(const char * szProtocol)
{
int nRet = -1;
if( szProtocol == NULL )
{
LOG(LERR, "Invalid Parameter");
return -1;
}
// 구버전 프로토콜을 유지한다.
if(strcmp(szProtocol, "I'M YOUR FATHER. BASTARD !") == 0)
{
LOG(LDBG, "-------- (OLD)CMD_EVENT_INFO_ONE Called!-----------");
nRet = CMD_EVENT_INFO_ONE;
}
else if(strcmp(szProtocol, "I'M YOUR GOD. BASTARD !") == 0)
{
LOG(LDBG, "-------- (OLD)CMD_EVENT_INFO_ALL Called! ---------");
nRet = CMD_EVENT_INFO_ALL;
}
else if(strcmp(szProtocol, "EVENT:INFO:ONE") == 0)
{
LOG(LDBG, "-------- CMD_EVENT_INFO_ONE Called!-----------");
nRet = CMD_EVENT_INFO_ONE;
}
else if(strcmp(szProtocol, "EVENT:INFO:ALL") == 0)
{
LOG(LDBG, "-------- CMD_EVENT_INFO_ALL Called! ---------");
nRet = CMD_EVENT_INFO_ALL;
}
// 프로토콜을 추가하려면 여기에 아래의 형태로 추가한다.
// else if(strcmp(szProtocol, "String...........") == 0)
// {
// nRet = CMD_XXXXXXXXX;
// }
else // Invalid Protocol
{
nRet = CMD_UDP_ERROR;
}
return nRet;
}
CUdpListener::CUdpListener(CEventDataManager* pEventDataManager)
: m_pEventDataManager( pEventDataManager )
{
m_nSocket = -1;
LOG(LDBG, "Constructor has been called.");
}
CUdpListener::~CUdpListener()
{
if ( m_nSocket != -1)
{
::close(m_nSocket);
m_nSocket = -1;
}
pthread_cancel(m_threadHandle);
}
bool CUdpListener::Init(int nPort)
{
LOG(LDBG, "Initializer has been called.");
int fRet = 0;
struct sockaddr_in SocAddr;
int nVal=1;
if(m_pEventDataManager == NULL )
{
LOG(LERR, "Invalid Object.");
return false;
}
if( nPort <= 0 )
{
LOG(LERR, "Invalid Parameter. Port=%d", nPort);
return false;
}
SocAddr.sin_family = AF_INET;
SocAddr.sin_port = htons(nPort);
SocAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// UDP 소켓 생성.
m_nSocket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (m_nSocket < 0)
{
LOG(LERR, "Socket Create: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
if (setsockopt(m_nSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&nVal, sizeof(int)) < 0)
{
LOG(LERR, "setsockopt(SO_REUSEADDR) failed.");
return false;
}
// UDP 소켓 바인드.
fRet = ::bind(m_nSocket, (struct sockaddr *)&SocAddr, sizeof(SocAddr));
if (fRet != 0)
{
LOG(LERR, "Socket Bind: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Initializer has been succeed.");
return true;
}
///@brief 이 함수에서 UDP 통신을 receive 한다.
void CUdpListener::Execute()
{
char szRcvBuffer[DEFAULT_BUFFER_SIZE];
char szSndBuffer[DEFAULT_BUFFER_SIZE];
int nRead = 0;
struct sockaddr_in cliaddr;
int addr_len = sizeof(cliaddr);
int bMode = 0;
int nRet = -1;
bool bRet = false;
string szTmp;
::memset(szRcvBuffer, 0, DEFAULT_BUFFER_SIZE);
::memset(szSndBuffer, 0, DEFAULT_BUFFER_SIZE);
//DEBUG_LOG("DEBUG: %d , %lu %lu, %lu", m_nSocket, szRcvBuffer, &cliaddr, &addr_len);
nRead = ::recvfrom(m_nSocket, (char *)&szRcvBuffer, (unsigned int)DEFAULT_BUFFER_SIZE, 0, (struct sockaddr *)&cliaddr, (socklen_t *)&addr_len);
if ( nRead <= 0 )
{
LOG(LERR, "recvfrom() error. %s.",strerror(errno));
return;
}
LOG(LDBG, "Request Buffer = %s", szRcvBuffer);
LOG(LDBG, "From = %s", inet_ntoa(cliaddr.sin_addr));
bMode = ParsingPacket(szRcvBuffer);
switch (bMode)
{
case CMD_EVENT_INFO_ONE:
{
CEventData resData;
nRet = m_pEventDataManager->GetLatestData(resData);
if ( nRet == -1 )
{
LOG(LERR, "GeLatestData() failed.");
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "1:%ld:Initializing Now.", ::time(NULL));
} else
{
if( nRet == 0 )
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "%d:%ld:%s", nRet,::time(NULL), resData.m_szEventData.c_str());
else
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "%d:%ld:%s", nRet,::time(NULL), resData.m_szEventData.c_str());
}
// 클라이언트 메시지 송신
SendMsg((char*)szSndBuffer, strlen(szSndBuffer),&cliaddr, (socklen_t) sizeof(cliaddr));
LOG(LDBG, "SEND MESSAGE %s.", szSndBuffer);
}
break;
case CMD_EVENT_INFO_ALL:
{
list<CEventData> listRet;
listRet.clear();
bRet = m_pEventDataManager->GetAllData(listRet);
if( nRet == false || listRet.empty() )
{
LOG(LERR, "GetAllData() failed.");
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "%d:%ld:No EVENT IS FOUND.", 1,(long)::time(NULL));
} else
{
// 2013-10-17
// 기존에는 모든 메세지를 보냈으나, sms메세지를 만들어주는 web page에서 처리가안되는것을 확인했다.
// 이에 따라 최근 100개 메세지를 전송하는 것으로 처리한다.
//for (list<CEventData>::iterator it = listRet.begin(); it != listRet.end(); it++)
int nCount = 0;
for (list<CEventData>::reverse_iterator it = listRet.rbegin(); it != listRet.rend(); it++)
{
// 2016.01.22 dadamin
// 96 => 1024 : buffer overflow 발생하여 메세지 전송 실패 발생하여 변경함
char timeBuf[1024] = {0};
tm* ptm = localtime(&it->m_evtTime);
::sprintf(timeBuf, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n",
ptm->tm_year + 1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec,
it->m_szEventData.c_str());
szTmp += timeBuf;
nCount++;
if( nCount >= 100 )
{
break;
}
// upd send size limit
if(szTmp.length() > 1100 ) {
break;
}
}
// upd send size limit
::snprintf(szSndBuffer, 1400, "%d:%ld:%s", 1,(long)::time(NULL) , szTmp.c_str());
}
SendMsg((char*)szSndBuffer, strlen(szSndBuffer),&cliaddr, (socklen_t) sizeof(cliaddr));
LOG(LDBG, "SEND MESSAGE %s.", szSndBuffer);
}
break;
default:
LOG(LDBG, "----------------- INVALID COMMAND REQUEST!!! ----------------------------------");
LOG(LERR, "Invalid Protocol.");
::memset(szSndBuffer, 0, DEFAULT_BUFFER_SIZE);
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "1:%ld:Invalid Arguments!", (long)::time(NULL));
LOG(LDBG, "SENDING Buffer = [%s]", szSndBuffer);
//::sendto(m_nSocket, szSndBuffer, strlen(szSndBuffer), 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
SendMsg((char*)szSndBuffer, strlen(szSndBuffer),&cliaddr, (socklen_t) sizeof(cliaddr));
// TODO: error check
return;
break;
}//~switch (bMode)
}
void* CUdpListener::EntryPoint(void* arg)
{
CUdpListener* pObject = reinterpret_cast<CUdpListener *>(arg);
if( pObject == NULL )
{
// static Function이기 때문에 로깅할 수 없다...
//ERROR_LOG("Critical Memory Error, Invalid Object.");
//exit(EXIT_FAILURE);
}
pthread_detach( pthread_self() );
while(1)
{
pthread_testcancel();
pObject->Execute();
pthread_testcancel();
}
// pthread_exit();
return (void *)NULL;
}
bool CUdpListener::Start()
{
int nRet = ::pthread_create(&m_threadHandle, 0, CUdpListener::EntryPoint, this);
if( nRet != 0 )
{
LOG(LERR, "Thread create failed: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Thread create succeed.");
sleep(0);
return true;
}
+76
View File
@@ -0,0 +1,76 @@
/***************************************************************************
UDP Listener Class
-----------------------------------------
begin : 2010/05/17
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 __UDP_LISTENER__
#define __UDP_LISTENER__
#include <pthread.h>
#include <string>
#include "Logger.h"
#include "EventDataManager.h"
using namespace std;
/// @brief Protocols
#define CMD_UDP_BASE 1000
#define CMD_UDP_ERROR CMD_UDP_BASE
#define CMD_EVENT_INFO_ONE ( CMD_UDP_BASE + 101 )
#define CMD_EVENT_INFO_ALL ( CMD_UDP_BASE + 102 )
/// @brief CUdpListener
/// UdpListener 는 client에서 udp 요청되는 패킷을 수신해서 관리하게 되며,
/// raid 정보 조회 후, 결과를 전송한다.
/// 내부적으로 Thread를 사용하고있다.
class CUdpListener
{
public:
/// @brief 생성자
/// @param [in] pEventManager CEventManager 객체
CUdpListener(CEventDataManager* pEventDataManager);
~CUdpListener();
/// @brief Init 함수 클래스 환경이 정상적인지를 검사한다.
/// @param [in] nPort UDP listen port 번호.
/// @return 성공: true, 실패: false
bool Init(int nPort);
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공: true, 실패: false
bool Start();
private:
// 이벤트 저장 객체
CEventDataManager* m_pEventDataManager;
// 쓰레드 핸들
pthread_t m_threadHandle;
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
int m_nSocket;
// 해당 함수의 내용은 수정하지 말것.
void Execute();
/// @brief 클라이언트로 부터 받아온 스트링 프로토콜을 정수 프로토콜로 변환한다.
/// @param [in] szProtocol 클라이언트로부터 전송받은 스트링 프로토콜.
/// @return 성공: 양의 정수의 프로토콜 값. 실패: -1
int ParsingPacket(const char * szProtocol);
int SendMsg(char * szSndBuffer,int size, struct sockaddr_in * cliaddr, socklen_t nAddrSize);
CEventData m_evtData;
};
#endif // __UDP_LISTENER__
+70
View File
@@ -0,0 +1,70 @@
/***************************************************************************
fhs_raidmond Header ( fhs_raidmond.h )
-----------------------------------------
begin : 2010/03/09
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 __FHS_RAIDMOND_GLOBAL_VALUE_H__
#define __FHS_RAIDMOND_GLOBAL_VALUE_H__
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <iostream>
using namespace std;
#include "Logger.h"
struct st_config
{
// Common Part
std::string szLogDir;
int nLogLevel;
// fhs_raidmond Part
int nCheckTerm;
int nReportPort;
int nEventLevel;
std::string szSMSHost;
int nSMSPort;
std::string szSMSSendfile;
// »ý¼ºÀÚ
st_config()
{
nLogLevel = 0;
nCheckTerm = 0;
nReportPort = 0;
nEventLevel = 0;
nSMSPort = 0;
}
};
#ifdef __cplusplus
extern "C" {
#endif
/// @brief Global config object.
extern struct st_config g_envConfig;
#ifdef __cplusplus
}
#endif
#endif /* __FHS_RAIDMOND_GLOBAL_VALUE_H__ */
+349
View File
@@ -0,0 +1,349 @@
#include "fhs_raidmond.h"
#include "GetConfig.h"
#include "Child.h"
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
/// config object initialize
struct st_config g_envConfig;
/// daemon flag
static bool _isdaemon = true;
/// @brief Program version 출력 함수.
/// @return void
static void ShowVersion(void)
{
cerr << "[info] " << PROG_NAME << " Version :" << PROG_VERSION << endl;
}
/// @brief Program version 사용 방법 출력 함수.
/// @return void
static void ShowUsages(void)
{
ShowVersion();
cerr << "usage: " << PROG_NAME << " [-vhcD]" << endl;
cerr << "options are: " << endl;
cerr << "-v : print current version" << endl;
cerr << "-c <path> : Log Diretory" << endl;
cerr << "-D : running console mode" << endl;
cerr << "-h : help " << endl;
}
/// @brief Child 프로세스 생성(fork) 함수
/// @return void
static void MakeChild(void)
{
pid_t processId;
// Child 프로세스 fork
processId = fork();
if( processId < 0 ) // Fork fail
{
int errorNum = errno;
LOG(LERR, "Child Process create failed. [%d][%s]", errorNum, strerror(errorNum) );
return;
}
else if( processId == 0 ) // Parent Process => Child Process
{
// Child Process Main 함수 호출 및 종료처리.
ChildMain();
exit( EXIT_SUCCESS );
}
else
{
// Parent Process => Logging
_LOG(LNOT, "Child Process create success. PID[%d]" , processId);
// 잠시 대기
usleep(100000);
}
}
/// @brief Parent Process 에서 child Process 가 종료된 경우 시그널 처리를 위한 함수
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void sigchld_hdl( int nSignalNumber )
{
pid_t killPid;
int nKillStatus;
while( ( killPid = waitpid( -1, &nKillStatus, WNOHANG ) ) > 0 )
{
// 자식 프로세스가 Signal 에 의해 종료되었는지 검사.
if( WIFSIGNALED( nKillStatus ) )
{
LOG(LWAR, "Child process[%d] killed by signal[%d]", killPid, WTERMSIG( nKillStatus ) );
}
else
{
LOG(LWAR, "Child process[%d] killed. Not signal", killPid );
// Child 프로세스가 EXIT_FAILURE 반환 ( 초기화 실패시 )
// 해당 내역을 화면 및 로그 상에 출력하고
// 자식 프로세스를 재생성 처리하지 않는다.
if( WIFEXITED( nKillStatus ) )
{
if( WEXITSTATUS( nKillStatus ) == EXIT_FAILURE )
{
LOG(LERR, "Child Process[%d] initilaize failed.", killPid );
LOG(LERR, "Parent Process[%d] exit by Child. Good Bye..", getpid());
cerr << "[error] " << PROG_NAME << ": Process exit by Child process initialize failed. check log file." << endl;
usleep(500000);
exit( EXIT_FAILURE );
}
}
}
// Child Process 재생성 처리.
MakeChild();
}
// 오류 발생시 해당 내역 로깅
if( killPid < 0 )
{
int errorNum = errno;
LOG(LERR, "Parent process error: SIG_CHLD receive but waitpid return error[%d][%s]", errorNum, strerror(errorNum));
}
return;
}
/// @brief Parent Process 종료 Signal 을 전달받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigTermParent( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
LOG(LWAR, "Parent Process[%d] exit job start by user signal [SIGTERM]", getpid() );
}
else
{
LOG(LWAR, "Parent Process[%d] exit job start by abnormal signal [%d]", getpid(), nSignalNumber );
}
// Process 종료관련 작업 추가
LOG(LWAR, "Parent Process[%d] exit job end. Good Bye..", getpid());
// KILL - Child
kill(0, SIGTERM);
// waitpid
while(waitpid(-1, NULL, WNOHANG) > 0);
usleep(500000);
exit( EXIT_SUCCESS );
}
/// @brief Parent Process 에서 Core 생성 관련 Signal 을 받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigCoreParent( int nSignalNumber )
{
LOG(LERR, "Parent Process[%d] abnoraml exit. Check Core file. Receive signal [%d]", getpid(), nSignalNumber );
//LOG(LERR, "Core file path : [%s/%s.core]", g_envConfig.szLogDir.c_str(), PROG_NAME );
// Process 종료관련 작업 추가
// Log Directory 상에 Core 파일 생성처리.
chdir( g_envConfig.szLogDir.c_str() );
signal( nSignalNumber, SIG_DFL );
// Core dump 생성을 위한 신호 발생처리.=> ?
raise( nSignalNumber );
}
/// @brief Parent 프로세스 signal 처리 설정을 위한 함수
/// @return void
static void SetSignalParent()
{
sigset_t set;
struct sigaction act;
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
memset( &act, 0x00, sizeof(act) );
sigfillset( &act.sa_mask );
/* 무시할 신호 목록 */
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL); /* 파이프 디스크립터 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP , &act, NULL); /* Process를 기동시킨 관리자의 로그아웃시 발생 시그널 */
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
if(_isdaemon)
{
sigaction( SIGINT , &act, NULL); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
}
else
{
act.sa_handler = SigTermParent;
sigaction( SIGINT, &act, NULL); /* ^C 키를 누른 경우 받는 신호 => kill -TERM 과 동일한 처리함 */
}
// Child Process 종료에 대한 처리기 설정.
act.sa_handler = sigchld_hdl;
sigaction( SIGCHLD, &act, NULL);
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SigTermParent;
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
/* Core 관련 signal 처리 : 오류 처리 및 Debug(core dump) 목적 */
// dadamin : 팀 기준 적용
//act.sa_handler = SigCoreParent;
//sigaction( SIGILL , &act, NULL); /* Illegal instruction */
//sigaction( SIGFPE , &act, NULL); /* Erroneout arithmetic operation */
//sigaction( SIGBUS , &act, NULL); /* Access to undefined portion of a memory object */
//sigaction( SIGSEGV, &act, NULL); /* Invalid memory reference */
//sigaction( SIGSYS , &act, NULL); /* Bad System Call */
//sigaction( SIGXCPU, &act, NULL); /* CPU-time limit exceeded */
//sigaction( SIGXFSZ, &act, NULL); /* File-size limit exceeded */
sigemptyset(&set); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask(SIG_SETMASK, &set, NULL);
}
// daemon 생성 함수
static bool daemon_create(bool bcreate)
{
// set parent signal
SetSignalParent();
// set mask
umask(0);
// daemon
if(bcreate && daemon(false, false) != 0 ) // after this line, parent's pid will be changed.
{
cerr << "[error] Daemonize Failed.(errno : " << errno << ")" << endl;
return false;
}
return true;
}
/// @brief std 상에 trim 함수가 없어서 직접 구현 아니면 boost/algorithm/string.hpp 상의 boost::trim 함수 사용
/// @return void
static void 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 );
}
/// @brief 현재 Process가 기동중인지 여부를 판단하기 위한 함수( 프로세스 중복 실행 체크)
/// @return 이미 해당 프로세스가 기동 중인 경우 true 반환, 그렇지 않으면 false 반환.
static bool IsCurrentProcessRun()
{
char tempBuffer[512];
FILE * fd = NULL;
bool bRun = false;
snprintf( tempBuffer, sizeof(tempBuffer), "pgrep -x %s | sort", PROG_NAME );
fd = popen( tempBuffer, "r" );
if( fd == NULL )
{
cerr << "[error] 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);
if( atoi( tempPid.c_str() ) != getpid() )
{
cout << "[info] Process duplication found. pid[" << atoi( tempPid.c_str() ) << "]" << endl;
bRun = true;
break;
}
}
pclose( fd );
return bRun;
}
}
// main function
int main( int argc, char * argv[] )
{
string cofigpath = DEFAULT_CONFIG_FILE;
// parse command line arguments
int o;
while ((o = getopt(argc, argv, "vhDc:")) >= 0)
{
switch (o)
{
case 'h': // help
ShowUsages();
return EXIT_SUCCESS;
break;
case 'v': // version
ShowVersion();
return EXIT_SUCCESS;
break;
case 'D': // consol mode
_isdaemon = false;
cerr << "Runnig Console mode." << endl;
break;
case 'c': // config file
cofigpath = optarg;
break;
}
}
// 프로그램 중복 실행 체크
if( IsCurrentProcessRun() == true )
{
cerr << "[warning] Process[" << PROG_NAME << "] is already running...." << endl;
return EXIT_FAILURE;
}
// load config
string szErrorMessage;
if(!GetConfig( cofigpath, g_envConfig, szErrorMessage ) )
{
cerr << "[error] Process[" << PROG_NAME << "]: " << szErrorMessage << endl;
return EXIT_FAILURE;
}
// init log
if( CLogger::Init( PROG_NAME, g_envConfig.szLogDir.c_str(), g_envConfig.nLogLevel ) == false )
{
cerr << "[error] Process[" << PROG_NAME << "]: Log init failed." << endl;
return EXIT_FAILURE;
}
// Global log object set
// daemon create
if(!daemon_create(_isdaemon))
return EXIT_FAILURE;
// Process 기동 관련 정보 로깅
_LOG(LINF, "***********************************************************" );
_LOG(LINF, " %s (FHS RAID Monitor Daemon) Start. Version: %s", PROG_NAME, PROG_VERSION );
_LOG(LINF, "***********************************************************" );
_LOG(LINF, "Config file : %s", cofigpath.c_str() );
_LOG(LINF, "Log Path : %s/%s", g_envConfig.szLogDir.c_str(), PROG_NAME );
_LOG(LINF, "Logging Level : %d", g_envConfig.nLogLevel );
_LOG(LINF, "health check term : %d", g_envConfig.nCheckTerm );
_LOG(LINF, "report thread port : %d", g_envConfig.nReportPort );
_LOG(LINF, "event level : %d", g_envConfig.nEventLevel );
_LOG(LINF, "sms send host : %s", g_envConfig.szSMSHost.c_str() );
_LOG(LINF, "sms send port : %d", g_envConfig.nSMSPort);
_LOG(LINF, "sms send file : %s", g_envConfig.szSMSSendfile.c_str() );
_LOG(LINF, "***********************************************************" );
// fork child
MakeChild();
// set process title
#if defined(__FreeBSD__)
setproctitle( "Parent [monitor Child process]" );
#endif
// wait
while( 1 )
{
pause();
}
return EXIT_SUCCESS;
}