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
+587
View File
@@ -0,0 +1,587 @@
Revision 1501
-------------------
수정일 : 2020-07-20
수정자 : 유희곤
- CHG: fimngd 의 internal cache 생성을 위한 fd 감시 On/Off 항목 개선 (#33112)
- EXTRACT_FD_COUNT 설정에 따라 fd count 정보 추출 기능을 on/off 처리
- CHotContentInfoMap() 함수의 잘못된 변수 맵핑 버그 수정
Revision 1382
-------------------
수정일 : 2016-5-31
수정자 : 노경민
- CHG : 서비스 트래픽 통계 응답 기능 추가
- 통계 수신 서버 종료 시 일부 통계 누락 발생 경우를 방어하기 위해 추가됨
Revision 1342
-------------------
수정일 : 2016-4-5
수정자 : 노경민
- BUG : 네크워트 통계 프로세스 CPU 점유 문제
- 전송할 통계 없을 시 sleep 로직 누락으로 CPU 점유 상승함
Revision 1340
-------------------
수정일 : 2016-4-4
수정자 : 노경민
- BUG : 메세지큐 관련 비정상 종료
- thread safe 하지 못한 구조 때문임
- BUG : 설정한 메세지큐 개수만큼 생성되지 않음
- 시스템 한계 500이지만 130개만 생성됨
- 시스템 한계 만큼 생성될 수 있도록 생성함(프로세스 한계는 5000임)
- BUG : 비정상 종료 후 재생성 시 메세지큐 무한 생성
- 관련 클래스 clear되지 않는 객체 참조 때문임
- CHG : Hot Content 처리 로직 개선
- SystemV message queue pop 속도보다 Hot Content 처리 속도가 늦어 발생하는
메모리닉 같은 현상을 개선함
- BUG : 서비스 정보 갱신 프로세스 메모리 닉
- 서비스 별 수행 쿼리에 대한 clear 없이 쿼리 수행으로 메모리닉 발생함
- BUG : 네트워크 통계 누락 발생
- 타임 구간 체크 로직에서 누락 발생할 수 이는 구조였음
- BUG : 서비스 정보 갱신 누락 발생
- 타임 구간 체크 로직에서 누락 발생할 수 이는 구조였음
Revision 1331
-------------------
수정일 : 2016-1-21
수정자 : 노경민
- CHG : 정상 종료 시 자신의 상태를 OUT으로 설정함
- 서비스 모듈(HTTPD) 구동 시 종료 될 경우 이전 상태를 계속 사용하기 때문
이를 방지하기 위해서 추가함
- 비정상 종료(kill -9 or -KILL)에 대해서는 이 기능이 수행되지 않음
- 운영자의한 종료 방법은 매뉴얼로 절차화
- CHG : 불필요한 컬럼 참조 수정
- delete_yn 컬럼은 사용하지 않음
- CHG : 로그 수정
- 정확하지 않는 로그에 대해서 수정함
Revision 1328
-------------------
수정일 : 2016-1-19
수정자 : 노경민
- CHG : 다른 서비스에 대한 동일한 디렉토리 설정 시 무인증 설정되지 않음
- 내부 자료 구조에서 사용하는 key 중복으로 발생한 문제임
Revision 1257
-------------------
수정일 : 2015-10-06
수정자 : 김오종
- MOD : 로그 내용 정리
- 로그에 주요정보 포함되어 있어 조정 처리
- 로그에 소스 위치 정보 제외하여 로그용량을 줄임
- Account 상태정보 로깅 조정
Revision 1254, 1255
-------------------
수정일 : 2015-10-05
수정자 : 김오종
- BUG: RCDB와 비정상 연결종료 현상에 대한 예외처리
- Account, Anony 정보 갱신시 예외처리 버그 수정
- AccountUpdateThread.cpp, AnonyUpdateThread.cpp 소스 일부 수정처리
- ADD: 기존 서비스 중 삭제된 서비스에 대한 로깅 처리 추가
- Accout 정보 갱신시에 삭제된 서비스에 대한 로그 추가
Revision 1217
-------------------
수정일 : 2015-09-09
수정자 : 김오종
- CHG: Version 3.5 변경
- fimngd의 역할이 아래와 같이 크게 조정됨에 따라 버전을 변경한다.
- 기존 openda-listener의 shared memory 관련기능 통합
- rcts의 rc_mond 데몬과 연계하여 타FHS의 상태 정보를 sared memory에 갱신처리한다.
- rcts의 rc_sscd 데몬으로 트래픽 및 스토리지 통계 데이터를 전달 한다.
- account, 무인증 폴더 정보등을 RCDB로부터 가져와 shared memory에 업데이트 한다.
- 기존 fimngd의 기능인 internal cache 기능은 그대로 포함한다.
- 기존 fimngd의 기능인 log 정리 기능은 logmngd로 대체 하도록 한다.
- *주의* fdcnt.sh가 같이 배포되어야 한다.
Revision 1118
-------------------
수정일 : 2014-11-11
수정자 : 김오종
- CHG: RCDB 연결을 필요시마다 수행 하도록 처리
- 서비스 폴더 생성시 RCDB 조회 할 때 필요시마다 connect 처리
- CHG: log 오타 수정
- "Caceh Replication Request Queue" --> "Internal Cache Request Queue" 로 변경
Revision 1068
-------------------
수정일 : 2014-08-27
수정자 : 김오종
- BUG: rcdb 접속시 password 정보 누락
- password 정보 추가
Revision 1014
-------------------
수정일 : 2014-07-24
수정자 : 김오종
- DEL: 테스트 소스 제거
- 서비스 폴더 생성 테스트 소스 제거
Revision 1011
-------------------
수정일 : 2014-07-23
수정자 : 김오종
- CHG: revision 변경
Revision 1009
-------------------
수정일 : 2014-07-23
수정자 : 김오종
- CHG: 구동 주기 및 로그 메세지 변경
- ServicePathCreaterThread.cpp 내의 로그 메세지 조정
- 구동 주기를 3min 으로 조정
Revision 1007
-------------------
수정일 : 2014-07-22
수정자 : 김오종
- DEL: UDP 통신을 통한 Internal Cache 제거
- MsgCacheRequest.h MsgCacheRequest.cpp 제거
- DEL: Transfer Log 전송 기능 제거
- ServiceInfoUpdaterThread.h ServiceInfoUpdaterThread.cpp 제거
- TransferLogSender.h - TransferLogSender.cpp 제거
- 해당 기능과 연관된 config 파일의 관련항목 제거
- ADD: 서비스 개퉁 후 서비스 디렉토리 생성 기능 추가
- ServicePathCreaterThread.h ServicePathCreaterThread.cpp 추가
- CHG: TCP/IP 통신을 통한 Internal Cache 추가
- ./coponent/BaseSocket.h ./coponent/BaseSocket.cpp 추가
- CacheGeneratorTrhead 클래스 수정
- rc_rmcd에 소켓연결을 위한 host,port 정보 추가
- CHG: 아파치 로그 추가 전송 및 로그파일 삭제 기능 변경
- 기존 아파치 로그전송은 작업일 하루 전만 전송 후 제거
- 작업일 최근 열흘을 대상으로 미전송 로그 전송 처리
- 아파치 로그 최근 열흘이전의 로그파일에 대한 삭제 처리
- LogFileCleaner, ApacheLogSender 클래스 변경
- CHG: 버전 변경에 따른 버전 정보 조정
- Makefile 상의 버전 정보를 3.3.0.x -> 3.4.0.x 로 변경
Revision 0963
-------------------
수정일 : 2014-03-10
수정자 : 김오종
- DEL: Internal Cache 발현 조건 중 Disk Busy 상황을 사용하지 않기로 결정됨에 따라 관련기능을 제거 처리 함
- geom, devstat 라이브러리 제거
- DiskIOstatCollector.h DiskIOstatCollector.cpp 파일 삭제
- work.cpp, HotContentDetectorThread.cpp 및 ProcessStatus class 부분 수정
- CHG: FreeBSD 10.X까지 지원하기 위해서 컴파일러 optimizer 옵션 조절
- Makefile 상에서 -o option 레벨을 3에서 0(zero)로 변경 처리함
Revision 0839
-------------------
수정일 : 2012-11-15
수정자 : 노경민
- BUG: 메모리 급증 현상 완화
- FHS 부하가 발생 시 fstat 응답 지연 확인되었으며, 이로 인해서 메모리 증가 확인됨
- 기존 불필요한 로직 제거 및 fstat 실행 최적화
- BUG: 아파치 로그 전송 중 비정상 종료 현상
- 구동 시간 대에서 구동을 위한 sleep 시간을 구하는 로직에서 제로 나누는 경우 때문임
- CHG: 로그 객체 가변 인자 체크 기능 추가
- 일부 로그 중 인자 누락으로 해당 부분을 체크하기 위해서 추가됨
- CHG: 로그 관련 컴파일 warning 제거
- 변경된 로그 객체로 검파일 시 발생한 warning 제거
- CHG: 브로드 캐스트 주소 획득 변경
- 주소 획득 시 NULL 리턴되는 경우 존재함(소켓 사용 후 close 호출하지 않아서 발생)
- 주소 획득 실패에 대한 로직 미흡했던 부분 변경함
- CHG: unlink() 함수에 대한 오류 처리 부분 수정
- unlink() 함수 리턴 값에 -1 일때 해당 에러가 출력되도록 수정함
- CHG: Hot Content 감지 디폴트 설정 변경
- FD_COUNT : 3 -> 10
- MIN_DISKIO_PERCENT : 50 -> 5
- CHG: 시스템 큐 Pop 로직 변경
- 시스템 큐에서 꺼낸 값을 바로 다운로드 큐에서 사용하던 구조를 변경함
- NEW: 주요 큐 사이즈 출력 기능 추가
- 다운로드 큐, 캐쉬 요청 큐, 로그 전성 큐를 매 2초마다 출력
- DEL: 코어 시그널 처리 로직 삭제
- 서비스 1팀 시그널 정책에 따른 로직 삭제
Revision 0755
-------------------
수정일 : 2012-05-03
수정자 : 김오종
- BUG: GTL 로 전송정보 전달시 tran_id 누락 현상
- TransferLogData.cpp 의 SetTranId() 수정
Revision 0731
-------------------
수정일 : 2012-04-05
수정자 : 김오종
- CHG: src/main.cpp 의 Daemon 생성 관련 코드 수정
- MakeDaemon() 함수상에 Daemon 생성 관련 stdin, stdout, stderr Close 처리 코드 추가 ( 원격 기동시 CTRL+C 처리 불편에 따른 수정)
Revision 0704
-------------------
수정일 : 2012-03-06
수정자 : 김오종
CHG: transfer_log_send_yn 정보 확인 주기 조정 6sec=>300sec 로 조정
- 신속성을 요하는 정보가 아니므로 RCDB의 부하를 줄이기 위한 조치.
CHG: ServiceInfoUpdaterThread 클래스 내의 RCDB 세션 관리방법 변경
- 본 클래스에서 RCDB 세션을 정상적일경우 재사용 할 수 있도록 변경 처리
- ServiceInfoUpdaterThread.cpp, ServiceInfoUpdaterThread.h 수정
Revision 0677
-------------------
수정일 : 2012-02-09
수정자 : 김오종
BUG: fimngd의 main.cpp 에 log객채 생성 파라메터 중 log path에 대한 인자값이 하드코딩되어있는 것이 확인 됨.
- main.cpp 의 소스 수정
추가 : 디버그 메세지 추가
- ProcessStatus.cpp 에 디버그 메세지 보강
Revision 0643
-------------------
수정일 : 2011-12-29
수정자 : 김오종
ADD: 신규 fimngd 소스를 등록한다. 아래 기능을 포함하고 있다.
fimngd : Hot Content 감지 및 복제처리 기능
rctl : opendav를 통한 외부 요청내역을 gtl로 실시간 전송하는 기능
log_rotator : httpd 의 access 로그와 error 로그를 로그백업 서버로 전송하는 기능.
데몬 형태가 아님 /etc/crontab 에 등록되어 구동.
FHS 내의 각 Application 의 로그 정리 기능을 신규로 포함 한다.
Revision 0641
-------------------
수정일 : 2011-12-29
수정자 : 김오종
DEL: 신규 fimngd를 등록하기 위한 사전작업으로 기존 fimngd 소스를 삭제 처리 함.
Revision 0556
-------------------
수정일 : 2011-05-30
수정자 : 장희준
CHG: fimngd.conf의 [COMMON] 섹션의 LOG_LEVEL 값만 사용하던 것을
[fimngd] 섹션의 LOG_LEVEL 값이 없는 경우에만 [COMMON] 세견의
LOG_LEVEL을 사용하도록 수정.
Revision 478
BUG : 메모리 누수 수정
아래 코드 중 root->firstChild->path = (char*) malloc( pathSize + 1 ); 에서 메모리 누수 발생.
root->firstChild->path != NULL 인 경우 root->firstChild->path의 메모리를 해제하도록 수정.
수정 전 :
OpenFileTreeNode*
COpenFileTree::GetHotContentTree( std::string path, unsigned int count )
{
.
.
/// 루트 노드의 child가 1이라는 말은 컨텐츠가 /user2/dav_storage 파티션에 있다는 말이다.
/// 이 경우 root->firstChild->path에는 /user2/dav_stroage 디렉토리내의
/// 어느 한 디렉토리의 이름만 가지게 되는데 이렇게 되면
/// /user2/dav_stroage 내의 모든 디렉토리에 대한 검색을 할 수 없게 된다.
/// 그래서, 이 경우는 root->firstChild->path = root->path로 설정함으로
/// /user2/dav_stroage 내의 모든 디렉토리에 대한 검색을 하도록 한다.
if( GetChildCount( root ) == 1 )
{
if( root->path != NULL )
{
int pathSize = strlen( root->path );
root->firstChild->path = (char*) malloc( pathSize + 1 ); --> 메모리 누수 발생
memset( root->firstChild->path, 0, pathSize + 1 );
strncpy( root->firstChild->path, root->path, pathSize );
}
}
return root;
}
수정 후 :
OpenFileTreeNode*
COpenFileTree::GetHotContentTree( std::string path, unsigned int count )
{
.
.
/// 루트 노드의 child가 1이라는 말은 컨텐츠가 /user2/dav_storage 파티션에 있다는 말이다.
/// 이 경우 root->firstChild->path에는 /user2/dav_stroage 디렉토리내의
/// 어느 한 디렉토리의 이름만 가지게 되는데 이렇게 되면
/// /user2/dav_stroage 내의 모든 디렉토리에 대한 검색을 할 수 없게 된다.
/// 그래서, 이 경우는 root->firstChild->path = root->path로 설정함으로
/// /user2/dav_stroage 내의 모든 디렉토리에 대한 검색을 하도록 한다.
if( GetChildCount( root ) == 1 )
{
if( root->firstChild == NULL )
{
TRACE( LOG_DEBUG, "end" );
return root;
}
if( root->path == NULL )
{
TRACE( LOG_DEBUG, "end" );
return root;
}
if( root->firstChild->path != NULL )
{
free( root->firstChild->path );
root->firstChild->path = NULL;
}
int pathSize = strlen( root->path );
root->firstChild->path = (char*) malloc( pathSize + 1 );
memset( root->firstChild->path, 0, pathSize + 1 );
strncpy( root->firstChild->path, root->path, pathSize );
}
return root;
}
Revision 476
CHG : fstat 결과에서 프로세스가 httpd인 것만 cache 요청 대상이 되게 하고
pid, fd, inode가 동일한 경우는 카운트를 증가 시키지 않도록 수정.
내부 테스트용으로 프로세스 httpd 외에 명령 인자로 특정 프로세스를 지정할 수 있게 수정.
: 변경 코드
- OpenFileTree.c
AddToOpenFileTree(), IsAllowedProcessName(), AddLeafNode()
typedef struct OPEN_FILE_TREE_NODE
BUG : 메모리 누수 수정
fstat.c의 free_devs()을 아래와 같이 수정
------- 기존 코드 ---------------------
free_devs()
{
if( devs == NULL )
{
return;
}
DEVS* d = devs;;
if( d != NULL )
{
free( d );
devs = NULL;
}
}
------- 수정 코드 ---------------------
free_devs()
{
if( devs == NULL )
{
return;
}
DEVS* next;
DEVS* d = devs;;
while( d != NULL )
{
next = d->next;
free( d );
d = next;
}
devs = NULL;
}
Revision 0462
-----------------------------
수정일 : 2010-12-28
수정자 : 장희준
Revision 461에서 수정일 및 수정자 정보가 빠져서 462로 다시 Revision 함.
Revision 0461
-------------------
수정일 : 2010-12-28
수정자 : 장희준
CHG: fhs.conf의 [fimngd] 섹션에 RCID 필드 추가
- rc_rmcd로 캐시 요청시 RCID 값을 전달하기 위해 추가 함.
CHG: fhs.conf의 [fimngd] 섹션에 FD_COUNT 필드 추가
- 기존에 소스 코드에 fix 되어 있던 값을 설정 파일에서 설정 하도록 하기 위함.
- fhs.conf FD_COUNT가 설정되지 않으면 소스 코드에서 기본 값으로 5를 사용 함.
CHG: fstat.h fstat.c에 대한 FreeBSD 32bit, 64bit 통합 작업.
- FreeBSD 64bit에서 fstat.c을 컴파일 하기 위해서는 Makefile에 __FREEBSD_64__을 define 해야 함.
CHG: fstat.h에 정의되어 있고 fstat.c에 구현되어 있던 리스트 자료구조 fs_list 제거
ADD: C++ 코드에서 OpenFileTreeNode을 사용하기 위한 래퍼 클래스 COpenFileTree 추가
ADD: 제거된 fs_list을 대체하는 트리 자료구조 OpenFileTreeNode을 TreeForFstat.h에 정의하고
TreeForFstat.c에 구현함으로 fstat.c와 자료구조를 분리 시킴.
CHG: 로깅 코드 변경
- 기존에는 로깅을 하는 모든 클래스는 생성자에서 Logger 객체의 포인터를 인자로 받아야 하고
.cpp 파일에 아래와 같은 로그 처리를 위한 매크로를 정의 해야 함.
예) #define CLASS_NAME "CCacheRequestManager"
#define DEBUG_LOG( format, ...) \
if(m_pLogger != NULL ) \
m_pLogger->Write( LOG_DEBUG,"[%s::%s()] " format, CLASS_NAME,__func__, ##__VA_ARGS__ )
- 변경된 로깅 코드에는 생성자에서 Logger 객체를 받지 않아도 되고 .cpp 파일에 매크로를 정의대신 Trace.h 추가 해야 함.
예) #include "Trace.h"
- 로깅 코드와 로그 형식 변경
: 기존
DEBUG_LOG("log string") ---> [2010-12-23 16:00:48] [DBG] [Parent_Process::main()] log string
: 변경
TRACE( LOG_DEBUG, "log string") ---> [2010-12-28 02:25:42] [DBG] log string [Parent_Process::main()]
_TRACE( LOG_DEBUG, "log string") ---> [2010-12-28 02:25:42] [DBG] log string
CHG: 설정 파일 처리 로직 변경
- 기존에는 설정 파일에 매핑되는 구조체 st_config를 fimngd.h에 정의하고 GetConfg.cpp에 C 코드 형태로
설정 파일의 값을 로딩하는 구조로 데이터와 구현이 분리되어 있음.
- C 코드 형태의 g_envConfig를 main.cpp에 정의해서 사용함.
- 변경 후에는 싱글톤 클래스 CFhsConfig를 추가함으로 전역 변수를 사용하는 불편함을 제거했음.
ADD: 로깅을 편리하게 하기 위해서 Logger 래퍼 싱글톤 클래스 Trace.h 추가
- Trace.h 추가로 전역 변수 g_Logger을 삭제하고 모든 클래스에서 멤버 변수 m_pLogger를 삭제하고 생성자에서 인자 Logger*도 삭제함.
CHG: 캐시 요청에 필요한 데이터 맵 관리를 기존에는 CCacheRequestManager가 담당했는데 이 역할을 CDataRequestMap 클래스로 이관하고
CCacheRequestManager가 수행하던 데이터 비교 역할을 CDataRequestInfo 클래스로 이관함.
ADD: CDataRequestMap 추가.
CCacheRequestManager가 직접 관리하던 CDataRequestInfo 맵의 역할을 분리하기 위해 추가된 클래스.
ADD: 캐시 요청 메시지 인코딩/디코딩 역할을 하는 CMsgCacheRequest 추가
Revision 0458
-------------------
수정일 : 2010-12-13
수정자 : 장희준
- BUG: array overflow 버그 수정
- CCacheRequestManager::SendRequest()에서 아래 코드 수정
//cm.hostname[HOSTNAME_LEN] = '\0';
cm.hostname[ HOSTNAME_LEN - 1 ] = '\0';
- CHG: gcc 4.4.5에서 컴파일 오류 수정
- Config.h에서 아래 수정
//void SetDelimiter( string& key, string& value = CONFIG_DEFAULT_VALUE_DELIMITER )
void SetDelimiter( string& key, string value = CONFIG_DEFAULT_VALUE_DELIMITER )
- Logger.cpp에 #include <string.h> 추가
- CHG: fhs.conf 관련 수정
- fhs.conf에 INTERNAL_NIC_NAME이 [COMMON] 섹션과 [fimngd] 섹션에서 중복 사용되고 있는데
[COMMON] 섹션에서만 사용하도록 변경.
- [fimngd] 섹션의 CACHE_CHECK_INTERVAL 필드명을 CACHE_CHECK_MAX_INTERVAL로 변경하고 이에 따른
소스 코드 수정
Revision 0327
-------------------
수정일 : 2010-08-03
수정자 : 김오종
- DEL: lib내의 Makefile 수정
- CBasesocket.o 제거
Revision 0326
-------------------
수정일 : 2010-08-03
수정자 : 김오종
- DEL: CBasesocket class 제거
- 사용하지 않는 부분이 포함되어 있어 제거 함.
Revision 0325
-------------------
수정일 : 2010-08-03
수정자 : 김오종
- BUG: 멤버 변수 속성 변경.
- 변수를 private에서 public으로 변경.
CCacheTargetFinder.h 의 m_nCachedContentCnt.
Revision 0324
-------------------
수정일 : 2010-08-03
수정자 : 김오종
- ADD: 캐시 대상파일 추출 주기 로직 변경
- 기존에 설정한 주가 값만 사용 했으나, 상황에 따라 아래처럼 조정한다.
: 대상파일의 개수가 2개 이하일때는 설정한 주기 값 사용.
: 대상파일의 수가 10개를 초과했을 경우에는 2sec의 주기 값 사용.
: 대상파일의 수가 2개 초과 10개 미만일때는 15sec의 주기 값 사용.
Revision 0323
-------------------
수정일 : 2010-08-02
수정자 : 김오종
- NEW: SVN 신규 등록
- 기존 svn://211.38.137.33/work/trunk/fimngd 에 존재하는 개발 완료 소스를 SVN 에 정식버전으로 등록함.
- 본 버전은 개발 및 성능 테스트를 완료한 버전으로 기존 cma의 기능을 보완한 것이다. 기본 기능은 아래와 같다.
: fhs의 mount경로 내의 file discription 수(5개이상)를 기반으로 cache Type(is_cached = 'Y')의 복제본을 증가 할지를 판단
후 증가 하는 기능을 포함하고 있다.(기존 cma의 기능)
: file discription 수가 5개이상을 유지 할 경우 확인주가때 마다 반복적으로 복제본수가 증가하는 현상을 개선.
- 단 현재 버전은 FreeBSD 5.4, 6.2 버전상에서만 테스트되었으며 다른 OS 로 포팅 처리시 코드를 재확인해야 함.
- NEW: History 저장을 위한 Changelog.txt 파일 추가
- 앞으로 각 작업에 대한 로그를 확인하도록 Changelog.txt 파일을 추가
+37
View File
@@ -0,0 +1,37 @@
#****************************************************************************
# Makefile for fimngd ( FHS Internal Management Daemon )
# -----------------------------------------
#
# begin : 2015/04/23
# copyright : (C) 2005 Solbox Inc.
# author : Development Team (Storage Part)
# email : storage.sd@solbox.com
# version : 3.5
#
# CopyRight(C) 2005 Solbox Inc. All Rights reserved.
# Redistribution and use in source and binary forms, with or with out
# modification, are not permitted in outside of Solbox Inc.
#*****************************************************************************
SUBDIRS = lib src
.PHONY: all $(SUBDIRS)
all: $(SUBDIRS)
sync;
$(SUBDIRS):
$(MAKE) all -C $@
install:
@for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) install); done
clean:
@for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) clean); done
# End of Makefile
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
fstat -u nobody -n $1 | sort | uniq | grep $1 | wc -l
+595
View File
@@ -0,0 +1,595 @@
#include "BaseSocket.h"
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define SOCKET_NOT_VALID -1
#define MAX_SEND_RETRY_COUNT 10 // Socket send 실패시 최대 재전송 시도 횟수.
/// @brief 생성자.
/// @param socket [in] 처리할 socket descriptor
CBaseSocket::CBaseSocket( const int& socket )
: m_sock( socket )
{
if( m_sock < 0 )
{
m_sock = SOCKET_NOT_VALID;
m_bConnected = false;
}
else
{
m_bConnected = true;
}
}
/// @brief 소멸자
CBaseSocket::~CBaseSocket()
{
// 소멸자 Socket 명시적 Close 처리.
Close();
}
/// @brief 소켓의 Close 처리를 수행함.
void CBaseSocket::Close()
{
m_bConnected = false;
if( m_sock != SOCKET_NOT_VALID )
{
close( m_sock );
m_sock = SOCKET_NOT_VALID;
}
}
/// @brief 전달받은 Target 으로 Socket 접속을 수행
/// @param szTarget [in] 접속 대상 Host name 또는 IP
/// @param nPort [in] 접속 Port
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool CBaseSocket::Connect( const std::string& szTarget, int nPort )
{
// 기존 접속을 Close 처리
Close();
unsigned int nHost = ConversionAddr( szTarget.c_str() );
if( nHost == INADDR_NONE )
{
LOG( LERR, "target host name resolve fail. [%s]->INADDR_NONE", szTarget.c_str());
return false;
}
struct sockaddr_in stTargetAddr;
m_sock = socket(AF_INET, SOCK_STREAM, 0);
if( m_sock == -1 )
{
int errorNum = errno;
LOG( LERR, "socket create failed.[%d][%s] Target:[%s]", errorNum, strerror(errorNum), szTarget.c_str() );
m_sock = SOCKET_NOT_VALID;
return false;
}
stTargetAddr.sin_family = AF_INET;
stTargetAddr.sin_addr.s_addr = nHost;
stTargetAddr.sin_port = htons( nPort );
// NEW 2012-05-18 huibong
// Connnection 종료시 많은 TIME_WAIT 상태 발생으로 인해 .. 이를 제거하기 위해 SO_LINGER 옵션을 설정처리한다.
struct linger opt_linger;
opt_linger.l_onoff = 1; /* LINGER ON */
// CHG 2014-05-27 huibong
// 아래와 같이 No Wait 로 처리할 경우... Server 역활 수행 중 Close 신호를 받지 못하는 경우가 발생 가능함.
// 따라서 5 sec 정도 대기하도록 수정 처리한다.
//opt_linger.l_linger = 0; /* No Wait => 0 for abortive disconnect */
opt_linger.l_linger = 5; // 5 sec 대기
int result = setsockopt( m_sock, SOL_SOCKET, SO_LINGER, &opt_linger, sizeof(opt_linger));
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "setsockopt func SO_LINGER set fail.[%d][%s]", errorNum, strerror(errorNum));
}
/* Send Timeout 설정. */
struct timeval tv_timeo = { 5, 0 };
result = setsockopt( m_sock, SOL_SOCKET, SO_SNDTIMEO, &tv_timeo, sizeof(tv_timeo));
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "setsockopt func SO_SNDTIMEO set fail.[%d][%s]", errorNum, strerror(errorNum));
}
if(connect(m_sock, (struct sockaddr *)&stTargetAddr, sizeof(stTargetAddr)) < 0 )
{
int errorNum = errno;
LOG( LERR, "connect fail.[%s][%d] [%d][%s]", szTarget.c_str(), nPort, errorNum, strerror( errorNum ) );
Close();
return false;
}
else
{
m_bConnected = true;
return true;
}
}
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
bool CBaseSocket::IsValidSocket()
{
if( m_sock != SOCKET_NOT_VALID && m_bConnected == true )
return true;
else
return false;
}
/// @brief m_sock 으로부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t CBaseSocket::Read( void * vptr, size_t size )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
while( (nRead = read( m_sock, vptr, size )) < 0 )
{
int errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2010-07-23 BUG huibong 잘못된 대입연산자를 비교연산자로 수정.
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
return nRead;
}
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t CBaseSocket::ReadN( void * vptr, size_t size )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
size_t nLeft = size;
char * ptr = (char *)vptr;
while( nLeft > 0 )
{
if( (nRead = read( m_sock, ptr, nLeft )) < 0 )
{
int errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
}
return size;
}
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류 , -2: Timeout
ssize_t CBaseSocket::ReadNTimeout( void * vptr, size_t size, int timeout )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
size_t nLeft = size;
char * ptr = (char *)vptr;
struct timeval timeOver;
int result;
fd_set selectFds;
FD_ZERO( &selectFds );
while( nLeft > 0 )
{
timeOver.tv_sec = timeout;
timeOver.tv_usec = 0;
FD_SET( m_sock, &selectFds );
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
if( result > 0 )
{
if( FD_ISSET( m_sock, &selectFds ))
{
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
{
int errorNum = errno;
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
}
}
else if( result == 0 ) // Timeout
{
//LOG( LDBG, "read timeout");
return -2;
}
else
{
int errorNum = errno;
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
return size;
}
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
ssize_t CBaseSocket::ReadNTimeout2( void * vptr, size_t size, int timeout )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
size_t nLeft = size;
char * ptr = (char *)vptr;
int errorNum;
// 우선은 읽기 시도.
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
{
errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nRead = 0;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
// 만약 더 받을 데이터가 존재한다면.
if( nLeft > 0 )
{
struct timeval timeOver;
int result;
fd_set selectFds;
FD_ZERO( &selectFds );
while( nLeft > 0 )
{
timeOver.tv_sec = timeout;
timeOver.tv_usec = 0;
FD_SET( m_sock, &selectFds );
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
if( result > 0 )
{
if( FD_ISSET( m_sock, &selectFds ))
{
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
{
errorNum = errno;
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
}
}
else if( result == 0 ) // Timeout
{
//LOG( LDBG, "read timeout");
return -2;
}
else
{
errorNum = errno;
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
}
return size;
}
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
/// @param size [in] write 하고자 하는 데이터의 크기.
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t CBaseSocket::WriteN( const void * vptr, size_t size )
{
if( IsValidSocket() == false )
return 0;
size_t nLeft;
ssize_t nWrite;
const char * ptr = (const char *)vptr;
nLeft = size;
int nTryCount = 0;
while( nLeft > 0 )
{
if( (nWrite = send( m_sock, ptr, nLeft, 0 )) < 0 )
{
int errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nWrite = 0;
++nTryCount;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "send func fail.[%d][%s]", errorNum, strerror(errorNum));
return -1;
}
}
else if( nWrite == 0 )
{
m_bConnected = false;
return 0;
}
if( nTryCount > MAX_SEND_RETRY_COUNT )
{
LOG( LERR, "send func failure due to exceeding count of retry[%d/%d]", nTryCount, MAX_SEND_RETRY_COUNT );
return 0 ;
}
nLeft -= nWrite;
ptr += nWrite;
}
return size;
}
// CHG 2011-05-03 huibong
// gethostbyname() 함수가 Thread Safe 하지 않기 때문에
// DNS resolve 처리시 잘못된 정보를 반환할 가능성이 존재
// 이에 따라 본 함수를 수정처리함.
/*
unsigned int CBaseSocket::ConversionAddr( const char * name )
{
struct hostent *he;
int max;
unsigned int retval;
if ((retval = inet_addr(name)) != INADDR_NONE)
return retval;
he = gethostbyname(name);
if (he == NULL)
return INADDR_NONE;
for (max = 0; he->h_addr_list[max]; max++) ;
if (max == 1)
return *((unsigned int *)(he->h_addr_list[0]));
else
return *((unsigned int *)(he->h_addr_list[random() % max]));
}
*/
unsigned int CBaseSocket::ConversionAddr( const char * name )
{
unsigned int retval;
struct addrinfo hints;
struct addrinfo *result = NULL;
int error;
// 전달받은 정보가 IP 주소인 경우...
// - DNS resolve 할 필요 없이 변환시킨 값을 그대로 사용한다.
if( (retval = inet_addr(name)) != INADDR_NONE )
return retval;
// getaddrinfo() 함수 호출을 위한 Hint 설정
memset( &hints, 0x00, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
// Thread Safe 한 DNS Resolve 처리함수 호출
// int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
// CHG 2014-11-14 huibong
// getaddrinfo 호출시 종종 EAI_NONAME 오류가 반환됨. (#20783)
// - 따라서 오류 반환시 재시도하도록 기능 추가
// CHG 2015-07-15 huibong
// usleep 의 multi thread 상에서 block 발생 가능
// - nanosleep 을 사용토록 변경 처리
for( int count = 0 ; count < 3; count++ )
{
error = getaddrinfo( name, NULL, &hints, &result );
// 오류 발생시
if( error != 0 )
{
if( result != NULL)
{
freeaddrinfo(result);
result = NULL;
}
// 잠시 대기 후 재시도 처리
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
}
else
{
// 정상 처리된 경우...
// - loop 탈출
break;
}
}
// 최종 오류 발생시
if( error != 0 )
{
LOG( LERR, "name[%s] dns resolve fail. getaddrinfo return error [%d][%s]", name, error, gai_strerror(error) );
return INADDR_NONE;
}
struct sockaddr_in * addr = (struct sockaddr_in *)result->ai_addr;
retval = (unsigned int)(addr->sin_addr.s_addr);
// DNS Resovle 결과 확인용 코드
/*
struct addrinfo *temp;
for( temp = result; temp; temp = temp->ai_next )
{
addr = (struct sockaddr_in *)temp->ai_addr;
printf ("getaddrinfo result = %s\n",inet_ntoa( addr->sin_addr));
}
*/
// getaddrinfo() 함수에서 생성한 메모리 영역 해제 처리.
freeaddrinfo(result);
return retval;
}
+118
View File
@@ -0,0 +1,118 @@
/***************************************************************************
BaseSocket ( Base Socket Class )
-----------------------------------------
begin : 2010/03/02
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __LIBRARY_BASE_SOCKET_H__
#define __LIBRARY_BASE_SOCKET_H__
#include <unistd.h>
#include <sys/types.h>
#include "Logger.h"
#define SOCKET_NOT_VALID -1
#define DEFAULT_DATA_RECEIVE_TIMEOUT 15 // sec
class CBaseSocket
{
protected:
/// @brief socket descriptor
int m_sock;
/// @brief socket 의 연결상태인지 여부를 저장하기 위한 변수.
bool m_bConnected;
public:
/// @brief 생성자.
CBaseSocket( const int & socket );
/// @brief 소멸자.
~CBaseSocket();
/// @brief 소켓의 Close 처리를 수행함.
void Close(void);
/// @brief 전달받은 Target 으로 Socket 접속을 수행
/// @param szTarget [in] 접속 대상 Host name 또는 IP
/// @param nPort [in] 접속 Port
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool Connect( const std::string& szTarget, int nPort );
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
bool IsValidSocket(void);
/// @brief 멤버변수인 socket 의 접속 상태 여부를 설정하기 위한 함수.
void SetConnectionStatus( bool bConnected) { m_bConnected = bConnected; }
/// @brief 현재 socket 의 접속 상태를 반환.
bool GetConnectionStatus( void) { return m_bConnected; }
//void SetLogger( Logger * pLog ) { m_pLog = pLog; }
protected:
/// @brief m_sock 로 부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t Read( void * vptr, size_t size );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t ReadN( void * vptr, size_t size );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
ssize_t ReadNTimeout( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
ssize_t ReadNTimeout2( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
public:
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
/// @param size [in] write 하고자 하는 데이터의 크기.
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t WriteN( const void * vptr, size_t size );
protected:
/// @brief 문자열로 전달받은 정보를 검사하여 IP 접속 정보를 생성한다.
unsigned int ConversionAddr( const char * name );
};
#endif /* __LIBRARY_BASE_SOCKET_H__ */
+215
View File
@@ -0,0 +1,215 @@
#include "Config.h"
#include <iostream>
#include <fstream>
#include <errno.h>
#include <stdlib.h>
#include <boost/algorithm/string.hpp> // use boost
Config::Config()
: m_keyDelimiter( CONFIG_DEFAULT_KEY_DELIMITER )
, m_valueDelimiter( CONFIG_DEFAULT_VALUE_DELIMITER )
{
}
/// @brief destructor
Config::~Config()
{
Clear();
}
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
/// @return On success return true, otherwise return false
bool Config::Open( const string path )
{
ifstream file;
// Config file open
file.open( path.c_str());
if( file.is_open() == false )
{
cerr << "[error] " << __FILE__<< ":" << __func__ << ": config file open failed.[" << path << "][" << strerror( errno ) << "]" << endl;
return false;
}
// 기존 데이터가 존재하면 삭제 처리.
if( m_configData.empty() == false )
m_configData.clear();
// config file parsing
string line;
string section;
vector< string > configs;
// 루프를 돌면서 Config 파일을 line 단위로 읽어들인당....
while( std::getline( file, line ) )
{
// 앞뒤 공백 제거 처리
boost::trim( line );
// 공백 or 주석처리 라인 검사
if( line.empty() == true || boost::starts_with( line, string("#") ) == true || line == "\r" )
{
continue;
}
// Section 여부 검사
if( boost::starts_with( line, string("[") ) == true && boost::ends_with( line, string("]") ) == true )
{
// [] 로 정의된 section 의 문자열 값 추출
line.erase( line.begin() );
line.erase( line.end() -1 );
boost::trim( line );
if( section.empty() == false && section != line )
{
// 이전 세션과 다른 신규 세션인 경우
// 기존까지 저장했던 데이터를 멤버 변수에 입력 처리 후 내부변수 초기화 처리.
m_configData.insert( make_pair( section, configs ) );
section.clear();
configs.clear();
}
// 신규 section 정보 저장처리.
section = line;
line.clear();
}
else
{
// Section 정보가 아닌 경우 => 실제 설정값 .. ^^
configs.push_back( line );
}
}
// 마지막 세션 처리된 정보가 존재하는 경우 멤버 변수에 저장 처리.
if( section.empty() == false )
{
m_configData.insert( make_pair( section, configs ) );
}
// 종료 처리.
file.close();
return true;
}
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
/// @return void
void Config::Clear()
{
m_configData.clear();
}
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
/// @return On success return true, otherwise return false
bool Config::GetConfig( const string& section, const string& key, string& value )
{
// Section 에 대한 임시 데이터 저장객체 생성
vector< string > configs;
// 해당 Section 이 존재하지 않는 경우
if( Find( section, configs ) == false )
return false;
string line;
string result;
vector< string >::const_iterator it;
// 해당 Key 이 존재하는지 검사
for( it = configs.begin(); it != configs.end(); it++)
{
line = *it;
// Line 상의 주석 제거
string::size_type pos = line.find( '#' );
if( pos != string::npos)
{
line = line.substr(0, pos);
boost::trim( line );
}
// key = value 에서 key 부분 추출
pos = line.find( m_keyDelimiter );
if( pos == string::npos )
{
continue;
}
else
{
result = line.substr(0, pos);
boost::trim( result );
}
if( key == result )
{
// Key 값이 동일한 경우
value = line.substr( pos+1 );
boost::trim( value );
return true;
}
}
return false;
}
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
/// @return On success return true, otherwise return false
bool Config::GetConfig( const string& section, const string& key, vector< string >& value )
{
string result;
vector< string > vec;
if( GetConfig( section, key, result ) == false )
return false;
// 전달받은 result 값을 value delimiter 를 이용하여 parsing 처리
boost::split( vec, result, boost::is_any_of( m_valueDelimiter ));
if( vec.empty() == true )
return false;
// 루프를 돌면서 trim 처리 후 결과값 저장처리.
vector< string >::const_iterator it;
for( it = vec.begin(); it != vec.end(); it++)
{
result = boost::trim_copy( *it );
if( result.empty() == false )
value.push_back( result );
}
if( value.empty() == true )
return false;
else
return true;
}
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
/// @param section [in] section 명
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
/// @return On success return true, otherwise return false
bool Config::Find( const string& section, vector<string>& configData )
{
map< string, vector< string > >::iterator it = m_configData.find( section );
if( it != m_configData.end() )
{
// 해당 section 을 찾은 경우
configData = it->second;
return true;
}
// 해당 section 을 찾지 못한 경우
return false;
}
+114
View File
@@ -0,0 +1,114 @@
/***************************************************************************
Config File Parser Class
-----------------------------------------
begin : 2010/02/27
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __LIBRARY_CONFIG_H__
#define __LIBRARY_CONFIG_H__
#include <string>
#include <map>
#include <vector>
using namespace std;
#define CONFIG_DEFAULT_KEY_DELIMITER "="
#define CONFIG_DEFAULT_VALUE_DELIMITER ","
/// @brief Config class
/// 1. config 파일의 내용을 파싱처리하여 각 Section, Key 에 해당하는 값을 반환처리
/// 2. config 파일은 [section] 단위로 구분된다.
/// 3. config 파일은 key=value 로 구분가능하며 이는 Delimiter 설정을 통해 변경가능하다.
/// 4. value 값이 다중으로 존재하는 경우 "," 값을 통해 구분가능, Delimiter 변경시 다른 값도 사용가능함.
/// 5. config 파일상에서 "#" 로 시작하는 문자열은 라인 끝까지 주석으로 처리된다.
/// 6. 특정 Key 값에 대한 다중 value 값 조회는 vector<string> 을 통해 수행한다.
/// 7. 만약 다중 value 값이 존재시 string 으로 반환받을 경우 해당 Row 가 통째로 반환된다.
/// 8. 본 객체는 Open , Clear 함수가 호출되기전까지 이전 Config 정보가 저장된다.
class Config
{
private:
/// @brief config information saved variable
// string : section data
// vector<string> : key=value data
map< string, vector< string> > m_configData;
/// @brief Key, Value 구분자 저장 변수
string m_keyDelimiter;
string m_valueDelimiter;
public:
/// @brief constructor
Config();
/// @brief destructor
~Config();
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
/// @return On success return true, otherwise return false
bool Open( const string path );
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
/// @return void
void Clear();
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
/// @return On success return true, otherwise return false
bool GetConfig( const string& section, const string& key, string& value );
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
/// @return On success return true, otherwise return false
bool GetConfig( const string& section, const string& key, vector< string >& value );
/// @brief Key, Value Delimiter Get 함수
/// @param key [out] key delimiter 값
/// @param value [out] value delimiter 값
void GetDelimiter( string& key, string& value )
{
key = m_keyDelimiter;
value = m_valueDelimiter;
}
// BUG 2010-11-30 huibong
// string& value = CONFIG_DEFAULT_VALUE_DELIMITER 값은 문법상 오류 구문임.
// gcc 3.4.6 버전에서는 Compile 되나 gcc 4.4.5 에서는 error 로 처리되어 수정처리함.
/// @brief Key, Value Delimiter Set 함수
/// @param key [out] key delimiter 값
/// @param value [out] value delimiter 값, 지정하지 않을 경우 Default 값이 사용됨.
void SetDelimiter( string& key, string value = CONFIG_DEFAULT_VALUE_DELIMITER )
{
m_keyDelimiter = key;
m_valueDelimiter = value;
}
protected:
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
/// @param section [in] section 명
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
/// @return On success return true, otherwise return false
bool Find( const string& section, vector<string>& configData );
};
#endif /* __LIBRARY_CONFIG_H__ */
+487
View File
@@ -0,0 +1,487 @@
/***************************************************************************
Logger.cpp
-----------------------------------------
begin : 2011/10/26
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "Logger.h"
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <iostream>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define MAX_BUFFER_SIZE 2048 // 임시 버퍼 최대 크기
#define DEFAULT_LOG_LEVEL LINF
using namespace std;
CLogger* CLogger::m_pInstance = NULL;
bool CLogger::m_bIsInitialized = false;
pthread_mutex_t CLogger::m_mutex = PTHREAD_MUTEX_INITIALIZER;
CLogger::CLogger( string programName, string logDir, int logLevel )
{
m_szProgramName = programName;
m_szLogDir = logDir;
if( IsValidLogLevel( logLevel ) == true )
{
m_nLogLevel = logLevel;
}
else
{
m_nLogLevel = DEFAULT_LOG_LEVEL;
}
MakeLogLevelString();
}
void CLogger::MakeLogLevelString()
{
m_vectorLogLevelString.push_back( "EMR" );
m_vectorLogLevelString.push_back( "ALT" );
m_vectorLogLevelString.push_back( "CRT" );
m_vectorLogLevelString.push_back( "ERR" );
m_vectorLogLevelString.push_back( "WAR" );
m_vectorLogLevelString.push_back( "NOT" );
m_vectorLogLevelString.push_back( "INF" );
m_vectorLogLevelString.push_back( "DBG" );
m_vectorLogLevelString.push_back( "DEV" );
m_vectorLogLevelString.push_back( "DEV1" );
m_vectorLogLevelString.push_back( "DEV2" );
}
CLogger::~CLogger()
{
m_vectorLogLevelString.clear();
}
bool CLogger::Init( string programName, string logDir, int logLevel )
{
if( m_bIsInitialized == true )
{
return true;
}
pthread_mutex_lock( &m_mutex );
// 변수 유효성 검사.
if( programName.empty() == true || logDir.empty() == true )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( IsValidLogLevel( logLevel ) == false )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( MakeLogDir( programName, logDir ) == false )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( CLogger::m_pInstance != NULL )
{
delete CLogger::m_pInstance;
CLogger::m_pInstance = NULL;
}
CLogger::m_pInstance = new CLogger( programName, logDir, logLevel );
m_bIsInitialized = true;
pthread_mutex_unlock( &m_mutex );
return true;
}
bool CLogger::IsValidLogLevel( int logLevel )
{
return ( ( logLevel < 0 || logLevel > MAX_LOG_LEVEL ) ? false : true );
}
bool CLogger::SetLogLevel( int logLevel )
{
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
m_nLogLevel = logLevel;
return true;
}
bool CLogger::MakeLogDir( string programName, string logDir )
{
string path = logDir + "/" + programName;
struct stat dirStat;
// 해당 이름을 가진 파일 또는 디렉토리가 존재하고
if( lstat( path.c_str(), &dirStat ) == 0 )
{
// 해당 이름이 디렉토리인 경우
if( S_ISDIR( dirStat.st_mode ) == true )
{
return true;
}
else
{
cerr << "exist file with the same name as log path(" << path << ")." << endl;
return false;
}
}
// 디렉토리 가 존재하지 않는 경우 디렉토리 생성 시도
string cmd = "mkdir -p " + path;
system( cmd.c_str() );
if( IsDirectory( path ) == false )
{
cerr << "can't make log directory. path=" << path << "." << endl;
return false;
}
return true;
}
bool CLogger::IsDirectory( string path )
{
struct stat dirStat;
if( lstat ( path.c_str(), &dirStat ) != 0 )
{
cerr << "Log path not valid. Check path [" << path << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
// 해당 정보가 Directory 가 아닌 경우
if( S_ISDIR( dirStat.st_mode ) == false )
{
return false;
}
return true;
}
void CLogger::Exit()
{
if( m_bIsInitialized == false )
{
return;
}
pthread_mutex_lock( &m_mutex );
if( CLogger::m_pInstance != NULL )
{
delete CLogger::m_pInstance;
CLogger::m_pInstance = NULL;
m_bIsInitialized = false;
}
pthread_mutex_unlock( &m_mutex );
}
CLogger* CLogger::GetInstance()
{
return CLogger::m_pInstance;
}
string CLogger::GetLogFilename( struct tm &timeNow )
{
char timeStr[256];
snprintf( timeStr, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
// Make File Name
string filename = m_szLogDir + "/" + m_szProgramName + "/" + m_szProgramName + "_" + string( timeStr );
return filename;
}
bool CLogger::Write( int logLevel, const char * fmt, ...)
{
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
return Write( logLevel, PREFIX_DATE, NULL, 0, buffer );
}
bool CLogger::WriteNoPrefix( int logLevel, const char * fmt, ...)
{
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
return Write( logLevel, PREFIX_NONE, NULL, 0, buffer );
return false;
}
// CHG 2012-08-16 huibong
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
// 함수명 : Write -> WriteWithFunc 으로 변경 처리
bool CLogger::WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
{
if( filename == NULL || funcname == NULL || lineNum < 0 || fmt == NULL )
{
return false;
}
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
char className[255];
string funcPrefix = GetClassName( className, filename );
funcPrefix += "::" + string( funcname ) + "()";
return Write( logLevel, PREFIX_FUNCTION, funcPrefix.c_str(), lineNum, buffer );
}
const char* CLogger::GetClassName( char* className, const char* filename )
{
if( className == NULL )
{
cout << "[ERROR] The input argument 'className' is NULL." << endl;
return NULL;
}
if( filename == NULL )
{
cout << "[ERROR] The input argument 'filename' is NULL." << endl;
strcpy( className, "NULL" );
return className;
}
int filenameSize = strlen( filename );
memcpy( className, filename, filenameSize );
// find end position
char endCharacter = '.';
int endPos = filenameSize - 1;
for( ; endPos > 0; --endPos )
{
if( className[endPos] == endCharacter )
{
break;
}
}
if( endPos == 0 )
{
cout << "[ERROR] endPos=0" << endl;
strcpy( className, "NULL" );
return className;
}
className[endPos] = '\0';
// find start position
char startCharacter = '/';
int startPos = endPos - 1;
for( ; startPos > 0; --startPos )
{
if( className[startPos] == startCharacter )
{
break;
}
}
if( startPos != 0 )
{
startPos += 1;
}
return (className + startPos );
}
bool CLogger::Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log )
{
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
if( logLevel > m_nLogLevel )
{
return false;
}
if( log == NULL )
{
return false;
}
// Get Current Data & Time
time_t now = time( NULL );
struct tm timeNow;
localtime_r( &now, &timeNow );
string filename = GetLogFilename( timeNow );
// Log file open
FILE* pFile = NULL;
pFile = fopen( filename.c_str(), "a+" );
if( pFile == NULL )
{
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
// 시간 정보처리
char timeStr[256];
snprintf( timeStr, (size_t)256, "[%02d:%02d:%02d]"
, timeNow.tm_hour, timeNow.tm_min, timeNow.tm_sec );
// Log Level 문자열 검색
string szLevel = m_vectorLogLevelString[ logLevel ];
switch( logPrefix )
{
case PREFIX_DATE:
/// 형식 예: [15:47:41] [DBG] sample log message.
fprintf( pFile, "%s [%-4s] %s\n", timeStr, szLevel.c_str(), log );
break;
case PREFIX_FUNCTION:
if( functionName == NULL )
{
fclose( pFile );
return false;
}
/// 형식 예: [15:47:41] [DBG] sample log message. [SomeClass::SomeFunction():12]
fprintf( pFile, "%s [%-4s] %s [%s:%d]\n", timeStr, szLevel.c_str(), log, functionName, lineNum );
break;
case PREFIX_NONE:
/// 형식 예: sample log message.
fprintf( pFile, "%s\n", log );
break;
}
// Write to log file
fflush( pFile );
// 종료 처리.
fclose( pFile );
return true;
}
bool CLogger::WriteHex( int logLevel, const unsigned char* data, const int size )
{
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
if( logLevel > m_nLogLevel )
{
return false;
}
if( data == NULL )
{
return false;
}
if( size <= 0 )
{
return false;
}
// Get Current Data & Time
time_t now = time( NULL );
struct tm timeNow;
localtime_r( &now, &timeNow );
string filename = GetLogFilename( timeNow );
// Log file open
FILE* pFile = NULL;
pFile = fopen( filename.c_str(), "a+" );
if( pFile == NULL )
{
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
for( int i = 0; i < size; ++i )
{
fprintf( pFile, "%02X", data[i] );
if( i == 0 )
{
continue;
}
if( ( (i+1) % 8 ) == 0 )
{
fprintf( pFile, " " );
}
if( ( (i+1) % 16 ) == 0 )
{
fprintf( pFile, " " );
}
if( ( (i+1) % 32 ) == 0 )
{
fprintf( pFile, "\n" );
}
}
fprintf( pFile, "\n" );
fflush( pFile );
// 종료 처리.
fclose( pFile );
return false;
}
+273
View File
@@ -0,0 +1,273 @@
/***************************************************************************
Logger.h
-----------------------------------------
begin : 2011/10/26
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.2.0.805
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __LOGGER_H__
#define __LOGGER_H__
#include <string>
#include <vector>
#include <pthread.h>
///@brief 로그 레벨 정의
#define LEMR 0 /* system is or will be unusable if situation is not resolved */
#define LALT 1 /* immediate action required */
#define LCRT 2 /* critical situations */
#define LERR 3 /* error conditions */
#define LWAR 4 /* recoverable errors */
#define LNOT 5 /* unusual situation that merits investigation */
#define LINF 6 /* information messages */
#define LDBG 7 /* verbose data for debugging */
#define LDEV 8 /* verbose data for developer */
#define LDEV1 9 /* start or end the function of application level */
#define LDEV2 10 /* start or end the function of application level */
#define MAX_LOG_LEVEL LDEV2
///@brief Log 정보를 파일로 저장하기 위한 Class.
///1. 가변 format 으로 전달된 로그 관련 정보를 Log Level 에 따라 로그 파일에 아래의 4가지 형식으로 저장한다.
///
/// 1.1 Prefix로 [hh:mm:ss]와 [ClassName::FunctionName]이 추가된 로그
/// LOG( level, format, ... ) 매크로 사용.
/// 예) [17:43:40] [DBG] log level debug [LoggerTestTestLogger]
///
/// 1.2 Prefix로 [hh:mm:ss]이 추가된 로그
/// _LOG( level, format, ... ) 매크로 사용
/// 예) [17:43:40] [EMR] log level emergency
///
/// 1.3 Prefix가 없는 로그
/// _LOG_( level, format, ... ) 매크로 사용
/// 예) log level emergency
///
/// 1.4 Hex 로그.
/// LOG_HEX( level, data, size ) 매크로 사용
/// 예) 00010203 04050607 08090A0B 0C0D0E0F
///
///2. Logger 객체 초기화시 전달된 Log Level 정보보다 전달받은 Log Level 정보가 큰 경우 해당 로그는 파일로 저장되지 않는다.
///
///3. 로그 파일은 매 일단위로 저장파일이 변경된다.
///
///4. 로그 저장을 위한 program 경로가 존재하지 않는 경우 자동 생성 처리된다.
///
///5. 로그 저장방식은 매 저장로그마다 open-close 로 처리된다.
///
///6. 파일로 기록시 Log Level 에 대한 정보도 함께 기록된다.
///
///7. 싱글톤으로 작성되었고, CLogger::Init(...)시에 쓰레드 안정성을 제공한다.
///
///8. 동적으로 로그 레벨을 변경할 수 있는 인터페이스를 제공한다.
///
class CLogger
{
// Attributes
private:
///@brief 싱글톤 객체 인트턴스.
static CLogger* m_pInstance;
///@brief 싱글톤 객체 초기화 여부.
static bool m_bIsInitialized;
///@brief 싱글톤 객체 초기화시 스레드 안정성을 위한 뮤텍스.
static pthread_mutex_t m_mutex;
///@brief 프로그램 이름. 로그 파일 경로를 만들 때 사용.
std::string m_szProgramName;
///@brief 공통 로그 디렉토리 이름. 로그 파일 경로를 만들 때 사용.
std::string m_szLogDir;
///@brief 로그 레벨.
int m_nLogLevel;
///@brief 로그 레벨에 대응되는 문자열 정보를 저장.
std::vector<std::string> m_vectorLogLevelString;
protected:
public:
///@brief 로그 형식을 지정.
typedef enum
{
PREFIX_NONE = 0, /// 클래스 설명의 1.3에 해당
PREFIX_DATE, /// 클래스 설명의 1.2에 해당
PREFIX_FUNCTION, /// 클래스 설명의 1.1에 해당
} LOG_PREFIX;
// Operations
private:
///@brief 생성자.
/// 프로그램 이름, 공통 로그 디렉토리, 로그 레벨을 저장하고
/// 로그 레벨에 대응되는 문자열 정보를 만든다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@param logLevel [in] 로그 레벨
CLogger( std::string programName, std::string logDir, int logLevel );
///@brief 소멸자.
/// 로그 레벨에 대응되는 문자열 정보를 저장하고 있는
/// 벡터 m_vectorLogLevelString을 clear 시킴.
virtual ~CLogger();
///@brief 로그 레벨에 대응되는 문자열을 만든다.
///@param none.
///@return none.
void MakeLogLevelString();
///@brief 로그 파일이 위치할 실제 로그 디렉토리를 생성한다.
/// 생성할 디렉토리 경로는 'logDir/programName'이 된다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@return 디렉토리가 이미 존재하거나 생성 성공하면 true,
/// 해당 경로가 존재하지만 디렉토리가 아니거나, 디렉토리 생성 실패하면 false 반환.
static bool MakeLogDir( std::string programName, std::string logDir );
///@brief 해당 경로가 디렉토리 인지 아닌지 판단.
///@param path [in] 디렉토리 인지 아닌지 판단할 경로.
///@return 해당 경로가 디렉토이면 true,
/// 경로가 존재하지 않거나 디렉토리가 아니면 false 반환.
static bool IsDirectory( std::string path );
///@brief 로그 레벨이 올바른지 판별.
///@param logLevel [in]
///@return 올바른 로그 레벨이면 true, 그렇지 않으면 false 반환.
static bool IsValidLogLevel( int logLevel );
///@brief 시간 정보를 입력 받아 로그 파일 이름을 만든다.
/// 로그 파일 이름 형식 : 프로그램명_YYYYMMDD.log
///param timeNow [in] 현재 시간 정보.
///return 로그 파일 이름.
std::string GetLogFilename( struct tm &timeNow );
///@brief 로그를 남기는는 클래스가 정의된 파일의 이름에서 클래스명을 추출한다.
/// 쓰레드 안정성을 보장한다.
///@param className [out] 파일 이름에서 추출된 클래스명
///@param filename [in] 파일 이름.
///@return 클래스명 추출이 성공하면 클래스명 문자열의 포인터, 추출 실패하면 NULL.
const char* GetClassName( char* className, const char* filename );
///@brief 인자 logPrefix에 따라 적절한 형식으로 로그 파일에 로그를 저장한다.
/// 인자 logLevel이 설정된 로그 레벨보다 높으면 로그를 출력하지 않는다.
///@param logLevel [in] 로그 레벨
///@param logPrefix [in] 로그 프리픽스 종류.
///@functionName [in] ClassName::FunctionNmae() 형식의 문자열.
///@lineNum [in] 라인 번호.
///@log [in] 출력하고자 하는 로그 내용.
bool Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log );
protected:
public:
///@brief 싱글톤 객체 m_pInstance를 생성하고 인자 정보로 로그 디렉토리를 만든다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@param logLevel [in] 로그 레벨
///@return 로그 디렉토리를 만들고 싱글톤 객체를 생성했으면 true,
/// 로그 디렉토리를 만들지 못 했거나 인자 값이 올바르지 않으면 false 반환.
static bool Init( std::string programName, std::string logDir, int logLevel );
///@brief 싱글톤 객체 m_pInstance를 delete 한다.
///@param none.
///@return none.
static void Exit();
///@brief 싱글톤 객체 m_pInstance를 반환한다.
///@param none.
///@return CLogger 객체의 인스턴스.
static CLogger* GetInstance();
///@brief Prefix로 [hh:mm:ss]이 추가된 형식으로 로그 저장.
///@param logLevel [in] 로그 레벨
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool Write( int logLevel, const char * fmt, ...)
__attribute__((format(printf, 3, 4)));
///@brief Prefix가 없는 로그 저장.
///@param logLevel [in] 로그 레벨
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteNoPrefix( int logLevel, const char * fmt, ...)
__attribute__((format(printf, 3, 4)));
// CHG 2012-08-16 huibong
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
///@brief Prefix로 [hh:mm:ss]와 [ClassName::FunctionName:line]이 추가된 형식으로 로그 저장.
///@param logLevel [in] 로그 레벨
///@param filename [in] 파일 이름
///@param funcname [in] 함수 이름
///@param lineNum [in] 라인 번호
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
__attribute__((format(printf, 6, 7)));
///@brief 로그를 hex 형식으로 저장.
///@param logLevel [in] 로그 레벨
///@param data [in] hex 형식으로 출력할 데이터.
///@pram size [in] data의 크기.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteHex( int logLevel, const unsigned char* data, const int size );
///@brief 로그을 설정한다. 인자 logLevel이 적절한 값이면 새로운 값으로 변경하고
/// 적절한 값이 아니면 로그 레벨을 변경하지 않는다.
///@param logLevel [in] 설정할 로그 레벨
///@return none.
bool SetLogLevel( int logLevel );
inline int GetLogLevel() { return m_nLogLevel; };
inline std::string GetLogDir() { return m_szLogDir + "/" + m_szProgramName; };
};
#define LOG( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteWithFunc( level, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__ ); \
}
#define _LOG( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->Write( level, format, ##__VA_ARGS__ ); \
}
#define _LOG_( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteNoPrefix( level, format, ##__VA_ARGS__ ); \
}
#define _LOG_HEX_( level, data, size ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteHex( level, (const unsigned char*)data, size ); \
}
#define FUNC_BEGIN() LOG( LDEV1, "begin" )
#define FUNC_END() LOG( LDEV1, "end" )
#define FRM_BEGIN() LOG( LDEV2, "begin" )
#define FRM_END() LOG( LDEV2, "end" )
#endif // __LOGGER_H__
+69
View File
@@ -0,0 +1,69 @@
#****************************************************************************
# Makefile for Cloud Storage Common Libaray
# -----------------------------------------
#
# begin : 2013/06/04
# copyright : (C) 2013 Solbox Inc.
# author : Development 1 Team
# - 2013/06/04 - 1st dadamin
# email : dev1@solbox.com
# version : 3.3.0
#
# CopyRight(C) 2005 Solbox Inc. All Rights reserved.
# Redistribution and use in source and binary forms, with or with out
# modification, are not permitted in outside of Solbox Inc.
#*****************************************************************************
# Library info
LIB_NAME = InterCommon
LIB = lib$(LIB_NAME).a
OBJS = Config.o Logger.o BaseSocket.o
# Compiler info
CC = /usr/bin/g++
AR = /usr/bin/ar
DIR_INCLUDE = -I/usr/local/include
ifeq ($(DEBUG), yes)
CFLAGS = -Wall -O0 -g -Wreturn-type -Wunused -Wuninitialized\
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-D_REENTRANT -D_THREAD_SAFE -D_PTHREADS
LFLAGS =
DFLAGS =
else
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized\
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-D_REENTRANT -D_THREAD_SAFE -D_PTHREADS
LFLAGS =
DFLAGS =
endif
############################
all:$(LIB)
sync
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
$(LIB): $(OBJS)
$(AR) crsv $@ $^
clean:
-rm -f *.o core *.out *.log
-rm -f $(LIB)
sync
install :
sync
# End of Makefile
+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__