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