This commit is contained in:
biosvos
2026-08-07 17:38:18 +09:00
commit 873193a243
9613 changed files with 2755992 additions and 0 deletions
+325
View File
@@ -0,0 +1,325 @@
Revision 1507
-------------------
수정일 : 2020-10-05
수정자 : 유희곤
- CHG: FreeBSD 12.x 컴파일시 발생하는 warning 코드 수정 (#33225)
- FreeBSD 12.x 의 gcc 9.3 컴파일시 sprintf 사용 관련 buffer size 문제로 warning 발생
- flow 상으로는 buffer overflow 발생 가능성 없지만.. 컴파일시마다 warning 발생하여 수정 처리
- 수정파일: ArecaWrapper.cpp
Revision 1489
-------------------
수정일 : 2020-01-10
수정자 : 유희곤
- BUG: 불필요 "Battery Module Failed" event 미전송 관련 버그 수정 (#32911)
- 실제로 Module 단어와 Failed 단어 사이에 공백이 3개 존재
- 이로 인해 해당 event 가 계속 전송되는 상황 발견됨
- 이에 Battery Module" check 후 Failed 문자열 check 하도록 수정
- 수정파일: Child.cpp
Revision 1472
-------------------
수정일 : 2019-09-16
수정자 : 유희곤
- CHG: HTTP 관련 줄바꿈문자 LF->CR+LF 변경 (#32794)
- CVE-2016-8743 이슈에 따라 Apache 2.2.32 버전부터 HTTP header 상에서
- 줄바꿈문자가 CR+LF 가 아닌 경우 HTTP 400 응답 발생
- 특히 최신 GMS 와 연동시 Apache 최신 버전 설치로 이와 같은 문제 발생 가능
- 이를 해결하기 위해 기존 줄바꿈 문자 \n -> \r\n 으로 변경처리
- 수정파일: SmsSender.cpp
- CHG: version info 변경
- version 3.4.0 => 3.5.0
- NEW: 불필요 "Battery Module Failed" evnet 는 운영자에게 전송하지 않도록 수정 (#32795)
- 운영자 요청으로 RAID event 중 "Battery Module Failed" event 는
- 운영자에게 notify 되지 않도록 수정
- 수정파일: Child.cpp
Revision 1336
-------------------
수정일 : 2016-1-22
수정자 : 노경민
- BUG: 초기화 실패 및 수집된 모든 이벤트 전송 불가
- 내부적으로 사용하고 있는 자료 구조에 접근 문제
- 메세지 생성 버퍼에 대한 overflow
Revision 1317
-------------------
수정일 : 2015-12-29
수정자 : 노경민
- BUG: 비정상 종료 현상
- 이벤트 SMS 장비로 전송 중 비정상 종료 현상 발생
- list에 대한 컨트롤 로직에서 잘못된 포인트 참조 발생
- BUG: 실행 불가능
- FreeBSD 6.2 장비에 동작하지 않는 버그
- 현재 적용된 Araca library 문제
- Revision 0970 적용 처리
- FreeBSD 10.x 정동 동작 확인 (version 1.20.00.28 2013-09-13 까지 정상 동작 확인)
- BUG: 이벤트 타임 오류
- Araca library에서 리턴되는 타임을 time_t로 변경 중 오류 발생
- BUG: 발생된 메일에 이벤트 로그 미출력
- GMS 장비에 UDP receive size 문제
- send size 1400 byte 변경함
- CHG: 추가 수정
- 로그 객체 변경
- 코어 덤프 설정 로직 삭제
- 소켓 객체 변경
Revision 1210
-------------------
수정일 : 2015-06-26
수정자 : 김오종
- BUG: 일부 장비에서 areca event를 정상적으로 가져오지 못하는 현상 수정 필요
- event lelvel 별로 event 수집의도로 작성된 코드가 의미 없어서 제거처리 함(ArecaWrapper.cpp)
Revision 1097
-------------------
수정일 : 2014-10-28
수정자 : 김오종
- CHG: raid card의 이벤트 중 메세지가 정의 되지 않은 이벤트 발생시 데몬이 죽는 현상 발생
- 이벤트 메세지 정의가 되어 있지 않은 경우에 대한 처리 추가(ArecaWrapper.cpp)
Revision 1095
-------------------
수정일 : 2014-10-22
수정자 : 유희곤
- CHG: GMS 에서 사용하는 arcmond_client 관련 수정
- httpd error_log 상에 불필요한 로그 발생 코드 수정 ( Client.cpp)
- gmake client
- GMS 에서만 필요한 binary 로서 실제 arcmond 와는 연관 없음.
- 따라서 binary tagging 등의 작업은 수행 안함.
Revision 1093
-------------------
수정일 : 2014-10-17
수정자 : 김오종
- CHG: version info 변경
- version 3.3.0 => 3.4.0
Revision 1092
-------------------
수정일 : 2014-10-17
수정자 : 김오종
- CHG: external library 현행화
- http://www.areca.com.tw/support/main.htm
- http://www.areca.us/support/download/API/20130320-342.zip
Revision 0970
-------------------
수정일 : 2014-03-27
수정자 : 신순영
- CHG: Makefile 파일 수정
- FreeBSD 버전 상관없이 무조건 환경설정을 util.conf 를 로딩하도록 수정
Revision 0967
-------------------
수정일 : 2014-03-17
수정자 : 신순영
- CHG: Makefile 파일 수정
- FreeBSD 10.x 에서 환경설정을 util.conf 를 로딩하도록 처리
- CHG: 기타
- GCC 버전업에 따른 warning 발생 관련 Makefile 상에서 -Wimplicit 옵션 제거
- 기존 3.1.0 -> 3.3.0 으로 버전 변경 처리
Revision 0901
-------------------
수정일 : 2013-10-18
수정자 : 김오종
- CHG: gms web에서 전체 message를 수신할수 없는 상태인것을 확인했으나 gsm web 수정보다는 최근 100건만 보내는 것으로 해결 함.
- UdpListener.cpp 의 CUdpListener::Execute() 함수 내에서 수정
Revision 0674
-------------------
수정일 : 2012-02-09
수정자 : 신순영
- BUG: lib/Logger.cpp 파일 수정
- gcc 4.4.5 버전에서 발생하는 parameter type에 따른 문제 수정
- CHG: Makefile 상의 버전정보 관리 방법 변경
- 목표 버전 변경으로 인한 ver 3.1.0 으로 변경
Revision 0673
-------------------
수정일 : 2012-02-09
수정자 : 신순영
- BUG: lib/Config.h 파일 수정
- gcc 4.4.5 버전에서 발생하는 parameter type에 따른 문제 수정
- CHG:
1. 컴파일시 불필요한 warning 제거
Revision 0585
-------------------
수정일 : 2011-07-27
수정자 : 장희준
- CHG: Make 파일 수정
- AutoDisableUpload.o 추가
Revision 0584
-------------------
수정일 : 2011-07-27
수정자 : 장희준
- ADD: 자동 업로드 방지 기능 추가
- AutoDisableUpload.h AutoDisableUpload.cpp 파일 추가
- Child.cpp 파일의 ChildMain()에서 자동 업로드 방지 기능 호출
- 자동 업로드 방지 이벤트 대상은 아래와 같음.
- Volume Degraded, RaidSet Degraded, Rebuild RaidSet, Device Failed, Start Rebuilding
Revision 0529
-------------------
수정일 : 2011-05-03
수정자 : 유희곤
- BUG: lib/BaseSocket.cpp ConversionAddr() 함수 수정
- ConversionAddr() 함수에서 gethostbyname() 함수 사용으로 인한 Thread-Safe 문제 발생
- Multi Thread App에서 요청한 장비와 다른 장비로 접속하는 문제가 발견되었으며
- 이로인해 Contents 전송, 관리 부분에서 문제가 발생할 수 있어 수정 처리함.
- 본 문제는 Thread Safe 한 getaddrinfo() 함수 사용으로 변경 처리함.
Revision 443
-------------------
수정일 : 2010-12-03
수정자 : 장희준
arcmond2 revision 정보 중복으로 다시 commit.
Revision 440
-------------------
수정일 : 2010-12-03
수정자 : 장희준
- CHG: Makefile 수정
- gmake install 시에 Makefile에 install 경로가 없어서 install 경로 설정
- arcmond.conf을 사용하지 않는데 arcmond.conf을 install 하고 있어서 설정
파일 install 삭제
Revision 0399
-------------------
수정일 : 2010-11-17
수정자 : 김오종
- BUG: 메모리 leak 발생 가능 함수 수정.
- CArecaWrapper::GetEvent() 함수와 CArecaWrapper::DiscoveryDevice()함수 수정.
- Logging 메세지 철자 수정.
- CHG: Makefile 상의 버전정보 관리 방법 변경
- 목표 버전 변경으로 인한 ver 3.0.1 로 변경
Revision 0322
-------------------
수정일 : 2010-08-02
수정자 : 김오종
- BUG: CBaseSocket::Read() 함수상의 문법관련 버그 수정
- 156 Line상의 잘못된 대입 연산자를 비교연산자로 수정처리.
Revision 0307
-------------------
수정일 : 2010-07-12
수정자 : 김오종
- CHG:
1. Revision 306 커밋 이슈와 관련된 부분에서 REPEAT_ALLOW_TIME 60을 제거.
- 불필요한 DEBUG 옵션에서 반복된 메세지처리 시간을 제거처리 함.
Revision 0306
-------------------
수정일 : 2010-07-12
수정자 : 김오종
- CHG:
1. makefile내용 변경.
- 기본 DEBUG로 커밋되어 있어 실수 유발가능성이 있다.
Revision 0301
-------------------
수정일 : 2010-07-08
수정자 : 김오종
- BUG:
1. arcmond_client 요청에 대한 udp response에서 마지막 한 byte가 누락 되는 버그 수정.
Revision 0294
-------------------
수정일 : 2010-07-05
수정자 : 김오종
- BUG:
1.NO EVENT 송신 시에 첫 번째 필드가 '0'으로 보내져야 정상상황에서 이벤트가 없는 것으로 판단됨.
최종적으로 php소스에서 '0'이 오면 정상으로 처리 중인 것을 확인.
- 첫 번째 필드를 '1'=>'0' 으로 변경.
2.UDP 송신함수인CUdpListener::SendMsg()함수 버그 발견.
- 해당 함수 호출시 두 번째 인자는 메세지의 길이를 입력해야함에도 불구하고, szSendBuffer사이의 기본크기를 인자로사용 함.
=> 두 번째 인자를 strlen(szSendBuffer) 로 변경 함.
- 해당 함수내에 전송요청한 바이트만큼 확인하는 코드에서 do~ while문의 조건을 (nWrite >= 0) 으로 사용하여 마지막에 한 byte가 더 전송됨을 확인 함.
=> (nWrite >= 0) 를 (nWrite > 0)로 변경 함.
Revision 0293
-------------------
수정일 : 2010-07-02
수정자 : 김오종
- BUG: - conf 파일의 디폴트 값을 가져오는 부분에서 clear()하지 않아 영향이 있었음.
Revision 0288
-------------------
수정일 : 2010-07-02
수정자 : 김오종
- NEW: SVN 신규 등록
- 필요파일 누락으로 추가 함.
-> libarclib32.a, libarclib64.a
Revision 0287
-------------------
수정일 : 2010-07-02
수정자 : 김오종
- NEW: SVN 신규 등록
- 기존 svn://211.38.137.33/work/trunk/raidmond 에 존재하는 개발 완료 소스 (Rev 987)를 SVN 에 정식버전으로 등록함.
- 본 버전은 개발 및 성능 테스트를 완료한 버전으로 areca raid card의 상태를 모니터링하는 기능을 함.
- 단 현재 버전은 FreeBSD 5.4, 6.2 버전상에서만 테스트되었으며 다른 OS 로 포팅 처리시 코드를 재확인해야 함.
- NEW: History 저장을 위한 Changelog.txt 파일 추가
- 앞으로 각 작업에 대한 로그를 확인하도록 Changelog.txt 파일을 추가
+37
View File
@@ -0,0 +1,37 @@
#****************************************************************************
# Makefile for ftsd ( FHS RAID Monitor Daemon)
# -----------------------------------------
#
# begin : 2010/05/18
# copyright : (C) 2005 SolutionBox Inc.
# author : Service 1 Team
# email : svc1@solbox.com
# version : 3.0.0
#
# CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
# Redistribution and use in source and binary forms, with or with out
# modification, are not permitted in outside of SolutionBox Inc.
#*****************************************************************************
SUBDIRS = lib src
.PHONY: all $(SUBDIRS)
all: $(SUBDIRS)
sync;
$(SUBDIRS):
$(MAKE) all -C $@
install:
@for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) install); done
clean:
@for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) clean); done
# End of Makefile
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
+304
View File
@@ -0,0 +1,304 @@
#ifndef _ARCLIBS_H
#define _ARCLIBS_H
/********************************************************/
/*
/* Data Structures & Function prototypes for S.M.A.R.T
/*
/********************************************************/
#include "arclib.h"
#ifdef __cplusplus
extern "C" {
#endif
#pragma pack(1)
#define MAX_DATA_LENGTH 512
#define SHORT_SELF_TEST 1
#define EXTENDED_SELF_TEST 2
/*
Attribute ID Numbers
Any non-zero value in the Attribute ID Number indicates an active attribute. The device supports the
following Attribute ID Numbers.
ID Attribute Name
=============================================
199 Ultra DMA CRC Error Count
198 Off-line Scan Uncorrectable Sector Count
197 Current Pending Sector Count
196 Reallocation Event Count
194 Temperature
193 Load Cycle Count
192 Power-off Retract Count
12 Device Power Cycle Count
10 Spin Retry Count
9 Power-on Hours Count
8 Seek Time Performance
7 Seek Error Rate
5 Reallocated Sector Count
4 Start/Stop Count
3 Spin Up Time
2 Throughput Performance
1 Raw Read Error Rate
0 Indicates that this entry in the data structure is not used
Status Flag definitions
Bit Definition
0 Pre-failure/advisory bit
0 An attribute value less than or equal to its corresponding attribute threshold indicates an
advisory condition where the usage or age of the device has exceeded its intended
design life period.
1 An attribute value less than or equal to its corresponding attribute threshold indicates a
pre-Failure condition where imminent loss of data is being predicted.
1 On-line Collective bit
0 The attribute value is updated only during Off-line testing.
1 The attribute value is updated during On-line testing or during both On-line and Off-line
testing.
2 - 5 Vendor specific
6 - 15 Reserved (0)
*/
/*
The following defines the 12 bytes that make up the information for each Attribute entry in the Device
Attribute Data Structure.
*/
typedef struct _DEVICE_ATTR_DATA // Individual Attribute Data Structure
{
BYTE id; // 0x00, Attribute ID Number (01h to FFh)
BYTE status[2]; // 0x01, Status flags
BYTE value; // 0x03, Attribute Value (valid values from 01h to FDh)
BYTE vendor_spec[8]; // 0x04, Vendor Specific
}sDEVICE_ATTR_DATA, *pDEVICE_ATTR_DATA; // total 12 bytes
/*
The following defines the 512 bytes that make up the Attribute Value information. This data structure is
accessed by the host in its entirety using the SMART Read Attribute Values subcommand. All multibyte
fields shown in these data structures are in byte ordering, that is, the least significant byte occupies the
lowest numbered byte address location in the field.
*/
typedef struct _SMART_ATTR_DATA // Device Attributes Data Structure
{
BYTE rev_num[2]; // 0x00 Data Structure Revision Number
sDEVICE_ATTR_DATA device_attr_data[30]; // 0x02 Device Attribute, from 1st~30th
BYTE dc_status; // 0x16A, Off¡Vline data collection status
BYTE st_status; // 0x16B, Self¡Vtest execution status
BYTE total_time_for_dc[2]; // 0x16C, Total time in seconds to complete off¡Vline data collection activity
BYTE vendor_spec1; // 0x16E, Vendor specific
BYTE dc_capability; // 0x16F, Off¡Vline data collection capability
BYTE smart_cap[2]; // 0x170, SMART capability
BYTE smart_error_log_cap; // 0x172, SMART device error logging capability
BYTE st_failure_check_point; // 0x173, Self¡Vtest failure check point
BYTE short_st_completion_time; // 0x174, Short self¡Vtest completion time in minutes
BYTE extended_st_completion_time; // 0x175, Extended self¡Vtest completion time in minutes
BYTE reserved[12]; // 0x176, Reserved
BYTE vendor_spec2[125]; // 0x182, Vendor specific
BYTE checksum; // 0x1FF, Data structure checksum
}sSMART_ATTR_DATA, *pSMART_ATTR_DATA; // total 512 bytes
/*
The following defines the 12 bytes that make up the information for each Threshold entry in the Device
Attribute Thresholds Data Structure. Attribute entries in the Individual Threshold Data Structure is in the
same order and correspond to the entries in the Individual Attribute Data Structure.
*/
typedef struct _DEVICE_ATTR_THRE_DATA // Individual Thresholds Data Structure
{
BYTE id; // 0x00, Attribute ID Number (01h to FFh)
BYTE threshold; // 0x01, Attribute Threshold
BYTE reserved[10]; // 0x02, Reserved (00h)
}sDEVICE_ATTR_THRE_DATA, *pDEVICE_ATTR_THRE_DATA; // total 12 bytes
/*
The following defines the 512 bytes that make up the Attribute Threshold information. This data structure
is accessed by the host in its entirety using the SMART Read Attribute Thresholds. All multibyte fields
shown in these data structures are in byte ordering, that is, the least significant byte occupies the lowest
numbered byte address location in the field.
The sequence of active Attribute Thresholds will appear in the same order as their corresponding
Attribute Values.
*/
typedef struct _SMART_ATTR_THRE_DATA // Device Attribute Thresholds Data Structure
{
BYTE rev_num[2]; // 0x00, Data Structure Revision Number
sDEVICE_ATTR_THRE_DATA device_attr_data[30]; // 0x02, Device Attribute, from 1st~30th
BYTE reserved[18]; // 0x16A, Reserved
BYTE vendor_spec[131]; // 0x17C, Vendor specific
BYTE checksum; // 0x1FF, Data structure checksum
}sSMART_ATTR_THRE_DATA, *pSMART_ATTR_THRE_THRE_DATA; // total 512 bytes
/*
Command data structure
Data format of each command data structure is shown below.
*/
typedef struct _COMMAND_DATA
{
BYTE dev_control_reg; // 0x00, Device Control register
BYTE features_reg; // 0x01, Features register
BYTE sector_count_reg; // 0x02, Sector count register
BYTE sector_number_reg; // 0x03, Sector number register
BYTE cylinder_low_reg; // 0x04, Cylinder Low register
BYTE cylinder_high_reg; // 0x05, Cylinder High register
BYTE head_reg; // 0x06, Device/Head register
BYTE command_reg; // 0x07, Command register
BYTE time_stamp[4]; // 0x08, Timestamp(ms from Power On)
}sCOMMAND_DATA, *pCOMMAND_DATA; // total 12 bytes
/*
Error data structure:
Data format of error data structure is shown below.
The state field contains a value indicating the device state when the command was issued to the device.
xBh-xFh Vendor specific
x5h-xAh Reserved
x4h SMART Off-line or Self-test
x3h Active/Idle
x2h Standby
x1h Sleep
x0h Unknown
Value
*/
typedef struct _ERROR_DATA
{
BYTE reserved; // 0x00, Reserved
BYTE error_reg; // 0x01, Error register
BYTE sector_count_reg; // 0x02, Sector count register
BYTE sector_number_reg; // 0x03, Sector number register
BYTE cylinder_low_reg; // 0x04, Cylinder Low register
BYTE cylinder_high_reg; // 0x05, Cylinder High register
BYTE head_reg; // 0x06, Device/Head register
BYTE status_reg; // 0x07, Status register
BYTE extended_error_data[19]; //0x08, Extended error data (vendor specific)
BYTE state; // 0x1B, State
BYTE life_timestamp[2]; // 0x1C Life timestamp (hours)
}sERROR_DATA, *pERROR_DATA; // total 30 bytes
/*
Error log data structure
Data format of error data structure is shown below.
*/
typedef struct _ERROR_LOG_DATA
{
sCOMMAND_DATA command_data[5]; // 0x00, Command data structure, from 1~5
sERROR_DATA error_data; // 0x3C, Error data structure
}sERROR_LOG_DATA, *pERROR_LOG_DATA; // total 90 bytes
/*
The following figure defines the 512 bytes that make up the SMART error log sector. All multibyte fields
shown in these data structures are in byte ordering.
*/
typedef struct _SMART_ERROR_LOG_SECTOR
{
BYTE version; // 0x00, SMART error log version
BYTE pointer; // 0x01, Error log pointer
sERROR_LOG_DATA log_data[5]; // 0x02, 1st~5th error log data structure
BYTE device_error_count[2]; // 0x1C4, Device error count
BYTE reserved[57]; // 0x1C6, Reserved
BYTE checksum; // 0x1FF, Data structure checksum
}sSMART_ERROR_LOG_SECTOR, *pSMART_ERROR_LOG_SECTOR; // total 512 bytes
/*
The data structure contains the descriptor of Self-test that the device has performed. Each descriptor is
24 bytes long and the self-test data structure is capable of containing up to 21 descriptors.
After 21 descriptors have been recorded, the oldest descriptor will be overwritten with a new descriptor.
The self-test log pointer points to the most recent descriptor. When there is no descriptor, the value is 0.
When there is descriptor(s) the value is 1 through 21.
*/
typedef struct _SELF_TEST_LOG_DESCRIPTOR
{
BYTE number; // 0x00, Self-test number
BYTE exe_status; // 0x01, Self-test execution status
BYTE life_time[2]; // 0x02, Life time power on hours
BYTE st_failure_check_point; // 0x04, Self-test failure check point
BYTE lba_of_first_failure[4];// 0x05, LBA of first failure
BYTE vendor_spec[15]; // 0x06, Vendor specific
}sSELF_TEST_LOG_DESCRIPTOR, *pSELF_TEST_LOG_DESCRIPTOR; // total 24 bytes
/*
Self-test log data structure
The following figure defines the 512 bytes that make up the Self-test log sector. All multibyte fields shown
in these data structures are in byte ordering.
*/
typedef struct _SELF_TEST_LOG_DATA
{
BYTE reversion[2]; // 0x00, Data structure revision
sSELF_TEST_LOG_DESCRIPTOR descriptor[21]; // 0x02, descriptors
BYTE vendor_spec[2]; // 0x1FA, Vendor specific
BYTE pointer; // 0x1FC, Self-test log pointer
BYTE reserved[2]; // 0x1FD, Reserved
BYTE checksum; // 0x1FF, Data structure checksum
}sSELF_TEST_LOG_DATA, *pSELF_TEST_LOG_DATA; // total 512 bytes
#ifdef _WIN32
class ARCLIB_API CArclibSMART : public CArclib
{
#else
class CArclibSMART : public CArclib
{
#endif
public:
// (O): Implemented
// (X): Not Implemented
enum
{
R_SMART_DATA = 0, // (O)Read smart data
R_THLD_DATA, // (O)Read threshold data
ED_AUTOSAVE, // (X)Enable/disable autosave
S_ATTR, // (X)Save attribute
EXE_OFFLINE, // (O)Execute offline
R_LOG, // (X)Read log
W_LOG, // (X)Write log
RESERVED1,
E_SMART, // (O)Enable SMART
D_SMART, // (O)Disable SMART
RET_SMART_STATUS, // (X)Return SMART status
ED_AUTO_OFFLINE, // (X)Enable/Disable automatic offline
RESERVED2,
RESERVED3,
RESERVED4,
RESERVED5,
RW_TEST, // (O)Read/Write test
STOP_RW_TEST, // (O)Stop Read/Write test
CHECK_RW_RESULT, // (O)Check Read/Write Result
RESERVED6
};
//################################################################################################
// Function: ArcExeSMART
// Parameters: (i) cmd: the commands listed above
// (i) drv: drive# where the SMART command is being executed
// (i) params: The options for EXE_OFFLINE, RW_TEST only.
// for EXE_OFFLINE: value SHORT_SELF_TEST indicates short self-test
// value EXTENDED_SELF_TEST indicates extended self-test
// for RW_TEST: percentage of RW_TEST
// (o) data: The option for R_SMART_DATA, R_THLD_DATA, CHECK_RW_RESULT only.
// the SMART data returned from the drive that indicates by drv,
// the memory allocation of 'data' is the responsibility of the
// calling thread, and it's size should be >= 512 bytes
//################################################################################################
ARC_STATUS ArcExeSMART(int cmd, BYTE drv, BYTE params, PBYTE data);
};
#pragma pack()
#ifdef __cplusplus
}
#endif
#endif
+170
View File
@@ -0,0 +1,170 @@
#ifndef _COMMDEF_H_
#define _COMMDEF_H_
#if !defined(__solaris__) && defined(__sun__)
#define __solaris__
#endif
#ifdef _WIN32
#ifdef ARCLIB_EXPORTS
#define ARCLIB_API
#else
#define ARCLIB_API
#endif
#ifndef NULL
#define NULL 0
#endif
#ifndef int8_t
typedef signed char int8_t;
#endif
#ifndef u_int8_t
typedef unsigned char u_int8_t;
#endif
#ifndef int16_t
typedef signed short int16_t;
#endif
#ifndef u_int16_t
typedef unsigned short u_int16_t;
#endif
#ifndef int32_t
typedef signed int int32_t;
#endif
#ifndef u_int32_t
typedef unsigned int u_int32_t;
#endif
#ifndef int64_t
typedef long long int64_t;
#endif
#ifndef u_int64_t
typedef unsigned long long u_int64_t;
#endif
#endif // end of _WIN32
#if defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) || defined(__APPLE__)
#define __unix_like__ 1
#include <stdio.h> //Standard input/output definitions
#include <string.h> //String function definitions
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h> //waitpid() and wait()
#ifdef __linux__
#include <linux/serial.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <unistd.h> // fork()
#include <netinet/in.h>
#include <arpa/inet.h> // inet_addr(...)
#include <netdb.h>
#include <strings.h>
#include <syslog.h>
#endif // end of defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) || defined(__APPLE__)
#ifdef __solaris__
typedef unsigned char u_int8_t;
typedef unsigned short u_int16_t;
typedef unsigned long u_int32_t;
typedef unsigned long long u_int64_t;
#endif
#ifdef _DOS
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <memory.h>
#include <io.h>
#include <fcntl.h>
#include <time.h>
#ifndef int8_t
typedef signed char int8_t;
#endif
#ifndef u_int8_t
typedef unsigned char u_int8_t;
#endif
#ifndef int16_t
typedef signed int int16_t;
#endif
#ifndef u_int16_t
typedef unsigned int u_int16_t;
#endif
#ifndef int32_t
typedef signed long int32_t;
#endif
#ifndef u_int32_t
typedef unsigned long u_int32_t;
#endif
#endif // end of _DOS
#ifndef _WIN32
#ifndef IN
#define IN
#endif
#ifndef OUT
#define OUT
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef BOOL
#define BOOL int8_t
#endif
#ifndef CHAR
#define CHAR int8_t
#endif
#ifndef UCHAR
#define UCHAR u_int8_t
#endif
#ifndef BYTE
#define BYTE u_int8_t
#endif
#ifndef PBYTE
#define PBYTE u_int8_t *
#endif
#ifndef WORD
#define WORD u_int16_t
#endif
#ifndef DWORD
#define DWORD u_int32_t
#endif
#ifndef LONG
#define LONG int32_t
#endif
#ifndef ULONG
#define ULONG uint32_t
#endif
#ifndef LVOID
#define LVOID void *
#endif
#ifndef LPVOID
#define LPVOID void *
#endif
#ifndef HANDLE
#define HANDLE int
#endif
#ifndef SOCKET
#define SOCKET int
#endif
#ifndef SOCKET_ERROR
#define SOCKET_ERROR -1
#endif
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#endif // end of _WIN32
#endif //end of _COMMDEF_H_
+75
View File
@@ -0,0 +1,75 @@
//
// @APPLE_LICENSE_HEADER_START@
//
// Copyright (c) 2005, 2006 Apple Computer, Inc. All Rights Reserved.
//
// This file contains Original Code and/or Modifications of Original Code
// as defined in and that are subject to the Apple Public Source License
// Version 2.0 (the 'License'). You may not use this file except in
// compliance with the License. Please obtain a copy of the License at
// http://www.opensource.apple.com/apsl/ and read it before using this
// file.
//
// The Original Code and all software distributed under the License are
// distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
// EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
// INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
// Please see the License for the specific language governing rights and
// limitations under the License.
//
// @APPLE_LICENSE_HEADER_END@
// $Id: darwin_userclient.h,v 1.3 2006/01/15 21:19:30 msmith Exp $
#ifndef __DARWINUSERCLIENT_H__
#define __DARWINUSERCLIENT_H__
// XXX trim these includes
#include <iostream>
#include <pthread.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <unistd.h> /* fork() */
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "commdef.h"
#include "interface.h"
#include <IOKit/IOKitLib.h>
class DarwinUserClientInterface : public ArcInterface
{
public:
DarwinUserClientInterface();
~DarwinUserClientInterface();
bool init(const int nPort);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
void requirelock();
void releaselock();
bool ClearReadBuffer();
bool ClearWriteBuffer();
bool ClearReadWriteBuffer();
int getMTU();
void *getDeviceHandle();
private:
io_connect_t connectionPort;
bool controllerIsOpen;
pthread_mutex_t mtx;
};
#endif // __DARWINUSERCLIENT_H__
+54
View File
@@ -0,0 +1,54 @@
#ifndef _DOSPCI_H_
#define _DOSPCI_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "commdef.h"
#include "if.h"
#include "stdio.h"
#include "memory.h"
extern int ttchk( void ); /* Return count of received characters */
extern void ttos(unsigned char ptr[], int len);
extern int ttinc( void ); /* Input a character from circular buffer */
extern void serini( void ); /* Initialize the com port for interrupts */
extern unsigned long GetDword(unsigned);
extern void SetDword(unsigned, unsigned long);
extern InProtectedMode();
extern find_lindsay();
extern SetA20();
class DosPciInterface : public ArcInterface
{
public:
DosPciInterface();
~DosPciInterface();
int init(const char nPortNum);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
void *getDeviceHandle();
int getMTU();
void requirelock();
void releaselock();
void setTimeOut(int nSec);
private:
BOOL ClearReadBuffer();
BOOL ClearWriteBuffer();
BOOL ClearReadWriteBuffer();
int nTimeOut; // in seconds
};
#ifdef __cplusplus
}
#endif
#endif

