base
This commit is contained in:
@@ -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 파일을 추가
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
fstat -u nobody -n $1 | sort | uniq | grep $1 | wc -l
|
||||
@@ -0,0 +1,595 @@
|
||||
#include "BaseSocket.h"
|
||||
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#define SOCKET_NOT_VALID -1
|
||||
#define MAX_SEND_RETRY_COUNT 10 // Socket send 실패시 최대 재전송 시도 횟수.
|
||||
|
||||
|
||||
/// @brief 생성자.
|
||||
/// @param socket [in] 처리할 socket descriptor
|
||||
CBaseSocket::CBaseSocket( const int& socket )
|
||||
: m_sock( socket )
|
||||
{
|
||||
if( m_sock < 0 )
|
||||
{
|
||||
m_sock = SOCKET_NOT_VALID;
|
||||
m_bConnected = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 소멸자
|
||||
CBaseSocket::~CBaseSocket()
|
||||
{
|
||||
// 소멸자 Socket 명시적 Close 처리.
|
||||
Close();
|
||||
}
|
||||
|
||||
/// @brief 소켓의 Close 처리를 수행함.
|
||||
void CBaseSocket::Close()
|
||||
{
|
||||
m_bConnected = false;
|
||||
|
||||
if( m_sock != SOCKET_NOT_VALID )
|
||||
{
|
||||
close( m_sock );
|
||||
m_sock = SOCKET_NOT_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 전달받은 Target 으로 Socket 접속을 수행
|
||||
/// @param szTarget [in] 접속 대상 Host name 또는 IP
|
||||
/// @param nPort [in] 접속 Port
|
||||
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
|
||||
bool CBaseSocket::Connect( const std::string& szTarget, int nPort )
|
||||
{
|
||||
// 기존 접속을 Close 처리
|
||||
Close();
|
||||
|
||||
unsigned int nHost = ConversionAddr( szTarget.c_str() );
|
||||
if( nHost == INADDR_NONE )
|
||||
{
|
||||
LOG( LERR, "target host name resolve fail. [%s]->INADDR_NONE", szTarget.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in stTargetAddr;
|
||||
|
||||
m_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if( m_sock == -1 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
|
||||
LOG( LERR, "socket create failed.[%d][%s] Target:[%s]", errorNum, strerror(errorNum), szTarget.c_str() );
|
||||
|
||||
m_sock = SOCKET_NOT_VALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
stTargetAddr.sin_family = AF_INET;
|
||||
stTargetAddr.sin_addr.s_addr = nHost;
|
||||
stTargetAddr.sin_port = htons( nPort );
|
||||
|
||||
// NEW 2012-05-18 huibong
|
||||
// Connnection 종료시 많은 TIME_WAIT 상태 발생으로 인해 .. 이를 제거하기 위해 SO_LINGER 옵션을 설정처리한다.
|
||||
struct linger opt_linger;
|
||||
opt_linger.l_onoff = 1; /* LINGER ON */
|
||||
|
||||
// CHG 2014-05-27 huibong
|
||||
// 아래와 같이 No Wait 로 처리할 경우... Server 역활 수행 중 Close 신호를 받지 못하는 경우가 발생 가능함.
|
||||
// 따라서 5 sec 정도 대기하도록 수정 처리한다.
|
||||
//opt_linger.l_linger = 0; /* No Wait => 0 for abortive disconnect */
|
||||
opt_linger.l_linger = 5; // 5 sec 대기
|
||||
|
||||
int result = setsockopt( m_sock, SOL_SOCKET, SO_LINGER, &opt_linger, sizeof(opt_linger));
|
||||
if( result != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "setsockopt func SO_LINGER set fail.[%d][%s]", errorNum, strerror(errorNum));
|
||||
|
||||
}
|
||||
|
||||
/* Send Timeout 설정. */
|
||||
struct timeval tv_timeo = { 5, 0 };
|
||||
|
||||
result = setsockopt( m_sock, SOL_SOCKET, SO_SNDTIMEO, &tv_timeo, sizeof(tv_timeo));
|
||||
if( result != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "setsockopt func SO_SNDTIMEO set fail.[%d][%s]", errorNum, strerror(errorNum));
|
||||
|
||||
}
|
||||
|
||||
if(connect(m_sock, (struct sockaddr *)&stTargetAddr, sizeof(stTargetAddr)) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "connect fail.[%s][%d] [%d][%s]", szTarget.c_str(), nPort, errorNum, strerror( errorNum ) );
|
||||
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bConnected = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
|
||||
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
|
||||
bool CBaseSocket::IsValidSocket()
|
||||
{
|
||||
if( m_sock != SOCKET_NOT_VALID && m_bConnected == true )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief m_sock 으로부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t CBaseSocket::Read( void * vptr, size_t size )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
while( (nRead = read( m_sock, vptr, size )) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2010-07-23 BUG huibong 잘못된 대입연산자를 비교연산자로 수정.
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return nRead;
|
||||
}
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t CBaseSocket::ReadN( void * vptr, size_t size )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
size_t nLeft = size;
|
||||
char * ptr = (char *)vptr;
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
if( (nRead = read( m_sock, ptr, nLeft )) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류 , -2: Timeout
|
||||
ssize_t CBaseSocket::ReadNTimeout( void * vptr, size_t size, int timeout )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
size_t nLeft = size;
|
||||
char * ptr = (char *)vptr;
|
||||
|
||||
struct timeval timeOver;
|
||||
int result;
|
||||
|
||||
fd_set selectFds;
|
||||
FD_ZERO( &selectFds );
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
timeOver.tv_sec = timeout;
|
||||
timeOver.tv_usec = 0;
|
||||
FD_SET( m_sock, &selectFds );
|
||||
|
||||
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
|
||||
|
||||
if( result > 0 )
|
||||
{
|
||||
if( FD_ISSET( m_sock, &selectFds ))
|
||||
{
|
||||
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
}
|
||||
|
||||
}
|
||||
else if( result == 0 ) // Timeout
|
||||
{
|
||||
//LOG( LDBG, "read timeout");
|
||||
return -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
|
||||
ssize_t CBaseSocket::ReadNTimeout2( void * vptr, size_t size, int timeout )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
size_t nLeft = size;
|
||||
char * ptr = (char *)vptr;
|
||||
int errorNum;
|
||||
|
||||
// 우선은 읽기 시도.
|
||||
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
|
||||
{
|
||||
errorNum = errno;
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nRead = 0;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
|
||||
// 만약 더 받을 데이터가 존재한다면.
|
||||
if( nLeft > 0 )
|
||||
{
|
||||
struct timeval timeOver;
|
||||
int result;
|
||||
|
||||
fd_set selectFds;
|
||||
FD_ZERO( &selectFds );
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
timeOver.tv_sec = timeout;
|
||||
timeOver.tv_usec = 0;
|
||||
FD_SET( m_sock, &selectFds );
|
||||
|
||||
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
|
||||
|
||||
if( result > 0 )
|
||||
{
|
||||
if( FD_ISSET( m_sock, &selectFds ))
|
||||
{
|
||||
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
|
||||
{
|
||||
errorNum = errno;
|
||||
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
}
|
||||
}
|
||||
else if( result == 0 ) // Timeout
|
||||
{
|
||||
//LOG( LDBG, "read timeout");
|
||||
return -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorNum = errno;
|
||||
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
|
||||
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
|
||||
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
|
||||
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
|
||||
/// @param size [in] write 하고자 하는 데이터의 크기.
|
||||
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t CBaseSocket::WriteN( const void * vptr, size_t size )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
size_t nLeft;
|
||||
ssize_t nWrite;
|
||||
|
||||
const char * ptr = (const char *)vptr;
|
||||
nLeft = size;
|
||||
|
||||
int nTryCount = 0;
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
if( (nWrite = send( m_sock, ptr, nLeft, 0 )) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nWrite = 0;
|
||||
++nTryCount;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "send func fail.[%d][%s]", errorNum, strerror(errorNum));
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nWrite == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( nTryCount > MAX_SEND_RETRY_COUNT )
|
||||
{
|
||||
LOG( LERR, "send func failure due to exceeding count of retry[%d/%d]", nTryCount, MAX_SEND_RETRY_COUNT );
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
nLeft -= nWrite;
|
||||
ptr += nWrite;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// CHG 2011-05-03 huibong
|
||||
// gethostbyname() 함수가 Thread Safe 하지 않기 때문에
|
||||
// DNS resolve 처리시 잘못된 정보를 반환할 가능성이 존재
|
||||
// 이에 따라 본 함수를 수정처리함.
|
||||
/*
|
||||
unsigned int CBaseSocket::ConversionAddr( const char * name )
|
||||
{
|
||||
struct hostent *he;
|
||||
int max;
|
||||
unsigned int retval;
|
||||
|
||||
if ((retval = inet_addr(name)) != INADDR_NONE)
|
||||
return retval;
|
||||
|
||||
he = gethostbyname(name);
|
||||
if (he == NULL)
|
||||
return INADDR_NONE;
|
||||
|
||||
for (max = 0; he->h_addr_list[max]; max++) ;
|
||||
if (max == 1)
|
||||
return *((unsigned int *)(he->h_addr_list[0]));
|
||||
else
|
||||
return *((unsigned int *)(he->h_addr_list[random() % max]));
|
||||
}
|
||||
*/
|
||||
|
||||
unsigned int CBaseSocket::ConversionAddr( const char * name )
|
||||
{
|
||||
unsigned int retval;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result = NULL;
|
||||
int error;
|
||||
|
||||
|
||||
// 전달받은 정보가 IP 주소인 경우...
|
||||
// - DNS resolve 할 필요 없이 변환시킨 값을 그대로 사용한다.
|
||||
if( (retval = inet_addr(name)) != INADDR_NONE )
|
||||
return retval;
|
||||
|
||||
// getaddrinfo() 함수 호출을 위한 Hint 설정
|
||||
memset( &hints, 0x00, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
// Thread Safe 한 DNS Resolve 처리함수 호출
|
||||
// int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
|
||||
|
||||
// CHG 2014-11-14 huibong
|
||||
// getaddrinfo 호출시 종종 EAI_NONAME 오류가 반환됨. (#20783)
|
||||
// - 따라서 오류 반환시 재시도하도록 기능 추가
|
||||
// CHG 2015-07-15 huibong
|
||||
// usleep 의 multi thread 상에서 block 발생 가능
|
||||
// - nanosleep 을 사용토록 변경 처리
|
||||
for( int count = 0 ; count < 3; count++ )
|
||||
{
|
||||
error = getaddrinfo( name, NULL, &hints, &result );
|
||||
|
||||
// 오류 발생시
|
||||
if( error != 0 )
|
||||
{
|
||||
if( result != NULL)
|
||||
{
|
||||
freeaddrinfo(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
// 잠시 대기 후 재시도 처리
|
||||
struct timespec sleep;
|
||||
sleep.tv_sec = 0;
|
||||
sleep.tv_nsec = 500000000; // 0.5 sec
|
||||
nanosleep( &sleep, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상 처리된 경우...
|
||||
// - loop 탈출
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 최종 오류 발생시
|
||||
if( error != 0 )
|
||||
{
|
||||
LOG( LERR, "name[%s] dns resolve fail. getaddrinfo return error [%d][%s]", name, error, gai_strerror(error) );
|
||||
return INADDR_NONE;
|
||||
}
|
||||
|
||||
struct sockaddr_in * addr = (struct sockaddr_in *)result->ai_addr;
|
||||
retval = (unsigned int)(addr->sin_addr.s_addr);
|
||||
|
||||
// DNS Resovle 결과 확인용 코드
|
||||
/*
|
||||
struct addrinfo *temp;
|
||||
for( temp = result; temp; temp = temp->ai_next )
|
||||
{
|
||||
addr = (struct sockaddr_in *)temp->ai_addr;
|
||||
printf ("getaddrinfo result = %s\n",inet_ntoa( addr->sin_addr));
|
||||
}
|
||||
*/
|
||||
|
||||
// getaddrinfo() 함수에서 생성한 메모리 영역 해제 처리.
|
||||
freeaddrinfo(result);
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,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__ */
|
||||
@@ -0,0 +1,215 @@
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <boost/algorithm/string.hpp> // use boost
|
||||
|
||||
|
||||
Config::Config()
|
||||
: m_keyDelimiter( CONFIG_DEFAULT_KEY_DELIMITER )
|
||||
, m_valueDelimiter( CONFIG_DEFAULT_VALUE_DELIMITER )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// @brief destructor
|
||||
Config::~Config()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
|
||||
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::Open( const string path )
|
||||
{
|
||||
ifstream file;
|
||||
|
||||
// Config file open
|
||||
file.open( path.c_str());
|
||||
if( file.is_open() == false )
|
||||
{
|
||||
cerr << "[error] " << __FILE__<< ":" << __func__ << ": config file open failed.[" << path << "][" << strerror( errno ) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 기존 데이터가 존재하면 삭제 처리.
|
||||
if( m_configData.empty() == false )
|
||||
m_configData.clear();
|
||||
|
||||
// config file parsing
|
||||
string line;
|
||||
string section;
|
||||
vector< string > configs;
|
||||
|
||||
// 루프를 돌면서 Config 파일을 line 단위로 읽어들인당....
|
||||
while( std::getline( file, line ) )
|
||||
{
|
||||
// 앞뒤 공백 제거 처리
|
||||
boost::trim( line );
|
||||
|
||||
// 공백 or 주석처리 라인 검사
|
||||
if( line.empty() == true || boost::starts_with( line, string("#") ) == true || line == "\r" )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Section 여부 검사
|
||||
if( boost::starts_with( line, string("[") ) == true && boost::ends_with( line, string("]") ) == true )
|
||||
{
|
||||
// [] 로 정의된 section 의 문자열 값 추출
|
||||
line.erase( line.begin() );
|
||||
line.erase( line.end() -1 );
|
||||
boost::trim( line );
|
||||
|
||||
if( section.empty() == false && section != line )
|
||||
{
|
||||
// 이전 세션과 다른 신규 세션인 경우
|
||||
// 기존까지 저장했던 데이터를 멤버 변수에 입력 처리 후 내부변수 초기화 처리.
|
||||
|
||||
m_configData.insert( make_pair( section, configs ) );
|
||||
section.clear();
|
||||
configs.clear();
|
||||
}
|
||||
|
||||
// 신규 section 정보 저장처리.
|
||||
section = line;
|
||||
line.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Section 정보가 아닌 경우 => 실제 설정값 .. ^^
|
||||
configs.push_back( line );
|
||||
}
|
||||
}
|
||||
|
||||
// 마지막 세션 처리된 정보가 존재하는 경우 멤버 변수에 저장 처리.
|
||||
if( section.empty() == false )
|
||||
{
|
||||
m_configData.insert( make_pair( section, configs ) );
|
||||
}
|
||||
|
||||
// 종료 처리.
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
|
||||
/// @return void
|
||||
void Config::Clear()
|
||||
{
|
||||
m_configData.clear();
|
||||
}
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::GetConfig( const string& section, const string& key, string& value )
|
||||
{
|
||||
// Section 에 대한 임시 데이터 저장객체 생성
|
||||
vector< string > configs;
|
||||
|
||||
// 해당 Section 이 존재하지 않는 경우
|
||||
if( Find( section, configs ) == false )
|
||||
return false;
|
||||
|
||||
string line;
|
||||
string result;
|
||||
vector< string >::const_iterator it;
|
||||
|
||||
// 해당 Key 이 존재하는지 검사
|
||||
for( it = configs.begin(); it != configs.end(); it++)
|
||||
{
|
||||
line = *it;
|
||||
|
||||
// Line 상의 주석 제거
|
||||
string::size_type pos = line.find( '#' );
|
||||
if( pos != string::npos)
|
||||
{
|
||||
line = line.substr(0, pos);
|
||||
boost::trim( line );
|
||||
}
|
||||
|
||||
// key = value 에서 key 부분 추출
|
||||
pos = line.find( m_keyDelimiter );
|
||||
if( pos == string::npos )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = line.substr(0, pos);
|
||||
boost::trim( result );
|
||||
}
|
||||
|
||||
if( key == result )
|
||||
{
|
||||
// Key 값이 동일한 경우
|
||||
value = line.substr( pos+1 );
|
||||
boost::trim( value );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::GetConfig( const string& section, const string& key, vector< string >& value )
|
||||
{
|
||||
string result;
|
||||
vector< string > vec;
|
||||
|
||||
if( GetConfig( section, key, result ) == false )
|
||||
return false;
|
||||
|
||||
// 전달받은 result 값을 value delimiter 를 이용하여 parsing 처리
|
||||
boost::split( vec, result, boost::is_any_of( m_valueDelimiter ));
|
||||
if( vec.empty() == true )
|
||||
return false;
|
||||
|
||||
// 루프를 돌면서 trim 처리 후 결과값 저장처리.
|
||||
vector< string >::const_iterator it;
|
||||
for( it = vec.begin(); it != vec.end(); it++)
|
||||
{
|
||||
result = boost::trim_copy( *it );
|
||||
|
||||
if( result.empty() == false )
|
||||
value.push_back( result );
|
||||
}
|
||||
|
||||
if( value.empty() == true )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
|
||||
/// @param section [in] section 명
|
||||
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::Find( const string& section, vector<string>& configData )
|
||||
{
|
||||
map< string, vector< string > >::iterator it = m_configData.find( section );
|
||||
if( it != m_configData.end() )
|
||||
{
|
||||
// 해당 section 을 찾은 경우
|
||||
configData = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 해당 section 을 찾지 못한 경우
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/***************************************************************************
|
||||
Config File Parser Class
|
||||
-----------------------------------------
|
||||
begin : 2010/02/27
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __LIBRARY_CONFIG_H__
|
||||
#define __LIBRARY_CONFIG_H__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
#define CONFIG_DEFAULT_KEY_DELIMITER "="
|
||||
#define CONFIG_DEFAULT_VALUE_DELIMITER ","
|
||||
|
||||
|
||||
/// @brief Config class
|
||||
/// 1. config 파일의 내용을 파싱처리하여 각 Section, Key 에 해당하는 값을 반환처리
|
||||
/// 2. config 파일은 [section] 단위로 구분된다.
|
||||
/// 3. config 파일은 key=value 로 구분가능하며 이는 Delimiter 설정을 통해 변경가능하다.
|
||||
/// 4. value 값이 다중으로 존재하는 경우 "," 값을 통해 구분가능, Delimiter 변경시 다른 값도 사용가능함.
|
||||
/// 5. config 파일상에서 "#" 로 시작하는 문자열은 라인 끝까지 주석으로 처리된다.
|
||||
/// 6. 특정 Key 값에 대한 다중 value 값 조회는 vector<string> 을 통해 수행한다.
|
||||
/// 7. 만약 다중 value 값이 존재시 string 으로 반환받을 경우 해당 Row 가 통째로 반환된다.
|
||||
/// 8. 본 객체는 Open , Clear 함수가 호출되기전까지 이전 Config 정보가 저장된다.
|
||||
class Config
|
||||
{
|
||||
private:
|
||||
/// @brief config information saved variable
|
||||
// string : section data
|
||||
// vector<string> : key=value data
|
||||
map< string, vector< string> > m_configData;
|
||||
|
||||
/// @brief Key, Value 구분자 저장 변수
|
||||
string m_keyDelimiter;
|
||||
string m_valueDelimiter;
|
||||
|
||||
public:
|
||||
/// @brief constructor
|
||||
Config();
|
||||
|
||||
/// @brief destructor
|
||||
~Config();
|
||||
|
||||
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
|
||||
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Open( const string path );
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
|
||||
/// @return void
|
||||
void Clear();
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
|
||||
/// @return On success return true, otherwise return false
|
||||
bool GetConfig( const string& section, const string& key, string& value );
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool GetConfig( const string& section, const string& key, vector< string >& value );
|
||||
|
||||
/// @brief Key, Value Delimiter Get 함수
|
||||
/// @param key [out] key delimiter 값
|
||||
/// @param value [out] value delimiter 값
|
||||
void GetDelimiter( string& key, string& value )
|
||||
{
|
||||
key = m_keyDelimiter;
|
||||
value = m_valueDelimiter;
|
||||
}
|
||||
|
||||
// BUG 2010-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__ */
|
||||
@@ -0,0 +1,487 @@
|
||||
/***************************************************************************
|
||||
Logger.cpp
|
||||
-----------------------------------------
|
||||
begin : 2011/10/26
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
#include "Logger.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <iostream>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_BUFFER_SIZE 2048 // 임시 버퍼 최대 크기
|
||||
#define DEFAULT_LOG_LEVEL LINF
|
||||
|
||||
using namespace std;
|
||||
|
||||
CLogger* CLogger::m_pInstance = NULL;
|
||||
bool CLogger::m_bIsInitialized = false;
|
||||
pthread_mutex_t CLogger::m_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
|
||||
CLogger::CLogger( string programName, string logDir, int logLevel )
|
||||
{
|
||||
m_szProgramName = programName;
|
||||
m_szLogDir = logDir;
|
||||
|
||||
if( IsValidLogLevel( logLevel ) == true )
|
||||
{
|
||||
m_nLogLevel = logLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nLogLevel = DEFAULT_LOG_LEVEL;
|
||||
}
|
||||
|
||||
MakeLogLevelString();
|
||||
}
|
||||
|
||||
void CLogger::MakeLogLevelString()
|
||||
{
|
||||
m_vectorLogLevelString.push_back( "EMR" );
|
||||
m_vectorLogLevelString.push_back( "ALT" );
|
||||
m_vectorLogLevelString.push_back( "CRT" );
|
||||
m_vectorLogLevelString.push_back( "ERR" );
|
||||
m_vectorLogLevelString.push_back( "WAR" );
|
||||
m_vectorLogLevelString.push_back( "NOT" );
|
||||
m_vectorLogLevelString.push_back( "INF" );
|
||||
m_vectorLogLevelString.push_back( "DBG" );
|
||||
m_vectorLogLevelString.push_back( "DEV" );
|
||||
m_vectorLogLevelString.push_back( "DEV1" );
|
||||
m_vectorLogLevelString.push_back( "DEV2" );
|
||||
}
|
||||
|
||||
CLogger::~CLogger()
|
||||
{
|
||||
m_vectorLogLevelString.clear();
|
||||
}
|
||||
|
||||
bool CLogger::Init( string programName, string logDir, int logLevel )
|
||||
{
|
||||
if( m_bIsInitialized == true )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
pthread_mutex_lock( &m_mutex );
|
||||
|
||||
// 변수 유효성 검사.
|
||||
if( programName.empty() == true || logDir.empty() == true )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( MakeLogDir( programName, logDir ) == false )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( CLogger::m_pInstance != NULL )
|
||||
{
|
||||
delete CLogger::m_pInstance;
|
||||
CLogger::m_pInstance = NULL;
|
||||
}
|
||||
|
||||
CLogger::m_pInstance = new CLogger( programName, logDir, logLevel );
|
||||
m_bIsInitialized = true;
|
||||
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::IsValidLogLevel( int logLevel )
|
||||
{
|
||||
return ( ( logLevel < 0 || logLevel > MAX_LOG_LEVEL ) ? false : true );
|
||||
}
|
||||
|
||||
bool CLogger::SetLogLevel( int logLevel )
|
||||
{
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_nLogLevel = logLevel;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::MakeLogDir( string programName, string logDir )
|
||||
{
|
||||
string path = logDir + "/" + programName;
|
||||
|
||||
struct stat dirStat;
|
||||
|
||||
// 해당 이름을 가진 파일 또는 디렉토리가 존재하고
|
||||
if( lstat( path.c_str(), &dirStat ) == 0 )
|
||||
{
|
||||
// 해당 이름이 디렉토리인 경우
|
||||
if( S_ISDIR( dirStat.st_mode ) == true )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "exist file with the same name as log path(" << path << ")." << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 디렉토리 가 존재하지 않는 경우 디렉토리 생성 시도
|
||||
string cmd = "mkdir -p " + path;
|
||||
system( cmd.c_str() );
|
||||
|
||||
if( IsDirectory( path ) == false )
|
||||
{
|
||||
cerr << "can't make log directory. path=" << path << "." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::IsDirectory( string path )
|
||||
{
|
||||
struct stat dirStat;
|
||||
|
||||
if( lstat ( path.c_str(), &dirStat ) != 0 )
|
||||
{
|
||||
cerr << "Log path not valid. Check path [" << path << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 해당 정보가 Directory 가 아닌 경우
|
||||
if( S_ISDIR( dirStat.st_mode ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLogger::Exit()
|
||||
{
|
||||
if( m_bIsInitialized == false )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock( &m_mutex );
|
||||
|
||||
if( CLogger::m_pInstance != NULL )
|
||||
{
|
||||
delete CLogger::m_pInstance;
|
||||
CLogger::m_pInstance = NULL;
|
||||
m_bIsInitialized = false;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
}
|
||||
|
||||
CLogger* CLogger::GetInstance()
|
||||
{
|
||||
return CLogger::m_pInstance;
|
||||
}
|
||||
|
||||
string CLogger::GetLogFilename( struct tm &timeNow )
|
||||
{
|
||||
char timeStr[256];
|
||||
snprintf( timeStr, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
|
||||
|
||||
// Make File Name
|
||||
string filename = m_szLogDir + "/" + m_szProgramName + "/" + m_szProgramName + "_" + string( timeStr );
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool CLogger::Write( int logLevel, const char * fmt, ...)
|
||||
{
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return Write( logLevel, PREFIX_DATE, NULL, 0, buffer );
|
||||
}
|
||||
|
||||
bool CLogger::WriteNoPrefix( int logLevel, const char * fmt, ...)
|
||||
{
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return Write( logLevel, PREFIX_NONE, NULL, 0, buffer );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// CHG 2012-08-16 huibong
|
||||
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
|
||||
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
|
||||
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
|
||||
// 함수명 : Write -> WriteWithFunc 으로 변경 처리
|
||||
bool CLogger::WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
|
||||
{
|
||||
if( filename == NULL || funcname == NULL || lineNum < 0 || fmt == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
|
||||
char className[255];
|
||||
string funcPrefix = GetClassName( className, filename );
|
||||
funcPrefix += "::" + string( funcname ) + "()";
|
||||
|
||||
return Write( logLevel, PREFIX_FUNCTION, funcPrefix.c_str(), lineNum, buffer );
|
||||
}
|
||||
|
||||
const char* CLogger::GetClassName( char* className, const char* filename )
|
||||
{
|
||||
if( className == NULL )
|
||||
{
|
||||
cout << "[ERROR] The input argument 'className' is NULL." << endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( filename == NULL )
|
||||
{
|
||||
cout << "[ERROR] The input argument 'filename' is NULL." << endl;
|
||||
strcpy( className, "NULL" );
|
||||
return className;
|
||||
}
|
||||
|
||||
int filenameSize = strlen( filename );
|
||||
memcpy( className, filename, filenameSize );
|
||||
|
||||
// find end position
|
||||
char endCharacter = '.';
|
||||
int endPos = filenameSize - 1;
|
||||
for( ; endPos > 0; --endPos )
|
||||
{
|
||||
if( className[endPos] == endCharacter )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( endPos == 0 )
|
||||
{
|
||||
cout << "[ERROR] endPos=0" << endl;
|
||||
strcpy( className, "NULL" );
|
||||
return className;
|
||||
}
|
||||
|
||||
className[endPos] = '\0';
|
||||
|
||||
// find start position
|
||||
char startCharacter = '/';
|
||||
int startPos = endPos - 1;
|
||||
for( ; startPos > 0; --startPos )
|
||||
{
|
||||
if( className[startPos] == startCharacter )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( startPos != 0 )
|
||||
{
|
||||
startPos += 1;
|
||||
}
|
||||
|
||||
return (className + startPos );
|
||||
}
|
||||
|
||||
bool CLogger::Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log )
|
||||
{
|
||||
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
|
||||
if( logLevel > m_nLogLevel )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( log == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Current Data & Time
|
||||
time_t now = time( NULL );
|
||||
struct tm timeNow;
|
||||
localtime_r( &now, &timeNow );
|
||||
|
||||
string filename = GetLogFilename( timeNow );
|
||||
|
||||
// Log file open
|
||||
FILE* pFile = NULL;
|
||||
pFile = fopen( filename.c_str(), "a+" );
|
||||
|
||||
if( pFile == NULL )
|
||||
{
|
||||
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 시간 정보처리
|
||||
char timeStr[256];
|
||||
snprintf( timeStr, (size_t)256, "[%02d:%02d:%02d]"
|
||||
, timeNow.tm_hour, timeNow.tm_min, timeNow.tm_sec );
|
||||
|
||||
// Log Level 문자열 검색
|
||||
string szLevel = m_vectorLogLevelString[ logLevel ];
|
||||
|
||||
switch( logPrefix )
|
||||
{
|
||||
case PREFIX_DATE:
|
||||
/// 형식 예: [15:47:41] [DBG] sample log message.
|
||||
fprintf( pFile, "%s [%-4s] %s\n", timeStr, szLevel.c_str(), log );
|
||||
break;
|
||||
|
||||
case PREFIX_FUNCTION:
|
||||
if( functionName == NULL )
|
||||
{
|
||||
fclose( pFile );
|
||||
return false;
|
||||
}
|
||||
/// 형식 예: [15:47:41] [DBG] sample log message. [SomeClass::SomeFunction():12]
|
||||
fprintf( pFile, "%s [%-4s] %s [%s:%d]\n", timeStr, szLevel.c_str(), log, functionName, lineNum );
|
||||
break;
|
||||
|
||||
case PREFIX_NONE:
|
||||
/// 형식 예: sample log message.
|
||||
fprintf( pFile, "%s\n", log );
|
||||
break;
|
||||
}
|
||||
// Write to log file
|
||||
fflush( pFile );
|
||||
|
||||
// 종료 처리.
|
||||
fclose( pFile );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::WriteHex( int logLevel, const unsigned char* data, const int size )
|
||||
{
|
||||
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
|
||||
if( logLevel > m_nLogLevel )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( data == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( size <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Current Data & Time
|
||||
time_t now = time( NULL );
|
||||
struct tm timeNow;
|
||||
localtime_r( &now, &timeNow );
|
||||
|
||||
string filename = GetLogFilename( timeNow );
|
||||
|
||||
// Log file open
|
||||
FILE* pFile = NULL;
|
||||
pFile = fopen( filename.c_str(), "a+" );
|
||||
|
||||
if( pFile == NULL )
|
||||
{
|
||||
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for( int i = 0; i < size; ++i )
|
||||
{
|
||||
fprintf( pFile, "%02X", data[i] );
|
||||
|
||||
if( i == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( (i+1) % 8 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, " " );
|
||||
}
|
||||
|
||||
if( ( (i+1) % 16 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, " " );
|
||||
}
|
||||
|
||||
if( ( (i+1) % 32 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, "\n" );
|
||||
}
|
||||
}
|
||||
fprintf( pFile, "\n" );
|
||||
fflush( pFile );
|
||||
|
||||
// 종료 처리.
|
||||
fclose( pFile );
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
/***************************************************************************
|
||||
Logger.h
|
||||
-----------------------------------------
|
||||
begin : 2011/10/26
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 3.2.0.805
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
#ifndef __LOGGER_H__
|
||||
#define __LOGGER_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <pthread.h>
|
||||
|
||||
///@brief 로그 레벨 정의
|
||||
#define LEMR 0 /* system is or will be unusable if situation is not resolved */
|
||||
#define LALT 1 /* immediate action required */
|
||||
#define LCRT 2 /* critical situations */
|
||||
#define LERR 3 /* error conditions */
|
||||
#define LWAR 4 /* recoverable errors */
|
||||
#define LNOT 5 /* unusual situation that merits investigation */
|
||||
#define LINF 6 /* information messages */
|
||||
#define LDBG 7 /* verbose data for debugging */
|
||||
#define LDEV 8 /* verbose data for developer */
|
||||
#define LDEV1 9 /* start or end the function of application level */
|
||||
#define LDEV2 10 /* start or end the function of application level */
|
||||
|
||||
#define MAX_LOG_LEVEL LDEV2
|
||||
|
||||
|
||||
///@brief Log 정보를 파일로 저장하기 위한 Class.
|
||||
///1. 가변 format 으로 전달된 로그 관련 정보를 Log Level 에 따라 로그 파일에 아래의 4가지 형식으로 저장한다.
|
||||
///
|
||||
/// 1.1 Prefix로 [hh:mm:ss]와 [ClassName::FunctionName]이 추가된 로그
|
||||
/// LOG( level, format, ... ) 매크로 사용.
|
||||
/// 예) [17:43:40] [DBG] log level debug [LoggerTestTestLogger]
|
||||
///
|
||||
/// 1.2 Prefix로 [hh:mm:ss]이 추가된 로그
|
||||
/// _LOG( level, format, ... ) 매크로 사용
|
||||
/// 예) [17:43:40] [EMR] log level emergency
|
||||
///
|
||||
/// 1.3 Prefix가 없는 로그
|
||||
/// _LOG_( level, format, ... ) 매크로 사용
|
||||
/// 예) log level emergency
|
||||
///
|
||||
/// 1.4 Hex 로그.
|
||||
/// LOG_HEX( level, data, size ) 매크로 사용
|
||||
/// 예) 00010203 04050607 08090A0B 0C0D0E0F
|
||||
///
|
||||
///2. Logger 객체 초기화시 전달된 Log Level 정보보다 전달받은 Log Level 정보가 큰 경우 해당 로그는 파일로 저장되지 않는다.
|
||||
///
|
||||
///3. 로그 파일은 매 일단위로 저장파일이 변경된다.
|
||||
///
|
||||
///4. 로그 저장을 위한 program 경로가 존재하지 않는 경우 자동 생성 처리된다.
|
||||
///
|
||||
///5. 로그 저장방식은 매 저장로그마다 open-close 로 처리된다.
|
||||
///
|
||||
///6. 파일로 기록시 Log Level 에 대한 정보도 함께 기록된다.
|
||||
///
|
||||
///7. 싱글톤으로 작성되었고, CLogger::Init(...)시에 쓰레드 안정성을 제공한다.
|
||||
///
|
||||
///8. 동적으로 로그 레벨을 변경할 수 있는 인터페이스를 제공한다.
|
||||
///
|
||||
class CLogger
|
||||
{
|
||||
// Attributes
|
||||
private:
|
||||
///@brief 싱글톤 객체 인트턴스.
|
||||
static CLogger* m_pInstance;
|
||||
|
||||
///@brief 싱글톤 객체 초기화 여부.
|
||||
static bool m_bIsInitialized;
|
||||
|
||||
///@brief 싱글톤 객체 초기화시 스레드 안정성을 위한 뮤텍스.
|
||||
static pthread_mutex_t m_mutex;
|
||||
|
||||
///@brief 프로그램 이름. 로그 파일 경로를 만들 때 사용.
|
||||
std::string m_szProgramName;
|
||||
|
||||
///@brief 공통 로그 디렉토리 이름. 로그 파일 경로를 만들 때 사용.
|
||||
std::string m_szLogDir;
|
||||
|
||||
///@brief 로그 레벨.
|
||||
int m_nLogLevel;
|
||||
|
||||
///@brief 로그 레벨에 대응되는 문자열 정보를 저장.
|
||||
std::vector<std::string> m_vectorLogLevelString;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
///@brief 로그 형식을 지정.
|
||||
typedef enum
|
||||
{
|
||||
PREFIX_NONE = 0, /// 클래스 설명의 1.3에 해당
|
||||
PREFIX_DATE, /// 클래스 설명의 1.2에 해당
|
||||
PREFIX_FUNCTION, /// 클래스 설명의 1.1에 해당
|
||||
} LOG_PREFIX;
|
||||
|
||||
// Operations
|
||||
private:
|
||||
///@brief 생성자.
|
||||
/// 프로그램 이름, 공통 로그 디렉토리, 로그 레벨을 저장하고
|
||||
/// 로그 레벨에 대응되는 문자열 정보를 만든다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@param logLevel [in] 로그 레벨
|
||||
CLogger( std::string programName, std::string logDir, int logLevel );
|
||||
|
||||
///@brief 소멸자.
|
||||
/// 로그 레벨에 대응되는 문자열 정보를 저장하고 있는
|
||||
/// 벡터 m_vectorLogLevelString을 clear 시킴.
|
||||
virtual ~CLogger();
|
||||
|
||||
///@brief 로그 레벨에 대응되는 문자열을 만든다.
|
||||
///@param none.
|
||||
///@return none.
|
||||
void MakeLogLevelString();
|
||||
|
||||
///@brief 로그 파일이 위치할 실제 로그 디렉토리를 생성한다.
|
||||
/// 생성할 디렉토리 경로는 'logDir/programName'이 된다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@return 디렉토리가 이미 존재하거나 생성 성공하면 true,
|
||||
/// 해당 경로가 존재하지만 디렉토리가 아니거나, 디렉토리 생성 실패하면 false 반환.
|
||||
static bool MakeLogDir( std::string programName, std::string logDir );
|
||||
|
||||
///@brief 해당 경로가 디렉토리 인지 아닌지 판단.
|
||||
///@param path [in] 디렉토리 인지 아닌지 판단할 경로.
|
||||
///@return 해당 경로가 디렉토이면 true,
|
||||
/// 경로가 존재하지 않거나 디렉토리가 아니면 false 반환.
|
||||
static bool IsDirectory( std::string path );
|
||||
|
||||
///@brief 로그 레벨이 올바른지 판별.
|
||||
///@param logLevel [in]
|
||||
///@return 올바른 로그 레벨이면 true, 그렇지 않으면 false 반환.
|
||||
static bool IsValidLogLevel( int logLevel );
|
||||
|
||||
///@brief 시간 정보를 입력 받아 로그 파일 이름을 만든다.
|
||||
/// 로그 파일 이름 형식 : 프로그램명_YYYYMMDD.log
|
||||
///param timeNow [in] 현재 시간 정보.
|
||||
///return 로그 파일 이름.
|
||||
std::string GetLogFilename( struct tm &timeNow );
|
||||
|
||||
///@brief 로그를 남기는는 클래스가 정의된 파일의 이름에서 클래스명을 추출한다.
|
||||
/// 쓰레드 안정성을 보장한다.
|
||||
///@param className [out] 파일 이름에서 추출된 클래스명
|
||||
///@param filename [in] 파일 이름.
|
||||
///@return 클래스명 추출이 성공하면 클래스명 문자열의 포인터, 추출 실패하면 NULL.
|
||||
const char* GetClassName( char* className, const char* filename );
|
||||
|
||||
///@brief 인자 logPrefix에 따라 적절한 형식으로 로그 파일에 로그를 저장한다.
|
||||
/// 인자 logLevel이 설정된 로그 레벨보다 높으면 로그를 출력하지 않는다.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param logPrefix [in] 로그 프리픽스 종류.
|
||||
///@functionName [in] ClassName::FunctionNmae() 형식의 문자열.
|
||||
///@lineNum [in] 라인 번호.
|
||||
///@log [in] 출력하고자 하는 로그 내용.
|
||||
bool Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log );
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
///@brief 싱글톤 객체 m_pInstance를 생성하고 인자 정보로 로그 디렉토리를 만든다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@return 로그 디렉토리를 만들고 싱글톤 객체를 생성했으면 true,
|
||||
/// 로그 디렉토리를 만들지 못 했거나 인자 값이 올바르지 않으면 false 반환.
|
||||
static bool Init( std::string programName, std::string logDir, int logLevel );
|
||||
|
||||
///@brief 싱글톤 객체 m_pInstance를 delete 한다.
|
||||
///@param none.
|
||||
///@return none.
|
||||
static void Exit();
|
||||
|
||||
///@brief 싱글톤 객체 m_pInstance를 반환한다.
|
||||
///@param none.
|
||||
///@return CLogger 객체의 인스턴스.
|
||||
static CLogger* GetInstance();
|
||||
|
||||
///@brief Prefix로 [hh:mm:ss]이 추가된 형식으로 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool Write( int logLevel, const char * fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
///@brief Prefix가 없는 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool WriteNoPrefix( int logLevel, const char * fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
|
||||
// CHG 2012-08-16 huibong
|
||||
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
|
||||
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
|
||||
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
|
||||
|
||||
///@brief Prefix로 [hh:mm:ss]와 [ClassName::FunctionName:line]이 추가된 형식으로 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param filename [in] 파일 이름
|
||||
///@param funcname [in] 함수 이름
|
||||
///@param lineNum [in] 라인 번호
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
|
||||
__attribute__((format(printf, 6, 7)));
|
||||
|
||||
///@brief 로그를 hex 형식으로 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param data [in] hex 형식으로 출력할 데이터.
|
||||
///@pram size [in] data의 크기.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool WriteHex( int logLevel, const unsigned char* data, const int size );
|
||||
|
||||
///@brief 로그을 설정한다. 인자 logLevel이 적절한 값이면 새로운 값으로 변경하고
|
||||
/// 적절한 값이 아니면 로그 레벨을 변경하지 않는다.
|
||||
///@param logLevel [in] 설정할 로그 레벨
|
||||
///@return none.
|
||||
bool SetLogLevel( int logLevel );
|
||||
|
||||
inline int GetLogLevel() { return m_nLogLevel; };
|
||||
inline std::string GetLogDir() { return m_szLogDir + "/" + m_szProgramName; };
|
||||
};
|
||||
|
||||
#define LOG( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->WriteWithFunc( level, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->Write( level, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG_( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->WriteNoPrefix( level, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG_HEX_( level, data, size ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->WriteHex( level, (const unsigned char*)data, size ); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define FUNC_BEGIN() LOG( LDEV1, "begin" )
|
||||
#define FUNC_END() LOG( LDEV1, "end" )
|
||||
|
||||
#define FRM_BEGIN() LOG( LDEV2, "begin" )
|
||||
#define FRM_END() LOG( LDEV2, "end" )
|
||||
|
||||
#endif // __LOGGER_H__
|
||||
@@ -0,0 +1,69 @@
|
||||
#****************************************************************************
|
||||
# Makefile for Cloud Storage Common Libaray
|
||||
# -----------------------------------------
|
||||
#
|
||||
# begin : 2013/06/04
|
||||
# copyright : (C) 2013 Solbox Inc.
|
||||
# author : Development 1 Team
|
||||
# - 2013/06/04 - 1st dadamin
|
||||
# email : dev1@solbox.com
|
||||
# version : 3.3.0
|
||||
#
|
||||
# CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or with out
|
||||
# modification, are not permitted in outside of Solbox Inc.
|
||||
#*****************************************************************************
|
||||
|
||||
# Library info
|
||||
|
||||
LIB_NAME = InterCommon
|
||||
|
||||
LIB = lib$(LIB_NAME).a
|
||||
|
||||
OBJS = Config.o Logger.o BaseSocket.o
|
||||
|
||||
# Compiler info
|
||||
CC = /usr/bin/g++
|
||||
AR = /usr/bin/ar
|
||||
|
||||
DIR_INCLUDE = -I/usr/local/include
|
||||
ifeq ($(DEBUG), yes)
|
||||
CFLAGS = -Wall -O0 -g -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-D_REENTRANT -D_THREAD_SAFE -D_PTHREADS
|
||||
LFLAGS =
|
||||
DFLAGS =
|
||||
else
|
||||
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-D_REENTRANT -D_THREAD_SAFE -D_PTHREADS
|
||||
LFLAGS =
|
||||
DFLAGS =
|
||||
endif
|
||||
############################
|
||||
|
||||
all:$(LIB)
|
||||
sync
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
|
||||
$(LIB): $(OBJS)
|
||||
$(AR) crsv $@ $^
|
||||
|
||||
|
||||
clean:
|
||||
-rm -f *.o core *.out *.log
|
||||
-rm -f $(LIB)
|
||||
sync
|
||||
|
||||
|
||||
install :
|
||||
sync
|
||||
|
||||
|
||||
# End of Makefile
|
||||
@@ -0,0 +1,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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -0,0 +1,184 @@
|
||||
/***************************************************************************
|
||||
Database Class
|
||||
-----------------------------------------
|
||||
begin : 2010/03/09
|
||||
copyright : (C) 2010 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2010 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
#include "Database.h"
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
DataBase::~DataBase()
|
||||
{
|
||||
if(m_PGconn != NULL) {
|
||||
PgCloseDB();
|
||||
}
|
||||
}
|
||||
|
||||
PGconn *DataBase::PgOpenDB(string &strHost, int Port, string &strDBName, string &strAcct, string &strPasswd, int timeout)
|
||||
{
|
||||
ostringstream conninfo;
|
||||
|
||||
// CHG 2014-10-29 huibong
|
||||
// application_name add to logging RCDB
|
||||
|
||||
conninfo << "host=" << strHost << " port=" << Port << " dbname=" << strDBName <<
|
||||
" user=" << strAcct << " password=" << strPasswd << " connect_timeout=" << timeout <<
|
||||
" application_name=" << PROG_NAME;
|
||||
|
||||
#ifdef _USE_LIBPQ_KEEPALIVE
|
||||
// This option is supported by at least 9.1.2. and Currently supports Linux systems.
|
||||
conninfo <<" keepalives=1";
|
||||
#endif // _USE_LIBPQ_KEEPALIVE
|
||||
//m_PGconn = PQsetdbLogin(strHost.c_str(), szPort, NULL, NULL, strDBName.c_str(), strAcct.c_str(), strPasswd.c_str());
|
||||
m_PGconn = PQconnectdb(conninfo.str().c_str());
|
||||
if(PQstatus(m_PGconn) == CONNECTION_BAD) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_PGconn;
|
||||
}
|
||||
|
||||
PGconn *DataBase::PgOpenDB(const char *pszDBName)
|
||||
{
|
||||
m_PGconn = PQsetdb(NULL, NULL, NULL, NULL, pszDBName);
|
||||
if(PQstatus(m_PGconn) == CONNECTION_BAD) {
|
||||
return NULL;
|
||||
}
|
||||
return m_PGconn;
|
||||
}
|
||||
|
||||
void DataBase::PgCloseDB()
|
||||
{
|
||||
if(m_PGconn != NULL)
|
||||
{
|
||||
PQfinish(m_PGconn);
|
||||
m_PGconn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int DataBase::PgResult(CFLAG flag)
|
||||
{
|
||||
int fRet = 0;
|
||||
int Result;
|
||||
|
||||
Result = PQresultStatus(m_pRes);
|
||||
switch(Result) {
|
||||
case PGRES_EMPTY_QUERY :
|
||||
fRet = -1;
|
||||
break;
|
||||
case PGRES_BAD_RESPONSE :
|
||||
fRet = -2;
|
||||
break;
|
||||
case PGRES_NONFATAL_ERROR :
|
||||
fRet = -3;
|
||||
break;
|
||||
case PGRES_FATAL_ERROR :
|
||||
fRet = -4;
|
||||
break;
|
||||
case PGRES_TUPLES_OK :
|
||||
fRet = 1;
|
||||
break;
|
||||
case PGRES_COMMAND_OK :
|
||||
fRet = 2;
|
||||
break;
|
||||
}
|
||||
if(fRet < 0) {
|
||||
m_ErrorMessage = PQresultErrorMessage(m_pRes);
|
||||
}
|
||||
m_ResultCode = Result;
|
||||
if(flag == CLEAR && m_pRes) {
|
||||
PQclear(m_pRes);
|
||||
m_pRes = NULL;
|
||||
}
|
||||
return fRet;
|
||||
}
|
||||
|
||||
string &DataBase::GetErrorMessage()
|
||||
{
|
||||
return m_ErrorMessage;
|
||||
}
|
||||
|
||||
int DataBase::GetCmdTuples()
|
||||
{
|
||||
//fprintf(stderr, "DataBase::GetCmdTuples PQcmdTuples %s\n", PQcmdTuples(m_pRes));
|
||||
return (int)atoi(PQcmdTuples(m_pRes));
|
||||
}
|
||||
|
||||
int DataBase::GetNoTuples()
|
||||
{
|
||||
return PQntuples(m_pRes);
|
||||
}
|
||||
|
||||
int DataBase::GetNoFields()
|
||||
{
|
||||
return PQnfields(m_pRes);
|
||||
}
|
||||
|
||||
PGresult *DataBase::GetRes()
|
||||
{
|
||||
return m_pRes;
|
||||
}
|
||||
|
||||
void DataBase::PgClear()
|
||||
{
|
||||
if(m_pRes)
|
||||
{
|
||||
PQclear(m_pRes);
|
||||
m_pRes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *DataBase::GetValue(int tuple, int field)
|
||||
{
|
||||
return PQgetvalue(m_pRes, tuple, field);
|
||||
}
|
||||
|
||||
int DataBase::PgDoExec(char *pszQuery)
|
||||
{
|
||||
return this->PgDoExec(pszQuery, NOT_CLEAR);
|
||||
}
|
||||
|
||||
int DataBase::PgDoExec(string &strQuery)
|
||||
{
|
||||
return this->PgDoExec((char *)strQuery.c_str(), NOT_CLEAR);
|
||||
}
|
||||
|
||||
int DataBase::PgDoExec(char *pszQuery, CFLAG flag)
|
||||
{
|
||||
if(m_PGconn == NULL) return -1;
|
||||
if(PQstatus(m_PGconn) != CONNECTION_OK) return -2;
|
||||
m_pRes = PQexec(m_PGconn, pszQuery);
|
||||
int r = PgResult(flag);
|
||||
return r;
|
||||
}
|
||||
|
||||
int DataBase::PgDoExecParams(char *pszQuery, int nParamCnt, const char * const *paramValues ,CFLAG flag)
|
||||
{
|
||||
if(m_PGconn == NULL) return -1;
|
||||
if(PQstatus(m_PGconn) != CONNECTION_OK) return -2;
|
||||
m_pRes = PQexecParams(m_PGconn, pszQuery, nParamCnt, NULL, paramValues, NULL, NULL, 0);
|
||||
int r = PgResult(flag);
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
int DataBase::PgEscapeString(char *to, const char *from, size_t length)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
//PQescapeStringConn(m_PGconn, to, from, length, &retval);
|
||||
PQescapeString(to, from, length);
|
||||
return retval;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
Database Class
|
||||
-----------------------------------------
|
||||
begin : 2010/03/11
|
||||
copyright : (C) 2010 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2010 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
#ifndef __DATABASE_H__
|
||||
#define __DATABASE_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "libpq-fe.h"
|
||||
#define MaxSizeOfDBQuery 1024*9
|
||||
|
||||
using namespace std;
|
||||
class DataBase
|
||||
{
|
||||
public:
|
||||
enum CFLAG { CLEAR = 1, NOT_CLEAR };
|
||||
DataBase() { m_PGconn = NULL; m_pRes = NULL;}
|
||||
~DataBase();
|
||||
PGconn *PgOpenDB(string &strHost, int Port, string &strDBName, string &strAcct, string &strPasswd, int timeout = 10);
|
||||
PGconn *PgOpenDB(const char *pszDBName);
|
||||
void PgCloseDB();
|
||||
int PgResult(CFLAG flag);
|
||||
PGconn *GetPgConn(){ return m_PGconn;}
|
||||
PGresult *GetRes();
|
||||
void SetRes(PGresult * v) {m_pRes = v;}
|
||||
int GetCmdTuples();
|
||||
int GetNoTuples();
|
||||
int GetNoFields();
|
||||
int GetResultCode() { return m_ResultCode; }
|
||||
char *GetValue(int tuple, int field);
|
||||
void PgClear();
|
||||
int PgDoExec(string &strQuery);
|
||||
int PgDoExec(char *pszQuery);
|
||||
int PgDoExec(char *pszQuery, CFLAG flag);
|
||||
int PgDoExecParams(char *pszQuery, int nParamCnt, const char * const *paramValues ,CFLAG flag = NOT_CLEAR);
|
||||
int PgEscapeString(char *to, const char *from, size_t length);
|
||||
string &GetErrorMessage();
|
||||
private:
|
||||
int m_ResultCode;
|
||||
PGconn *m_PGconn;
|
||||
PGresult *m_pRes;
|
||||
string m_ErrorMessage;
|
||||
};
|
||||
|
||||
#endif // ~__DATABASE_H__
|
||||
@@ -0,0 +1,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;
|
||||
}
|
||||
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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 //
|
||||
@@ -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__
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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__
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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) );
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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__
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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__
|
||||
Reference in New Issue
Block a user