This commit is contained in:
biosvos
2026-08-07 17:38:18 +09:00
commit 873193a243
9613 changed files with 2755992 additions and 0 deletions
+573
View File
@@ -0,0 +1,573 @@
Revision 1534
-------------------
수정일 : 2021-04-19
수정자 : 유희곤
- NEW: content 에 대한 size, atime, mtime, ctime 추출 기능 추가 (#33516)
- stat 함수를 이용하여 content 에 대한 size, access, modify, change time 정보 추출 기능 추가
- 이와 관련 interface 함수도 추가 처리.
Revision 1430
-------------------
수정일 : 2017-12-26
수정자 : 유희곤
- BUG: Disk 일부 장애 상황에서 content read 관련 버그 수정 (#31633)
- content read 관련 반환값을 size_t (unsigned int) 형으로 사용하여
- 실제 오류 발생시 음수값 반환 상황을 인지하지 못함.
- 이에 관련 코드 수정 처리
- 해당 상황 발생시 호출한 control 프로세스로 오류 내역 보고하도록 처리.
- 수정 파일: FileSender.cpp
Revision 1364
-------------------
수정일 : 2016-05-12
수정자 : 유희곤
- NEW: 고객사 토토디스크 지원용 File Check 기능 추가 (#27533)
- 토토디스크 지원 관련 Revision 1358 에서 추가한 MD5 Hash 추출 기능 이외에
- Checksum , DNA CHECK Key 값 추출 기능 추가.
- 추가 기능은 토토디스크에서 제공한 JAVA 소스 분석을 통해 기능 추가 및 JAVA 와 result 비교 처리 완료.
- 수정 파일: FileHash.h FileHash.cpp SocketControl.h SocketControl.cpp Worker.h Worker.cpp
- 추가 파일: TOTOChecksum.h TOTOChecksum.cpp
- CHG: 토토디스크 지원을 위한 Client interface 기능 추가 (#27533)
- 토토디스크 관련 ftsd 와 통신 프로토콜 수정 및 전달 기능 추가.
- 수정파일: FtsdSocketControl.h FtsdSocketControl.cpp
- CHG: Client interface 의 Data 수신 Timeout 관련 기능 수정
- 프로토콜 형식이 일치하지 않는 경우... Data 수신 처리시 alive check 로 인한 timeout 처리 미발생.
- 이는 수신 처리 timeout 이 기본 15 sec 인데.. 5 sec 마다 alive check 가 동작하여 timeout 이 미발생함.
- 이를 해결하지 위해 data body 수신 처리시.. timeout 을 2 sec 로 지정 처리함.
- 수정파일: FtsdSocketControl.cpp
- CHG: 문서 인코딩 관련 오류 파일 수정
- 수정 파일: LocalIPCache.cpp ProcessStatus.cpp
Revision 1358
-------------------
수정일 : 2016-05-09
수정자 : 유희곤
- NEW: 고객사 토토디스크 지원용 MD5 Hash 추출기능 추가 (#27460)
- 토토디스크 MD5 Hash 추출 관련 JAVA 소스 분석을 통한 기능 추가
- 토토디스크 MD5 Hash 추출 관련 통신 CONTROL_FILE_CHECK_TOTO 프로토콜 및 관련 기능 추가
- 수정 파일: Protocol.h SocketControl.h SocketControl.cpp Worker.h Worker.cpp FileHash.h FileHash.cpp
- CHG: FreeBSD 10.3 컴파일 관련 header 추가
- 수정 파일: LocalIPCache.cpp ProcessStatus.cpp
Revision 1235
-------------------
수정일 : 2015-09-14
수정자 : 유희곤
- CHG: 최신 BaseSocket 모듈 적용 (#24376, #24141)
- EPIPE 및 usleep 관련 수정 버전 적용
- 수정 파일: lib/BaseSocket.cpp
- CHG: usleep -> nanosleep 변경 (#24376)
- multi thread 에서 lock 관련 문제점 발생 가능.
- 프로세스 기동 및 시그널 처리에서만 사용하여... thread 와 연관 없지만.. 수정 처리함.
- 수정 파일: Listener.cpp, Worker.cpp
- CHG: Main 버전 (3.5.0) 변경 사항 적용
- 기존 3.4.0 -> 3.5.0 으로 버전 변경 처리.
Revision 1207
-------------------
수정일 : 2015-06-17
수정자 : 유희곤
- CHG: Content 저장 위치에 해당 물리파일이 이미 존재하는 경우 overwrite 대신 복합 처리 방식 사용 (#22892)
- 원본, 복제본 등의 overwrite 방지 목적
- rc_gcmd 동작으로 인해 물리 파일이 자동으로 정리되므로.. 기존과 같이 overwrite 사용할 필요 없어짐.
- 물리 Size 가 다른 경우.. 실패 처리
- 물리 Size 가 동일할 경우... overwrite 생략.. 기존 물리 파일 그대로 사용.
- 수신 완료 처리 후 물리 파일 size 체크 기능 신규 추가
- 이후 기존과 같이 hash, size 체크가 동작하도록 처리.
- 수정파일: SocketControl.cpp, SocketControl.h
Revision 1192
-------------------
수정일 : 2015-03-27
수정자 : 유희곤
- BUG: /stg 로 설정, mount 정보가 /stg/node0 1개인 경우 proper 경로가 /stg 로 선택되는 오류 수정 (#21917)
- mount 정보가 1개인 경우.
- 설정값과 추출된 mount 정보 중 길이가 큰 값을 사용하도록 수정 처리
- 수정파일 : ProperStorage.cpp
Revision 1123
-------------------
수정일 : 2014-11-17
수정자 : 유희곤
- CHG: DNS resolve 실패시 Retry 기능 추가 (#20783)
- 통신 접속 관련 lib/CBaseSocket 모듈에서
- getaddrinfo() 의 DNS resolve 실패가 자주 발생함.
- 오류코드 FreeBSD : EAI_NONAME(8), Linux: EAI_AGAIN(-3)
- 이에 3회 재시도 기능 추가
- 수정파일: lib/BaseSocket.cpp
Revision 1114
-------------------
수정일 : 2014-11-03
수정자 : 유희곤
- CHG: Directory 생성시 chown to nobody 기능 추가 (일감 #20663)
- ftsd 에 의해 서비스 폴더가 생성된 경우.. Apache 접근 불가 발생.
- 이에 Directoy 생성 후 nobody 사용자가 접근할 수 있도록 chown 처리 기능 추가
- 그 외 cache 폴더인 경우.. mkdir -p 옵션 미사용으로 인해... 자동 생성 불가
- 따라서 파일 수신 처리시 cache 폴더 생성되도록 코드 추가함.
- CHG: Main 버전 변경
- 기존 3.3.0 -> 3.4.0 으로 버전 변경 처리.
Revision 0993
-------------------
수정일 : 2014-05-27
수정자 : 유희곤
- BUG: 작업 Thead 의 비정상 상태 관련 버그 (일감 #19102)
- CFileSender 클래스 소멸자에서 다른 thread 에 대해 pthread_cancel 호출로 인한 문제발생
- CFileSender 내 pthread_t 에 대한 OS 별 초기화 및 조건별 처리토록 기능 추가, 수정
- 그 외 pthread_cancel() 사용 모듈에 대한 점검 및 주석 추가.
- CHG: ProperStorage 모듈 로그 정리 및 가독성 향상
- 실서비스 투입 후 정상 동작 확인에 따른 불필요한 Information 로그 정리
- Debug 로그 정리
- 로그 Format 정리
- CHG: BaseSocket 모듈 Connect() 함수의 SO_LINGER 옵션 변경
- 수많은 TCP TIME_WAIT 발생을 억제하기 위해 Revision 0771 에서 적용되었으나...
- Socket Server 가 Client 의 Close 신호를 전달받지 못하는 경우가 발생 가능함 (rc_statd2 개발시 확인된 내역)
- 따라서 l_linger 설정값을 0 (No Wait) -> 5 sec 대기토록 옵션 변경함.
- CHG: Worker.cpp 로그 출력 내역 정리
- 가독성 향상을 위해 출력 로그 내역 정리
Revision 0961
-------------------
수정일 : 2014-03-06
수정자 : 유희곤
- BUG: 로그 Write 중 시스템 먹통 현상 관련 수정 (일감 #17905)
- std::string.append() 함수 관련 잘못된 인자값 사용으로 인해 core 발생.
- 이와 관련하여 전체 소스 검사 후 수정 처리.
- 수정파일: SocketControl.cpp
- CHG: OS 의존성 제거 (일감 #17662, #18017)
- FreeBSD 10.X 지원 관련 OS 의존성 제거를 위해 geom, devstat 이용 관련 최적 Mount 정보 추출 기능 제거
- FreeBSD 6.2, FreeBSD 10.0, CentOS 5.4 에서도 동작하도록 최적 Mount 추출 관련 ProperStorage 모듈 재개발
- FreeBSD 에서는 getmntinfo(), Linux 에서는 getmntent_r() 을 사용토록 개발 완료.
- FreeBSD 6.2, FreeBSD 10.0, CentOS 5.4 에서 정상 동작 확인 완료.
- ProperStorage.h ProperStorage.cpp Makefile
- CHG: Worker 프로세스 초기화 실패시 프로세스 종료 기능 추가.
- Worker 프로세스 초기화 실패시... 무한 재기동 발생으로 인해 기능 수정
- CHG: Mount disable 검사 기능 추가
- 최적 Mount 선택시 Mount disable 여부( /stg/node0.disable) 검사 기능 추가.
- CHG: 파일 수신시 파일 Size 와 Mount 저장 가능 Size 비교 업무 Flow 추가.
- 파일 수신시 파일 size 와 저장 가능한 Mount 여유 공간 size 비교 후.
- 저장 불가능할 경우.. 오류 전달 기능 추가.
- CHG: Mutex 초기화 수정
- Linux OS 호환을 위해 Mutex 초기화 관련 PTHREAD_MUTEX_INITIALIZER -> pthread_mutex_init() 로 변경 처리.
- CHG: 기타
- FreeBSD 6.2, FreeBSD 10.0, CentOS 5.4 Cross 컴파일 관련 include 조정.
- pthread handle 처리 관련 Linux 호환을 위해 NULL 연산 수정 처리.
- GCC 버전업에 따른 warning 발생 관련 Makefile 상에서 -Wimplicit 옵션 제거
- 불필요한 미사용 변수 제거 처리.
- CHG: Main 버전 변경
- 기존 3.2.0 -> 3.3.0 으로 버전 변경 처리.
Revision 0858
-------------------
수정일 : 2013-03-19
수정자 : 유희곤
- BUG: thread 관련 pthread_exit() 호출로 인한 메모리 누수
- deatch 된 thread 에 pthread_exit() 호출로 인해 자원 반납이 제대로 처리되지 않아 메모리 누수 발생
- 이와 관련된 pthread_exit() 코드 제거 및 return NULL 로 수정 처리
- FileSender.cpp ProperStorage.cpp Worker.cpp 수정 처리 완료.
- CHG: 초기화되지 않은 변수 초기화
- FileSender.cpp CFileSender class 의 멤버변수 m_threadHandle 초기화 처리 (valgrind 보고 내역)
- CHG: ftsd/interface/sample 상의 테스트 코드 수정
- 기능 테스트를 쉽게 할 수 있도록 테스트 코드 추가 및 수정.
Revision 0837
-------------------
수정일 : 2012-11-15
수정자 : 유희곤
- CHG: Revision 832 에서 수정된 Logger.h 적용
- 인자 유효성 점검 기능이 추가된 ./lib/Logger.h 를 적용함. ( Revision 832 참고 )
- 이로 인해 Compile 시 Warning 이 발생하는 코드를 전부 수정 처리함.
- TargetFhsInfo.cpp, Worker.cpp 수정 처리 완료.
- CHG: 프로세서 상태 정보 표시시 공백 관련 수정.
- ProcessStatus.cpp 상에서 화면에 표시되는 setproctitle() 함수 호출 관련 불필요한 공백 제거
Revision 0811
-------------------
수정일 : 2012-09-04
수정자 : 유희곤
- NEW: 파일에 대한 unlink 처리시 강제 삭제 처리 기능 추가
- unlink 관련 모드 정보를 전달받아 처리하도록 기능 추가함.
- 제어 모듈을 위한 Interface 함수 수정.
- CHG: 수정된 Logger 처리 모듈 적용
- 일감 #10138 에서 수정된 Logger 모듈 (Revision 805) 적용 처리.
Revision 0803
-------------------
수정일 : 2012-08-14
수정자 : 유희곤
- NEW: 파일에 대한 Check ( Size, Hash ) 기능 및 인터페이스 추가
- 요청 파일에 대한 존재 여부 확인 및 Size 정보 추출, Hash 정보 추출 기능 추가.
- 제어 모듈을 위한 Interface 함수 추가.
- NEW: 파일에 대한 Unlink 기능 및 인터페이스 추가
- 요청 파일에 대한 unlink 처리 기능 추가
- 제어 모듈을 위한 Interface 함수 추가
- CHG: 양방향 Main 버전 (3.2.0) 변경 사항 적용
- 기존 3.1.0 -> 3.2.0 으로 버전 변경 처리.
Revision 0771
-------------------
수정일 : 2012-05-25
수정자 : 유희곤
- NEW: 파일 Write 처리시 lock 처리 기능 추가. ( #8159 참고 )
- 동일 파일에 대한 동시 write 발생 가능으로 인해.. write 처리전 lock 획득 후 write 하도록 기능 추가.
- 사용된 file lock 은 lockf() 함수이며.. lock 획득 실패시 5 sec 대기 후 재시도.. 재시도에서 실패할 경우 작업 실패로 처리함.
- SocketControl.cpp 의 ReceiveToFile() 함수 수정처리.
- CHG: 무수히 많은 TIME_WAIT 상태 발생 ( #9021 )
- ftsd 가 많은 세션을 생성 처리할 경우 tcp 세션 종료시 TIME_WAIT 상태가 많이 발생 가능.
- 이를 방어하기 위해 client socket 생성시 SO_LINGER 옵션을 설정 처리함.
- lib/BaseSocket.cpp 의 Connect() 함수 수정
- CHG: TCP 접속시 DNS resolve 실패 발생 관련 오류 내역 로깅 보강
- getaddrinfo() 함수를 이용시 DNS resolve 실패가 발생할 경우..
- 해당 상세 내역으로 로깅 처리토록 기능 수정 처리.
- lib/BaseSocket.cpp 의 ConversionAddr() 함수 수정
- CHG: Worker 프로세스의 core 발생 시그널 처리기 변경
- Worker 프로세스의 문제점 발생시 문제점 분석을 용이하도록 core 발생 시그널에 대한 핸들함수를 시스템 기본으로 변경 처리.
- 기존 core 발생 시그널에 대해 핸들러를 처리할 경우.. 문제가 발생한 부분에 대한 core dump 분석이 제대로 안되는 문제점 해결 목적.
- Worker.cpp 의 SetSignalWorker() 함수
- CHG: "Connection already closed" 로그 제거
- Client Socket 의 종료 여부 판단을 위해 추가한 로그 문자열이 불필요하게 많이 발생하여.. 제거 처리.
- SocketControl.cpp 의 GetPacketHeader() 함수.
- CHG: "File already exists" 로그의 Level 을 Warning 으로 변경.
- File write 처리시 동일 파일의 존재 유무를 판단하여.. 로깅 처리하는 부분이 ERR 로 처리되어..혼동 발생 가능.
- 이로 인해 해당 메시지의 Log Level 을 Error -> Warning 으로 변경 처리.
- SocketControl.cpp 의 ReceiveFile() 함수.
Revision 0668
-------------------
수정일 : 2012-02-07
수정자 : 유희곤
- CHG: Logger 처리 객체 변경 및 관련 코드 수정
- 서비스 1팀 공통 Logger 클래스 ( singleton 방식) 적용 및 관련 코드 수정
- Log 메시지 관련 알아보기 쉽도록 부분 수정 처리.
- CHG: inet_ntoa() 함수의 Thread-safe 문제점으로 인해 inet_ntop() 함수로 수정
- LocalIPCache.cpp, Worker.cpp 상에 관련 코드 수정 처리
- CHG: Target FHS 와 Source FHS 가 동일한 장비인지 비교 및 방어 코드 추가
- Target FHS 와 Source FHS 가 동일 FHS 장비일 경우 원본 Content 유실 등의 문제 발생 가능
- 이를 방어하기 위해 FileSender.cpp::Init() 함수상에 hostname 비교 처리 로직 추가함.
- BUG: Control 프로세스로 무응답 발생 관련 버그 수정
- Content 전송 완료 후 Content Size 여부 재검사 로직 수행시
- Content 변경이 감지되어 작업 실패가 발생할 경우 이를 Control 프로세스로 보고하는 코그가 없어
- Control 프로세스가 무한 대기되는 현상이 발생..
- 이에 대한 Bug 수정 처리함
- FileSender.cpp SendFileToFhs() 함수내의 업무 flow 수정 처리
- BUG: 잘못된 protocol 형식을 수신할 경우 CPU, Memory 점유율 증가 관련 문제 해결
- 잘못된 형식의 Packet Header 정보 반복 수신시 CPU, Memory 사용률 증가 현상 발생
- 이를 방어하기 위해 SocketControl.cpp 의 GetPacketHeader() 함수 반환값을 다양화하고...
- 각 업무 Flow 상에서 판단하여 강제로 Connnection 을 Close 하도록 수정 완료
- SocketControl.h SocketControl.cpp 함수 수정 처리
- CHG: 불필요한 테스트용 파일 제거
- src/get_ip_from_nic.cpp
- src/tael.cpp
- src/tael.sh
- src/propertest.cpp
- src/test.cpp
- src/threadtest.cpp
- CHG: 버전 정보 변경
- 기존 3.0.1 버전 정보를 3.1.0 으로 수정 처리
- CHG: 기타 Compile 관련 부분
- Makefile 상에 불필요한 정보 삭제 처리
- Warning 발생 관련 부분 수정 처리
Revision 0553
-------------------
수정일 : 2011-05-24
수정자 : 김오종
- BUG: 설정 파일의 FILE_STORAGE_ROOT가 /stg일때 geom에서 정보를 못 가져올 경우 root 경로 disk full
현상에 대한 방어 코드 추가.
- FILE_STORAGE_ROOT 가 /stg 또는 /stg/ 가 아닌경우 하나의 디스크로 인정.
- FILE_STORAGE_ROOT 가 /stg 또는 /stg/ 일 경우 geom에서 정보를 못 가져온 경우.
-> 최초에는 /stg/node0 으로 조정.
-> 이전에 성공한 경우가 있다면 이전 값을 리턴한다.
Revision 0529
-------------------
수정일 : 2011-05-03
수정자 : 유희곤
- BUG: lib/BaseSocket.cpp ConversionAddr() 함수 수정
- ConversionAddr() 함수에서 gethostbyname() 함수 사용으로 인한 Thread-Safe 문제 발생
- Multi Thread App에서 요청한 장비와 다른 장비로 접속하는 문제가 발견되었으며
- 이로인해 Contents 전송, 관리 부분에서 문제가 발생할 수 있어 수정 처리함.
- 본 문제는 Thread Safe 한 getaddrinfo() 함수 사용으로 변경 처리함.
Revision 0515
-------------------
수정일 : 2011-04-07
수정자 : 노경민
- NEW: 동일 파일 체크 기능 추가
- 동일 파일 존재 유무 체크하여 로깅되는 기능을 추가함.
- 수정된 파일 SocketControl.cpp임
Revision 0440
-------------------
수정일 : 2010-12-01
수정자 : 유희곤
- CHG: src/FileSender.cpp off_t 출력 형식 수정
- CFileSender::CheckFileInfo() 함수상의 off_t 타입 확인 결과 32, 64Bit 장비에서 모두 __int64_t 로 정의됨
- 또한 printf 출력 형식 중 %jd => intmax_t 방식이 존재하며
- /usr/include/machine/_types.h 확인 결과 32, 64Bit 장비에서 모두 __int64_t 로 정의됨.
- 따라서 기존 출력형식 %lld 를 %jd 로 수정처리
- CHG: Makefile 상의 버전정보 변경
- 3.0.1.439 => 3.0.1.440
Revision 0439
-------------------
수정일 : 2010-11-30
수정자 : 유희곤
- CHG: src/FileSender.cpp off_t 출력 형식 수정
- CFileSender::CheckFileInfo() 함수상의 off_t 타입 확인 결과 32, 64Bit 장비에서 모두 __int64_t 로 정의됨
- 따라서 기존 출력형식 %ld 를 32Bit 적용을 위해 %lld 로 수정처리
- 이와 같이 처리하면 32 Bit 는 정상, 64 Bit 는 Compile Warning 이 발생함.
- CHG: Makefile 상의 버전정보 변경
- 3.0.1.438 => 3.0.1.439
Revision 0438
-------------------
수정일 : 2010-11-30
수정자 : 유희곤
- CHG: gcc 4.4.5 컴파일시 발생한 Header File include 오류 관련 Header 추가처리
- lib/Logger.cpp
- src/SocketControl.h
- src/GetConfig.cpp
- src/LocalIPCache.cpp
- src/Worker.cpp
- src/FileSender.cpp
- src/FileHash.cpp
- src/Listener.cpp
- src/SocketControl.cpp
- src/ProperStorage.cpp
- BUG: lib/Config.h 구문 오류 수정
- SetDelimiter 함수의 두번째 인자인 string& value = CONFIG_DEFAULT_VALUE_DELIMITER 구문 오류
- string value = CONFIG_DEFAULT_VALUE_DELIMITER 형식으로 수정 처리
- CHG: src/LocalIPCache.cpp 중요 변수 초기화 코드 추가
- GetIP() 함수상에 struct ifreq 변수 초기화 코드 추가
- CHG: 컴파일러 최적화를 위한 if~else 문의 {} 블록 처리 코드 추가
- src/Worker.cpp 의 SigTermWorker() 함수
- src/Listener.cpp 의 SigTermListener() 함수
- BUG: src/FileSender.cpp 구문 오류
- CFileSender::Execute() 함수 상에서 다음 코드의 OR 조건이 잘못되어 수정처리
- if( CheckHashValue() == false | m_bThreadStop == true )
- CFileSender::CheckFileInfo() 함수상의 off_t 타입의 출력형식을 기존 %llu 에서 %ld 로 변경처리함.
- CHG: src/Listener.cpp 의 Daemon 생성 관련 코드 수정
- MakeDaemon() 함수상에 Daemon 생성 관련 stdin, stdout, stderr Close 처리 코드 추가 ( 원격 기동시 CTRL+C 처리 불편에 따른 수정)
- MakeDaemon() 함수상에 파일 권한 관련 umask(0) 코드 추가.
- CHG: Makefile 상의 버전정보 변경
- 3.0.1.379 => 3.0.1.438
Revision 0379
-------------------
수정일 : 2010-10-13
수정자 : 김오종
- CHG: replication 요청시 local filesize 확인 부분 버그 수정.
- 형변환 부분수정.
- CHG: Makefile 상의 버전정보 관리 방법 변경
- 목표 버전 변경으로 인한 ver 3.0.1 로 변경
Revision 0328
-------------------
수정일 : 2010-08-05
수정자 : 김오종
- CHG: 참조하는 conf 파일명을 변경합니다.
- 기존 ftsd.conf => fhs.conf 로 변경.
- CHG: 컴파일시 warning 보고 부분 제거.
- 컴파일시 if() 구문에 서로 다른 타입의 변경에 따른 warning 제거.
- 컴파일시 사용하지 않는 변수에 대한 warning 제거.
- CHG: Makefile 상의 버전정보 관리 방법 변경
- REVISION 을 추가로 정의하고 Version 표시할때 사용 한다.
Revision 0319
-------------------
수정일 : 2010-07-23
수정자 : 유희곤
- BUG: CBaseSocket::Read() 함수상의 문법관련 버그 수정
- 156 Line상의 잘못된 대입 연산자를 비교연산자로 수정처리.
- CHG: Makefile 상의 버전정보 변경
- 3.0.0.264 => 3.0.0.319
Revision 0264
-------------------
수정일 : 2010-06-01
수정자 : 유희곤
- CHG: Logger Class 의 Init() 호출시 경로가 Symbolic Link인 경우 처리코드 추가
- Log Path 경로가 Directory 가 아닌 Symbolic Link 인 경우로 발생
- 따라서 이러한 경우 기존에는 Error 로 처리되어 Init() 함수 호출이 실패됨.
- 해당 코드를 Symbolic Link 또는 Directory 인 경우에는 정상적으로 처리되도록 수정함.
- CHG: Makefile 상의 버전정보 변경
- Makefile 상에 설정된 Version 정보를 기존 1.0-R0240 에서 양뱡향 버전 표시 방법으로 변경처리
- 3.0.0.264-생성일시분초 형식
Revision 0240
-------------------
수정일 : 2010-05-07
수정자 : 유희곤
- NEW: RC 간 파일 복제 기능 수행을 위한 기능 추가
- RC 간 파일 복제를 수행하기 위해 Control Daemon 으로 부터 정보 수신시 Target Tran ID 정보 수신 기능 추가
- 이를 위해 Control Daemon 과의 통신 프로토콜 부분이 수정됨 ( SocketControl Class 수정 )
- 전달받은 Tran ID 정보를 임시 저장하기 위한 Worker.cpp 수정
- 원본 파일 및 Target Tran ID 정보 변경 처리를 위한 FileSender, TargetFhsInfo Class 수정
Revision 0229
-------------------
수정일 : 2010-04-13
수정자 : 유희곤
- CHG: Process 상태 정보 모니터링 클래스 Lock 제어 수정
- ProcessStatus Class 상에 Mutex Lock 코드 버그 수정
- Lock 관련 Dead Lock 발생 가능성 코드 수정
Revision 0222
-------------------
수정일 : 2010-04-09
수정자 : 유희곤
- CHG: CBaseSocket 관련 로그 처리 기능 수정
- 필요없는 Log(Timeout) 에 대한 삭제 처리
- 해당 로그 발생 빈도가 높아 성능에 영향을 미칠것으로 판단하여 주석처리함.
Revision 0221
-------------------
수정일 : 2010-04-09
수정자 : 유희곤
- CHG: Log 관련 버그 수정
- Cache 처리 관련 로깅 버그 수정.
Revision 0220
-------------------
수정일 : 2010-04-09
수정자 : 유희곤
- CHG: conf 상에 존재하는 CACHE_STORAGE_ROOT 정보 삭제 및 관련 코드 삭제 처리
- Cache 저장 경로는 FILE_STORAGE_ROOT 에 저장된 경로 하위에 cache 경로 생성 후 처리하기로 결정함
- 따라서 CACHE_STORAGE_ROOT 는 현재 의미가 없어 삭제처리함.
- CHG: Cache 처리 요청시 저장경로 정보 변경
- Cache 처리 요청시 기존에 conf 에 저장된 경로가 아닌
- dav_storage 의 하위 cache 폴더 상에 cache 된 파일이 저장되도록 수정처리함.
- CHG: Worker Thread 에서 Socket 데이터 수신시 처리로직 변경
- Client Socket 종료, Timeout 에 대한 처리 로직 추가
- CHG: FileSender Thread 의 중지 기능 추가
- File 전송 처리시 중간에 정지시키는 기능 추가함.
Revision 0176
-------------------
수정일 : 2010-03-23
수정자 : 유희곤
- NEW: SVN 신규 등록
- 기존 svn://doit.solbox.com/work/trunk/ftsd 에 존재하는 개발 완료 소스 (Rev 491)를 SVN 에 정식버전으로 등록함.
- Listen 처리를 위한 TCP Port 는 14001 로 지정함.
- 본 버전은 개발 및 성능 테스트를 완료한 버전으로 Replication 및 Cache 처리 기능을 가짐
- 단 현재 버전은 FreeBSD 5.4, 6.2 버전상에서만 테스트되었으며 다른 OS 로 포팅 처리시 코드를 재확인해야 함.
- NEW: History 저장을 위한 Changelog.txt 파일 추가
- 앞으로 각 작업에 대한 로그를 확인하도록 Changelog.txt 파일을 추가
+37
View File
@@ -0,0 +1,37 @@
#****************************************************************************
# Makefile for ftsd ( File TranSfer Daemon)
# -----------------------------------------
#
# begin : 2010/02/25
# 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.
#*****************************************************************************
SUBDIRS = lib src interface/sample
.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
+54
View File
@@ -0,0 +1,54 @@
/***************************************************************************
ftsd ( File TranSfer Daemon ) Common Header
-----------------------------------------
begin : 2010/02/25
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 __DEFINE_FTSD_H__
#define __DEFINE_FTSD_H__
#include <unistd.h>
#include <string>
#ifdef __cplusplus
extern "C" {
#endif
// Global Config object
struct st_config
{
std::string szLogDir;
std::string szStorageRoot;
std::string szInternalNicName;
int nLogLevel;
int nWorkerProcessCount;
int nMaxFileSendThread;
int nFhsInternalIpCacheTimeout;
int nProperStorageRefresPeriod;
int nMaxBandwidthUse;
st_config()
{
nWorkerProcessCount = 0;
nMaxFileSendThread = 0;
nFhsInternalIpCacheTimeout = 0;
nProperStorageRefresPeriod = 0;
nMaxBandwidthUse = 0;
nLogLevel = 0;
}
};
#ifdef __cplusplus
}
#endif
#endif /* __DEFINE_FTSD_H__ */
+91
View File
@@ -0,0 +1,91 @@
Revision 1534
-------------------
수정일 : 2021-04-19
수정자 : 유희곤
- NEW: content 에 대한 size, atime, mtime, ctime 추출 기능 추가 (#33516)
- stat 함수를 이용하여 content 에 대한 size, access, modify, change time 정보 추출 기능 추가
- 이와 관련 interface 함수도 추가 처리
Revision 1364
-------------------
수정일 : 2016-05-12
수정자 : 유희곤
- NEW: 고객사 토토디스크 지원용 File Check 기능 추가 (#27533)
- 토토디스크 지원 관련 Revision 1358 에서 추가한 MD5 Hash 추출 기능 이외에
- Checksum , DNA CHECK Key 값 추출 관련 ftsd 와 통신 프로토콜 수정 및 전달 기능 추가.
- 수정파일: FtsdSocketControl.h FtsdSocketControl.cpp
- CHG: Client interface 의 Data 수신 Timeout 관련 기능 수정
- 프로토콜 형식이 일치하지 않는 경우... Data 수신 처리시 alive check 로 인한 timeout 처리 미발생.
- 이는 수신 처리 timeout 이 기본 15 sec 인데.. 5 sec 마다 alive check 가 동작하여 timeout 이 미발생함.
- 이를 해결하지 위해 data body 수신 처리시.. timeout 을 2 sec 로 지정 처리함.
- 수정파일: FtsdSocketControl.cpp
Revision 1358
-------------------
수정일 : 2016-05-09
수정자 : 유희곤
- NEW: 고객사 토토디스크 지원용 MD5 Hash 추출관련 프로토콜 및 interface 함수 추가 (#27460)
- 토토디스크 MD5 Hash 추출 관련 통신 CONTROL_FILE_CHECK_TOTO 프로토콜 및 관련 interface 함수 추가
- 토토디스크용 Test 파일 추가.
- 수정 파일: FtsdProtocol.h FtsdSocketControl.h FtsdSocketControl.cpp sample/main_TOTOcheck.cpp
Revision 0811
-------------------
수정일 : 2012-09-04
수정자 : 유희곤
- NEW: 파일에 대한 unlink 처리시 강제 삭제 처리 기능 추가
- unlink 관련 모드 정보를 전달받아 처리하도록 기능 추가함.
- 제어 모듈을 위한 Interface 함수 수정.
- CHG: 수정된 Logger 처리 모듈 적용
- 일감 #10138 에서 수정된 Logger 모듈 (Revision 805) 적용 처리
Revision 0803
-------------------
수정일 : 2012-08-14
수정자 : 유희곤
- NEW: 파일에 대한 Check ( Size, Hash ) 기능 및 인터페이스 추가
- 요청 파일에 대한 존재 여부 확인 및 Size 정보 추출, Hash 정보 추출 기능 추가.
- 제어 모듈을 위한 Interface 함수 추가.
- NEW: 파일에 대한 Unlink 기능 및 인터페이스 추가
- 요청 파일에 대한 unlink 처리 기능 추가
- 제어 모듈을 위한 Interface 함수 추가
- CHG: 양방향 Main 버전 (3.2.0) 변경 사항 적요.
- 기존 3.1.0 -> 3.2.0 으로 버전 변경 처리.
Revision 0668
-------------------
수정일 : 2012-02-07
수정자 : 유희곤
- CHG: Logger 처리 객체 변경 및 관련 코드 수정
- 서비스 1팀 공통 Logger 클래스 ( singleton 방식) 적용 및 관련 코드 수정
- Log 메시지 관련 알아보기 쉽도록 부분 수정 처리.
Revision 0638
-------------------
수정일 : 2011-12-19
수정자 : 유희곤
- NEW: ftsd 사용을 위한 Interface 소스파일 및 샘플 소스 파일을 최초로 SVN 형상에 추가
- ftsd 를 사용하는 Control 프로세스 상에 제공하기 위한 Internface 용 참고 소스 파일 추가 (interface 폴더 )
- ftsd 사용을 위한 Internface 소스 파일에 대한 샘플 소스 제공 ( interface/sample 폴더 )
- 본 변경 사항은 SVN 형상만 변경하였으므로.. 실제 ftsd 버전업은 수행하지 않는다.
+70
View File
@@ -0,0 +1,70 @@
/***************************************************************************
ftsd control interface ( File Replication & Cache & Move & Delete Control) Header ( FtsdProtocol.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 __FTSD_PROTOCOL_H__
#define __FTSD_PROTOCOL_H__
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 extend_code[2]; // 확장 및 Padding bits ( 2 Byte )
};
// Packet Header stx 코드
#define HEADER_STX_CODE 0x02
// Packet Header type 구분코드
#define HEADER_TYPE_REQUEST 0x00
#define HEADER_TYPE_RESPONSE 0x01
// Packet command 공통.
#define COMMON_ALIVE_CHECK 0x7F
// Packet command : control 프로세스 <-> ftsd 통신 ( Command 첫번째 Byte 만 사용 )
#define NOT_CONTROL_COMMAND 0x00 // Control 이 전송한 요청이 아닌 경우.
#define CONTROL_FILE_REPLICATION 0x01 // Content 복제 생성 요청
#define CONTROL_FILE_CACHE 0x02 // Content 에 대해 Cache 폴더로 복제 요청
#define CONTROL_FILE_CHECK 0x03 // Content 에 대한 존재 여부, Size 확인 및 Hash 추출 요청
#define CONTROL_FILE_UNLINK 0x04 // Content 에 대한 unlink 처리 요청
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460)
#define CONTROL_FILE_CHECK_TOTO 0x05 // 토토디스크 고객사 지원을 위한 MD5 Hash 추출 기능 (2016-05-03 추가)
// NEW 2021-04-01 huibong content stat(size, atime, mtime, ctime) 정보 추출 기능 추가 (#33516)
#define CONTROL_FILE_STAT 0x06
// Packet Result : type이 Reponse 인 경우에만 세팅됨.( 첫번째 Byte 만 사용시 )
#define HEADER_RESULT_SUCCESS 0x00
#define HEADER_RESULT_ERROR 0x01
// 기타 정보
#define LENGTH_FIELD_SIZE 4 // 가변데이터 형식 사용시 Length 필드의 메모리 크기 (unsigned int)
// unlink 요청시 Mode 설정 정보
#define UNLINK_MODE_NORMAL 0 // 해당 Content 가 존재하고 size 값이 정확한 경우에만 삭제, 나머지는 오류
#define UNLINK_MODE_FORCE 1 // 해당 Content 가 존재하지 않거나.. Size 값이 틀려도 강제로 삭제 처리.. 오류로 처리되는 상황은 통신, 시스템 오류 발생시.
#endif /* __FTSD_PROTOCOL_H__ */
File diff suppressed because it is too large Load Diff
+344
View File
@@ -0,0 +1,344 @@
/***************************************************************************
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 __FTSD_SOCKET_CONTROL_H__
#define __FTSD_SOCKET_CONTROL_H__
#include "BaseSocket.h"
#include "FtsdProtocol.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 CFtsdSocketControl : 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 생성자.
CFtsdSocketControl();
/// @brief 소멸자.
~CFtsdSocketControl();
/// @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 szFileName [in] 복제할 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @param nFileSize [in] 복제할 원본 Source 파일의 크기.
/// @param szTargetTranId [in] RC 간 복제 처리시 변경할 대상 Tran ID 정보 값.
/// @param nFileHashCheckLevel [in] File 에 대한 Hash Check Level 정보 ( conf 파일에 지정됨)
/// @param bUseInternalIp [in] 내부망을 이용하여 파일 송수신을 수행할지 여부 \n
///< 해당값을 true 로 지정시 ftsd 상에서 내부망을 우선 사용하여 파일 복제 시도
///< 만약 내부망 사용 불가시 자동으로 외부망 사용.
///< RC-RC 간 처리시에는 사용하지 않도록 false 로 지정할 것.
/// @param vecTargetFhs [in] 복제 대상 Target FHS Host Name 정보
/// @return Replication 복제 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool SendFileReplicationRequest(const std::string& szFileName, unsigned long long nFileSize, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs);
bool SendFileReplicationRequest(const std::string& szFileName, unsigned long long nFileSize, const std::string& szTargetTranId, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs);
/// @brief File Replication 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
/// @param bSuccess [out] File Replication 이 정상적으로 수행되었는지 여부 \n
///< trnsfer 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
///< 정상적으로 처리된 경우 true 가 저장되며 \n
///< mapSuccessFhs, mapFailFhs 상에 관련 정보가 저장됨.
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
/// @param mapSuccessFhs [out] bSuccess == true 인 경우 \n
///< Replication 처리에 성공한 FHS 및 저장된 File 이름 정보를 저장
/// @param mapFailFhs [out] bSuccess == true 인 경우 \n
///< Replication 처리에 실패한 FHS Host Name 및 발생된 오류메시지 정보를 저장.
///
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///<
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 로부터
///< Replication 에 대한 처리 결과 정보를 수신하지 못한 경우. \n
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
///< 응답을 대기할 수 있다. \n
///<
///< 1 : 파일 복제 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
///<
///< 2 : ftsd 로 부터 Data 을 수신하였으나 File Replication 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
int GetFileReplicationResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage, std::map< std::string, std::string>& mapSuccessFhs, std::map< std::string, std::string>& mapFailFhs );
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 File Cache 명령 전송.
/// @param szFileName [in] Cache 처리할 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @param nFileSize [in] Cache 처리할 원본 Source 파일의 크기.
/// @param nFileHashCheckLevel [in] File 에 대한 Hash Check Level 정보 ( conf 파일에 지정됨)
/// @param bUseInternalIp [in] 내부망을 이용하여 파일 송수신을 수행할지 여부 \n
///< 해당값을 true 로 지정시 ftsd 상에서 내부망을 우선 사용하여 파일 복제 시도
///< 만약 내부망 사용 불가시 자동으로 외부망 사용.
/// @param vecTargetFhs [in] Cache 대상 Target FHS Host Name 정보
/// @return Cache 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool SendFileCacheRequest(const std::string& szFileName, unsigned long long nFileSize, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs);
/// @brief File Cache 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
/// @param bSuccess [out] File Cache 처리가 정상적으로 수행되었는지 여부 \n
///< trnsfer 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
///< 정상적으로 처리된 경우 true 가 저장되며 \n
///< mapSuccessFhs, mapFailFhs 상에 관련 정보가 저장됨.
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
/// @param mapSuccessFhs [out] bSuccess == true 인 경우 \n
///< Cache 처리에 성공한 FHS 및 저장된 File 이름 정보를 저장
/// @param mapFailFhs [out] bSuccess == true 인 경우 \n
///< Cache 처리에 실패한 FHS Host Name 및 발생된 오류메시지 정보를 저장.
///
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///<
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 로부터
///< Cache 에 대한 처리 결과 정보를 수신하지 못한 경우. \n
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
///< 응답을 대기할 수 있다. \n
///<
///< 1 : 파일 Cache 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
///<
///< 2 : ftsd 로 부터 Data 을 수신하였으나 File Cache 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
int GetFileCacheResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage, std::map< std::string, std::string>& mapSuccessFhs, std::map< std::string, std::string>& mapFailFhs );
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 Content Check 명령 전송.
/// @param szFileName [in] 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @param bHashCheck [in] Hash 값을 추출할지 여부
/// @param nHashCheckSize [in] Hash 값을 추출할 경우 Size 설정값 ( MByte 단위 )\n
///< 0 : Content 에 대한 전체 Hash 값을 추출함.
///< 숫자 : Content 의 앞 부분부터 지정된 크기 (MByte ) 까지 Hash 값을 추출
/// @return Check 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool SendFileCheckRequest(const std::string& szFileName, bool bHashCheck, unsigned long long nHashCheckSize );
/// @brief File Check 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
/// @param bSuccess [out] File Check 처리가 정상적으로 수행되었는지 여부 \n
///< ftsd 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
///< 정상적으로 처리된 경우 true 가 저장되며 \n
///< nFileSize, szHashValue 상에 결과 정보가 저장됨.
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
/// @param nFileSize [out] bSuccess == true 인 경우 요청한 Content 에 대한 file size 정보를 저장. ( Byte 단위 )
/// @param szHashValue [out] bSuccess == true 이고... Hash 값 추출을 요청한 경우 추출된 Hash 값 정보를 저장.
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///<
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 으로부터 처리 결과 정보를 수신하지 못한 경우. \n
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
///< 응답을 대기할 수 있다. \n
///<
///< 1 : 파일 Check 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
///<
///< 2 : ftsd 으로 부터 Data 을 수신하였으나 File Check 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
int GetFileCheckResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage, unsigned long long& nFileSize, std::string& szHashValue );
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 Unlink 명령 전송.
/// @param szFileName [in] 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @param nFileSize [in] 원본 파일의 크기 ( Byte 단위 )
/// @param bForceUnlink [in] 강제 삭제 처리 여부 ( Defalult false )
/// false : 일반모드 - 해당 파일이 존재하고 Size 값이 동일할 경우에만 삭제처리.. 나머지는 오류로 처리.
/// true : 강제모드 - 해당 파일이 존재하지 않거나.. Size 가 틀려도 강제로 삭제 처리.. 오류는 통신, 시스템 오류 발생시에만
/// @return Unlink 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool SendFileUnlinkRequest(const std::string& szFileName, unsigned long long nFileSize, bool bForceUnlink = false );
/// @brief File Unlink 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
/// @param bSuccess [out] File unlink 처리가 정상적으로 수행되었는지 여부 \n
///< ftsd 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
///< 정상적으로 처리된 경우 true 가 저장되며 따로 수신하는 Data 는 없음. \n
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///<
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 으로부터 처리 결과 정보를 수신하지 못한 경우. \n
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
///< 응답을 대기할 수 있다. \n
///<
///< 1 : 파일 Unlink 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
///<
///< 2 : ftsd 으로 부터 Data 을 수신하였으나 File Unlink 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
int GetFileUnlinkResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage );
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460)
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 Content Check 명령 전송. (토토디스크 지원용)
/// @param szFileName [in] 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @return Check 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool SendFileCheckTOTORequest( const std::string& szFileName );
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460, #27533)
/// @brief File Check 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
/// @param bSuccess [out] File Check 처리가 정상적으로 수행되었는지 여부 \n
///< ftsd 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
///< 정상적으로 처리된 경우 true 가 저장되며 \n
///< nFileSize, szHashValue 상에 결과 정보가 저장됨.
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
/// @param nFileSize [out] bSuccess == true 인 경우 요청한 Content 에 대한 file size 정보를 저장. ( Byte 단위 )
/// @param szTotoMd5 [out] bSuccess == true 인 경우 추출된 totorasa 용 MD5 Hash 값 정보를 저장.
/// @param szChecksum [out] bSuccess == true 인 경우 추출된 totorasa 용 Checksum 정보를 저장.
/// @param szDnaCheckKey [out] bSuccess == true 인 경우 추출된 totorasa 용 DNA Check key 값 정보를 저장.
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///<
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 으로부터 처리 결과 정보를 수신하지 못한 경우. \n
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
///< 응답을 대기할 수 있다. \n
///<
///< 1 : 파일 Check 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
///<
///< 2 : ftsd 으로 부터 Data 을 수신하였으나 File Check 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
int GetFileCheckTOTOResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage
, unsigned long long& nFileSize, std::string& szTotoMd5, std::string& szChecksum, std::string& szDnaCheckKey );
// NEW 2021-04-01 huibong content stat(size, atime, mtime, ctime) 정보 추출 기능 추가 (#33516)
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 Content stat 명령 전송.
/// @param szFileName [in] 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @return stat 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool SendFileStatRequest( const std::string & szFileName );
// NEW 2021-04-01 huibong content stat(size, atime, mtime, ctime) 정보 추출 기능 추가 (#33516)
/// @brief File stat 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
/// @param bSuccess [out] File Check 처리가 정상적으로 수행되었는지 여부 \n
///< ftsd 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
///< 정상적으로 처리된 경우 true 가 저장되며 \n
///< nFileSize, nAccessTime, nModifyTime, nChangeTime 상에 결과 정보가 저장됨.
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
/// @param nFileSize [out] bSuccess == true 인 경우 요청한 Content 에 대한 file size 정보를 저장. ( Byte 단위 )
/// @param nAccessTime [out] bSuccess == true 인 경우 요청한 Content 에 대한 access time 정보를 저장. ( sec 단위)
/// @param nModifyTime [out] bSuccess == true 인 경우 요청한 Content 에 대한 modify time 정보를 저장. ( sec 단위)
/// @param nChangeTime [out] bSuccess == true 인 경우 요청한 Content 에 대한 change time 정보를 저장. ( sec 단위)
///
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///<
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 으로부터 처리 결과 정보를 수신하지 못한 경우. \n
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
///< 응답을 대기할 수 있다. \n
///<
///< 1 : 파일 Check 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
///<
///< 2 : ftsd 으로 부터 Data 을 수신하였으나 File Check 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
int GetFileStatResult( int nTimeout, bool & bSuccess, std::string & szErrorMessage
, long & nFileSize, long & nAccessTime, long & nModifyTime, long & nChangeTime );
/// @brief 연결된 Socket 통신을 이용하여 내부적으로 정의된 Alive Check 패킷 전송 \n
///< => 해당 패킷에 대한 처리는 내부적으로 처리되어 결과값을 확인할 필요는 없다.
/// @return Socket 연결 해제 또는 전송 관련 오류 발생시 false, 전송 성공시에는 true 반환.
bool SendAliveCheck(void);
/// @brief Packet Header 정보를 Log 파일에 Logging 처리 ( Debug 처리를 위한 함수)
void PrintHeaderToLog(void);
protected:
/// @brief Packet Header 부분의 수신 처리를 위한 함수. Alive Check 요청 패킷은 자동으로 무시처리함.
/// @param timeout [in] 대기시간.
/// @retrun 성공시 true, 오류 발생및 실패시 fasle 반환.
bool GetPacketHeader(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 );
/// @brief pValue 에 저장된 데이터를 long (64Byte) 형으로 변환처리.
long GetDataToLong( BYTE * pValue );
};
#endif /* __FTSD_SOCKET_CONTROL_H__ */
+64
View File
@@ -0,0 +1,64 @@
#****************************************************************************
# Makefile for ftsd interface sample
# -----------------------------------------
#
# begin : 2010/03/16
# copyright : (C) 2005 SolutionBox Inc.
# author : Service 1 Team
# email : svc1@solbox.com
# version : 3.1..R0668
#
# CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
# Redistribution and use in source and binary forms, with or with out
# modification, are not permitted in outside of SolutionBox Inc.
#*****************************************************************************
# Program info
PROG_NAME = ftsd_test
# Compiler info
CC = /usr/bin/g++
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized -Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual -fno-rtti -D_REENTRANT
LFLAGS =
DFLAGS = -D_DEBUG_ -DPROG_NAME=\"$(PROG_NAME)\"
# Enviroment
DIR_INCLUDE = -I./. -I./.. -I./../../lib
DIR_LIB =
#OBJ = ../../lib/Logger.o ../../lib/BaseSocket.o ../FtsdSocketControl.o main_replication.o
#OBJ = ../../lib/Logger.o ../../lib/BaseSocket.o ../FtsdSocketControl.o main_cache.o
#OBJ = ../../lib/Logger.o ../../lib/BaseSocket.o ../FtsdSocketControl.o main_check.o
#OBJ = ../../lib/Logger.o ../../lib/BaseSocket.o ../FtsdSocketControl.o main_unlink.o
#OBJ = ../../lib/Logger.o ../../lib/BaseSocket.o ../FtsdSocketControl.o main_TOTOcheck.o
OBJ = ../../lib/Logger.o ../../lib/BaseSocket.o ../FtsdSocketControl.o main_stat.o
LIBS =
APP = $(PROG_NAME)
############################
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 *.out *.log ./../*.o
-rm -f $(APP)
sync
install : $(APP)
sync
# End of Makefile
@@ -0,0 +1,177 @@
#include <stdlib.h>
#include <string>
#include <map>
#include <iterator>
#include "Logger.h"
#include "FtsdSocketControl.h"
#define LOG_PATH "/user/service/logs" // Log 파일은 /user/service/logs/sample/sample_날짜.log 로 생성됨.
#define TRANSFER_LISTEN_PORT 14001 // ftsd 의 Listen Port
int main( int argc, char * argv[] )
{
std::string szSourceHostName;
std::string szFileName;
if( argc != 3 )
{
///////////// 1. 기본 정보 설정 ///////////////////
// Source 장비 Host Name
//szSourceHostName = "bd-16-fhs001.ktsh.co.kr";
szSourceHostName = "bd-16-fhs003.ktsh.co.kr";
// Source 파일명 ( Mount 위치까지 포함함 전체 경로 )
//szFileName = "/stg/node0/348/4075fac10de1ae95667310cf7e2c9b9a";
//szFileName = "/stg/node0/size0";
//szFileName = "/stg/node0/size256K";
//szFileName = "/stg/node0/size1M";
//szFileName = "/stg/node0/size1M2";
//szFileName = "/stg/node0/size1M3";
//szFileName = "/stg/node0/size4M";
szFileName = "/stg/node0/size10M";
//szFileName = "/stg/node0/size1G";
}
else
{
szSourceHostName = argv[1];
szFileName = argv[2];
}
////////////// 결과값을 저장할 변수 //////////////////
// File Size
unsigned long long nFileSize = 0;
// File 추출값 저장 변수
std::string szTotoMd5;
std::string szChecksum;
std::string szDnaCheckKey;
// 오류 메시지
std::string szErrorMessage;
////////////// Sample 코드 //////////////
// Log 처리용 객체 생성 및 초기화.
if( CLogger::Init( PROG_NAME, LOG_PATH, LDBG ) == false )
{
std::cout << "[error] Logger object created failed.." << std::endl;
return 0;
}
// Start logging
_LOG( LINF, "ftsd check sample Start: Source[%s]", szFileName.c_str());
// ftsd 와 통신을 처리할 Socket Control 객체 생성 및 접속
CFtsdSocketControl ftsdSocket;
if( ftsdSocket.ConnectTarget( szSourceHostName, TRANSFER_LISTEN_PORT ) == false )
{
// Source ftsd 으로 접속 실패시
_LOG( LERR, "Source FHS connect fail. [%s][%d]", szSourceHostName.c_str(), TRANSFER_LISTEN_PORT );
return EXIT_FAILURE;
}
// ftsd 로 TOTO 파일에 대한 Check 요청 전달
// SendFileCheckTOTORequest() 함수는 FtsdSocketControl.h 파일 참조.
if( ftsdSocket.SendFileCheckTOTORequest( szFileName ) == false )
{
// Source ftsd 로 전송 실패시
_LOG( LERR, "Check Request send fail.[%s][%s]", szSourceHostName.c_str(), szFileName.c_str());
return EXIT_FAILURE;
}
// 요청에 대한 응답 대기
int nTimeout = 5; // 응답 대기 시간 ( sec )
int nResult = 0;
bool bResultSuccess; // 처리 결과의 성공/실패 여부를 저장하기 위한 변수.
// 루프를 돌면서 요청에 대한 응답을 대기
while(1)
{
// nTimeout 에 지정된 시간동안 응답대기 시도
// GetFileCheckTOTOResult() 함수는 SocketControl.h 파일 참고.
nResult = ftsdSocket.GetFileCheckTOTOResult( nTimeout, bResultSuccess, szErrorMessage, nFileSize, szTotoMd5, szChecksum, szDnaCheckKey );
if( nResult == -1 )
{
// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
// 해당 내역 로깅 및 루프 종료
_LOG( LERR, "ftsd Response wait fail by socket [%s][%s]", szSourceHostName.c_str(), szFileName.c_str() );
break;
}
else if( nResult == 0 )
{
// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Allive Check 패킷 한번 쏘고 다시 Loop 로
if( ftsdSocket.SendAliveCheck() == false )
{
// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
_LOG( LERR, "ftsd Response wait fail by socket2 [%s][%s]", szSourceHostName.c_str(), szFileName.c_str() );
break;
}
// 정상적인 경우 다시 응답대기.
continue;
}
else if( nResult == 1 )
{
// 요청에 대한 처리결과 정보가 수신된 경우.
// 해당 정보 로깅처리.
if( bResultSuccess == true )
{
// 요청에 대한 처리가 정상적으로 처리된 경우
//_LOG( LINF, "[%s] Result SUCCESS [%llu][%s]", szFileName.c_str(), nFileSize, szHashValue.c_str());
_LOG( LINF, "TOTO Result size [%llu]", nFileSize );
_LOG( LINF, "TOTO Result md5 hash [%s]", szTotoMd5.c_str());
_LOG( LINF, "TOTO Result checksum [%s]", szChecksum.c_str() );
_LOG( LINF, "TOTO Result dna key [%s]", szDnaCheckKey.c_str() );
}
else
{
// 오류 발생시
_LOG( LINF, "[%s][%s] Result ERROR [%s]", szFileName.c_str(), szSourceHostName.c_str(), szErrorMessage.c_str() );
}
break; // 응답을 받았으니 응답 대기 루프 종료
}
else
{
// Replication 요청에 대한 응답패킷이 아닌 경우.
// 해당 패킷은 무시하고 다시 Loop 로
continue;
}
}
// End logging
_LOG( LINF, "ftsd TOTO check sample process End [%s][%s]", szSourceHostName.c_str(), szFileName.c_str());
_LOG( LINF, "-------------------------------------------------------------------------------" );
CLogger::Exit();
return EXIT_SUCCESS;
}
+179
View File
@@ -0,0 +1,179 @@
#include <stdlib.h>
#include <string>
#include <map>
#include <iterator>
#include "Logger.h"
#include "FtsdSocketControl.h"
#define LOG_PATH "/user/service/logs" // Log 파일은 /user/service/logs/sample/sample_날짜.log 로 생성됨.
#define TRANSFER_LISTEN_PORT 14001 // ftsd 의 Listen Port
int main()
{
///////////// 1. 기본 정보 설정 ///////////////////
// Source 장비 Host Name
std::string szSourceHostName = "bd-16-fhs001.ktsh.co.kr";
// Source 파일명 ( Mount 위치까지 포함함 전체 경로 )
//std::string szSourceFileNameHash = "/stg/node1/186/4b2d62b6357b548ac984894a12630e25";
//std::string szSourceFileNameHash = "/user2/dav_storage/186/00ace1da4678aeb61e7aac6708dcdcaa";
std::string szSourceFileNameHash = "/stg/node0/1/huibong.txt";
// Source 파일의 크기 ( 만약 일치하지 않을 경우 ftsd 에서 오류로 처리함)
//unsigned long long nSourceFileSize = 100000000;
unsigned long long nSourceFileSize = 42;
// Target FHS Host Name 정보 ( 다중 Target 사용 가능으로 인해 vector 사용)
std::vector< std::string > vecTarget;
//vecTarget.push_back( "bd-16-fhs002.ktsh.co.kr" );
//vecTarget.push_back( "bd-16-fhs003.ktsh.co.kr" );
//vecTarget.push_back( "222.122.153.81" );
vecTarget.push_back( "222.122.153.82" );
//vecTarget.push_back( "bd-04-fhs003.ktsh.co.kr" );
//vecTarget.push_back( "bd-04-fhs004.ktsh.co.kr" );
//vecTarget.push_back( "bd-04-fhs005.ktsh.co.kr" );
//vecTarget.push_back( "bd-04-fhs006.ktsh.co.kr" );
///////////// 2. 옵션 설정 //////////////
// 전송완료후 Hash 검사 Level, 0: 안함, 1: 앞뒤 1Mbyte만 검사, 2: 파일 전체검사
int nFileHashCheckLevel = 1;
// 파일 전송시 내부망을 사용할지 여부, RC 내 처리시에는 true 설정, RC-RC 간 동작시에는 효율성을 위해 false 설정할 것.
bool bUseInternalIp = true;
////////////// Sample 코드 //////////////
// Log 처리용 객체 생성 및 초기화.
if( CLogger::Init( PROG_NAME, LOG_PATH, LDBG ) == false )
{
std::cout << "[error] Logger object created failed.." << std::endl;
return 0;
}
// Start logging
_LOG( LINF, "ftsd sample Start: Source[%s][%s][%llu]", szSourceHostName.c_str(), szSourceFileNameHash.c_str(), nSourceFileSize );
// ftsd 와 통신을 처리할 Socket Control 객체 생성 및 접속
CFtsdSocketControl ftsdSocket;
if( ftsdSocket.ConnectTarget( szSourceHostName, TRANSFER_LISTEN_PORT ) == false )
{
// Source ftsd 으로 접속 실패시
_LOG( LERR, "Source FHS connect fail. [%s][%d]", szSourceHostName.c_str(), TRANSFER_LISTEN_PORT );
return EXIT_FAILURE;
}
// Source ftsd 로 파일에 대한 Cache 처리 요청
if( ftsdSocket.SendFileCacheRequest( szSourceFileNameHash, nSourceFileSize, nFileHashCheckLevel, bUseInternalIp, vecTarget ) == false )
{
// Source ftsd 로 Replication 요청 전송 실패시
_LOG( LERR, "Cache Request send fail.[%s][%s][%llu]", szSourceHostName.c_str(), szSourceFileNameHash.c_str(), nSourceFileSize);
return EXIT_FAILURE;
}
// Replication 요청에 대한 응답 대기
int nResult = 0;
int nTimeout = 5; // 응답 대기 시간 ( sec )
bool bResultSuccess; // 처리 결과의 성공/실패 여부를 저장하기 위한 변수.
std::string szResultErrorMessage; // bResultSuccess= fale 인 경우 오류메시지를 저장하기 위한 변수.
std::map< std::string, std::string> mapSuccessInfo; // 성공한 FHS Host명 및 파일정보를 저장하기 위한 list
std::map< std::string, std::string> mapFailInfo; // 실패한 FHS Host명 및 각 FHS별 오류메시지를 저장하기 위한 list
// 루프를 돌면서 Replication 요청에 대한 응답을 대기
while(1)
{
// nTimeout 에 지정된 시간동안 응답대기 시도
nResult = ftsdSocket.GetFileCacheResult( nTimeout, bResultSuccess, szResultErrorMessage, mapSuccessInfo, mapFailInfo );
if( nResult == -1 )
{
// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
// 해당 내역 로깅 및 루프 종료
_LOG( LERR, "ftsd Response wait fail by socket [%s][%s]", szSourceHostName.c_str(), szSourceFileNameHash.c_str() );
break;
}
else if( nResult == 0 )
{
// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Allive Check 패킷 한번 쏘고 다시 Loop 로
if( ftsdSocket.SendAliveCheck() == false )
{
// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
_LOG( LERR, "ftsd Response wait fail by socket2 [%s][%s]", szSourceHostName.c_str(), szSourceFileNameHash.c_str() );
break;
}
// 정상적인 경우 다시 응답대기.
continue;
}
else if( nResult == 1 )
{
// 요청에 대한 처리결과 정보가 수신된 경우.
// 해당 정보 로깅처리.
if( bResultSuccess == true )
{
// 요청에 대한 처리가 일단은 수행된 경우 => 성공한 FHS 정보 와 실패한 FHS 정보가 나타남.
std::map< std::string, std::string>::const_iterator it;
// 성공한 FHS 목록
for( it = mapSuccessInfo.begin(); it != mapSuccessInfo.end(); it++ )
{
// 성공한 경우 Target FHS Host Name 및 저장된 File Full Name 정보가 표시됨.
_LOG( LINF, "Result SUCCESS [%s][%s]", (it->first).c_str(), (it->second).c_str() );
}
// 실패한 FHS 목록
for( it = mapFailInfo.begin(); it != mapFailInfo.end(); it++ )
{
// 실패한 경우 Target FHS Host Name 및 오류메시지 정보가 표시됨.
_LOG( LINF, "Result FAIL [%s][%s]", (it->first).c_str(), (it->second).c_str() );
}
}
else
{
// 요청에 대한 처리를 아예 수행할 수 없는 경우 => Source FHS 파일 정보 및 각 정보 검사시 오류가 발생한 경우. ( Target FHS 로 접근 작업 전 )
// 인자로 전달한 szResultErrorMessage 상에 오류 발생정보가 저장됨.
_LOG( LINF, "Cache result error [%s][%s][%s]", szSourceHostName.c_str(), szSourceFileNameHash.c_str(), szResultErrorMessage.c_str() );
}
break; // 응답을 받았으니 응답 대기 루프 종료
}
else
{
// Replication 요청에 대한 응답패킷이 아닌 경우.
// 해당 패킷은 무시하고 다시 Loop 로
continue;
}
}
// End logging
_LOG( LINF, "ftsd sample process End [%s][%s][%llu]", szSourceHostName.c_str(), szSourceFileNameHash.c_str(), nSourceFileSize );
_LOG( LINF, "-------------------------------------------------------------------------------" );
CLogger::Exit();
return EXIT_SUCCESS;
}
+166
View File
@@ -0,0 +1,166 @@
#include <stdlib.h>
#include <string>
#include <map>
#include <iterator>
#include "Logger.h"
#include "FtsdSocketControl.h"
#define LOG_PATH "/user/service/logs" // Log 파일은 /user/service/logs/sample/sample_날짜.log 로 생성됨.
#define TRANSFER_LISTEN_PORT 14001 // ftsd 의 Listen Port
int main()
{
///////////// 1. 기본 정보 설정 ///////////////////
// Source 장비 Host Name
//std::string szSourceHostName = "bd-16-fhs001.ktsh.co.kr";
//std::string szSourceHostName = "nh-61-fhs018.x-cdn.com";
std::string szSourceHostName = "nh-61-fhs005.x-cdn.com";
// Source 파일명 ( Mount 위치까지 포함함 전체 경로 )
//std::string szFileName = "/stg/node0/348/d31e2f9043ac62d273c1fd87008a6c86";
//std::string szFileName = "/stg/node0/10m_1";
//std::string szFileName = "/stg/node0/600/2139178cdcacb3ba2a2ca9533bee7fbf";
//std::string szFileName = "/stg/node2/600/616964e59ed7ee956470f88c271cbe68";
//std::string szFileName = "/stg/node0/594/fdd9a1f5b32f062622254fb7c5b4c537";
std::string szFileName = "/stg/node0/594/f962ec80bb5e3257e95925305f6a7296";
// Hash 정보 추출 여부
bool bHashCheck = true;
// Hash 추출 size ( 0 : 전체... 숫자값 : 앞부분부터 지정된 위치의 까지 MByte 단위임 )
//unsigned long long nHashCheckSize = 10;
unsigned long long nHashCheckSize = 0;
////////////// 결과값을 저장할 변수 //////////////////
// File Size
unsigned long long nFileSize = 0;
// Hash 추출값
std::string szHashValue;
// 오류 메시지
std::string szErrorMessage;
////////////// Sample 코드 //////////////
// Log 처리용 객체 생성 및 초기화.
if( CLogger::Init( PROG_NAME, LOG_PATH, LDBG ) == false )
{
std::cout << "[error] Logger object created failed.." << std::endl;
return 0;
}
// Start logging
_LOG( LINF, "ftsd check sample Start: Source[%s]", szFileName.c_str());
// ftsd 와 통신을 처리할 Socket Control 객체 생성 및 접속
CFtsdSocketControl ftsdSocket;
if( ftsdSocket.ConnectTarget( szSourceHostName, TRANSFER_LISTEN_PORT ) == false )
{
// Source ftsd 으로 접속 실패시
_LOG( LERR, "Source FHS connect fail. [%s][%d]", szSourceHostName.c_str(), TRANSFER_LISTEN_PORT );
return EXIT_FAILURE;
}
// ftsd 로 파일에 대한 Check 요청 전달
// SendFileCheckRequest() 함수는 FtsdSocketControl.h 파일 참조.
if( ftsdSocket.SendFileCheckRequest( szFileName, bHashCheck, nHashCheckSize ) == false )
{
// Source ftsd 로 전송 실패시
_LOG( LERR, "Check Request send fail.[%s][%s]", szSourceHostName.c_str(), szFileName.c_str());
return EXIT_FAILURE;
}
// 요청에 대한 응답 대기
int nTimeout = 5; // 응답 대기 시간 ( sec )
int nResult = 0;
bool bResultSuccess; // 처리 결과의 성공/실패 여부를 저장하기 위한 변수.
// 루프를 돌면서 요청에 대한 응답을 대기
while(1)
{
// nTimeout 에 지정된 시간동안 응답대기 시도
// GetFileCheckResult() 함수는 SocketControl.h 파일 참고.
nResult = ftsdSocket.GetFileCheckResult( nTimeout, bResultSuccess, szErrorMessage, nFileSize, szHashValue );
if( nResult == -1 )
{
// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
// 해당 내역 로깅 및 루프 종료
_LOG( LERR, "ftsd Response wait fail by socket [%s][%s]", szSourceHostName.c_str(), szFileName.c_str() );
break;
}
else if( nResult == 0 )
{
// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Allive Check 패킷 한번 쏘고 다시 Loop 로
if( ftsdSocket.SendAliveCheck() == false )
{
// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
_LOG( LERR, "ftsd Response wait fail by socket2 [%s][%s]", szSourceHostName.c_str(), szFileName.c_str() );
break;
}
// 정상적인 경우 다시 응답대기.
continue;
}
else if( nResult == 1 )
{
// 요청에 대한 처리결과 정보가 수신된 경우.
// 해당 정보 로깅처리.
if( bResultSuccess == true )
{
// 요청에 대한 처리가 정상적으로 처리된 경우
//_LOG( LINF, "[%s] Result SUCCESS [%llu][%s]", szFileName.c_str(), nFileSize, szHashValue.c_str());
_LOG( LINF, "Result size [%llu]", nFileSize );
_LOG( LINF, "Result Hash [%s]", szHashValue.c_str());
}
else
{
// 오류 발생시
_LOG( LINF, "[%s][%s] Result ERROR [%s]", szFileName.c_str(), szSourceHostName.c_str(), szErrorMessage.c_str() );
}
break; // 응답을 받았으니 응답 대기 루프 종료
}
else
{
// Replication 요청에 대한 응답패킷이 아닌 경우.
// 해당 패킷은 무시하고 다시 Loop 로
continue;
}
}
// End logging
_LOG( LINF, "ftsd check sample process End [%s][%s]", szSourceHostName.c_str(), szFileName.c_str());
_LOG( LINF, "-------------------------------------------------------------------------------" );
CLogger::Exit();
return EXIT_SUCCESS;
}
@@ -0,0 +1,181 @@
#include <stdlib.h>
#include <string>
#include <map>
#include <iterator>
#include "Logger.h"
#include "FtsdSocketControl.h"
#define LOG_PATH "/user/service/logs" // Log 파일은 /user/service/logs/sample/sample_날짜.log 로 생성됨.
#define TRANSFER_LISTEN_PORT 14001 // ftsd 의 Listen Port
int main()
{
///////////// 1. 기본 정보 설정 ///////////////////
// Source 장비 Host Name
std::string szSourceHostName = "bd-16-fhs001.ktsh.co.kr";
// Source 파일명 ( Mount 위치까지 포함함 전체 경로 )
//std::string szSourceFileNameHash = "/stg/node1/186/4b2d62b6357b548ac984894a12630e25";
//std::string szSourceFileNameHash = "/user2/dav_storage/186/00ace1da4678aeb61e7aac6708dcdcaa";
std::string szSourceFileNameHash = "/stg/node0/1/huibong.txt";
// Source 파일의 크기 ( 만약 일치하지 않을 경우 ftsd 에서 오류로 처리함)
//unsigned long long nSourceFileSize = 100000000;
unsigned long long nSourceFileSize = 42;
// Target FHS Host Name 정보 ( 다중 Target 사용 가능으로 인해 vector 사용)
std::vector< std::string > vecTarget;
//vecTarget.push_back( "bd-16-fhs002.ktsh.co.kr" );
//vecTarget.push_back( "bd-16-fhs003.ktsh.co.kr" );
//vecTarget.push_back( "222.122.153.81" );
vecTarget.push_back( "222.122.153.82" );
//vecTarget.push_back( "bd-04-fhs003.ktsh.co.kr" );
//vecTarget.push_back( "bd-04-fhs004.ktsh.co.kr" );
//vecTarget.push_back( "bd-04-fhs005.ktsh.co.kr" );
//vecTarget.push_back( "bd-04-fhs006.ktsh.co.kr" );
///////////// 2. 옵션 설정 //////////////
// 전송완료후 Hash 검사 Level, 0: 안함, 1: 앞뒤 1Mbyte만 검사, 2: 파일 전체검사
int nFileHashCheckLevel = 1;
// 파일 전송시 내부망을 사용할지 여부, RC 내 처리시에는 true 설정, RC-RC 간 동작시에는 효율성을 위해 false 설정할 것.
bool bUseInternalIp = true;
////////////// Sample 코드 //////////////
// Log 처리용 객체 생성 및 초기화.
if( CLogger::Init( PROG_NAME, LOG_PATH, LDBG ) == false )
{
std::cout << "[error] Logger object created failed.." << std::endl;
return 0;
}
// Start logging
_LOG( LINF, "ftsd sample Start: Source[%s][%s][%llu]", szSourceHostName.c_str(), szSourceFileNameHash.c_str(), nSourceFileSize );
// ftsd 와 통신을 처리할 Socket Control 객체 생성 및 접속
CFtsdSocketControl ftsdSocket;
if( ftsdSocket.ConnectTarget( szSourceHostName, TRANSFER_LISTEN_PORT ) == false )
{
// Source ftsd 으로 접속 실패시
_LOG( LERR, "Source FHS connect fail. [%s][%d]", szSourceHostName.c_str(), TRANSFER_LISTEN_PORT );
return EXIT_FAILURE;
}
// Source ftsd 로 파일에 대한 Replication 처리 요청
// SendFileReplicationRequest() 함수는 FtsdSocketControl.h 파일 참조.
if( ftsdSocket.SendFileReplicationRequest( szSourceFileNameHash, nSourceFileSize, nFileHashCheckLevel, bUseInternalIp, vecTarget ) == false )
{
// Source ftsd 로 Replication 요청 전송 실패시
_LOG( LERR, "Replication Request send fail.[%s][%s][%llu]", szSourceHostName.c_str(), szSourceFileNameHash.c_str(), nSourceFileSize);
return EXIT_FAILURE;
}
// Replication 요청에 대한 응답 대기
int nResult = 0;
int nTimeout = 5; // 응답 대기 시간 ( sec )
bool bResultSuccess; // 처리 결과의 성공/실패 여부를 저장하기 위한 변수.
std::string szResultErrorMessage; // bResultSuccess= fale 인 경우 오류메시지를 저장하기 위한 변수.
std::map< std::string, std::string> mapSuccessInfo; // 성공한 FHS Host명 및 파일정보를 저장하기 위한 list
std::map< std::string, std::string> mapFailInfo; // 실패한 FHS Host명 및 각 FHS별 오류메시지를 저장하기 위한 list
// 루프를 돌면서 Replication 요청에 대한 응답을 대기
while(1)
{
// nTimeout 에 지정된 시간동안 응답대기 시도
// GetFileReplicationResult() 함수는 SocketControl.h 파일 참고.
nResult = ftsdSocket.GetFileReplicationResult( nTimeout, bResultSuccess, szResultErrorMessage, mapSuccessInfo, mapFailInfo );
if( nResult == -1 )
{
// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
// 해당 내역 로깅 및 루프 종료
_LOG( LERR, "ftsd Response wait fail by socket [%s][%s]", szSourceHostName.c_str(), szSourceFileNameHash.c_str() );
break;
}
else if( nResult == 0 )
{
// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Allive Check 패킷 한번 쏘고 다시 Loop 로
if( ftsdSocket.SendAliveCheck() == false )
{
// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
_LOG( LERR, "ftsd Response wait fail by socket2 [%s][%s]", szSourceHostName.c_str(), szSourceFileNameHash.c_str() );
break;
}
// 정상적인 경우 다시 응답대기.
continue;
}
else if( nResult == 1 )
{
// 요청에 대한 처리결과 정보가 수신된 경우.
// 해당 정보 로깅처리.
if( bResultSuccess == true )
{
// 요청에 대한 처리가 일단은 수행된 경우 => 성공한 FHS 정보 와 실패한 FHS 정보가 나타남.
std::map< std::string, std::string>::const_iterator it;
// 성공한 FHS 목록
for( it = mapSuccessInfo.begin(); it != mapSuccessInfo.end(); it++ )
{
// 성공한 경우 Target FHS Host Name 및 저장된 File Full Name 정보가 표시됨.
_LOG( LINF, "Result SUCCESS [%s][%s]", (it->first).c_str(), (it->second).c_str() );
}
// 실패한 FHS 목록
for( it = mapFailInfo.begin(); it != mapFailInfo.end(); it++ )
{
// 실패한 경우 Target FHS Host Name 및 오류메시지 정보가 표시됨.
_LOG( LINF, "Result FAIL [%s][%s]", (it->first).c_str(), (it->second).c_str() );
}
}
else
{
// 요청에 대한 처리를 아예 수행할 수 없는 경우 => Source FHS 파일 정보 및 각 정보 검사시 오류가 발생한 경우. ( Target FHS 로 접근 작업 전 )
// 인자로 전달한 szResultErrorMessage 상에 오류 발생정보가 저장됨.
_LOG( LINF, "Replication result error [%s][%s][%s]", szSourceHostName.c_str(), szSourceFileNameHash.c_str(), szResultErrorMessage.c_str() );
}
break; // 응답을 받았으니 응답 대기 루프 종료
}
else
{
// Replication 요청에 대한 응답패킷이 아닌 경우.
// 해당 패킷은 무시하고 다시 Loop 로
continue;
}
}
// End logging
_LOG( LINF, "ftsd sample process End [%s][%s][%llu]", szSourceHostName.c_str(), szSourceFileNameHash.c_str(), nSourceFileSize );
_LOG( LINF, "-------------------------------------------------------------------------------" );
CLogger::Exit();
return EXIT_SUCCESS;
}
+150
View File
@@ -0,0 +1,150 @@
#include <stdlib.h>
#include <string>
#include <map>
#include <iterator>
#include "Logger.h"
#include "../FtsdSocketControl.h"
#define LOG_PATH "/user/service/logs" // Log 파일은 /user/service/logs/sample/sample_날짜.log 로 생성됨.
#define TRANSFER_LISTEN_PORT 14001 // ftsd 의 Listen Port
int main()
{
///////////// 1. 기본 정보 설정 ///////////////////
// Source 장비 Host Name
std::string szSourceHostName = "sb-02-fhs001.solbox.com";
// Source 파일명 ( Mount 위치까지 포함함 전체 경로 )
std::string szFileName = "/stg/node2/66/8bed0cb840eb9a5f2b1eab790e9a3c53";
////////////// 결과값을 저장할 변수 //////////////////
long nFileSize = 0;
long nAccessTime = 0;
long nModifyTime = 0;
long nChangeTime = 0;
// 오류 메시지
std::string szErrorMessage;
////////////// Sample 코드 //////////////
// Log 처리용 객체 생성 및 초기화.
if( CLogger::Init( PROG_NAME, LOG_PATH, LDBG ) == false )
{
std::cout << "[error] Logger object created failed.." << std::endl;
return 0;
}
// Start logging
_LOG( LINF, "ftsd stat sample Start: Source[%s]", szFileName.c_str());
// ftsd 와 통신을 처리할 Socket Control 객체 생성 및 접속
CFtsdSocketControl ftsdSocket;
if( ftsdSocket.ConnectTarget( szSourceHostName, TRANSFER_LISTEN_PORT ) == false )
{
// Source ftsd 으로 접속 실패시
_LOG( LERR, "Source FHS connect fail. [%s][%d]", szSourceHostName.c_str(), TRANSFER_LISTEN_PORT );
return EXIT_FAILURE;
}
// ftsd 로 파일에 대한 stat 요청 전달
// SendFileCheckRequest() 함수는 FtsdSocketControl.h 파일 참조.
if( ftsdSocket.SendFileStatRequest( szFileName) == false )
{
// Source ftsd 로 전송 실패시
_LOG( LERR, "Stat Request send fail.[%s][%s]", szSourceHostName.c_str(), szFileName.c_str());
return EXIT_FAILURE;
}
// 요청에 대한 응답 대기
int nTimeout = 10; // 응답 대기 시간 ( sec )
int nResult = 0;
bool bResultSuccess; // 처리 결과의 성공/실패 여부를 저장하기 위한 변수.
// 루프를 돌면서 요청에 대한 응답을 대기
while(1)
{
// nTimeout 에 지정된 시간동안 응답대기 시도
// GetFileStatResult() 함수는 SocketControl.h 파일 참고.
nResult = ftsdSocket.GetFileStatResult( nTimeout, bResultSuccess, szErrorMessage, nFileSize, nAccessTime, nModifyTime, nChangeTime );
if( nResult == -1 )
{
// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
// 해당 내역 로깅 및 루프 종료
_LOG( LERR, "ftsd Response wait fail by socket [%s][%s]", szSourceHostName.c_str(), szFileName.c_str() );
break;
}
else if( nResult == 0 )
{
// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Allive Check 패킷 한번 쏘고 다시 Loop 로
if( ftsdSocket.SendAliveCheck() == false )
{
// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
_LOG( LERR, "ftsd Response wait fail by socket2 [%s][%s]", szSourceHostName.c_str(), szFileName.c_str() );
break;
}
// 정상적인 경우 다시 응답대기.
continue;
}
else if( nResult == 1 )
{
// 요청에 대한 처리결과 정보가 수신된 경우.
// 해당 정보 로깅처리.
if( bResultSuccess == true )
{
// 요청에 대한 처리가 정상적으로 처리된 경우
_LOG( LINF, "Result size [%ld] access[%ld] modify[%ld] change[%ld]"
, nFileSize, nAccessTime, nModifyTime, nChangeTime );
}
else
{
// 오류 발생시
_LOG( LINF, "[%s][%s] Result ERROR [%s]", szFileName.c_str(), szSourceHostName.c_str(), szErrorMessage.c_str() );
}
break; // 응답을 받았으니 응답 대기 루프 종료
}
else
{
// Stat 요청에 대한 응답패킷이 아닌 경우.
// 해당 패킷은 무시하고 다시 Loop 로
continue;
}
}
// ftsd socket 종료
ftsdSocket.Close();
// End logging
_LOG( LINF, "ftsd stat sample process End [%s][%s]", szSourceHostName.c_str(), szFileName.c_str());
_LOG( LINF, "-------------------------------------------------------------------------------" );
CLogger::Exit();
return EXIT_SUCCESS;
}
+148
View File
@@ -0,0 +1,148 @@
#include <stdlib.h>
#include <string>
#include <map>
#include <iterator>
#include "Logger.h"
#include "FtsdSocketControl.h"
#define LOG_PATH "/user/service/logs" // Log 파일은 /user/service/logs/sample/sample_날짜.log 로 생성됨.
#define TRANSFER_LISTEN_PORT 14001 // ftsd 의 Listen Port
int main()
{
///////////// 1. 기본 정보 설정 ///////////////////
// Source 장비 Host Name
std::string szSourceHostName = "bd-16-fhs001.ktsh.co.kr";
// Source 파일명 ( Mount 위치까지 포함함 전체 경로 )
//std::string szFileName = "/stg/node0/10m_1.bak";
std::string szFileName = "/stg/node0/huibong.txt";
// File Size
unsigned long long nFileSize = 0;
////////////// 결과값을 저장할 변수 //////////////////
// 오류 메시지
std::string szErrorMessage;
////////////// Sample 코드 //////////////
// Log 처리용 객체 생성 및 초기화.
if( CLogger::Init( PROG_NAME, LOG_PATH, LDBG ) == false )
{
std::cout << "[error] Logger object created failed.." << std::endl;
return 0;
}
// Start logging
_LOG( LINF, "ftsd unlink sample Start: Source[%s]", szFileName.c_str());
// ftsd 와 통신을 처리할 Socket Control 객체 생성 및 접속
CFtsdSocketControl ftsdSocket;
if( ftsdSocket.ConnectTarget( szSourceHostName, TRANSFER_LISTEN_PORT ) == false )
{
// Source ftsd 으로 접속 실패시
_LOG( LERR, "Source FHS connect fail. [%s][%d]", szSourceHostName.c_str(), TRANSFER_LISTEN_PORT );
return EXIT_FAILURE;
}
// ftsd 로 파일에 대한 Check 요청 전달
// SendFileCheckRequest() 함수는 FtsdSocketControl.h 파일 참조.
if( ftsdSocket.SendFileUnlinkRequest( szFileName, nFileSize, true ) == false )
{
// Source ftsd 로 전송 실패시
_LOG( LERR, "Unlink Request send fail.[%s][%s]", szSourceHostName.c_str(), szFileName.c_str());
return EXIT_FAILURE;
}
// 요청에 대한 응답 대기
int nTimeout = 5; // 응답 대기 시간 ( sec )
int nResult = 0;
bool bResultSuccess; // 처리 결과의 성공/실패 여부를 저장하기 위한 변수.
// 루프를 돌면서 요청에 대한 응답을 대기
while(1)
{
// nTimeout 에 지정된 시간동안 응답대기 시도
// GetFileCheckResult() 함수는 SocketControl.h 파일 참고.
nResult = ftsdSocket.GetFileUnlinkResult( nTimeout, bResultSuccess, szErrorMessage);
if( nResult == -1 )
{
// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
// 해당 내역 로깅 및 루프 종료
_LOG( LERR, "ftsd Response wait fail by socket [%s][%s]", szSourceHostName.c_str(), szFileName.c_str() );
break;
}
else if( nResult == 0 )
{
// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Allive Check 패킷 한번 쏘고 다시 Loop 로
if( ftsdSocket.SendAliveCheck() == false )
{
// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
_LOG( LERR, "ftsd Response wait fail by socket2 [%s][%s]", szSourceHostName.c_str(), szFileName.c_str() );
break;
}
// 정상적인 경우 다시 응답대기.
continue;
}
else if( nResult == 1 )
{
// 요청에 대한 처리결과 정보가 수신된 경우.
// 해당 정보 로깅처리.
if( bResultSuccess == true )
{
// 요청에 대한 처리가 정상적으로 처리된 경우
//_LOG( LINF, "[%s] Result SUCCESS [%llu][%s]", szFileName.c_str(), nFileSize, szHashValue.c_str());
_LOG( LINF, "Unlink result SUCCESS.");
}
else
{
// 오류 발생시
_LOG( LINF, "[%s][%s] Result ERROR (%s)", szFileName.c_str(), szSourceHostName.c_str(), szErrorMessage.c_str() );
}
break; // 응답을 받았으니 응답 대기 루프 종료
}
else
{
// Replication 요청에 대한 응답패킷이 아닌 경우.
// 해당 패킷은 무시하고 다시 Loop 로
continue;
}
}
// End logging
_LOG( LINF, "ftsd check sample process End [%s][%s]", szSourceHostName.c_str(), szFileName.c_str());
_LOG( LINF, "-------------------------------------------------------------------------------" );
CLogger::Exit();
return EXIT_SUCCESS;
}
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh
CMD="$1"
SLEEP="$2"
while [ 1 ]; do
date
eval $CMD
echo " "
sleep $SLEEP
done
+595
View File
@@ -0,0 +1,595 @@
#include "BaseSocket.h"
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define SOCKET_NOT_VALID -1
#define MAX_SEND_RETRY_COUNT 10 // Socket send 실패시 최대 재전송 시도 횟수.
/// @brief 생성자.
/// @param socket [in] 처리할 socket descriptor
CBaseSocket::CBaseSocket( const int& socket )
: m_sock( socket )
{
if( m_sock < 0 )
{
m_sock = SOCKET_NOT_VALID;
m_bConnected = false;
}
else
{
m_bConnected = true;
}
}
/// @brief 소멸자
CBaseSocket::~CBaseSocket()
{
// 소멸자 Socket 명시적 Close 처리.
Close();
}
/// @brief 소켓의 Close 처리를 수행함.
void CBaseSocket::Close()
{
m_bConnected = false;
if( m_sock != SOCKET_NOT_VALID )
{
close( m_sock );
m_sock = SOCKET_NOT_VALID;
}
}
/// @brief 전달받은 Target 으로 Socket 접속을 수행
/// @param szTarget [in] 접속 대상 Host name 또는 IP
/// @param nPort [in] 접속 Port
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool CBaseSocket::Connect( const std::string& szTarget, int nPort )
{
// 기존 접속을 Close 처리
Close();
unsigned int nHost = ConversionAddr( szTarget.c_str() );
if( nHost == INADDR_NONE )
{
LOG( LERR, "target host name resolve fail. [%s]->INADDR_NONE", szTarget.c_str());
return false;
}
struct sockaddr_in stTargetAddr;
m_sock = socket(AF_INET, SOCK_STREAM, 0);
if( m_sock == -1 )
{
int errorNum = errno;
LOG( LERR, "socket create failed.[%d][%s] Target:[%s]", errorNum, strerror(errorNum), szTarget.c_str() );
m_sock = SOCKET_NOT_VALID;
return false;
}
stTargetAddr.sin_family = AF_INET;
stTargetAddr.sin_addr.s_addr = nHost;
stTargetAddr.sin_port = htons( nPort );
// NEW 2012-05-18 huibong
// Connnection 종료시 많은 TIME_WAIT 상태 발생으로 인해 .. 이를 제거하기 위해 SO_LINGER 옵션을 설정처리한다.
struct linger opt_linger;
opt_linger.l_onoff = 1; /* LINGER ON */
// CHG 2014-05-27 huibong
// 아래와 같이 No Wait 로 처리할 경우... Server 역활 수행 중 Close 신호를 받지 못하는 경우가 발생 가능함.
// 따라서 5 sec 정도 대기하도록 수정 처리한다.
//opt_linger.l_linger = 0; /* No Wait => 0 for abortive disconnect */
opt_linger.l_linger = 5; // 5 sec 대기
int result = setsockopt( m_sock, SOL_SOCKET, SO_LINGER, &opt_linger, sizeof(opt_linger));
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "setsockopt func SO_LINGER set fail.[%d][%s]", errorNum, strerror(errorNum));
}
/* Send Timeout 설정. */
struct timeval tv_timeo = { 5, 0 };
result = setsockopt( m_sock, SOL_SOCKET, SO_SNDTIMEO, &tv_timeo, sizeof(tv_timeo));
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "setsockopt func SO_SNDTIMEO set fail.[%d][%s]", errorNum, strerror(errorNum));
}
if(connect(m_sock, (struct sockaddr *)&stTargetAddr, sizeof(stTargetAddr)) < 0 )
{
int errorNum = errno;
LOG( LERR, "connect fail.[%s][%d] [%d][%s]", szTarget.c_str(), nPort, errorNum, strerror( errorNum ) );
Close();
return false;
}
else
{
m_bConnected = true;
return true;
}
}
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
bool CBaseSocket::IsValidSocket()
{
if( m_sock != SOCKET_NOT_VALID && m_bConnected == true )
return true;
else
return false;
}
/// @brief m_sock 으로부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t CBaseSocket::Read( void * vptr, size_t size )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
while( (nRead = read( m_sock, vptr, size )) < 0 )
{
int errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2010-07-23 BUG huibong 잘못된 대입연산자를 비교연산자로 수정.
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
return nRead;
}
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t CBaseSocket::ReadN( void * vptr, size_t size )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
size_t nLeft = size;
char * ptr = (char *)vptr;
while( nLeft > 0 )
{
if( (nRead = read( m_sock, ptr, nLeft )) < 0 )
{
int errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
}
return size;
}
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류 , -2: Timeout
ssize_t CBaseSocket::ReadNTimeout( void * vptr, size_t size, int timeout )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
size_t nLeft = size;
char * ptr = (char *)vptr;
struct timeval timeOver;
int result;
fd_set selectFds;
FD_ZERO( &selectFds );
while( nLeft > 0 )
{
timeOver.tv_sec = timeout;
timeOver.tv_usec = 0;
FD_SET( m_sock, &selectFds );
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
if( result > 0 )
{
if( FD_ISSET( m_sock, &selectFds ))
{
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
{
int errorNum = errno;
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
}
}
else if( result == 0 ) // Timeout
{
//LOG( LDBG, "read timeout");
return -2;
}
else
{
int errorNum = errno;
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
return size;
}
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
ssize_t CBaseSocket::ReadNTimeout2( void * vptr, size_t size, int timeout )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
size_t nLeft = size;
char * ptr = (char *)vptr;
int errorNum;
// 우선은 읽기 시도.
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
{
errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nRead = 0;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
// 만약 더 받을 데이터가 존재한다면.
if( nLeft > 0 )
{
struct timeval timeOver;
int result;
fd_set selectFds;
FD_ZERO( &selectFds );
while( nLeft > 0 )
{
timeOver.tv_sec = timeout;
timeOver.tv_usec = 0;
FD_SET( m_sock, &selectFds );
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
if( result > 0 )
{
if( FD_ISSET( m_sock, &selectFds ))
{
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
{
errorNum = errno;
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
}
}
else if( result == 0 ) // Timeout
{
//LOG( LDBG, "read timeout");
return -2;
}
else
{
errorNum = errno;
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
}
return size;
}
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
/// @param size [in] write 하고자 하는 데이터의 크기.
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t CBaseSocket::WriteN( const void * vptr, size_t size )
{
if( IsValidSocket() == false )
return 0;
size_t nLeft;
ssize_t nWrite;
const char * ptr = (const char *)vptr;
nLeft = size;
int nTryCount = 0;
while( nLeft > 0 )
{
if( (nWrite = send( m_sock, ptr, nLeft, 0 )) < 0 )
{
int errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nWrite = 0;
++nTryCount;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "send func fail.[%d][%s]", errorNum, strerror(errorNum));
return -1;
}
}
else if( nWrite == 0 )
{
m_bConnected = false;
return 0;
}
if( nTryCount > MAX_SEND_RETRY_COUNT )
{
LOG( LERR, "send func failure due to exceeding count of retry[%d/%d]", nTryCount, MAX_SEND_RETRY_COUNT );
return 0 ;
}
nLeft -= nWrite;
ptr += nWrite;
}
return size;
}
// CHG 2011-05-03 huibong
// gethostbyname() 함수가 Thread Safe 하지 않기 때문에
// DNS resolve 처리시 잘못된 정보를 반환할 가능성이 존재
// 이에 따라 본 함수를 수정처리함.
/*
unsigned int CBaseSocket::ConversionAddr( const char * name )
{
struct hostent *he;
int max;
unsigned int retval;
if ((retval = inet_addr(name)) != INADDR_NONE)
return retval;
he = gethostbyname(name);
if (he == NULL)
return INADDR_NONE;
for (max = 0; he->h_addr_list[max]; max++) ;
if (max == 1)
return *((unsigned int *)(he->h_addr_list[0]));
else
return *((unsigned int *)(he->h_addr_list[random() % max]));
}
*/
unsigned int CBaseSocket::ConversionAddr( const char * name )
{
unsigned int retval;
struct addrinfo hints;
struct addrinfo *result = NULL;
int error;
// 전달받은 정보가 IP 주소인 경우...
// - DNS resolve 할 필요 없이 변환시킨 값을 그대로 사용한다.
if( (retval = inet_addr(name)) != INADDR_NONE )
return retval;
// getaddrinfo() 함수 호출을 위한 Hint 설정
memset( &hints, 0x00, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
// Thread Safe 한 DNS Resolve 처리함수 호출
// int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
// CHG 2014-11-14 huibong
// getaddrinfo 호출시 종종 EAI_NONAME 오류가 반환됨. (#20783)
// - 따라서 오류 반환시 재시도하도록 기능 추가
// CHG 2015-07-15 huibong
// usleep 의 multi thread 상에서 block 발생 가능
// - nanosleep 을 사용토록 변경 처리
for( int count = 0 ; count < 3; count++ )
{
error = getaddrinfo( name, NULL, &hints, &result );
// 오류 발생시
if( error != 0 )
{
if( result != NULL)
{
freeaddrinfo(result);
result = NULL;
}
// 잠시 대기 후 재시도 처리
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
}
else
{
// 정상 처리된 경우...
// - loop 탈출
break;
}
}
// 최종 오류 발생시
if( error != 0 )
{
LOG( LERR, "name[%s] dns resolve fail. getaddrinfo return error [%d][%s]", name, error, gai_strerror(error) );
return INADDR_NONE;
}
struct sockaddr_in * addr = (struct sockaddr_in *)result->ai_addr;
retval = (unsigned int)(addr->sin_addr.s_addr);
// DNS Resovle 결과 확인용 코드
/*
struct addrinfo *temp;
for( temp = result; temp; temp = temp->ai_next )
{
addr = (struct sockaddr_in *)temp->ai_addr;
printf ("getaddrinfo result = %s\n",inet_ntoa( addr->sin_addr));
}
*/
// getaddrinfo() 함수에서 생성한 메모리 영역 해제 처리.
freeaddrinfo(result);
return retval;
}
+118
View File
@@ -0,0 +1,118 @@
/***************************************************************************
BaseSocket ( Base Socket Class )
-----------------------------------------
begin : 2010/03/02
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __LIBRARY_BASE_SOCKET_H__
#define __LIBRARY_BASE_SOCKET_H__
#include <unistd.h>
#include <sys/types.h>
#include "Logger.h"
#define SOCKET_NOT_VALID -1
#define DEFAULT_DATA_RECEIVE_TIMEOUT 15 // sec
class CBaseSocket
{
protected:
/// @brief socket descriptor
int m_sock;
/// @brief socket 의 연결상태인지 여부를 저장하기 위한 변수.
bool m_bConnected;
public:
/// @brief 생성자.
CBaseSocket( const int & socket );
/// @brief 소멸자.
~CBaseSocket();
/// @brief 소켓의 Close 처리를 수행함.
void Close(void);
/// @brief 전달받은 Target 으로 Socket 접속을 수행
/// @param szTarget [in] 접속 대상 Host name 또는 IP
/// @param nPort [in] 접속 Port
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool Connect( const std::string& szTarget, int nPort );
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
bool IsValidSocket(void);
/// @brief 멤버변수인 socket 의 접속 상태 여부를 설정하기 위한 함수.
void SetConnectionStatus( bool bConnected) { m_bConnected = bConnected; }
/// @brief 현재 socket 의 접속 상태를 반환.
bool GetConnectionStatus( void) { return m_bConnected; }
//void SetLogger( Logger * pLog ) { m_pLog = pLog; }
protected:
/// @brief m_sock 로 부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t Read( void * vptr, size_t size );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t ReadN( void * vptr, size_t size );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
ssize_t ReadNTimeout( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
ssize_t ReadNTimeout2( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
public:
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
/// @param size [in] write 하고자 하는 데이터의 크기.
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t WriteN( const void * vptr, size_t size );
protected:
/// @brief 문자열로 전달받은 정보를 검사하여 IP 접속 정보를 생성한다.
unsigned int ConversionAddr( const char * name );
};
#endif /* __LIBRARY_BASE_SOCKET_H__ */
+215
View File
@@ -0,0 +1,215 @@
#include "Config.h"
#include <iostream>
#include <fstream>
#include <errno.h>
#include <stdlib.h>
#include <boost/algorithm/string.hpp> // use boost
Config::Config()
: m_keyDelimiter( CONFIG_DEFAULT_KEY_DELIMITER )
, m_valueDelimiter( CONFIG_DEFAULT_VALUE_DELIMITER )
{
}
/// @brief destructor
Config::~Config()
{
Clear();
}
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
/// @return On success return true, otherwise return false
bool Config::Open( const string path )
{
ifstream file;
// Config file open
file.open( path.c_str());
if( file.is_open() == false )
{
cerr << "[error] " << __FILE__<< ":" << __func__ << ": config file open failed.[" << path << "][" << strerror( errno ) << "]" << endl;
return false;
}
// 기존 데이터가 존재하면 삭제 처리.
if( m_configData.empty() == false )
m_configData.clear();
// config file parsing
string line;
string section;
vector< string > configs;
// 루프를 돌면서 Config 파일을 line 단위로 읽어들인당....
while( std::getline( file, line ) )
{
// 앞뒤 공백 제거 처리
boost::trim( line );
// 공백 or 주석처리 라인 검사
if( line.empty() == true || boost::starts_with( line, string("#") ) == true || line == "\r" )
{
continue;
}
// Section 여부 검사
if( boost::starts_with( line, string("[") ) == true && boost::ends_with( line, string("]") ) == true )
{
// [] 로 정의된 section 의 문자열 값 추출
line.erase( line.begin() );
line.erase( line.end() -1 );
boost::trim( line );
if( section.empty() == false && section != line )
{
// 이전 세션과 다른 신규 세션인 경우
// 기존까지 저장했던 데이터를 멤버 변수에 입력 처리 후 내부변수 초기화 처리.
m_configData.insert( make_pair( section, configs ) );
section.clear();
configs.clear();
}
// 신규 section 정보 저장처리.
section = line;
line.clear();
}
else
{
// Section 정보가 아닌 경우 => 실제 설정값 .. ^^
configs.push_back( line );
}
}
// 마지막 세션 처리된 정보가 존재하는 경우 멤버 변수에 저장 처리.
if( section.empty() == false )
{
m_configData.insert( make_pair( section, configs ) );
}
// 종료 처리.
file.close();
return true;
}
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
/// @return void
void Config::Clear()
{
m_configData.clear();
}
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
/// @return On success return true, otherwise return false
bool Config::GetConfig( const string& section, const string& key, string& value )
{
// Section 에 대한 임시 데이터 저장객체 생성
vector< string > configs;
// 해당 Section 이 존재하지 않는 경우
if( Find( section, configs ) == false )
return false;
string line;
string result;
vector< string >::const_iterator it;
// 해당 Key 이 존재하는지 검사
for( it = configs.begin(); it != configs.end(); it++)
{
line = *it;
// Line 상의 주석 제거
string::size_type pos = line.find( '#' );
if( pos != string::npos)
{
line = line.substr(0, pos);
boost::trim( line );
}
// key = value 에서 key 부분 추출
pos = line.find( m_keyDelimiter );
if( pos == string::npos )
{
continue;
}
else
{
result = line.substr(0, pos);
boost::trim( result );
}
if( key == result )
{
// Key 값이 동일한 경우
value = line.substr( pos+1 );
boost::trim( value );
return true;
}
}
return false;
}
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
/// @return On success return true, otherwise return false
bool Config::GetConfig( const string& section, const string& key, vector< string >& value )
{
string result;
vector< string > vec;
if( GetConfig( section, key, result ) == false )
return false;
// 전달받은 result 값을 value delimiter 를 이용하여 parsing 처리
boost::split( vec, result, boost::is_any_of( m_valueDelimiter ));
if( vec.empty() == true )
return false;
// 루프를 돌면서 trim 처리 후 결과값 저장처리.
vector< string >::const_iterator it;
for( it = vec.begin(); it != vec.end(); it++)
{
result = boost::trim_copy( *it );
if( result.empty() == false )
value.push_back( result );
}
if( value.empty() == true )
return false;
else
return true;
}
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
/// @param section [in] section 명
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
/// @return On success return true, otherwise return false
bool Config::Find( const string& section, vector<string>& configData )
{
map< string, vector< string > >::iterator it = m_configData.find( section );
if( it != m_configData.end() )
{
// 해당 section 을 찾은 경우
configData = it->second;
return true;
}
// 해당 section 을 찾지 못한 경우
return false;
}
+114
View File
@@ -0,0 +1,114 @@
/***************************************************************************
Config File Parser Class
-----------------------------------------
begin : 2010/02/27
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __LIBRARY_CONFIG_H__
#define __LIBRARY_CONFIG_H__
#include <string>
#include <map>
#include <vector>
using namespace std;
#define CONFIG_DEFAULT_KEY_DELIMITER "="
#define CONFIG_DEFAULT_VALUE_DELIMITER ","
/// @brief Config class
/// 1. config 파일의 내용을 파싱처리하여 각 Section, Key 에 해당하는 값을 반환처리
/// 2. config 파일은 [section] 단위로 구분된다.
/// 3. config 파일은 key=value 로 구분가능하며 이는 Delimiter 설정을 통해 변경가능하다.
/// 4. value 값이 다중으로 존재하는 경우 "," 값을 통해 구분가능, Delimiter 변경시 다른 값도 사용가능함.
/// 5. config 파일상에서 "#" 로 시작하는 문자열은 라인 끝까지 주석으로 처리된다.
/// 6. 특정 Key 값에 대한 다중 value 값 조회는 vector<string> 을 통해 수행한다.
/// 7. 만약 다중 value 값이 존재시 string 으로 반환받을 경우 해당 Row 가 통째로 반환된다.
/// 8. 본 객체는 Open , Clear 함수가 호출되기전까지 이전 Config 정보가 저장된다.
class Config
{
private:
/// @brief config information saved variable
// string : section data
// vector<string> : key=value data
map< string, vector< string> > m_configData;
/// @brief Key, Value 구분자 저장 변수
string m_keyDelimiter;
string m_valueDelimiter;
public:
/// @brief constructor
Config();
/// @brief destructor
~Config();
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
/// @return On success return true, otherwise return false
bool Open( const string path );
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
/// @return void
void Clear();
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
/// @return On success return true, otherwise return false
bool GetConfig( const string& section, const string& key, string& value );
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
/// @return On success return true, otherwise return false
bool GetConfig( const string& section, const string& key, vector< string >& value );
/// @brief Key, Value Delimiter Get 함수
/// @param key [out] key delimiter 값
/// @param value [out] value delimiter 값
void GetDelimiter( string& key, string& value )
{
key = m_keyDelimiter;
value = m_valueDelimiter;
}
// BUG 2010-11-30 huibong
// string& value = CONFIG_DEFAULT_VALUE_DELIMITER 값은 문법상 오류 구문임.
// gcc 3.4.6 버전에서는 Compile 되나 gcc 4.4.5 에서는 error 로 처리되어 수정처리함.
/// @brief Key, Value Delimiter Set 함수
/// @param key [out] key delimiter 값
/// @param value [out] value delimiter 값, 지정하지 않을 경우 Default 값이 사용됨.
void SetDelimiter( string& key, string value = CONFIG_DEFAULT_VALUE_DELIMITER )
{
m_keyDelimiter = key;
m_valueDelimiter = value;
}
protected:
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
/// @param section [in] section 명
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
/// @return On success return true, otherwise return false
bool Find( const string& section, vector<string>& configData );
};
#endif /* __LIBRARY_CONFIG_H__ */
+487
View File
@@ -0,0 +1,487 @@
/***************************************************************************
Logger.cpp
-----------------------------------------
begin : 2011/10/26
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "Logger.h"
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <iostream>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define MAX_BUFFER_SIZE 2048 // 임시 버퍼 최대 크기
#define DEFAULT_LOG_LEVEL LINF
using namespace std;
CLogger* CLogger::m_pInstance = NULL;
bool CLogger::m_bIsInitialized = false;
pthread_mutex_t CLogger::m_mutex = PTHREAD_MUTEX_INITIALIZER;
CLogger::CLogger( string programName, string logDir, int logLevel )
{
m_szProgramName = programName;
m_szLogDir = logDir;
if( IsValidLogLevel( logLevel ) == true )
{
m_nLogLevel = logLevel;
}
else
{
m_nLogLevel = DEFAULT_LOG_LEVEL;
}
MakeLogLevelString();
}
void CLogger::MakeLogLevelString()
{
m_vectorLogLevelString.push_back( "EMR" );
m_vectorLogLevelString.push_back( "ALT" );
m_vectorLogLevelString.push_back( "CRT" );
m_vectorLogLevelString.push_back( "ERR" );
m_vectorLogLevelString.push_back( "WAR" );
m_vectorLogLevelString.push_back( "NOT" );
m_vectorLogLevelString.push_back( "INF" );
m_vectorLogLevelString.push_back( "DBG" );
m_vectorLogLevelString.push_back( "DEV" );
m_vectorLogLevelString.push_back( "DEV1" );
m_vectorLogLevelString.push_back( "DEV2" );
}
CLogger::~CLogger()
{
m_vectorLogLevelString.clear();
}
bool CLogger::Init( string programName, string logDir, int logLevel )
{
if( m_bIsInitialized == true )
{
return true;
}
pthread_mutex_lock( &m_mutex );
// 변수 유효성 검사.
if( programName.empty() == true || logDir.empty() == true )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( IsValidLogLevel( logLevel ) == false )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( MakeLogDir( programName, logDir ) == false )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( CLogger::m_pInstance != NULL )
{
delete CLogger::m_pInstance;
CLogger::m_pInstance = NULL;
}
CLogger::m_pInstance = new CLogger( programName, logDir, logLevel );
m_bIsInitialized = true;
pthread_mutex_unlock( &m_mutex );
return true;
}
bool CLogger::IsValidLogLevel( int logLevel )
{
return ( ( logLevel < 0 || logLevel > MAX_LOG_LEVEL ) ? false : true );
}
bool CLogger::SetLogLevel( int logLevel )
{
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
m_nLogLevel = logLevel;
return true;
}
bool CLogger::MakeLogDir( string programName, string logDir )
{
string path = logDir + "/" + programName;
struct stat dirStat;
// 해당 이름을 가진 파일 또는 디렉토리가 존재하고
if( lstat( path.c_str(), &dirStat ) == 0 )
{
// 해당 이름이 디렉토리인 경우
if( S_ISDIR( dirStat.st_mode ) == true )
{
return true;
}
else
{
cerr << "exist file with the same name as log path(" << path << ")." << endl;
return false;
}
}
// 디렉토리 가 존재하지 않는 경우 디렉토리 생성 시도
string cmd = "mkdir -p " + path;
system( cmd.c_str() );
if( IsDirectory( path ) == false )
{
cerr << "can't make log directory. path=" << path << "." << endl;
return false;
}
return true;
}
bool CLogger::IsDirectory( string path )
{
struct stat dirStat;
if( lstat ( path.c_str(), &dirStat ) != 0 )
{
cerr << "Log path not valid. Check path [" << path << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
// 해당 정보가 Directory 가 아닌 경우
if( S_ISDIR( dirStat.st_mode ) == false )
{
return false;
}
return true;
}
void CLogger::Exit()
{
if( m_bIsInitialized == false )
{
return;
}
pthread_mutex_lock( &m_mutex );
if( CLogger::m_pInstance != NULL )
{
delete CLogger::m_pInstance;
CLogger::m_pInstance = NULL;
m_bIsInitialized = false;
}
pthread_mutex_unlock( &m_mutex );
}
CLogger* CLogger::GetInstance()
{
return CLogger::m_pInstance;
}
string CLogger::GetLogFilename( struct tm &timeNow )
{
char timeStr[256];
snprintf( timeStr, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
// Make File Name
string filename = m_szLogDir + "/" + m_szProgramName + "/" + m_szProgramName + "_" + string( timeStr );
return filename;
}
bool CLogger::Write( int logLevel, const char * fmt, ...)
{
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
return Write( logLevel, PREFIX_DATE, NULL, 0, buffer );
}
bool CLogger::WriteNoPrefix( int logLevel, const char * fmt, ...)
{
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
return Write( logLevel, PREFIX_NONE, NULL, 0, buffer );
return false;
}
// CHG 2012-08-16 huibong
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
// 함수명 : Write -> WriteWithFunc 으로 변경 처리
bool CLogger::WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
{
if( filename == NULL || funcname == NULL || lineNum < 0 || fmt == NULL )
{
return false;
}
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
char className[255];
string funcPrefix = GetClassName( className, filename );
funcPrefix += "::" + string( funcname ) + "()";
return Write( logLevel, PREFIX_FUNCTION, funcPrefix.c_str(), lineNum, buffer );
}
const char* CLogger::GetClassName( char* className, const char* filename )
{
if( className == NULL )
{
cout << "[ERROR] The input argument 'className' is NULL." << endl;
return NULL;
}
if( filename == NULL )
{
cout << "[ERROR] The input argument 'filename' is NULL." << endl;
strcpy( className, "NULL" );
return className;
}
int filenameSize = strlen( filename );
memcpy( className, filename, filenameSize );
// find end position
char endCharacter = '.';
int endPos = filenameSize - 1;
for( ; endPos > 0; --endPos )
{
if( className[endPos] == endCharacter )
{
break;
}
}
if( endPos == 0 )
{
cout << "[ERROR] endPos=0" << endl;
strcpy( className, "NULL" );
return className;
}
className[endPos] = '\0';
// find start position
char startCharacter = '/';
int startPos = endPos - 1;
for( ; startPos > 0; --startPos )
{
if( className[startPos] == startCharacter )
{
break;
}
}
if( startPos != 0 )
{
startPos += 1;
}
return (className + startPos );
}
bool CLogger::Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log )
{
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
if( logLevel > m_nLogLevel )
{
return false;
}
if( log == NULL )
{
return false;
}
// Get Current Data & Time
time_t now = time( NULL );
struct tm timeNow;
localtime_r( &now, &timeNow );
string filename = GetLogFilename( timeNow );
// Log file open
FILE* pFile = NULL;
pFile = fopen( filename.c_str(), "a+" );
if( pFile == NULL )
{
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
// 시간 정보처리
char timeStr[256];
snprintf( timeStr, (size_t)256, "[%02d:%02d:%02d]"
, timeNow.tm_hour, timeNow.tm_min, timeNow.tm_sec );
// Log Level 문자열 검색
string szLevel = m_vectorLogLevelString[ logLevel ];
switch( logPrefix )
{
case PREFIX_DATE:
/// 형식 예: [15:47:41] [DBG] sample log message.
fprintf( pFile, "%s [%-4s] %s\n", timeStr, szLevel.c_str(), log );
break;
case PREFIX_FUNCTION:
if( functionName == NULL )
{
fclose( pFile );
return false;
}
/// 형식 예: [15:47:41] [DBG] sample log message. [SomeClass::SomeFunction():12]
fprintf( pFile, "%s [%-4s] %s [%s:%d]\n", timeStr, szLevel.c_str(), log, functionName, lineNum );
break;
case PREFIX_NONE:
/// 형식 예: sample log message.
fprintf( pFile, "%s\n", log );
break;
}
// Write to log file
fflush( pFile );
// 종료 처리.
fclose( pFile );
return true;
}
bool CLogger::WriteHex( int logLevel, const unsigned char* data, const int size )
{
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
if( logLevel > m_nLogLevel )
{
return false;
}
if( data == NULL )
{
return false;
}
if( size <= 0 )
{
return false;
}
// Get Current Data & Time
time_t now = time( NULL );
struct tm timeNow;
localtime_r( &now, &timeNow );
string filename = GetLogFilename( timeNow );
// Log file open
FILE* pFile = NULL;
pFile = fopen( filename.c_str(), "a+" );
if( pFile == NULL )
{
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
for( int i = 0; i < size; ++i )
{
fprintf( pFile, "%02X", data[i] );
if( i == 0 )
{
continue;
}
if( ( (i+1) % 8 ) == 0 )
{
fprintf( pFile, " " );
}
if( ( (i+1) % 16 ) == 0 )
{
fprintf( pFile, " " );
}
if( ( (i+1) % 32 ) == 0 )
{
fprintf( pFile, "\n" );
}
}
fprintf( pFile, "\n" );
fflush( pFile );
// 종료 처리.
fclose( pFile );
return false;
}
+273
View File
@@ -0,0 +1,273 @@
/***************************************************************************
Logger.h
-----------------------------------------
begin : 2011/10/26
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.2.0.805
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __LOGGER_H__
#define __LOGGER_H__
#include <string>
#include <vector>
#include <pthread.h>
///@brief 로그 레벨 정의
#define LEMR 0 /* system is or will be unusable if situation is not resolved */
#define LALT 1 /* immediate action required */
#define LCRT 2 /* critical situations */
#define LERR 3 /* error conditions */
#define LWAR 4 /* recoverable errors */
#define LNOT 5 /* unusual situation that merits investigation */
#define LINF 6 /* information messages */
#define LDBG 7 /* verbose data for debugging */
#define LDEV 8 /* verbose data for developer */
#define LDEV1 9 /* start or end the function of application level */
#define LDEV2 10 /* start or end the function of application level */
#define MAX_LOG_LEVEL LDEV2
///@brief Log 정보를 파일로 저장하기 위한 Class.
///1. 가변 format 으로 전달된 로그 관련 정보를 Log Level 에 따라 로그 파일에 아래의 4가지 형식으로 저장한다.
///
/// 1.1 Prefix로 [hh:mm:ss]와 [ClassName::FunctionName]이 추가된 로그
/// LOG( level, format, ... ) 매크로 사용.
/// 예) [17:43:40] [DBG] log level debug [LoggerTestTestLogger]
///
/// 1.2 Prefix로 [hh:mm:ss]이 추가된 로그
/// _LOG( level, format, ... ) 매크로 사용
/// 예) [17:43:40] [EMR] log level emergency
///
/// 1.3 Prefix가 없는 로그
/// _LOG_( level, format, ... ) 매크로 사용
/// 예) log level emergency
///
/// 1.4 Hex 로그.
/// LOG_HEX( level, data, size ) 매크로 사용
/// 예) 00010203 04050607 08090A0B 0C0D0E0F
///
///2. Logger 객체 초기화시 전달된 Log Level 정보보다 전달받은 Log Level 정보가 큰 경우 해당 로그는 파일로 저장되지 않는다.
///
///3. 로그 파일은 매 일단위로 저장파일이 변경된다.
///
///4. 로그 저장을 위한 program 경로가 존재하지 않는 경우 자동 생성 처리된다.
///
///5. 로그 저장방식은 매 저장로그마다 open-close 로 처리된다.
///
///6. 파일로 기록시 Log Level 에 대한 정보도 함께 기록된다.
///
///7. 싱글톤으로 작성되었고, CLogger::Init(...)시에 쓰레드 안정성을 제공한다.
///
///8. 동적으로 로그 레벨을 변경할 수 있는 인터페이스를 제공한다.
///
class CLogger
{
// Attributes
private:
///@brief 싱글톤 객체 인트턴스.
static CLogger* m_pInstance;
///@brief 싱글톤 객체 초기화 여부.
static bool m_bIsInitialized;
///@brief 싱글톤 객체 초기화시 스레드 안정성을 위한 뮤텍스.
static pthread_mutex_t m_mutex;
///@brief 프로그램 이름. 로그 파일 경로를 만들 때 사용.
std::string m_szProgramName;
///@brief 공통 로그 디렉토리 이름. 로그 파일 경로를 만들 때 사용.
std::string m_szLogDir;
///@brief 로그 레벨.
int m_nLogLevel;
///@brief 로그 레벨에 대응되는 문자열 정보를 저장.
std::vector<std::string> m_vectorLogLevelString;
protected:
public:
///@brief 로그 형식을 지정.
typedef enum
{
PREFIX_NONE = 0, /// 클래스 설명의 1.3에 해당
PREFIX_DATE, /// 클래스 설명의 1.2에 해당
PREFIX_FUNCTION, /// 클래스 설명의 1.1에 해당
} LOG_PREFIX;
// Operations
private:
///@brief 생성자.
/// 프로그램 이름, 공통 로그 디렉토리, 로그 레벨을 저장하고
/// 로그 레벨에 대응되는 문자열 정보를 만든다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@param logLevel [in] 로그 레벨
CLogger( std::string programName, std::string logDir, int logLevel );
///@brief 소멸자.
/// 로그 레벨에 대응되는 문자열 정보를 저장하고 있는
/// 벡터 m_vectorLogLevelString을 clear 시킴.
virtual ~CLogger();
///@brief 로그 레벨에 대응되는 문자열을 만든다.
///@param none.
///@return none.
void MakeLogLevelString();
///@brief 로그 파일이 위치할 실제 로그 디렉토리를 생성한다.
/// 생성할 디렉토리 경로는 'logDir/programName'이 된다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@return 디렉토리가 이미 존재하거나 생성 성공하면 true,
/// 해당 경로가 존재하지만 디렉토리가 아니거나, 디렉토리 생성 실패하면 false 반환.
static bool MakeLogDir( std::string programName, std::string logDir );
///@brief 해당 경로가 디렉토리 인지 아닌지 판단.
///@param path [in] 디렉토리 인지 아닌지 판단할 경로.
///@return 해당 경로가 디렉토이면 true,
/// 경로가 존재하지 않거나 디렉토리가 아니면 false 반환.
static bool IsDirectory( std::string path );
///@brief 로그 레벨이 올바른지 판별.
///@param logLevel [in]
///@return 올바른 로그 레벨이면 true, 그렇지 않으면 false 반환.
static bool IsValidLogLevel( int logLevel );
///@brief 시간 정보를 입력 받아 로그 파일 이름을 만든다.
/// 로그 파일 이름 형식 : 프로그램명_YYYYMMDD.log
///param timeNow [in] 현재 시간 정보.
///return 로그 파일 이름.
std::string GetLogFilename( struct tm &timeNow );
///@brief 로그를 남기는는 클래스가 정의된 파일의 이름에서 클래스명을 추출한다.
/// 쓰레드 안정성을 보장한다.
///@param className [out] 파일 이름에서 추출된 클래스명
///@param filename [in] 파일 이름.
///@return 클래스명 추출이 성공하면 클래스명 문자열의 포인터, 추출 실패하면 NULL.
const char* GetClassName( char* className, const char* filename );
///@brief 인자 logPrefix에 따라 적절한 형식으로 로그 파일에 로그를 저장한다.
/// 인자 logLevel이 설정된 로그 레벨보다 높으면 로그를 출력하지 않는다.
///@param logLevel [in] 로그 레벨
///@param logPrefix [in] 로그 프리픽스 종류.
///@functionName [in] ClassName::FunctionNmae() 형식의 문자열.
///@lineNum [in] 라인 번호.
///@log [in] 출력하고자 하는 로그 내용.
bool Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log );
protected:
public:
///@brief 싱글톤 객체 m_pInstance를 생성하고 인자 정보로 로그 디렉토리를 만든다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@param logLevel [in] 로그 레벨
///@return 로그 디렉토리를 만들고 싱글톤 객체를 생성했으면 true,
/// 로그 디렉토리를 만들지 못 했거나 인자 값이 올바르지 않으면 false 반환.
static bool Init( std::string programName, std::string logDir, int logLevel );
///@brief 싱글톤 객체 m_pInstance를 delete 한다.
///@param none.
///@return none.
static void Exit();
///@brief 싱글톤 객체 m_pInstance를 반환한다.
///@param none.
///@return CLogger 객체의 인스턴스.
static CLogger* GetInstance();
///@brief Prefix로 [hh:mm:ss]이 추가된 형식으로 로그 저장.
///@param logLevel [in] 로그 레벨
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool Write( int logLevel, const char * fmt, ...)
__attribute__((format(printf, 3, 4)));
///@brief Prefix가 없는 로그 저장.
///@param logLevel [in] 로그 레벨
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteNoPrefix( int logLevel, const char * fmt, ...)
__attribute__((format(printf, 3, 4)));
// CHG 2012-08-16 huibong
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
///@brief Prefix로 [hh:mm:ss]와 [ClassName::FunctionName:line]이 추가된 형식으로 로그 저장.
///@param logLevel [in] 로그 레벨
///@param filename [in] 파일 이름
///@param funcname [in] 함수 이름
///@param lineNum [in] 라인 번호
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
__attribute__((format(printf, 6, 7)));
///@brief 로그를 hex 형식으로 저장.
///@param logLevel [in] 로그 레벨
///@param data [in] hex 형식으로 출력할 데이터.
///@pram size [in] data의 크기.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteHex( int logLevel, const unsigned char* data, const int size );
///@brief 로그을 설정한다. 인자 logLevel이 적절한 값이면 새로운 값으로 변경하고
/// 적절한 값이 아니면 로그 레벨을 변경하지 않는다.
///@param logLevel [in] 설정할 로그 레벨
///@return none.
bool SetLogLevel( int logLevel );
inline int GetLogLevel() { return m_nLogLevel; };
inline std::string GetLogDir() { return m_szLogDir + "/" + m_szProgramName; };
};
#define LOG( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteWithFunc( level, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__ ); \
}
#define _LOG( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->Write( level, format, ##__VA_ARGS__ ); \
}
#define _LOG_( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteNoPrefix( level, format, ##__VA_ARGS__ ); \
}
#define _LOG_HEX_( level, data, size ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteHex( level, (const unsigned char*)data, size ); \
}
#define FUNC_BEGIN() LOG( LDEV1, "begin" )
#define FUNC_END() LOG( LDEV1, "end" )
#define FRM_BEGIN() LOG( LDEV2, "begin" )
#define FRM_END() LOG( LDEV2, "end" )
#endif // __LOGGER_H__
+62
View File
@@ -0,0 +1,62 @@
#****************************************************************************
# Makefile for INTERACTIVE Common Libaray
# -----------------------------------------
#
# 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.
#*****************************************************************************
# Library info
LIB_NAME = InterCommon
LIB = lib$(LIB_NAME).a
OBJS = md5c.o Config.o Logger.o BaseSocket.o
# Compiler info
CC = /usr/bin/g++
AR = /usr/bin/ar
DIR_INCLUDE = -I/usr/local/include
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized\
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-D_REENTRANT
LFLAGS =
DFLAGS =
############################
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
+46
View File
@@ -0,0 +1,46 @@
/* GLOBAL.H - RSAREF types and constants */
/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
Inc., created 1991. All rights reserved.
*/
#ifndef _GLOBAL_H_
#define _GLOBAL_H_ 1
/* PROTOTYPES should be set to one if and only if the compiler supports
function argument prototyping.
The following makes PROTOTYPES default to 1 if it has not already been
defined as 0 with C compiler flags.
*/
#ifndef PROTOTYPES
#define PROTOTYPES 1
#endif
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
typedef unsigned int UINT4;
#ifndef NULL_PTR
#define NULL_PTR ((POINTER)0)
#endif
#ifndef UNUSED_ARG
#define UNUSED_ARG(x) x = *(&x);
#endif
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
returns an empty list.
*/
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif
#endif /* end _GLOBAL_H_ */
+50
View File
@@ -0,0 +1,50 @@
/* MD5.H - header file for MD5C.C
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#ifndef _MD5_H_
#define _MD5_H_ 1
#ifdef __cplusplus
extern "C" {
#endif
/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
void MD5Init PROTO_LIST ((MD5_CTX *));
void MD5Update PROTO_LIST
((MD5_CTX *, unsigned char *, unsigned int));
void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
#ifdef __cplusplus
}
#endif
#endif
+315
View File
@@ -0,0 +1,315 @@
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
//#include "stdafx.h"
#include "global.h"
#include "md5.h"
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
static void Encode PROTO_LIST
((unsigned char *, UINT4 *, unsigned int));
static void Decode PROTO_LIST
((UINT4 *, unsigned char *, unsigned int));
static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void MD5Init (MD5_CTX *context/* context */)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void MD5Update (MD5_CTX *context /* context */, unsigned char *input/* input block */, unsigned int inputLen/* length of input block */)
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)&input[i],
inputLen-i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void MD5Final (unsigned char digest[16]/* message digest */, MD5_CTX *context/* context */)
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)context, 0, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform (UINT4 state[4], unsigned char block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)x, 0, sizeof (x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
/* Note: Replace "for loop" with standard memcpy if possible.
*/
static void MD5_memcpy (POINTER output, POINTER input, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
/* Note: Replace "for loop" with standard memset if possible.
*/
static void MD5_memset (POINTER output, int value, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
}
+257
View File
@@ -0,0 +1,257 @@
/* MDDRIVER.C - test driver for MD2, MD4 and MD5
*/
/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
rights reserved.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/* The following makes MD default to MD5 if it has not already been
defined with C compiler flags.
*/
#include "stdafx.h"
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "global.h"
#define MD5 5
#ifndef MD
#define MD MD5
#endif
#if MD == 2
#include "md2.h"
#endif
#if MD == 4
#include "md4.h"
#endif
#if MD == 5
#include "md5.h"
#endif
/* Length of test block, number of test blocks.
*/
#define TEST_BLOCK_LEN 1024
#define TEST_BLOCK_COUNT 5000
static void MDString PROTO_LIST ((char *));
static void MDTimeTrial PROTO_LIST ((void));
static void MDTestSuite PROTO_LIST ((void));
static void MDFile PROTO_LIST ((char *));
static void MDFilter PROTO_LIST ((void));
static void MDPrint PROTO_LIST ((unsigned char [16]));
#if MD == 2
#define MD_CTX MD2_CTX
#define MDInit MD2Init
#define MDUpdate MD2Update
#define MDFinal MD2Final
#endif
#if MD == 4
#define MD_CTX MD4_CTX
#define MDInit MD4Init
#define MDUpdate MD4Update
#define MDFinal MD4Final
#endif
#if MD == 5
#define MD_CTX MD5_CTX
#define MDInit MD5Init
#define MDUpdate MD5Update
#define MDFinal MD5Final
#endif
/* Main driver.
Arguments (may be any combination):
-sstring - digests string
-t - runs time trial
-x - runs test script
filename - digests file
(none) - digests standard input
*/
/*
int main (int argc, char *argv[])
{
int i;
if (argc > 1)
for (i = 1; i < argc; i++)
if (argv[i][0] == '-' && argv[i][1] == 's')
MDString (argv[i] + 2);
else if (strcmp (argv[i], "-t") == 0)
MDTimeTrial ();
else if (strcmp (argv[i], "-x") == 0)
MDTestSuite ();
else
MDFile (argv[i]);
else
MDFilter ();
return (0);
}
*/
int _tmain(int argc, _TCHAR* argv[])
{
int i;
if (argc > 1) {
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-' && argv[i][1] == _T('s'))
MDString ((char*)(argv[i] + 2));
else if (_tcscmp (argv[i], _T("-t")) == 0)
MDTimeTrial ();
else if (_tcscmp (argv[i], _T("-x")) == 0)
MDTestSuite ();
else
MDFile ((char*)argv[i]);
}
} else {
MDFilter ();
}
return 0;
}
/* Digests a string and prints the result.
*/
static void MDString (char *string)
{
MD_CTX context;
unsigned char digest[16];
unsigned int len = (unsigned int)strlen (string);
MDInit (&context);
MDUpdate (&context, (unsigned char*)string, len);
MDFinal (digest, &context);
printf ("MD%d (\"%s\") = ", MD, string);
MDPrint (digest);
printf ("\n");
}
/* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte
blocks.
*/
static void MDTimeTrial ()
{
MD_CTX context;
time_t endTime, startTime;
unsigned char block[TEST_BLOCK_LEN], digest[16];
unsigned int i;
printf
("MD%d time trial. Digesting %d %d-byte blocks ...", MD,
TEST_BLOCK_COUNT, TEST_BLOCK_LEN);
/* Initialize block */
for (i = 0; i < TEST_BLOCK_LEN; i++)
block[i] = (unsigned char)(i & 0xff);
/* Start timer */
time (&startTime);
/* Digest blocks */
MDInit (&context);
for (i = 0; i < TEST_BLOCK_COUNT; i++)
MDUpdate (&context, block, TEST_BLOCK_LEN);
MDFinal (digest, &context);
/* Stop timer */
time (&endTime);
printf (" done\n");
printf ("Digest = ");
MDPrint (digest);
printf ("\nTime = %ld seconds\n", (long)(endTime-startTime));
printf
("Speed = %ld bytes/second\n",
(long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime));
}
/* Digests a reference suite of strings and prints the results.
*/
static void MDTestSuite ()
{
printf ("MD%d test suite:\n", MD);
MDString ("");
MDString ("a");
MDString ("abc");
MDString ("message digest");
MDString ("abcdefghijklmnopqrstuvwxyz");
MDString
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
MDString
("1234567890123456789012345678901234567890\
1234567890123456789012345678901234567890");
}
/* Digests a file and prints the result.
*/
static void MDFile (char *filename)
{
FILE *file;
MD_CTX context;
int len;
unsigned char buffer[1024], digest[16];
if ((file = fopen (filename, "rb")) == NULL)
printf ("%s can't be opened\n", filename);
else {
MDInit (&context);
while (len = fread (buffer, 1, 1024, file))
MDUpdate (&context, buffer, len);
MDFinal (digest, &context);
fclose (file);
printf ("MD%d (%s) = ", MD, filename);
MDPrint (digest);
printf ("\n");
}
}
/* Digests the standard input and prints the result.
*/
static void MDFilter ()
{
MD_CTX context;
int len;
unsigned char buffer[16], digest[16];
MDInit (&context);
while (len = fread (buffer, 1, 16, stdin))
MDUpdate (&context, buffer, len);
MDFinal (digest, &context);
MDPrint (digest);
printf ("\n");
}
/* Prints a message digest in hexadecimal.
*/
static void MDPrint (unsigned char digest[16])
{
unsigned int i;
for (i = 0; i < 16; i++)
printf ("%02x", digest[i]);
}
+473
View File
@@ -0,0 +1,473 @@
#include "FileHash.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#define PARTITIAL_LIMIT (1) // (단위:MByte))
typedef unsigned long long UINT64;
CFileHash::CFileHash()
{
MDInit( &m_contextForBuffer );
m_nPartitialSize = PARTITIAL_LIMIT*(1024*1024);
}
string CFileHash::GetLastErrorMessage()
{
string szMessage = m_szLastErrorMessage;
return szMessage;
}
int CFileHash::GetPartitialSize()
{
return m_nPartitialSize/(1024*1024);
}
bool CFileHash::SetPartitialSize( int nPartitialSize )
{
if( nPartitialSize <= 0)
return false;
m_nPartitialSize = nPartitialSize*(1024*1024);
return true;
}
void CFileHash::UpdateBufferHash(unsigned char* szBuffer, int nLen )
{
MDUpdate( &m_contextForBuffer, szBuffer, nLen );
}
void CFileHash::GetBufferHash(string& szResult)
{
unsigned char szDigest[16];
char szHexBuffer[3];
int i;
szResult.clear();
// 멤버 context를 이해애서 Digest값을 얻어온다.
MDFinal( szDigest, &m_contextForBuffer );
// 해시값을 hex_digest 값으로 바꿔준다.
for( i = 0; i<16 ; i++ )
{
memset( szHexBuffer, 0x00, sizeof( szHexBuffer ) );
sprintf( szHexBuffer, "%02x", szDigest[i] );
szResult.append( (char*)szHexBuffer);
}
}
/// @breif Buffer Hash 했던 값을 초기화 하는 함수.
void CFileHash::ClearBufferHash()
{
MDInit( &m_contextForBuffer );
}
/// @brief Sender에서 사용하는 함수로서 파일에 대한 해쉬값을 레벨에 따라 생성한다.
/// @param szFileFullPath [in] 파일의 절대경로 값.
/// @param nHashLevel [in] 해싱 방법에 대한 레벨 값.
/// @param szResult [out] 해싱된 결과값을 되돌려주는 변수.
/// @return 성공은 return true, 그 외에는 return false
bool CFileHash::GetFileHash(const string& szFileFullPath, int nHashLevel, string& szResult)
{
struct stat filestatus;
switch(nHashLevel)
{
case HASH_LEVEL_NONE:
szResult = "0000";
break;
case HASH_LEVEL_FULL:
// 해시 대상파일 오픈.
if( !GetHashFull(szFileFullPath, szResult) )
{
return false;
}
break;
case HASH_LEVEL_PARTITIAL:
// 파일 사이즈를 체크한다. PARTITIAL_LIMIT 사이즈 이하이면
stat( szFileFullPath.c_str(), &filestatus );
if( filestatus.st_size <= m_nPartitialSize*2 )
{
// 2MB이하일경우 파일전체 해시값을 구한다.
if( !GetHashFull(szFileFullPath, szResult) )
{
return false;
}
}else
{
// 옵션일 경우 PARTITIAL_LIMIT사이즈의 1/2을
// 파일 맨앞과 맨뒤에서 추출해서 해시값을 생성한다.
if( !GetHashPartitial(szFileFullPath, szResult) )
{
return false;
}
}
break;
case HASH_LEVEL_FRONT_PARTITIAL:
// 파일 사이즈를 체크한다. 설정된 값 이하이면
stat( szFileFullPath.c_str(), &filestatus );
if( filestatus.st_size <= m_nPartitialSize )
{
// 파일전체 해시값을 구한다.
if( !GetHashFull(szFileFullPath, szResult) )
{
return false;
}
}
else
{
// 파일 맨앞에서 해시값을 생성한다.
if( !GetHashFrontPartitial(szFileFullPath, szResult) )
{
return false;
}
}
break;
default:
sprintf( m_szLastErrorMessage, "Not support level[%d] on this class", nHashLevel);
return false;
break;
}
return true;
}
/// @brief Receiver에서 사용하는 함수로서 해당파일의 해시값과 Sender에서 받은 해싱값을 비교한 결과를 전달한다.
/// @param szFileFullPath [in] 파일의 절대경로 값.
/// @param nHashLevel [in] 해싱 방법에 대한 레벨 값.
/// @param szResult [out] Sender로 부터 받은 해시 값.
/// @return 같은 값일경우 return true, 그 외에는 return false
bool CFileHash::GetHashFull(const string& szFileFullPath, string& szResult)
{
int fd;
int nLen;
int i;
MD_CTX context;
unsigned char szBuffer[1024], szDigest[16];
char szHexBuffer[3];
memset(szBuffer, 0x00, sizeof(szBuffer));
memset(szDigest, 0x00, sizeof(szDigest));
memset(szHexBuffer, 0x00, sizeof(szHexBuffer));
szResult.clear();
if( ( fd = open(szFileFullPath.c_str(), O_RDONLY ) ) == -1 )
{
sprintf( m_szLastErrorMessage, "File open failed.[%s] ", szFileFullPath.c_str());
return false;
}
else
{
MDInit( &context );
while( ( nLen = read(fd, szBuffer, 1024) ) )
MDUpdate( &context, szBuffer, nLen );
MDFinal( szDigest, &context );
// 해시값을 hex_digest 값으로 바꿔준다.
for( i = 0; i<16 ; i++ )
{
memset( szHexBuffer, 0x00, sizeof( szHexBuffer ) );
sprintf( szHexBuffer, "%02x", szDigest[i] );
szResult.append( (char*)szHexBuffer);
}
close( fd );
}
return true;
}
bool CFileHash::GetHashPartitial(const string &szFileFullPath, string& szResult)
{
int fd;
MD_CTX context;
int nLen;
int i;
unsigned char szBuffer[1024], szDigest[16];
char szHexBuffer[3];
UINT64 nFilePos;
memset(szBuffer, 0x00, sizeof(szBuffer));
memset(szDigest, 0x00, sizeof(szDigest));
memset(szHexBuffer, 0x00, sizeof(szHexBuffer));
szResult.clear();
if( ( fd = open(szFileFullPath.c_str(), O_RDONLY ) ) == -1 )
{
sprintf( m_szLastErrorMessage, "File open failed.[%s] ", szFileFullPath.c_str());
return false;
}
else
{
MDInit( &context );
// 파일의 앞부분의 해시값을 추출한다.
nFilePos = 0;
while( (nLen = read(fd, szBuffer, 1024)) )
{
MDUpdate( &context, szBuffer, nLen );
nFilePos = lseek(fd, 0, SEEK_CUR);
// 앞부분의 해시할 값까지만 하기위한 조건.
if( (nFilePos >= (UINT64)(m_nPartitialSize)) )
break;
}
// 파일의 끝에서 해시값 추출할 시작점으로 파일포지션을 옮겨준다.
lseek(fd, 0, SEEK_END);
lseek(fd, -m_nPartitialSize , SEEK_END);
while( (nLen = read(fd, szBuffer, 1024)) )
{
MDUpdate( &context, szBuffer, nLen );
nFilePos = lseek(fd, 0, SEEK_CUR);
}
MDFinal( szDigest, &context );
// 해시값을 hex_digest 값으로 바꿔준다.
for( i = 0; i<16 ; i++ )
{
memset( szHexBuffer, 0x00, sizeof( szHexBuffer ) );
sprintf( szHexBuffer, "%02x", szDigest[i] );
szResult.append( (char*)szHexBuffer);
}
close( fd );
}
return true;
}
bool CFileHash::GetHashFrontPartitial(const string &szFileFullPath, string& szResult)
{
int fd;
MD_CTX context;
int nLen;
int i;
unsigned char szBuffer[1024], szDigest[16];
char szHexBuffer[3];
UINT64 nFilePos;
memset(szBuffer, 0x00, sizeof(szBuffer));
memset(szDigest, 0x00, sizeof(szDigest));
memset(szHexBuffer, 0x00, sizeof(szHexBuffer));
szResult.clear();
if( ( fd = open(szFileFullPath.c_str(), O_RDONLY ) ) == -1 )
{
sprintf( m_szLastErrorMessage, "File open failed.[%s] ", szFileFullPath.c_str());
return false;
}
else
{
MDInit( &context );
// 파일의 앞부분의 해시값을 추출한다.
nFilePos = 0;
while( (nLen = read(fd, szBuffer, 1024)) )
{
MDUpdate( &context, szBuffer, nLen );
nFilePos = lseek(fd, 0, SEEK_CUR);
// 앞부분의 해시할 값까지만 하기위한 조건.
if( (nFilePos >= (UINT64)(m_nPartitialSize)) )
break;
}
MDFinal( szDigest, &context );
// 해시값을 hex_digest 값으로 바꿔준다.
for( i = 0; i<16 ; i++ )
{
memset( szHexBuffer, 0x00, sizeof( szHexBuffer ) );
sprintf( szHexBuffer, "%02x", szDigest[i] );
szResult.append( (char*)szHexBuffer);
}
close( fd );
}
return true;
}
bool CFileHash::CheckFileHash(const string& szFileFullPath, int nHashLevel, const string szCompareHash)
{
string szMd5;
if( !GetFileHash(szFileFullPath, nHashLevel, szMd5 ) )
{
return false;
}
if( szCompareHash.compare(szMd5) != 0 )
{
sprintf( m_szLastErrorMessage, "Hash not match. source[%s] local[%s]", szCompareHash.c_str(), szMd5.c_str());
return false;
}
return true;
}
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460, #27533)
/// @brief 토토디스크 고객사 지원용 파일 Hash 정보 추출 함수
/// @param szFileFullPath [in] 파일의 절대경로 값.
/// @param nFileTotalSize [in] 파일 크기 값.
/// @param szResultTotosoraMd5 [out] TOTOROSA MD5 추출 결과값을 반환하기 위한 변수.
/// @param szResultDnaCheckKey [out] 토토 DNA Check Key 추출 결과값을 반환하기 위한 변수.
/// @return 성공은 return true, 그 외에는 return false
bool CFileHash::GetHashTOTO( const string &szFileFullPath, const unsigned long long nFileTotalSize, string& szResultTotosoraMd5, string& szResultDnaCheckKey )
{
int fd;
MD_CTX context;
int i;
unsigned char szBuffer[10240], szDigest[16];
char szHexBuffer[3];
memset( szBuffer, 0x00, sizeof( szBuffer ) );
memset( szDigest, 0x00, sizeof( szDigest ) );
memset( szHexBuffer, 0x00, sizeof( szHexBuffer ) );
szResultTotosoraMd5.clear();
szResultDnaCheckKey.clear();
if( (fd = open( szFileFullPath.c_str(), O_RDONLY )) == -1 )
{
sprintf( m_szLastErrorMessage, "File open failed. [%s] ", szFileFullPath.c_str() );
return false;
}
else
{
////////////// TOTOROSA MD5 해시 추출 Start ///////////////////////
// 2016-05-04 huibong ( #27460 )
// 토토디스크 고객사 지원을 위해
// 토토디스크에서 사용하는 Content Hash 추출 방법에 따른 기능 개발
// 추출 관련해서는 MD5 Hash 추출 방법을 사용하며...
// 파일 앞 최대 약 1MByte 까지 추출하고... 파일 크기가 1 M 이상이면.. 맨뒤의 10 KByte 추가 추출
// 하지만.. 고객사 Java 코드 보니까.. 추출 코드가 전반적으로 이상하게 되어 있어....
// 임의 수정시 문제 될 수 있으므로... 고객사에서 사용한 추출 Flow 를 그대로 사용한다.
// 관련 변수 초기화.
long nFileSize = 0;
int dwBytesRead = 0;
bool bRun = true;
// MD5 hash 객체 초기화.
MDInit( &context );
// 최초 10,240 만큼 read.
dwBytesRead = read( fd, szBuffer, 10240 );
while( dwBytesRead > 0 )
{
nFileSize += dwBytesRead;
MDUpdate( &context, szBuffer, dwBytesRead );
if( nFileSize > 1048576 )
{
if( (nFileTotalSize > 1048576 + 10240) && bRun )
{
// 파일의 끝에서 해시값 추출할 시작점으로 파일포지션을 옮겨준다.
lseek( fd, 0, SEEK_END );
lseek( fd, -10240, SEEK_END );
bRun = false;
}
else
{
break;
}
}
dwBytesRead = read( fd, szBuffer, 10240 );
}
MDFinal( szDigest, &context );
// 해시값을 hex_digest 값으로 바꿔준다.
for( i = 0; i<16; i++ )
{
memset( szHexBuffer, 0x00, sizeof( szHexBuffer ) );
sprintf( szHexBuffer, "%02x", szDigest[i] );
szResultTotosoraMd5.append( (char*)szHexBuffer );
}
////////////// TOTOROSA MD5 해시 추출 End ///////////////////////
// 파일 Position 을 맨 앞으로 이동 처리한다.
lseek( fd, 0, SEEK_SET );
// 사용 버퍼 객체 초기화.
memset( szBuffer, 0x00, sizeof( szBuffer ) );
memset( szDigest, 0x00, sizeof( szDigest ) );
memset( szHexBuffer, 0x00, sizeof( szHexBuffer ) );
////////////// DNA CHECK Key 추출 Start ///////////////////////
// 2016-05-10 huibong ( #27533 )
// 토토디스크 고객사 지원을 위해 토토디스크에서 사용하는 Content DNA 추출 방법에 따른 기능 개발
// 추출 관련해서는 MD5 Hash 추출 방법을 사용하며...
// 파일 앞 최대 약 10MByte 까지 추출한 후 Hash 생성 후.. 마지막에 파일 Size 정보를 append 처리하는 방식 사용
// 하지만.. 고객사 Java 코드 보니까.. 코드가 전반적으로 이상하게 되어 있어만...
// 임의 수정시 문제 될 수 있으므로... 고객사에서 사용한 추출 Flow 를 그대로 사용한다.
// MD5 hash 객체 초기화.
MDInit( &context );
nFileSize = 10485760; // 10MB
if( nFileTotalSize <= 10485760 )
{
nFileSize = nFileTotalSize;
}
do
{
if( nFileSize < 1024 )
{
dwBytesRead = read( fd, szBuffer, (int)nFileSize );
}
else
{
dwBytesRead = read( fd, szBuffer, 1024 );
}
MDUpdate( &context, szBuffer, dwBytesRead );
nFileSize = nFileSize - dwBytesRead;
} while( nFileSize > 0 );
MDFinal( szDigest, &context );
// 해시값을 hex_digest 값으로 바꿔준다.
for( i = 0; i<16; i++ )
{
memset( szHexBuffer, 0x00, sizeof( szHexBuffer ) );
sprintf( szHexBuffer, "%02x", szDigest[i] );
szResultDnaCheckKey.append( (char*)szHexBuffer );
}
// 추출된 10M Hash 결과에 파일 Size 정보를 append 처리한다.
memset( szBuffer, 0x00, sizeof( szBuffer ) );
sprintf( (char*)szBuffer, "%llu", nFileTotalSize );
szResultDnaCheckKey.append( (char *)szBuffer );
////////////// DNA CHECK Key 추출 End ///////////////////////
// 파일 close
close( fd );
}
return true;
}
+113
View File
@@ -0,0 +1,113 @@
/***************************************************************************
File Hash 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 __FILEHASH_H__
#define __FILEHASH_H__
#include <string>
#include "global.h"
#include "md5.h"
#define MD_CTX MD5_CTX
#define MDInit MD5Init
#define MDUpdate MD5Update
#define MDFinal MD5Final
using namespace std;
#define HASH_LEVEL_NONE 0
#define HASH_LEVEL_PARTITIAL 1
#define HASH_LEVEL_FULL 2
#define HASH_LEVEL_FRONT_PARTITIAL 3 // 2012-08-13 Content 앞 특정 부분만 Hash 추출을 위해 추가
/// @brief CFileHash class
/// 주 목적은 파일의 해시값을 구하는 것이다.
///
/// 상황에 따라 세가지 해시방법을 제공한다.
/// 1. 파일 전체를 해시.
/// 2. 파일의 앞일부와 뒤의 일부를 해시처리 한다.(속도 개선)
/// 3. buffer와 buffer의 길이를 입력값으로 하는 buffer 모드.
///
/// 또한 전달받은 해시와 로컬파일의 해시를 Level에 따라 체크 하는 인터페이스도
/// 제공하고있다.
///
/// 에러 상황은 GetLastErrorMessage() 함수를 통해 어떤이유로 에러가 발생했는지
/// 확인 할 수 있다.
class CFileHash
{
public :
CFileHash();
/// @brief Sender에서 사용하는 함수로서 파일에 대한 해쉬값을 레벨에 따라 생성한다.
/// @param szFileFullPath [in] 파일의 절대경로 값.
/// @param nHashLevel [in] 해싱 방법에 대한 레벨 값.
/// @param szResult [out] 해싱된 결과값을 되돌려주는 변수. nHashLevel이 HASH_LEVEL_NONE일 경우 항상 "0000"이 들어감.
/// @return 성공은 return true, 그 외에는 return false
bool GetFileHash(const string &szFileFullPath, int nHashLevel, string& szResult);
/// @brief Receiver에서 사용하는 함수로서 해당파일의 해시값과 Sender에서 받은 해싱값을 비교한 결과를 전달한다.
/// @param szFileFullPath [in] 파일의 절대경로 값.
/// @param nHashLevel [in] 해싱 방법에 대한 레벨 값.
/// @param szCompareHash [out] Sender로 부터 받은 해시 값.
/// @return 같은 값일경우 return true, 그 외에는 return false
bool CheckFileHash(const string& szFileFullPath, int nHashLevel, const string szCompareHash);
/// @brief Sender쪽에서 보낼때 파일을 buffer단위로 해싱처리를 하기위한 인터페이스다.
/// @param szBuffer [in] 해싱할 데이터
/// @param nLen [in] 해싱할 데이터의 길이.
/// @return 없음.
void UpdateBufferHash(unsigned char* szBuffer, int nLen );
/// @brief UpdateBufferHash() 함수를 이용해서 해싱한 결과값을 얻어온다.
/// @param szResult [out] 결과값을 되돌려주는 변수
/// @return 없음.
void GetBufferHash(string& szResult);
/// @brief Buffer Hash 했던 값을 초기화 하는 함수.
/// @return 없음.
void ClearBufferHash();
/// @brief HASH_LEVEL_PARTITIAL일 경우 파일의 앞뒤의 일정용량을 해시대상으로 삼는데 그 용량값의 설정값을 얻는다.
/// @return 없음.
int GetPartitialSize();
/// @brief HASH_LEVEL_PARTITIAL일 경우 파일의 앞뒤의 일정용량을 해시대상으로 삼는데 그 용량값의 설정값을 세팅한다.
/// @param nPartitialSize [in] MByte 단위로 partitial 크기를 설정한다. (0 또는 (-) 음수는 처리안함)
/// @return 성공은 return true, 실패는 return false
bool SetPartitialSize( int nPartitialSize );
/// @brief 각 함수 호출시 마지막에 난 에러메세지를 얻을 수 있다.
/// @return 마지막에 발생한 에러메세지.
string GetLastErrorMessage();
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460, #27533)
/// @brief 토토디스크 고객사 지원용 파일 Hash 정보 추출 함수
/// @param szFileFullPath [in] 파일의 절대경로 값.
/// @param nFileTotalSize [in] 파일 크기 값.
/// @param szResultTotosoraMd5 [out] TOTOROSA MD5 추출 결과값을 반환하기 위한 변수.
/// @param szResultDnaCheckKey [out] 토토 DNA Check Key 추출 결과값을 반환하기 위한 변수.
/// @return 성공은 return true, 그 외에는 return false
bool GetHashTOTO( const string &szFileFullPath, const unsigned long long nFileTotalSize, string& szResultTotosoraMd5, string& szResultDnaCheckKey );
private :
int m_nPartitialSize;
MD_CTX m_contextForBuffer;
char m_szLastErrorMessage[1024];
bool GetHashFull(const string &szFileFullPath, string& szResult);
bool GetHashPartitial(const string &szFileFullPath, string& szResult);
bool GetHashFrontPartitial(const string &szFileFullPath, string& szResult);
};
#endif //__FILEHASH_H__
+706
View File
@@ -0,0 +1,706 @@
#include "FileSender.h"
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <iostream>
#include <algorithm> // find 함수 사용 목적
CFileSender::CFileSender(CIPCache * pIpCache, CProcessStatus * pProcess, CSocketControl * pSockCtl )
: m_bProcessing( false )
, m_bThreadStop( false )
, m_pIpCache ( pIpCache )
, m_pProcessStatus( pProcess )
, m_pSocketControl( pSockCtl )
, m_fhsAvailableCount(0)
{
// NEW 2013-03-19 huibong
// Thread 핸들 멤버 변수 초기화 처리 (Valgrind 체크시 수정 필요사항)
// CHG 2014-05-26 huibong
// 본 모듈 특징상 Thread 가 생성되었다가
// 1. 지정된 전송 작업을 마친 후 정상적으로 Thread 가 종료됨.
// 2. 업무 Flow 에 따라 Thread 가 전송 작업 중 모듈 객체 자체가 소멸될 수 있음.
// 이에 따라 Thread Handle 을 정확하게 제어해야 함.
// - 잘못 제어할 경우... 다른 Thread Handle 에 명령을 내릴 수 있으므로 주의 (#19102)
// 하지만... OS 에 따라 pthread_t Type 이 서로 다름
// - FreeBSD : pthread 구조체에 대한 포인터
// - Linux : unsigned long integer
#ifdef __FreeBSD__
m_threadHandle = NULL;
#else // Linux 인 경우...
m_threadHandle = 0;
#endif
}
CFileSender::~CFileSender()
{
// Thread 동작 정지 처리.
#ifdef __FreeBSD__
if( m_threadHandle != NULL )
pthread_cancel( m_threadHandle );
#else // Linux 인 경우...
if( m_threadHandle != 0 )
pthread_cancel( m_threadHandle );
#endif
m_listTarget.clear();
}
bool CFileSender::Init( const std::string& szFileName, unsigned long long nFileSize, const std::string& szTargetTranId
, std::vector<string>& vecTarget, int nHashLevel, bool bUseInternalIp, char command, std::string& szErrorMessage )
{
// 사용여부 플래그를 확인
if( IsIdle() == false )
return false;
// 전달받은 소스 파일 정보 검증.
if( CheckFileInfo( szFileName, nFileSize, szErrorMessage ) == false )
return false;
// Target FHS 갯수 검사
if( vecTarget.size() <= 0 )
{
szErrorMessage = "Target FHS count not valid.(";
szErrorMessage += vecTarget.size();
szErrorMessage += ")";
LOG( LERR, "%s", szErrorMessage.c_str() );
return false;
}
// NEW 2012-02-01 huibong
// 전달받은 Target FHS 정보 중에 현재 FHS ( 원본 ) 가 포함되었는지 검사하는 방어 코드를 추가한다.
// 실제 Control 프로세스 개발자가 실수로 원본 FHS 을 Target FHS 로 설정하여 전송 작업으로 인한 원본 파일 유실이 발생함.
char tempBuffer[256];
memset( tempBuffer, 0x00, sizeof(tempBuffer));
if( gethostname( tempBuffer, 255 ) != 0 )
{
// Current 장비의 hostname 을 가져오지 못할 경우 오류로 처리 및 전송 실패 처리.
szErrorMessage = "Source FHS hostname not valid.";
LOG( LERR, "%s [%d][%s]", szErrorMessage.c_str(), errno, strerror(errno));
return false;
}
else
{
// Current host name 이 정상인 경우 Target FHS 상에 해당 정보가 존재하는지 검사한다.
std::string szCurrentHostName = tempBuffer;
std::vector<string>::const_iterator it = find( vecTarget.begin(), vecTarget.end(), szCurrentHostName );
if( it != vecTarget.end() ) // 실제로 현재 FHS 와 Target FHS 정보가 동일할 경우 오류 처리
{
szErrorMessage = "Source FHS(";
szErrorMessage += szCurrentHostName ;
szErrorMessage += ") is included Target FHS(";
szErrorMessage += *it;
szErrorMessage += "). request not valid.";
LOG( LERR, "%s", szErrorMessage.c_str() );
return false;
}
}
// 정상인 경우 전달받은 정보를 멤버변수에 저장처리후 true 반환.
m_szSourceFileName = szFileName;
m_nSourceFileSize = nFileSize;
m_szTargetTranId = szTargetTranId;
m_vecTargetFhs = vecTarget;
m_nHashLevel = nHashLevel;
m_requestType = command;
m_bUseInternalIp = bUseInternalIp;
// 기타 변수 초기화.
m_listTarget.clear();
m_fhsAvailableCount = 0;
m_szSourceHashValue.clear();
m_bThreadStop = false;
return true;
}
/// @brief 파일 전송 관련 작업을 정지시킨다.
void CFileSender::Stop()
{
if( IsIdle() == true )
return;
m_bThreadStop = true;
return;
}
bool CFileSender::Start()
{
int nRet = ::pthread_create( &m_threadHandle, 0, CFileSender::SenderThread, this );
if( nRet != 0 )
{
// Thread 생성 실패시
int errorNum = errno;
LOG( LERR, "thread create failed.[%d][%s]", errorNum, strerror(errorNum) );
// 파일 Replication 수행을 위한 Thread 생성 실패시
// Control daemon 으로 오류 패킷 전송 처리.
m_pSocketControl->SendErrorMessageToControl( "file trnasfer thread create failed.", m_requestType );
return false;
}
return true;
}
/// @brief FileSender Class 의 Thread Function, 파일의 전송을 담당함.
void * CFileSender::SenderThread( void * arg )
{
CFileSender * pObject = reinterpret_cast<CFileSender *>(arg);
pthread_detach( pthread_self() );
// 파일 Sending 작업을 위한 함수 호출.
pObject->SetThreadStart();
pObject->Execute();
pObject->SetThreadEnd();
// CHG 2014-05-26 huibong
// Thread Handle 관련 변수 초기화 기능 추가
#ifdef __FreeBSD__
pObject->m_threadHandle = NULL;
#else // Linux 인 경우...
pObject->m_threadHandle = 0;
#endif
// CHG 2013-03-19 huibong
// detach 된 Thread 에 대해 pthread_exit() 호출시
// 기준 할당 자원에 대한 해지 처리가 되지 않아 메모리 누수 상황이 발생.
// 따라서 이를 해결하기 detach 된 thread 에 대해 pthread_exit() 호출 코드 제거.
//pthread_exit( NULL );
return NULL;
}
/// @brief 실제 파일의 전송을 처리하기 위한 함수.
void CFileSender::Execute()
{
m_pProcessStatus->AddSendCount();
// 1. Target FHS 정보 초기화.
InitFhsInfo();
// 2. Target FHS 로 접속 처리.
if( ConnectTargetFhs() == false || m_bThreadStop == true )
{
// 접속을 시도했는데 유효한 Connection 이 1개도 없는 경우
m_pProcessStatus->SubtractSendCount();
m_listTarget.clear();
return;
}
// 3. 파일의 전송 처리.
if( SendFileToFhs() == false || m_bThreadStop == true )
{
m_pProcessStatus->SubtractSendCount();
m_listTarget.clear();
return;
}
// BUG 2010-11-30 huibong
// if 구문 안의 OR 조건이 '||' 아닌 '|' 로 처리되어 이에 대한 수정처리
// 4. Hash 파일 검사 여부에 따른 처리.
if( CheckHashValue() == false || m_bThreadStop == true )
{
m_pProcessStatus->SubtractSendCount();
m_listTarget.clear();
return;
}
// 5. 해당 처리 내역을 Control 로 전송처리
if( m_bThreadStop == false )
SendTransferResultToControl();
// 6. 종료 처리
m_listTarget.clear();
m_pProcessStatus->SubtractSendCount();
}
/// @brief 대상 FHS 정보를 설정하고 접속을 설정함.
bool CFileSender::InitFhsInfo()
{
// FHS 정보 저장소 Clear 처리.
m_listTarget.clear();
// 전달받은 FHS 정보를 Target FHS 에 저장처리.
std::vector<string>::const_iterator it;
for( it = m_vecTargetFhs.begin(); it != m_vecTargetFhs.end(); it++)
{
CTargetFhsInfo target( *it );
m_listTarget.push_back( target );
}
return true;
}
/// @brief 대상 FHS 로 접속 처리를 수행.
bool CFileSender::ConnectTargetFhs()
{
// Target FHS 정보를 이용하여 접속 처리.
std::list< CTargetFhsInfo >::iterator it;
for( it = m_listTarget.begin(); it != m_listTarget.end(); it++)
{
it->MakeConnection( m_bUseInternalIp, m_pIpCache );
it->PrintToConnectionInfo();
}
// 각 Target FHS 로 접속된 유효한 Connection 이 1개로도 있는지 검사한다.
// 만약 유효한 Connection 이 1 개라도 존재하지 않는 경우 Control Daemon 에게 오류메시지를 전달하고
// 작업을 종료처리한다.
m_fhsAvailableCount = 0;
for( it = m_listTarget.begin(); it != m_listTarget.end(); it++)
{
if( it->IsAvailable() == true )
m_fhsAvailableCount++;
}
if( m_fhsAvailableCount == 0 )
{
// 유효한 Connection 을 가진 FHS 가 존재하지 않는 경우
// Control 로 오류 메시지 전송처리.
// 재시도에 대한 처리를 위해
// 오류로 처리하지 않고 성공으로 처리하여 Control 에서 재시도 처리가 이루어지도록 한다.
SendTransferResultToControl();
return false;
}
return true;
}
/// @brief 각 FHS 로 파일 전송을 시작한다.
bool CFileSender::SendFileToFhs()
{
// 1. 원본 파일에 대한 Open 처리.
std::string szErrorMessage;
int sourceFd = open( m_szSourceFileName.c_str(), O_RDONLY );
if( sourceFd == -1 )
{
// 해당 파일을 Open 할 수 없는 경우.
// control 로 오류 메시지 전송
szErrorMessage = "Source file open fail.(" + m_szSourceFileName + ")";
m_pSocketControl->SendErrorMessageToControl( szErrorMessage, m_requestType );
return false;
}
// 2. 각 FHS 로 파일 전송 요청 메시지 전송.
// ** 주의 : Control-Transfer 간 Protocol Command 가
// Transfer-Transfer 간 Command 와 다르므로 변환처리하여 전송해야 한다.
char transferCommand;
switch( m_requestType )
{
case CONTROL_FILE_REPLICATION:
transferCommand = TRANSFER_FILE_REPLICATION;
break;
case CONTROL_FILE_CACHE:
transferCommand = TRANSFER_FILE_CACHE;
break;
default:
LOG( LERR, "Command convert error [%02x]", m_requestType );
transferCommand = m_requestType;
break;
}
std::list< CTargetFhsInfo >::iterator it;
m_fhsAvailableCount = 0;
for( it = m_listTarget.begin(); it != m_listTarget.end(); it++)
{
if( it->ReadyToFileTransfer( m_szSourceFileName, m_nSourceFileSize, m_szTargetTranId, transferCommand ) == false )
{
LOG( LERR, "FHS Error [%s][%s]", (it->GetHostName()).c_str(), (it->GetErrorMessage()).c_str() );
}
// 유효 목록 FHS count 갱신
if( it->IsAvailable() == true )
m_fhsAvailableCount++;
}
// 3. 전송 가능한 FHS 정보 확인.
if( m_fhsAvailableCount == 0 )
{
// 유효한 FHS 가 없는 경우
// 오류메시지로 전송해야 하지만 그럴 경우 Control 에서 Retry 를 수행하지 않으므로
// 정상적인 동작을 수행시켜 차후에 Retry 가 수행될 수 있도록 수정한다.
close( sourceFd );
LOG( LERR, "Available target fhs not exist [%s][%llu]", m_szSourceFileName.c_str(), m_nSourceFileSize );
SendTransferResultToControl();
return false;
}
// 4. 각 FHS 로 파일 전송 시작.
// - 우선은 Buffer 를 이용한 전송처리.
// TODO 차후에는 Hash Level, 유효 FHS 수를 확인하여 noCopySend (sendfile) 방법으로 전송처리.
//if( m_nHashLevel != HASH_LEVEL_FULL || m_fhsAvailableCount == 1 )
// 0 Byte 파일이 아닌 경우에만 전송 처리.
if( m_nSourceFileSize > 0 )
{
// 2017-12-26 BUG huibong (#31633)
// read() 호출 관련 반환값 저장을 위한 nRead 가 size_t(unsigned) 형일 경우
// read() 호출시 오류로 인한 상황 인지를 못하게 됨.
// 특히 disk 장애시 -1 을 반환하고 errno 에 5(EIO) 값이 저장됨.
//size_t nRead = 0;
ssize_t nRead = 0;
size_t nWrite = 0;
unsigned char fileBuffer[FILE_DATA_BUFFER_SIZE];
memset( fileBuffer, 0x00, sizeof(fileBuffer));
unsigned long long nTotalSendSize = 0;
CFileHash * pFileHash = NULL;
if( m_nHashLevel == HASH_LEVEL_FULL)
{
pFileHash = new CFileHash;
pFileHash->ClearBufferHash();
}
// EOF를 만날 때 까지 buffer 크기 만큼 읽어 전송 처리 => 이전에 파일 사이즈 검사는 했음.
while( (nRead = read( sourceFd, fileBuffer, FILE_DATA_BUFFER_SIZE )) > 0 )
{
nWrite = (size_t)nRead;
for( it = m_listTarget.begin(); it != m_listTarget.end(); it++)
{
it->SendBufferToFile( (void *)fileBuffer, nWrite );
}
// File 에 대한 Full Hash 검사시 버퍼의 내용을 Hash 객체에 저장 처리.
if( pFileHash != NULL )
{
pFileHash->UpdateBufferHash( fileBuffer, nRead);
}
nTotalSendSize += nWrite;
// Thread 정지 처리인 경우
if( m_bThreadStop == true )
break;
}
// 2017-12-26 BUG huibong (#31633)
// disk 장애 발생시 read() 함수는 -1을 반환하고... errno 에 5(EIO) 값이 저장됨.
// 이와 관련된 기능 추가
if( nRead < 0 )
{
int errorNum = errno;
close( sourceFd );
// Hash 객체 삭제 처리
if( pFileHash != NULL )
{
delete pFileHash;
pFileHash = NULL;
}
// std::string 에서 unsinged long long 값을 문자열로 처리시 문제가 발생하여
// C style로 처리함.
char tempBuffer[1024];
snprintf( tempBuffer, sizeof( tempBuffer ) - 1, "Transfer error. source file[%s][%llu] read[%llu] error(%d:%s)."
, m_szSourceFileName.c_str(), m_nSourceFileSize, nTotalSendSize
, errorNum, strerror( errorNum ) );
szErrorMessage = tempBuffer;
// NEW 2012-02-02 huibong
// Content read error 상황을 Control 프로세스에 오류 상황으로 Control 프로세스에 보고 처리한다.
m_pSocketControl->SendErrorMessageToControl( szErrorMessage, m_requestType );
LOG( LERR, "%s", szErrorMessage.c_str() );
return false;
}
// Hash 생성시 해당 처리 결과 값을 멤버변수에 저장처리.
if( pFileHash != NULL )
{
pFileHash->GetBufferHash( m_szSourceHashValue );
delete pFileHash;
pFileHash = NULL;
}
// Thread 정지 처리인 경우
if( m_bThreadStop == true )
{
close( sourceFd );
LOG( LWAR, "File[%s] Transfer stop By thread stop flag", m_szSourceFileName.c_str() );
// CHG 2012-02-02 huibong
// File Send Thread 가 중지되는 경우는 현재 Control 과 통신 연결이 끊어진 경우 밖에 없으므로
// Control 프로세스로 결과를 전송하는 기능은 탑재하지 않는다..
// 만약 Control 가 통신 연결 해제 상황 외에 Thread 가 정지하는 기능을 추가할 경우
// Control 로 수행 결과를 전송하는 함수를 호출처리해야 한다.
return false;
}
// 만약 전달받은 파일 크기와 실제 전송한 파일의 크기가 다른 경우
// 오류 처리 하고 Socket 종료한다. => 이러면 전송된 파일은 자동으로 unlink 처리됨.
if( m_nSourceFileSize != nTotalSendSize )
{
close( sourceFd );
// std::string 에서 unsinged long long 값을 문자열로 처리시 문제가 발생하여
// C style로 처리함.
char tempBuffer[1024];
snprintf( tempBuffer, sizeof(tempBuffer)-1, "Transfer completed. But source file[%s] size changed. (file: %llu, transfer: %llu)"
, m_szSourceFileName.c_str(), m_nSourceFileSize, nTotalSendSize );
szErrorMessage = tempBuffer;
// NEW 2012-02-02 huibong
// Content 전송 완료 후 원본 파일이 변경된 상황이므로.. Control 프로세스에서 재시도를 못하도록
// 오류 상황으로 Control 프로세스에 보고 처리한다.
m_pSocketControl->SendErrorMessageToControl( szErrorMessage, m_requestType );
LOG( LERR, "%s", szErrorMessage.c_str());
return false;
}
_LOG( LINF, "File[%s] Transfer Complete[%llu / %llu]", m_szSourceFileName.c_str(), nTotalSendSize, m_nSourceFileSize );
}
else
{
_LOG( LINF, "File[%s] Transfer Complete. 0 byte file", m_szSourceFileName.c_str());
}
// 5. 파일 전송 완료 후 File Descriptor Close
close( sourceFd );
// 6. 전송 결과 응답 대기 처리.
for( it = m_listTarget.begin(); it != m_listTarget.end(); it++)
{
if( it->GetFileTransferResult() == false )
{
LOG( LERR, "Get transfer result failed [%s][%s]", (it->GetHostName()).c_str(), (it->GetErrorMessage()).c_str() );
}
}
// 7. 전송 완료 처리가 완료된 유효한 FHS 가 존재하는지 확인.
m_fhsAvailableCount = 0;
for( it = m_listTarget.begin(); it != m_listTarget.end(); it++)
{
if( it->IsAvailable() == true )
m_fhsAvailableCount++;
}
// 8. 전송 가능한 FHS 정보 확인.
if( m_fhsAvailableCount == 0 )
{
// 유효한 FHS 가 없는 경우
// 오류메시지로 전송해야 하지만 그럴 경우 Control 에서 Retry 를 수행하지 않으므로
// 정상적인 동작을 수행시켜 차후에 Retry 가 수행될 수 있도록 수정한다.
LOG( LERR, "Available target fhs not exist by send complete [%s][%llu]", m_szSourceFileName.c_str(), m_nSourceFileSize );
SendTransferResultToControl();
return false;
}
// 9. 전송 완료 처리 후 원본 소스 파일이 변경되었는지 다시 검증
if( CheckFileInfo( m_szSourceFileName, m_nSourceFileSize, szErrorMessage ) == false )
{
// 전송 완료 후 소스 파일 검증 처리시 오류가 발생한 경우.
// 이때는 원본 파일이 변경된 경우이므로 Control 에서 재시도를 하지 못하도록 오류로 처리한다.
LOG( LERR, "File[%s] transfer completed. But source file size changed.[%s]", m_szSourceFileName.c_str(), szErrorMessage.c_str());
m_pSocketControl->SendErrorMessageToControl( szErrorMessage, m_requestType );
return false;
}
return true;
}
/// @brief 파일에 대한 Hash 값을 생성하여 각 FHS 로 전송된 File 의 Hash 검사를 요청한다.
bool CFileSender::CheckHashValue()
{
// Hash 검사를 수행하지 않는 경우 그냥 통과. ^^
if( m_nHashLevel != HASH_LEVEL_PARTITIAL && m_nHashLevel != HASH_LEVEL_FULL )
return true;
// 0 Byte 파일인 경우 Hash 검사 그냥 통과.
if( m_nSourceFileSize == 0 )
return true;
std::string szErrorMessage;
// 자 Hash 검사를 수행하기 위해 Source 파일에 대한 Hash 를 생성한다.
if( m_nHashLevel == HASH_LEVEL_PARTITIAL )
{
// 부분 Hash 검사인 경우.
// Hash 처리를 위한 객체를 생성한 후 Hash 검사를 수행
CFileHash fileHash;
if( fileHash.GetFileHash( m_szSourceFileName, m_nHashLevel, m_szSourceHashValue) == false )
{
szErrorMessage = "source file hash create fail [" + m_szSourceFileName + "] [" + fileHash.GetLastErrorMessage() + "]";
m_pSocketControl->SendErrorMessageToControl( szErrorMessage, m_requestType );
LOG( LERR, "%s", szErrorMessage.c_str());
return false;
}
}
// Full Hash 인 경우 Socket 으로 데이터 전송시 Source Hash 값이 생성됨.
// Thread 정지 처리인 경우
if( m_bThreadStop == true )
{
LOG( LERR, "File[%s] Hash check stop By thread stop flag", m_szSourceFileName.c_str() );
// CHG 2012-02-02 huibong
// File Send Thread 가 중지되는 경우는 현재 Control 과 통신 연결이 끊어진 경우 밖에 없으므로
// Control 프로세스로 결과를 전송하는 기능은 탑재하지 않는다..
// 만약 Control 가 통신 연결 해제 상황 외에 Thread 가 정지하는 기능을 추가할 경우
// Control 로 수행 결과를 전송하는 함수를 호출처리해야 한다.
return false;
}
// 정상적으로 Hash 생성이 완료된 경우 각 FHS 로 Hash 검사 요청 처리.
std::list< CTargetFhsInfo >::iterator it;
for( it = m_listTarget.begin(); it != m_listTarget.end(); it++)
{
if( it->SendFileHashCheckRequest( m_nHashLevel, m_nSourceFileSize, m_szSourceHashValue) == false )
{
LOG( LERR, "Get hash check result failed [%d][%s][%s]", m_nHashLevel, (it->GetHostName()).c_str(), (it->GetErrorMessage()).c_str() );
}
}
// 각 FHS 로 부터 처리된 Hash 검사 결과 정보 수신 처리.
for( it = m_listTarget.begin(); it != m_listTarget.end(); it++)
{
if( it->GetFileHashCheckResult() == false )
{
LOG( LERR, "Get hash check result failed [%d][%s][%s]", m_nHashLevel, (it->GetHostName()).c_str(), (it->GetErrorMessage()).c_str() );
}
// Thread 정지 처리인 경우
if( m_bThreadStop == true )
{
LOG( LERR, "File[%s] Hash result stop By thread stop flag", m_szSourceFileName.c_str() );
// CHG 2012-02-02 huibong
// File Send Thread 가 중지되는 경우는 현재 Control 과 통신 연결이 끊어진 경우 밖에 없으므로
// Control 프로세스로 결과를 전송하는 기능은 탑재하지 않는다..
// 만약 Control 가 통신 연결 해제 상황 외에 Thread 가 정지하는 기능을 추가할 경우
// Control 로 수행 결과를 전송하는 함수를 호출처리해야 한다.
return false;
}
}
return true;
}
/// @brief 파일 Transfer 처리 결과를 Control Daemon 으로 전송처리.
bool CFileSender::SendTransferResultToControl()
{
std::map< std::string, std::string> mapSuccessList;
std::map< std::string, std::string> mapFailList;
std::string szHostName;
std::string szFileFullName;
std::string szErrorMessage;
// 루프를 돌면서 메시지를 생성
std::list< CTargetFhsInfo >::iterator it;
for( it = m_listTarget.begin(); it != m_listTarget.end(); it++)
{
if( (it->GetResult( szHostName, szFileFullName, szErrorMessage)) == true )
{
mapSuccessList[ szHostName ] = szFileFullName;
LOG( LDBG, "SEND::SUCCESS [%s]->[%s][%s]", m_szSourceFileName.c_str(), szHostName.c_str(), szFileFullName.c_str());
}
else
{
mapFailList[ szHostName ] = szErrorMessage;
LOG( LERR, "SEND::FAIL [%s]->[%s][%s]", m_szSourceFileName.c_str(), szHostName.c_str(), szErrorMessage.c_str());
}
}
return m_pSocketControl->SendFileReplicationResult( m_requestType, mapSuccessList, mapFailList);
}
/// @brief 전달받은 파일 및 크기가 실제 현재 경로에 존재, 크기가 정확한지 검사하기 위한 함수.
bool CFileSender::CheckFileInfo( const std::string& szFileName, unsigned long long nFileSize, std::string& szErrorMessage )
{
// 1. 전달받은 파일이 존재하는지 검사.
if( access(szFileName.c_str(), R_OK) == -1 )
{
szErrorMessage = "source file access fail.[" + szFileName + "]";
LOG( LERR, "%s", szErrorMessage.c_str() );
return false;
}
// 2. 파일 크기 검사.
FILE * pFile = fopen( szFileName.c_str(), "r+" );
if( pFile == NULL )
{
szErrorMessage = "source file open fail.[" + szFileName + "]";
LOG( LERR, "%s", szErrorMessage.c_str() );
return false;
}
else
{
fseeko( pFile, 0, SEEK_END );
off_t totalSize = ftello( pFile );
rewind( pFile );
fclose( pFile ); // 열려진 descriptor close
// ADD 2010-12-01 huibong off_t type 확인
// /usr/include/sys/_types.h 에 다음과 같이 정의됨. (64Bit, 32Bit 장비 )
// typedef __int64_t __off_t; /* file offset */
// 또한 printf 포맷 형식 중 %jd => intmax_t 형식이 존재 (/usr/include/machine/stdint.h)
// intmax_t 은 /usr/include/machine/_types.h 에 다음과 같이 정의됨 (64Bit,32Bit 동일)
// typedef __int64_t __intmax_t;
// 이에 따라 snprintf 사용시 off_t totalSize 출력형식을 기존 %lld -> %jd 로 변경처리
if( (unsigned long long)totalSize != nFileSize )
{
// std::string 에 숫자를 append 처리시 오류가 자주 발생하여 C Style 로 변환하여 처리함.
char tempBuffer[1024];
snprintf( tempBuffer, sizeof(tempBuffer)-1
, "source file size not match.[ request: %llu, local: %jd ]"
, nFileSize, totalSize );
szErrorMessage = tempBuffer;
LOG( LERR, "%s", szErrorMessage.c_str() );
return false;
}
}
// 모두 정상인 경우.
return true;
}
+120
View File
@@ -0,0 +1,120 @@
/***************************************************************************
ftsd ( File TranSfer Daemon ) Header ( FileSender.h )
-----------------------------------------
begin : 2010/03/13
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 __FILE_SENDER_H__
#define __FILE_SENDER_H__
#include "Logger.h"
#include "IPCache.h"
#include "ProcessStatus.h"
#include "SocketControl.h"
#include "TargetFhsInfo.h"
#include "FileHash.h"
#include <list>
#include <map>
class CFileSender
{
public :
CFileSender(CIPCache * pIpCache, CProcessStatus * pProcess, CSocketControl * pSockCtl );
~CFileSender();
bool Init( const std::string& szFileName, unsigned long long nFileSize, const std::string& szTargetTranId,
std::vector<string>& vecTarget, int nHashLevel, bool bUseInternalIp, char command, std::string& szErrorMessage );
bool Start( void );
/// @brief 파일 전송 관련 작업을 정지시킨다.
void Stop(void);
// 현재 객체를 사용할 수 있는지 여부.
// File 관련 작업중인 경우 false, Idle 상태인 경우 true 를 반환한다.
bool IsIdle( void ) { return !m_bProcessing; }
void SetThreadStart(void) { m_bProcessing = true; }
void SetThreadEnd(void) { m_bProcessing = false; }
private:
/// @brief FileSender Class 의 Thread Function, 파일의 전송을 담당함.
static void * SenderThread( void * arg );
/// @brief 실제 파일의 전송을 처리하기 위한 함수.
void Execute(void);
protected:
/// @brief 대상 FHS 정보를 설정하고 접속을 설정함.
bool InitFhsInfo(void);
/// @brief 전달받은 파일 및 크기가 실제 현재 경로에 존재, 크기가 정확한지 검사하기 위한 함수.
bool CheckFileInfo( const std::string& szFileName, unsigned long long nFileSize, std::string& szErrorMessage );
/// @brief 대상 FHS 로 접속 처리를 수행.
bool ConnectTargetFhs(void);
/// @brief 각 FHS 로 파일 전송을 시작한다.
bool SendFileToFhs(void);
/// @brief 파일에 대한 Hash 값을 생성하여 각 FHS 로 전송된 File 의 Hash 검사를 요청한다.
bool CheckHashValue(void);
/// @brief 파일 Transfer 처리 결과를 Control Daemon 으로 전송처리.
bool SendTransferResultToControl(void);
private:
bool m_bProcessing; // 현재 CFileSender 객체가 작업 중인지 여부를 저장하기 위한 변수.
bool m_bThreadStop; // Thread 의 동작 정지 여부를 판단하기 위한 변수
// 전역 Object 에 대한 멤버 포인터.
CIPCache * m_pIpCache;
CProcessStatus * m_pProcessStatus;
// Control Daemon 과 연결된 Socket Control Object Pointer
CSocketControl * m_pSocketControl;
std::string m_szSourceFileName; // Source File Full Name
unsigned long long m_nSourceFileSize; // Source File Size
std::string m_szTargetTranId; // RC 간 동기화시 사용할 Target Tran ID 정보
std::vector< string > m_vecTargetFhs; // 복제 대상 FHS 정보
int m_nHashLevel; // Hash 검사 Level
char m_requestType; // 명령어 정보, Replication or Cache
bool m_bUseInternalIp; // 내부망 사용 여부.
// 쓰레드 핸들
pthread_t m_threadHandle;
// Target FHS Handle 정보를 저장하기 위한 멤버 변수
std::list< CTargetFhsInfo > m_listTarget;
int m_fhsAvailableCount;
std::string m_szSourceHashValue;
};
#endif /* __FILE_SENDER_H__ */
+193
View File
@@ -0,0 +1,193 @@
#include "GetConfig.h"
#include "Config.h"
#include <stdlib.h>
/// @brief config value chech
/// @param szValue [in] value
/// @param conf [in] Config 객체
/// @param defsection [in] default section
/// @param defkey [in] default key
/// @return 성공시 true, 오류 발생시 false 를 반환.
static bool CheckValue(std::string& szValue, Config& conf, const std::string& defsection, const std::string& defkey)
{
if( szValue.size() > 0 )
return true;
if( defsection.size() <= 0 || defkey.size() <= 0 )
return false;
conf.GetConfig( defsection, defkey, szValue );
if( szValue.size() > 0 )
return true;
return false;
}
bool GetConfig( const std::string& szConfFile, struct st_config& stConfig, std::string& errorMessage)
{
// Config 처리를 위한 객체 생성
Config conf;
// Config File open
if( conf.Open( szConfFile) == false )
{
errorMessage = "Config file open failed.[" + szConfFile + "]";
return false;
}
// 각 Section , Key 값 파싱 및 저장처리
std::string szValue;
// [common]1. log path
if( conf.GetConfig( PROG_NAME, "DEFAULT_LOG_DIR", szValue ) == false )
{
if( !CheckValue(szValue, conf, "COMMON", "DEFAULT_LOG_DIR") )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->LOG_DIR";
return false;
}
}
stConfig.szLogDir = szValue;
szValue.clear();
// [common]2. file storage root
if( conf.GetConfig( PROG_NAME, "FILE_STORAGE_ROOT", szValue ) == false )
{
if( !CheckValue(szValue, conf, "COMMON", "FILE_STORAGE_ROOT") )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->FILE_STORAGE_ROOT";
return false;
}
}
stConfig.szStorageRoot = szValue;
szValue.clear();
// [common]3. log level
if( conf.GetConfig( PROG_NAME, "LOG_LEVEL", szValue ) == false )
{
if( !CheckValue(szValue, conf, "COMMON", "LOG_LEVEL") )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->LOG_LEVEL";
return false;
}
}
stConfig.nLogLevel = atoi(szValue.c_str());
szValue.clear();
// [common]4. internal nic name
if( conf.GetConfig( PROG_NAME, "INTERNAL_NIC_NAME", szValue ) == false )
{
if( !CheckValue(szValue, conf, "COMMON", "INTERNAL_NIC_NAME") )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->INTERNAL_NIC_NAME";
return false;
}
}
stConfig.szInternalNicName = szValue;
szValue.clear();
// [ftsd]1. worker process count
if( conf.GetConfig( PROG_NAME, "WORKER_PROCESS_COUNT", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->WORKER_PROCESS_COUNT";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->WORKER_PROCESS_COUNT";
return false;
}
stConfig.nWorkerProcessCount = atoi(szValue.c_str());
szValue.clear();
// [ftsd]2. max file send thread count
if( conf.GetConfig( PROG_NAME, "MAX_FILE_SEND_THREAD", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->MAX_FILE_SEND_THREAD";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->MAX_FILE_SEND_THREAD";
return false;
}
stConfig.nMaxFileSendThread = atoi(szValue.c_str());
szValue.clear();
// [ftsd]3. fhs internal ip cache timeout
if( conf.GetConfig( PROG_NAME, "FHS_INTERNAL_IP_CACHE_TIMEOUT", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->FHS_INTERNAL_IP_CACHE_TIMEOUT";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->FHS_INTERNAL_IP_CACHE_TIMEOUT";
return false;
}
stConfig.nFhsInternalIpCacheTimeout = atoi(szValue.c_str());
szValue.clear();
// [ftsd]4. proper storage refresh preiod(sec)
if( conf.GetConfig( PROG_NAME, "PROPER_STORAGE_REFRESH_PERIOD", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->PROPER_STORAGE_REFRESH_PERIOD";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->PROPER_STORAGE_REFRESH_PERIOD";
return false;
}
stConfig.nProperStorageRefresPeriod = atoi(szValue.c_str());
szValue.clear();
// [ftsd]5. max network bandwidth use amount(%)
if( conf.GetConfig( PROG_NAME, "MAX_BANDWIDTH_USE", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->MAX_BANDWIDTH_USE";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->MAX_BANDWIDTH_USE";
return false;
}
stConfig.nMaxBandwidthUse = atoi(szValue.c_str());
szValue.clear();
// 성공시
return true;
}
+40
View File
@@ -0,0 +1,40 @@
/***************************************************************************
ftsd ( File TranSfer Daemon ) Header ( GetConfig.h )
-----------------------------------------
begin : 2010/03/03
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __GET_CONFIG_H__
#define __GET_CONFIG_H__
#include "../define_ftsd.h"
#include <string>
#ifdef __cplusplus
extern "C" {
#endif
/// @brief config file parsing and save to stConfig function
/// @param szConfFile [in] Conf 파일에 대한 경로 및 파일 정보
/// @param stConfig [out] Conf 파일의 정보를 저장하기 위한 st_config 참조변수
/// @param errorMessage [out] 오류발생시 해당 오류 정보를 저장하여 반환하기 위한 참조변수
/// @return 성공시 true, 오류 발생시 false 를 반환. 상세한 오류 정보는 errorMessage 변수에 저장됨.
bool GetConfig( const std::string& szConfFile, struct st_config& stConfig, std::string& errorMessage);
#ifdef __cplusplus
}
#endif
#endif /* __GET_CONFIG_H__ */
+132
View File
@@ -0,0 +1,132 @@
#include <iostream>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "IPCache.h"
#define MX_LOCK_MAP()\
do \
{\
pthread_mutex_lock(&m_mx_IPPairMap);\
} while( 0 );
#define MX_UNLOCK_MAP()\
do \
{\
pthread_mutex_unlock(&m_mx_IPPairMap);\
} while( 0 );
// initialize class
CPrivateIP::CPrivateIP()
: m_time_lastUpdated ( 0L )
{
}
CPrivateIP::CPrivateIP(const std::string szPrivateIP, const long time_lastUpdated )
: m_szPrivateIP ( szPrivateIP )
, m_time_lastUpdated ( time_lastUpdated )
{
}
// initialize class
CIPCache::CIPCache()
{
m_time_timeout = 300; // 5min ( default 300 second )
//m_mx_IPPairMap = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init( &m_mx_IPPairMap, NULL );
}
CIPCache::~CIPCache()
{
pthread_mutex_destroy(&m_mx_IPPairMap);
}
bool CIPCache::SetTimeout(const long time_timeout)
{
if ( time_timeout < 0 )
{
// time is equal or bigger than 0
return false;
}
m_time_timeout = time_timeout;
return true;
}
bool CIPCache::GetTimeout(long& time_timeout)
{
time_timeout = m_time_timeout;
return true;
}
bool CIPCache::GetPrivateIP( const std::string& szPublic, std::string& szPrivate )
{
time_t time_now;
time_t res = 0;
// Public ip check
if (szPublic.empty() == true)
return false;
res = time( &time_now );
if ( res < 0)
{
return false;
}
MX_LOCK_MAP();
IPPairMap::iterator it;
it = m_IPPair.find(szPublic);
if ( it == m_IPPair.end() ) // Not exist...
{
MX_UNLOCK_MAP();
return false;
}
else if ( time_now - it->second.m_time_lastUpdated > (long)m_time_timeout ) // Cache Time out
{
m_IPPair.erase(it);
MX_UNLOCK_MAP();
return false;
}
else
{
szPrivate = it->second.m_szPrivateIP;
MX_UNLOCK_MAP();
return true;
}
}
bool CIPCache::SetPrivateIP( const std::string& szPublic, std::string& szPrivate )
{
time_t time_now;
time_t res = 0;
// check valid ip
if( (int)inet_addr(szPrivate.c_str()) == -1 )
{
return false;
}
res = time( &time_now );
if ( res < 0)
{
return false;
}
MX_LOCK_MAP();
m_IPPair[szPublic].m_szPrivateIP = szPrivate;
m_IPPair[szPublic].m_time_lastUpdated = time_now;
MX_UNLOCK_MAP();
return true;
}
+81
View File
@@ -0,0 +1,81 @@
/***************************************************************************
IP Cache 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 __IPCACHE_H__
#define __IPCACHE_H__
#include <string>
#include <map>
/// @brief CIPCache class
class CPrivateIP
{
public :
CPrivateIP();
CPrivateIP(const std::string szPrivateIP, const long time_lastUpdated );
/// @brief 사설 IP값을 저장한다.
std::string m_szPrivateIP;
long m_time_lastUpdated;
private :
};
/// @brief CIPCache class
class CIPCache
{
public :
CIPCache();
~CIPCache();
/// @brief 요청된 Host명(혹은 공인IP)에 대해 캐시된 데이터를 반환한다.
/// @param szPublic [in] 요청 Host명 값.
/// @param szPrivate [out] 요청 Host에 매칭되는 Private IP값.
/// @return 성공은 return true, 그 외에는 return false
bool GetPrivateIP( const std::string& szPublic, std::string& szPrivate);
/// @brief 요청된 Host명(혹은 공인IP)에 대해 캐시된 데이터를 저장한다.
/// @param szPublic [in] 요청 Host명 값.
/// @param szPrivate [in] 요청 Host에 매칭되는 Private IP값.
/// @return 성공은 return true, 그 외에는 return false
bool SetPrivateIP(const std::string& szPublic, std::string& szPrivate);
/// @brief timeout 만료 기준을 설정한다. default = 300.
/// @param time_timeout [in] 만료 설정 할 초(second).
/// @return 성공은 return true, 그 외에는 return false
bool SetTimeout(const long time_timeout);
/// @brief 설정된 timeout 만료 값을 얻어온다. default = 300.
/// @param time_timeout [out] 만료 설정 할 초(second).
/// @return 성공은 return true, 그 외에는 return false
bool GetTimeout(long& time_timeout);
private :
/// @brief IP Pair를 저장하는 map
typedef std::map<std::string, CPrivateIP> IPPairMap;
/// @brief SetTimeout()을 통해 설정되는 값.
long m_time_timeout;
/// @brief Public IP와 Private IP의 쌍을 가지는 Map, 최근 수정 시각을 포함한다.
IPPairMap m_IPPair;
/// @brief ipPairMap의 mutex
pthread_mutex_t m_mx_IPPairMap;
};
#endif //__IPCACHE_H__
+585
View File
@@ -0,0 +1,585 @@
#include "Listener.h"
#include "GetConfig.h"
#include "Logger.h"
#include "Worker.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <iostream>
#include <fstream>
using namespace std;
// Accept 대기 Count 수
// CHG 2010-03-18 huibong
// Accept 접속 대기 수가 몰리는 현상이 발생하여 5->30 으로 변경함.
#define DEFAULT_ACCEPT_WAIT_COUNT 30
// 전역 객체 정보
// 1. config 정보를 저장하기 위한 전역 객체
struct st_config g_envConfig;
// 2. Listener Socket
// => 시그널 처리시 문제로 인해 전역함수로 생성. initialize listener.cpp
int g_listenSocket = -1;
int main( int argc, char * argv[] )
{
// Version 정보 표시
if( argc == 2 && strcmp( argv[1], "-v") == 0)
{
cerr << "[info] " << PROG_NAME << " (File TranSfer Daemon) Version : " << PROG_VERSION << endl;
return EXIT_SUCCESS;
}
// 프로그램 중복 실행 체크
if( IsCurrentProcessRun() == true )
{
cerr << "[warning] Process[" << PROG_NAME << "] is already running...." << endl;
return EXIT_SUCCESS;
}
// Config 정보 설정 및 전역 정보 설정
// extern struct st_config g_envConfig => define_ftsd.h 파일 참조
string szErrorMessage;
if( GetConfig( DEFAULT_CONFIG_FILE, g_envConfig, szErrorMessage ) == false )
{
cerr << "[error] Process[" << PROG_NAME << "]: " << szErrorMessage << endl;
return EXIT_FAILURE;
}
// Log 처리 객체 생성
if( CLogger::Init( PROG_NAME, g_envConfig.szLogDir.c_str(), LINF ) == false )
{
cerr << "[error] Process[" << PROG_NAME << "]: Log init failed." << endl;
return EXIT_FAILURE;
}
// Process 기동 관련 정보 로깅
_LOG( LINF, "***********************************************************" );
_LOG( LINF, " %s (File TranSfer Daemon) Start. Version: %s", PROG_NAME, PROG_VERSION );
_LOG( LINF, "***********************************************************" );
_LOG( LINF, "Config file : %s", DEFAULT_CONFIG_FILE );
_LOG( LINF, "Listen Port : %d", SVC_LISTEN_PORT );
_LOG( LINF, "Log Path : %s/%s", g_envConfig.szLogDir.c_str(), PROG_NAME );
_LOG( LINF, "Storage root : %s", g_envConfig.szStorageRoot.c_str() );
_LOG( LINF, "Internal NIC : %s", g_envConfig.szInternalNicName.c_str() );
_LOG( LINF, "Worker Process : %d", g_envConfig.nWorkerProcessCount );
_LOG( LINF, "Max Send Thread : %d", g_envConfig.nMaxFileSendThread );
_LOG( LINF, "FHS Cache Time : %d (sec)", g_envConfig.nFhsInternalIpCacheTimeout );
_LOG( LINF, "Stroage Refresh : %d (sec)", g_envConfig.nProperStorageRefresPeriod );
_LOG( LINF, "MAX Bandwidth : %d (%%)", g_envConfig.nMaxBandwidthUse );
_LOG( LINF, "Logging Level : %d", g_envConfig.nLogLevel );
_LOG( LINF, "***********************************************************" );
// Log Level 재설정
#ifdef _DEBUG_
if( CLogger::GetInstance() != NULL )
{
CLogger::GetInstance()->SetLogLevel( LDBG );
}
#else
if( CLogger::GetInstance() != NULL )
{
CLogger::GetInstance()->SetLogLevel( g_envConfig.nLogLevel);
}
#endif
// 프로그램 Daemonize
if( MakeDaemon() != 0 )
{
LOG( LERR, "Process[%s] Daemonize failed.", PROG_NAME);
cerr << "[error] Process[" << PROG_NAME << "] Daemonize failed." << endl;
return EXIT_FAILURE;
}
// Listener 프로세스의 Signal 처리기 설정
SetSignalListener();
// Listen Socket 생성
if( MakeListenSocket( g_listenSocket ) == false )
{
LOG( LERR, "Listen Socket Create failed. => Process Exit." );
return EXIT_FAILURE;
}
// Worker Process 생성
if( MakeProcessWorker( g_listenSocket ) == false )
{
close( g_listenSocket );
LOG( LERR, "Worker Process make failed. => Listener Process exit. Goob Bye..");
return EXIT_FAILURE;
}
// Listener Process : 그냥 대기
#if defined(__FreeBSD__)
setproctitle( "Listener [monitor worker process]" );
#endif
while( 1 )
{
// Listener Process 는 할 일이 없다.
// => Worker 프로세스 종료시 SIGCHLD 신호로 인해 신호처리기에서 Worker Process 재성성 수행함.
// => 따라서 그냥 시그널 대기
pause();
//LOG( LNOT, "Listener process receive signal. -> suspend" );
}
// 다음의 코드는 Daemon 으로 동작하기 때문에 수행되지 않는다.
close( g_listenSocket );
CLogger::Exit();
return EXIT_SUCCESS;
}
/// @brief Worker Process 생성(fork) 처리 함수
/// @param listenSocket [in] Listen Socket
/// @return 생성 성공시 true, 실패시에는 false 를 반환.
bool MakeProcessWorker( int listenSocket )
{
pid_t processId;
// Conf 에 정의된 Worker Process Count 만큼 Worker 프로세스 생성 처리.
for( int index = 0; index < g_envConfig.nWorkerProcessCount; index++ )
{
// Worker 프로세스 fork
processId = fork();
if( processId < 0 ) // Fork fail
{
int errorNum = errno;
LOG( LERR, "Worker Process[%d th] create failed. [%d][%s]", index, errorNum, strerror(errorNum) );
return false;
}
else if( processId == 0 ) // Child Process => Worker Process
{
// Worker Process Main 함수 호출 및 종료처리.
WorkerMain( listenSocket );
exit( EXIT_SUCCESS );
}
else
{
// Parent Process => Logging
_LOG( LINF, "Worker Process[%d th] create success. PID[%d]" , index, processId);
// 잠시 대기
// CHG 2015-09-14 huibong
// - #24376 usleep -> nanosleep 으로 변경 처리.
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 200000000; // 0.2 sec
nanosleep( &sleep, NULL );
}
}
return true;
}
/// @brief Worker Process 재생성(fork) 처리 함수
/// @param listenSocket [in] Listen Socket
/// @return 생성 성공시 true, 실패시에는 false 를 반환.
bool RemakeProcessWorker( int listenSocket )
{
pid_t processId;
// Worker 프로세스 fork
processId = fork();
if( processId < 0 ) // Fork fail
{
int errorNum = errno;
LOG( LERR, "Worker Process recreate failed. [%d][%s]", errorNum, strerror(errorNum) );
return false;
}
else if( processId == 0 ) // Child Process => Worker Process
{
// Worker Process Main 함수 호출 및 종료처리.
WorkerMain( listenSocket );
exit( EXIT_SUCCESS );
}
else
{
// Parent Process => Logging
LOG( LWAR, "Worker Process recreate success. PID[%d]" , processId);
// 잠시 대기
// CHG 2015-09-14 huibong
// - #24376 usleep -> nanosleep 으로 변경 처리.
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 200000000; // 0.2 sec
nanosleep( &sleep, NULL );
}
return true;
}
/// @brief 현재 Process가 기동중인지 여부를 판단하기 위한 함수( 프로세스 중복 실행 체크)
/// @return 이미 해당 프로세스가 기동 중인 경우 true 반환, 그렇지 않으면 false 반환.
bool IsCurrentProcessRun()
{
char tempBuffer[512];
FILE * fd = NULL;
bool bRun = false;
snprintf( tempBuffer, sizeof(tempBuffer), "pgrep -x %s | sort", PROG_NAME );
fd = popen( tempBuffer, "r" );
if( fd == NULL )
{
cerr << "[error] Process duplication check failed.[popen error][" << strerror(errno) << "]" << endl;
// 오류 발생시 true 반환하여 프로세스 실행 방지처리
return true;
}
else
{
memset( tempBuffer, 0x00, sizeof(tempBuffer) );
while( fgets( tempBuffer, sizeof(tempBuffer)-1, fd) != NULL )
{
string tempPid( tempBuffer );
Trim(tempPid);
if( atoi( tempPid.c_str() ) != getpid() )
{
cout << "[info] Process duplication found. pid[" << atoi( tempPid.c_str() ) << "]" << endl;
bRun = true;
break;
}
}
pclose( fd );
return bRun;
}
}
/// @brief std 상에 trim 함수가 없어서 직접 구현 아니면 boost/algorithm/string.hpp 상의 boost::trim 함수 사용
/// @return void
void Trim( string & str )
{
if( str.length() == 0 )
return ;
// 문자열 뒤의 공백, TAB, CR 등의 문자 제거처리.
string::size_type pos = str.find_last_not_of(" \a\b\f\n\r\t\v");
if( pos != string::npos )
str.erase( pos + 1 );
// 문자열 앞의 공백, TAB, CR 등의 문자 제거처리.
pos = str.find_first_not_of(" \a\b\f\n\r\t\v");
if( pos != string::npos )
str.erase( 0, pos );
}
/// @brief Daemon Process 생성처리
/// @return 0 인 경우 성공, -1 인 경우 오류발생
int MakeDaemon()
{
pid_t processId;
processId = fork();
if( processId == -1 )
{
int errorNum = errno;
cout << "[error] " << PROG_NAME << ": daemon fork fail.[" << strerror(errorNum) << "]" << endl;
LOG( LERR, "Daemon fork failed. [%d][%s]", errorNum, strerror(errorNum));
return -1;
}
if( processId != 0 )
{
// Parent Process => exit
exit( EXIT_SUCCESS );
}
else
{
// NEW 2010-11-30 huibong
// Daemon 생성시 파일 권한처리 관련 umask 코드 추가.
umask(0);
setsid();
}
// NEW 2010-11-30 huibong
// Daemon 생성시 stdin, stdout, stderr 처리 Miss로 인해
// 원격 ssh 를 이용한 기동 처리시 CTRL+C 를 눌러야 기동처리되는 버그 수정
//fclose(stdin);
//fclose(stdout);
//fclose(stderr);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
return 0;
}
/// @brief Listener Process 종료 Signal 을 전달받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigTermListener( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
LOG( LWAR, "Listener Process[%d] exit job start by user signal [SIGTERM]", getpid() );
}
else
{
LOG( LWAR, "Listener Process[%d] exit job start by abnormal signal [%d]", getpid(), nSignalNumber );
}
// Process 종료관련 작업 추가
close( g_listenSocket );
LOG( LWAR, "Listener Process[%d] exit job end. Good Bye..", getpid());
CLogger::Exit();
// CHG 2015-09-14 huibong
// - #24376 usleep -> nanosleep 으로 변경 처리.
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
exit( EXIT_SUCCESS );
}
/// @brief Listener Process 에서 Core 생성 관련 Signal 을 받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigCoreListener( int nSignalNumber )
{
LOG( LERR, "Listener Process[%d] abnoraml exit. Check Core file. Receive signal [%d]", getpid(), nSignalNumber );
LOG( LERR, "Core file path : [%s/%s.core]", g_envConfig.szLogDir.c_str(), PROG_NAME );
// Process 종료관련 작업 추가
close( g_listenSocket );
CLogger::Exit();
// Log Directory 상에 Core 파일 생성처리.
chdir( g_envConfig.szLogDir.c_str() );
signal( nSignalNumber, SIG_DFL );
// Core dump 생성을 위한 신호 발생처리.=> ?
raise( nSignalNumber );
}
/// @brief Listener Process 에서 자식 프로세스인 Worker Process 가 종료된 경우 시그널 처리를 위한 함수
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigChldListener( int nSignalNumber )
{
pid_t killPid;
int nKillStatus;
while( ( killPid = waitpid( -1, &nKillStatus, WNOHANG ) ) > 0 )
{
// 자식 프로세스가 Signal 에 의해 종료되었는지 검사.
if( WIFSIGNALED( nKillStatus ) )
{
LOG( LWAR, "Worker process[%d] killed by signal[%d]", killPid, WTERMSIG( nKillStatus ) );
}
else
{
LOG( LWAR, "Worker process[%d] killed. Not signal", killPid );
// CHG 2014-02-28 huibong
// Worker 프로세스가 EXIT_FAILURE 반환 ( 초기화 실패시 )
// 해당 내역을 화면 및 로그 상에 출력하고
// 자식 프로세스를 재생성 처리하지 않는다.
if( WIFEXITED( nKillStatus ) )
{
if( WEXITSTATUS( nKillStatus ) == EXIT_FAILURE )
{
_LOG( LERR, "Worker Process[%d] initilaize failed.", killPid );
_LOG( LERR, "Program abnormally exited because Worker initialize faild..");
// Main 종료 시그널 발생
raise( SIGTERM );
continue;
}
}
}
// Worker Process 재생성 처리.
if( RemakeProcessWorker( g_listenSocket ) == false )
{
// Worker Process 재성성 실패시 => 그냥 로깅
LOG( LERR, "Worker process recreate failed.");
}
else
{
LOG( LWAR, "Worker process recreate success by SIGCHLD");
}
}
// 오류 발생시 해당 내역 로깅
if( killPid < 0 )
{
int errorNum = errno;
LOG( LERR, "Listener process error: SIG_CHLD receive but waitpid return error[%d][%s]", errorNum, strerror(errorNum));
}
return;
}
/// @brief Listener프로세스 signal 처리 설정을 위한 함수
/// @return void
void SetSignalListener()
{
sigset_t set;
struct sigaction act;
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
memset( &act, 0x00, sizeof(act) );
sigfillset( &act.sa_mask );
/* 무시할 신호 목록 */
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL); /* 파이프 디스크립터 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP , &act, NULL); /* Process를 기동시킨 관리자의 로그아웃시 발생 시그널 */
sigaction( SIGINT , &act, NULL); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
// Child Process 인 Worker 프로세스 종료에 대한 처리기 설정.
act.sa_handler = SigChldListener;
sigaction( SIGCHLD, &act, NULL);
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SigTermListener;
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
/* Core 관련 signal 처리 : 오류 처리 및 Debug(core dump) 목적 */
act.sa_handler = SigCoreListener;
sigaction( SIGILL , &act, NULL); /* Illegal instruction */
sigaction( SIGFPE , &act, NULL); /* Erroneout arithmetic operation */
sigaction( SIGBUS , &act, NULL); /* Access to undefined portion of a memory object */
sigaction( SIGSEGV, &act, NULL); /* Invalid memory reference */
sigaction( SIGSYS , &act, NULL); /* Bad System Call */
sigaction( SIGXCPU, &act, NULL); /* CPU-time limit exceeded */
sigaction( SIGXFSZ, &act, NULL); /* File-size limit exceeded */
sigemptyset(&set); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask(SIG_SETMASK, &set, NULL);
}
/// @brief Listen 처리를 위한 Socket 생성 함수
/// @param listenSocket [out] 생성된 Socket 정보를 저장하기 위한 참조변수
/// @return 성공시 true, 오류발생시 false 반환.
bool MakeListenSocket( int& listenSocket )
{
listenSocket = socket( AF_INET, SOCK_STREAM, 0 );
if( listenSocket == -1 )
{
int errorNum = errno;
LOG( LERR, "Listen socket create failed.[%d][%s]", errorNum, strerror(errorNum) );
cerr << "[error] Process[" << PROG_NAME << "] Listen socket create failed.[" << strerror(errorNum) << "]" << endl;
return false;
}
struct sockaddr_in listenSockAddr;
socklen_t listenSockLen = 0;
memset(&listenSockAddr, 0x00, sizeof(listenSockAddr));
listenSockAddr.sin_family = AF_INET;
listenSockAddr.sin_port = htons( SVC_LISTEN_PORT ); // SVC_LISTEN_PORT : defined Makefile
listenSockAddr.sin_addr.s_addr = htonl( INADDR_ANY );
listenSockLen = sizeof(listenSockAddr);
int result = 0;
// Socket Port Reuse Option Set
int opt = 1;
result = setsockopt( listenSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt) );
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "Listen socket option[SO_REUSEADDR] set failed. [%d][%s]", errorNum, strerror(errorNum) );
cerr << "[error] Process[" << PROG_NAME << "] Listen socket SO_REUSEADDR set failed.[" << strerror(errorNum) << "]" << endl;
return false;
}
// Keep Alive Option set
opt = 1;
result = setsockopt( listenSocket, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt) );
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "Listen socket option[SO_KEEPALIVE] set failed. [%d][%s]", errorNum, strerror(errorNum) );
cerr << "[error] Process[" << PROG_NAME << "] Listen socket SO_KEEPALIVE set failed.[" << strerror(errorNum) << "]" << endl;
return false;
}
// Non Block Mode Set
/*
int flags;
if(flags = fcntl(listenSocket, F_GETFL, 0) >= 0)
{
flags |= O_NONBLOCK;
if(fcntl(listenSocket, F_SETFL, flags) < 0)
{
int errorNum = errno;
ERROR_LOG( "Listen socket non-block set failed.[%d][%s]", errorNum, strerror(errorNum) );
cerr << "[error] Process[" << PROG_NAME << "] Listen socket non-block set failed.[" << strerror(errorNum) << "]" << endl;
return false;
}
}
*/
// Socket Bind
result = bind( listenSocket, (struct sockaddr *)&listenSockAddr, listenSockLen);
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "Listen socket bind failed.[%d][%s]", errorNum, strerror(errorNum) );
cerr << "[error] Process[" << PROG_NAME << "] Listen socket bind failed.[" << strerror(errorNum) << "]" << endl;
return false;
}
// Socket Listen
result = listen( listenSocket, DEFAULT_ACCEPT_WAIT_COUNT );
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "Listen socket bind failed.[%d][%s]", errorNum, strerror(errorNum) );
cerr << "[error] Process[" << PROG_NAME << "] Listen socket bind failed.[" << strerror(errorNum) << "]" << endl;
return false;
}
return true;
}
+74
View File
@@ -0,0 +1,74 @@
/***************************************************************************
ftsd ( File TranSfer Daemon ) Header ( Listener.h )
-----------------------------------------
begin : 2010/03/05
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 __LISTENER_H__
#define __LISTENER_H__
#include "../define_ftsd.h"
#include <string>
#ifdef __cplusplus
extern "C" {
#endif
/// @brief 현재 Process가 기동중인지 여부를 판단하기 위한 함수( 프로세스 중복 실행 체크)
/// @return 이미 해당 프로세스가 기동 중인 경우 true 반환, 그렇지 않으면 false 반환.
bool IsCurrentProcessRun( void );
/// @brief std 상에 trim 함수가 없어서 직접 구현 아니면 boost/algorithm/string.hpp 상의 boost::trim 함수 사용
/// @param str [in/out] Trim 할 문자열을 저장한 String 참조변수.
/// @return void
void Trim( std::string & str );
/// @brief Daemon Process 생성처리
/// @return 0 인 경우 성공, -1 인 경우 오류발생
int MakeDaemon( void );
/// @brief Worker Process 생성(fork) 처리 함수
/// @param listenSocket [in] Listen Socket
/// @return 생성 성공시 true, 실패시에는 false 를 반환.
bool MakeProcessWorker( int listenSocket );
/// @brief Worker Process 재생성(fork) 처리 함수
/// @param listenSocket [in] Listen Socket
/// @return 생성 성공시 true, 실패시에는 false 를 반환.
bool RemakeProcessWorker( int listenSocket );
/// @brief Listener 프로세스 signal 처리 설정을 위한 함수
/// @return void
void SetSignalListener( void );
/// @brief Listen 처리를 위한 Socket 생성 함수
/// @param listenSocket [out] 생성된 Socket 정보를 저장하기 위한 참조변수
/// @return 성공시 true, 오류발생시 false 반환.
bool MakeListenSocket( int& listenSocket );
/* Signal 처리를 위한 각 Signal Handler 함수는
* 다른 Code 에서 Include 처리시 Static 관련 문제로 인해
* 본 Header 에서 선언처리 하지 않음. cpp 에만 존재
*/
#ifdef __cplusplus
}
#endif
#endif /* __LISTENER_H__ */
+151
View File
@@ -0,0 +1,151 @@
#include "LocalIPCache.h"
#include <errno.h>
#include <string.h>
#include <unistd.h>
// IP Info save cache interval (sec)
#define IPCACHE_TERM_SECOND 60
// Constructor
CLocalIPCache::CLocalIPCache( const string& szNICName )
: m_szNICName( szNICName )
{
m_szLocalIP.clear();
pthread_mutex_init(&m_mxLock, NULL);
LOG( LDBG, "Created CLocalIPCache object..");
}
CLocalIPCache::~CLocalIPCache()
{
// 동작 중인 Thread 정지 처리.
// - 만약 Thread 가 이미 종료된 경우 m_threadHandle 가 다른 Thread Handle 일 수 있으므로 업무 Flow 수정시 주의할 것
pthread_cancel(m_threadHandle);
pthread_mutex_destroy(&m_mxLock);
//LOG( LDBG, "Destroyed CLocalIPCache object..");
}
bool CLocalIPCache::GetLocalIP(string& szLocalIP)
{
LOG( LDBG, "return IP is [%s]", m_szLocalIP.c_str());
pthread_mutex_lock(&m_mxLock);
szLocalIP = m_szLocalIP;
pthread_mutex_unlock(&m_mxLock);
// 유효한 IP인지를 확인 한다.
if( (int)inet_addr(szLocalIP.c_str()) == -1 )
{
LOG( LERR, "[%s] is invalid IP.", szLocalIP.c_str());
return false;
}
return true;
}
bool CLocalIPCache::GetIP(string& szLocalIP)
{
int fd = 0; // make new file descriptor to open socket
int nResult = 0;
struct ifreq interface;
struct sockaddr_in * pAddr = NULL;
// NEW 2010-11-30 huibong struct 초기화 코드 추가
memset( &interface, 0x00, sizeof(struct ifreq) );
fd = socket(AF_INET, SOCK_DGRAM, 0); // use IPv4
if (fd < 0)
{
LOG( LERR, "socket(SOCK_DGRAM) create failed.");
return false;
}
interface.ifr_addr.sa_family = AF_INET;
strncpy(interface.ifr_name, m_szNICName.c_str(), IFNAMSIZ-1);
nResult = ioctl(fd, SIOCGIFADDR, &interface);
if( nResult < 0 )
{
LOG( LERR, "ioctl error [%s][%d][%s]", m_szNICName.c_str(), errno, strerror(errno));
close(fd);
return false;
}
close(fd);
// CHG 2012-02-01 huibong
// inet_ntoa() 함수가 static 메모리 사용으로 인해 Thread-safe 하지 않으므로..
// inet_ntop() 함수로 교체 처리한다.
//szLocalIP = inet_ntoa(((struct sockaddr_in *)&interfaceReq.ifr_addr)->sin_addr);
pAddr = (struct sockaddr_in *)&(interface.ifr_addr);
char tempBuffer[INET_ADDRSTRLEN];
memset(tempBuffer, 0x00, sizeof(tempBuffer));
if( inet_ntop( AF_INET, &(pAddr->sin_addr), tempBuffer, sizeof(tempBuffer)) != NULL )
{
szLocalIP = tempBuffer;
return true;
}
else
{
LOG( LERR, "inet_ntop error.[%d][%s]", errno, strerror(errno));
return false;
}
}
///@brief 이 함수에서 로컬IP 정보를 가져온다.
void CLocalIPCache::Excute()
{
string szLocalIP;
if ( !GetIP(szLocalIP) )
{
LOG( LWAR, "Don't get ip from [%s]NIC. ", m_szNICName.c_str());
}
pthread_mutex_lock(&m_mxLock);
m_szLocalIP = szLocalIP;
pthread_mutex_unlock(&m_mxLock);
}
void* CLocalIPCache::EntryPoint(void* arg)
{
CLocalIPCache* pObject = reinterpret_cast<CLocalIPCache *>(arg);
pthread_detach( pthread_self() );
while(1)
{
pthread_testcancel();
pObject->Excute();
pthread_testcancel();
sleep(IPCACHE_TERM_SECOND);
}
return NULL;
}
bool CLocalIPCache::Start()
{
if( m_szNICName.empty() )
{
LOG( LERR, "Thread create failed: NIC name is empty.");
return false;
}
int nRet = ::pthread_create(&m_threadHandle, 0, CLocalIPCache::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;
}
+79
View File
@@ -0,0 +1,79 @@
/***************************************************************************
Local Ip Cache Class
-----------------------------------------
begin : 2010/03/31
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 __LOCAL_IP_CACHE__
#define __LOCAL_IP_CACHE__
#include <pthread.h>
#include <string>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include "Logger.h"
using namespace std;
/// @brief CLocalIPCache
/// CLocalIPCache는 생성자의 두 번째 param으로 입력한 NIC명의
/// IP정보를 전달 해주는 클래스이다.
/// 주요 인터페이스 함수는 쓰레드를 시작 하는 start()함수와
/// IP를 얻어오는 GetLocalIP() 함수이다.
///
/// 내부적으로 Thread를 사용하고있다.
class CLocalIPCache
{
public:
/// @brief 생성자
/// @param [in] szNICName 현재 클래스를 사용하여 IP정보를 얻을 NIC 장비의 이름을 입력한다.
CLocalIPCache( const string& szNICName );
~CLocalIPCache();
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공은 return true 실패는 return false
bool Start();
/// @brief 생성자의 두 번째 param으로 입력된 NIC 장비의 IP정보를 리턴한다.
/// @param [out] szLocalIP 요청한 NIC에 해당하는 IP값을 전달한다.
/// @return 성공은 return true, 실패하면 false.
bool GetLocalIP(string& szLocalIP);
private:
// 입력받은 NIC 명.
string m_szNICName;
// 해당 NIC의 ip를 입력받는다.
string m_szLocalIP;
pthread_mutex_t m_mxLock;
// 쓰레드 핸들
pthread_t m_threadHandle;
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
// 해당 함수의 내용은 수정하지 말것.
void Excute();
// m_szNICName 해당 NIC의 ip정보를 얻는 함수이다.
bool GetIP(string& szLocalIP);
};
#endif // __LOCAL_IP_CACHE__
+74
View File
@@ -0,0 +1,74 @@
#****************************************************************************
# Makefile for ftsd ( File TranSfer Daemon)
# -----------------------------------------
#
# begin : 2010/02/25
# 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.
#*****************************************************************************
# Program info
PROG_NAME = ftsd
REVISION = 1534
PROG_VERSION = 3.5.0.$(REVISION)-`date +%Y%m%d%H%M%S`
DEFAULT_CONFIG_FILE = /user/service/etc/fhs.conf
SVC_LISTEN_PORT = 14001
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 = -D_DEBUG_ -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DSVC_LISTEN_PORT=$(SVC_LISTEN_PORT)
DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"\
-DSVC_LISTEN_PORT=$(SVC_LISTEN_PORT)
# Application Enviroment
APP = $(PROG_NAME)
DIR_INCLUDE = -I../lib
DIR_LIB = -L../lib
OBJ = GetConfig.o Listener.o LocalIPCache.o IPCache.o ProcessStatus.o ProperStorage.o FileHash.o TOTOChecksum.o SocketControl.o TargetFhsInfo.o FileSender.o Worker.o
LIBS = ../lib/libInterCommon.a -lpthread
#---------------------------------------------------------------------#
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 *.out *.log
-rm -f $(APP)
sync
install : $(APP)
-cp $(APP) $(INSTALL_BIN)/$(APP)
sync
# End of Makefile
+209
View File
@@ -0,0 +1,209 @@
#include <iostream>
#include "ProcessStatus.h"
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#define MX_LOCK_SEND_CNT()\
do \
{\
pthread_mutex_lock(&m_mx_nSendCount);\
} while( 0 );
#define MX_UNLOCK_SEND_CNT()\
do \
{\
pthread_mutex_unlock(&m_mx_nSendCount);\
UpdateTitle();\
} while( 0 );
#define MX_LOCK_RECV_CNT()\
do \
{\
pthread_mutex_lock(&m_mx_nReceiveCount);\
} while( 0 );
#define MX_UNLOCK_RECV_CNT()\
do \
{\
pthread_mutex_unlock(&m_mx_nReceiveCount);\
UpdateTitle();\
} while( 0 );
#define MX_LOCK_TRAN_RATE()\
do \
{\
pthread_mutex_lock(&m_mx_nTransferRate);\
} while( 0 );
#define MX_UNLOCK_TRAN_RATE()\
do \
{\
pthread_mutex_unlock(&m_mx_nTransferRate);\
} while( 0 );
// Constructor
CProcessStatus::CProcessStatus()
: m_nSendCount(0)
, m_nReceiveCount(0)
, m_nTransferRate(100)
{
// Initialize Mutext variable
//m_mx_nSendCount = PTHREAD_MUTEX_INITIALIZER;
//m_mx_nReceiveCount = PTHREAD_MUTEX_INITIALIZER;
//m_mx_nTransferRate = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init( &m_mx_nSendCount, NULL );
pthread_mutex_init( &m_mx_nReceiveCount, NULL );
pthread_mutex_init( &m_mx_nTransferRate, NULL );
return;
}
CProcessStatus::~CProcessStatus()
{
// Destory Mutext variable
pthread_mutex_destroy(&m_mx_nSendCount);
pthread_mutex_destroy(&m_mx_nReceiveCount);
pthread_mutex_destroy(&m_mx_nTransferRate);
return;
}
void CProcessStatus::UpdateTitle()
{
#if defined(__FreeBSD__)
setproctitle("Worker [S:%3d R:%3d N:%3d]", m_nSendCount, m_nReceiveCount, m_nTransferRate );
#endif
return ;
}
int CProcessStatus::GetSendCount(void)
{
int nValue = 0;
MX_LOCK_SEND_CNT();
nValue = m_nSendCount;
MX_UNLOCK_SEND_CNT();
return nValue;
}
bool CProcessStatus::SetSendCount(const int nSendCount)
{
// 입력값이 0 보다 작은 경우 false 반환.
if( nSendCount < 0 )
{
return false;
}
MX_LOCK_SEND_CNT();
m_nSendCount = nSendCount;
MX_UNLOCK_SEND_CNT();
return true;
}
bool CProcessStatus::AddSendCount()
{
MX_LOCK_SEND_CNT();
++m_nSendCount;
MX_UNLOCK_SEND_CNT();
return true;
}
bool CProcessStatus::SubtractSendCount()
{
MX_LOCK_SEND_CNT();
--m_nSendCount;
if( m_nSendCount < 0 )
m_nSendCount = 0;
MX_UNLOCK_SEND_CNT();
return true;
}
int CProcessStatus::GetReceiveCount(void)
{
int nValue = 0;
MX_LOCK_RECV_CNT();
nValue = m_nReceiveCount;
MX_UNLOCK_RECV_CNT();
return nValue;
}
bool CProcessStatus::SetReceiveCount(const int nReceiveCount)
{
if( nReceiveCount < 0 )
{
return false;
}
MX_LOCK_RECV_CNT();
m_nReceiveCount = nReceiveCount;
MX_UNLOCK_RECV_CNT();
return true;
}
bool CProcessStatus::AddReceiveCount()
{
MX_LOCK_RECV_CNT();
++m_nReceiveCount;
MX_UNLOCK_RECV_CNT();
return true;
}
bool CProcessStatus::SubtractReceiveCount()
{
MX_LOCK_RECV_CNT();
--m_nReceiveCount;
if( m_nReceiveCount < 0 )
m_nReceiveCount = 0;
MX_UNLOCK_RECV_CNT();
return true;
}
int CProcessStatus::GetTransferRate()
{
int nValue = 0;
MX_LOCK_TRAN_RATE();
nValue = m_nTransferRate;
MX_UNLOCK_TRAN_RATE();
return nValue;
}
bool CProcessStatus::SetTransferRate(const int nTransferRate)
{
if ( nTransferRate < 0 || nTransferRate > 100 )
{
return false;
}
MX_LOCK_TRAN_RATE();
m_nTransferRate = nTransferRate;
MX_UNLOCK_TRAN_RATE();
return true;
}
+92
View File
@@ -0,0 +1,92 @@
/***************************************************************************
Process Status class
-----------------------------------------
begin : 2010/03/05
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : tael@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.
***************************************************************************/
// TODO: comment 보완
#ifndef __PROCESS_STATUS_H__
#define __PROCESS_STATUS_H__
#include <string>
#include <map>
using namespace std;
/// @brief CProcessStatus class. 현재 송신/수신 중인 갯수를 관리하는 클래스.
class CProcessStatus
{
public :
CProcessStatus();
~CProcessStatus();
/// @brief 현재 설정된 Send Count 값을 가져온다.
/// @return 성공은 SendCount, 그 외에는 음수 값
int GetSendCount(void);
/// @brief Send Count를 설정한다.
/// @param nSendCount [in] Send Count를 설정한다.
/// @return 성공은 return true, 그 외에는 return false
bool SetSendCount(const int nSendCount); // TODO: NOT USED, remove it
/// @brief
/// @return 성공은 return true, 그 외에는 return false
bool AddSendCount(void);
/// @brief
/// @return 성공은 return true, 그 외에는 return false
bool SubtractSendCount(void);
/// @brief 현재 설정된 ReceiveCount 값을 가져온다.
/// @return 성공은 ReceiveCount, 그 외에는 음수 값
int GetReceiveCount(void);
/// @brief 현재 설정된 Receive Count 값을 가져온다.
/// @param nReceiveCount [in] Receive Count를 설정한다.
/// @return 성공은 m_nReceiveCount, 그 외에는 음수 값
bool SetReceiveCount(const int nReceiveCount);// TODO: NOT USED, remove it
/// @brief
/// @return 성공은 return true, 그 외에는 return false
bool AddReceiveCount(void);
/// @brief
/// @return 성공은 return true, 그 외에는 return false
bool SubtractReceiveCount(void);
/// @brief 현재 설정된 TransferRate 값을 가져온다. 0~100까지의 값을 가진다.
/// @return 성공은 m_nTransferRate, 그 외에는 음수 값
int GetTransferRate(void);
/// @brief 현재 설정된 Transfer Rate 값을 설정한다. ( 0~100 )
/// @param nTransferRate [in] 설정된 전송률을 설정한다. ( 0~100 )
/// @return 성공은 m_nReceiveCount, 그 외에는 음수 값
bool SetTransferRate(const int nTransferRate);
private :
/// @brief 현재 프로세스 타이틀을 업데이트 한다. (SndCnt,RcvCnt정보를 포함한다.) (FreeBSD Only)
void UpdateTitle(void);
/// @brief 현재 전송중인 개수를 저장. 0보다 큰 값을 가지게 된다.
int m_nSendCount;
/// @brief 현재 수신중인 개수를 저장. 0보다 큰 값을 가지게 된다.
int m_nReceiveCount;
/// @brief 현재 설정된 전송률을 저장. 정수 단위로 0~100까지의 값을 가지게 된다.
int m_nTransferRate;
pthread_mutex_t m_mx_nSendCount ;
pthread_mutex_t m_mx_nReceiveCount;
pthread_mutex_t m_mx_nTransferRate;
}; // ~class CProcessStatus
#endif // __PROCESS_STATUS_H__
+585
View File
@@ -0,0 +1,585 @@
#include "ProperStorage.h"
#include "Logger.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#ifdef __FreeBSD__
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#else // Linux
#include <mntent.h>
#include <sys/vfs.h>
#endif
#define LIMIT_STORAGE_SIZE 10737418240LL // 최소 Storage 용량.
#define DISABLE_FLAG ".disable" // Mount disable 플래그
// 생성자
CProperStorage::CProperStorage( const std::string & strStorageRoot, const int nCheckInterval )
{
// 멤버 변수 초기화
pthread_mutex_init( &m_mutexLock, NULL ); // Mutex Lock init.
m_nCheckInterval = nCheckInterval;
m_strProperPath.clear();
m_nAvailableSize = 0;
// 최상위 경로값에서 마지막 문자가 '/' 인 경우.. 제거 처리한다.
// - 업무 Flow 관련 경로 처리 문제 사전 해결
// - 시스템에서 추출된 mount 정보와 비교 처리시 정상 비교가 될 수 있도록..
if( strStorageRoot.length() > 1 )
{
if( strStorageRoot.at( strStorageRoot.length() -1 ) == '/' )
{
m_strStorageRoot = strStorageRoot.substr( 0, strStorageRoot.length() -1 );
}
else
m_strStorageRoot = strStorageRoot;
}
else
m_strStorageRoot = strStorageRoot;
}
// 소멸자
CProperStorage::~CProperStorage()
{
// 동작 중인 Thread 정지 처리.
// - 만약 Thread 가 이미 종료된 경우 m_threadHandle 가 다른 Thread Handle 일 수 있으므로 업무 Flow 수정시 주의할 것
pthread_cancel( m_threadHandle );
// Mutex Lock 제거
pthread_mutex_destroy( &m_mutexLock );
}
// Content Write 관련 최적 Mount 경로를 반환한다.
bool CProperStorage::GetProperPath( std::string& strProperPath )
{
bool bResult;
// Thread 와 동시 접근을 제어하기 위해 Lock 처리
pthread_mutex_lock( &m_mutexLock );
if( m_strProperPath.empty() == true )
{
// 최적 경로를 추출하지 못한 경우...
bResult = false;
LOG( LERR, "proper mount path empty. return false.");
}
else
{
// 최적 경로가 존재하는 경우..
strProperPath = m_strProperPath;
bResult = true;
LOG( LDBG, "proper mount path return. [%s]", strProperPath.c_str() );
}
pthread_mutex_unlock( &m_mutexLock );
return bResult;
}
// Content Write 관련 최적 Mount 경로 및 사용 가능 Free Size 를 반환한다.
bool CProperStorage::GetProperPath( std::string& strProperPath, unsigned long long & nAvailableSzie )
{
bool bResult;
// Thread 와 동시 접근을 제어하기 위해 Lock 처리
pthread_mutex_lock( &m_mutexLock );
if( m_strProperPath.empty() == true )
{
// 최적 경로를 추출하지 못한 경우...
nAvailableSzie = 0;
bResult = false;
LOG( LERR, "proper mount path empty. return false.");
}
else
{
// 최적 경로가 존재하는 경우..
strProperPath = m_strProperPath;
nAvailableSzie = m_nAvailableSize;
bResult = true;
LOG( LDBG, "proper mount path return. [%s] free[%llu Byte]", strProperPath.c_str(), nAvailableSzie );
}
pthread_mutex_unlock( &m_mutexLock );
return bResult;
}
// Content Write 관련 최적 Mount 경로의 사용 가능 Free Size 를 반환한다.
// - GetProperPath() 함수를 통해 경로 정보 수신 후 본 함수를 호출할 경우...
// - Thread 에 의해 경로 정보 및 Free 용량 정보가 변경되어 다른 경로에 대한 Free 용량 정보가 전달될 수 있으니... 사용시 주의한다.
void CProperStorage::GetAvailableSize( unsigned long long & nAvailableSzie )
{
// Thread 와 동시 접근을 제어하기 위해 Lock 처리
pthread_mutex_lock( &m_mutexLock );
nAvailableSzie = m_nAvailableSize;
LOG( LDBG, "proper mount free size [%llu] return. path[%s]", nAvailableSzie, m_strProperPath.c_str() );
pthread_mutex_unlock( &m_mutexLock );
return;
}
// Thread 를 생성하여 Mount 정보에 대한 검사를 주기적으로 수행한다.
bool CProperStorage::Start()
{
// 생성자를 통해 전달받은 최상위 경로 정보가 유효하지 않은 경우..
if( m_strStorageRoot.empty() == true )
{
LOG( LERR, "storage root path empty. ");
return false;
}
// 생성자를 통해 전달받은 최상위 경로 정보가 '/' 정보인 경우에도 유효하지 않으므로 오류로 처리한다.
if( strcmp( m_strStorageRoot.c_str(), "/") == 0 )
{
LOG( LERR, "storage root path not vaild. [%s]", m_strStorageRoot.c_str() );
return false;
}
// Thread 를 생성 시킨다.
int nResult = pthread_create( &m_threadHandle, 0, CProperStorage::threadFunc, this );
if( nResult != 0 )
{
// Thread 생성 실패시...
int errorNum = errno;
LOG( LERR, "thread create failed.[%d][%s]", errorNum, strerror(errorNum) );
return false;
}
return true;
}
// Thread 함수
void * CProperStorage::threadFunc( void * arg )
{
CProperStorage * pObject = reinterpret_cast<CProperStorage *>(arg);
pthread_detach( pthread_self() );
while(1)
{
pthread_testcancel();
pObject->Execute();
pthread_testcancel();
// 지정된 시간동안 sleep..
sleep( pObject->m_nCheckInterval );
}
return NULL;
}
// sort 처리를 수행하기 위한 함수.
bool SortMountAvailableSize( struct systme_mount_info fisrt, struct systme_mount_info second)
{
// first 의 available_byte 용량 순으로 정렬.
return ( fisrt.available_byte > second.available_byte ) ? true : false;
}
// 실제 시스템 Disk Mount 정보를 조회하여... 최적 Mount 경로 정보를 추출하기 위한 함수.
// 본 함수 Flow 로직은 코드를 단순하게 하여 라인 수를 줄여 compact 하게 할 수 있으나... 함수 Flow 이해가 어렵게 된다.
// 따라서.. 중복되는 상황이 나오더라도.. 업무 Flow 순서에 명확하도록 개발한다.
void CProperStorage::Execute()
{
// Start() 함수에서 최상위 경로 인자값에 대한 검사를 했으므로.... 최상위 경로값을 정상이라고 판단하고 검사를 수행한다.
// 최상위 경로값은 다음과 같이 세팅될 수 있다.
// - /stg , /stg/, /stg/node0 , /stg/node0/
// - /user2 , /user2/, /user2/dav_storage, /user2/dav_storage/
// 1. 최상위 경로값에서 마지막 문자가 '/' 인 경우.. 제거 처리한다.
// - 업무 Flow 관련 경로 처리 문제 사전 해결
// - 시스템에서 추출된 mount 정보와 비교 처리시 정상 비교가 될 수 있도록..
// => 본 처리는 생성자에서 처리를 수행하므로.. pass....
// 2. 장비의 Mount 정보 와 available 용량 정보를 추출한다.
if( GetSystmeMountInfo() == false )
{
// 시스템의 Mount 정보 추출 실패 또는 Mount 정보가 존재하지 않는 경우...
// Mount 정보 추출 실패로 인해 최적 경로 정보를 invalid 정보로 설정 처리한다.
SetProperPathError();
return;
}
// Mount 정보 저장 관련 임시 객체
struct systme_mount_info stMountInfo;
// 3. 수정된 최상위 경로값과 동일한 장비 Mount 정보가 존재하는지 비교한다.
// - 비교시 문자열 Full 비교 수행.. ( /stg/node0 등으로 설정된 경우를 위해 )
// 각 조건에 맞아 추출된 Mount 정보를 저장하기 위한 임시 변수.
std::vector<struct systme_mount_info> vecTempMount;
std::vector<struct systme_mount_info>::iterator it;
//_LOG( LDBG, "Worker[%d]::ProperStorage: mount full scan start. path[%s]", getpid(), m_strStorageRoot.c_str() );
for( it = m_vecMount.begin(); it < m_vecMount.end(); it++ )
{
if( strcmp( m_strStorageRoot.c_str(), it->mount_name.c_str() ) == 0 )
{
stMountInfo.mount_name = it->mount_name;
stMountInfo.available_byte = it->available_byte;
vecTempMount.push_back( stMountInfo );
_LOG( LDBG, "Worker[%d]::ProperStorage: mount name full scan. [%s] available byte[%llu]"
, getpid(), stMountInfo.mount_name.c_str(), stMountInfo.available_byte );
}
}
// 4. 만약 위의 3번 항목에서 Mount 장비를 찾지 못한 경우....
// - conf 상에 설정된 경로 정보가 실제 Mount 정보를 나타내는 것이 아니다.
// - 수정된 최상위 경로부터 부분 비교를 시작해서 없을 경우.. sub path 부분을 제외한 후 다시 장비 Mount 정보와 비교한다.
// - 장비 mount 정보를 찾을 때까지 본 비교를 반복하여 수행한다.
if( vecTempMount.empty() == true )
{
// 최초 비교시에는 원래 정보를 가지고 부분 비교처리.. (/stg 등으로 설정된 경우를 위해)
std::string strPreviousPath = m_strStorageRoot;
std::string strCurrentPath = m_strStorageRoot;
do
{
//_LOG( LDBG, "Worker[%d]::ProperStorage: mount partical scan start.. path[%s]", getpid(), strCurrentPath.c_str() );
// 수정된 경로 정보만을 가지고 부분 비교를 수행....
for( it = m_vecMount.begin(); it < m_vecMount.end(); it++ )
{
// 부분 비교 처리
if( strncmp( strCurrentPath.c_str(), it->mount_name.c_str(), strlen(strCurrentPath.c_str()) ) == 0 )
{
stMountInfo.mount_name = it->mount_name;
stMountInfo.available_byte = it->available_byte;
vecTempMount.push_back( stMountInfo );
_LOG( LDBG, "Worker[%d]::ProperStorage: mount partical scan. path[%s], mount[%s] available byte[%llu]"
, getpid(), strCurrentPath.c_str(), stMountInfo.mount_name.c_str(), stMountInfo.available_byte );
}
}
// 위에서 정보 추출이 실패한 경우..상위 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 );
}
// 5. 3,4 항목에서 장비 mount 를 찾은 경우....
//
// 5.1 1개 Mount 만 검색된 경우...
// - 최종 마운트 경로 정보는 1 항목에서 수정된 경로이며.....
// - 여유용량이 임계치를 이상이면 정상, 임계치 미만이면 오류 처리한다.
// - 1개 이므로.. mount 에 대한 disable 검사는 수행하지 않는다. (왜냐면 소용 없으므로... )
//
// 5.2 다중 Mount 가 검색된 경우...
// - 각 mount 에 대한 여유용량 임계치를 검사한다.
// 만약 여유용량이 임계치 미만이면 목록에서 제거한다.
// - 수정된 mount 목록에서 각 Mount 경로에 대한 disable 검사를 수행한다.
// - 최종... disable 되지 않고.. 여유 용량이 가장 많은 mount 를 선택한다.
// 만약 전부 disable 된 경우... disable 을 무시하고 여유용량이 가장 많은 mount 를 선택한다.
// - 최종 마운트 경로 정보는 시스템에서 추출된 Mount 경로를 사용한다. ( 5.1 과는 다른 선택임 )
if( vecTempMount.empty() == true )
{
// 적합한 Mount 경로를 찾지 못한 경우...
// Mount 정보 추출 실패로 인해 최적 경로 정보를 invalid 정보로 설정 처리한다.
SetProperPathError();
LOG( LERR, "proper mount path find failed. conf path[%s]", m_strStorageRoot.c_str() );
}
else
{
// 시스템에서 1개 Mount 정보만 검색된 경우.
if( vecTempMount.size() == 1 )
{
// 여유용량에 대한 임계치를 검사 후...
// 최적 Mount 경로 정보는 운영자가 설정한 경로 정보로 설정한다.. (/user2/dav_storage , /stg/node0, /stg/node0/aa/bb 등의 경우)
if( vecTempMount[0].available_byte < LIMIT_STORAGE_SIZE )
{
LOG( LERR, "proper mount not found. mount[%s] available size[%llu] limit[%llu]"
, m_strStorageRoot.c_str(), vecTempMount[0].available_byte, LIMIT_STORAGE_SIZE );
SetProperPathError();
}
else
{
// CHG 2015-03-27 huibong
// 설정값이 /stg 이고.. mount 정보가 1개 /stg/node0 인 경우...
// 아래 로직에 의해 경로값이 설정값인 /stg 가 선택되는 문제 발생. ( #21917 )
// 이를 해결하기 위해.. 설정값과 추출된 mount 이름 중 길이가 큰 값을 사용하도록 수정 처리한다.
// SetProperPath( m_strStorageRoot, vecTempMount[0].available_byte );
if( m_strStorageRoot.size() > vecTempMount[0].mount_name.size() )
SetProperPath( m_strStorageRoot, vecTempMount[0].available_byte );
else
SetProperPath( vecTempMount[0].mount_name, vecTempMount[0].available_byte );
}
}
else
{
// 시스템에서 1개 초과 Mount 정보만 검색된 경우. -> 시스템에서 추출된 Mount 경로를 최적 Mount 경로를 사용한다.
// 여유용량에 대한 임계치를 검사 후... -> 임계치 이하 항목은 제거..
// 여유 용량이 가장 많은 Mount 순으로 정렬한 후...
// Mount disable 검사....
// 만약 전체 mount disable 되어 있다면... 가장 용량이 많은 Mount 선택 처리..
// 임계치 이상의 여유 공간을 가진 Mount 정보를 임시로 저장할 Vector.
std::vector<struct systme_mount_info> vecAvailMount;
for( it = vecTempMount.begin(); it < vecTempMount.end(); it++ )
{
// 여유 용량에 대한 임계치 검사.
if( it->available_byte >= LIMIT_STORAGE_SIZE )
{
stMountInfo.mount_name = it->mount_name;
stMountInfo.available_byte = it->available_byte;
vecAvailMount.push_back( stMountInfo );
}
else
{
_LOG( LWAR, "mount available size not enough. mount[%s] available size[%llu] limit[%llu]"
, it->mount_name.c_str(), it->available_byte, LIMIT_STORAGE_SIZE );
}
}
// 임계치 이상의 용량을 가진 Mount 가 없는 경우...
if( vecAvailMount.empty() == true )
{
LOG( LERR, "proper mount not found. mount available size not enough. limit[%llu]", LIMIT_STORAGE_SIZE );
SetProperPathError();
}
else
{
// 최소 임계치 이상의 용량을 가진 Mount 가 존재하는 경우..
// Available 용량이 큰 순서대로 sort 처리...
// 루프를 돌며서 각 Mount 별로 disable 검사.. 만약 disable 처리가 안된 경우. 해당 Mount 를 Proper Mount 롤 선정.
std::sort( vecAvailMount.begin(), vecAvailMount.end(), SortMountAvailableSize );
for( it = vecAvailMount.begin(); it < vecAvailMount.end(); it++ )
{
//_LOG( LDBG, "ProperStorage: Sort result. mount[%s] available size[%llu]" , it->mount_name.c_str(), it->available_byte );
// Mount 별로 Mount disable 되어 있는지 검사...
if( CheckMountDisable( it->mount_name ) == false )
{
SetProperPath( it->mount_name, it->available_byte );
return;
}
}
// 위의 루프에서 Mount 가 전부 disable 되어 있어 적합한 Mount 를 찾지 못한 경우...
// 용량별로 sort 되어 있으므로.. 첫번째 Mount 를 선정한다.
_LOG( LWAR, "Worker[%d]::ProperStorage: all mount disable. forced selected by available size order.[%s] size[%llu]"
, getpid(), vecAvailMount[0].mount_name.c_str(), vecAvailMount[0].available_byte );
SetProperPath( vecAvailMount[0].mount_name, vecAvailMount[0].available_byte );
return;
}
}
}
return;
}
// FHS 장비의 Mount 정보를 추출하여... 멤버 변수인 m_vecMount 에 저장한다.
// return true : Mount 정보 정상 추출시...
// false : Mount 정보 추출 실패 또는 추출된 Mount 정보가 없는 경우...
bool CProperStorage::GetSystmeMountInfo()
{
// 추출된 Mount 정보 저장 객체 초기화.
struct systme_mount_info stMountInfo;
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++ )
{
stMountInfo.mount_name = pStatFsBuf[i].f_mntonname;
stMountInfo.available_byte = pStatFsBuf[i].f_bavail * (unsigned long long)pStatFsBuf[i].f_bsize ;
m_vecMount.push_back( stMountInfo );
//LOG( LDBG, "system mount name[%s] available byte[%llu]", stMountInfo.mount_name.c_str(), stMountInfo.available_byte );
// 시스템에서 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 ) )
{
stMountInfo.mount_name = stMnt.mnt_dir;
stMountInfo.available_byte = statFsBuf.f_bavail * (unsigned long long)statFsBuf.f_bsize ;
m_vecMount.push_back( stMountInfo );
//LOG( LDBG, "system mount name[%s] available byte[%llu]", stMountInfo.mount_name.c_str(), stMountInfo.available_byte );
}
}
// 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;
}
// 인자로 전달받은 Mount 에 대해 disable flag 가 등록되어 있는지 검사
// true : mount disable flag 가 걸려 있는 경우.
// false : mount disable flag 가 없는 경우..
bool CProperStorage::CheckMountDisable( const std::string & strMountName)
{
char szDisableName[512];
struct stat flagStat;
sprintf( szDisableName, "%s%s", strMountName.c_str(), DISABLE_FLAG );
// Mount disable flag 가 존재하고....
if( lstat( szDisableName, &flagStat) == 0 )
{
// 해당 파일이 정규 파일인 경우.. ( 폴더, 링크 등은 제외 처리 )
if( S_ISREG(flagStat.st_mode) != 0 )
{
return true;
}
}
return false;
}
// 전달받은 경로로부터.. 상위 Path 정보를 추출하여 전달한다.
// 오류 발생시 [out] 값인 strUpperPath 가 empty 된다.
void CProperStorage::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;
}
// Content Write 관련 최적 Mount 경로 및 사용 가능 Free Size 를 설정한다.
void CProperStorage::SetProperPath( std::string& strProperPath, unsigned long long & nAvailableSzie )
{
// Thread 와 동시 접근을 제어하기 위해 Lock 처리
pthread_mutex_lock( &m_mutexLock );
m_strProperPath = strProperPath;
m_nAvailableSize = nAvailableSzie;
pthread_mutex_unlock( &m_mutexLock );
_LOG( LDBG, "Worker[%d]::ProperStorage: proper path set. [%s] free[%llu]byte", getpid(), m_strProperPath.c_str(), m_nAvailableSize );
return;
}
// Content Write 관련 최적 Mount 경로 및 사용 가능 Free Size 추출 실패시..
void CProperStorage::SetProperPathError()
{
// Thread 와 동시 접근을 제어하기 위해 Lock 처리
pthread_mutex_lock( &m_mutexLock );
m_strProperPath.clear();
m_nAvailableSize = 0;
pthread_mutex_unlock( &m_mutexLock );
LOG( LERR, "Worker[%d]: proper mount path set invalid value.", getpid() );
return;
}
+126
View File
@@ -0,0 +1,126 @@
/***************************************************************************
Proper storage info collect thread class
-----------------------------------------
begin : 2014/02/27
copyright : (C) 2005 SolutionBox Inc.
author : solbox dev team
email : huibong@solbox.com
version : 3.3.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 __PROPER_STORAGE_H__
#define __PROPER_STORAGE_H__
#include <pthread.h>
#include <string>
#include <vector>
#include <unistd.h>
// 시스템에서 추출된 Mount 정보를 저장하기 위한 struct...
struct systme_mount_info {
std::string mount_name; // Mount Name..
unsigned long long available_byte; // available byte
};
/// @brief CProperStorage
/// 본 클래스는 Thread 클래스로서
/// 장비에 mount 된 경로 정보 중... 가장 Free 용량이 많은 Mount 경로 정보를 반환한다.
/// 각 Mount 에 대한 검사는 주기적으로 Thred 에 의해 동작된다.
class CProperStorage
{
public:
/// @brief 생성자
/// @param [in] strStorageRoot 전체 Mount 된 경로 정보 중 사용할 최상위 경로 정보. ( /stg , /user2/dav_storage 등 )
/// @param [in] nCheckInterval 각 Mount 정보에 대한 상태 검사 주기, 초(sec) 단위
CProperStorage( const std::string & strStorageRoot, const int nCheckInterval );
~CProperStorage();
/// @brief Thread 기동 함수
/// @param none
/// @return 성공시 true, 그 외 false
bool Start();
/// @brief 생성자에 전달된 최상위 경로 정보를 바탕으로 시스템에 Mount 된 정보를 검사하여...
/// Content Write 에 가장 적절한 mount 경로정보를 전달한다.
/// @param [out] strProperPath Content Write 에 가장 적절한 Mount 경로 ( /stg/node0, /stg/node1, /user2/dav_storage 등 )
/// @return 성공시 true, 그 외 false
bool GetProperPath( std::string& strProperPath );
bool GetProperPath( std::string& strProperPath, unsigned long long & nAvailableSzie );
/// Content Write 에 가장 적절한 mount 경로정보의 Free Size 정보. ( Byte 단위)
// - GetProperPath() 함수를 통해 경로 정보 수신 후 본 함수를 호출할 경우...
// - Thread 에 의해 경로 정보 및 Free 용량 정보가 변경되어 다른 경로에 대한 Free 용량 정보가 전달될 수 있으니... 사용시 주의한다.
void GetAvailableSize( unsigned long long & nAvailableSzie );
private:
// 생성자를 통해 전달받은 최상위 경로 정보 저장.
std::string m_strStorageRoot;
// Mount 정보에 대한 검사 주기 (생성자를 통해 전달받음, sec 단위 )
int m_nCheckInterval;
// Thread 에서 검사된 최적의 Content Write 경로 정보 저장 변수. ( 주기적으로 변경됨 )
std::string m_strProperPath;
// 추출된 m_strProperPath 경로의 Free Size ( Byte 단위 )
unsigned long long m_nAvailableSize;
// 검사 결과 저장 관련 m_strProperPath, m_nAvailableSize 에 대해 동시 get, set 처리 관련 Mutext lock
pthread_mutex_t m_mutexLock;
// systme 에서 추출된 mount 상태 정보를 저장하기 위한 vector 변수
std::vector<struct systme_mount_info> m_vecMount;
private:
// 쓰레드 핸들
pthread_t m_threadHandle;
// 쓰레드 함수..
static void * threadFunc( void * arg );
// 실제 경로 최적 Mount 경로 정보 추출을 담당할 함수.
void Execute( void );
// FHS 장비의 Mount 정보를 추출하여... 멤버 변수인 m_vecMount 에 저장한다.
// return true : Mount 정보 정상 추출시...
// false : Mount 정보 추출 실패 또는 추출된 Mount 정보가 없는 경우...
bool GetSystmeMountInfo();
// 전달받은 경로로부터.. 상위 Path 정보를 추출하여 전달한다.
// 오류 발생시 [out] 값인 strUpperPath 가 empty 된다.
void GetUpperPath( const std::string & strSourcePath, std::string & strUpperPath );
// Content Write 관련 최적 Mount 경로 및 사용 가능 Free Size 를 설정한다.
void SetProperPath( std::string& strProperPath, unsigned long long & nAvailableSzie );
// Content Write 관련 최적 Mount 경로 및 사용 가능 Free Size 추출 실패시..
void SetProperPathError();
// 인자로 전달받은 Mount 에 대해 disable flag 가 등록되어 있는지 검사
bool CheckMountDisable( const std::string & strMountName);
// vector 정렬 함수.
//bool SortMountAvailableSize( struct systme_mount_info & fisrt, struct systme_mount_info & second);
};
#endif //__PROPER_STORAGE_H__
+85
View File
@@ -0,0 +1,85 @@
/***************************************************************************
ftsd ( File TranSfer Daemon ) Header ( Protocol.h )
-----------------------------------------
begin : 2010/03/09
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __PROTOCOL_H__
#define __PROTOCOL_H__
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 extend_code[2]; // 확장 및 Padding bits ( 2 Byte )
};
// Communication Packet Header stx 코드
#define HEADER_STX_CODE 0x02
// Communication Packet Header type 구분코드
#define HEADER_TYPE_REQUEST 0x00
#define HEADER_TYPE_RESPONSE 0x01
// Communication Packet command 공통.
#define COMMON_ALIVE_CHECK 0x7F
// Communication Packet command
// control<->transfer 통신 (Command 첫번째 Byte 만 사용)
//
#define NOT_CONTROL_COMMAND 0x00 // Control 이 전송한 요청이 아닌 경우.
#define CONTROL_FILE_REPLICATION 0x01 // Content Replication 처리 요청
#define CONTROL_FILE_CACHE 0x02 // Content Cache 폴더로 복제 처리 요청
#define CONTROL_FILE_CHECK 0x03 // Content 에 대한 존재 여부, Size 확인 및 Hash 추출 요청
#define CONTROL_FILE_UNLINK 0x04 // Content 에 대한 unlink 처리 요청
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460)
#define CONTROL_FILE_CHECK_TOTO 0x05 // 토토디스크 고객사 지원을 위한 MD5 Hash 추출 기능 (2016-05-03 추가)
// NEW 2021-04-01 huibong content stat(size, atime, mtime, ctime) 정보 추출 기능 추가 (#33516)
#define CONTROL_FILE_STAT 0x06
// Communication Packet command
// transfer<->transfer 간의 내부 통신 (Command 두번째 Byte 만 사용)
//
#define TRANSFER_LOCAL_IP 0x01 // 내부망 IP 요청 및 결과 처리시.
#define TRANSFER_FILE_REPLICATION 0x02 // 파일 복제 처리시
#define TRANSFER_FILE_CACHE 0x03 // 파일 Cache 처리시
#define TRANSFER_FILE_HASH 0x04 // 파일 Hash Check
#define TRANSFER_FILE_START 0x05 // 파일 전송 시작시 Header
#define TRANSFER_FILE_END 0x06 // 파일 전송 종료시 전달. 수신 받은 파일 정보 요청 목적
// Communication Packet Result
// => type이 Response 인 경우에만 세팅됨.( 첫번째 Byte 만 사용시 )
#define HEADER_RESULT_SUCCESS 0x00
#define HEADER_RESULT_ERROR 0x01
// 기타 정보
#define LENGTH_FIELD_SIZE 4 // 가변데이터 형식 사용시 Length 필드의 메모리 크기 (unsigned int)
// unlink 요청시 Mode 설정 정보
#define UNLINK_MODE_NORMAL 0 // 해당 Content 가 존재하고 size 값이 정확한 경우에만 삭제, 나머지는 오류
#define UNLINK_MODE_FORCE 1 // 해당 Content 가 존재하지 않거나.. Size 값이 틀려도 강제로 삭제 처리.. 오류로 처리되는 상황은 통신, 시스템 오류 발생시.
#endif /* __PROTOCOL_H__ */
File diff suppressed because it is too large Load Diff
+243
View File
@@ -0,0 +1,243 @@
/***************************************************************************
ftsd ( File TranSfer Daemon ) Header ( SocketControl.h )
-----------------------------------------
begin : 2010/03/09
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __SOCKET_CONTROL_H__
#define __SOCKET_CONTROL_H__
#include <stdio.h>
#include <iostream>
#include <vector>
#include <map>
#include "Protocol.h"
#include "BaseSocket.h"
///< BYTE 타입 정의
#ifndef _BYTE_DEFINED
#define _BYTE_DEFINED
typedef unsigned char BYTE;
#endif // _BYTE_DEFINED
#define DEFAULT_SOCKET_TEMP_BUFFER_SIZE 1024 // SocketControl 에서 사용할 임시버퍼 크기.
#define FILE_DATA_BUFFER_SIZE 16384 // 16 Kbyte, 파일 송수신시 사용할 임시 버퍼의 크기.
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 생성자.
/// @param socket [in] 처리할 socket descriptor
CSocketControl();
CSocketControl( const int & socket );
/// @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 Packet 의 Header 정보를 수신하여 각 정보를 전달받은 참조변수로 반환.
/// @param bRequest [out] Request 요청인지 여부
/// @param bFromControl [out] Control 로 부터 전달된 Command 인지 여부
/// @param command [out] Command 정보
/// @return 1 : Data 수신 성공시
/// 0 : Timeout 발생시
/// -1 : 접속 종료시
int GetHeaderInfo( bool& bRequest, bool& bFromControl, char& command );
/// @brief Packet 의 Header 정보 중 현재 전달받은 Header 의 Result 값을 반환
/// @param result [out] result 4 Byte 부분의 값을 저장하기 위한 참조변수
/// @return result 4 Byte 부분 중 첫번째 Byte 값을 반환.
char GetHeaderResult(void );
void GetHeaderResult( std::vector<char>& result );
/// @brief Packet Header 정보를 Log 파일에 Logging 처리
void PrintHeaderToLog(void);
/// @brief Transfer Daemon 으로 Local NIC IP 정보 전송
/// @param bResult [in] szValue 에 저장된 Local IP 정보의 유효여부
/// @param szValue [in] Local NIC IP 정보
/// @return 전송 성공시 true, 실패시 false 반환.
bool SendLocalIpInfo( bool bResult, const std::string& szValue );
/// @brief Socket 으로 연결된 대상의 Local NIC IP 정보를 요청한 후 해당 정보 수신.
bool GetLocalIpInfo( std::string& szValue );
/// @brief 연결된 socket 으로 파일 수신 요청 패킷을 전송한다.
bool SendFileReceiveRequest( std::string& szFileName, unsigned long long nFileSize, char commandCode );
/// @brief File 수신 요청에 대한 응답 패킷을 수신처리하기 위한 함수( TRANSFER_FILE_REPLICATION, TRANSFER_FILE_CACHE 요청에 대한 response 처리).
/// 본 패킷이 정상인 경우 이 패킷을 수신한 Daemon 은 파일 전송 시작 패킷 및 File의 전송을 바로 시작한다.
bool GetFileReceiveResponse( char commandCode, bool& bSuccess, std::string& szErrorString );
/// @brief File 송신 시작(TRANSFER_FILE_START::REQUEST) 요청 패킷.
bool SendFileStartRequest(void);
/// @brief File 송신 완료후 해당 파일 정보 요청을 위한 (TRANSFER_FILE_END::REQUEST) 요청 패킷.
bool SendFileEndRequest(void);
/// @brief 파일 수신 완료에 따른 응답패킷을 파싱처리.
bool GetFileEndResult( bool& bSuccess, std::string& szFileFullName, unsigned long long& nFileSize, std::string& szErrorString );
/// @brief 파일의 수신 요청을 받은 경우 해당 업무를 수행하기 위한 함수
///< 본 함수는 파일의 수신, 수신 관련 통신 작업을 내부적으로 진행 처리함.
bool ReceiveFile( const std::string& szStorageRoot, unsigned long long nMaxStorageAvailableSize, char commandCode );
/// @brief 특정 파일에 대한 Hash 검사 요청을 연결된 Socket 을 통해 전송한다.
bool SendHashCheckRequest(const std::string& szFileName, unsigned long long nFileSize
, unsigned int nHashLevel, const std::string& szSourceHash );
/// @brief 특정 파일에 대한 Hash 검사 요청을 받은 경우 이를 처리한다.
bool CheckFileHash(void);
/// @brief 특정 파일에 대한 Hash 검사 결과를 연결된 Socket 으로 전송한다.
bool SendHashCheckResponse( bool bSuccess, std::string& szErrorString );
/// @brief Hash 검사 요청에 대한 결과값을 수신한다.
bool GetHashCheckResult( bool& bSuccess, std::string& szErrorString );
/// @brief Alive Check 를 위한 패킷 전송 => 해당 패킷의 응답은 필요없으므로 수신시 무시할 것.
bool SendAliveCheck(void);
/// @brief Control 로 부터 CONTROL_FILE_REPLICATION 또는 CONTROL_FILE_CACHE Request 요청을 받은 경우 \n
///< Packet Data 부분의 상세 정보를 가져온다.
bool GetFileRequestInfo( std::string& szFileName, unsigned long long& nFileSize, std::string& szTargetTranId,
int& nFileHashCheckLevel, bool& bUseInternalIp, std::vector< std::string >& vecTargetFhs);
/// @brief Control 로 부터 COCONTROL_FILE_CHECK Request 요청을 받은 경우 Packet Data의 상세 정보를 가져온다.
bool GetRequestCheckFromControl( std::string& szFileName, bool& bHashCheck, unsigned long long& nHashCheckSize );
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460)
/// @brief Control 로 부터 CONTROL_FILE_CHECK_TOTO Request 요청을 받은 경우 Packet Data의 상세 정보를 가져온다.
bool GetRequestCheckTOTOFromControl( std::string& szFileName );
/// @brief Control 로 부터 COCONTROL_FILE_UNLINK Request 요청을 받은 경우 Packet Data의 상세 정보를 가져온다.
bool GetRequestUnlinkFromControl( std::string& szFileName, unsigned long long& nFileSize, unsigned int& nUnlinkMode );
// NEW 2021-04-01 huibong content stat(size, atime, mtime, ctime) 정보 추출 기능 추가 (#33516)
/// @brief Control 로 부터 CONTROL_FILE_STAT Request 요청을 받은 경우 Packet Data의 상세 정보를 가져온다.
bool GetRequestStatFromControl( std::string & szFileName );
/// @brief Control 로 요청에 대한 오류 결과 메시지를 전송한다.
bool SendErrorMessageToControl( const std::string& szErrorMessage, char commandCode );
/// @brief Control 로 파일 복제 요청에 대한 성공 처리 결과 메시지를 전송한다.
bool SendFileReplicationResult( char commandCode
, std::map< std::string, std::string>& mapSuccessList, std::map< std::string, std::string>& mapFailList );
/// @brief Control 로 Check 요청에 대한 성공 처리 결과를 전달한다.
bool SendCheckResultToControl( char commandCode, const unsigned long long& nFileSize, const std::string& szHashValue );
/// @brief Control 로 Unlink 요청에 대한 성공 처리 결과를 전달한다... Data 부분은 존재하지 않음.
bool SendUnlinkResultToControl( char commandCode );
// NEW 2016-05-11 huibong 토토디스크 지원용 기능 추가 (#27460, #27533)
/// @brief 고객사 토토디스크 지원을 위한 기능
/// Control 로 부터 전달받은 Content 에 대해 Size 정보 및 MD5 Hash, Checksum 정보 등을 추출하여 전달한다.
bool SendTOTOCheckResultToControl( char commandCode, const unsigned long long& nFileSize
, const std::string& szResultTotoMd5, const std::string& szResultChecksum, const std::string& szResultDnaCheckKey );
// NEW 2021-04-01 huibong content stat(size, atime, mtime, ctime) 정보 추출 기능 추가 (#33516)
/// @brief Control 로 Stat 요청에 대한 성공 처리 결과를 전달한다.
bool SendStatResultToControl( char commandCode, const long & nFileSize, const long & nAccessTime, const long & nModifyTime, const long & nChangeTime );
protected:
/// @brief Packet Header 부분의 수신 처리를 위한 함수. Alive Check 요청 패킷은 자동으로 무시처리함.
/// @param timeout [in] 대기시간.
/// @retrun ( 해당 Define 은 SocketControl.cpp 참고 )
/// 1 : PACKET_HEADER_RECEIVE_SUCCESS : 성공시
/// 0 : PACKET_HEADER_RECEIVE_TIMEOUT : Timeout 발생시
/// -1 : PACKET_HEADER_RECEIVE_SOCK_CLOSED : socket 종료된 경우
/// -2 : PACKET_HEADER_RECEIVE_INVALID_PROTOCOL : 잘못된 Packet 형식인 경우
/// -3 : PACKET_HEADER_RECEIVE_READ_ERROR : 기타 오류
int GetPacketHeader(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 );
/// @brief 전달받은 Directory 정보를 확인하여 존재하지 않을 경우 생성처리.
bool MakeDirectory( const std::string& szFullPath );
/// @brief Socket 으로 부터 수신받은 데이터를 파일에 Write 처리한다.
///< 만약 File Write 처리시 오류가 발생하는 경우 Socket Data 의 정상적인 처리를 위해
///< Socket 데이터 수신만 처리하고 오류를 반환한다.
/// @returnFile Write 가 오류 없이 정상적으로 처리된 경우 true, 오류발생시 false 및 오류메시지 반환
bool ReceiveToFile( FILE * pFile, unsigned long long nFileSize, std::string& errorMessage );
// Socket 으로 부터 수신받은 데이터를 읽어서.. 버린다.
// - 기존 물리 파일이 존재하는 경우.. overwrite 처리를 않기로 해서...
// - socket 으로 부터 수신된 data 는 버린다.
// return 오류 없이 정상적으로 처리된 경우 true, 오류발생시 false 및 오류메시지 반환
bool ReceiveToDummy( unsigned long long nFileSize, std::string& errorMessage );
/// @brief File 수신 요청에 대한 응답 패킷 전송( TRANSFER_FILE_REPLICATION, TRANSFER_FILE_CACHE 요청에 대한 response 패킷임.
/// 해당 패킷이 정상인 경우 이 패킷을 수신한 Daemon 은 파일 전송 시작 패킷 및 File의 전송을 바로 시작한다.
bool SendFileReceiveResponse( bool bSuccess, std::string& szErrorString, char commandCode );
/// @brief File 송신 완료(TRANSFER_FILE_END) 패킷에 대한 응답 패킷 전송
bool SendFileEndResponse( bool bSuccess, std::string& szFileFullName, unsigned long long nFileSize, std::string& szErrorString );
};
#endif /* __SOCKET_CONTROL_H__ */
+186
View File
@@ -0,0 +1,186 @@
#include "TOTOChecksum.h"
#include "Logger.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
typedef unsigned long long UINT64;
// 토토디스크 고객사용 CRC Table.
long g_arrayTotoCrc[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
// 생성자
CTotoChecksum::CTotoChecksum()
{
// 오류메시지 객체 초기화.
m_szErrorMessage.clear();
}
// 소멸자
CTotoChecksum::~CTotoChecksum()
{
}
int CTotoChecksum::calcCRC32( unsigned char b, unsigned int iCrc32 )
{
//return (int)((dwCrc32 >>> 8) ^ CRC_TABLE[(dwCrc32 ^ b) & 0xFF]);
// JAVA >>> 연산은 C 의 >> 와 동일하지만.. 빈 공간을 무조건 0 채운다.
// 따라서.. 이를 지원하기 위해.. iCrc32 인자값을 unsigned int 형으로 변경 처리한다.
//_LOG( LDBG, "TOTO calcCRC32 byte[%c] crc[%d] [%d] [%d]", b, iCrc32, (iCrc32 >> 8), (iCrc32 ^ b) );
return (int)((iCrc32 >> 8) ^ g_arrayTotoCrc[(iCrc32 ^ b) & 0xFF]);
}
/// @brief 토토디스크 고객사 지원용 파일 Checksum 정보 추출 함수
/// @param szFileFullPath [in] 파일의 절대경로 값.
/// @param nFileTotalSize [in] 파일 크기 값.
/// @param szResult [out] Checksum 추출 결과값을 반환하기 위한 변수.
/// @return 성공은 return true, 그 외에는 return false
bool CTotoChecksum::GetChecksum( const std::string &szFileFullPath, const unsigned long long nFileTotalSize, std::string& szResult )
{
int fd;
unsigned char szBuffer[4096];
int nLen;
UINT64 nFileSkipCount;
int i;
long nResultValue = 0;
int iCrc32 = 0xffffffff;
memset( szBuffer, 0x00, sizeof( szBuffer ) );
// 저장변수 초기화.
szResult.clear();
// 파일 open
if( (fd = open( szFileFullPath.c_str(), O_RDONLY )) == -1 )
{
m_szErrorMessage = "File open failed. [" + szFileFullPath + "]";
return false;
}
else
{
// 파일을 10 개 지점으로 분할하여 지점별 4096 Byte 씩 추출하여 CRC 계산 처리 수행.
nFileSkipCount = (nFileTotalSize > 0 ? nFileTotalSize / 10 : 0);
while( (nLen = read( fd, szBuffer, 4096 )) )
{
for( i = 0; i < nLen; i++ )
{
iCrc32 = calcCRC32( szBuffer[i], iCrc32 );
}
lseek( fd, (int)nFileSkipCount, SEEK_CUR );
}
//_LOG( LDBG, "TOTO Checksum #1 [%d]", iCrc32 );
// 파일 크기 정보를 이용하여 추가로 CRC 계산 처리.
memset( szBuffer, 0x00, sizeof( szBuffer ) );
sprintf( (char *)szBuffer, "%012llu", nFileTotalSize );
nLen = strlen( (char *)szBuffer );
for( i = 0; i < nLen; i++ )
{
iCrc32 = calcCRC32( szBuffer[i], iCrc32 );
//_LOG( LDBG, "TOTO Checksum #2 byte[%c] crc[%d]", szBuffer[i], iCrc32 );
}
//_LOG( LDBG, "TOTO Checksum #3 [%d][%s]", iCrc32, szBuffer );
// 최종 결과에 대한 마지막 변환 계산.
nResultValue = ~iCrc32 & 0xFFFFFFFFL;
//_LOG( LDBG, "TOTO Checksum #4 [%ld]", nResultValue );
// 반환값 처리를 위한 정수를 문자열로 변환 처리.
memset( szBuffer, 0x00, sizeof( szBuffer ) );
sprintf( (char*)szBuffer, "%ld", nResultValue );
szResult.append( (char *)szBuffer );
}
return true;
}
+74
View File
@@ -0,0 +1,74 @@
/***************************************************************************
Totodisk Checksum Class (#27460, #27533)
-----------------------------------------
begin : 2016/05/11
copyright : (C) 2005 SolutionBox Inc.
author : huibong
email : storage.sd@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 __TOTO_CHECKSUM_H__
#define __TOTO_CHECKSUM_H__
#include <unistd.h>
#include <string>
/// @brief CTotoChecksum class
/// 토토디스크 고객사 지원을 위한 클래스로서
/// 해당 고객사에서 제공한 파일의 Checksum 추출 기능 (java 코드) 을
/// 구현하기 위한 클래스임.
///
/// 본 클래스의 코드는
/// 토토디스크에서 제공한 Java 소스를 이용하여 최대한 유사하게 구현하였으며...
/// 비효율적인 코드가 존재하더라고.. 고객사 코드를 최대한 그대로 변환하려 한 것이므로....
/// 함부로 최적화 하면 절대 안된다....(허락 없이 수정시 옥상에서 던져버릴 것임)
///
/// 에러 상황은 GetErrorMessage() 함수를 통해 어떤이유로 에러가 발생했는지
/// 확인 할 수 있다.
///
class CTotoChecksum
{
public :
// 생성자
CTotoChecksum();
// 소멸자
~CTotoChecksum();
/// @brief 토토디스크 고객사 지원용 파일 Checksum 정보 추출 함수
/// @param szFileFullPath [in] 파일의 절대경로 값.
/// @param nFileTotalSize [in] 파일 크기 값.
/// @param szResult [out] Checksum 추출 결과값을 반환하기 위한 변수.
/// @return 성공은 return true, 그 외에는 return false
bool GetChecksum( const std::string &szFileFullPath, const unsigned long long nFileTotalSize, std::string& szResult );
/// @brief 각 함수 호출시 마지막에 난 에러메세지를 얻을 수 있다.
/// @return 마지막에 발생한 에러메세지.
std::string GetErrorMessage( void ) { return m_szErrorMessage; }
private:
// 토토에서 제공한 CRC 연산 함수.
int calcCRC32( unsigned char b, unsigned int iCrc32 );
private :
std::string m_szErrorMessage;
};
#endif //__TOTO_CHECKSUM_H__
+339
View File
@@ -0,0 +1,339 @@
#include "TargetFhsInfo.h"
CTargetFhsInfo::CTargetFhsInfo( std::string szHostName )
: m_szHostName( szHostName )
, m_szIp( szHostName )
, m_bTransferSucess( true )
{
}
CTargetFhsInfo::~CTargetFhsInfo()
{
m_socketControl.Close();
}
/// @brief 대상 FHS로 접속을 시도한다.
bool CTargetFhsInfo::MakeConnection( bool bUseInternalIp, CIPCache * pIpCache )
{
// 내부망을 사용하지 않는 경우
if( bUseInternalIp == false )
{
// m_szIp 저장된 정보를 이용하여 접속 시도처리.
if( m_socketControl.ConnectTarget( m_szHostName, SVC_LISTEN_PORT ) == false )
{
m_bTransferSucess = false;
//m_szErrorMessage = "Can't connect to target FHS [" + m_szHostName + "]";
m_szErrorMessage = "connection fail by hostname";
return false;
}
else
{
m_bTransferSucess = true;
return true;
}
}
// 내부망을 사용하는 경우
// 1. Cache 검색 처리
// 2. Cache 에 존재하지 않는 경우
// - 기존 외부망 정보를 이용하여 접속 시도
// - 내부망 IP 정보 요청 및 Cache 처리
// - 내부망 IP 로 접속 시도
// - 내부망 IP 접속 실패시 다시 외부망으로 연결 처리
// 3. Cache 에 존재하면 해당 정보를 이용하여 접속 시도
// - 내부망 접속 실패시 외부망으로 연결 처리.
std::string szTempIp;
// Cache 에 대상 FHS 정보가 존재하는 경우
if( pIpCache->GetPrivateIP( m_szHostName, szTempIp ) == true )
{
// 접속 시도해서 성공하면 OK
if( m_socketControl.ConnectTarget( szTempIp, SVC_LISTEN_PORT ) == true )
{
// 멤버변수의 m_szIp 정보를 변경 처리
m_szIp = szTempIp;
m_bTransferSucess = true;
return true;
}
}
// 그외의 경우
// - Cache 에 저장된 정보로 접속 시도 실패시
// - Cache 에 저장된 정보가 없는 경우.
// 일단 외부망으로 접속 시도
if( m_socketControl.ConnectTarget( m_szHostName, SVC_LISTEN_PORT ) == false )
{
// 외부망 접속 실패시 => 더이상 방법이 없으므로 실패 처리
m_socketControl.Close();
m_bTransferSucess = false;
//m_szErrorMessage = "Can't connect to target FHS[" + m_szHostName + "]";
m_szErrorMessage = "connection fail by hostname";
return false;
}
// 외부망 접속이 성공한 경우.
// - 내부망 IP 정보 요청 처리.
if( m_socketControl.GetLocalIpInfo( szTempIp ) == false )
{
// 내부망 IP 요청 처리 실패시.
// 현재의 접속된 외부망이 유효한지 확인하여
// 유효한 경우 외부망 접속을 그냥 사용
// 유효하지 않은 경우 에러를 반환.
if( m_socketControl.GetConnectionStatus() == false )
{
m_bTransferSucess = false;
//m_szErrorMessage = "Can't connect to target FHS[" + m_szHostName + "]";
m_szErrorMessage = "connection fail by hostname";
return false;
}
else
{
m_bTransferSucess = true;
return true;
}
}
// 외부망을 통해 내부망 정보 수신을 성공한 경우.
// 내부망 정보로 접속 시도.
m_socketControl.Close();
if( m_socketControl.ConnectTarget( szTempIp, SVC_LISTEN_PORT ) == true )
{
// 내부망 접속이 성공한 경우.
// 해당 정보를 Cache 및 멤버 변수에 설정.
m_szIp = szTempIp;
pIpCache->SetPrivateIP( m_szHostName, szTempIp);
m_bTransferSucess = true;
return true;
}
// 전달받은 내부망 정보로 접속이 실패한 경우
// 다시 외부망으로 접속 시도.
m_socketControl.Close();
if( m_socketControl.ConnectTarget( m_szHostName, SVC_LISTEN_PORT ) == false )
{
// 외부망 접속 실패시 => 더이상 방법이 없으므로 실패 처리
m_socketControl.Close();
m_bTransferSucess = false;
m_szErrorMessage = "connection fail by hostname";
return false;
}
else
{
// 마지막 외부망으로 접속이 성공한 경우.
m_szIp = m_szHostName;
m_bTransferSucess = true;
return true;
}
}
void CTargetFhsInfo::PrintToConnectionInfo()
{
_LOG( LINF, "FHS Target host[%s] IP[%s] Connect[%s]"
, m_szHostName.c_str(), m_szIp.c_str()
, ( m_socketControl.GetConnectionStatus() == true ? "YES" : "NO"));
}
/// @brief 대상 FHS 로 접속이 유효한지 여부를 판단하기 위한 함수.
bool CTargetFhsInfo::IsAvailable()
{
if( m_socketControl.GetConnectionStatus() == true && m_bTransferSucess == true )
return true;
else
return false;
}
/// @brief 대상 FHS 로 파일 전송 시작을 위한 패킷 전송.
bool CTargetFhsInfo::ReadyToFileTransfer( std::string& szFileFullName, unsigned long long nFileSize, std::string& szTargetTranId, char command )
{
// 전송할 준비가 안된 경우.
if( m_bTransferSucess == false )
return false;
// 전달받은 파일 정보에서 현재의 Mount 정보를 제거한다.
// 방식은 뒤에서 / 문자 두개를 찾아서 처리
size_t pos = szFileFullName.rfind( '/' );
pos = szFileFullName.rfind('/', pos-1);
std::string szFileName = szFileFullName.substr( pos+1 );
// 2010-05-07 ADD huibong
// 인자로 전달받은 szTargetTranId 값의 존재 여부를 확인하여
// 해당 값이 존재하는 경우 기존 Tran ID 정보를 전달받은 Tran ID 정보를 변환처리하여 전달한다. ( RC 간 전송처리시 사용)
if( szTargetTranId.size() > 0 )
{
pos = szFileName.rfind( '/' );
std::string szTempFileName = szFileName.substr ( pos+1 );
szFileName = szTargetTranId + "/" + szTempFileName;
}
// Socket Control로 파일 전송에 대한 요청 패킷 전송.
if( m_socketControl.SendFileReceiveRequest( szFileName, nFileSize, command) == false )
{
// 요청 패킷 전달 실패시.
m_bTransferSucess = false;
m_szErrorMessage = "Can't send packet.[file transfer request][" + m_szHostName + "]";
return false;
}
// 요청에 대한 응답 대기.
if( m_socketControl.GetFileReceiveResponse( command, m_bTransferSucess, m_szErrorMessage ) == false )
{
// 응답패킷 수신 실패시
m_bTransferSucess = false;
m_szErrorMessage = "Can't receive packet.[file transfer response][" + m_szHostName + "]";
return false;
}
// 현재 파일 전송이 가능한지 응답 결과를 보고 판단한다.
if( m_bTransferSucess == false )
return false;
// 파일 전송 시작 패킷 전송.
if( m_socketControl.SendFileStartRequest() == false )
{
m_bTransferSucess = false;
m_szErrorMessage = "Can't send packet.[file transfer start packet][" + m_szHostName + "]";
return false;
}
return true;
}
/// @brief 파일 Data 의 전송을 처리하기 위한 함수
bool CTargetFhsInfo::SendBufferToFile(const void * buffer, size_t & size )
{
if( m_bTransferSucess == false )
return false;
// 전달받은 패킷을 해당 socket 으로 전송 처리.
int nWrite = m_socketControl.WriteN( buffer, size );
if( nWrite != (int) size )
{
// 오류 발생시 : WriteN 함수 반환값 0: Socket Closed, -1: 오류 발생시
m_bTransferSucess = false;
m_szErrorMessage = "Can't send packet.[file data send fail.][" + m_szHostName + "]";
LOG( LERR, "File data write fail.[%d/%zu][%s]" , nWrite, size, m_szHostName.c_str());
return false;
}
return true;
}
/// @brief 파일 전송 완료후 전송 결과에 대한 응답패킷을 수신한다.
bool CTargetFhsInfo::GetFileTransferResult()
{
if( m_bTransferSucess == false )
{
LOG( LERR, "[%s] TRANSFER_FILE_END process fail by flag" , m_szHostName.c_str());
return false;
}
// 파일 전송 완료 Packet 전송.
if( m_socketControl.SendFileEndRequest() == false )
{
LOG( LERR, "Cannot send TRANSFER_FILE_END request [%s]", m_szHostName.c_str());
m_bTransferSucess = false;
m_szErrorMessage = "Can't send TRANSFER_FILE_END Request [" + m_szHostName + "]";
return false;
}
// 전송 완료에 대한 응답패킷 수신.
if( m_socketControl.GetFileEndResult( m_bTransferSucess, m_szTransferResultFileName, m_nTransferResultFileSize, m_szErrorMessage) == false )
{
// 응답패킷 수신 실패시
LOG( LERR, "Cannot receive TRANSFER_FILE_END response [%s]", m_szHostName.c_str());
m_bTransferSucess = false;
m_szErrorMessage = "Can't receive TRANSFER_FILE_END response [" + m_szHostName + "]";
return false;
}
if( m_bTransferSucess == false )
{
LOG( LDBG, "[%s] TRANSFER_FILE_END process COMPLETE TO FAIL[%s]", m_szHostName.c_str(), m_szErrorMessage.c_str());
}
else
{
LOG( LDBG, "[%s] TRANSFER_FILE_END process COMPLETE TO SUCCESS[%s]", m_szHostName.c_str(), m_szTransferResultFileName.c_str());
}
return true;
}
/// @brief 파일 Hash 검사를 요청하고 이에 대한 결과를 반환받는다.
bool CTargetFhsInfo::SendFileHashCheckRequest( int nHashLevel, unsigned long long nFileSize, std::string& szSourceHash)
{
if( m_bTransferSucess == false )
{
LOG( LERR, "[%s] TRANSFER_FILE_HASH process fail by flag", m_szHostName.c_str());
return false;
}
// 만약 전달받은 File Name 이 존재하지 않는 경우
if( m_szTransferResultFileName.size() == 0 )
{
LOG( LERR, "[%s] TRANSFER_FILE_HASH fail [target file name not valid]", m_szHostName.c_str());
return false;
}
// Hash 검사 요청 메시지 전송.
if( m_socketControl.SendHashCheckRequest( m_szTransferResultFileName, nFileSize, nHashLevel, szSourceHash ) == false )
{
m_bTransferSucess = false;
m_szErrorMessage = "Can't send packet.[file hash check start packet][" + m_szHostName + "]";
LOG( LERR, "[%s] TRANSFER_FILE_HASH request send fail [%s]", m_szHostName.c_str(), m_szTransferResultFileName.c_str());
return false;
}
else
{
LOG( LDBG, "[%s] TRANSFER_FILE_HASH request send success [%s][%d][%s]", m_szHostName.c_str(), m_szTransferResultFileName.c_str(), nHashLevel, szSourceHash.c_str() );
}
return true;
}
bool CTargetFhsInfo::GetFileHashCheckResult()
{
if( m_bTransferSucess == false )
{
LOG( LERR, "[%s] TRANSFER_FILE_HASH process fail by flag", m_szHostName.c_str());
return false;
}
// Hash 검사 완료에 대한 응답 패킷 수신.
if( m_socketControl.GetHashCheckResult( m_bTransferSucess, m_szErrorMessage) == false )
{
// 응답패킷 수신 실패시
m_bTransferSucess = false;
m_szErrorMessage = "Can't receive TRANSFER_FILE_HASH response [" + m_szHostName + "]";
LOG( LERR, "Cannot receive TRANSFER_FILE_HASH response [%s][%s]", m_szHostName.c_str(), m_szTransferResultFileName.c_str());
return false;
}
return true;
}
bool CTargetFhsInfo::GetResult( std::string& szHostName, std::string& szFileFullName, std::string& szErrorMessage)
{
szHostName = m_szHostName;
szFileFullName = m_szTransferResultFileName;
szErrorMessage = m_szErrorMessage;
return m_bTransferSucess;
}
+80
View File
@@ -0,0 +1,80 @@
/***************************************************************************
ftsd ( File TranSfer Daemon ) Header ( TargetFhsInfo.h )
-----------------------------------------
begin : 2010/03/13
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 __TARGET_FHS_INFO_H__
#define __TARGET_FHS_INFO_H__
#include <string>
#include "Logger.h"
#include "SocketControl.h"
#include "IPCache.h"
class CTargetFhsInfo
{
public:
CTargetFhsInfo( std::string szHostName );
~CTargetFhsInfo();
/// @brief 대상 FHS로 접속을 시도한다.
bool MakeConnection( bool bUseInternalIp, CIPCache * pIpCache );
/// @brief 대상 FHS 로 접속이 유효한지 여부를 판단하기 위한 함수.
bool IsAvailable(void);
/// @brief 대상 FHS 의 접속 정보를 반환.
std::string GetHostName(void) { return m_szHostName; }
/// @brief 오류발생시 마지막 오류 문자열을 반환.
std::string GetErrorMessage(void) { return m_szErrorMessage; }
/// @brief Log 파일 상에 Connection 관련 정보를 표시.
void PrintToConnectionInfo(void);
/// @brief 대상 FHS 로 파일 전송 시작을 위한 패킷 전송.
bool ReadyToFileTransfer( std::string& szFileFullName, unsigned long long nFileSize, std::string& szTargetTranId, char command );
/// @brief 파일 전송 완료후 전송 결과에 대한 응답패킷을 수신한다.
bool GetFileTransferResult(void);
/// @brief 파일 Data 의 전송을 처리하기 위한 함수
bool SendBufferToFile(const void * buffer, size_t& size );
/// @brief 파일 전송 처리에 대한 결과 정보를 반환.
bool GetResult( std::string& szHostName, std::string& szFileFullName, std::string& szErrorMessage);
/// @brief 파일 Hash 검사를 요청한다.
bool SendFileHashCheckRequest( int nHashLevel, unsigned long long nFileSize, std::string& szSourceHash);
/// @brief 파일 Hash 결과 검사에 대한 결과 정보를 수신한다.
bool GetFileHashCheckResult(void);
private:
CSocketControl m_socketControl; // Socket 및 Packet 생성 및 처리를 담당하기 위한 Socket Control Class
std::string m_szHostName; // Target FHS Host Name
std::string m_szIp; // Target FHS 접속 정보 - 내부망을 사용하지 않는 경우 m_szHostName 과 동일
bool m_bTransferSucess;
std::string m_szErrorMessage;
std::string m_szTransferResultFileName;
unsigned long long m_nTransferResultFileSize;
};
#endif /* __TARGET_FHS_INFO_H__ */
+999
View File
@@ -0,0 +1,999 @@
#include "Worker.h"
#include "Logger.h"
#include "TOTOChecksum.h" // NEW 2016-05-11 토토디스크 고객사 checksum 추출 지원 목적.
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#define DEFAULT_ALIVE_CHECK_TIME 5 // sec
// 1. config 정보를 저장하기 위한 전역 객체 => Listener.cpp 에 정의
extern struct st_config g_envConfig;
// 2. Listener Socket
// => 시그널 처리시 문제로 인해 전역함수로 생성. initialize listener.cpp
extern int g_listenSocket;
/// @brief Worker Process 의 main 함수
/// @param listenSocket [in] Listen Socket Descriptor
int WorkerMain( const int listenSocket )
{
// Set Signal Handler
SetSignalWorker();
#if defined(__FreeBSD__)
setproctitle( "Worker [initialize process]");
#endif
// Object initialize
// 1. Local NIC Cache Class 생성 및 초기화.
CLocalIPCache localIpCache( g_envConfig.szInternalNicName);
localIpCache.Start();
// 2. Target 내부 IP Cache Class 생성 및 초기화
CIPCache ipCache;
ipCache.SetTimeout( g_envConfig.nFhsInternalIpCacheTimeout );
// 3. Process Status 생성 및 초기화
CProcessStatus processStatus;
// 4. Replication 처리시 내부 저장위치를 알려줄 Class 초기화.
CProperStorage properStorage( g_envConfig.szStorageRoot, g_envConfig.nProperStorageRefresPeriod );
if( properStorage.Start() == false )
{
_LOG( LWAR, "Worker[%d]: Proper Storage thread create failed. => Process Exit", getpid() );
exit( EXIT_FAILURE ); // EXIT_FAILURE 를 반환하여 재생성 처리 방지...
}
// 접속 요청을 변수 생성 및 초기화.
int clientSocket;
struct sockaddr_in clientSockAddr;
socklen_t clientSockLen = sizeof(clientSockAddr);
// Thread 관련 변수.
pthread_t workerThreadId;
struct WorkerThreadArg * pThreadArg = NULL;
// 접속 요청 대기 및 처리 루프
#if defined(__FreeBSD__)
setproctitle( "Worker [wait for connection]");
#endif
while(1)
{
clientSocket = accept( listenSocket, (struct sockaddr *) &clientSockAddr, &clientSockLen );
if( clientSocket == -1 )
{
// 오류발생시 해당 내역 로깅처리.
int errorNum = errno;
LOG( LERR, "Worker process: client accept failed. [%d][%s]", errorNum, strerror(errorNum) );
}
else
{
// 정상적인 client 인 경우
// 1. 변수 전달을 위한 객체 생성
pThreadArg = ( struct WorkerThreadArg *)malloc( sizeof(struct WorkerThreadArg));
if( pThreadArg == NULL)
{
int errorNum = errno;
close( clientSocket );
// Error Logging
// CHG 2012-02-01 huibong
// inet_ntoa() 함수가 Thread-Safe 하지 않으므로 inet_ntop() 함수로 변경처리
//LOG( LERR, "Worker Thread argument malloc failed.[%s]->[%d][%s]",inet_ntoa(clientSockAddr.sin_addr), errorNum, strerror( errorNum ));
char tempBuffer[INET_ADDRSTRLEN];
memset(tempBuffer, 0x00, sizeof(tempBuffer));
if( inet_ntop( AF_INET, &(clientSockAddr.sin_addr), tempBuffer, sizeof(tempBuffer)) != NULL )
{
LOG( LERR, "[%s] Worker Thread argument malloc failed [%d][%s]", tempBuffer, errorNum, strerror( errorNum ));
}
else
{
LOG( LERR, "Worker Thread argument malloc failed [%d][%s] and inet_ntop error[%d][%s]", errorNum, strerror( errorNum ), errno, strerror(errno) );
}
continue;
}
else
{
// 인자로 전달할 변수정보 세팅.
pThreadArg->clientSocketDesc = clientSocket;
pThreadArg->pLocalIpCache = &localIpCache;
pThreadArg->pIpCache = &ipCache;
pThreadArg->pProcessStatus = &processStatus;
pThreadArg->pProperStorage = &properStorage;
}
// 2. 각 client 요청을 처리할 Thread 생성
if( pthread_create( &workerThreadId, NULL, WorkerThreadProc, (void *)pThreadArg) != 0 )
{
int errorNum = errno;
close( clientSocket );
free( pThreadArg );
// Error Logging
// CHG 2012-02-01 huibong
// inet_ntoa() 함수가 Thread-Safe 하지 않으므로 inet_ntop() 함수로 변경처리
//LOG( LERR, "Worker Thread create failed.[%s]->[%d][%s]",inet_ntoa(clientSockAddr.sin_addr), errorNum, strerror( errorNum ));
char tempBuffer[INET_ADDRSTRLEN];
memset(tempBuffer, 0x00, sizeof(tempBuffer));
if( inet_ntop( AF_INET, &(clientSockAddr.sin_addr), tempBuffer, sizeof(tempBuffer)) != NULL )
{
LOG( LERR, "[%s] Worker Thread create failed [%d][%s]",tempBuffer, errorNum, strerror( errorNum ));
}
else
{
LOG( LERR, "Worker Thread create failed [%d][%s] and inet_ntop error[%d][%s]", errorNum, strerror( errorNum ), errno, strerror(errno) );
}
}
}
} // while( 1 )
// 아래의 코드는 실행되지 않는 코드임.
// Process 종료 처리.
close( listenSocket );
LOG( LWAR, "Worker Process[%d] exit.. Good Bye..", getpid());
CLogger::Exit();
// 잠시 대기 후 종료처리.
// CHG 2015-09-14 huibong
// - #24376 usleep -> nanosleep 으로 변경 처리.
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
// exit( EXIT_SUCCESS );
return EXIT_SUCCESS; // fork 를 수행한 함수에서 exit 함수 호출을 통한 종료처리 (Listener.cpp)
}
void * WorkerThreadProc( void * arg)
{
// 전달받은 인자값을 내부 변수에 저장처리.
int clientSocket = ((struct WorkerThreadArg *) arg)->clientSocketDesc;
// 아래의 정보는 WorkerMain() 에서 생성한 전역관련 정보임.
// 전역정보의 생성 및 해제처리는 WorkerMain() 함수에서 처리된다.
CLocalIPCache * pLocalIpCache = ((struct WorkerThreadArg *) arg)->pLocalIpCache;
CIPCache * pIpCache = ((struct WorkerThreadArg *) arg)->pIpCache;
CProcessStatus * pProcessStatus = ((struct WorkerThreadArg *) arg)->pProcessStatus;
CProperStorage * pProperStorage = ((struct WorkerThreadArg *) arg)->pProperStorage;
free( arg ); // 전달 받은 변수를 저장한 동적 생성 버퍼를 해제한다.
pthread_detach(pthread_self()); // 메인 함수에서 이 스레드가 종료되기를 기다리지 않게 분리
LOG( LDBG, "Worker[%d] client[%d] start", getpid(), clientSocket );
// client 로 부터 전달받은 요청 패킷을 처리할 socket 관련 class 생성
CSocketControl socketControl( clientSocket );
struct timeval timeOver;
int result;
int receive_result;
fd_set selectFds;
FD_ZERO( &selectFds );
// 파일의 송신을 담당하기 위한 FileSender Thread Class 생성
CFileSender fileSender( pIpCache, pProcessStatus, &socketControl);
// Packet Header 정보를 이용한 client 요청 분석
bool bRequest;
bool bFromControl;
char command;
// Socket 요청 대기 - Server 이므로 client 에서 접속 종료전까지 접속 유지 처리.
while(1)
{
timeOver.tv_sec = DEFAULT_ALIVE_CHECK_TIME;
timeOver.tv_usec = 0;
FD_SET( clientSocket, &selectFds );
result = select( clientSocket+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
if( result > 0 )
{
if( FD_ISSET( clientSocket, &selectFds) )
{
// Socket 으로 신호가 들어온 경우 ( Data 수신 또는 접속 종료시)
receive_result = socketControl.GetHeaderInfo( bRequest, bFromControl, command );
if( receive_result == -1 )
{
// Socket이 종료된 경우
// File Sender Thread 가 동작 중이지 않은 경우 그냥 종료 처리.
if( fileSender.IsIdle() == true )
{
LOG( LDBG, "Worker[%d] client[%d] connection closed => Thread exit", getpid(), clientSocket );
break; // 종료 처리.
}
else
{
// Control 과의 접속이 종료된 상황에서 File Sender Thread 가 동작중인 경우.
// fileSender Thread 를 정지시키고 최대 10초간 대기 후 종료처리를 수행한다.
fileSender.Stop();
for( int i=0; i < 10; i++)
{
if( fileSender.IsIdle() == true )
break;
else
sleep(1);
}
LOG( LDBG, "Worker[%d] client[%d] connection closed in file sending. Thread exit", getpid(), clientSocket );
break; // 종료 처리.
}
}
else if( receive_result == 0 )
{
// Read Timeout 발생시 => Server Daemon 이므로 client 접속종료시까지 대기
continue;
}
// 정상적으로 데이터를 수신한 경우.
// 요청 분석.
if( bFromControl == false && bRequest == true )
{
// Transfer Daemon 간 요청인 경우
switch( command )
{
case TRANSFER_LOCAL_IP: // 1. 내부 NIC IP 요청인 경우
LOG( LDBG, "Worker[%d] client[%d] receive TRANSFER_LOCAL_IP", getpid(), clientSocket );
ProcessLocalIpRequest( &socketControl, pLocalIpCache);
break;
case TRANSFER_FILE_REPLICATION: // 2. 파일 Replication 수신 요청인 경우
LOG( LDBG, "Worker[%d] client[%d] receive TRANSFER_FILE_REPLICATION", getpid(), clientSocket );
pProcessStatus->AddReceiveCount();
ProcessFileReceive( &socketControl, pProperStorage, command );
pProcessStatus->SubtractReceiveCount();
break;
case TRANSFER_FILE_CACHE: // 3. 파일 Cache 수신 요청인 경우
LOG( LDBG, "Worker[%d] client[%d] receive TRANSFER_FILE_CACHE", getpid(), clientSocket );
pProcessStatus->AddReceiveCount();
ProcessFileReceive( &socketControl, pProperStorage, command );
pProcessStatus->SubtractReceiveCount();
break;
case TRANSFER_FILE_HASH: // 4. File Hash 검사 요청시.
LOG( LDBG, "Worker[%d] client[%d] receive TRANSFER_FILE_HASH", getpid(), clientSocket );
pProcessStatus->AddReceiveCount();
ProcessFileHashCheck( &socketControl );
pProcessStatus->SubtractReceiveCount();
break;
case COMMON_ALIVE_CHECK: // 5. Alive Check 요청인 경우 무시처리.
LOG( LDBG, "Worker[%d] client[%d] receive COMMON_ALIVE_CHECK", getpid(), clientSocket );
break;
default:
LOG( LERR, "Worker[%d] client[%d] receive [Unknown request from transfer][%02x]", getpid(), clientSocket, command );
socketControl.PrintHeaderToLog();
break;
}
}
else if( bFromControl == true && bRequest == true )
{
// Control Daemon 으로부터 요청인 경우
switch( command )
{
case CONTROL_FILE_REPLICATION: // 1. 파일 Replication 처리 요청
LOG( LDBG, "Worker[%d] client[%d] receive CONTROL_FILE_REPLICATION", getpid(), clientSocket );
ProcessFileSend( fileSender, pProcessStatus, &socketControl, command );
break;
case CONTROL_FILE_CACHE: // 2. 파일 Cache 처리 요청
LOG( LDBG, "Worker[%d] client[%d] receive CONTROL_FILE_CACHE", getpid(), clientSocket );
ProcessFileSend( fileSender, pProcessStatus, &socketControl, command );
break;
case CONTROL_FILE_CHECK: // 3. Content 에 대한 존재 여부 및 Size, Hash 정보 추출 요청
LOG( LDBG, "Worker[%d] client[%d] receive CONTROL_FILE_CHECK", getpid(), clientSocket );
ProcessFileCheck( &socketControl, command );
break;
case CONTROL_FILE_UNLINK: // 4. Content 에 대한 unlink 처리 요청
LOG( LDBG, "Worker[%d] client[%d] receive CONTROL_FILE_UNLINK", getpid(), clientSocket );
ProcessFileUnlink( &socketControl, command );
break;
case COMMON_ALIVE_CHECK: // 5. Alive Check 요청인 경우 무시처리.
LOG( LDBG, "Worker[%d] client[%d] receive COMMON_ALIVE_CHECK", getpid(), clientSocket );
break;
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460)
case CONTROL_FILE_CHECK_TOTO: // 6. 토토디스크 고객사 지원을 위한 MD5 Hash 추출 기능 (2016-05-03 추가)
LOG( LDBG, "Worker[%d] client[%d] receive CONTROL_FILE_CHECK_TOTO", getpid(), clientSocket );
ProcessFileCheckTOTO( &socketControl, command );
break;
// NEW 2021-04-01 huibong content stat(size, atime, mtime, ctime) 정보 추출 기능 추가 (#33516)
case CONTROL_FILE_STAT:
LOG( LDBG, "Worker[%d] client[%d] receive CONTROL_FILE_STAT", getpid(), clientSocket );
ProcessFileStat( &socketControl, command );
break;
default:
LOG( LERR, "Worker[%d] client[%d] receive [Unknown request from control][%02x]", getpid(), clientSocket, command );
socketControl.PrintHeaderToLog();
break;
}
}
else
{
LOG( LERR, "Worker[%d] client[%d] receive error [Not defined packet header]", getpid(), clientSocket );
socketControl.PrintHeaderToLog();
}
}
}
else if( result == 0 ) // Timeout
{
// Alive Check Packet send.
if( socketControl.SendAliveCheck() == false )
{
_LOG( LINF, "Worker[%d] client[%d] alive check failed", getpid(), clientSocket );
break;
}
}
else // select function 오류.
{
int errorNum = errno;
LOG( LERR, "Worker[%d] client[%d] select function error [%d][%s]" , getpid(), clientSocket, errorNum, strerror(errorNum));
break;
}
}
// 종료 처리.
socketControl.Close();
// Logging
LOG( LDBG, "Worker[%d] client[%d] thread end", getpid(), clientSocket );
// Thread 종료 처리.
// CHG 2013-03-19 huibong
// detach 된 Thread 에 대해 pthread_exit() 호출시
// 기준 할당 자원에 대한 해지 처리가 되지 않아 메모리 누수 상황이 발생.
// 따라서 이를 해결하기 detach 된 thread 에 대해 pthread_exit() 호출 코드 제거.
//pthread_exit(NULL);
return NULL;
}
/// @brief Control 로 부터 Transfer 간 파일 전송(Replication, Cache, Move) 요청이 들어온 경우 이를 처리하기 위한 함수.
bool ProcessFileSend( CFileSender& fileSender, CProcessStatus * pProcessStatus, CSocketControl * pSocketControl, char command )
{
// 1. Control 로 부터 Packet Data 부분을 전달받는다.
std::string szSourceFileName;
std::string szTargetTranId; // RC 간 동기화시 Target Tran ID 정보를 저장하기 위한 변수
unsigned long long nSourceFileSize;
int nFileHashCheckLevel;
bool bUseInternalIp;
std::vector< std::string > vecTargetFhs;
std::string szErrorMessage; // 오류 메시지 정보를 임시로 저장하기 위한 변수.
if( pSocketControl->GetFileRequestInfo( szSourceFileName, nSourceFileSize, szTargetTranId
, nFileHashCheckLevel, bUseInternalIp, vecTargetFhs ) == false )
{
// Data 정보 수신 실패시 Control 로 오류 메시지를 전송한다.
pSocketControl->SendErrorMessageToControl( "File Replication/Cache request info get failed.", command );
LOG( LERR, "Worker[%d] File Replication/Cache request info get failed.", getpid() );
return false;
}
// 2. 현재 Process 에서 MAX File Send Thread 값에 제한이 걸리지 않는지 검사.
if( pProcessStatus->GetSendCount() >= g_envConfig.nMaxFileSendThread )
{
// 오류 메시지를 Socket 으로 전달하고 종료처리.
pSocketControl->SendErrorMessageToControl( "Max file send thread count over", command );
LOG( LERR, "Worker[%d] Max file send thread count over.", getpid() );
return false;
}
// 3. 파일 전송을 담당하는 FileSender 가 현재 사용중인지 검사.
if( fileSender.IsIdle() == false )
{
// 오류 메시지를 Socket 으로 전달하고 종료한다.
pSocketControl->SendErrorMessageToControl( "Already file send job stated.", command );
LOG( LERR, "Worker[%d] Already file send job stated.", getpid());
return false;
}
// 4. 요청 정보를 fileSender 에게 설정한다.
if( fileSender.Init( szSourceFileName, nSourceFileSize, szTargetTranId, vecTargetFhs, nFileHashCheckLevel, bUseInternalIp, command, szErrorMessage ) == false )
{
// 오류 메시지를 전송한다.
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d] Request or Source file info not valid.[%s]", getpid(), szErrorMessage.c_str());
return false;
}
// 5. fileSender 에게 작업 시작을 알리고 반환처리한다.
// 나머지 작업은 fileSender 에서 내부적으로 처리해 버린다.
fileSender.Start();
return true;
}
/// @brief Local NIC IP 요청에 대한 처리를 수행한다.
/// @param pSocketControl [in] 요청 Client socket 에 대한 CSocketControl object pointer
/// @param pLocalIpCache [in] Local NIC IP 정보 처리를 위한 CLocalIPCache object pointer
/// @return Local NIC 처리결과 전송 성공시 true, 실패시 false 반환.
bool ProcessLocalIpRequest( CSocketControl * pSocketControl, CLocalIPCache * pLocalIpCache )
{
string szLocalIp;
bool bResult;
// Local NIC IP 정보 확인.
bResult = pLocalIpCache->GetLocalIP( szLocalIp );
if( bResult == false )
{
LOG( LWAR, "Worker[%d]: Local NIC IP get failed.", getpid() );
}
// 해당 NIC 정보 전송
if( pSocketControl->SendLocalIpInfo( bResult, szLocalIp ) == true )
return true;
else
return false;
}
/// @brief Replication 대상 파일의 수신 요청에 대한 처리를 수행한다.
/// @param pSocketControl [in] 요청 Client socket 에 대한 CSocketControl object pointer
/// @param pProperStorage [in] CProperStorage Object Pointer.
/// @param commandCode [in] Replication 또는 Cache 요청인지 여부값 (TRANSFER_FILE_REPLICATION, TRANSFER_FILE_CACHE)
/// @return 파일 수신 및 처리 성공시 true, 오류 발생시 false 반환.
bool ProcessFileReceive( CSocketControl * pSocketControl, CProperStorage * pProperStorage, char commandCode )
{
string szProperStorage;
unsigned long long nMaxAvailableSize;
// 2014-03-04 CHG huibong
// CProperStorage 객체 수정에 따른 처리 코드 변경함.
// - CProperStorage::GetProperPath() 함수는 적합한 저장 경로를 추출하지 못한 경우... 빈값을 반환한다.
// - 하지만 본 함수에서는 socket 을 통해 오류 내역을 전달할 수 없으므로... socket 처리 함수에서 이를 처리토록 한다.
// 1. 전달받은 파일에 대해 저장할 위치를 검색한다.
// - 본 함수의 인자로 전달받은 CProperStorage 객체 포인터는 NULL 이 될 수 없다.
pProperStorage->GetProperPath( szProperStorage, nMaxAvailableSize );
// 2. 만약 Cache 처리요청인 경우
// 위에서 구한 경로 하위 cache 폴더로 저장되도록 저장경로를 수정처리한다.
// 즉 /stg/node1/cache/261/abdeesss 로 처리되도록 한다.
if( commandCode == TRANSFER_FILE_CACHE && szProperStorage.empty() == false )
{
szProperStorage += "/cache";
}
// 3. SocketControl 에서 해당 내역을 처리하도록 전달처리.
if( pSocketControl->ReceiveFile( szProperStorage, nMaxAvailableSize, commandCode ) == false )
return false;
return true;
}
bool ProcessFileHashCheck( CSocketControl * pSocketControl )
{
// ScocketControl 에게 파일 정보 및 Hash Level, Hash 값 정보를 전달받아
// Hash 를 검사하도록 처리한다.
if( pSocketControl->CheckFileHash( ) == false )
{
LOG( LERR, "Worker[%d]: Reciever hash check fail ", getpid());
return false;
}
return true;
}
/// @brief Control 로 부터 Content 에 대한 Check ( Size, Hash ) 요청을 받은 경우 이를 처리하기 위한 함수
/// @param
/// @retrun
bool ProcessFileCheck( CSocketControl * pSocketControl, char command )
{
// 1. Control 로 부터 Packet Data 부분을 전달받는다.
std::string szFileName;
bool bHashCheck;
unsigned long long nHashCheckSize; // MByte 단위값.
std::string szErrorMessage; // 오류 메시지 정보를 임시로 저장하기 위한 변수.
if( pSocketControl->GetRequestCheckFromControl( szFileName, bHashCheck, nHashCheckSize ) == false )
{
// Data 정보 수신 실패시 Control 로 오류 메시지를 전송한다.
pSocketControl->SendErrorMessageToControl( "File Check request info get failed.", command );
LOG( LERR, "Worker[%d] File Check request info get failed.", getpid() );
return false;
}
// 2. 결과값을 저장하기 위한 변수 초기화
unsigned long long nFileSize = 0;
std::string szHashValue;
// 3. 전달받은 파일이 존재하는지 검사.
if( access(szFileName.c_str(), R_OK) == -1 )
{
szErrorMessage = "Check file access fail.[" + szFileName + "]";
// 오류 메시지를 전송한다.
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: %s", getpid(), szErrorMessage.c_str());
return false;
}
// 4. 파일 크기값 추출
FILE * pFile = fopen( szFileName.c_str(), "r+" );
if( pFile == NULL )
{
szErrorMessage = "Check file open fail.[" + szFileName + "]";
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: %s", getpid(), szErrorMessage.c_str());
return false;
}
else
{
fseeko( pFile, 0, SEEK_END );
off_t totalSize = ftello( pFile );
rewind( pFile );
fclose( pFile ); // 열려진 descriptor close
nFileSize = (unsigned long long)totalSize; // 파일 Size 추출 완료
}
// 5. Hash 값 추출인 경우
if( bHashCheck == true )
{
// Hash 처리를 위한 객체를 생성한 후 Hash 검사를 수행
CFileHash fileHash;
if( nHashCheckSize == 0 ) // 전체 Size 에 대한 Hash 추출인 경우...
{
if( fileHash.GetFileHash( szFileName, HASH_LEVEL_FULL, szHashValue) == false )
{
szErrorMessage = "Hash(full) create fail [" + fileHash.GetLastErrorMessage() + "]";
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: %s", getpid(), szErrorMessage.c_str());
return false;
}
}
else
{
// Content 앞부분에 대한 일부 Size 에 Hash 추출인 경우... 추출 Size 설정
fileHash.SetPartitialSize( nHashCheckSize );
if( fileHash.GetFileHash( szFileName, HASH_LEVEL_FRONT_PARTITIAL, szHashValue) == false )
{
szErrorMessage = "Hash(front) create fail [" + fileHash.GetLastErrorMessage() + "]";
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: %s", getpid(), szErrorMessage.c_str());
return false;
}
}
}
// 6. 추출된 정보를 전달한다.
if( pSocketControl->SendCheckResultToControl( command, nFileSize, szHashValue ) == false )
{
// 실패 발생시 로깅 처리.
LOG( LERR, "Worker[%d] File[%s] Check result[%llu] send fail.", getpid(), szFileName.c_str(), nFileSize );
return false;
}
// 7. 처리 내역 로깅
_LOG( LINF, "File[%s] check complete. size[%llu] hash[%s]", szFileName.c_str(), nFileSize, szHashValue.c_str());
return true;
}
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460, #27533)
/// @brief 고객사 토토디스크 지원을 위한 기능
/// Control 로 부터 전달받은 Content 에 대해 Size 정보 및 MD5 Hash, Checksum 정보 등을 추출하여 전달한다.
/// @param
/// @retrun
bool ProcessFileCheckTOTO( CSocketControl * pSocketControl, char command )
{
// 1. Control 로 부터 Packet Data 부분을 전달받는다.
std::string szFileName;
std::string szErrorMessage; // 오류 메시지 정보를 임시로 저장하기 위한 변수.
if( pSocketControl->GetRequestCheckTOTOFromControl( szFileName ) == false )
{
// Data 정보 수신 실패시 Control 로 오류 메시지를 전송한다.
pSocketControl->SendErrorMessageToControl( "File Check request info get failed.", command );
LOG( LERR, "Worker[%d]: [TOTO] File Check request info get failed.", getpid() );
return false;
}
// 2. 결과값을 저장하기 위한 변수 초기화
unsigned long long nFileSize = 0;
std::string szResultTotoMd5;
std::string szResultChecksum;
std::string szResultDnaCheckKey;
// 3. 전달받은 파일이 존재하는지 검사.
if( access( szFileName.c_str(), R_OK ) == -1 )
{
szErrorMessage = "Check file access fail.[" + szFileName + "]";
// 오류 메시지를 전송한다.
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: [TOTO] %s", getpid(), szErrorMessage.c_str() );
return false;
}
// 4. 파일 크기값 추출
FILE * pFile = fopen( szFileName.c_str(), "r+" );
if( pFile == NULL )
{
szErrorMessage = "Check file open fail.[" + szFileName + "]";
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: [TOTO] %s", getpid(), szErrorMessage.c_str() );
return false;
}
else
{
fseeko( pFile, 0, SEEK_END );
off_t totalSize = ftello( pFile );
rewind( pFile );
fclose( pFile ); // 열려진 descriptor close
nFileSize = (unsigned long long)totalSize; // 파일 Size 추출 완료
}
// 5. 토토측 MD5 및 DNA Check key 추출 함수 호출
CFileHash fileHash;
if( fileHash.GetHashTOTO( szFileName, nFileSize, szResultTotoMd5, szResultDnaCheckKey ) == false )
{
szErrorMessage = "MD5 extract fail [" + fileHash.GetLastErrorMessage() + "]";
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: [TOTO] %s", getpid(), szErrorMessage.c_str() );
return false;
}
// 6. 토토측 Checksum 추출 함수 호출.
CTotoChecksum totoChecksum;
if( totoChecksum.GetChecksum( szFileName, nFileSize, szResultChecksum ) == false )
{
szErrorMessage = "Checksum extract fail [" + totoChecksum.GetErrorMessage() + "]";
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: [TOTO] %s", getpid(), szErrorMessage.c_str() );
return false;
}
// 7. 추출된 정보를 전달한다.
if( pSocketControl->SendTOTOCheckResultToControl( command, nFileSize, szResultTotoMd5, szResultChecksum, szResultDnaCheckKey ) == false )
{
// 실패 발생시 로깅 처리.
LOG( LERR, "Worker[%d] [TOTO] File[%s] Check size[%llu] & result send fail.", getpid(), szFileName.c_str(), nFileSize);
return false;
}
// 8. 처리 내역 로깅
_LOG( LINF, "[TOTO] File[%s] check complete. size[%llu] totomd5[%s] checksum[%s] dnakey[%s]"
, szFileName.c_str(), nFileSize, szResultTotoMd5.c_str(), szResultChecksum.c_str(), szResultDnaCheckKey.c_str() );
return true;
}
/// @brief Control 로 부터 Content 에 대한 Unlink 요청을 받은 경우 이를 처리하기 위한 함수
/// @param
/// @retrun
bool ProcessFileUnlink( CSocketControl * pSocketControl, char command )
{
// 1. Control 로 부터 Packet Data 부분을 전달받는다.
std::string szFileName;
unsigned long long nFileSize;
unsigned int nUnlinkMode = 0;
std::string szErrorMessage; // 오류 메시지 정보를 임시로 저장하기 위한 변수.
if( pSocketControl->GetRequestUnlinkFromControl( szFileName, nFileSize, nUnlinkMode ) == false )
{
// Data 정보 수신 실패시 Control 로 오류 메시지를 전송한다.
pSocketControl->SendErrorMessageToControl( "File Unlink request info get failed.", command );
LOG( LERR, "Worker[%d] File Unlink request info get failed.", getpid() );
return false;
}
// 3. 전달받은 파일이 존재하는지 검사.
// - 일반 모드 : 해당 파일이 존재하지 않을 경우 오류로 처리...
// - 강제 모드 : 해당 파일이 존재하지 않을 경우.. 이미 삭제된 것으로 판단하여 정상으로 처리.
if( access(szFileName.c_str(), R_OK) == -1 )
{
if( nUnlinkMode == UNLINK_MODE_FORCE )
{
// 강제 삭제 모드인 경우 해당 파일이 존재하지 않으므로.. 정상으로 처리..
// 로깅은 필히 남길 것.
_LOG( LWAR, "File[%s][[%llu] not found. but unlink result success by unlink force mode", szFileName.c_str(), nFileSize);
// 처리 결과 전달
if( pSocketControl->SendUnlinkResultToControl( command ) == false )
{
// 실패 발생시 로깅 처리.
LOG( LERR, "Worker[%d] file[%s] unlink result send fail.", getpid(), szFileName.c_str() );
return false;
}
return true;
}
else
{
// 강제 삭제 모드가 아닌 경우.. 해당 파일이 존재하지 않으므로 실패로 처리.
szErrorMessage = "unlink file not found.[" + szFileName + "]";
// 오류 메시지를 전송한다.
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: %s", getpid(), szErrorMessage.c_str());
return false;
}
}
// 4. 파일 크기값 추출
FILE * pFile = fopen( szFileName.c_str(), "r+" );
if( pFile == NULL )
{
szErrorMessage = "Unlink file open fail.[" + szFileName + "]";
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: %s", getpid(), szErrorMessage.c_str());
return false;
}
else
{
fseeko( pFile, 0, SEEK_END );
off_t totalSize = ftello( pFile );
rewind( pFile );
fclose( pFile ); // 열려진 descriptor close
if( (unsigned long long)totalSize != nFileSize )
{
// std::string 에 숫자를 append 처리시 오류가 자주 발생하여 C Style 로 변환하여 처리함.
char tempBuffer[1024];
snprintf( tempBuffer, sizeof(tempBuffer)-1
, "unlink file[%s] size not match.[request:%llu, local:%jd]"
, szFileName.c_str(), nFileSize, totalSize );
if( nUnlinkMode == UNLINK_MODE_FORCE )
{
// 강제 삭제 모드인 경우.. 관련 내역을 로깅 처리만 수행
_LOG( LWAR, "%s. but unlink force mode", tempBuffer );
}
else
{
// 일반 모드인 경우 Size 가 서로 다르므로.. 실패로 처리
szErrorMessage = tempBuffer;
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: %s", getpid(), szErrorMessage.c_str());
return false;
}
}
}
// 5. unlink 처리
if( unlink( szFileName.c_str() ) != 0 )
{
int errorNum = errno;
char tempBuffer[1024];
snprintf( tempBuffer, sizeof(tempBuffer)-1
, "Unlink [%s][%llu][%d] system error[%d][%s]"
, szFileName.c_str(), nFileSize, nUnlinkMode, errorNum, strerror(errorNum) );
szErrorMessage = tempBuffer;
pSocketControl->SendErrorMessageToControl( szErrorMessage, command );
LOG( LERR, "Worker[%d]: %s", getpid(), szErrorMessage.c_str());
return false;
}
// 6. 처리 결과를 전달한다.
if( pSocketControl->SendUnlinkResultToControl( command ) == false )
{
// 실패 발생시 로깅 처리.
LOG( LERR, "Worker[%d] File[%s] unlink result send fail.", getpid(), szFileName.c_str() );
return false;
}
// 7. 로깅
if( nUnlinkMode == UNLINK_MODE_FORCE )
{
_LOG( LINF, "File[%s][%llu] unlink complete with force mode.", szFileName.c_str(), nFileSize );
}
else
{
_LOG( LINF, "File[%s][%llu] unlink complete.", szFileName.c_str(), nFileSize );
}
return true;
}
// NEW 2021-04-01 huibong content stat(size, atime, mtime, ctime) 정보 추출 기능 추가 (#33516)
bool ProcessFileStat( CSocketControl * pSocketControl, char command )
{
// 1. Control 로 부터 Packet Data 부분을 전달받는다.
std::string strFileName;
// 오류 메시지 정보를 임시로 저장하기 위한 변수.
std::string strErrorMessage;
if( pSocketControl->GetRequestStatFromControl( strFileName ) == false )
{
// Data 정보 수신 실패시 Control 로 오류 메시지를 전송한다.
pSocketControl->SendErrorMessageToControl( "file stat request receive failed.", command );
LOG( LERR, "Worker[%d] file stat request receive failed.", getpid() );
return false;
}
// 2. 전달받은 파일이 존재하는지 검사.
if( access( strFileName.c_str(), R_OK ) == -1 )
{
int errorNum = errno;
//strErrorMessage = "file access error [" + strFileName + "][" + strerror( errorNum ) + "]";
strErrorMessage = strerror( errorNum );
// 오류 메시지를 전송한다.
pSocketControl->SendErrorMessageToControl( strErrorMessage, command );
LOG( LERR, "Worker[%d]: stat access error [%s][%s]", getpid(), strFileName.c_str(), strErrorMessage.c_str() );
return false;
}
// 3. 요청 파일에 대한 stat 정보를 추출한다.
struct stat stFileStat;
if( stat( strFileName.c_str(), &stFileStat ) != 0 )
{
int errorNum = errno;
//strErrorMessage = "stat function error [" + strFileName + "][" + strerror( errorNum ) + "]";
strErrorMessage = strerror( errorNum );
pSocketControl->SendErrorMessageToControl( strErrorMessage, command );
LOG( LERR, "Worker[%d]: stat function error [%s][%s]", getpid(), strFileName.c_str(), strErrorMessage.c_str());
return false;
}
// 4. 추출된 정보를 전달한다.
if( pSocketControl->SendStatResultToControl( command
, stFileStat.st_size, stFileStat.st_atime, stFileStat.st_mtime, stFileStat.st_ctime ) == false )
{
// 실패 발생시 로깅 처리.
LOG( LERR, "Worker[%d] file[%s] stat result send fail. [ size:%ld access:%ld modify:%ld change:%ld ]"
, getpid(), strFileName.c_str()
, stFileStat.st_size, stFileStat.st_atime, stFileStat.st_mtime, stFileStat.st_ctime );
return false;
}
// 7. 처리 내역 로깅
_LOG( LINF, "file[%s] stat complete.[ size:%ld access:%ld modify:%ld change:%ld ]"
, strFileName.c_str(), stFileStat.st_size, stFileStat.st_atime, stFileStat.st_mtime, stFileStat.st_ctime );
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Worker Process 종료 Signal 을 전달받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigTermWorker( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
LOG( LWAR, "Worker Process[%d] exit job start by user signal [SIGTERM]", getpid() );
}
else
{
LOG( LWAR, "Worker Process[%d] exit job start by abnormal signal [%d]", getpid(), nSignalNumber );
}
// Process 종료관련 작업 추가
close( g_listenSocket );
LOG( LWAR, "Worker Process[%d] exit job end. Good Bye..", getpid());
CLogger::Exit();
// CHG 2015-09-14 huibong
// - #24376 usleep -> nanosleep 으로 변경 처리.
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
exit( EXIT_SUCCESS );
}
/// @brief Worker 프로세스 signal 처리 설정을 위한 함수
/// @return void
void SetSignalWorker( void )
{
sigset_t set;
struct sigaction act;
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
memset( &act, 0x00, sizeof(act) );
sigfillset( &act.sa_mask );
/* 무시할 신호 목록 */
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL); /* 파이프 디스크립터 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP , &act, NULL); /* Process를 기동시킨 관리자의 로그아웃시 발생 시그널 */
sigaction( SIGINT , &act, NULL); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
//act.sa_handler = SigChldWorker;
sigaction( SIGCHLD, &act, NULL);
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SigTermWorker;
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
/* Core 관련 signal 처리 : 오류 처리 및 Debug(core dump) 목적 */
// CHG 2012-05-21 huibong
// Worker 프로세스의 문제 발생시 문제점 해결을 위한 core 파일 분석을 위해.. signal handler 를 기본으로 변경 처리함.
act.sa_handler = SIG_DFL;
sigaction( SIGILL , &act, NULL); /* Illegal instruction */
sigaction( SIGFPE , &act, NULL); /* Erroneout arithmetic operation */
sigaction( SIGBUS , &act, NULL); /* Access to undefined portion of a memory object */
sigaction( SIGSEGV, &act, NULL); /* Invalid memory reference */
sigaction( SIGSYS , &act, NULL); /* Bad System Call */
sigaction( SIGXCPU, &act, NULL); /* CPU-time limit exceeded */
sigaction( SIGXFSZ, &act, NULL); /* File-size limit exceeded */
sigemptyset(&set); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask(SIG_SETMASK, &set, NULL);
}
+112
View File
@@ -0,0 +1,112 @@
/***************************************************************************
ftsd ( File TranSfer Daemon ) Header ( Worker.h )
-----------------------------------------
begin : 2010/03/04
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 __WORKER_H__
#define __WORKER_H__
#include "../define_ftsd.h"
#include "LocalIPCache.h"
#include "IPCache.h"
#include "ProcessStatus.h"
#include "ProperStorage.h"
#include "SocketControl.h"
#include "FileSender.h"
#ifdef __cplusplus
extern "C" {
#endif
// 이거는 malloc 을 사용해야 하므로 C++ 스타일의 구조체를 만들지 않는다.
struct WorkerThreadArg {
int clientSocketDesc; // Client Socket Descriptor
CLocalIPCache * pLocalIpCache; // Local NIC IP Cache Calss pointer
CIPCache * pIpCache; // 내부망 IP 정보 Cache Class pointer
CProcessStatus * pProcessStatus; // Process 상태 정보 Class pointer
CProperStorage * pProperStorage; // 내부 저장 stroage 정보 Class pointer
};
/// @brief Worker Process 의 main 함수
/// @param listenSocket [in] Listen Socket Descriptor
/// @return
int WorkerMain( const int listenSocket );
/// @brief 각 요청을 처리하기 위함 Thread 함수.
/// @param arg [in] struct WorkerThreadArg 에 대한 포인터.
/// @return
void * WorkerThreadProc( void * arg );
/// @brief Local NIC IP 요청에 대한 처리를 수행한다.
/// @param pSocketControl [in] 요청 Client socket 에 대한 CSocketControl object pointer
/// @param pLocalIpCache [in] Local NIC IP 정보 처리를 위한 CLocalIPCache object pointer
/// @return Local NIC 처리결과 전송 성공시 true, 실패시 false 반환.
bool ProcessLocalIpRequest( CSocketControl * pSocketControl, CLocalIPCache * pLocalIpCache );
/// @brief Replication 대상 파일의 수신 요청에 대한 처리를 수행한다.
/// @param pSocketControl [in] 요청 Client socket 에 대한 CSocketControl object pointer
/// @param pProperStorage [in] CProperStorage Object Pointer. 해당값이 NULL 인 경우 Cache, NULL 인 아닌 경우 Replication 처리
/// @return 파일 수신 및 처리 성공시 true, 오류 발생시 false 반환.
bool ProcessFileReceive( CSocketControl * pSocketControl, CProperStorage * pProperStorage, char commandCode );
bool ProcessFileHashCheck( CSocketControl * pSocketControl );
/// @brief 파일 전송 관련 작업을 수행한다.
bool ProcessFileSend( CFileSender& fileSender, CProcessStatus * pProcessStatus
, CSocketControl * pSocketControl, char command );
/// @brief Control 로 부터 Content 에 대한 Check ( Size, Hash ) 요청을 받은 경우 이를 처리하기 위한 함수
bool ProcessFileCheck( CSocketControl * pSocketControl, char command );
/// @brief Control 로 부터 Content 에 대한 Unlink 요청을 받은 경우 이를 처리하기 위한 함수
bool ProcessFileUnlink( CSocketControl * pSocketControl, char command );
// NEW 2016-05-04 huibong 토토디스크 지원용 기능 추가 (#27460, #27533)
/// @brief 고객사 토토디스크 지원을 위한 기능
/// Control 로 부터 전달받은 Content 에 대해 Size 정보 및 MD5 Hash, Checksum 정보 등을 추출하여 전달한다.
/// @param
/// @retrun
bool ProcessFileCheckTOTO( CSocketControl * pSocketControl, char command );
// NEW 2021-04-01 huibong content stat(size, atime, mtime, ctime) 정보 추출 기능 추가 (#33516)
/// @brief Control 로 부터 Content 에 대한 stat ( size, atime, mtime, ctime ) 요청을 받은 경우 이를 처리하기 위한 함수
bool ProcessFileStat( CSocketControl * pSocketControl, char command );
/// @brief Worker 프로세스 signal 처리 설정을 위한 함수
/// @return void
void SetSignalWorker( void );
/* Signal 처리를 위한 각 Signal Handler 함수는
* 다른 Code 에서 Include 처리시 Static 관련 문제로 인해
* 본 Header 에서 선언처리 하지 않음. cpp 에만 존재
*/
#ifdef __cplusplus
}
#endif
#endif /* __WORKER_H__ */