+57
View File
@@ -0,0 +1,57 @@
#ifndef _ETHERNET_H_
#define _ETHERNET_H_
#include "commdef.h"
#include "interface.h"
#ifdef _WIN32
#include "Winsock2.h"
#endif
#ifdef _WIN32
class ARCLIB_API EthernetInterface : public ArcInterface
#else
class EthernetInterface : public ArcInterface
#endif
{
public:
EthernetInterface();
~EthernetInterface();
bool init(const char *szIPAddr, short nPort = 7890);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
int getMTU();
// helper functions
public:
void *getDeviceHandle();
SOCKET getSocket();
private:
BOOL ClearReadBuffer();
BOOL ClearWriteBuffer();
BOOL ClearReadWriteBuffer();
int WaitForReply(SOCKET s, long time_sec, long time_usec);
SOCKET m_socket;
#ifdef _WIN32
CRITICAL_SECTION m_cs;
void requirelock()
{
EnterCriticalSection(&m_cs);
}
void releaselock()
{
LeaveCriticalSection(&m_cs);
}
#elif defined(__unix_like__)
#endif
struct sockaddr_in agentaddr;
struct sockaddr_in manager_addr;
};
#endif
+94
View File
@@ -0,0 +1,94 @@
#ifndef __FREEBSDSCSI_H__
#define __FREEBSDSCSI_H__
#include <iostream>
#include <pthread.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <unistd.h> /* fork() */
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <err.h>
#include <cam/cam.h>
#include <cam/cam_debug.h>
#include <cam/cam_ccb.h>
#include <cam/scsi/scsi_all.h>
#include <cam/scsi/scsi_da.h>
#include <cam/scsi/scsi_pass.h>
#include <cam/scsi/scsi_message.h>
#include <camlib.h>
#include "commdef.h"
#include "interface.h"
#include "arclib.h"
#define SCSI_INQUIRY 0x12
#define SCSI_WRITE_BUF 0x3B
#define SCSI_READ_BUF 0x3C
#define SENSE_LEN 14
#define CDB_SIZE 10
#define BUF_SIZE 2048
typedef struct
{
BYTE ErrorCode; // Error Code (70H or 71H)
BYTE SegmentNum; // Number of current segment descriptor
BYTE SenseKey; // Sense Key(See bit definitions too)
BYTE InfoByte0; // Information MSB
BYTE InfoByte1; // Information MID
BYTE InfoByte2; // Information MID
BYTE InfoByte3; // Information LSB
BYTE AddSenLen; // Additional Sense Length
BYTE ComSpecInf0; // Command Specific Information MSB
BYTE ComSpecInf1; // Command Specific Information MID
BYTE ComSpecInf2; // Command Specific Information MID
BYTE ComSpecInf3; // Command Specific Information LSB
BYTE AddSenseCode; // Additional Sense Code
BYTE AddSenQual; // Additional Sense Code Qualifier
BYTE FieldRepUCode; // Field Replaceable Unit Code
BYTE SenKeySpec15; // Sense Key Specific 15th byte
BYTE SenKeySpec16; // Sense Key Specific 16th byte
BYTE SenKeySpec17; // Sense Key Specific 17th byte
BYTE AddSenseBytes; // Additional Sense Bytes
} sSENSE_DATA_FMT, *pSENSE_DATA_FMT;
class FreeBSDSCSIInterface : public ArcInterface
{
public:
FreeBSDSCSIInterface();
~FreeBSDSCSIInterface();
bool init(const int nScsiPort);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
int syncSend(const char *outBuf, int outLen, char *inBuf, int inLen, void *extdata = 0);
void requirelock();
void releaselock();
int getMTU();
void *getDeviceHandle();
private:
HANDLE m_hScsi;
cam_device *arc_device;
int fd;
pthread_mutex_t mut;
};
#endif
+308
View File
@@ -0,0 +1,308 @@
#ifndef _INTERFACE_H_
#define _INTERFACE_H_
#include "commdef.h"
// the error code the INTERFACE returned,
// if no error occurred, return the bytes sent or read
//
#define IF_OK (0)
#define IF_MORE_DATA (-1)
#define IF_FAIL_READ (-2)
#define IF_FAIL_WRITE (-3)
#define IF_NEED_RETRY (-4)
#define IF_OVER_MTU_SIZE (-5)
#define IF_FAIL_PARAMETER (-6)
#define IF_READ_TIMEOUT (-7)
#define IF_WRITE_TIMEOUT (-8)
#define IF_CTLR_FAILED (-9)
// rwflag
#define IF_WRITE_ONLY 0x01 // just do the operation of send
#define IF_READ_ONLY 0x02 // just do the operation of read
#define IF_RAW_READ 0x04
#define IF_RAW_WRITE 0x08
#define IF_SAS 0x10
// THE BELOW BLOCK IS ONLY FOR INTERNAL USE
/************************************************************************************/
enum
{
GUI_SET_SERIAL = 0x10,
GUI_SET_VENDOR,
GUI_SET_MODEL,
GUI_IDENTIFY,
GUI_CHECK_PASSWORD,
GUI_LOGOUT,
GUI_HTTP,
GUI_SET_ETHERNET_ADDR,
GUI_SET_LOGO,
GUI_POLL_EVENT,
GUI_GET_EVENT,
GUI_GET_HW_MONITOR,
GUI_SMART_TEST,
GUI_SET_TIME,
GUI_SNMP,
GUI_MISC, // 0x1F
GUI_GET_INFO_R = 0x20,
GUI_GET_INFO_V,
GUI_GET_INFO_P,
GUI_GET_INFO_S,
GUI_CLEAR_EVENT,
GUI_MUTE_BEEPER = 0x30,
GUI_BEEPER_SETTING,
GUI_SET_PASSWORD,
GUI_HOST_INTERFACE_MODE,
GUI_REBUILD_PRIORITY,
GUI_MAX_ATA_MODE,
GUI_RESET_CONTROLLER,
GUI_COM_PORT_SETTING,
GUI_NO_OPERATION,
GUI_DHCP_IP,
GUI_CREATE_PASS_THROUGH = 0x40,
GUI_MODIFY_PASS_THROUGH,
GUI_DELETE_PASS_THROUGH,
GUI_IDENTIFY_DEVICE,
GUI_CREATE_RAIDSET = 0x50,
GUI_DELETE_RAIDSET,
GUI_EXPAND_RAIDSET,
GUI_ACTIVATE_RAIDSET,
GUI_CREATE_HOT_SPARE,
GUI_DELETE_HOT_SPARE,
GUI_CREATE_VOLUME = 0x60,
GUI_MODIFY_VOLUME,
GUI_DELETE_VOLUME,
GUI_START_CHECK_VOLUME,
GUI_STOP_CHECK_VOLUME
};
// Application specific
enum
{
GUI_RAW_READ_WRITE = 0xEC,
GUI_RAW_READ = 0xED,
GUI_RAW_WRITE = 0xEE,
GUI_SET_ENCLOSURE_UNIT_SERIAL,
GUI_GET_TCPPORT,
GUI_GET_COMATTR,
// status code
GUI_WOULDBLOCK,
GUI_TIMEOUT
};
/****************************************************************************************/
//
// Library returned status
//
#define ARC_STATUS int
#define ARC_SUCCESS 0x00 // Operation succeeded
#define ARC_FAILURE 0x01 // Operation failed
#define ARC_RETURN_FRAME_ERROR 0x02 // The library does not recognize the returned data
// (including invalid data header, length or checksum, etc...)
#define ARC_INVALID_COM_HANDLE 0x03 // Invalid RS-232 handle
#define ARC_DATA_TRANSMIT_ERROR 0x04 // Failed to write to media
#define ARC_DATA_RECEIVE_ERROR 0x05 // Failed to read from media( no response from raid subsystem)
#define ARC_PARAMETER_ERROR 0x06 // The wrong parameter(s)
#define ARC_OPENFILE_ERROR 0x07 // Failed to open file
#define ARC_PASSWORD_REQUIRED 0x08 // Password required
#define ARC_INVALID_PASSWORD 0x09 // Wrong password
#define ARC_INSUFFICIENT_MEM 0x0A // Memory too small
#define ARC_CANT_ALLOC_MEM 0x0B // Failed to allocate necessary memory
#define ARC_BUFFER_TOO_SMALL 0x0C // The buffer is too small to put the returned data
#define ARC_SOCKET_ERROR 0x0D // Socket error
#define ARC_INVALID_SOCKET 0x0E // Invalid socket
#define ARC_INIT_COM_ERROR 0x0F // Failed to open COM port
#define ARC_SOCKET_STARTUP_ERROR 0x10 // Failed to init socket
#define ARC_INVALID_INTERFACE 0x11 // Invalid interface
#define ARC_NO_SUCH_DEVICE 0x12 // Device not found( including raidset, volumeset, physical drive )
#define ARC_DATA_TRANSMIT_TIMEOUT 0x13 // Failed to write to media in a given time
#define ARC_DATA_RECEIVE_TIMEOUT 0x14 // Failed to read from media in a given time
#define ARC_CTLR_FAILURE 0x15 // Controller failure or inactive
#define ARC_UNKNOWN_ERROR 0x3F // Unknown error
// RAID controller returned status
#define GUI_OK 0x41 // Operation successed
#define GUI_RAIDSET_NOT_NORMAL 0x42
#define GUI_VOLUMESET_NOT_NORMAL 0x43
#define GUI_NO_RAIDSET 0x44
#define GUI_NO_VOLUMESET 0x45
#define GUI_NO_PHYSICAL_DRIVE 0x46
#define GUI_PARAMETER_ERROR 0x47
#define GUI_UNSUPPORTED_COMMAND 0x48
#define GUI_DISK_CONFIG_CHANGED 0x49
#define GUI_INVALID_PASSWORD 0x4a
#define GUI_NO_DISK_SPACE 0x4b
#define GUI_CHECKSUM_ERROR 0x4c
#define GUI_PASSWORD_REQUIRED 0x4d
#define GUI_NO_MORE_DATA 0x4e // Internal use only
#define GUI_INTERNAL_ERROR 0x4f
#define GUI_FIRMWARE_CRC_ERROR 0x50
#define GUI_FIRMWARE_INVALID 0x51
#define GUI_FIRMWARE_UPDATE_FAILED 0x52
#define GUI_FIRMWARE_NO_HDD 0x53
#define GUI_END_OF_DATA 0x54
typedef int (*fn_decode_frame)(unsigned char *buf, int len);
typedef unsigned char (*fn_decode_cs)(unsigned char *buf, int len);
////////////////////////////////////////////////////////////
// for internal use only
//
typedef struct _IF_CMD_BLOCK
{
unsigned long timeout; // [in]in milliseconds
unsigned long rwflag; // [in]the flag which control the behavior of read/write
const char *outBuf; // [in] the output data buffer to be sent
unsigned long outLen; // [in] the output data buffer size
char *inBuf; // [out] the input data buffer to put the firmware returned data
unsigned long inLen; // [out] the input data buffer size
unsigned long io_status;// [out] the status of i/o
fn_decode_frame df; // [in]
fn_decode_cs dc; // [in]
}sIF_CMD_BLOCK, *pIF_CMD_BLOCK;
////////////////////////////////////////////////////////////
#ifdef _WIN32
class ARCLIB_API ArcInterface
#else
class ArcInterface
#endif
{
public:
virtual ~ArcInterface()
{
}
virtual int send(sIF_CMD_BLOCK *ifData) = 0;
virtual int recv(sIF_CMD_BLOCK *ifData) = 0;
virtual int syncSend(sIF_CMD_BLOCK *ifData) = 0;
//
// MTU: Maximum transmission unit
// the size (in bytes) of the largest packet that this layer can carry out.
//
virtual int getMTU() = 0;
virtual void *getDeviceHandle() = 0;
// These two member functions will be called by the syncSend() member function
// to ensure the synchronization of send() and recv() to the single controller.
// The requirelock() will be called before the send(),
// and releaselock() will be called after the recv().
virtual void requirelock(){}
virtual void releaselock(){}
virtual int getFirmSpec()
{
return 1;
}
// set the timeout for interface read operation
void setTimeOut(int nSec)
{
if(nSec > 0)
{
nTimeOut = nSec;
}
}
int getTimeOut()
{
return nTimeOut;
}
private:
int nTimeOut;
};
typedef void (*CMD_CALLBACK)(void *data);
typedef enum _SRC_SOURCE
{
SRC_UNKNOWN = -1,
SRC_COMM = 0,
SRC_DRIVER,
SRC_INBAND,
SRC_ETHERNET,
SRC_DRIVER_ODIN,
SRC_TOTAL
};
#ifdef _WIN32
class ARCLIB_API CArclibObj
#else
class CArclibObj
#endif
{
public:
CArclibObj()
{
m_Source = SRC_UNKNOWN;
}
virtual ~CArclibObj() {}
public:
unsigned long m_Source;
};
#ifdef _WIN32
class ARCLIB_API CArclibBase : public CArclibObj
#else
class CArclibBase : public CArclibObj
#endif
{
public:
CArclibBase()
{
m_Interface = NULL;
m_CallBackFunc = NULL;
}
virtual ~CArclibBase()
{
if(m_Interface)
{
delete m_Interface;
m_Interface = NULL;
}
}
virtual void ArcSetCallBack(CMD_CALLBACK pFunc)
{
m_CallBackFunc = pFunc;
}
/************************************************************************************
Function Name: ArcInitSession
Function: Startup areca library by assigning an interface to it
Input: 1. ArcInterface
Output: None.
Return Values: 1. ARC_STATUS
Note: This function should be called before any member functions be called
************************************************************************************/
virtual ARC_STATUS ArcInitSession(ArcInterface *Interface)
{
m_Interface = Interface;
return ARC_SUCCESS;
}
protected:
ArcInterface *m_Interface; // The communication path to the raid-subsystem
CMD_CALLBACK m_CallBackFunc;
};
#endif
+95
View File
@@ -0,0 +1,95 @@
#ifndef _INTERFACE_H_
#define _INTERFACE_H_
#include "commdef.h"
// the error code the INTERFACE returned,
// if no error occurred, return the bytes sent or read
//
#define IF_OK (0)
#define IF_MORE_DATA (-1)
#define IF_FAIL_READ (-2)
#define IF_FAIL_WRITE (-3)
#define IF_NEED_RETRY (-4)
#define IF_OVER_MTU_SIZE (-5)
#define IF_FAIL_PARAMETER (-6)
#define IF_READ_TIMEOUT (-7)
#define IF_WRITE_TIMEOUT (-8)
// rwflag
#define IF_WRITE_ONLY 0x01 // just do the operation of send
#define IF_READ_ONLY 0x02 // just do the operation of read
#define IF_RAW_READ_WRITE 0x04 // do the raw data r/w
#define IF_SAS 0x08
typedef int (*fn_decode_frame)(unsigned char *buf, int len);
typedef unsigned char (*fn_decode_cs)(unsigned char *buf, int len);
////////////////////////////////////////////////////////////
// for internal use only
//
typedef struct _IF_CMD_BLOCK
{
unsigned long timeout; // [in]in milliseconds
unsigned long rwflag; // [in]the flag which control the behavior of read/write
const char *outBuf; // [in] the output data buffer to be sent
unsigned long outLen; // [in] the output data buffer size
char *inBuf; // [out] the input data buffer to put the firmware returned data
unsigned long inLen; // [out] the input data buffer size
fn_decode_frame df; // [in]
fn_decode_cs dc; // [in]
}sIF_CMD_BLOCK, *pIF_CMD_BLOCK;
////////////////////////////////////////////////////////////
#ifdef _WIN32
class ARCLIB_API ArcInterface
#else
class ArcInterface
#endif
{
public:
virtual ~ArcInterface()
{
}
virtual int send(sIF_CMD_BLOCK *ifData) = 0;
virtual int recv(sIF_CMD_BLOCK *ifData) = 0;
virtual int syncSend(sIF_CMD_BLOCK *ifData) = 0;
//
// MTU: Maximum transmission unit
// the size (in bytes) of the largest packet that this layer can carry out.
//
virtual int getMTU() = 0;
virtual void *getDeviceHandle() = 0;
// These two member functions will be called by the syncSend() member function
// to ensure the synchronization of send() and recv() to the single controller.
// The requirelock() will be called before the send() called,
// and releaselock() will be called after the recv() called.
virtual void requirelock(){}
virtual void releaselock(){}
// set the timeout for interface read operation
void setTimeOut(int nSec)
{
if(nSec > 0)
{
nTimeOut = nSec;
}
}
int getTimeOut()
{
return nTimeOut;
}
private:
int nTimeOut;
};
#endif
+30
View File
@@ -0,0 +1,30 @@
#ifndef _LINUXCOMM_H_
#define _LINUXCOMM_H_
#include "commdef.h"
#include "interface.h"
#include <pthread.h>
class LinuxCommInterface : public ArcInterface
{
public:
LinuxCommInterface();
~LinuxCommInterface();
bool init(const char nPortNum, char nBaudRate = 7, char nStopBit = 0);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
void requirelock();
void releaselock();
int getMTU();
void *getDeviceHandle();
public:
BOOL ClearReadWriteBuffer();
int m_hComm;
int fd;
pthread_mutex_t mut;
};
#endif
+107
View File
@@ -0,0 +1,107 @@
#ifndef __LINUXIOCTL_H__
#define __LINUXIOCTL_H__
#include <iostream>
#include <pthread.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <unistd.h> /* fork() */
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#ifdef __linux__
#include <scsi/sg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#endif
#include <sys/ioctl.h>
#include <unistd.h>
#include "commdef.h"
#include "interface.h"
/*DeviceType*/
#define ARECA_SATA_RAID 0x90000000
/*FunctionCode*/
#define FUNCTION_READ_RQBUFFER 0x0801
#define FUNCTION_WRITE_WQBUFFER 0x0802
#define FUNCTION_CLEAR_RQBUFFER 0x0803
#define FUNCTION_CLEAR_WQBUFFER 0x0804
#define FUNCTION_CLEAR_ALLQBUFFER 0x0805
#define FUNCTION_RETURN_CODE_3F 0x0806
#define FUNCTION_SAY_HELLO 0x0807
#if defined(__linux__) || defined (__solaris__)
/* ARECA IO CONTROL CODE*/
#define ARCMSR_IOCTL_READ_RQBUFFER ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER
#define ARCMSR_IOCTL_WRITE_WQBUFFER ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER
#define ARCMSR_IOCTL_CLEAR_RQBUFFER ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER
#define ARCMSR_IOCTL_CLEAR_WQBUFFER ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER
#define ARCMSR_IOCTL_CLEAR_ALLQBUFFER ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER
#define ARCMSR_IOCTL_RETURN_CODE_3F ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F
#define ARCMSR_IOCTL_SAY_HELLO ARECA_SATA_RAID | FUNCTION_SAY_HELLO
#elif __FreeBSD__
#define ARCMSR_IOCTL_READ_RQBUFFER _IOWR('F', FUNCTION_READ_RQBUFFER, sSRB_BUFFER)
#define ARCMSR_IOCTL_WRITE_WQBUFFER _IOWR('F', FUNCTION_WRITE_WQBUFFER, sSRB_BUFFER)
#define ARCMSR_IOCTL_CLEAR_RQBUFFER _IOWR('F', FUNCTION_CLEAR_RQBUFFER, sSRB_BUFFER)
#define ARCMSR_IOCTL_CLEAR_WQBUFFER _IOWR('F', FUNCTION_CLEAR_WQBUFFER, sSRB_BUFFER)
#define ARCMSR_IOCTL_CLEAR_ALLQBUFFER _IOWR('F', FUNCTION_CLEAR_ALLQBUFFER, sSRB_BUFFER)
#define ARCMSR_IOCTL_RETURN_CODE_3F _IOWR('F', FUNCTION_RETURN_CODE_3F, sSRB_BUFFER)
#define ARCMSR_IOCTL_SAY_HELLO _IOWR('F', FUNCTION_SAY_HELLO, sSRB_BUFFER)
#endif
/* ARECA IOCTL ReturnCode */
#define ARCMSR_IOCTL_RETURNCODE_OK 0x01
#define ARCMSR_IOCTL_RETURNCODE_ERROR 0x06
#define ARCMSR_IOCTL_RETURNCODE_3F 0x3F
typedef struct _SRB_IO_CONTROL
{
unsigned int HeaderLength;
UCHAR Signature[8];
unsigned int Timeout;
unsigned int ControlCode;
unsigned int ReturnCode;
unsigned int Length;
} sSRB_IO_CONTROL, *pSRB_IO_CONTROL;
typedef struct _SRB_BUFFER
{
sSRB_IO_CONTROL srbioctl; // ioctl header
UCHAR ioctldatabuffer[1032]; // areca gui program does not accept more than 1031 byte
} sSRB_BUFFER, *pSRB_BUFFER;
class LinuxIoctlInterface : public ArcInterface
{
public:
LinuxIoctlInterface();
~LinuxIoctlInterface();
bool init(const int nScsiPort);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
void requirelock();
void releaselock();
int getMTU();
void *getDeviceHandle();
private:
BOOL ClearReadBuffer();
BOOL ClearWriteBuffer();
BOOL ClearReadWriteBuffer();
HANDLE m_hScsi;
int fd;
pthread_mutex_t mut;
};
#endif
+64
View File
@@ -0,0 +1,64 @@
#ifndef __LINUX_PASS_IOCTL_H__
#define __LINUX_PASS_IOCTL_H__
#include <iostream>
#include <pthread.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <unistd.h> /* fork() */
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#ifdef __linux__
#include <scsi/sg.h>
#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#endif
#include <sys/ioctl.h>
#include <unistd.h>
#include "commdef.h"
#include "interface.h"
#include "arclib.h"
#define SCSI_INQUIRY 0x12
#define SCSI_WRITE_BUF 0x3B
#define SCSI_READ_BUF 0x3C
#define SENSE_LEN 14
#define CDB_SIZE 10
#define BUF_SIZE 2048
class LinuxPassIoctlInterface : public ArcInterface
{
public:
LinuxPassIoctlInterface();
~LinuxPassIoctlInterface();
bool init(const int nScsiPort);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
void requirelock();
void releaselock();
BOOL ClearReadBuffer();
BOOL ClearWriteBuffer();
BOOL ClearReadWriteBuffer();
int getMTU();
void *getDeviceHandle();
public:
HANDLE m_hScsi;
int fd;
pthread_mutex_t mut;
};
#endif
+94
View File
@@ -0,0 +1,94 @@
#ifndef __LINUXSCSI_H__
#define __LINUXSCSI_H__
#include <iostream>
#include <pthread.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <unistd.h> /* fork() */
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#ifdef __linux__
#include <scsi/sg.h>
#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#endif
#include <sys/ioctl.h>
#include <unistd.h>
#include "commdef.h"
#include "interface.h"
#include "arclib.h"
#define SCSI_INQUIRY 0x12
#define SCSI_WRITE_BUF 0x3B
#define SCSI_READ_BUF 0x3C
#define SENSE_LEN 14
#define CDB_SIZE 10
#define BUF_SIZE 2048
typedef struct
{
int inlen; // [i] Length of data written to device
int outlen; // [i] Length of data read from device
char cdb[CDB_SIZE]; // [i] SCSI command (6 <= x <= 16)
// [o] Data read from device starts here
// [o] On error, sense buffer starts here
char buf[4100]; // [i] Data written to device starts here
}sSRB_BUF, *pSRB_BUF;
typedef struct
{
BYTE ErrorCode; // Error Code (70H or 71H)
BYTE SegmentNum; // Number of current segment descriptor
BYTE SenseKey; // Sense Key(See bit definitions too)
BYTE InfoByte0; // Information MSB
BYTE InfoByte1; // Information MID
BYTE InfoByte2; // Information MID
BYTE InfoByte3; // Information LSB
BYTE AddSenLen; // Additional Sense Length
BYTE ComSpecInf0; // Command Specific Information MSB
BYTE ComSpecInf1; // Command Specific Information MID
BYTE ComSpecInf2; // Command Specific Information MID
BYTE ComSpecInf3; // Command Specific Information LSB
BYTE AddSenseCode; // Additional Sense Code
BYTE AddSenQual; // Additional Sense Code Qualifier
BYTE FieldRepUCode; // Field Replaceable Unit Code
BYTE SenKeySpec15; // Sense Key Specific 15th byte
BYTE SenKeySpec16; // Sense Key Specific 16th byte
BYTE SenKeySpec17; // Sense Key Specific 17th byte
BYTE AddSenseBytes; // Additional Sense Bytes
} sSENSE_DATA_FMT, *pSENSE_DATA_FMT;
class LinuxSCSIInterface : public ArcInterface
{
public:
LinuxSCSIInterface();
~LinuxSCSIInterface();
bool init(const int nScsiPort);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
void requirelock();
void releaselock();
int getMTU();
void *getDeviceHandle();
public:
HANDLE m_hScsi;
int fd;
pthread_mutex_t mut;
};
#endif
+156
View File
@@ -0,0 +1,156 @@
#ifndef _SASBASE_H
#define _SASBASE_H
#pragma pack(1)
enum _SAS_ATTRIBUTE_ITEMS
{
SAS_READ_RECOVERED_WO_DELAY,
SAS_READ_RECOVERED_W_DELAY,
SAS_READ_RECOVERED_W_RETRY,
SAS_READ_RECOVERED,
SAS_READ_TOTAL_BYTES,
SAS_READ_UNRECOVERED,
SAS_WRITE_RECOVERED_WO_DELAY,
SAS_WRITE_RECOVERED_W_DELAY,
SAS_WRITE_RECOVERED_W_RETRY,
SAS_WRITE_RECOVERED,
SAS_WRITE_TOTAL_BYTES,
SAS_WRITE_UNRECOVERED,
SAS_VERIFY_RECOVERED_WO_DELAY,
SAS_VERIFY_RECOVERED_W_DELAY,
SAS_VERIFY_RECOVERED_W_RETRY,
SAS_VERIFY_RECOVERED,
SAS_VERIFY_UNRECOVERED,
SAS_NON_MEDIUM_ERRORS,
TOTAL_SAS_ATTR_ITEMS
};
enum _SMART_ITEMS
{
SMART_READ_ERROR_RATE_1, // read error rate
SMART_SPINUP_TIME_3, // spinup time
SMART_REALLOCATION_5, // reallocation
SMART_SEEK_ERROR_RATE_7, // seek error rate
SMART_SPINUP_RETRY_10, // spinup retry
SMART_CALIBRATION_RETRY_11, // calibration retry
SMART_TEMPERATURE_194, // temperature
TOTAL_SMART_ITEMS,
};
enum _SAS_HW
{
SAS_HW_DISK, // disks
SAS_HW_VOLTAGE, // voltages
SAS_HW_FAN, // fans
SAS_HW_POWER, // powers
SAS_HW_TEMPERATURE, // temperatures
TOTAL_SAS_HW
};
typedef struct sSMART_DATA
{
WORD smIndex;
BYTE smStatus;
BYTE smThreshold;
} sSMART_DATA, *pSMART_DATA;
// SCSI attribtes
typedef struct sSCSI_ATTR
{
BYTE scsiChannel; // channel for SCSI target (0/1)
BYTE scsiId; // SCSI ID for the volume
BYTE scsiLun; // LUN (0 if target is IDE)
BYTE scsiTaggedQueuing; // 1 --> queue enabled
BYTE scsiCacheMode; // 1 --> Cache enabled
BYTE scsiSpeed; // IDE(0:ATA33/1:ATA66/2:ATA100/3:ATA133)
} sSCSI_ATTR, *pSCSI_ATTR;
typedef struct sGUI_ENC_PROPERTY
{
BYTE gepVendor[8]; // vendor name
BYTE gepProduct[16]; // product name
BYTE gepRev[4]; // reversion
BYTE gepEncType; // enclosure type
BYTE gepEncnumber; // enclosure#
BYTE gepEncDisks; // number of disks
BYTE gepEncVoltages; // number of voltages
BYTE gepEncFans; // number of fans
BYTE gepEncPowers; // number of powers
BYTE gepEncTemperatures; // number of temperatures
BYTE gepRes[0x1D]; // reserved
} sGUI_ENC_PROPERTY, *pGUI_ENC_PROPERTY;
#define MAX_ENCLOSURES 8
#define MAX_PHY_PER_ENCLOSURE 32
#define MAX_DEV_PER_ENCLOSURE 32
enum
{
ENC_TYPE_NOT_INSTALLED, // not installed
ENC_TYPE_INTERNAL, // built-in enclosure
ENC_TYPE_SES2, // ses2
ENC_TYPE_SMP, // smp
ENC_TYPE_CTRL // controller
};
#define MAX_ELEMENT_STR_LEN 24
#define MAX_SENSORS 32
// constant of SES element definitions
// common status
#define SES_COMMON_STATUS_OK 0x00000001
#define SES_COMMON_STATUS_CRITICAL 0x00000002
// power
#define SES_POWER_FAIL 0x40000000
// fan(cooling)
#define SES_FAN_FAIL 0x40000000
// temperature
#define SES_OVER_TEMPERATURE 0x08000000
// voltage
#define SES_OVER_VOLTAGE 0x00000200
#define SES_UNDER_VOLTAGE 0x00000100
#define SES_STATUS_OK(x) (x & SES_COMMON_STATUS_OK)
#define SES_STATUS_CRITICAL(x) (x & SES_COMMON_STATUS_CRITICAL)
typedef struct sELEMENT
{
BYTE snNumberOfSensors; // number of elements
BYTE snElementStr[MAX_SENSORS][MAX_ELEMENT_STR_LEN]; // description of elements
LONG snValue[MAX_SENSORS]; // the value of sensor
DWORD snRawValue[MAX_SENSORS]; // the SES RAW value of sensor
}sELEMENT, *pELEMENT;
typedef struct sDISK_ELEMENT
{
BYTE snNumberOfElements; // number of elements
BYTE snElementStr[MAX_SENSORS][MAX_ELEMENT_STR_LEN]; // description of elements
}sDISK_ELEMENT, *pDISK_ELEMENT;
typedef struct sSENSORS
{
sDISK_ELEMENT disk;
sELEMENT voltage;
sELEMENT fan;
sELEMENT power;
sELEMENT temperature;
sELEMENT battery;
} sSENSORS, *pSENSORS;
#pragma pack()
#endif
+32
View File
@@ -0,0 +1,32 @@
#ifndef _SOLARISCOMM_H_
#define _SOLARISCOMM_H_
#include "commdef.h"
#include "interface.h"
#include <pthread.h>
class SolarisCommInterface : public ArcInterface
{
public:
SolarisCommInterface();
~SolarisCommInterface();
bool init(const char nPortNum, char nBaudRate = 7, char nStopBit = 0);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
void requirelock();
void releaselock();
int getMTU();
void *getDeviceHandle();
BOOL ClearReadBuffer();
BOOL ClearWriteBuffer();
BOOL ClearReadWriteBuffer();
private:
int m_hComm;
int fd;
pthread_mutex_t mut;
};
#endif
+102
View File
@@ -0,0 +1,102 @@
#ifndef __SOLARISIOCTL_H__
#define __SOLARISIOCTL_H__
#include <iostream>
#include <pthread.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <unistd.h> /* fork() */
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <ftw.h>
#include <sys/mhd.h>
#include <sys/scsi/impl/uscsi.h>
#include <sys/scsi/generic/commands.h>
#include <sys/scsi/generic/inquiry.h>
#include "commdef.h"
#include "interface.h"
typedef struct _SRB_IO_CONTROL sSRB_IO_CONTROL, *pSRB_IO_CONTROL;
typedef struct _SRB_BUFFER sSRB_BUFFER, *pSRB_BUFFER;
/*DeviceType*/
#define ARECA_SATA_RAID 0x90000000
/*FunctionCode*/
#define FUNCTION_READ_RQBUFFER 0x0801
#define FUNCTION_WRITE_WQBUFFER 0x0802
#define FUNCTION_CLEAR_RQBUFFER 0x0803
#define FUNCTION_CLEAR_WQBUFFER 0x0804
#define FUNCTION_CLEAR_ALLQBUFFER 0x0805
#define FUNCTION_RETURN_CODE_3F 0x0806
#define FUNCTION_SAY_HELLO 0x0807
#define FUNCTION_SAY_GOODBYE 0x0808
/* ARECA IO CONTROL CODE*/
#define ARCMSR_IOCTL_READ_RQBUFFER ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER
#define ARCMSR_IOCTL_WRITE_WQBUFFER ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER
#define ARCMSR_IOCTL_CLEAR_RQBUFFER ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER
#define ARCMSR_IOCTL_CLEAR_WQBUFFER ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER
#define ARCMSR_IOCTL_CLEAR_ALLQBUFFER ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER
#define ARCMSR_IOCTL_RETURN_CODE_3F ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F
#define ARCMSR_IOCTL_SAY_HELLO ARECA_SATA_RAID | FUNCTION_SAY_HELLO
#define ARCMSR_IOCTL_SAY_GOODBYE ARECA_SATA_RAID | FUNCTION_SAY_GOODBYE
/* ARECA IOCTL ReturnCode */
#define ARCMSR_IOCTL_RETURNCODE_OK 0x00000001
#define ARCMSR_IOCTL_RETURNCODE_ERROR 0x00000006
#define ARCMSR_IOCTL_RETURNCODE_3F 0x0000003F
#define SYSERR (-1)
typedef struct _SRB_IO_CONTROL
{
unsigned int HeaderLength;
UCHAR Signature[8];
unsigned int Timeout;
unsigned int ControlCode;
unsigned int ReturnCode;
unsigned int Length;
};
typedef struct _SRB_BUFFER
{
sSRB_IO_CONTROL srbioctl; /*ioctl header*/
UCHAR ioctldatabuffer[224];/*areca gui program does not accept more than 1031 byte*/
};
class SolarisIoctlInterface : public ArcInterface
{
public:
SolarisIoctlInterface();
~SolarisIoctlInterface();
bool init(const int nScsiPort);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
void requirelock();
void releaselock();
void *getDeviceHandle();
BOOL ClearReadBuffer();
BOOL ClearWriteBuffer();
BOOL ClearReadWriteBuffer();
int getMTU();
private:
HANDLE m_hScsi;
int fd;
pthread_mutex_t mut;
};
#endif
+93
View File
@@ -0,0 +1,93 @@
#ifndef __SOLARISSCSI_H__
#define __SOLARISSCSI_H__
#include <iostream>
#include <pthread.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <unistd.h> /* fork() */
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#ifdef __linux__
#include <scsi/sg.h>
#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#endif
#include <sys/ioctl.h>
#include <unistd.h>
#include "commdef.h"
#include "interface.h"
#include "arclib.h"
#define SCSI_INQUIRY 0x12
#define SCSI_WRITE_BUF 0x3B
#define SCSI_READ_BUF 0x3C
#define SENSE_LEN 14
#define CDB_SIZE 10
#define BUF_SIZE 2048
typedef struct
{
int inlen; // [i] Length of data written to device
int outlen; // [i] Length of data read from device
char cdb[CDB_SIZE]; // [i] SCSI command (6 <= x <= 16)
// [o] Data read from device starts here
// [o] On error, sense buffer starts here
char buf[4100]; // [i] Data written to device starts here
}sSRB_BUF, *pSRB_BUF;
typedef struct
{
BYTE ErrorCode; // Error Code (70H or 71H)
BYTE SegmentNum; // Number of current segment descriptor
BYTE SenseKey; // Sense Key(See bit definitions too)
BYTE InfoByte0; // Information MSB
BYTE InfoByte1; // Information MID
BYTE InfoByte2; // Information MID
BYTE InfoByte3; // Information LSB
BYTE AddSenLen; // Additional Sense Length
BYTE ComSpecInf0; // Command Specific Information MSB
BYTE ComSpecInf1; // Command Specific Information MID
BYTE ComSpecInf2; // Command Specific Information MID
BYTE ComSpecInf3; // Command Specific Information LSB
BYTE AddSenseCode; // Additional Sense Code
BYTE AddSenQual; // Additional Sense Code Qualifier
BYTE FieldRepUCode; // Field Replaceable Unit Code
BYTE SenKeySpec15; // Sense Key Specific 15th byte
BYTE SenKeySpec16; // Sense Key Specific 16th byte
BYTE SenKeySpec17; // Sense Key Specific 17th byte
BYTE AddSenseBytes; // Additional Sense Bytes
} sSENSE_DATA_FMT, *pSENSE_DATA_FMT;
class SolarisSCSIInterface : public ArcInterface
{
public:
SolarisSCSIInterface();
~SolarisSCSIInterface();
bool init(const int nScsiPort);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
int getMTU();
void *getDeviceHandle();
private:
HANDLE m_hScsi;
//pthread_mutex_t *m_LOCK;
int fd;
};
#endif
+39
View File
@@ -0,0 +1,39 @@
#ifndef _WINCOMM_H_
#define _WINCOMM_H_
#include <iostream>
#include <tchar.h>
// TODO: reference additional headers your program requires here
#include <wtypes.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include "commdef.h"
#include "interface.h"
class ARCLIB_API WinCommInterface : public ArcInterface
{
friend class CArclib;
public:
WinCommInterface();
~WinCommInterface();
bool init(const char nPortNum, char nBaudRate = 7, char nStopBit = 0);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
int getMTU();
void *getDeviceHandle();
void requirelock();
void releaselock();
private:
BOOL ClearReadBuffer();
BOOL ClearWriteBuffer();
BOOL ClearReadWriteBuffer();
HANDLE m_hComm;
HANDLE m_hSyncComm;
PSECURITY_DESCRIPTOR pSD;
};
#endif
Binary file not shown.
+132
View File
@@ -0,0 +1,132 @@
#ifndef _WIN_PASS_IOCTL_H_
#define _WIN_PASS_IOCTL_H_
#include "commdef.h"
#include "interface.h"
#include <iostream>
#include <tchar.h>
#include <wtypes.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <winioctl.h>
#define FILE_DEVICE_CONTROLLER 0x00000004
#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
#define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) //0x0004D008 see NTDDSCSI.H for definition
#define IOCTL_SCSI_RESCAN_BUS CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define ARCMSR_IOCTL_READ_RQBUFFER 0x90002004
#define ARCMSR_IOCTL_WRITE_WQBUFFER 0x90002008
#define ARCMSR_IOCTL_CLEAR_RQBUFFER 0x9000200C
#define ARCMSR_IOCTL_CLEAR_WQBUFFER 0x90002010
#define ARCMSR_IOCTL_CLEAR_ALLQBUFFER 0x90002014
#define ARCMSR_IOCTL_RETURN_CODE_3F 0x90002018
#define ARCMSR_IOCTL_SAY_HELLO 0x9000201C
// return code
#define SRB_STATUS_SUCCESS 0x01
#define SRB_STATUS_INVALID_REQUEST 0x06
class ARCLIB_API WinPassIoctlInterface : public ArcInterface
{
friend class CArclib;
public:
WinPassIoctlInterface();
~WinPassIoctlInterface();
bool init(const int nScsiPort);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
int getMTU();
void *getDeviceHandle();
void requirelock();
void releaselock();
private:
BOOL ClearReadBuffer();
BOOL ClearWriteBuffer();
BOOL ClearReadWriteBuffer();
HANDLE m_hScsi;
HANDLE m_hSyncIm;
PSECURITY_DESCRIPTOR pSD;
};
//
// SCSI CDB operation codes
//
#define SCSIOP_TEST_UNIT_READY 0x00
#define SCSIOP_REZERO_UNIT 0x01
#define SCSIOP_REWIND 0x01
#define SCSIOP_REQUEST_BLOCK_ADDR 0x02
#define SCSIOP_REQUEST_SENSE 0x03
#define SCSIOP_FORMAT_UNIT 0x04
#define SCSIOP_READ_BLOCK_LIMITS 0x05
#define SCSIOP_REASSIGN_BLOCKS 0x07
#define SCSIOP_READ6 0x08
#define SCSIOP_RECEIVE 0x08
#define SCSIOP_WRITE6 0x0A
#define SCSIOP_PRINT 0x0A
#define SCSIOP_SEND 0x0A
#define SCSIOP_SEEK6 0x0B
#define SCSIOP_TRACK_SELECT 0x0B
#define SCSIOP_SLEW_PRINT 0x0B
#define SCSIOP_SEEK_BLOCK 0x0C
#define SCSIOP_PARTITION 0x0D
#define SCSIOP_READ_REVERSE 0x0F
#define SCSIOP_WRITE_FILEMARKS 0x10
#define SCSIOP_FLUSH_BUFFER 0x10
#define SCSIOP_SPACE 0x11
#define SCSIOP_INQUIRY 0x12
#define SCSIOP_VERIFY6 0x13
#define SCSIOP_RECOVER_BUF_DATA 0x14
#define SCSIOP_MODE_SELECT 0x15
#define SCSIOP_RESERVE_UNIT 0x16
#define SCSIOP_RELEASE_UNIT 0x17
#define SCSIOP_COPY 0x18
#define SCSIOP_ERASE 0x19
#define SCSIOP_MODE_SENSE 0x1A
#define SCSIOP_START_STOP_UNIT 0x1B
#define SCSIOP_STOP_PRINT 0x1B
#define SCSIOP_LOAD_UNLOAD 0x1B
#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C
#define SCSIOP_SEND_DIAGNOSTIC 0x1D
#define SCSIOP_MEDIUM_REMOVAL 0x1E
#define SCSIOP_READ_CAPACITY 0x25
#define SCSIOP_READ 0x28
#define SCSIOP_WRITE 0x2A
#define SCSIOP_SEEK 0x2B
#define SCSIOP_LOCATE 0x2B
#define SCSIOP_WRITE_VERIFY 0x2E
#define SCSIOP_VERIFY 0x2F
#define SCSIOP_SEARCH_DATA_HIGH 0x30
#define SCSIOP_SEARCH_DATA_EQUAL 0x31
#define SCSIOP_SEARCH_DATA_LOW 0x32
#define SCSIOP_SET_LIMITS 0x33
#define SCSIOP_READ_POSITION 0x34
#define SCSIOP_SYNCHRONIZE_CACHE 0x35
#define SCSIOP_COMPARE 0x39
#define SCSIOP_COPY_COMPARE 0x3A
#define SCSIOP_WRITE_DATA_BUFF 0x3B
#define SCSIOP_READ_DATA_BUFF 0x3C
#define SCSIOP_CHANGE_DEFINITION 0x40
#define SCSIOP_READ_SUB_CHANNEL 0x42
#define SCSIOP_READ_TOC 0x43
#define SCSIOP_READ_HEADER 0x44
#define SCSIOP_PLAY_AUDIO 0x45
#define SCSIOP_PLAY_AUDIO_MSF 0x47
#define SCSIOP_PLAY_TRACK_INDEX 0x48
#define SCSIOP_PLAY_TRACK_RELATIVE 0x49
#define SCSIOP_PAUSE_RESUME 0x4B
#define SCSIOP_LOG_SELECT 0x4C
#define SCSIOP_LOG_SENSE 0x4D
#endif
+132
View File
@@ -0,0 +1,132 @@
#ifndef _WIN_PASS_IOCTL_ODIN_H_
#define _WIN_PASS_IOCTL_ODIN_H_
#include "commdef.h"
#include "if.h"
#include <iostream>
#include <tchar.h>
#include <wtypes.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <winioctl.h>
#define FILE_DEVICE_CONTROLLER 0x00000004
#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
#define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) //0x0004D008 see NTDDSCSI.H for definition
#define IOCTL_SCSI_RESCAN_BUS CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define ARCMSR_IOCTL_READ_RQBUFFER 0x90002004
#define ARCMSR_IOCTL_WRITE_WQBUFFER 0x90002008
#define ARCMSR_IOCTL_CLEAR_RQBUFFER 0x9000200C
#define ARCMSR_IOCTL_CLEAR_WQBUFFER 0x90002010
#define ARCMSR_IOCTL_CLEAR_ALLQBUFFER 0x90002014
#define ARCMSR_IOCTL_RETURN_CODE_3F 0x90002018
#define ARCMSR_IOCTL_SAY_HELLO 0x9000201C
// return code
#define SRB_STATUS_SUCCESS 0x01
#define SRB_STATUS_INVALID_REQUEST 0x06
class ARCLIB_API WinPassIoctlOdinInterface : public ArcInterface
{
friend class CArclibOdin;
public:
WinPassIoctlOdinInterface();
~WinPassIoctlOdinInterface();
bool init(const int nScsiPort);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
int getMTU();
void *getDeviceHandle();
void requirelock();
void releaselock();
private:
BOOL ClearReadBuffer();
BOOL ClearWriteBuffer();
BOOL ClearReadWriteBuffer();
HANDLE m_hScsi;
HANDLE m_hSyncIm;
PSECURITY_DESCRIPTOR pSD;
};
//
// SCSI CDB operation codes
//
#define SCSIOP_TEST_UNIT_READY 0x00
#define SCSIOP_REZERO_UNIT 0x01
#define SCSIOP_REWIND 0x01
#define SCSIOP_REQUEST_BLOCK_ADDR 0x02
#define SCSIOP_REQUEST_SENSE 0x03
#define SCSIOP_FORMAT_UNIT 0x04
#define SCSIOP_READ_BLOCK_LIMITS 0x05
#define SCSIOP_REASSIGN_BLOCKS 0x07
#define SCSIOP_READ6 0x08
#define SCSIOP_RECEIVE 0x08
#define SCSIOP_WRITE6 0x0A
#define SCSIOP_PRINT 0x0A
#define SCSIOP_SEND 0x0A
#define SCSIOP_SEEK6 0x0B
#define SCSIOP_TRACK_SELECT 0x0B
#define SCSIOP_SLEW_PRINT 0x0B
#define SCSIOP_SEEK_BLOCK 0x0C
#define SCSIOP_PARTITION 0x0D
#define SCSIOP_READ_REVERSE 0x0F
#define SCSIOP_WRITE_FILEMARKS 0x10
#define SCSIOP_FLUSH_BUFFER 0x10
#define SCSIOP_SPACE 0x11
#define SCSIOP_INQUIRY 0x12
#define SCSIOP_VERIFY6 0x13
#define SCSIOP_RECOVER_BUF_DATA 0x14
#define SCSIOP_MODE_SELECT 0x15
#define SCSIOP_RESERVE_UNIT 0x16
#define SCSIOP_RELEASE_UNIT 0x17
#define SCSIOP_COPY 0x18
#define SCSIOP_ERASE 0x19
#define SCSIOP_MODE_SENSE 0x1A
#define SCSIOP_START_STOP_UNIT 0x1B
#define SCSIOP_STOP_PRINT 0x1B
#define SCSIOP_LOAD_UNLOAD 0x1B
#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C
#define SCSIOP_SEND_DIAGNOSTIC 0x1D
#define SCSIOP_MEDIUM_REMOVAL 0x1E
#define SCSIOP_READ_CAPACITY 0x25
#define SCSIOP_READ 0x28
#define SCSIOP_WRITE 0x2A
#define SCSIOP_SEEK 0x2B
#define SCSIOP_LOCATE 0x2B
#define SCSIOP_WRITE_VERIFY 0x2E
#define SCSIOP_VERIFY 0x2F
#define SCSIOP_SEARCH_DATA_HIGH 0x30
#define SCSIOP_SEARCH_DATA_EQUAL 0x31
#define SCSIOP_SEARCH_DATA_LOW 0x32
#define SCSIOP_SET_LIMITS 0x33
#define SCSIOP_READ_POSITION 0x34
#define SCSIOP_SYNCHRONIZE_CACHE 0x35
#define SCSIOP_COMPARE 0x39
#define SCSIOP_COPY_COMPARE 0x3A
#define SCSIOP_WRITE_DATA_BUFF 0x3B
#define SCSIOP_READ_DATA_BUFF 0x3C
#define SCSIOP_CHANGE_DEFINITION 0x40
#define SCSIOP_READ_SUB_CHANNEL 0x42
#define SCSIOP_READ_TOC 0x43
#define SCSIOP_READ_HEADER 0x44
#define SCSIOP_PLAY_AUDIO 0x45
#define SCSIOP_PLAY_AUDIO_MSF 0x47
#define SCSIOP_PLAY_TRACK_INDEX 0x48
#define SCSIOP_PLAY_TRACK_RELATIVE 0x49
#define SCSIOP_PAUSE_RESUME 0x4B
#define SCSIOP_LOG_SELECT 0x4C
#define SCSIOP_LOG_SENSE 0x4D
#endif
+113
View File
@@ -0,0 +1,113 @@
#ifndef _WINSCSI_H_
#define _WINSCSI_H_
#include "commdef.h"
#include "interface.h"
#include "arclib.h"
#include <iostream>
#include <tchar.h>
#include <wtypes.h>
#include <stdio.h>
#include <string.h>
#define MAX_SCSI_DEV 10
#define MAX_SCSI_CH 2
#define MAX_SCSI_TARGETID 127 // older value is 15, modify for SAS, upgrade to 127, 2008/03/11
#define MAX_SCSI_LUN 7
//
// SCSI CDB operation codes
//
#define SCSIOP_TEST_UNIT_READY 0x00
#define SCSIOP_REZERO_UNIT 0x01
#define SCSIOP_REWIND 0x01
#define SCSIOP_REQUEST_BLOCK_ADDR 0x02
#define SCSIOP_REQUEST_SENSE 0x03
#define SCSIOP_FORMAT_UNIT 0x04
#define SCSIOP_READ_BLOCK_LIMITS 0x05
#define SCSIOP_REASSIGN_BLOCKS 0x07
#define SCSIOP_READ6 0x08
#define SCSIOP_RECEIVE 0x08
#define SCSIOP_WRITE6 0x0A
#define SCSIOP_PRINT 0x0A
#define SCSIOP_SEND 0x0A
#define SCSIOP_SEEK6 0x0B
#define SCSIOP_TRACK_SELECT 0x0B
#define SCSIOP_SLEW_PRINT 0x0B
#define SCSIOP_SEEK_BLOCK 0x0C
#define SCSIOP_PARTITION 0x0D
#define SCSIOP_READ_REVERSE 0x0F
#define SCSIOP_WRITE_FILEMARKS 0x10
#define SCSIOP_FLUSH_BUFFER 0x10
#define SCSIOP_SPACE 0x11
#define SCSIOP_INQUIRY 0x12
#define SCSIOP_VERIFY6 0x13
#define SCSIOP_RECOVER_BUF_DATA 0x14
#define SCSIOP_MODE_SELECT 0x15
#define SCSIOP_RESERVE_UNIT 0x16
#define SCSIOP_RELEASE_UNIT 0x17
#define SCSIOP_COPY 0x18
#define SCSIOP_ERASE 0x19
#define SCSIOP_MODE_SENSE 0x1A
#define SCSIOP_START_STOP_UNIT 0x1B
#define SCSIOP_STOP_PRINT 0x1B
#define SCSIOP_LOAD_UNLOAD 0x1B
#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C
#define SCSIOP_SEND_DIAGNOSTIC 0x1D
#define SCSIOP_MEDIUM_REMOVAL 0x1E
#define SCSIOP_READ_CAPACITY 0x25
#define SCSIOP_READ 0x28
#define SCSIOP_WRITE 0x2A
#define SCSIOP_SEEK 0x2B
#define SCSIOP_LOCATE 0x2B
#define SCSIOP_WRITE_VERIFY 0x2E
#define SCSIOP_VERIFY 0x2F
#define SCSIOP_SEARCH_DATA_HIGH 0x30
#define SCSIOP_SEARCH_DATA_EQUAL 0x31
#define SCSIOP_SEARCH_DATA_LOW 0x32
#define SCSIOP_SET_LIMITS 0x33
#define SCSIOP_READ_POSITION 0x34
#define SCSIOP_SYNCHRONIZE_CACHE 0x35
#define SCSIOP_COMPARE 0x39
#define SCSIOP_COPY_COMPARE 0x3A
#define SCSIOP_WRITE_DATA_BUFF 0x3B
#define SCSIOP_READ_DATA_BUFF 0x3C
#define SCSIOP_CHANGE_DEFINITION 0x40
#define SCSIOP_READ_SUB_CHANNEL 0x42
#define SCSIOP_READ_TOC 0x43
#define SCSIOP_READ_HEADER 0x44
#define SCSIOP_PLAY_AUDIO 0x45
#define SCSIOP_PLAY_AUDIO_MSF 0x47
#define SCSIOP_PLAY_TRACK_INDEX 0x48
#define SCSIOP_PLAY_TRACK_RELATIVE 0x49
#define SCSIOP_PAUSE_RESUME 0x4B
#define SCSIOP_LOG_SELECT 0x4C
#define SCSIOP_LOG_SENSE 0x4D
class ARCLIB_API WinScsiInterface : public ArcInterface
{
friend class CArclib;
public:
WinScsiInterface();
~WinScsiInterface();
bool init_physical_drive(const int pd);
bool init(const int scsi,const int ch = 0, const int id = 0, const int lun = 0);
int send(sIF_CMD_BLOCK *ifData);
int recv(sIF_CMD_BLOCK *ifData);
int syncSend(sIF_CMD_BLOCK *ifData);
int getMTU();
void *getDeviceHandle();
private:
HANDLE m_hScsi;
unsigned int nAddress;
};
#endif
+595
View File
@@ -0,0 +1,595 @@
#include "BaseSocket.h"
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define SOCKET_NOT_VALID -1
#define MAX_SEND_RETRY_COUNT 10 // Socket send 실패시 최대 재전송 시도 횟수.
/// @brief 생성자.
/// @param socket [in] 처리할 socket descriptor
CBaseSocket::CBaseSocket( const int& socket )
: m_sock( socket )
{
if( m_sock < 0 )
{
m_sock = SOCKET_NOT_VALID;
m_bConnected = false;
}
else
{
m_bConnected = true;
}
}
/// @brief 소멸자
CBaseSocket::~CBaseSocket()
{
// 소멸자 Socket 명시적 Close 처리.
Close();
}
/// @brief 소켓의 Close 처리를 수행함.
void CBaseSocket::Close()
{
m_bConnected = false;
if( m_sock != SOCKET_NOT_VALID )
{
close( m_sock );
m_sock = SOCKET_NOT_VALID;
}
}
/// @brief 전달받은 Target 으로 Socket 접속을 수행
/// @param szTarget [in] 접속 대상 Host name 또는 IP
/// @param nPort [in] 접속 Port
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool CBaseSocket::Connect( const std::string& szTarget, int nPort )
{
// 기존 접속을 Close 처리
Close();
unsigned int nHost = ConversionAddr( szTarget.c_str() );
if( nHost == INADDR_NONE )
{
LOG( LERR, "target host name resolve fail. [%s]->INADDR_NONE", szTarget.c_str());
return false;
}
struct sockaddr_in stTargetAddr;
m_sock = socket(AF_INET, SOCK_STREAM, 0);
if( m_sock == -1 )
{
int errorNum = errno;
LOG( LERR, "socket create failed.[%d][%s] Target:[%s]", errorNum, strerror(errorNum), szTarget.c_str() );
m_sock = SOCKET_NOT_VALID;
return false;
}
stTargetAddr.sin_family = AF_INET;
stTargetAddr.sin_addr.s_addr = nHost;
stTargetAddr.sin_port = htons( nPort );
// NEW 2012-05-18 huibong
// Connnection 종료시 많은 TIME_WAIT 상태 발생으로 인해 .. 이를 제거하기 위해 SO_LINGER 옵션을 설정처리한다.
struct linger opt_linger;
opt_linger.l_onoff = 1; /* LINGER ON */
// CHG 2014-05-27 huibong
// 아래와 같이 No Wait 로 처리할 경우... Server 역활 수행 중 Close 신호를 받지 못하는 경우가 발생 가능함.
// 따라서 5 sec 정도 대기하도록 수정 처리한다.
//opt_linger.l_linger = 0; /* No Wait => 0 for abortive disconnect */
opt_linger.l_linger = 5; // 5 sec 대기
int result = setsockopt( m_sock, SOL_SOCKET, SO_LINGER, &opt_linger, sizeof(opt_linger));
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "setsockopt func SO_LINGER set fail.[%d][%s]", errorNum, strerror(errorNum));
}
/* Send Timeout 설정. */
struct timeval tv_timeo = { 5, 0 };
result = setsockopt( m_sock, SOL_SOCKET, SO_SNDTIMEO, &tv_timeo, sizeof(tv_timeo));
if( result != 0 )
{
int errorNum = errno;
LOG( LERR, "setsockopt func SO_SNDTIMEO set fail.[%d][%s]", errorNum, strerror(errorNum));
}
if(connect(m_sock, (struct sockaddr *)&stTargetAddr, sizeof(stTargetAddr)) < 0 )
{
int errorNum = errno;
LOG( LERR, "connect fail.[%s][%d] [%d][%s]", szTarget.c_str(), nPort, errorNum, strerror( errorNum ) );
Close();
return false;
}
else
{
m_bConnected = true;
return true;
}
}
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
bool CBaseSocket::IsValidSocket()
{
if( m_sock != SOCKET_NOT_VALID && m_bConnected == true )
return true;
else
return false;
}
/// @brief m_sock 으로부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t CBaseSocket::Read( void * vptr, size_t size )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
while( (nRead = read( m_sock, vptr, size )) < 0 )
{
int errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2010-07-23 BUG huibong 잘못된 대입연산자를 비교연산자로 수정.
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
return nRead;
}
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t CBaseSocket::ReadN( void * vptr, size_t size )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
size_t nLeft = size;
char * ptr = (char *)vptr;
while( nLeft > 0 )
{
if( (nRead = read( m_sock, ptr, nLeft )) < 0 )
{
int errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
}
return size;
}
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류 , -2: Timeout
ssize_t CBaseSocket::ReadNTimeout( void * vptr, size_t size, int timeout )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
size_t nLeft = size;
char * ptr = (char *)vptr;
struct timeval timeOver;
int result;
fd_set selectFds;
FD_ZERO( &selectFds );
while( nLeft > 0 )
{
timeOver.tv_sec = timeout;
timeOver.tv_usec = 0;
FD_SET( m_sock, &selectFds );
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
if( result > 0 )
{
if( FD_ISSET( m_sock, &selectFds ))
{
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
{
int errorNum = errno;
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
}
}
else if( result == 0 ) // Timeout
{
//LOG( LDBG, "read timeout");
return -2;
}
else
{
int errorNum = errno;
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
return size;
}
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
ssize_t CBaseSocket::ReadNTimeout2( void * vptr, size_t size, int timeout )
{
if( IsValidSocket() == false )
return 0;
ssize_t nRead = 0;
size_t nLeft = size;
char * ptr = (char *)vptr;
int errorNum;
// 우선은 읽기 시도.
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
{
errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nRead = 0;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
// 만약 더 받을 데이터가 존재한다면.
if( nLeft > 0 )
{
struct timeval timeOver;
int result;
fd_set selectFds;
FD_ZERO( &selectFds );
while( nLeft > 0 )
{
timeOver.tv_sec = timeout;
timeOver.tv_usec = 0;
FD_SET( m_sock, &selectFds );
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
if( result > 0 )
{
if( FD_ISSET( m_sock, &selectFds ))
{
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
{
errorNum = errno;
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
{
nRead = 0;
continue;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
else if( nRead == 0 )
{
m_bConnected = false;
return 0;
}
nLeft -= nRead;
ptr += nRead;
}
}
else if( result == 0 ) // Timeout
{
//LOG( LDBG, "read timeout");
return -2;
}
else
{
errorNum = errno;
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
return -1;
}
}
}
return size;
}
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
/// @param size [in] write 하고자 하는 데이터의 크기.
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t CBaseSocket::WriteN( const void * vptr, size_t size )
{
if( IsValidSocket() == false )
return 0;
size_t nLeft;
ssize_t nWrite;
const char * ptr = (const char *)vptr;
nLeft = size;
int nTryCount = 0;
while( nLeft > 0 )
{
if( (nWrite = send( m_sock, ptr, nLeft, 0 )) < 0 )
{
int errorNum = errno;
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
{
nWrite = 0;
++nTryCount;
}
else if( errorNum == ECONNRESET || errorNum == EPIPE )
{
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
m_bConnected = false;
return 0;
}
else
{
LOG( LERR, "send func fail.[%d][%s]", errorNum, strerror(errorNum));
return -1;
}
}
else if( nWrite == 0 )
{
m_bConnected = false;
return 0;
}
if( nTryCount > MAX_SEND_RETRY_COUNT )
{
LOG( LERR, "send func failure due to exceeding count of retry[%d/%d]", nTryCount, MAX_SEND_RETRY_COUNT );
return 0 ;
}
nLeft -= nWrite;
ptr += nWrite;
}
return size;
}
// CHG 2011-05-03 huibong
// gethostbyname() 함수가 Thread Safe 하지 않기 때문에
// DNS resolve 처리시 잘못된 정보를 반환할 가능성이 존재
// 이에 따라 본 함수를 수정처리함.
/*
unsigned int CBaseSocket::ConversionAddr( const char * name )
{
struct hostent *he;
int max;
unsigned int retval;
if ((retval = inet_addr(name)) != INADDR_NONE)
return retval;
he = gethostbyname(name);
if (he == NULL)
return INADDR_NONE;
for (max = 0; he->h_addr_list[max]; max++) ;
if (max == 1)
return *((unsigned int *)(he->h_addr_list[0]));
else
return *((unsigned int *)(he->h_addr_list[random() % max]));
}
*/
unsigned int CBaseSocket::ConversionAddr( const char * name )
{
unsigned int retval;
struct addrinfo hints;
struct addrinfo *result = NULL;
int error;
// 전달받은 정보가 IP 주소인 경우...
// - DNS resolve 할 필요 없이 변환시킨 값을 그대로 사용한다.
if( (retval = inet_addr(name)) != INADDR_NONE )
return retval;
// getaddrinfo() 함수 호출을 위한 Hint 설정
memset( &hints, 0x00, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
// Thread Safe 한 DNS Resolve 처리함수 호출
// int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
// CHG 2014-11-14 huibong
// getaddrinfo 호출시 종종 EAI_NONAME 오류가 반환됨. (#20783)
// - 따라서 오류 반환시 재시도하도록 기능 추가
// CHG 2015-07-15 huibong
// usleep 의 multi thread 상에서 block 발생 가능
// - nanosleep 을 사용토록 변경 처리
for( int count = 0 ; count < 3; count++ )
{
error = getaddrinfo( name, NULL, &hints, &result );
// 오류 발생시
if( error != 0 )
{
if( result != NULL)
{
freeaddrinfo(result);
result = NULL;
}
// 잠시 대기 후 재시도 처리
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
}
else
{
// 정상 처리된 경우...
// - loop 탈출
break;
}
}
// 최종 오류 발생시
if( error != 0 )
{
LOG( LERR, "name[%s] dns resolve fail. getaddrinfo return error [%d][%s]", name, error, gai_strerror(error) );
return INADDR_NONE;
}
struct sockaddr_in * addr = (struct sockaddr_in *)result->ai_addr;
retval = (unsigned int)(addr->sin_addr.s_addr);
// DNS Resovle 결과 확인용 코드
/*
struct addrinfo *temp;
for( temp = result; temp; temp = temp->ai_next )
{
addr = (struct sockaddr_in *)temp->ai_addr;
printf ("getaddrinfo result = %s\n",inet_ntoa( addr->sin_addr));
}
*/
// getaddrinfo() 함수에서 생성한 메모리 영역 해제 처리.
freeaddrinfo(result);
return retval;
}
+118
View File
@@ -0,0 +1,118 @@
/***************************************************************************
BaseSocket ( Base Socket Class )
-----------------------------------------
begin : 2010/03/02
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __LIBRARY_BASE_SOCKET_H__
#define __LIBRARY_BASE_SOCKET_H__
#include <unistd.h>
#include <sys/types.h>
#include "Logger.h"
#define SOCKET_NOT_VALID -1
#define DEFAULT_DATA_RECEIVE_TIMEOUT 15 // sec
class CBaseSocket
{
protected:
/// @brief socket descriptor
int m_sock;
/// @brief socket 의 연결상태인지 여부를 저장하기 위한 변수.
bool m_bConnected;
public:
/// @brief 생성자.
CBaseSocket( const int & socket );
/// @brief 소멸자.
~CBaseSocket();
/// @brief 소켓의 Close 처리를 수행함.
void Close(void);
/// @brief 전달받은 Target 으로 Socket 접속을 수행
/// @param szTarget [in] 접속 대상 Host name 또는 IP
/// @param nPort [in] 접속 Port
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool Connect( const std::string& szTarget, int nPort );
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
bool IsValidSocket(void);
/// @brief 멤버변수인 socket 의 접속 상태 여부를 설정하기 위한 함수.
void SetConnectionStatus( bool bConnected) { m_bConnected = bConnected; }
/// @brief 현재 socket 의 접속 상태를 반환.
bool GetConnectionStatus( void) { return m_bConnected; }
//void SetLogger( Logger * pLog ) { m_pLog = pLog; }
protected:
/// @brief m_sock 로 부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t Read( void * vptr, size_t size );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t ReadN( void * vptr, size_t size );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
ssize_t ReadNTimeout( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
ssize_t ReadNTimeout2( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
public:
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
/// @param size [in] write 하고자 하는 데이터의 크기.
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t WriteN( const void * vptr, size_t size );
protected:
/// @brief 문자열로 전달받은 정보를 검사하여 IP 접속 정보를 생성한다.
unsigned int ConversionAddr( const char * name );
};
#endif /* __LIBRARY_BASE_SOCKET_H__ */
+238
View File
@@ -0,0 +1,238 @@
#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 );
// ${value} : 참조 값 찾기
pos = value.find( "${" );
if( pos != string::npos )
{
value = value.substr(pos+2);
pos = value.rfind("}");
if( pos != string::npos )
{
value = value.substr(0,pos);
pos = value.find( '.' );
if( pos != string::npos )
{
string ss = value.substr(0,pos);
string kk = value.substr(pos+1);
return GetConfig( ss, kk,value );
}
else
return false;
}
else
return false;
}
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;
}
+110
View File
@@ -0,0 +1,110 @@
/***************************************************************************
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;
}
/// @brief Key, Value Delimiter Set 함수
/// @param key [out] key delimiter 값
/// @param value [out] value delimiter 값, 지정하지 않을 경우 Default 값이 사용됨.
void SetDelimiter( string& key, string value = CONFIG_DEFAULT_VALUE_DELIMITER )
{
m_keyDelimiter = key;
m_valueDelimiter = value;
}
protected:
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
/// @param section [in] section 명
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
/// @return On success return true, otherwise return false
bool Find( const string& section, vector<string>& configData );
};
#endif /* __LIBRARY_CONFIG_H__ */
+487
View File
@@ -0,0 +1,487 @@
/***************************************************************************
Logger.cpp
-----------------------------------------
begin : 2011/10/26
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "Logger.h"
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <iostream>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define MAX_BUFFER_SIZE 2048 // 임시 버퍼 최대 크기
#define DEFAULT_LOG_LEVEL LINF
using namespace std;
CLogger* CLogger::m_pInstance = NULL;
bool CLogger::m_bIsInitialized = false;
pthread_mutex_t CLogger::m_mutex = PTHREAD_MUTEX_INITIALIZER;
CLogger::CLogger( string programName, string logDir, int logLevel )
{
m_szProgramName = programName;
m_szLogDir = logDir;
if( IsValidLogLevel( logLevel ) == true )
{
m_nLogLevel = logLevel;
}
else
{
m_nLogLevel = DEFAULT_LOG_LEVEL;
}
MakeLogLevelString();
}
void CLogger::MakeLogLevelString()
{
m_vectorLogLevelString.push_back( "EMR" );
m_vectorLogLevelString.push_back( "ALT" );
m_vectorLogLevelString.push_back( "CRT" );
m_vectorLogLevelString.push_back( "ERR" );
m_vectorLogLevelString.push_back( "WAR" );
m_vectorLogLevelString.push_back( "NOT" );
m_vectorLogLevelString.push_back( "INF" );
m_vectorLogLevelString.push_back( "DBG" );
m_vectorLogLevelString.push_back( "DEV" );
m_vectorLogLevelString.push_back( "DEV1" );
m_vectorLogLevelString.push_back( "DEV2" );
}
CLogger::~CLogger()
{
m_vectorLogLevelString.clear();
}
bool CLogger::Init( string programName, string logDir, int logLevel )
{
if( m_bIsInitialized == true )
{
return true;
}
pthread_mutex_lock( &m_mutex );
// 변수 유효성 검사.
if( programName.empty() == true || logDir.empty() == true )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( IsValidLogLevel( logLevel ) == false )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( MakeLogDir( programName, logDir ) == false )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( CLogger::m_pInstance != NULL )
{
delete CLogger::m_pInstance;
CLogger::m_pInstance = NULL;
}
CLogger::m_pInstance = new CLogger( programName, logDir, logLevel );
m_bIsInitialized = true;
pthread_mutex_unlock( &m_mutex );
return true;
}
bool CLogger::IsValidLogLevel( int logLevel )
{
return ( ( logLevel < 0 || logLevel > MAX_LOG_LEVEL ) ? false : true );
}
bool CLogger::SetLogLevel( int logLevel )
{
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
m_nLogLevel = logLevel;
return true;
}
bool CLogger::MakeLogDir( string programName, string logDir )
{
string path = logDir + "/" + programName;
struct stat dirStat;
// 해당 이름을 가진 파일 또는 디렉토리가 존재하고
if( lstat( path.c_str(), &dirStat ) == 0 )
{
// 해당 이름이 디렉토리인 경우
if( S_ISDIR( dirStat.st_mode ) == true )
{
return true;
}
else
{
cerr << "exist file with the same name as log path(" << path << ")." << endl;
return false;
}
}
// 디렉토리 가 존재하지 않는 경우 디렉토리 생성 시도
string cmd = "mkdir -p " + path;
system( cmd.c_str() );
if( IsDirectory( path ) == false )
{
cerr << "can't make log directory. path=" << path << "." << endl;
return false;
}
return true;
}
bool CLogger::IsDirectory( string path )
{
struct stat dirStat;
if( lstat ( path.c_str(), &dirStat ) != 0 )
{
cerr << "Log path not valid. Check path [" << path << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
// 해당 정보가 Directory 가 아닌 경우
if( S_ISDIR( dirStat.st_mode ) == false )
{
return false;
}
return true;
}
void CLogger::Exit()
{
if( m_bIsInitialized == false )
{
return;
}
pthread_mutex_lock( &m_mutex );
if( CLogger::m_pInstance != NULL )
{
delete CLogger::m_pInstance;
CLogger::m_pInstance = NULL;
m_bIsInitialized = false;
}
pthread_mutex_unlock( &m_mutex );
}
CLogger* CLogger::GetInstance()
{
return CLogger::m_pInstance;
}
string CLogger::GetLogFilename( struct tm &timeNow )
{
char timeStr[256];
snprintf( timeStr, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
// Make File Name
string filename = m_szLogDir + "/" + m_szProgramName + "/" + m_szProgramName + "_" + string( timeStr );
return filename;
}
bool CLogger::Write( int logLevel, const char * fmt, ...)
{
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
return Write( logLevel, PREFIX_DATE, NULL, 0, buffer );
}
bool CLogger::WriteNoPrefix( int logLevel, const char * fmt, ...)
{
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
return Write( logLevel, PREFIX_NONE, NULL, 0, buffer );
return false;
}
// CHG 2012-08-16 huibong
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
// 함수명 : Write -> WriteWithFunc 으로 변경 처리
bool CLogger::WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
{
if( filename == NULL || funcname == NULL || lineNum < 0 || fmt == NULL )
{
return false;
}
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
char className[255];
string funcPrefix = GetClassName( className, filename );
funcPrefix += "::" + string( funcname ) + "()";
return Write( logLevel, PREFIX_FUNCTION, funcPrefix.c_str(), lineNum, buffer );
}
const char* CLogger::GetClassName( char* className, const char* filename )
{
if( className == NULL )
{
cout << "[ERROR] The input argument 'className' is NULL." << endl;
return NULL;
}
if( filename == NULL )
{
cout << "[ERROR] The input argument 'filename' is NULL." << endl;
strcpy( className, "NULL" );
return className;
}
int filenameSize = strlen( filename );
memcpy( className, filename, filenameSize );
// find end position
char endCharacter = '.';
int endPos = filenameSize - 1;
for( ; endPos > 0; --endPos )
{
if( className[endPos] == endCharacter )
{
break;
}
}
if( endPos == 0 )
{
cout << "[ERROR] endPos=0" << endl;
strcpy( className, "NULL" );
return className;
}
className[endPos] = '\0';
// find start position
char startCharacter = '/';
int startPos = endPos - 1;
for( ; startPos > 0; --startPos )
{
if( className[startPos] == startCharacter )
{
break;
}
}
if( startPos != 0 )
{
startPos += 1;
}
return (className + startPos );
}
bool CLogger::Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log )
{
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
if( logLevel > m_nLogLevel )
{
return false;
}
if( log == NULL )
{
return false;
}
// Get Current Data & Time
time_t now = time( NULL );
struct tm timeNow;
localtime_r( &now, &timeNow );
string filename = GetLogFilename( timeNow );
// Log file open
FILE* pFile = NULL;
pFile = fopen( filename.c_str(), "a+" );
if( pFile == NULL )
{
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
// 시간 정보처리
char timeStr[256];
snprintf( timeStr, (size_t)256, "[%02d:%02d:%02d]"
, timeNow.tm_hour, timeNow.tm_min, timeNow.tm_sec );
// Log Level 문자열 검색
string szLevel = m_vectorLogLevelString[ logLevel ];
switch( logPrefix )
{
case PREFIX_DATE:
/// 형식 예: [15:47:41] [DBG] sample log message.
fprintf( pFile, "%s [%-4s] %s\n", timeStr, szLevel.c_str(), log );
break;
case PREFIX_FUNCTION:
if( functionName == NULL )
{
fclose( pFile );
return false;
}
/// 형식 예: [15:47:41] [DBG] sample log message. [SomeClass::SomeFunction():12]
fprintf( pFile, "%s [%-4s] %s [%s:%d]\n", timeStr, szLevel.c_str(), log, functionName, lineNum );
break;
case PREFIX_NONE:
/// 형식 예: sample log message.
fprintf( pFile, "%s\n", log );
break;
}
// Write to log file
fflush( pFile );
// 종료 처리.
fclose( pFile );
return true;
}
bool CLogger::WriteHex( int logLevel, const unsigned char* data, const int size )
{
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
if( logLevel > m_nLogLevel )
{
return false;
}
if( data == NULL )
{
return false;
}
if( size <= 0 )
{
return false;
}
// Get Current Data & Time
time_t now = time( NULL );
struct tm timeNow;
localtime_r( &now, &timeNow );
string filename = GetLogFilename( timeNow );
// Log file open
FILE* pFile = NULL;
pFile = fopen( filename.c_str(), "a+" );
if( pFile == NULL )
{
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
for( int i = 0; i < size; ++i )
{
fprintf( pFile, "%02X", data[i] );
if( i == 0 )
{
continue;
}
if( ( (i+1) % 8 ) == 0 )
{
fprintf( pFile, " " );
}
if( ( (i+1) % 16 ) == 0 )
{
fprintf( pFile, " " );
}
if( ( (i+1) % 32 ) == 0 )
{
fprintf( pFile, "\n" );
}
}
fprintf( pFile, "\n" );
fflush( pFile );
// 종료 처리.
fclose( pFile );
return false;
}
+273
View File
@@ -0,0 +1,273 @@
/***************************************************************************
Logger.h
-----------------------------------------
begin : 2011/10/26
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.2.0.805
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __LOGGER_H__
#define __LOGGER_H__
#include <string>
#include <vector>
#include <pthread.h>
///@brief 로그 레벨 정의
#define LEMR 0 /* system is or will be unusable if situation is not resolved */
#define LALT 1 /* immediate action required */
#define LCRT 2 /* critical situations */
#define LERR 3 /* error conditions */
#define LWAR 4 /* recoverable errors */
#define LNOT 5 /* unusual situation that merits investigation */
#define LINF 6 /* information messages */
#define LDBG 7 /* verbose data for debugging */
#define LDEV 8 /* verbose data for developer */
#define LDEV1 9 /* start or end the function of application level */
#define LDEV2 10 /* start or end the function of application level */
#define MAX_LOG_LEVEL LDEV2
///@brief Log 정보를 파일로 저장하기 위한 Class.
///1. 가변 format 으로 전달된 로그 관련 정보를 Log Level 에 따라 로그 파일에 아래의 4가지 형식으로 저장한다.
///
/// 1.1 Prefix로 [hh:mm:ss]와 [ClassName::FunctionName]이 추가된 로그
/// LOG( level, format, ... ) 매크로 사용.
/// 예) [17:43:40] [DBG] log level debug [LoggerTestTestLogger]
///
/// 1.2 Prefix로 [hh:mm:ss]이 추가된 로그
/// _LOG( level, format, ... ) 매크로 사용
/// 예) [17:43:40] [EMR] log level emergency
///
/// 1.3 Prefix가 없는 로그
/// _LOG_( level, format, ... ) 매크로 사용
/// 예) log level emergency
///
/// 1.4 Hex 로그.
/// LOG_HEX( level, data, size ) 매크로 사용
/// 예) 00010203 04050607 08090A0B 0C0D0E0F
///
///2. Logger 객체 초기화시 전달된 Log Level 정보보다 전달받은 Log Level 정보가 큰 경우 해당 로그는 파일로 저장되지 않는다.
///
///3. 로그 파일은 매 일단위로 저장파일이 변경된다.
///
///4. 로그 저장을 위한 program 경로가 존재하지 않는 경우 자동 생성 처리된다.
///
///5. 로그 저장방식은 매 저장로그마다 open-close 로 처리된다.
///
///6. 파일로 기록시 Log Level 에 대한 정보도 함께 기록된다.
///
///7. 싱글톤으로 작성되었고, CLogger::Init(...)시에 쓰레드 안정성을 제공한다.
///
///8. 동적으로 로그 레벨을 변경할 수 있는 인터페이스를 제공한다.
///
class CLogger
{
// Attributes
private:
///@brief 싱글톤 객체 인트턴스.
static CLogger* m_pInstance;
///@brief 싱글톤 객체 초기화 여부.
static bool m_bIsInitialized;
///@brief 싱글톤 객체 초기화시 스레드 안정성을 위한 뮤텍스.
static pthread_mutex_t m_mutex;
///@brief 프로그램 이름. 로그 파일 경로를 만들 때 사용.
std::string m_szProgramName;
///@brief 공통 로그 디렉토리 이름. 로그 파일 경로를 만들 때 사용.
std::string m_szLogDir;
///@brief 로그 레벨.
int m_nLogLevel;
///@brief 로그 레벨에 대응되는 문자열 정보를 저장.
std::vector<std::string> m_vectorLogLevelString;
protected:
public:
///@brief 로그 형식을 지정.
typedef enum
{
PREFIX_NONE = 0, /// 클래스 설명의 1.3에 해당
PREFIX_DATE, /// 클래스 설명의 1.2에 해당
PREFIX_FUNCTION, /// 클래스 설명의 1.1에 해당
} LOG_PREFIX;
// Operations
private:
///@brief 생성자.
/// 프로그램 이름, 공통 로그 디렉토리, 로그 레벨을 저장하고
/// 로그 레벨에 대응되는 문자열 정보를 만든다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@param logLevel [in] 로그 레벨
CLogger( std::string programName, std::string logDir, int logLevel );
///@brief 소멸자.
/// 로그 레벨에 대응되는 문자열 정보를 저장하고 있는
/// 벡터 m_vectorLogLevelString을 clear 시킴.
virtual ~CLogger();
///@brief 로그 레벨에 대응되는 문자열을 만든다.
///@param none.
///@return none.
void MakeLogLevelString();
///@brief 로그 파일이 위치할 실제 로그 디렉토리를 생성한다.
/// 생성할 디렉토리 경로는 'logDir/programName'이 된다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@return 디렉토리가 이미 존재하거나 생성 성공하면 true,
/// 해당 경로가 존재하지만 디렉토리가 아니거나, 디렉토리 생성 실패하면 false 반환.
static bool MakeLogDir( std::string programName, std::string logDir );
///@brief 해당 경로가 디렉토리 인지 아닌지 판단.
///@param path [in] 디렉토리 인지 아닌지 판단할 경로.
///@return 해당 경로가 디렉토이면 true,
/// 경로가 존재하지 않거나 디렉토리가 아니면 false 반환.
static bool IsDirectory( std::string path );
///@brief 로그 레벨이 올바른지 판별.
///@param logLevel [in]
///@return 올바른 로그 레벨이면 true, 그렇지 않으면 false 반환.
static bool IsValidLogLevel( int logLevel );
///@brief 시간 정보를 입력 받아 로그 파일 이름을 만든다.
/// 로그 파일 이름 형식 : 프로그램명_YYYYMMDD.log
///param timeNow [in] 현재 시간 정보.
///return 로그 파일 이름.
std::string GetLogFilename( struct tm &timeNow );
///@brief 로그를 남기는는 클래스가 정의된 파일의 이름에서 클래스명을 추출한다.
/// 쓰레드 안정성을 보장한다.
///@param className [out] 파일 이름에서 추출된 클래스명
///@param filename [in] 파일 이름.
///@return 클래스명 추출이 성공하면 클래스명 문자열의 포인터, 추출 실패하면 NULL.
const char* GetClassName( char* className, const char* filename );
///@brief 인자 logPrefix에 따라 적절한 형식으로 로그 파일에 로그를 저장한다.
/// 인자 logLevel이 설정된 로그 레벨보다 높으면 로그를 출력하지 않는다.
///@param logLevel [in] 로그 레벨
///@param logPrefix [in] 로그 프리픽스 종류.
///@functionName [in] ClassName::FunctionNmae() 형식의 문자열.
///@lineNum [in] 라인 번호.
///@log [in] 출력하고자 하는 로그 내용.
bool Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log );
protected:
public:
///@brief 싱글톤 객체 m_pInstance를 생성하고 인자 정보로 로그 디렉토리를 만든다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@param logLevel [in] 로그 레벨
///@return 로그 디렉토리를 만들고 싱글톤 객체를 생성했으면 true,
/// 로그 디렉토리를 만들지 못 했거나 인자 값이 올바르지 않으면 false 반환.
static bool Init( std::string programName, std::string logDir, int logLevel );
///@brief 싱글톤 객체 m_pInstance를 delete 한다.
///@param none.
///@return none.
static void Exit();
///@brief 싱글톤 객체 m_pInstance를 반환한다.
///@param none.
///@return CLogger 객체의 인스턴스.
static CLogger* GetInstance();
///@brief Prefix로 [hh:mm:ss]이 추가된 형식으로 로그 저장.
///@param logLevel [in] 로그 레벨
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool Write( int logLevel, const char * fmt, ...)
__attribute__((format(printf, 3, 4)));
///@brief Prefix가 없는 로그 저장.
///@param logLevel [in] 로그 레벨
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteNoPrefix( int logLevel, const char * fmt, ...)
__attribute__((format(printf, 3, 4)));
// CHG 2012-08-16 huibong
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
///@brief Prefix로 [hh:mm:ss]와 [ClassName::FunctionName:line]이 추가된 형식으로 로그 저장.
///@param logLevel [in] 로그 레벨
///@param filename [in] 파일 이름
///@param funcname [in] 함수 이름
///@param lineNum [in] 라인 번호
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
__attribute__((format(printf, 6, 7)));
///@brief 로그를 hex 형식으로 저장.
///@param logLevel [in] 로그 레벨
///@param data [in] hex 형식으로 출력할 데이터.
///@pram size [in] data의 크기.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteHex( int logLevel, const unsigned char* data, const int size );
///@brief 로그을 설정한다. 인자 logLevel이 적절한 값이면 새로운 값으로 변경하고
/// 적절한 값이 아니면 로그 레벨을 변경하지 않는다.
///@param logLevel [in] 설정할 로그 레벨
///@return none.
bool SetLogLevel( int logLevel );
inline int GetLogLevel() { return m_nLogLevel; };
inline std::string GetLogDir() { return m_szLogDir + "/" + m_szProgramName; };
};
#define LOG( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteWithFunc( level, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__ ); \
}
#define _LOG( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->Write( level, format, ##__VA_ARGS__ ); \
}
#define _LOG_( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteNoPrefix( level, format, ##__VA_ARGS__ ); \
}
#define _LOG_HEX_( level, data, size ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteHex( level, (const unsigned char*)data, size ); \
}
#define FUNC_BEGIN() LOG( LDEV1, "begin" )
#define FUNC_END() LOG( LDEV1, "end" )
#define FRM_BEGIN() LOG( LDEV2, "begin" )
#define FRM_END() LOG( LDEV2, "end" )
#endif // __LOGGER_H__
+62
View File
@@ -0,0 +1,62 @@
#****************************************************************************
# Makefile for INTERACTIVE Common Libaray
# -----------------------------------------
#
# begin : 2010/02/27
# copyright : (C) 2005 SolutionBox Inc.
# author : Service 1 Team
# email : svc1@solbox.com
# version : 1.0
#
# CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
# Redistribution and use in source and binary forms, with or with out
# modification, are not permitted in outside of SolutionBox Inc.
#*****************************************************************************
# Library info
LIB_NAME = InterCommon
LIB = lib$(LIB_NAME).a
OBJS = 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
+415
View File
@@ -0,0 +1,415 @@
#include "ArecaWrapper.h"
#include <vector>
#include <time.h>
#define MAX_EVENT_BUFF_SIZE 512
#define UNKNOWN_EVT_STR "Unknown Event"
CArecaWrapper::CArecaWrapper(int nEventLevel)
: m_nEventLevel( nEventLevel )
{
pthread_mutex_init(&mutex_lock, NULL);
}
CArecaWrapper::~CArecaWrapper()
{
pthread_mutex_destroy(&mutex_lock);
int nInterfaceIndex;
CArclib *ctrl;
for (nInterfaceIndex =0; nInterfaceIndex < m_nTotalCtrl; nInterfaceIndex++)
{
ctrl = &m_Arc[nInterfaceIndex];
LinuxIoctlInterface *out = (LinuxIoctlInterface*)ctrl->ArcGetInterface();
delete out;
}
}
// libacrlib에서 사용하는 pSYS_TIME 타입의 값을 time_t로 변환한다.
time_t CArecaWrapper::GetTime_t(pSYS_TIME evtTime)
{
/*
tm tmpTime;
tmpTime.tm_year = evtTime->u.tmYear+100;
tmpTime.tm_mon = evtTime->u.tmMonth-1;
tmpTime.tm_mday = evtTime->u.tmDate;
tmpTime.tm_hour = evtTime->u.tmHour;
tmpTime.tm_min = evtTime->u.tmMinute;
tmpTime.tm_sec = evtTime->u.tmSecond;
return mktime(&tmpTime);
*/
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = gmtime ( &rawtime );
timeinfo->tm_year = evtTime->u.tmYear+100;
timeinfo->tm_mon = evtTime->u.tmMonth-1;
timeinfo->tm_mday = evtTime->u.tmDate;
timeinfo->tm_hour = evtTime->u.tmHour;
timeinfo->tm_min = evtTime->u.tmMinute;
timeinfo->tm_sec = evtTime->u.tmSecond;
timeinfo->tm_isdst = 0; // disable daylight saving time
time_t ret = mktime ( timeinfo );
return ret;
}
/*
bool CArecaWrapper::DisableUpload()
{
system( "touch /user/service/vmasd.disable" );
struct stat st;
if( lstat( "/user/service/vmasd.disable", &st ) != 0 )
{
ERROR_LOG( "can't touch vmasd.disable" );
return false;
}
INFO_LOG( "disable upload." );
return true;
}
bool CArecaWrapper::IsDisableUpload( int eventCategory, int eventId )
{
switch( eventCategory )
{
case EVENT_DEVICE: // device event
/// The meaning of eventId
/// 0 : Device Inserted
/// 1 : Device Removed
/// 2 : Reading Error
/// 3 : Writing Error
/// 4 : ATA Ecc Error
/// 5 : Change ATA Mode
/// 6 : Time Out Error
/// 7 : Device Failed
/// 8 : PCI Parity Error
/// 9 : Dev Fail (SMART)
/// 10 : Pass
case EVENT_VOLUMESET: // volumeset event
case EVENT_RAIDSET: // raidset event
}
}
*/
//int CArecaWrapper::GetEvent(int nEventFlag, char *pszResult)
bool CArecaWrapper::GetEvent(int nEventFlag, list<CEventData>& listRet)
{
CArclib *ctrl;
ARC_STATUS stat = ARC_SUCCESS;
bool gotEvent = false;
int nCount = 0; // total number of event objects we got
int i;
int nCurEvtLevel = EVT_SERIOUS;
sSYSTEM_INFO sysInfo;
BYTE ptr1[64];
char tmpStr[64];
char eventStrBuf[MAX_EVENT_BUFF_SIZE];
int eventCategory = 0;
int eventId = 0;
//the time event occurred, defined in arclib.h
pSYS_TIME evtTime = (pSYS_TIME)new sSYS_TIME;
pthread_mutex_lock(&mutex_lock);
if (m_nTotalCtrl == 0) {
LOG(LERR, "No Raild controller was found.");
pthread_mutex_unlock(&mutex_lock);
if( evtTime )
{
delete evtTime;
}
return false;
}
ctrl = &m_Arc[0];
memset(ptr1, 0, sizeof(ptr1));
memset(tmpStr, 0, sizeof(tmpStr));
memset(eventStrBuf, 0, sizeof(eventStrBuf));
// event object defined in arclib.h
pEVENT_DATA pEventObject = (pEVENT_DATA)new sEVENT_DATA;
stat = ctrl->ArcGetSysInfo(&sysInfo);
if( stat != ARC_SUCCESS )
{
LOG(LERR, "ArcGetSysInfo Failed: %d",stat);
pthread_mutex_unlock(&mutex_lock);
if( pEventObject )
{
delete pEventObject;
}
if( evtTime )
{
delete evtTime;
}
return false;
}
/* We should call ArcSetTime() to correct the raid-subsystem time
Call ArcGetReqEventPage() to get the required event page from raid subsystem.
There are 4 event pages reside in the raid subsystem and each contains 16 event objects.
*/
memset(pEventObject, 0, sizeof(sEVENT_DATA));
stat = ctrl->ArcGetReqEventPage(nEventFlag, &nCount);
if (stat == ARC_SUCCESS)
{
if (nCount != 0)
{
for ( i = nCount - 1; i >= 0; i--)
{
// Call ArcGetEventObject function to extract the individual event object from event page
if (ctrl->ArcGetEventObject( i, pEventObject ))
{
::memset(eventStrBuf, 0, MAX_EVENT_BUFF_SIZE);
eventCategory = (int)pEventObject->evtCategory;
eventId = pEventObject->evtType;
*((LONG *)evtTime) = pEventObject->evtTime;
// Parse the event object we got
switch ((int)pEventObject->evtCategory)
{
/*
The member "evtStr" of event object structure contains the string to indicate
which raidset owns this event object
*/
case EVENT_RAIDSET: // raidset event
nCurEvtLevel = pEventObject->evtType;
memcpy(tmpStr, pEventObject->evtStr, 16);
if ( nCurEvtLevel > RS_EVT_NO_EVENT )
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmRaidEvent[pEventObject->evtType]);
}
sprintf((char *)eventStrBuf, "Controller#%d: %s %s",1, tmpStr, ptr1);
gotEvent = true;
break;
/*
The member "evtStr" of event object structure contains the string to indicate
which volumeset owns this event object
*/
case EVENT_VOLUMESET: // volumeset event
nCurEvtLevel = pEventObject->evtType;
memcpy(tmpStr, pEventObject->evtStr, 16);
if ( nCurEvtLevel >= VS_EVT_TOTALS)
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmVolEvent[pEventObject->evtType]);
}
sprintf((char *)eventStrBuf, "Controller#%d: %s %s", 1, tmpStr, ptr1);
gotEvent = true;
break;
case EVENT_DEVICE: // device event
nCurEvtLevel = pEventObject->evtType;
if( sysInfo.gsiTargetType == TARGET_SAS )
{
memcpy(tmpStr, pEventObject->evtStr, 16);
}
else
{
sprintf(tmpStr, "IDE Channel #%2d", pEventObject->evtChannel + 1);
}
if ( nCurEvtLevel >= DEV_EVT_TOTALS)
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmDevEvent[pEventObject->evtType]);
}
sprintf((char *)eventStrBuf, "Controller#%d: %s %s", 1
, tmpStr, ptr1 );
gotEvent = true;
break;
case EVENT_HOST: // host event
//this is Host SCSI events
nCurEvtLevel = pEventObject->evtType;
if ( sysInfo.gsiScsiHostChannels)
{
if ( nCurEvtLevel >= SCSI_EVT_TOTALS )
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmScsiHostEvent[pEventObject->evtType]);
}
} else {
if ( nCurEvtLevel >= SCSI_EVT_TOTALS )
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmIdeHostEvent[pEventObject->evtType]);
}
}
// CHG 2020-10-05 huibong FreeBSD 12.x 컴파일시 발생하는 warning 코드 수정 (#33225)
// - FreeBSD 12.x 의 gcc 9.3 컴파일시 sprintf 사용 관련 buffer size 문제로 warning 발생
// - flow 상으로는 buffer overflow 발생 가능성 없음
// - 하지만.. 컴파일시마다 warning 발생하므로.. 수정 결정
sprintf((char *)eventStrBuf, "Controller#%d: %s %s", 1, eventCat[pEventObject->evtCategory], ptr1 );
gotEvent = true;
break;
case EVENT_HW_MONITOR: // hardware monitor event
nCurEvtLevel = pEventObject->evtType;
memcpy(tmpStr, eventCat[pEventObject->evtCategory], 16);
if ( nCurEvtLevel >= HW_EVT_TOTALS )
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmHwMonEvent[pEventObject->evtType]);
}
sprintf((char *)eventStrBuf, "Controller#%d: %s %s", 1
, tmpStr, ptr1 );
gotEvent = true;
break;
case EVENT_NEW_83782D:
memcpy(tmpStr, pEventObject->evtStr, 16);
if ( pEventObject->evtType >= GHM_TOTALS )
{
strcpy( (char *)ptr1, UNKNOWN_EVT_STR);
}
else
{
strcpy( (char *)ptr1, htmNewEventStr[pEventObject->evtType]);
}
sprintf((char *)eventStrBuf, "Controller#%d: %s %s",1
, tmpStr, ptr1 );
gotEvent = true;
break;
case EVENT_NO_EVENT:
// 이벤트가 없는 경우
gotEvent = true;
default:
continue;
}// end switch
}// end if
// 모든 이벤트를 결과 list에 추가필요 수정 2015-06-26
CEventData objEvent;
objEvent.m_evtTime = GetTime_t(evtTime);
objEvent.m_szEventData = eventStrBuf;
objEvent.SetEventType( eventCategory, eventId );
listRet.push_back(objEvent);
}// end for
} else {
_LOG(LWAR, "Event empty.");
gotEvent = true;
}
}// end if
if (pEventObject) {
delete pEventObject;
}
if (evtTime) {
delete evtTime;
}
pthread_mutex_unlock(&mutex_lock);
return gotEvent;
}
int CArecaWrapper::DiscoveryDevice(void)
{
dev_t dev;
char buf[64];
mode_t mode = 0666;
unsigned int nTotalCtrl = 0;
ARC_STATUS stat = ARC_SUCCESS;
sSYSTEM_INFO sysInfo;
mode |= S_IFCHR;
for (int i = 0; i < 4; i++) {
memset(buf, 0, sizeof(buf));
sprintf(buf,"/dev/arcmsr%d", i);
unlink(buf);
}
for (int mymajor = 255; mymajor > 161; mymajor--)
{
for (int myminor = 0; myminor < 4; myminor++)
{
LinuxIoctlInterface *out = new LinuxIoctlInterface();
memset(buf, 0, sizeof(buf));
sprintf(buf,"/dev/arcmsr%d", nTotalCtrl);
dev = makedev(mymajor, myminor);
mknod(buf, mode, dev);
if (out->init(nTotalCtrl)) {
stat = m_Arc[nTotalCtrl++].ArcInitSession(out);
if (stat != ARC_SUCCESS) {
_LOG(LERR, "ArcInitSession Failed : %d",stat);
if( out )
{
delete out;
out = NULL;
}
unlink(buf);
return 0;
}
} else {
delete out;
out = NULL;
unlink(buf);
}
}
if (nTotalCtrl) {
break;
}
}
return nTotalCtrl;
}
int CArecaWrapper::InitArecaControllers(void)
{
int nCount = 0;
int nInterfaceIndex = 0;
m_nTotalCtrl = DiscoveryDevice();
_LOG(LDBG, "Total Count: %d", m_nTotalCtrl);
if(m_nTotalCtrl == 0)
{
return -1;
}
for (nInterfaceIndex =0; nInterfaceIndex < m_nTotalCtrl; nInterfaceIndex++)
{
m_Arc[nInterfaceIndex].ArcGetReqEventPage(FLAG_ALL, &nCount);
}
return m_nTotalCtrl;
}
+94
View File
@@ -0,0 +1,94 @@
/***************************************************************************
Areca Wrapper Class
-----------------------------------------
begin : 2010/05/19
copyright : (C) 2010 SolutionBox Inc.
author : svc1
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2010 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __ARECA_WRAPPER__
#define __ARECA_WRAPPER__
#include <algorithm>
#include <iostream>
// 가장 중요하고 핵심적인 헤더 파일
#include "arclib.h"
#include "ethernet.h"
#include "EventData.h"
#include <list>
#include "Logger.h"
using namespace std;
// 필요한 인터페이스에 대한 헤더파일
#if defined(__linux__) || defined(__FreeBSD__)
#include "linux_comm.h"
#include "linux_ioctl.h"
#if defined(__linux__)
#include "linux_scsi.h"
#include "linux_pass_ioctl.h"
#else
#include "freebsd_scsi.h"
#endif
#endif
// 정보를 조회할 최대 컨트롤 수.
#define MAX_CONTROLLER_SUPPORTED 64
// for GetEvent()'s first param
#define GET_EVENT_ALL 0
#define GET_EVENT_ONE 1
class CArecaWrapper
{
public:
/// @brief 생성자.
/// @param nEventLevel [in] 필터 할 이벤트 레벨을 지정한다. conf를 통해 받아오게 되며, 레벨은 아래와 같다.
///< -------- EVENT LEVEL ---------
///< 0: Not to report
///< 1: Serious Error Notification
///< 2: Error Notification
///< 3: Warning Notification
///< 4: Information Notification
///< ------------------------------
CArecaWrapper(int nEventLevel);
/// @brief 소멸자.
~CArecaWrapper();
/// @brief Areca Controller의 정보를 얻을 준비를 한다.
// @return Areca Controller의 개수를 리턴한다. 없을 경우 -1을 리턴한다.
int InitArecaControllers(void);
/// @brief Areca Controller의 정보를 얻을 준비를 한다.
/// @param nFlag [in] 이벤트 받을 형태를 지정한다.
//< GET_EVENT_ALL : 저장된 모든 이벤트 데이터를 수신한다.
//< GET_EVENT_ONE : 최근 1개의 이벤트 데이터를 수신한다.
/// @param listRet [out] Areca Library를 통해 얻은 데이터를 저장한다. 데이터의 타입은 CEventData 형태이다.
/// @return 성공시 true, 실패시 false 를 리턴한다.
bool GetEvent(int nFlag, list<CEventData>& listRet);
private:
CArclib m_Arc[MAX_CONTROLLER_SUPPORTED];
pthread_mutex_t mutex_lock;
int DiscoveryDevice(void);
time_t GetTime_t(pSYS_TIME evtTime);
int m_nEventLevel;
int m_nTotalCtrl;
//bool IsDisableUpload( int eventCategory, int eventId );
//bool DisableUpload();
};
#endif // __ARECA_WRAPPER__
+127
View File
@@ -0,0 +1,127 @@
/***************************************************************************
AutoDisableUpload.cpp
-----------------------------------------
begin : 2011/07/26
copyright : (C) 2010 SolutionBox Inc.
author : svc1
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2010 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "AutoDisableUpload.h"
using namespace std;
CAutoDisableUpload::CAutoDisableUpload()
{
}
CAutoDisableUpload::~CAutoDisableUpload()
{
}
void CAutoDisableUpload::DoProcess( int eventCategory, int eventId )
{
if( IsDisableUpload( eventCategory, eventId ) == false )
{
return;
}
system( "touch /user/service/vmasd.disable" );
struct stat st;
if( lstat( "/user/service/vmasd.disable", &st ) != 0 )
{
LOG(LERR, "can't touch vmasd.disable. event category = %s, event name = %s",
m_szEventCategory.c_str(), m_szEventName.c_str() );
return;
}
_LOG(LINF, "disable upload. event category = %s, event name = %s",
m_szEventCategory.c_str(), m_szEventName.c_str() );
}
bool CAutoDisableUpload::IsDisableUpload( int eventCategory, int eventId )
{
switch( eventCategory )
{
case EVENT_DEVICE:
/// The meaning of eventId.
/// 0(DEV_EVT_ADDED) - Device Inserted
/// 1(DEV_EVT_REMOVED) - Device Removed
/// 2(DEV_EVT_READ_ERROR) - Reading Error
/// 3(DEV_EVT_WRITE_ERROR) - Writing Error
/// 4(DEV_EVT_ATA_ECC_ERROR) - ATA Ecc Error
/// 5(DEV_EVT_ATA_CHANGE_MODE) - Change ATA Mode
/// 6(DEV_EVT_TIMEOUT) - Time Out Error
/// 7(DEV_EVT_MARK_FAILED) - Device Failed
/// 8(DEV_EVT_PCI_ERROR) - PCI Parity Error
/// 9(DEV_EVT_SMART_FAILED) - Dev Fail (SMART)
/// 10(DEV_EVT_CREATE_PASS) - Pass Through Disk Created
/// 11(DEV_EVT_MODIFY_PASS) - Pass Through Disk Modified
/// 12(DEV_EVT_DELETE_PASS) - Pass Through Disk Deleted
m_szEventCategory = "Device Event";
m_szEventName = htmDevEvent[ eventId ];
return ( eventId == DEV_EVT_MARK_FAILED ? true : false );
case EVENT_VOLUMESET:
/// The meaning of eventId.
/// 0(VS_EVT_INITIALIZING) - Start Initialize
/// 1(VS_EVT_REBUILDING) - Start Rebuilding
/// 2(VS_EVT_MIGRATING) - Start Migrating
/// 3(VS_EVT_CHECKING) - Start Checking
/// 4(VS_EVT_COMPLETE_INIT) - Complete Init
/// 5(VS_EVT_COMPLETE_REBUILD) - Complete Rebuild
/// 6(VS_EVT_COMPLETE_MIGRATING) - Complete Migrate
/// 7(VS_EVT_COMPLETE_CHECKING) - Complete Check
/// 8(VS_EVT_CREATE) - Create Volume
/// 9(VS_EVT_DELETE) - Delete Volume
/// 10(VS_EVT_MODIFY) - Modify Volume
/// 11(VS_EVT_DEGRADED) - Volume Degraded
/// 12(VS_EVT_FAILED) - Volume Failed
/// 13(VS_EVT_REVIVED) - Failed Volume Revived
/// 14(VS_EVT_ABORT_INIT) - Abort Initialization
/// 15(VS_EVT_ABORT_REBUILD) - Abort Rebuilding
/// 16(VS_EVT_ABORT_MIGRATING) - Abort Migration
/// 17(VS_EVT_ABORT_CHECKING) - Abort Checking
/// 18(VS_EVT_STOP_INIT) - Stop Initialization
/// 19(VS_EVT_STOP_REBUILD) - Stop Rebuilding
/// 20(VS_EVT_STOP_MIGRATING) - Stop Migration
/// 21(VS_EVT_STOP_CHECKING) - Stop Checking
m_szEventCategory = "VolumeSet Event";
m_szEventName = htmVolEvent[ eventId ];
return ( ( eventId == VS_EVT_REBUILDING ) || ( eventId == VS_EVT_DEGRADED ) ? true : false );
case EVENT_RAIDSET:
/// The meaning of eventId
/// 0(RS_EVT_CREATE) - Create RaidSet
/// 1(RS_EVT_DELETE) - Delete RaidSet
/// 2(RS_EVT_EXPAND) - Expand RaidSet
/// 3(RS_EVT_REBUILD) - Rebuild RaidSet
/// 4(RS_EVT_DEGRADED) - RaidSet Degraded
m_szEventCategory = "RaidSet Event";
m_szEventName = htmRaidEvent[ eventId ];
return ( ( eventId == RS_EVT_REBUILD ) || ( eventId == RS_EVT_DEGRADED ) ? true : false );
/// for test code
///case EVENT_NEW_83782D:
/// m_szEventCategory = "New Events";
/// m_szEventName = htmNewEventStr[ eventId ];
/// return ( eventId == GHM_GUI_LOGIN ? true : false );
default:
m_szEventCategory = "";
m_szEventName = "";
}
return false;
}
+57
View File
@@ -0,0 +1,57 @@
/***************************************************************************
AutoDisableUpload.h
-----------------------------------------
begin : 2011/07/26
copyright : (C) 2010 SolutionBox Inc.
author : svc1
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2010 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __AUTODISABLEUPLOAD_H__
#define __AUTODISABLEUPLOAD_H__
#include "arclib.h"
#include "Logger.h"
#include <string>
class CAutoDisableUpload
{
// Attributes
private:
std::string m_szEventCategory;
std::string m_szEventName;
protected:
public:
// Operations
private:
/// @brief 업로드 방지 이벤트 발생 여부 확인.
/// @param eventCategory [in] 이벤트 카테고리
/// @param eventId [in] 이벤트 카테고리별 이벤트 아이디
/// @return 업로드 방지 이벤트면 true, 그렇지 않으면 false.
bool IsDisableUpload( int eventCategory, int eventId );
protected:
public:
CAutoDisableUpload();
virtual ~CAutoDisableUpload();
/// @brief 업로드 방지 이벤트가 발생했으면 /user/service/vmasd.disable 파일을 생성해서
/// 업로드가 방지 되도록 한다.
/// @param eventCategory [in] 이벤트 카테고리
/// @param eventId [in] 이벤트 카테고리별 이벤트 아이디
/// @return 없음.
void DoProcess( int eventCategory, int eventId );
};
#endif // __AUTODISABLEUPLOAD_H__
+257
View File
@@ -0,0 +1,257 @@
#include "fhs_raidmond.h"
#include "Child.h"
#include "SmsSender.h"
#include "ArecaWrapper.h"
#include "UdpListener.h"
#include "EventDataManager.h"
#include "AutoDisableUpload.h"
#define MAXSIZEOFSTR 128
/// @brief child Process 종료 Signal 을 전달받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigTermChild( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
_LOG( LWAR, "Child Process[%d] exit job start by user signal [SIGTERM]", getpid() );
}
else
{
_LOG(LWAR, "Child Process[%d] exit job start by abnormal signal [%d]", getpid(), nSignalNumber );
}
_LOG(LWAR, "Child Process[%d] exit job end. Good Bye..", getpid());
usleep(500000);
exit( EXIT_SUCCESS );
}
/// @brief child Process 에서 Core 생성 관련 Signal 을 받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigCoreChild( int nSignalNumber )
{
_LOG(LERR, "Child Process[%d] abnoraml exit. Check Core file. Receive signal [%d]", getpid(), nSignalNumber );
//ERROR_LOG( "Core file path : [%s/%s.core]", g_envConfig.szLogDir.c_str(), PROG_NAME );
// Process 종료관련 작업 추가
// Log Directory 상에 Core 파일 생성처리.
chdir( g_envConfig.szLogDir.c_str() );
signal( nSignalNumber, SIG_DFL );
// Core dump 생성을 위한 신호 발생처리.=> ?
raise( nSignalNumber );
}
/// @brief child process signal 처리 설정을 위한 함수
/// @return void
static void SetSignalChild( void )
{
sigset_t set;
struct sigaction act;
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
memset( &act, 0x00, sizeof(act) );
sigfillset( &act.sa_mask );
/* 무시할 신호 목록 */
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL); /* 파이프 디스크립터 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP , &act, NULL); /* Process를 기동시킨 관리자의 로그아웃시 발생 시그널 */
sigaction( SIGINT , &act, NULL); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
// Child 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
sigaction( SIGCHLD, &act, NULL);
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SigTermChild;
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
/* Core 관련 signal 처리 : 오류 처리 및 Debug(core dump) 목적 */
// dadamin : 팀 기준 적용
//act.sa_handler = SigCoreChild;
//sigaction( SIGILL , &act, NULL); /* Illegal instruction */
//sigaction( SIGFPE , &act, NULL); /* Erroneout arithmetic operation */
//sigaction( SIGBUS , &act, NULL); /* Access to undefined portion of a memory object */
//sigaction( SIGSEGV, &act, NULL); /* Invalid memory reference */
//sigaction( SIGSYS , &act, NULL); /* Bad System Call */
//sigaction( SIGXCPU, &act, NULL); /* CPU-time limit exceeded */
//sigaction( SIGXFSZ, &act, NULL); /* File-size limit exceeded */
sigemptyset(&set); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask(SIG_SETMASK, &set, NULL);
}
/// @brief Child Process 의 main 함수
int ChildMain(void)
{
bool bRet = false;
int nFailCnt = 0;
// set child signal
SetSignalChild();
#if defined(__FreeBSD__)
setproctitle( "Child [initialize process]");
#endif
char szTime[MAXSIZEOFSTR];
time_t ltime;
struct tm *pTm = NULL;
char szHostname[MAXSIZEOFSTR];
// ** SMS Sender 객체 생성 및 초기화
CSmsSender objSmsSender(g_envConfig.szSMSHost, g_envConfig.nSMSPort, g_envConfig.szSMSSendfile);
bRet = objSmsSender.Init();
if( bRet == false )
{
LOG(LERR, "Initializing SmsSender Object has failed.");
exit(EXIT_FAILURE);
}
// ** SMS Sender 객체 생성 및 초기화
// 2015-06-26 두 번째 파라메터는 더이상 의미가 없다.
CArecaWrapper objAreca(g_envConfig.nEventLevel);
if( objAreca.InitArecaControllers() < 0 )
{
LOG(LERR, "Initializing Areca RAID Controller has failed.");
exit(EXIT_FAILURE);
}
// ** EventDataManager 객체 생성 및 초기화
CEventDataManager objDataManager;
bRet = objDataManager.Init();
if( bRet == false )
{
LOG(LERR, "Initializing SmsSender Object has failed.");
exit(EXIT_FAILURE);
}
// ** Raid Event Monitor 객체 생성 및 초기화
// ** UDP Listener 객체 생성 및 초기화
CUdpListener udpObj(&objDataManager);
// report thread port :
bRet = udpObj.Init(g_envConfig.nReportPort);
if( bRet == false )
{
LOG(LERR, "Initializing UdpListener Object has failed.");
exit(EXIT_FAILURE);
}
udpObj.Start();
// 현재 hostname
// hostname이 변경되면 반영되지 않는다. 반영이 꼭필요하다면 while구문 안으로 넣으면 된다.
if( ::gethostname(szHostname, MAXSIZEOFSTR) < 0 )
{
_LOG(LWAR, "gethostname failed. : %s", szHostname);
::snprintf(szHostname, MAXSIZEOFSTR, "%s", "error.hostname.com");
}
nFailCnt = 0;
while( 1 )
{
list<CEventData> listRet;
if( objAreca.GetEvent(GET_EVENT_ALL, listRet) == false )
{
if( nFailCnt < 3 )
{
nFailCnt++;
_LOG(LWAR, "Get RAID Event Data Failed.");
}
else
{
LOG(LERR, "Get RAID Event Data Failed. %d(th). Send SMS.",nFailCnt);
nFailCnt = 0;
// 현재 시각 설정
time((time_t *)&ltime);
pTm = ::localtime((time_t *)&ltime);
::memset(szTime, 0, sizeof(szTime));
::snprintf(szTime, MAXSIZEOFSTR, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
pTm->tm_year+1900, pTm->tm_mon +1, pTm->tm_mday,
pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
objSmsSender.SendToWebServ(szHostname, szTime ,"Can NOT Receive Data From RAID Controller!");
}
sleep(g_envConfig.nCheckTerm);
continue;
}
nFailCnt = 0; // 성공하면 실패 카운트를 리셋한다.
// 받아온 Raid Event 저장
bRet = objDataManager.SetCurrentData(listRet);
if( bRet == false )
{
LOG(LERR, "SetCurrentData Failed. but it's Impossible. Check ArecaWrapper::GetEvent().");
sleep(g_envConfig.nCheckTerm);
continue;
}
// SMS 전송 목록
listRet.clear();
bRet = objDataManager.GetSmsEvent(listRet);
if( bRet == false )
{
LOG(LERR, "GetSmsEvent() failed.");
sleep(g_envConfig.nCheckTerm);
continue;
}
for (list<CEventData>::iterator it=listRet.begin(); it!=listRet.end(); it++)
{
// NEW 2019-09-16 huibong 불필요 "Battery Module Failed" event 는 전송하지 않는다. (#32795)
// - "Battery Module Failed" event 는 운영자가 수신해도 할 작업이 없음
// - 하지만 일 10~20 건 정도가 발생하여 운영자에게 불필요 event 가 전달됨
// - 이와 관련 KT 운영팀 윤철희 실장이 해당 event 는 무시하도록 처리해 달라고 해서...
// - 해당 메시지 발생시 운영자에게 event 전송하지 않도록 한다.
// - 실제로 CEventDataManager 모듈에서도 처리가능하지만...
// - 본 모듈에서 실제 event 전송을 담당하므로.. 본 모듈에서 무시 처리하도록 수정함.
// BUG 2020-01-10 huibong 불필요 "Battery Module Failed" event 미전송 관련 버그 수정 (#32911)
// - 실제로 Module 단어와 Failed 단어 사이에 공백이 3개 존재
// - 이로 인해 해당 event 가 계속 전송되는 상황 발견됨
// - 이에 Battery Module" check 후 Failed 문자열 check 하도록 수정
std::string::size_type find_result;
find_result = it->m_szEventData.find( "Battery Module" );
if( find_result != std::string::npos )
{
find_result = it->m_szEventData.find( "Fail" );
if( find_result != std::string::npos )
{
_LOG( LDBG, "Do not send event with operator requests [%s]", it->m_szEventData.c_str() );
continue;
}
}
pTm = ::localtime(&(it->m_evtTime));
::memset(szTime, 0, sizeof(szTime));
::snprintf(szTime, MAXSIZEOFSTR, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
pTm->tm_year+1900, pTm->tm_mon +1, pTm->tm_mday,
pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
_LOG(LWAR, "SMS Sent.[%s::%s:%s]",szHostname, szTime, it->m_szEventData.c_str());
//FIXME:호출하면 SMS가 발송된다... :많은사람에게 문자가 수신되므로 디버깅 때는 가급적 자제할것. please........
objSmsSender.SendToWebServ(szHostname, szTime ,it->m_szEventData.c_str());
/// 2011.07.26, 수정자 : 장희준
/// 업로드 자동 방지
CAutoDisableUpload autoDisableUpload;
autoDisableUpload.DoProcess( it->GetEventCategory(), it->GetEventId() );
}
sleep(g_envConfig.nCheckTerm);
}
// wait
while(1)
{
// 그냥 시그널 대기
pause();
}
//잠시 대기 후 종료처리.
usleep(500000);
// exit( EXIT_SUCCESS );
return EXIT_SUCCESS; // fork 를 수행한 함수에서 exit 함수 호출을 통한 종료처리
}
+32
View File
@@ -0,0 +1,32 @@
/***************************************************************************
fhs_raidmond Header ( Child.h )
-----------------------------------------
begin : 2010/03/09
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __CHILD_PROCESS_H__
#define __CHILD_PROCESS_H__
#ifdef __cplusplus
extern "C" {
#endif
/// @brief Child Process ÀÇ main ÇÔ¼ö
/// @return
int ChildMain( void );
#ifdef __cplusplus
}
#endif
#endif /* __CHILD_PROCESS_H__ */
+131
View File
@@ -0,0 +1,131 @@
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <iostream>
using namespace std;
#define MaxRTTime 5
#define MaxRecvBuffSize (20 * 1024)
void handleAlarm(int signal)
{
return; // just return and interupt.
}
// main function
int main( int argc, char * argv[] )
{
if(argc != 4)
{
cerr << PROG_NAME << " Version :" << PROG_VERSION << endl;
cerr << "Usage: " << PROG_NAME << " server-ip port mode" << endl;
return EXIT_FAILURE;
}
static bool success = false;
// parse command line arguments
string host = argv[1];
int port = atoi(argv[2]);
string mode = argv[3];
//cout << "arguments : " << host << "," << port << "," << mode << endl;
int r = -1;
struct sockaddr_in cliaddr;
int addr_len = sizeof(cliaddr);
char recvbuf[MaxRecvBuffSize];
string result;
// socket initialize
int s = -1;
s = socket(AF_INET, SOCK_DGRAM, 0);
if(s < 0)
{
cerr << "Socket Create: errno:" << errno << " errmsg:" << strerror(errno) << endl;
return EXIT_FAILURE;
}
struct timeval timeout;
timeout.tv_sec = MaxRTTime;
timeout.tv_usec = 0;
int optlen = sizeof(timeout);
int errtimeout = -1;
if( setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, (socklen_t)optlen) < 0)
{
struct sigaction sigact, oldact;
sigact.sa_handler = handleAlarm;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
#ifdef SA_INTERRUPT
sigact.sa_flags |= SA_INTERRUPT;
#endif // SA_INTERRUPT
if(sigaction(SIGALRM, &sigact, &oldact) < 0)
{
cerr << "sigaction error: errno:" << errno << " errmsg:" << strerror(errno) << endl;
return EXIT_FAILURE;
}
errtimeout = EINTR;
}
else
errtimeout = EAGAIN;
struct sockaddr_in SocAddr;
SocAddr.sin_family = AF_INET;
SocAddr.sin_port = htons(port);
//SocAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (inet_aton(host.c_str(), &SocAddr.sin_addr)==0)
{
cerr << "inet_aton() failed: errno:" << errno << " errmsg:" << strerror(errno) << endl;
return EXIT_FAILURE;
}
// send
int len = mode.length();
if( sendto( s, mode.c_str(), mode.length(), 0, (struct sockaddr *)&SocAddr, sizeof(SocAddr) ) != len)
{
cerr << "sendto error : errno :"<< errno << " errmg:" << strerror(errno) << endl;
goto GOTO_END;
}
if( errtimeout == EINTR )
{
alarm(MaxRTTime);
}
// receive
do
{
memset(recvbuf, 0, MaxRecvBuffSize);
r = recvfrom( s, (char *)&recvbuf, (unsigned int)MaxRecvBuffSize, 0, (struct sockaddr *)&cliaddr, (socklen_t *)&addr_len );
//cerr << "nREAD = " << r << "," << errno << endl;
if(r >= 0)
result += recvbuf;
else
{
if( errno == errtimeout ) // timeout
{
cerr << "3:" << (long)time(NULL) << ":Disabled" << endl;
goto GOTO_END;
}
}
} while (r <= 0);
cout << result << endl;
if (result.size())
success = true;
GOTO_END:
close(s);
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
+60
View File
@@ -0,0 +1,60 @@
/***************************************************************************
Areca Library Event Data Class
-----------------------------------------
begin : 2010/05/21
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __EVENT_DATA__
#define __EVENT_DATA__
#include <pthread.h>
#include <string>
#include <time.h>
/// @brief CEventData
/// EventData 는 Areca library로부터 받아오는 raid event 정보를 저장한다.
/// 내부적으로 Thread를 사용하고있다.
class CEventData
{
private:
int m_nEventCategory;
int m_nEventId;
public:
/// @brief Areca Library에서 얻어온 데이터의 시간값을 저장한다.
time_t m_evtTime;
std::string m_szEventData;
public:
/// @brief 생성자
CEventData(){};
/// @brief 소멸자
~CEventData(){};
inline void SetEventType( int eventCategory, int evnetId )
{
m_nEventCategory = eventCategory;
m_nEventId = evnetId;
}
inline int GetEventCategory() { return m_nEventCategory; };
inline int GetEventId() { return m_nEventId; };
/// @brief Areca Library에서 얻어온 이벤트 데이터를 저장한다.
///< 데이터의 형태로 반복여부를 확인하여 중복 반복시 최초 1개의 데이터만을 알림하도록 설계되었다.
inline bool operator==(const CEventData& t)
{
return ( (t.m_evtTime == m_evtTime) && (t.m_szEventData == m_szEventData) );
}
};
#endif // __EVENT_DATA__
+163
View File
@@ -0,0 +1,163 @@
#include <iostream>
#include <sstream>
#include "EventDataManager.h"
#include <stdlib.h>
#include <algorithm>
#define REPEAT_ALLOW_TIME 60*60
// 생성자
CEventDataManager::CEventDataManager()
{
pthread_mutex_init(&m_mutex, NULL);
}
// 소멸자
CEventDataManager::~CEventDataManager()
{
pthread_mutex_destroy(&m_mutex);
}
bool CEventDataManager::Init(void)
{
return true;
}
bool CEventDataManager::GetAllData(list<CEventData>& listRet)
{
pthread_mutex_lock( &m_mutex );
// SetCurrentData가 정상적으로 동작하였다면, m_Old.size()의 조건에 걸릴 수 없다.
if ( m_Current.size() < 1 || m_Old.size() < 1 )
{
pthread_mutex_unlock( &m_mutex );
_LOG(LINF, "Data have Nothing.");
return false;
}
listRet = m_Current;
pthread_mutex_unlock( &m_mutex );
return true;
}
int CEventDataManager::GetLatestData( CEventData& resData )
{
pthread_mutex_lock( &m_mutex );
// SetCurrentData가 정상적으로 동작하였다면, m_Old.size()의 조건에 걸릴 수 없다.
if ( m_Current.size() < 1 || m_Old.size() < 1 )
{
pthread_mutex_unlock( &m_mutex );
_LOG(LINF, "Data have Nothing.");
return -1;
}
if( m_Old.back().m_evtTime == m_Current.back().m_evtTime )
{ // ( 과거와 현재 최종 이벤트 시각이 동일하면 변화가 없는 것이다. )
resData = m_Current.back();
resData.m_szEventData = "NO EVENT";
pthread_mutex_unlock( &m_mutex );
return 0;
}
// 과거와 현재 최종 이벤트 시각이 다르면 이벤트가 추가된 것이다.
resData = m_Current.back();
pthread_mutex_unlock( &m_mutex );
return 1;
}
bool CEventDataManager::SetCurrentData(list<CEventData>& listRet)
{
pthread_mutex_lock( &m_mutex );
if( listRet.empty() )
{
pthread_mutex_unlock( &m_mutex );
_LOG(LINF, "EventData is empty.");
return false;
}
// 들어온 데이터는 모두 시간순으로 정렬한다. (오름차순)
// Old 데이터를 지운다.
m_Old.clear();
//현재 값이 비어있을 경우 (최초 실행으로 간주함)
if( m_Current.empty() == true)
{
m_Old = listRet;
}
else
{
m_Old = m_Current;
}
m_Current = listRet;
pthread_mutex_unlock( &m_mutex );
return true;
}
bool CEventDataManager::GetSmsEvent(list<CEventData>& listRet)
{
CEventData fetchedData;
CEventData lastDataOfOld;
list<CEventData> eventData = m_Current;
list<CEventData> listFindTemp;
pthread_mutex_lock( &m_mutex );
if( m_Current.size() == 0 )
{
LOG(LERR, "List have No Data");
pthread_mutex_unlock( &m_mutex );
return false;
}
// 과거의 최신 데이터를 저장한다.
m_SentOld = m_Old.back();
// 현재 리스트의 뒤쪽(최신)부터 동일 데이터를 찾는다.
// (데이터에 시간 값이 포함되어 있기 때문에 완전히 동일한 데이터는 없는 것으로 간주한다.)
// (있을 경우 무시해도 되지 않을까?)
listFindTemp.push_back(m_SentOld);
// find_end를 사용하기 위해서 원소가 1개인 리스트를 생성한다.
list<CEventData>::iterator it = find_end(m_Current.begin(), m_Current.end(), listFindTemp.begin(), listFindTemp.end());
// 뒤쪽부터 원소가 1개인 리스트(listFindTemp)를 찾는다.
// find_end()는 집합에 속하는 부분집합을 찾는다.
// 찾아낸 데이터의 뒤쪽 부분은 신규 데이터이다.
if( it == m_Current.end() )
{ // end()와 같다면, 끝까지 찾지 못한 것을 의미한다. (NOT FOUND)
// 찾지 못한 것은 전체가 다 새로운 것이다.
_LOG(LINF, "List has NEW Event perfectly.");
it = m_Current.begin();
}
else
{ // 찾아낸 데이터의 다음 데이터를 가리키도록 한다.
++it;
}
// 신규 데이터 목록 중 앞쪽(오래된)부터 중복된 데이터인지를 검사한다.
for( ; it != m_Current.end(); it++)
{
if( it->m_szEventData == m_SentOld.m_szEventData
&& it->m_evtTime - m_SentOld.m_evtTime < REPEAT_ALLOW_TIME
&& it->m_evtTime - m_SentOld.m_evtTime >= 0 )
{ // 내용이 중복되고 마지막 이벤트로부터 1시간 미만 차이나면?
// BUG: Areca bug로 시간이 역순할 수 있다. REPEAT_ALLOW_TIME보다 작은 음수 값이 나오게 되면 무시하면 안된다.
_LOG(LINF, "There is Repeted Event.[%s]",it->m_szEventData.c_str());
// 중복 되면 버린다.(과거 데이터를 우선한다)
continue;
}
// 중복 데이터가 아니면 결과에 추가 한다.(SMS발송 대상)
listRet.push_back(*it);
m_SentOld = *it;
_LOG(LDBG, "ADD : [%lu::%s]", it->m_evtTime, it->m_szEventData.c_str());
}
// SMS발송 대상이 없을 경우 디버깅 로그만 남긴다.
if( listRet.size() == 0 )
{
LOG(LDBG, "There is No New Event.");
}
pthread_mutex_unlock( &m_mutex );
return true;
}
+53
View File
@@ -0,0 +1,53 @@
/***************************************************************************
SMS Raid Event Data Manager Class
-----------------------------------------
begin : 2010/05/24
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __EVENT_DATA_MANAGER__
#define __EVENT_DATA_MANAGER__
#include <pthread.h>
#include <string>
#include <time.h>
#include "Logger.h"
#include "EventData.h"
#include <list>
using namespace std;
/// @brief CEventDataManager
/// EventDataManager 는 Areca library로부터 받아오는 raid event 정보를 저장한다.
class CEventDataManager
{
public:
/// @brief 생성자
CEventDataManager();
/// @brief 소멸자
~CEventDataManager();
//TODO:
bool Init();
bool SetCurrentData(list<CEventData>& listRet);
bool GetSmsEvent(list<CEventData>& listRet);
int GetLatestData( CEventData& resData );
bool GetAllData(list<CEventData>& listRet);
private:
// TODO:
list<CEventData> m_Current;
list<CEventData> m_Old;
CEventData m_SentOld;
pthread_mutex_t m_mutex;
};
#endif // __EVENT_DATA_MANAGER__
+189
View File
@@ -0,0 +1,189 @@
#include "fhs_raidmond.h"
#include "Config.h"
#include "GetConfig.h"
/// @brief config value chech
/// @param szValue [in] value
/// @param conf [in] Config 객체
/// @param defsection [in] default section
/// @param defkey [in] default key
/// @return 성공시 true, 오류 발생시 false 를 반환.
static bool CheckValue(std::string& szValue, Config& conf, const std::string& defsection, const std::string& defkey)
{
if( szValue.size() > 0 )
return true;
if( defsection.size() <= 0 || defkey.size() <= 0 )
return false;
conf.GetConfig( defsection, defkey, szValue );
if( szValue.size() > 0 )
return true;
return false;
}
bool GetConfig( const std::string& szConfFile, struct st_config& stConfig, std::string& errorMessage )
{
bool ret = false;
// Config 처리를 위한 객체 생성
Config conf;
// Config File open
if( conf.Open( szConfFile) == false )
{
errorMessage = "Config file open failed.[" + szConfFile + "]";
return false;
}
std::string szValue;
szValue.clear();
// log path
if( conf.GetConfig( PROG_NAME, "DEFAULT_LOG_DIR", szValue ) == false )
{
if( !CheckValue(szValue, conf, "COMMON", "DEFAULT_LOG_DIR") )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->LOG_DIR";
return false;
}
}
stConfig.szLogDir = szValue;
szValue.clear();
// log level
if( conf.GetConfig( PROG_NAME, "LOG_LEVEL", szValue ) == false )
{
if( !CheckValue(szValue, conf, "COMMON", "LOG_LEVEL") )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->LOG_LEVEL";
return false;
}
}
stConfig.nLogLevel = atoi(szValue.c_str());
szValue.clear();
// check term
if( conf.GetConfig( PROG_NAME, "HEALTH_CHECK_TERM", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->HEALTH_CHECK_TERM";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->HEALTH_CHECK_TERM";
return false;
}
stConfig.nCheckTerm = atoi(szValue.c_str());
szValue.clear();
// report port
if( conf.GetConfig( PROG_NAME, "REPORT_THREAD_PORT", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->REPORT_THREAD_PORT";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->REPORT_THREAD_PORT";
return false;
}
stConfig.nReportPort = atoi(szValue.c_str());
szValue.clear();
//event level
if( conf.GetConfig( PROG_NAME, "EVENT_LEVEL", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->EVENT_LEVEL";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->EVENT_LEVEL";
return false;
}
stConfig.nEventLevel = atoi(szValue.c_str());
szValue.clear();
//sms send host
if( conf.GetConfig( PROG_NAME, "SMS_SEND_HOST", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_HOST";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_HOST";
return false;
}
stConfig.szSMSHost = szValue;
szValue.clear();
//sms send port
if( conf.GetConfig( PROG_NAME, "SMS_SEND_PORT", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_HOST";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_PORT";
return false;
}
stConfig.nSMSPort = atoi(szValue.c_str());
szValue.clear();
//sms send file
if( conf.GetConfig( PROG_NAME, "SMS_SEND_URI", szValue ) == false )
{
errorMessage = "Config info get failed. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_FILE";
return false;
}
if( !CheckValue(szValue, conf, "", "") )
{
errorMessage = "Config info get empty. [";
errorMessage += PROG_NAME;
errorMessage += "]->SMS_SEND_FILE";
return false;
}
stConfig.szSMSSendfile = szValue;
szValue.clear();
ret = true;
return ret;
}
+37
View File
@@ -0,0 +1,37 @@
/***************************************************************************
rc_rmcd ( File Replication & Cache Control Daemon ) Header ( GetConfig.h )
-----------------------------------------
begin : 2010/03/03
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __GET_CONFIG_H__
#define __GET_CONFIG_H__
#ifdef __cplusplus
extern "C" {
#endif
/// @brief config file parsing and save to stConfig function
/// @param szConfFile [in] Conf 파일에 대한 경로 및 파일 정보
/// @param stConfig [out] Conf 파일의 정보를 저장하기 위한 st_config 참조변수
/// @param errorMessage [out] 오류발생시 해당 오류 정보를 저장하여 반환하기 위한 참조변수
/// @return 성공시 true, 오류 발생시 false 를 반환. 상세한 오류 정보는 errorMessage 변수에 저장됨.
bool GetConfig( const std::string& szConfFile, struct st_config& stConfig, std::string& errorMessage);
#ifdef __cplusplus
}
#endif
#endif /* __GET_CONFIG_H__ */
+87
View File
@@ -0,0 +1,87 @@
#****************************************************************************
# Makefile for Arcmond
# -----------------------------------------
#
# begin : 2010/05/17
# copyright : (C) 2005 SolutionBox Inc.
# author : Service 1 Team
# email : svc1@solbox.com
# version : 3.0.0
#
# CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
# Redistribution and use in source and binary forms, with or with out
# modification, are not permitted in outside of SolutionBox Inc.
#*****************************************************************************
# Program info
PROG_NAME = arcmond
PROG_NAME_C = arcmond_client
#REVISION = `svnversion -n .`
REVISION = 1507
BUILD_DATE = `date +%Y%m%d%H%M%S`
PROG_VERSION = 3.5.0.$(REVISION)-$(BUILD_DATE)
DEFAULT_CONFIG_FILE = /user/service/etc/util.conf
INSTALL_BIN = /user/service/bin
OSBITS := $(shell getconf LONG_BIT)
# Compiler info
CC = /usr/bin/g++
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized \
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-fno-rtti -D_REENTRANT -Wno-unused -Wno-non-virtual-dtor
LFLAGS = -lpthread
# DEBUG or RELEASE Mode select
#DFLAGS = -D_DEBUG_ -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
# Application Enviroment
APP = $(PROG_NAME)
DIR_INCLUDE = -I./. -I../lib -I ../external/include #-I /user/db/pgsql/include -I../
DIR_LIB = -L../lib -L../external/bin/
OBJ = GetConfig.o Child.o main.o ArecaWrapper.o UdpListener.o SmsSender.o EventDataManager.o AutoDisableUpload.o
LIBS = ../lib/libInterCommon.a ../external/bin/libarclib${OSBITS}.a
ifeq ($(CLIENT), yes)
PROG_NAME = $(PROG_NAME_C)
OBJ = Client.o
LIBS =
endif
############################
all:$(APP)
#rm -f main.o
sync
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
test: $(OBJ)
$(CC) $(LFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
$(PROG_NAME): $(OBJ)
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
tael: $(OBJ) SmsSender.o
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
client:
$(MAKE) CLIENT="yes"
clean:
-rm -f *.o core *.out *.log
-rm -f $(APP)
sync
install : $(APP)
-cp $(APP) $(INSTALL_BIN)/$(APP)
sync
# End of Makefile
+256
View File
@@ -0,0 +1,256 @@
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "SmsSender.h"
#include <iterator>
#define DEFAULT_BUFFER_SIZE 9216
#define MaxSizeOfTRxBuffer 1024
string CSmsSender::RemoveBlankSpace(const char* pszData, size_t nLength)
{
char * szTemp = NULL;
string strReturn;
const char * src;
char * dest;
szTemp = (char*) ::malloc(sizeof(char) * nLength +1);
::memset(szTemp, 0 , sizeof(char)*nLength +1);
src = pszData;
dest = szTemp;
if( pszData == NULL )
{
strReturn.clear();
return strReturn;
}
if( *src == '\0' )
{
strReturn = src;
return strReturn;
}
// start with 2nd position
src++;
while ( src <= (pszData + nLength) && *(src-1) != '\0' )
{
if( *(src-1) == ' ' && *(src) == ' ' )
{ // 연속된 공백이 발견되면, 스킵한다.
src++;
continue;
}
*dest = *(src-1);
src++;
dest++;
}
// 종료표기
dest++;
*(dest) = '\0';
strReturn = szTemp;
if (szTemp != NULL)
{
free(szTemp);
szTemp = NULL;
}
return strReturn;
}
char hexchars[] = "0123456789ABCDEF";
string CSmsSender::PostDataEncode(const char *pszCommand, size_t length)
{
int i;
char tmpBuffer[MaxSizeOfTRxBuffer];
string strReturn;
if( pszCommand == NULL )
{
strReturn.clear();
return strReturn;
}
::memset(tmpBuffer, 0 , MaxSizeOfTRxBuffer);
i = 0;
while( *pszCommand != '\0' )
{
if( *pszCommand == ' ' )
{ // ' ' => '+'
tmpBuffer[i++] = '+';
pszCommand++;
}
else if(*pszCommand == '%')
{ // % => %%
tmpBuffer[i++] = '%';
tmpBuffer[i++] = '%';
pszCommand++;
}
else if( (*pszCommand < '0' && *pszCommand != '-' && *pszCommand != '.' )
|| (*pszCommand < 'A' && *pszCommand > '9' )
|| (*pszCommand > 'Z' && *pszCommand < 'a' && *pszCommand != '_' )
|| (*pszCommand > 'z' ) )
{
tmpBuffer[i++] = '%';
tmpBuffer[i++] = hexchars[(unsigned char)*pszCommand >> 4];
tmpBuffer[i++] = hexchars[(unsigned char)*pszCommand & 15];
pszCommand++;
}
else
{
tmpBuffer[i++] = *pszCommand++;
}
}
tmpBuffer[i] = '\0';
strReturn = tmpBuffer;
return strReturn;
}
CSmsSender::CSmsSender(const std::string& szHost, const int nPort, const std::string& szPath)
: CBaseSocket( SOCKET_NOT_VALID), m_szHost(szHost), m_nPort(nPort), m_szPath(szPath)
{
// 생성자
}
CSmsSender::~CSmsSender()
{
// 소멸자에 BaseSocket의 명시적 Close 처리를 한다.
Close();
}
bool CSmsSender::Init(void)
{
bool bRet = false;
// 데이터 체크
if( m_szHost.empty() || m_nPort < 0 || m_szPath.empty() )
{
LOG(LERR, "Invalid Parameter.");
return false;
}
return true;
}
bool CSmsSender::SendToWebServ(const string& pszHost, const string& pszTime, const string& pszMsg)
{
string szHost;
string szTime;
string szMsg;
char szSndBuffer[DEFAULT_BUFFER_SIZE];
char szRcvBuffer[DEFAULT_BUFFER_SIZE];
bool bRet = false;
int nRet = 0;
if( pszHost.empty() || pszMsg.empty() || pszTime.empty() )
{
LOG(LERR, "Invalid Parameter.");
Close();
return false;
}
// Connect
bRet = Connect(m_szHost, m_nPort);
if( bRet == false )
{
LOG(LERR, "Socket Connect Error.[%s:%d]", m_szHost.c_str(), m_nPort);
return false;
}
if( IsValidSocket() == false )
{
LOG(LERR, "Invalid Socket.");
Close();
return false;
}
::bzero(szSndBuffer, DEFAULT_BUFFER_SIZE);
::bzero(szRcvBuffer, DEFAULT_BUFFER_SIZE);
szHost = PostDataEncode(pszHost.c_str(), pszHost.size());
szTime = PostDataEncode(pszTime.c_str(), pszTime.size());
szMsg = RemoveBlankSpace(pszMsg.c_str(), pszMsg.size());
LOG(LDBG, "SMSMsg = [%s]", szMsg.c_str());
szMsg = PostDataEncode(szMsg.c_str(), szMsg.size());
// CHG 2019-09-16 huibong HTTP 관련 줄바꿈문자 LF->CR+LF 변경 (#32794)
// - CVE-2016-8743 이슈에 따라 Apache 2.2.32 버전부터 HTTP header 상에서
// - 줄바꿈문자가 CR+LF 가 아닌 경우 HTTP 400 응답 발생
// - 이를 해결하기 위해 기존 줄바꿈 문자 \n -> \r\n 으로 변경처리한다.
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "GET %s?host=%s&time=%s&msg=%s HTTP/1.0\r\n"\
"Content-Type: text/plain\r\n"\
"User-Agent: Arcmond\r\n"\
"Host: %s\r\n"\
"Connection: close\r\n"\
"Cache-Control: no-cache\r\n\r\n"
,m_szPath.c_str(), szHost.c_str(), szTime.c_str(), szMsg.c_str() ,m_szHost.c_str());
//DEBUG_LOG("%s", szSndBuffer);
//요청 전송 시작
nRet = WriteN(&szSndBuffer, ::strlen(szSndBuffer)+1);
// MAX_SEND_RETRY_COUNT 회수만큼 재시도 후 실패처리된다.
if( nRet == 0 )
{
LOG(LERR, "write socket closed.");
Close();
return false;
}
else if( nRet == -1 )
{
LOG(LERR, "write socket error.(%s)",strerror(errno));
Close();
return false;
}
// 응답 결과 받기.
nRet = ReadNTimeout(szRcvBuffer, DEFAULT_BUFFER_SIZE);
if( nRet == 0 )
{
// Remain이 0일 경우가 모두 받은 상황인데, 그것을 알 수 없다면,
// Ret==0일 때가 다 준 상황으로 판단해야 하지 않을까? 그렇다면 에러가 아니다.
LOG(LDBG, "read socket closed.");
}
else if( nRet == -1 )
{ // 단순 소켓 에러.
LOG(LERR, "read socket error.(%s)",strerror(errno));
Close();
return false;
}
else if( nRet == -2 )
{ // 타임아웃.
LOG(LERR, "read socket timed out.");
Close();
return false;
}
// 정상 결과는 아래와 같은 형태이다.
//----------------------------------------------------------------
// HTTP/1.1 200 OK
// Date: Thu, 10 Jun 2010 03:59:23 GMT
// Server: Apache/2.0.55 (Unix) DAV/2 PHP/5.2.1
// X-Powered-By: PHP/5.2.1
// Content-Length: 87
// Connection: close
// Content-Type: text/html; charset=EUC-KR
//
// [RAID:qcrts4.ktsh.co.kr]::2010-07-09 12:59:19:Controller#1: SW API Interface API Log In
//----------------------------------------------------------------
// 첫번째 라인만 출력하기 위해서 \n을 \0으로 바꾸고 출력한다.
char* pEnd = strchr(szRcvBuffer, '\n');
*pEnd = '\0';
LOG(LINF, "Result:%s", szRcvBuffer);
// Close()는 return값이 없음.
Close();
return true;
}
+59
View File
@@ -0,0 +1,59 @@
/***************************************************************************
SMS Sender Class
-----------------------------------------
begin : 2010/05/19
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __SMS_SENDER__
#define __SMS_SENDER__
#include <pthread.h>
#include <string>
#include "Logger.h"
#include "BaseSocket.h"
using namespace std;
/// @brief CSmsSender
/// SmsSender는 지정된 포멧에 따라 php 웹 페이지를 호출한다.
///
class CSmsSender : public CBaseSocket
{
public:
/// @brief 생성자
/// @param [in] szHost SMS 전송 장비 호스트
/// @param [in] nPort SMS 전송 장비 접근 Port
/// @param [in] szPath SMS 전송 기능이 구현된 PHP 파일명.
CSmsSender(const string& szHost, const int nPort, const string& szPath);
~CSmsSender();
/// @brief Init 함수 클래스 환경이 정상적인지를 검사한다.
/// @return 성공: true, 실패: false
bool Init();
/// @brief PHP Web페이지를 통해 SMS발송 요청을 수행한다.
/// @return 성공: true, 실패: false
bool CallWebPage();
bool SendToWebServ(const string& pszHost, const string& pszTime, const string& pszMsg);
private:
// 로깅 파일
string PostDataEncode(const char *pszCommand, size_t length);
string RemoveBlankSpace(const char* pszData, size_t nLength);
string m_szHost;
int m_nPort;
string m_szPath;
string m_szMessage;
string m_szGroupId;
};
#endif // __SMS_SENDER__
+321
View File
@@ -0,0 +1,321 @@
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "UdpListener.h"
#define DEFAULT_BUFFER_SIZE 9216
#define MaxSizeOfTID 52
#define MaxSizeOfIssuer 128
#define MaxSizeOfSID 128
#define MaxSizeOfRCID 32
int CUdpListener::SendMsg(char * szSndBuffer,int size, struct sockaddr_in * cliaddr, socklen_t nAddrSize)
{
int SndBlockSize = 8196;
char szLineBuffer[SndBlockSize];
int nLeft = size;
char * pTmp = szSndBuffer;
int nWrite = 0;
do
{
int offset = 0;
::memset(szLineBuffer, 0, SndBlockSize);
if( nLeft < SndBlockSize )
SndBlockSize = nLeft;
while( offset < SndBlockSize )
szLineBuffer[offset++] = *pTmp++;
szLineBuffer[offset] = '\0';
//DEBUG_LOG("LINE : [%s]", szLineBuffer);
nWrite = ::sendto(m_nSocket, szLineBuffer, offset + 1, 0, (struct sockaddr *)cliaddr, nAddrSize);
if(nWrite < 0)
{ // error
LOG(LERR, "sendto socket(%d) error (%s)", m_nSocket, strerror(errno));
break;
}
else if(nWrite == 0)
{ // socket closed
break;
}
else
{
LOG(LDBG, "SEND MESSAGE %d, %d, %s", nWrite, offset+1, szLineBuffer);
}
nLeft -= nWrite;
} while ( nLeft > 0 );
return 0;
}
/// @brief 클라이언트로 부터 받아온 스트링 프로토콜을 정수 프로토콜로 변환한다.
/// @param [in] szProtocol 클라이언트로부터 전송받은 스트링 프로토콜.
/// @return 성공: 양의 정수의 프로토콜 값. 실패: -1
int CUdpListener::ParsingPacket(const char * szProtocol)
{
int nRet = -1;
if( szProtocol == NULL )
{
LOG(LERR, "Invalid Parameter");
return -1;
}
// 구버전 프로토콜을 유지한다.
if(strcmp(szProtocol, "I'M YOUR FATHER. BASTARD !") == 0)
{
LOG(LDBG, "-------- (OLD)CMD_EVENT_INFO_ONE Called!-----------");
nRet = CMD_EVENT_INFO_ONE;
}
else if(strcmp(szProtocol, "I'M YOUR GOD. BASTARD !") == 0)
{
LOG(LDBG, "-------- (OLD)CMD_EVENT_INFO_ALL Called! ---------");
nRet = CMD_EVENT_INFO_ALL;
}
else if(strcmp(szProtocol, "EVENT:INFO:ONE") == 0)
{
LOG(LDBG, "-------- CMD_EVENT_INFO_ONE Called!-----------");
nRet = CMD_EVENT_INFO_ONE;
}
else if(strcmp(szProtocol, "EVENT:INFO:ALL") == 0)
{
LOG(LDBG, "-------- CMD_EVENT_INFO_ALL Called! ---------");
nRet = CMD_EVENT_INFO_ALL;
}
// 프로토콜을 추가하려면 여기에 아래의 형태로 추가한다.
// else if(strcmp(szProtocol, "String...........") == 0)
// {
// nRet = CMD_XXXXXXXXX;
// }
else // Invalid Protocol
{
nRet = CMD_UDP_ERROR;
}
return nRet;
}
CUdpListener::CUdpListener(CEventDataManager* pEventDataManager)
: m_pEventDataManager( pEventDataManager )
{
m_nSocket = -1;
LOG(LDBG, "Constructor has been called.");
}
CUdpListener::~CUdpListener()
{
if ( m_nSocket != -1)
{
::close(m_nSocket);
m_nSocket = -1;
}
pthread_cancel(m_threadHandle);
}
bool CUdpListener::Init(int nPort)
{
LOG(LDBG, "Initializer has been called.");
int fRet = 0;
struct sockaddr_in SocAddr;
int nVal=1;
if(m_pEventDataManager == NULL )
{
LOG(LERR, "Invalid Object.");
return false;
}
if( nPort <= 0 )
{
LOG(LERR, "Invalid Parameter. Port=%d", nPort);
return false;
}
SocAddr.sin_family = AF_INET;
SocAddr.sin_port = htons(nPort);
SocAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// UDP 소켓 생성.
m_nSocket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (m_nSocket < 0)
{
LOG(LERR, "Socket Create: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
if (setsockopt(m_nSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&nVal, sizeof(int)) < 0)
{
LOG(LERR, "setsockopt(SO_REUSEADDR) failed.");
return false;
}
// UDP 소켓 바인드.
fRet = ::bind(m_nSocket, (struct sockaddr *)&SocAddr, sizeof(SocAddr));
if (fRet != 0)
{
LOG(LERR, "Socket Bind: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Initializer has been succeed.");
return true;
}
///@brief 이 함수에서 UDP 통신을 receive 한다.
void CUdpListener::Execute()
{
char szRcvBuffer[DEFAULT_BUFFER_SIZE];
char szSndBuffer[DEFAULT_BUFFER_SIZE];
int nRead = 0;
struct sockaddr_in cliaddr;
int addr_len = sizeof(cliaddr);
int bMode = 0;
int nRet = -1;
bool bRet = false;
string szTmp;
::memset(szRcvBuffer, 0, DEFAULT_BUFFER_SIZE);
::memset(szSndBuffer, 0, DEFAULT_BUFFER_SIZE);
//DEBUG_LOG("DEBUG: %d , %lu %lu, %lu", m_nSocket, szRcvBuffer, &cliaddr, &addr_len);
nRead = ::recvfrom(m_nSocket, (char *)&szRcvBuffer, (unsigned int)DEFAULT_BUFFER_SIZE, 0, (struct sockaddr *)&cliaddr, (socklen_t *)&addr_len);
if ( nRead <= 0 )
{
LOG(LERR, "recvfrom() error. %s.",strerror(errno));
return;
}
LOG(LDBG, "Request Buffer = %s", szRcvBuffer);
LOG(LDBG, "From = %s", inet_ntoa(cliaddr.sin_addr));
bMode = ParsingPacket(szRcvBuffer);
switch (bMode)
{
case CMD_EVENT_INFO_ONE:
{
CEventData resData;
nRet = m_pEventDataManager->GetLatestData(resData);
if ( nRet == -1 )
{
LOG(LERR, "GeLatestData() failed.");
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "1:%ld:Initializing Now.", ::time(NULL));
} else
{
if( nRet == 0 )
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "%d:%ld:%s", nRet,::time(NULL), resData.m_szEventData.c_str());
else
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "%d:%ld:%s", nRet,::time(NULL), resData.m_szEventData.c_str());
}
// 클라이언트 메시지 송신
SendMsg((char*)szSndBuffer, strlen(szSndBuffer),&cliaddr, (socklen_t) sizeof(cliaddr));
LOG(LDBG, "SEND MESSAGE %s.", szSndBuffer);
}
break;
case CMD_EVENT_INFO_ALL:
{
list<CEventData> listRet;
listRet.clear();
bRet = m_pEventDataManager->GetAllData(listRet);
if( nRet == false || listRet.empty() )
{
LOG(LERR, "GetAllData() failed.");
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "%d:%ld:No EVENT IS FOUND.", 1,(long)::time(NULL));
} else
{
// 2013-10-17
// 기존에는 모든 메세지를 보냈으나, sms메세지를 만들어주는 web page에서 처리가안되는것을 확인했다.
// 이에 따라 최근 100개 메세지를 전송하는 것으로 처리한다.
//for (list<CEventData>::iterator it = listRet.begin(); it != listRet.end(); it++)
int nCount = 0;
for (list<CEventData>::reverse_iterator it = listRet.rbegin(); it != listRet.rend(); it++)
{
// 2016.01.22 dadamin
// 96 => 1024 : buffer overflow 발생하여 메세지 전송 실패 발생하여 변경함
char timeBuf[1024] = {0};
tm* ptm = localtime(&it->m_evtTime);
::sprintf(timeBuf, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n",
ptm->tm_year + 1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec,
it->m_szEventData.c_str());
szTmp += timeBuf;
nCount++;
if( nCount >= 100 )
{
break;
}
// upd send size limit
if(szTmp.length() > 1100 ) {
break;
}
}
// upd send size limit
::snprintf(szSndBuffer, 1400, "%d:%ld:%s", 1,(long)::time(NULL) , szTmp.c_str());
}
SendMsg((char*)szSndBuffer, strlen(szSndBuffer),&cliaddr, (socklen_t) sizeof(cliaddr));
LOG(LDBG, "SEND MESSAGE %s.", szSndBuffer);
}
break;
default:
LOG(LDBG, "----------------- INVALID COMMAND REQUEST!!! ----------------------------------");
LOG(LERR, "Invalid Protocol.");
::memset(szSndBuffer, 0, DEFAULT_BUFFER_SIZE);
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "1:%ld:Invalid Arguments!", (long)::time(NULL));
LOG(LDBG, "SENDING Buffer = [%s]", szSndBuffer);
//::sendto(m_nSocket, szSndBuffer, strlen(szSndBuffer), 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
SendMsg((char*)szSndBuffer, strlen(szSndBuffer),&cliaddr, (socklen_t) sizeof(cliaddr));
// TODO: error check
return;
break;
}//~switch (bMode)
}
void* CUdpListener::EntryPoint(void* arg)
{
CUdpListener* pObject = reinterpret_cast<CUdpListener *>(arg);
if( pObject == NULL )
{
// static Function이기 때문에 로깅할 수 없다...
//ERROR_LOG("Critical Memory Error, Invalid Object.");
//exit(EXIT_FAILURE);
}
pthread_detach( pthread_self() );
while(1)
{
pthread_testcancel();
pObject->Execute();
pthread_testcancel();
}
// pthread_exit();
return (void *)NULL;
}
bool CUdpListener::Start()
{
int nRet = ::pthread_create(&m_threadHandle, 0, CUdpListener::EntryPoint, this);
if( nRet != 0 )
{
LOG(LERR, "Thread create failed: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Thread create succeed.");
sleep(0);
return true;
}
+76
View File
@@ -0,0 +1,76 @@
/***************************************************************************
UDP Listener Class
-----------------------------------------
begin : 2010/05/17
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __UDP_LISTENER__
#define __UDP_LISTENER__
#include <pthread.h>
#include <string>
#include "Logger.h"
#include "EventDataManager.h"
using namespace std;
/// @brief Protocols
#define CMD_UDP_BASE 1000
#define CMD_UDP_ERROR CMD_UDP_BASE
#define CMD_EVENT_INFO_ONE ( CMD_UDP_BASE + 101 )
#define CMD_EVENT_INFO_ALL ( CMD_UDP_BASE + 102 )
/// @brief CUdpListener
/// UdpListener 는 client에서 udp 요청되는 패킷을 수신해서 관리하게 되며,
/// raid 정보 조회 후, 결과를 전송한다.
/// 내부적으로 Thread를 사용하고있다.
class CUdpListener
{
public:
/// @brief 생성자
/// @param [in] pEventManager CEventManager 객체
CUdpListener(CEventDataManager* pEventDataManager);
~CUdpListener();
/// @brief Init 함수 클래스 환경이 정상적인지를 검사한다.
/// @param [in] nPort UDP listen port 번호.
/// @return 성공: true, 실패: false
bool Init(int nPort);
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공: true, 실패: false
bool Start();
private:
// 이벤트 저장 객체
CEventDataManager* m_pEventDataManager;
// 쓰레드 핸들
pthread_t m_threadHandle;
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
int m_nSocket;
// 해당 함수의 내용은 수정하지 말것.
void Execute();
/// @brief 클라이언트로 부터 받아온 스트링 프로토콜을 정수 프로토콜로 변환한다.
/// @param [in] szProtocol 클라이언트로부터 전송받은 스트링 프로토콜.
/// @return 성공: 양의 정수의 프로토콜 값. 실패: -1
int ParsingPacket(const char * szProtocol);
int SendMsg(char * szSndBuffer,int size, struct sockaddr_in * cliaddr, socklen_t nAddrSize);
CEventData m_evtData;
};
#endif // __UDP_LISTENER__
+70
View File
@@ -0,0 +1,70 @@
/***************************************************************************
fhs_raidmond Header ( fhs_raidmond.h )
-----------------------------------------
begin : 2010/03/09
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __FHS_RAIDMOND_GLOBAL_VALUE_H__
#define __FHS_RAIDMOND_GLOBAL_VALUE_H__
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <iostream>
using namespace std;
#include "Logger.h"
struct st_config
{
// Common Part
std::string szLogDir;
int nLogLevel;
// fhs_raidmond Part
int nCheckTerm;
int nReportPort;
int nEventLevel;
std::string szSMSHost;
int nSMSPort;
std::string szSMSSendfile;
// »ý¼ºÀÚ
st_config()
{
nLogLevel = 0;
nCheckTerm = 0;
nReportPort = 0;
nEventLevel = 0;
nSMSPort = 0;
}
};
#ifdef __cplusplus
extern "C" {
#endif
/// @brief Global config object.
extern struct st_config g_envConfig;
#ifdef __cplusplus
}
#endif
#endif /* __FHS_RAIDMOND_GLOBAL_VALUE_H__ */
+349
View File
@@ -0,0 +1,349 @@
#include "fhs_raidmond.h"
#include "GetConfig.h"
#include "Child.h"
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
/// config object initialize
struct st_config g_envConfig;
/// daemon flag
static bool _isdaemon = true;
/// @brief Program version 출력 함수.
/// @return void
static void ShowVersion(void)
{
cerr << "[info] " << PROG_NAME << " Version :" << PROG_VERSION << endl;
}
/// @brief Program version 사용 방법 출력 함수.
/// @return void
static void ShowUsages(void)
{
ShowVersion();
cerr << "usage: " << PROG_NAME << " [-vhcD]" << endl;
cerr << "options are: " << endl;
cerr << "-v : print current version" << endl;
cerr << "-c <path> : Log Diretory" << endl;
cerr << "-D : running console mode" << endl;
cerr << "-h : help " << endl;
}
/// @brief Child 프로세스 생성(fork) 함수
/// @return void
static void MakeChild(void)
{
pid_t processId;
// Child 프로세스 fork
processId = fork();
if( processId < 0 ) // Fork fail
{
int errorNum = errno;
LOG(LERR, "Child Process create failed. [%d][%s]", errorNum, strerror(errorNum) );
return;
}
else if( processId == 0 ) // Parent Process => Child Process
{
// Child Process Main 함수 호출 및 종료처리.
ChildMain();
exit( EXIT_SUCCESS );
}
else
{
// Parent Process => Logging
_LOG(LNOT, "Child Process create success. PID[%d]" , processId);
// 잠시 대기
usleep(100000);
}
}
/// @brief Parent Process 에서 child Process 가 종료된 경우 시그널 처리를 위한 함수
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void sigchld_hdl( int nSignalNumber )
{
pid_t killPid;
int nKillStatus;
while( ( killPid = waitpid( -1, &nKillStatus, WNOHANG ) ) > 0 )
{
// 자식 프로세스가 Signal 에 의해 종료되었는지 검사.
if( WIFSIGNALED( nKillStatus ) )
{
LOG(LWAR, "Child process[%d] killed by signal[%d]", killPid, WTERMSIG( nKillStatus ) );
}
else
{
LOG(LWAR, "Child process[%d] killed. Not signal", killPid );
// Child 프로세스가 EXIT_FAILURE 반환 ( 초기화 실패시 )
// 해당 내역을 화면 및 로그 상에 출력하고
// 자식 프로세스를 재생성 처리하지 않는다.
if( WIFEXITED( nKillStatus ) )
{
if( WEXITSTATUS( nKillStatus ) == EXIT_FAILURE )
{
LOG(LERR, "Child Process[%d] initilaize failed.", killPid );
LOG(LERR, "Parent Process[%d] exit by Child. Good Bye..", getpid());
cerr << "[error] " << PROG_NAME << ": Process exit by Child process initialize failed. check log file." << endl;
usleep(500000);
exit( EXIT_FAILURE );
}
}
}
// Child Process 재생성 처리.
MakeChild();
}
// 오류 발생시 해당 내역 로깅
if( killPid < 0 )
{
int errorNum = errno;
LOG(LERR, "Parent process error: SIG_CHLD receive but waitpid return error[%d][%s]", errorNum, strerror(errorNum));
}
return;
}
/// @brief Parent Process 종료 Signal 을 전달받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigTermParent( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
LOG(LWAR, "Parent Process[%d] exit job start by user signal [SIGTERM]", getpid() );
}
else
{
LOG(LWAR, "Parent Process[%d] exit job start by abnormal signal [%d]", getpid(), nSignalNumber );
}
// Process 종료관련 작업 추가
LOG(LWAR, "Parent Process[%d] exit job end. Good Bye..", getpid());
// KILL - Child
kill(0, SIGTERM);
// waitpid
while(waitpid(-1, NULL, WNOHANG) > 0);
usleep(500000);
exit( EXIT_SUCCESS );
}
/// @brief Parent Process 에서 Core 생성 관련 Signal 을 받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigCoreParent( int nSignalNumber )
{
LOG(LERR, "Parent Process[%d] abnoraml exit. Check Core file. Receive signal [%d]", getpid(), nSignalNumber );
//LOG(LERR, "Core file path : [%s/%s.core]", g_envConfig.szLogDir.c_str(), PROG_NAME );
// Process 종료관련 작업 추가
// Log Directory 상에 Core 파일 생성처리.
chdir( g_envConfig.szLogDir.c_str() );
signal( nSignalNumber, SIG_DFL );
// Core dump 생성을 위한 신호 발생처리.=> ?
raise( nSignalNumber );
}
/// @brief Parent 프로세스 signal 처리 설정을 위한 함수
/// @return void
static void SetSignalParent()
{
sigset_t set;
struct sigaction act;
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
memset( &act, 0x00, sizeof(act) );
sigfillset( &act.sa_mask );
/* 무시할 신호 목록 */
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL); /* 파이프 디스크립터 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP , &act, NULL); /* Process를 기동시킨 관리자의 로그아웃시 발생 시그널 */
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
if(_isdaemon)
{
sigaction( SIGINT , &act, NULL); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
}
else
{
act.sa_handler = SigTermParent;
sigaction( SIGINT, &act, NULL); /* ^C 키를 누른 경우 받는 신호 => kill -TERM 과 동일한 처리함 */
}
// Child Process 종료에 대한 처리기 설정.
act.sa_handler = sigchld_hdl;
sigaction( SIGCHLD, &act, NULL);
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SigTermParent;
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
/* Core 관련 signal 처리 : 오류 처리 및 Debug(core dump) 목적 */
// dadamin : 팀 기준 적용
//act.sa_handler = SigCoreParent;
//sigaction( SIGILL , &act, NULL); /* Illegal instruction */
//sigaction( SIGFPE , &act, NULL); /* Erroneout arithmetic operation */
//sigaction( SIGBUS , &act, NULL); /* Access to undefined portion of a memory object */
//sigaction( SIGSEGV, &act, NULL); /* Invalid memory reference */
//sigaction( SIGSYS , &act, NULL); /* Bad System Call */
//sigaction( SIGXCPU, &act, NULL); /* CPU-time limit exceeded */
//sigaction( SIGXFSZ, &act, NULL); /* File-size limit exceeded */
sigemptyset(&set); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask(SIG_SETMASK, &set, NULL);
}
// daemon 생성 함수
static bool daemon_create(bool bcreate)
{
// set parent signal
SetSignalParent();
// set mask
umask(0);
// daemon
if(bcreate && daemon(false, false) != 0 ) // after this line, parent's pid will be changed.
{
cerr << "[error] Daemonize Failed.(errno : " << errno << ")" << endl;
return false;
}
return true;
}
/// @brief std 상에 trim 함수가 없어서 직접 구현 아니면 boost/algorithm/string.hpp 상의 boost::trim 함수 사용
/// @return void
static void Trim( string & str )
{
if( str.length() == 0 )
return ;
// 문자열 뒤의 공백, TAB, CR 등의 문자 제거처리.
string::size_type pos = str.find_last_not_of(" \a\b\f\n\r\t\v");
if( pos != string::npos )
str.erase( pos + 1 );
// 문자열 앞의 공백, TAB, CR 등의 문자 제거처리.
pos = str.find_first_not_of(" \a\b\f\n\r\t\v");
if( pos != string::npos )
str.erase( 0, pos );
}
/// @brief 현재 Process가 기동중인지 여부를 판단하기 위한 함수( 프로세스 중복 실행 체크)
/// @return 이미 해당 프로세스가 기동 중인 경우 true 반환, 그렇지 않으면 false 반환.
static bool IsCurrentProcessRun()
{
char tempBuffer[512];
FILE * fd = NULL;
bool bRun = false;
snprintf( tempBuffer, sizeof(tempBuffer), "pgrep -x %s | sort", PROG_NAME );
fd = popen( tempBuffer, "r" );
if( fd == NULL )
{
cerr << "[error] Process duplication check failed.[popen error][" << strerror(errno) << "]" << endl;
// 오류 발생시 true 반환하여 프로세스 실행 방지처리
return true;
}
else
{
memset( tempBuffer, 0x00, sizeof(tempBuffer) );
while( fgets( tempBuffer, sizeof(tempBuffer)-1, fd) != NULL )
{
string tempPid( tempBuffer );
Trim(tempPid);
if( atoi( tempPid.c_str() ) != getpid() )
{
cout << "[info] Process duplication found. pid[" << atoi( tempPid.c_str() ) << "]" << endl;
bRun = true;
break;
}
}
pclose( fd );
return bRun;
}
}
// main function
int main( int argc, char * argv[] )
{
string cofigpath = DEFAULT_CONFIG_FILE;
// parse command line arguments
int o;
while ((o = getopt(argc, argv, "vhDc:")) >= 0)
{
switch (o)
{
case 'h': // help
ShowUsages();
return EXIT_SUCCESS;
break;
case 'v': // version
ShowVersion();
return EXIT_SUCCESS;
break;
case 'D': // consol mode
_isdaemon = false;
cerr << "Runnig Console mode." << endl;
break;
case 'c': // config file
cofigpath = optarg;
break;
}
}
// 프로그램 중복 실행 체크
if( IsCurrentProcessRun() == true )
{
cerr << "[warning] Process[" << PROG_NAME << "] is already running...." << endl;
return EXIT_FAILURE;
}
// load config
string szErrorMessage;
if(!GetConfig( cofigpath, g_envConfig, szErrorMessage ) )
{
cerr << "[error] Process[" << PROG_NAME << "]: " << szErrorMessage << endl;
return EXIT_FAILURE;
}
// init log
if( CLogger::Init( PROG_NAME, g_envConfig.szLogDir.c_str(), g_envConfig.nLogLevel ) == false )
{
cerr << "[error] Process[" << PROG_NAME << "]: Log init failed." << endl;
return EXIT_FAILURE;
}
// Global log object set
// daemon create
if(!daemon_create(_isdaemon))
return EXIT_FAILURE;
// Process 기동 관련 정보 로깅
_LOG(LINF, "***********************************************************" );
_LOG(LINF, " %s (FHS RAID Monitor Daemon) Start. Version: %s", PROG_NAME, PROG_VERSION );
_LOG(LINF, "***********************************************************" );
_LOG(LINF, "Config file : %s", cofigpath.c_str() );
_LOG(LINF, "Log Path : %s/%s", g_envConfig.szLogDir.c_str(), PROG_NAME );
_LOG(LINF, "Logging Level : %d", g_envConfig.nLogLevel );
_LOG(LINF, "health check term : %d", g_envConfig.nCheckTerm );
_LOG(LINF, "report thread port : %d", g_envConfig.nReportPort );
_LOG(LINF, "event level : %d", g_envConfig.nEventLevel );
_LOG(LINF, "sms send host : %s", g_envConfig.szSMSHost.c_str() );
_LOG(LINF, "sms send port : %d", g_envConfig.nSMSPort);
_LOG(LINF, "sms send file : %s", g_envConfig.szSMSSendfile.c_str() );
_LOG(LINF, "***********************************************************" );
// fork child
MakeChild();
// set process title
#if defined(__FreeBSD__)
setproctitle( "Parent [monitor Child process]" );
#endif
// wait
while( 1 )
{
pause();
}
return EXIT_SUCCESS;
}