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
+38
View File
@@ -0,0 +1,38 @@
Revision 0966
-------------------
수정일 : 2014-03-14
수정자 : 김오종
- BUG: Login Info Queue에서 pop 후 CCDB에 인서트 하는 Thread 작동 안되는 현상 수정
- Object instance 생성위치 변경으로 해결
- CHG: pgsql 라이브러리 참조 경로 변경
Revision 0924
-------------------
수정일 : 2014-01-13
수정자 : 김오종
- MOD: 서비스 용도를 활용해서 service type을 구분한 부분에 대한 로직 변경.
- Cloud Streaming의 아래와 같은 특성을 이용하여 구분하도록 적용한다.
조건1: Cloud Streaming Master/Slave는 CCDB의 cs_service.cs_service_config상에 같은 서비스 ID가 두 개 이상 존재하게된다.
조건2: 조건1을 만족하고 cs_service.cs_service_config Table 상에 svc_seq와 slave_svc_seq 값이 같은서비스가 존재한다면 Cloud Streaming Master/Slave서비스이다.
- ADD: sdk를 활용한 sp-console이 배포됨에 따라 ISSUER에 대한 처리 로직 변경 필요.
- ISSUER 값이 sp-console, sp-console3으로 요청이 올 경우 RC대표 도메인을 리턴하도록 변경 처리
Revision 0904
-------------------
수정일 : 2013-10-30
수정자 : 김오종
- BUG: CCDB상에 고객 ID만 존재하고 고객에대한 서비스가 없을 경우 오동작 수정
Revision 0896
-------------------
수정일 : 2013-10-14
수정자 : 김오종
- NEW: SVN 신규 등록
- cc_tsd 로 신규 등록 처리
- 기존 cc_tsd와 cc_timed의 기능을 포함하는 신규 cc_tsd소스를 등록한다.
- CHG:
- BUG:
+37
View File
@@ -0,0 +1,37 @@
#****************************************************************************
# Makefile for rc_cchkd
# -----------------------------------------
#
# begin : 2012/08/08
# copyright : (C) 2012 SolutionBox Inc.
# author : Service 1 Team
# email : svc1@solbox.com
# version : 3.2.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
+546
View File
@@ -0,0 +1,546 @@
#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>
#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 */
opt_linger.l_linger = 0; /* No Wait => 0 for abortive disconnect */
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 [%s] fail.[%d][%s]", szTarget.c_str(), 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 ) // 2010-07-23 BUG huibong 잘못된 대입연산자를 비교연산자로 수정.
{
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 )
{
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)
{
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 )
{
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)
{
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 )
{
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, *result;
int error;
// 전달받은 정보가 잘못된 경우
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);
error = getaddrinfo( name, NULL, &hints, &result );
// 오류 발생시
if( error != 0 )
{
LOG( LERR, "name[%s] dns resolve fail. getaddrinfo return error [%d][%s]", name, error, gai_strerror(error) );
return INADDR_NONE;
}
struct sockaddr_in * addr = (struct sockaddr_in *)result->ai_addr;
retval = (unsigned int)(addr->sin_addr.s_addr);
// DNS Resovle 결과 확인용 코드
/*
struct addrinfo *temp;
for( temp = result; temp; temp = temp->ai_next )
{
addr = (struct sockaddr_in *)temp->ai_addr;
printf ("getaddrinfo result = %s\n",inet_ntoa( addr->sin_addr));
}
*/
// getaddrinfo() 함수에서 생성한 메모리 영역 해제 처리.
freeaddrinfo(result);
return retval;
}
+118
View File
@@ -0,0 +1,118 @@
/***************************************************************************
BaseSocket ( Base Socket Class )
-----------------------------------------
begin : 2010/03/02
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __LIBRARY_BASE_SOCKET_H__
#define __LIBRARY_BASE_SOCKET_H__
#include <unistd.h>
#include <sys/types.h>
#include "Logger.h"
#define SOCKET_NOT_VALID -1
#define DEFAULT_DATA_RECEIVE_TIMEOUT 15 // sec
class CBaseSocket
{
protected:
/// @brief socket descriptor
int m_sock;
/// @brief socket 의 연결상태인지 여부를 저장하기 위한 변수.
bool m_bConnected;
public:
/// @brief 생성자.
CBaseSocket( const int & socket );
/// @brief 소멸자.
~CBaseSocket();
/// @brief 소켓의 Close 처리를 수행함.
void Close(void);
/// @brief 전달받은 Target 으로 Socket 접속을 수행
/// @param szTarget [in] 접속 대상 Host name 또는 IP
/// @param nPort [in] 접속 Port
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool Connect( const std::string& szTarget, int nPort );
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
bool IsValidSocket(void);
/// @brief 멤버변수인 socket 의 접속 상태 여부를 설정하기 위한 함수.
void SetConnectionStatus( bool bConnected) { m_bConnected = bConnected; }
/// @brief 현재 socket 의 접속 상태를 반환.
bool GetConnectionStatus( void) { return m_bConnected; }
//void SetLogger( Logger * pLog ) { m_pLog = pLog; }
protected:
/// @brief m_sock 로 부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t Read( void * vptr, size_t size );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t ReadN( void * vptr, size_t size );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
ssize_t ReadNTimeout( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
/// @param size [in] read 하고자 하는 데이터의 크기.
/// @param timeout [in] Timeout value (sec)
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
ssize_t ReadNTimeout2( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
public:
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
/// @param size [in] write 하고자 하는 데이터의 크기.
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
ssize_t WriteN( const void * vptr, size_t size );
protected:
/// @brief 문자열로 전달받은 정보를 검사하여 IP 접속 정보를 생성한다.
unsigned int ConversionAddr( const char * name );
};
#endif /* __LIBRARY_BASE_SOCKET_H__ */
+215
View File
@@ -0,0 +1,215 @@
#include "Config.h"
#include <iostream>
#include <fstream>
#include <errno.h>
#include <stdlib.h>
#include <boost/algorithm/string.hpp> // use boost
Config::Config()
: m_keyDelimiter( CONFIG_DEFAULT_KEY_DELIMITER )
, m_valueDelimiter( CONFIG_DEFAULT_VALUE_DELIMITER )
{
}
/// @brief destructor
Config::~Config()
{
Clear();
}
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
/// @return On success return true, otherwise return false
bool Config::Open( const string path )
{
ifstream file;
// Config file open
file.open( path.c_str());
if( file.is_open() == false )
{
cerr << "[error] " << __FILE__<< ":" << __func__ << ": config file open failed.[" << path << "][" << strerror( errno ) << "]" << endl;
return false;
}
// 기존 데이터가 존재하면 삭제 처리.
if( m_configData.empty() == false )
m_configData.clear();
// config file parsing
string line;
string section;
vector< string > configs;
// 루프를 돌면서 Config 파일을 line 단위로 읽어들인당....
while( std::getline( file, line ) )
{
// 앞뒤 공백 제거 처리
boost::trim( line );
// 공백 or 주석처리 라인 검사
if( line.empty() == true || boost::starts_with( line, string("#") ) == true || line == "\r" )
{
continue;
}
// Section 여부 검사
if( boost::starts_with( line, string("[") ) == true && boost::ends_with( line, string("]") ) == true )
{
// [] 로 정의된 section 의 문자열 값 추출
line.erase( line.begin() );
line.erase( line.end() -1 );
boost::trim( line );
if( section.empty() == false && section != line )
{
// 이전 세션과 다른 신규 세션인 경우
// 기존까지 저장했던 데이터를 멤버 변수에 입력 처리 후 내부변수 초기화 처리.
m_configData.insert( make_pair( section, configs ) );
section.clear();
configs.clear();
}
// 신규 section 정보 저장처리.
section = line;
line.clear();
}
else
{
// Section 정보가 아닌 경우 => 실제 설정값 .. ^^
configs.push_back( line );
}
}
// 마지막 세션 처리된 정보가 존재하는 경우 멤버 변수에 저장 처리.
if( section.empty() == false )
{
m_configData.insert( make_pair( section, configs ) );
}
// 종료 처리.
file.close();
return true;
}
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
/// @return void
void Config::Clear()
{
m_configData.clear();
}
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
/// @return On success return true, otherwise return false
bool Config::GetConfig( const string& section, const string& key, string& value )
{
// Section 에 대한 임시 데이터 저장객체 생성
vector< string > configs;
// 해당 Section 이 존재하지 않는 경우
if( Find( section, configs ) == false )
return false;
string line;
string result;
vector< string >::const_iterator it;
// 해당 Key 이 존재하는지 검사
for( it = configs.begin(); it != configs.end(); it++)
{
line = *it;
// Line 상의 주석 제거
string::size_type pos = line.find( '#' );
if( pos != string::npos)
{
line = line.substr(0, pos);
boost::trim( line );
}
// key = value 에서 key 부분 추출
pos = line.find( m_keyDelimiter );
if( pos == string::npos )
{
continue;
}
else
{
result = line.substr(0, pos);
boost::trim( result );
}
if( key == result )
{
// Key 값이 동일한 경우
value = line.substr( pos+1 );
boost::trim( value );
return true;
}
}
return false;
}
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
/// @return On success return true, otherwise return false
bool Config::GetConfig( const string& section, const string& key, vector< string >& value )
{
string result;
vector< string > vec;
if( GetConfig( section, key, result ) == false )
return false;
// 전달받은 result 값을 value delimiter 를 이용하여 parsing 처리
boost::split( vec, result, boost::is_any_of( m_valueDelimiter ));
if( vec.empty() == true )
return false;
// 루프를 돌면서 trim 처리 후 결과값 저장처리.
vector< string >::const_iterator it;
for( it = vec.begin(); it != vec.end(); it++)
{
result = boost::trim_copy( *it );
if( result.empty() == false )
value.push_back( result );
}
if( value.empty() == true )
return false;
else
return true;
}
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
/// @param section [in] section 명
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
/// @return On success return true, otherwise return false
bool Config::Find( const string& section, vector<string>& configData )
{
map< string, vector< string > >::iterator it = m_configData.find( section );
if( it != m_configData.end() )
{
// 해당 section 을 찾은 경우
configData = it->second;
return true;
}
// 해당 section 을 찾지 못한 경우
return false;
}
+114
View File
@@ -0,0 +1,114 @@
/***************************************************************************
Config File Parser Class
-----------------------------------------
begin : 2010/02/27
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __LIBRARY_CONFIG_H__
#define __LIBRARY_CONFIG_H__
#include <string>
#include <map>
#include <vector>
using namespace std;
#define CONFIG_DEFAULT_KEY_DELIMITER "="
#define CONFIG_DEFAULT_VALUE_DELIMITER ","
/// @brief Config class
/// 1. config 파일의 내용을 파싱처리하여 각 Section, Key 에 해당하는 값을 반환처리
/// 2. config 파일은 [section] 단위로 구분된다.
/// 3. config 파일은 key=value 로 구분가능하며 이는 Delimiter 설정을 통해 변경가능하다.
/// 4. value 값이 다중으로 존재하는 경우 "," 값을 통해 구분가능, Delimiter 변경시 다른 값도 사용가능함.
/// 5. config 파일상에서 "#" 로 시작하는 문자열은 라인 끝까지 주석으로 처리된다.
/// 6. 특정 Key 값에 대한 다중 value 값 조회는 vector<string> 을 통해 수행한다.
/// 7. 만약 다중 value 값이 존재시 string 으로 반환받을 경우 해당 Row 가 통째로 반환된다.
/// 8. 본 객체는 Open , Clear 함수가 호출되기전까지 이전 Config 정보가 저장된다.
class Config
{
private:
/// @brief config information saved variable
// string : section data
// vector<string> : key=value data
map< string, vector< string> > m_configData;
/// @brief Key, Value 구분자 저장 변수
string m_keyDelimiter;
string m_valueDelimiter;
public:
/// @brief constructor
Config();
/// @brief destructor
~Config();
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
/// @return On success return true, otherwise return false
bool Open( const string path );
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
/// @return void
void Clear();
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
/// @return On success return true, otherwise return false
bool GetConfig( const string& section, const string& key, string& value );
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
/// @param section [in] 찾고자 하는 Section 값
/// @param key [in] 찾고자 하는 key 값
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
/// @return On success return true, otherwise return false
bool GetConfig( const string& section, const string& key, vector< string >& value );
/// @brief Key, Value Delimiter Get 함수
/// @param key [out] key delimiter 값
/// @param value [out] value delimiter 값
void GetDelimiter( string& key, string& value )
{
key = m_keyDelimiter;
value = m_valueDelimiter;
}
// BUG 2010-12-06 huibong
// string& value = CONFIG_DEFAULT_VALUE_DELIMITER 값은 문법상 오류 구문임.
// gcc 3.4.6 버전에서는 Compile 되나 gcc 4.4.5 에서는 error 로 처리되어 수정처리함.
/// @brief Key, Value Delimiter Set 함수
/// @param key [out] key delimiter 값
/// @param value [out] value delimiter 값, 지정하지 않을 경우 Default 값이 사용됨.
void SetDelimiter( string& key, string value = CONFIG_DEFAULT_VALUE_DELIMITER )
{
m_keyDelimiter = key;
m_valueDelimiter = value;
}
protected:
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
/// @param section [in] section 명
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
/// @return On success return true, otherwise return false
bool Find( const string& section, vector<string>& configData );
};
#endif /* __LIBRARY_CONFIG_H__ */
+487
View File
@@ -0,0 +1,487 @@
/***************************************************************************
Logger.cpp
-----------------------------------------
begin : 2011/10/26
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "Logger.h"
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <iostream>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define MAX_BUFFER_SIZE 2048 // 임시 버퍼 최대 크기
#define DEFAULT_LOG_LEVEL LINF
using namespace std;
CLogger* CLogger::m_pInstance = NULL;
bool CLogger::m_bIsInitialized = false;
pthread_mutex_t CLogger::m_mutex = PTHREAD_MUTEX_INITIALIZER;
CLogger::CLogger( string programName, string logDir, int logLevel )
{
m_szProgramName = programName;
m_szLogDir = logDir;
if( IsValidLogLevel( logLevel ) == true )
{
m_nLogLevel = logLevel;
}
else
{
m_nLogLevel = DEFAULT_LOG_LEVEL;
}
MakeLogLevelString();
}
void CLogger::MakeLogLevelString()
{
m_vectorLogLevelString.push_back( "EMR" );
m_vectorLogLevelString.push_back( "ALT" );
m_vectorLogLevelString.push_back( "CRT" );
m_vectorLogLevelString.push_back( "ERR" );
m_vectorLogLevelString.push_back( "WAR" );
m_vectorLogLevelString.push_back( "NOT" );
m_vectorLogLevelString.push_back( "INF" );
m_vectorLogLevelString.push_back( "DBG" );
m_vectorLogLevelString.push_back( "DEV" );
m_vectorLogLevelString.push_back( "DEV1" );
m_vectorLogLevelString.push_back( "DEV2" );
}
CLogger::~CLogger()
{
m_vectorLogLevelString.clear();
}
bool CLogger::Init( string programName, string logDir, int logLevel )
{
if( m_bIsInitialized == true )
{
return true;
}
pthread_mutex_lock( &m_mutex );
// 변수 유효성 검사.
if( programName.empty() == true || logDir.empty() == true )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( IsValidLogLevel( logLevel ) == false )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( MakeLogDir( programName, logDir ) == false )
{
pthread_mutex_unlock( &m_mutex );
return false;
}
if( CLogger::m_pInstance != NULL )
{
delete CLogger::m_pInstance;
CLogger::m_pInstance = NULL;
}
CLogger::m_pInstance = new CLogger( programName, logDir, logLevel );
m_bIsInitialized = true;
pthread_mutex_unlock( &m_mutex );
return true;
}
bool CLogger::IsValidLogLevel( int logLevel )
{
return ( ( logLevel < 0 || logLevel > MAX_LOG_LEVEL ) ? false : true );
}
bool CLogger::SetLogLevel( int logLevel )
{
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
m_nLogLevel = logLevel;
return true;
}
bool CLogger::MakeLogDir( string programName, string logDir )
{
string path = logDir + "/" + programName;
struct stat dirStat;
// 해당 이름을 가진 파일 또는 디렉토리가 존재하고
if( lstat( path.c_str(), &dirStat ) == 0 )
{
// 해당 이름이 디렉토리인 경우
if( S_ISDIR( dirStat.st_mode ) == true )
{
return true;
}
else
{
cerr << "exist file with the same name as log path(" << path << ")." << endl;
return false;
}
}
// 디렉토리 가 존재하지 않는 경우 디렉토리 생성 시도
string cmd = "mkdir -p " + path;
system( cmd.c_str() );
if( IsDirectory( path ) == false )
{
cerr << "can't make log directory. path=" << path << "." << endl;
return false;
}
return true;
}
bool CLogger::IsDirectory( string path )
{
struct stat dirStat;
if( lstat ( path.c_str(), &dirStat ) != 0 )
{
cerr << "Log path not valid. Check path [" << path << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
// 해당 정보가 Directory 가 아닌 경우
if( S_ISDIR( dirStat.st_mode ) == false )
{
return false;
}
return true;
}
void CLogger::Exit()
{
if( m_bIsInitialized == false )
{
return;
}
pthread_mutex_lock( &m_mutex );
if( CLogger::m_pInstance != NULL )
{
delete CLogger::m_pInstance;
CLogger::m_pInstance = NULL;
m_bIsInitialized = false;
}
pthread_mutex_unlock( &m_mutex );
}
CLogger* CLogger::GetInstance()
{
return CLogger::m_pInstance;
}
string CLogger::GetLogFilename( struct tm &timeNow )
{
char timeStr[256];
snprintf( timeStr, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
// Make File Name
string filename = m_szLogDir + "/" + m_szProgramName + "/" + m_szProgramName + "_" + string( timeStr );
return filename;
}
bool CLogger::Write( int logLevel, const char * fmt, ...)
{
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
return Write( logLevel, PREFIX_DATE, NULL, 0, buffer );
}
bool CLogger::WriteNoPrefix( int logLevel, const char * fmt, ...)
{
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
return Write( logLevel, PREFIX_NONE, NULL, 0, buffer );
return false;
}
// CHG 2012-08-16 huibong
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
// 함수명 : Write -> WriteWithFunc 으로 변경 처리
bool CLogger::WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
{
if( filename == NULL || funcname == NULL || lineNum < 0 || fmt == NULL )
{
return false;
}
// 가변 인자 처리
va_list args;
char buffer[MAX_BUFFER_SIZE];
va_start( args, fmt );
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
{
va_end( args );
return false;
}
va_end(args);
char className[255];
string funcPrefix = GetClassName( className, filename );
funcPrefix += "::" + string( funcname ) + "()";
return Write( logLevel, PREFIX_FUNCTION, funcPrefix.c_str(), lineNum, buffer );
}
const char* CLogger::GetClassName( char* className, const char* filename )
{
if( className == NULL )
{
cout << "[ERROR] The input argument 'className' is NULL." << endl;
return NULL;
}
if( filename == NULL )
{
cout << "[ERROR] The input argument 'filename' is NULL." << endl;
strcpy( className, "NULL" );
return className;
}
int filenameSize = strlen( filename );
memcpy( className, filename, filenameSize );
// find end position
char endCharacter = '.';
int endPos = filenameSize - 1;
for( ; endPos > 0; --endPos )
{
if( className[endPos] == endCharacter )
{
break;
}
}
if( endPos == 0 )
{
cout << "[ERROR] endPos=0" << endl;
strcpy( className, "NULL" );
return className;
}
className[endPos] = '\0';
// find start position
char startCharacter = '/';
int startPos = endPos - 1;
for( ; startPos > 0; --startPos )
{
if( className[startPos] == startCharacter )
{
break;
}
}
if( startPos != 0 )
{
startPos += 1;
}
return (className + startPos );
}
bool CLogger::Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log )
{
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
if( logLevel > m_nLogLevel )
{
return false;
}
if( log == NULL )
{
return false;
}
// Get Current Data & Time
time_t now = time( NULL );
struct tm timeNow;
localtime_r( &now, &timeNow );
string filename = GetLogFilename( timeNow );
// Log file open
FILE* pFile = NULL;
pFile = fopen( filename.c_str(), "a+" );
if( pFile == NULL )
{
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
// 시간 정보처리
char timeStr[256];
snprintf( timeStr, (size_t)256, "[%02d:%02d:%02d]"
, timeNow.tm_hour, timeNow.tm_min, timeNow.tm_sec );
// Log Level 문자열 검색
string szLevel = m_vectorLogLevelString[ logLevel ];
switch( logPrefix )
{
case PREFIX_DATE:
/// 형식 예: [15:47:41] [DBG] sample log message.
fprintf( pFile, "%s [%-4s] %s\n", timeStr, szLevel.c_str(), log );
break;
case PREFIX_FUNCTION:
if( functionName == NULL )
{
fclose( pFile );
return false;
}
/// 형식 예: [15:47:41] [DBG] sample log message. [SomeClass::SomeFunction():12]
fprintf( pFile, "%s [%-4s] %s [%s:%d]\n", timeStr, szLevel.c_str(), log, functionName, lineNum );
break;
case PREFIX_NONE:
/// 형식 예: sample log message.
fprintf( pFile, "%s\n", log );
break;
}
// Write to log file
fflush( pFile );
// 종료 처리.
fclose( pFile );
return true;
}
bool CLogger::WriteHex( int logLevel, const unsigned char* data, const int size )
{
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
if( IsValidLogLevel( logLevel ) == false )
{
return false;
}
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
if( logLevel > m_nLogLevel )
{
return false;
}
if( data == NULL )
{
return false;
}
if( size <= 0 )
{
return false;
}
// Get Current Data & Time
time_t now = time( NULL );
struct tm timeNow;
localtime_r( &now, &timeNow );
string filename = GetLogFilename( timeNow );
// Log file open
FILE* pFile = NULL;
pFile = fopen( filename.c_str(), "a+" );
if( pFile == NULL )
{
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
return false;
}
for( int i = 0; i < size; ++i )
{
fprintf( pFile, "%02X", data[i] );
if( i == 0 )
{
continue;
}
if( ( (i+1) % 8 ) == 0 )
{
fprintf( pFile, " " );
}
if( ( (i+1) % 16 ) == 0 )
{
fprintf( pFile, " " );
}
if( ( (i+1) % 32 ) == 0 )
{
fprintf( pFile, "\n" );
}
}
fprintf( pFile, "\n" );
fflush( pFile );
// 종료 처리.
fclose( pFile );
return false;
}
+273
View File
@@ -0,0 +1,273 @@
/***************************************************************************
Logger.h
-----------------------------------------
begin : 2011/10/26
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.2.0.805
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __LOGGER_H__
#define __LOGGER_H__
#include <string>
#include <vector>
#include <pthread.h>
///@brief 로그 레벨 정의
#define LEMR 0 /* system is or will be unusable if situation is not resolved */
#define LALT 1 /* immediate action required */
#define LCRT 2 /* critical situations */
#define LERR 3 /* error conditions */
#define LWAR 4 /* recoverable errors */
#define LNOT 5 /* unusual situation that merits investigation */
#define LINF 6 /* information messages */
#define LDBG 7 /* verbose data for debugging */
#define LDEV 8 /* verbose data for developer */
#define LDEV1 9 /* start or end the function of application level */
#define LDEV2 10 /* start or end the function of application level */
#define MAX_LOG_LEVEL LDEV2
///@brief Log 정보를 파일로 저장하기 위한 Class.
///1. 가변 format 으로 전달된 로그 관련 정보를 Log Level 에 따라 로그 파일에 아래의 4가지 형식으로 저장한다.
///
/// 1.1 Prefix로 [hh:mm:ss]와 [ClassName::FunctionName]이 추가된 로그
/// LOG( level, format, ... ) 매크로 사용.
/// 예) [17:43:40] [DBG] log level debug [LoggerTestTestLogger]
///
/// 1.2 Prefix로 [hh:mm:ss]이 추가된 로그
/// _LOG( level, format, ... ) 매크로 사용
/// 예) [17:43:40] [EMR] log level emergency
///
/// 1.3 Prefix가 없는 로그
/// _LOG_( level, format, ... ) 매크로 사용
/// 예) log level emergency
///
/// 1.4 Hex 로그.
/// LOG_HEX( level, data, size ) 매크로 사용
/// 예) 00010203 04050607 08090A0B 0C0D0E0F
///
///2. Logger 객체 초기화시 전달된 Log Level 정보보다 전달받은 Log Level 정보가 큰 경우 해당 로그는 파일로 저장되지 않는다.
///
///3. 로그 파일은 매 일단위로 저장파일이 변경된다.
///
///4. 로그 저장을 위한 program 경로가 존재하지 않는 경우 자동 생성 처리된다.
///
///5. 로그 저장방식은 매 저장로그마다 open-close 로 처리된다.
///
///6. 파일로 기록시 Log Level 에 대한 정보도 함께 기록된다.
///
///7. 싱글톤으로 작성되었고, CLogger::Init(...)시에 쓰레드 안정성을 제공한다.
///
///8. 동적으로 로그 레벨을 변경할 수 있는 인터페이스를 제공한다.
///
class CLogger
{
// Attributes
private:
///@brief 싱글톤 객체 인트턴스.
static CLogger* m_pInstance;
///@brief 싱글톤 객체 초기화 여부.
static bool m_bIsInitialized;
///@brief 싱글톤 객체 초기화시 스레드 안정성을 위한 뮤텍스.
static pthread_mutex_t m_mutex;
///@brief 프로그램 이름. 로그 파일 경로를 만들 때 사용.
std::string m_szProgramName;
///@brief 공통 로그 디렉토리 이름. 로그 파일 경로를 만들 때 사용.
std::string m_szLogDir;
///@brief 로그 레벨.
int m_nLogLevel;
///@brief 로그 레벨에 대응되는 문자열 정보를 저장.
std::vector<std::string> m_vectorLogLevelString;
protected:
public:
///@brief 로그 형식을 지정.
typedef enum
{
PREFIX_NONE = 0, /// 클래스 설명의 1.3에 해당
PREFIX_DATE, /// 클래스 설명의 1.2에 해당
PREFIX_FUNCTION, /// 클래스 설명의 1.1에 해당
} LOG_PREFIX;
// Operations
private:
///@brief 생성자.
/// 프로그램 이름, 공통 로그 디렉토리, 로그 레벨을 저장하고
/// 로그 레벨에 대응되는 문자열 정보를 만든다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@param logLevel [in] 로그 레벨
CLogger( std::string programName, std::string logDir, int logLevel );
///@brief 소멸자.
/// 로그 레벨에 대응되는 문자열 정보를 저장하고 있는
/// 벡터 m_vectorLogLevelString을 clear 시킴.
virtual ~CLogger();
///@brief 로그 레벨에 대응되는 문자열을 만든다.
///@param none.
///@return none.
void MakeLogLevelString();
///@brief 로그 파일이 위치할 실제 로그 디렉토리를 생성한다.
/// 생성할 디렉토리 경로는 'logDir/programName'이 된다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@return 디렉토리가 이미 존재하거나 생성 성공하면 true,
/// 해당 경로가 존재하지만 디렉토리가 아니거나, 디렉토리 생성 실패하면 false 반환.
static bool MakeLogDir( std::string programName, std::string logDir );
///@brief 해당 경로가 디렉토리 인지 아닌지 판단.
///@param path [in] 디렉토리 인지 아닌지 판단할 경로.
///@return 해당 경로가 디렉토이면 true,
/// 경로가 존재하지 않거나 디렉토리가 아니면 false 반환.
static bool IsDirectory( std::string path );
///@brief 로그 레벨이 올바른지 판별.
///@param logLevel [in]
///@return 올바른 로그 레벨이면 true, 그렇지 않으면 false 반환.
static bool IsValidLogLevel( int logLevel );
///@brief 시간 정보를 입력 받아 로그 파일 이름을 만든다.
/// 로그 파일 이름 형식 : 프로그램명_YYYYMMDD.log
///param timeNow [in] 현재 시간 정보.
///return 로그 파일 이름.
std::string GetLogFilename( struct tm &timeNow );
///@brief 로그를 남기는는 클래스가 정의된 파일의 이름에서 클래스명을 추출한다.
/// 쓰레드 안정성을 보장한다.
///@param className [out] 파일 이름에서 추출된 클래스명
///@param filename [in] 파일 이름.
///@return 클래스명 추출이 성공하면 클래스명 문자열의 포인터, 추출 실패하면 NULL.
const char* GetClassName( char* className, const char* filename );
///@brief 인자 logPrefix에 따라 적절한 형식으로 로그 파일에 로그를 저장한다.
/// 인자 logLevel이 설정된 로그 레벨보다 높으면 로그를 출력하지 않는다.
///@param logLevel [in] 로그 레벨
///@param logPrefix [in] 로그 프리픽스 종류.
///@functionName [in] ClassName::FunctionNmae() 형식의 문자열.
///@lineNum [in] 라인 번호.
///@log [in] 출력하고자 하는 로그 내용.
bool Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log );
protected:
public:
///@brief 싱글톤 객체 m_pInstance를 생성하고 인자 정보로 로그 디렉토리를 만든다.
///@param programName [in] 프로그램 이름
///@param logDir [in] 공통 로그 디렉토리 경로
///@param logLevel [in] 로그 레벨
///@return 로그 디렉토리를 만들고 싱글톤 객체를 생성했으면 true,
/// 로그 디렉토리를 만들지 못 했거나 인자 값이 올바르지 않으면 false 반환.
static bool Init( std::string programName, std::string logDir, int logLevel );
///@brief 싱글톤 객체 m_pInstance를 delete 한다.
///@param none.
///@return none.
static void Exit();
///@brief 싱글톤 객체 m_pInstance를 반환한다.
///@param none.
///@return CLogger 객체의 인스턴스.
static CLogger* GetInstance();
///@brief Prefix로 [hh:mm:ss]이 추가된 형식으로 로그 저장.
///@param logLevel [in] 로그 레벨
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool Write( int logLevel, const char * fmt, ...)
__attribute__((format(printf, 3, 4)));
///@brief Prefix가 없는 로그 저장.
///@param logLevel [in] 로그 레벨
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteNoPrefix( int logLevel, const char * fmt, ...)
__attribute__((format(printf, 3, 4)));
// CHG 2012-08-16 huibong
// 가변인자를 사용하는 Write 함수 다중 정의로 인해...
// Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨.
// 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함.
///@brief Prefix로 [hh:mm:ss]와 [ClassName::FunctionName:line]이 추가된 형식으로 로그 저장.
///@param logLevel [in] 로그 레벨
///@param filename [in] 파일 이름
///@param funcname [in] 함수 이름
///@param lineNum [in] 라인 번호
///@param fmt [in] 로그 내용 포맷.
///@param __VAR_ARGS__ [in] 가변 인자.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
__attribute__((format(printf, 6, 7)));
///@brief 로그를 hex 형식으로 저장.
///@param logLevel [in] 로그 레벨
///@param data [in] hex 형식으로 출력할 데이터.
///@pram size [in] data의 크기.
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
bool WriteHex( int logLevel, const unsigned char* data, const int size );
///@brief 로그을 설정한다. 인자 logLevel이 적절한 값이면 새로운 값으로 변경하고
/// 적절한 값이 아니면 로그 레벨을 변경하지 않는다.
///@param logLevel [in] 설정할 로그 레벨
///@return none.
bool SetLogLevel( int logLevel );
inline int GetLogLevel() { return m_nLogLevel; };
inline std::string GetLogDir() { return m_szLogDir + "/" + m_szProgramName; };
};
#define LOG( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteWithFunc( level, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__ ); \
}
#define _LOG( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->Write( level, format, ##__VA_ARGS__ ); \
}
#define _LOG_( level, format, ... ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteNoPrefix( level, format, ##__VA_ARGS__ ); \
}
#define _LOG_HEX_( level, data, size ) \
if( CLogger::GetInstance() != NULL ) \
{ \
CLogger::GetInstance()->WriteHex( level, (const unsigned char*)data, size ); \
}
#define FUNC_BEGIN() LOG( LDEV1, "begin" )
#define FUNC_END() LOG( LDEV1, "end" )
#define FRM_BEGIN() LOG( LDEV2, "begin" )
#define FRM_END() LOG( LDEV2, "end" )
#endif // __LOGGER_H__
+68
View File
@@ -0,0 +1,68 @@
#****************************************************************************
# Makefile for INTERACTIVE Common Libaray
# -----------------------------------------
#
# begin : 2012/08/08
# copyright : (C) 2005 SolutionBox Inc.
# author : Service 1 Team
# email : svc1@solbox.com
# version : 1.0
#
# CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
# Redistribution and use in source and binary forms, with or with out
# modification, are not permitted in outside of SolutionBox Inc.
#*****************************************************************************
# Library info
LIB_NAME = InterCommon
LIB = lib$(LIB_NAME).a
OBJS = md5c.o Config.o Logger.o BaseSocket.o
# Compiler info
CC = /usr/bin/g++
AR = /usr/bin/ar
DIR_INCLUDE = -I/usr/local/include
ifeq ($(DEBUG), yes)
CFLAGS = -Wall -O0 -g -Wimplicit -Wreturn-type -Wunused -Wuninitialized\
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-D_REENTRANT -D_THREAD_SAFE -D_REENTRANT -D_PTHREADS
LFLAGS =
DFLAGS =
else
CFLAGS = -Wall -O3 -g -Wimplicit -Wreturn-type -Wunused -Wuninitialized\
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-D_REENTRANT -D_THREAD_SAFE -D_REENTRANT -D_PTHREADS
LFLAGS =
DFLAGS =
endif
############################
all:$(LIB)
sync
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
$(LIB): $(OBJS)
$(AR) crsv $@ $^
clean:
-rm -f *.o core *.out *.log
-rm -f $(LIB)
sync
install :
sync
# End of Makefile
+46
View File
@@ -0,0 +1,46 @@
/* GLOBAL.H - RSAREF types and constants */
/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
Inc., created 1991. All rights reserved.
*/
#ifndef _GLOBAL_H_
#define _GLOBAL_H_ 1
/* PROTOTYPES should be set to one if and only if the compiler supports
function argument prototyping.
The following makes PROTOTYPES default to 1 if it has not already been
defined as 0 with C compiler flags.
*/
#ifndef PROTOTYPES
#define PROTOTYPES 1
#endif
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
typedef unsigned int UINT4;
#ifndef NULL_PTR
#define NULL_PTR ((POINTER)0)
#endif
#ifndef UNUSED_ARG
#define UNUSED_ARG(x) x = *(&x);
#endif
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
returns an empty list.
*/
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif
#endif /* end _GLOBAL_H_ */
+50
View File
@@ -0,0 +1,50 @@
/* MD5.H - header file for MD5C.C
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#ifndef _MD5_H_
#define _MD5_H_ 1
#ifdef __cplusplus
extern "C" {
#endif
/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
void MD5Init PROTO_LIST ((MD5_CTX *));
void MD5Update PROTO_LIST
((MD5_CTX *, unsigned char *, unsigned int));
void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
#ifdef __cplusplus
}
#endif
#endif
+315
View File
@@ -0,0 +1,315 @@
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
//#include "stdafx.h"
#include "global.h"
#include "md5.h"
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
static void Encode PROTO_LIST
((unsigned char *, UINT4 *, unsigned int));
static void Decode PROTO_LIST
((UINT4 *, unsigned char *, unsigned int));
static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void MD5Init (MD5_CTX *context/* context */)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void MD5Update (MD5_CTX *context /* context */, unsigned char *input/* input block */, unsigned int inputLen/* length of input block */)
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)&input[i],
inputLen-i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void MD5Final (unsigned char digest[16]/* message digest */, MD5_CTX *context/* context */)
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)context, 0, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform (UINT4 state[4], unsigned char block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)x, 0, sizeof (x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
/* Note: Replace "for loop" with standard memcpy if possible.
*/
static void MD5_memcpy (POINTER output, POINTER input, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
/* Note: Replace "for loop" with standard memset if possible.
*/
static void MD5_memset (POINTER output, int value, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
}
+257
View File
@@ -0,0 +1,257 @@
/* MDDRIVER.C - test driver for MD2, MD4 and MD5
*/
/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
rights reserved.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/* The following makes MD default to MD5 if it has not already been
defined with C compiler flags.
*/
#include "stdafx.h"
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "global.h"
#define MD5 5
#ifndef MD
#define MD MD5
#endif
#if MD == 2
#include "md2.h"
#endif
#if MD == 4
#include "md4.h"
#endif
#if MD == 5
#include "md5.h"
#endif
/* Length of test block, number of test blocks.
*/
#define TEST_BLOCK_LEN 1024
#define TEST_BLOCK_COUNT 5000
static void MDString PROTO_LIST ((char *));
static void MDTimeTrial PROTO_LIST ((void));
static void MDTestSuite PROTO_LIST ((void));
static void MDFile PROTO_LIST ((char *));
static void MDFilter PROTO_LIST ((void));
static void MDPrint PROTO_LIST ((unsigned char [16]));
#if MD == 2
#define MD_CTX MD2_CTX
#define MDInit MD2Init
#define MDUpdate MD2Update
#define MDFinal MD2Final
#endif
#if MD == 4
#define MD_CTX MD4_CTX
#define MDInit MD4Init
#define MDUpdate MD4Update
#define MDFinal MD4Final
#endif
#if MD == 5
#define MD_CTX MD5_CTX
#define MDInit MD5Init
#define MDUpdate MD5Update
#define MDFinal MD5Final
#endif
/* Main driver.
Arguments (may be any combination):
-sstring - digests string
-t - runs time trial
-x - runs test script
filename - digests file
(none) - digests standard input
*/
/*
int main (int argc, char *argv[])
{
int i;
if (argc > 1)
for (i = 1; i < argc; i++)
if (argv[i][0] == '-' && argv[i][1] == 's')
MDString (argv[i] + 2);
else if (strcmp (argv[i], "-t") == 0)
MDTimeTrial ();
else if (strcmp (argv[i], "-x") == 0)
MDTestSuite ();
else
MDFile (argv[i]);
else
MDFilter ();
return (0);
}
*/
int _tmain(int argc, _TCHAR* argv[])
{
int i;
if (argc > 1) {
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-' && argv[i][1] == _T('s'))
MDString ((char*)(argv[i] + 2));
else if (_tcscmp (argv[i], _T("-t")) == 0)
MDTimeTrial ();
else if (_tcscmp (argv[i], _T("-x")) == 0)
MDTestSuite ();
else
MDFile ((char*)argv[i]);
}
} else {
MDFilter ();
}
return 0;
}
/* Digests a string and prints the result.
*/
static void MDString (char *string)
{
MD_CTX context;
unsigned char digest[16];
unsigned int len = (unsigned int)strlen (string);
MDInit (&context);
MDUpdate (&context, (unsigned char*)string, len);
MDFinal (digest, &context);
printf ("MD%d (\"%s\") = ", MD, string);
MDPrint (digest);
printf ("\n");
}
/* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte
blocks.
*/
static void MDTimeTrial ()
{
MD_CTX context;
time_t endTime, startTime;
unsigned char block[TEST_BLOCK_LEN], digest[16];
unsigned int i;
printf
("MD%d time trial. Digesting %d %d-byte blocks ...", MD,
TEST_BLOCK_COUNT, TEST_BLOCK_LEN);
/* Initialize block */
for (i = 0; i < TEST_BLOCK_LEN; i++)
block[i] = (unsigned char)(i & 0xff);
/* Start timer */
time (&startTime);
/* Digest blocks */
MDInit (&context);
for (i = 0; i < TEST_BLOCK_COUNT; i++)
MDUpdate (&context, block, TEST_BLOCK_LEN);
MDFinal (digest, &context);
/* Stop timer */
time (&endTime);
printf (" done\n");
printf ("Digest = ");
MDPrint (digest);
printf ("\nTime = %ld seconds\n", (long)(endTime-startTime));
printf
("Speed = %ld bytes/second\n",
(long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime));
}
/* Digests a reference suite of strings and prints the results.
*/
static void MDTestSuite ()
{
printf ("MD%d test suite:\n", MD);
MDString ("");
MDString ("a");
MDString ("abc");
MDString ("message digest");
MDString ("abcdefghijklmnopqrstuvwxyz");
MDString
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
MDString
("1234567890123456789012345678901234567890\
1234567890123456789012345678901234567890");
}
/* Digests a file and prints the result.
*/
static void MDFile (char *filename)
{
FILE *file;
MD_CTX context;
int len;
unsigned char buffer[1024], digest[16];
if ((file = fopen (filename, "rb")) == NULL)
printf ("%s can't be opened\n", filename);
else {
MDInit (&context);
while (len = fread (buffer, 1, 1024, file))
MDUpdate (&context, buffer, len);
MDFinal (digest, &context);
fclose (file);
printf ("MD%d (%s) = ", MD, filename);
MDPrint (digest);
printf ("\n");
}
}
/* Digests the standard input and prints the result.
*/
static void MDFilter ()
{
MD_CTX context;
int len;
unsigned char buffer[16], digest[16];
MDInit (&context);
while (len = fread (buffer, 1, 16, stdin))
MDUpdate (&context, buffer, len);
MDFinal (digest, &context);
MDPrint (digest);
printf ("\n");
}
/* Prints a message digest in hexadecimal.
*/
static void MDPrint (unsigned char digest[16])
{
unsigned int i;
for (i = 0; i < 16; i++)
printf ("%02x", digest[i]);
}
+304
View File
@@ -0,0 +1,304 @@
/***************************************************************************
Config Class (Config.cpp)
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "cc_tsd.h"
#include "Configs.h"
#include "Config.h"
CMyConfig *CMyConfig::m_pInstance = NULL;
void StringSplit(string str, string delim, vector<string> &results, bool bUseEmpty /*= false*/)
{
const string strEmpty("");
string::size_type cutAt;
while( (cutAt = str.find_first_of(delim)) != str.npos )
{
if(cutAt > 0)
{
results.push_back(str.substr(0,cutAt));
}
else
{
if(bUseEmpty && cutAt == 0)
results.push_back(strEmpty);
}
str = str.substr(cutAt+1);
}
if(str.length() > 0)
{
results.push_back(str);
}
}
CCommonConfig::CCommonConfig( string szFilename, string szProgramName )
: m_szConfigFile(szFilename), m_szProgramName(szProgramName), m_nLogLevel(0)
{
}
CCommonConfig::~CCommonConfig()
{
}
bool CCommonConfig::LoadConf()
{
#ifdef _DEBUG
cout << "CCommonConfig::LoadConf() =>" << endl;
#endif // _DEBUG
string szValue;
// Config 처리를 위한 객체 생성
Config conf;
// Config File open
if( conf.Open( m_szConfigFile ) == false )
{
m_szErrMessage = "Config file open failed.[" + m_szConfigFile + "]";
return false;
}
// log path
if( conf.GetConfig( "COMMON", "DEFAULT_LOG_DIR", szValue ) )
{
m_szAppLogRoot = szValue;
}
// log level
if( conf.GetConfig( "COMMON", "LOG_LEVEL", szValue ) )
{
m_nLogLevel = atoi( szValue.c_str() );
}
#ifdef _DEBUG
PrintValue();
#endif // _DEBUG
return true;
}
bool CCommonConfig::CheckValue()
{
if(m_szAppLogRoot.empty())
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->DEFAULT_LOG_DIR";
return false;
}
if( m_nLogLevel <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + " or COMMON]->LOG_LEVEL";
return false;
}
return true;
}
void CCommonConfig::PrintValue()
{
cout << "Log Value : " << m_szAppLogRoot << "," << m_nLogLevel << endl;
}
CMyConfig::CMyConfig( string szFilename, string szProgramName)
: CCommonConfig(szFilename, szProgramName)
, m_nListenPort(0), m_nDBPort(0), m_bLoginInfo(false)
{
}
CMyConfig::~CMyConfig()
{
}
bool CMyConfig::LoadConf()
{
if( CCommonConfig::LoadConf() == false)
return false;
#ifdef _DEBUG
cout << "CMyConfig::LoadConf() =>" << endl;
#endif // _DEBUG
string szValue;
// Config 처리를 위한 객체 생성
Config conf;
// Config File open
if( conf.Open( m_szConfigFile ) == false )
{
m_szErrMessage = "Config file open failed.[" + m_szConfigFile + "]";
return false;
}
// log dir
if( conf.GetConfig( m_szProgramName, "DEFAULT_LOG_DIR", szValue ) )
{
m_szAppLogRoot = szValue;
}
// log level
if( conf.GetConfig( m_szProgramName, "LOG_LEVEL", szValue ) )
{
m_nLogLevel = atoi( szValue.c_str() );
}
// TCP Listen Port
if(conf.GetConfig( m_szProgramName, "TCP_LISTEN_PORT", szValue ))
{
m_nListenPort = atoi( szValue.c_str() );
}
// db host(ip)
if( conf.GetConfig( m_szProgramName, "CCDB_IP", szValue ) )
{
m_szDBIP = szValue;
}
// db port
if( conf.GetConfig( m_szProgramName, "CCDB_PORT", szValue ) )
{
m_nDBPort = atoi( szValue.c_str() );
}
// db name
if( conf.GetConfig( m_szProgramName, "CCDB_DB_NAME", szValue ) )
{
m_szDBName = szValue;
}
// db account
if( conf.GetConfig( m_szProgramName, "CCDB_ACCT", szValue ) )
{
m_szDBAccount = szValue;
}
// db account password
if( conf.GetConfig( m_szProgramName, "CCDB_ACCT_PW", szValue ) )
{
m_szDBPwd = szValue;
}
// log dir
if( conf.GetConfig( m_szProgramName, "LOGIN_INFO_INSERT", szValue ) )
{
m_szLoginInfo = szValue;
}
#ifdef _DEBUG
PrintValue();
#endif // _DEBUG
return true;
}
bool CMyConfig::CheckValue()
{
if( CCommonConfig::CheckValue() )
{
if( m_nListenPort <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->TCP_LISTEN_PORT";
return false;
}
if(m_szDBIP.size() <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->CCDB_IP";
return false;
}
if( m_nDBPort <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->CCDB_PORT";
return false;
}
if(m_szDBName.size() <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->CCDB_DB_NAME";
return false;
}
if(m_szDBAccount.size() <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->CCDB_ACCT";
return false;
}
if(m_szDBPwd.size() <= 0)
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->CCDB_ACCT_PW";
return false;
}
if( strcmp(m_szLoginInfo.c_str(), "on") == 0 || strcmp(m_szLoginInfo.c_str(), "off") == 0 )
{
if( strcmp(m_szLoginInfo.c_str(), "on") == 0 )
{
m_bLoginInfo = true;
}
else
{
m_bLoginInfo = false;
}
}
else
{
m_szErrMessage = "Config info get failed. [" + m_szProgramName + "]->LOGIN_INFO_INSERT";
return false;
}
return true;
}
else
{
return false;
}
return true;
}
void CMyConfig::PrintValue()
{
CCommonConfig::PrintValue();
cout << "TCP Listen Port :" << m_nListenPort << endl;
cout << "DB Host :" << m_szDBIP << endl;
cout << "DB Port :" << m_nDBPort << endl;
cout << "DB Name :" << m_szDBName << endl;
cout << "DB Account :" << m_szDBAccount << endl;
cout << "DB Account Pwd :" << m_szDBPwd << endl;
cout << "Loginf Info :" << m_szLoginInfo << endl;
}
bool CMyConfig::Init( string szProgramName, string szFilename )
{
if( CMyConfig::m_pInstance == NULL )
{
CMyConfig::m_pInstance = new CMyConfig(szFilename, szProgramName);
}
return true;
}
void CMyConfig::Exit()
{
if( CMyConfig::m_pInstance != NULL )
{
delete CMyConfig::m_pInstance;
CMyConfig::m_pInstance = NULL;
}
}
CMyConfig* CMyConfig::GetInstance()
{
return CMyConfig::m_pInstance;
}
+95
View File
@@ -0,0 +1,95 @@
/***************************************************************************
Config Class Header ( Config.h )
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "cc_tsd.h"
#ifndef __CC_TSD_CONFIG_H__
#define __CC_TSD_CONFIG_H__
void StringSplit(string str, string delim, vector<string> &results, bool bUseEmpty /*= false*/);
class CCommonConfig
{
public:
CCommonConfig( string szFilename, string szProgramName );
virtual ~CCommonConfig();
bool LoadConf();
bool CheckValue();
void PrintValue();
inline const char * GetErrMessage() { return m_szErrMessage.c_str(); }
inline const char * GetAppLogRoot() { return m_szAppLogRoot.c_str(); }
inline int GetAppLogLevel() { return m_nLogLevel; }
protected:
string m_szConfigFile;
string m_szProgramName;
string m_szErrMessage;
// log
string m_szAppLogRoot;
int m_nLogLevel;
private:
};
class CMyConfig : public CCommonConfig
{
public:
static bool Init( string szProgramName, string szFilename );
static void Exit();
static CMyConfig* GetInstance();
private:
static CMyConfig* m_pInstance;
public:
bool LoadConf();
bool CheckValue();
inline int GetTCPListenPort() { return m_nListenPort; }
inline string GetDBIP() { return m_szDBIP; }
inline int GetDBPort() { return m_nDBPort; }
inline string GetDBName() { return m_szDBName; }
inline string GetDBAccount() { return m_szDBAccount; }
inline string GetDBPwd() { return m_szDBPwd; }
inline bool GetLoginInfo() { return m_bLoginInfo; }
void PrintValue();
protected:
CMyConfig( string szFilename, string szProgramName );
virtual ~CMyConfig();
protected:
int m_nListenPort;
string m_szDBIP;
int m_nDBPort;
string m_szDBName;
string m_szDBAccount;
string m_szDBPwd;
bool m_bLoginInfo;
string m_szLoginInfo;
private:
};
#endif // __CC_STATD_CONFIG_H__
+71
View File
@@ -0,0 +1,71 @@
/***************************************************************************
Data Class
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __DATA_H__
#define __DATA_H__
#include "cc_tsd.h"
#include <list>
#include <map>
#include <string>
#include <time.h>
/// @brief CLoginInfo class
class CLoginInfo
{
public :
// service ID
std::string m_szUserID;
std::string m_szIssuer;
std::string m_szClientIP;
std::string m_szLoginDate;
}; // ~class CLoginInfo
/// @brief CLoginInfo class
class CServiceInfo
{
public :
std::string m_szServiceSeq;
std::string m_szServiceID;
std::string m_szRcDomain;
std::string m_szServiceDomain;
std::string m_szRctsDomain;
std::string m_szStatusCode;
std::string m_szCode;
}; // ~class CServiceInfo
typedef map< std::string, CServiceInfo > CServiceInfoMap;
typedef pair< std::string, CServiceInfo > CServiceInfoPair;
/// @brief CLoginInfo class
class CCustomerInfo
{
public :
// service ID
std::string m_szUserSeq;
std::string m_szUserID;
std::string m_szPassWord;
//!! Map
CServiceInfoMap mapServiceInfo;
}; // ~class CServiceInfo
typedef map< std::string, CCustomerInfo > CCustomerInfoMap;
typedef pair< std::string, CCustomerInfo > CCustomerInfoPair;
#endif //__DATA_H__
+127
View File
@@ -0,0 +1,127 @@
/***************************************************************************
Queue Class
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "DataQueue.h"
#include "Data.h"
using namespace std;
#define MX_LOCK_DATA()\
do \
{\
pthread_mutex_lock(&m_mxData);\
} while( 0 )
#define MX_UNLOCK_DATA()\
do \
{\
pthread_mutex_unlock(&m_mxData);\
} while( 0 )
#define MX_LOCK_MAXSIZE()\
do \
{\
pthread_mutex_lock(&m_mxMaxSize);\
} while( 0 )
#define MX_UNLOCK_MAXSIZE()\
do \
{\
pthread_mutex_unlock(&m_mxMaxSize);\
} while( 0 )
template <class DataClass>
CQueue<DataClass>::CQueue()
//CQueue::CQueue()
: m_nMaxSize(DEFAULT_MAX_QUEUE_SIZE)
, m_nDepth(0)
{
pthread_mutex_init(&m_mxData, NULL);
pthread_mutex_init(&m_mxMaxSize, NULL);
}
template <class DataClass>
CQueue<DataClass>::~CQueue()
{
pthread_mutex_destroy(&m_mxData);
pthread_mutex_destroy(&m_mxMaxSize);
}
template <class DataClass>
void CQueue<DataClass>::Init(void)
{
//clear queue
MX_LOCK_DATA();
while ( !m_qData.empty() )
{
Pop();
}
MX_UNLOCK_DATA();
}
template <class DataClass>
bool CQueue<DataClass>::Push(DataClass& userData)
{
if ( GetCurrentMaxSize() != DEFAULT_MAX_QUEUE_SIZE && GetDepth() >= GetCurrentMaxSize() )
{
return false;
}
MX_LOCK_DATA();
m_qData.push(userData);
MX_UNLOCK_DATA();
return true;
}
template <class DataClass>
bool CQueue<DataClass>::Pop(void)
{
if ( GetDepth() < 0 )
{
return false;
}
MX_LOCK_DATA();
m_qData.pop();
MX_UNLOCK_DATA();
return true;
}
template <class DataClass>
DataClass CQueue<DataClass>::Front(void)
{
return m_qData.front();
}
template <class DataClass>
int CQueue<DataClass>::GetCurrentMaxSize(void)
{
return m_nMaxSize;
}
template <class DataClass>
bool CQueue<DataClass>::SetCurrentMaxSize(int& nMaxSize)
{
if (nMaxSize < 0)
{
return false;
}
MX_LOCK_MAXSIZE();
m_nMaxSize = nMaxSize;
MX_UNLOCK_MAXSIZE();
return true;
}
template <class DataClass>
int CQueue<DataClass>::GetDepth(void)
{
return m_qData.size();
}
// FIXABLE: if u need another type queue, add or remove type
template class CQueue<CLoginInfo>;
+74
View File
@@ -0,0 +1,74 @@
/***************************************************************************
Queue Class
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __DATA_QUEUE_H__
#define __DATA_QUEUE_H__
#include <pthread.h>
#include <queue>
#define DEFAULT_MAX_QUEUE_SIZE 0
template <class DataClass>
/// @brief CQueue class
class CQueue
{
public :
CQueue();
~CQueue();
/// @brief clear queue
void Init(void);
/// @brief push data
/// @param userData [in] DataClass
/// @return 성공은 return true, 그 외에는 return false
bool Push(DataClass& userData);
/// @brief pop data ( just remove from queue )
/// @return 성공은 return true, 그 외에는 return false
bool Pop();
/// @brief GetDataClass, (it doesn't remove data from queue)
/// @return 성공은 return true, 그 외에는 return false
DataClass Front();
/// @brief get max queue size, default is 0 (0 means infinity)
/// @return 성공은 0,+ 그 외에는 -
int GetCurrentMaxSize(void);
/// @brief set max queue size, it have nothing to do with memory allocation in this class.
// please use it for infinity queue size to limit the speed what job processing.
/// @param userData [in] set 0 to infinity or positive integer( default: 0)
/// @return 성공은 return true, 그 외에는 return false
bool SetCurrentMaxSize(int& nMaxSize);
/// @brief 현재 Queue의 Depth(size)를 리턴한다.
/// @return stl queue의 size 값
int GetDepth(void);
private :
/// @brief 각 데이터별로 Queue에 들어있는 1건의 실제 데이터.
std::queue <DataClass> m_qData;
/// @brief 큐의 최대크기를 설정하는 변수
int m_nMaxSize;
/// @brief 큐의 현재 크기를 갖는 변수
int m_nDepth;
/// @brief Data에 대한 뮤텍스 변수
pthread_mutex_t m_mxData;
/// @brief MaxSize에 대한 뮤텍스 변수
pthread_mutex_t m_mxMaxSize;
}; // ~class CQueue
#endif //__DATA_QUEUE_H__
+157
View File
@@ -0,0 +1,157 @@
/***************************************************************************
Database Class
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "Database.h"
#include <string.h>
#include <stdlib.h>
DataBase::~DataBase()
{
if(m_PGconn != NULL) {
PgCloseDB();
}
}
PGconn *DataBase::PgOpenDB(string &strHost, int Port, string &strDBName, string &strAcct, string &strPasswd)
{
char szPort[12];
::memset(szPort, 0, sizeof(szPort));
::snprintf(szPort, sizeof(szPort), "%d", Port);
m_PGconn = PQsetdbLogin(strHost.c_str(), szPort, NULL, NULL, strDBName.c_str(), strAcct.c_str(), strPasswd.c_str());
if(PQstatus(m_PGconn) == CONNECTION_BAD) {
return NULL;
}
return m_PGconn;
}
PGconn *DataBase::PgOpenDB(const char *pszDBName)
{
m_PGconn = PQsetdb(NULL, NULL, NULL, NULL, pszDBName);
if(PQstatus(m_PGconn) == CONNECTION_BAD) {
return NULL;
}
return m_PGconn;
}
void DataBase::PgCloseDB()
{
if(m_PGconn != NULL)
{
PQfinish(m_PGconn);
m_PGconn = NULL;
}
}
int DataBase::PgResult(CFLAG flag)
{
int fRet = 0;
int Result;
Result = PQresultStatus(m_pRes);
switch(Result) {
case PGRES_EMPTY_QUERY :
fRet = -1;
break;
case PGRES_BAD_RESPONSE :
fRet = -2;
break;
case PGRES_NONFATAL_ERROR :
fRet = -3;
break;
case PGRES_FATAL_ERROR :
fRet = -4;
break;
case PGRES_TUPLES_OK :
fRet = 1;
break;
case PGRES_COMMAND_OK :
fRet = 2;
break;
}
if(fRet < 0) {
m_ErrorMessage = PQresultErrorMessage(m_pRes);
}
m_ResultCode = Result;
if(flag == CLEAR) {
PQclear(m_pRes);
}
return fRet;
}
string &DataBase::GetErrorMessage()
{
return m_ErrorMessage;
}
int DataBase::GetCmdTuples()
{
//fprintf(stderr, "DataBase::GetCmdTuples PQcmdTuples %s\n", PQcmdTuples(m_pRes));
return (int)atoi(PQcmdTuples(m_pRes));
}
int DataBase::GetNoTuples()
{
return PQntuples(m_pRes);
}
int DataBase::GetNoFields()
{
return PQnfields(m_pRes);
}
PGresult *DataBase::GetRes()
{
return m_pRes;
}
void DataBase::PgClear()
{
PQclear(m_pRes);
}
char *DataBase::GetValue(int tuple, int field)
{
return PQgetvalue(m_pRes, tuple, field);
}
int DataBase::PgDoExec(char *pszQuery)
{
return this->PgDoExec(pszQuery, NOT_CLEAR);
}
int DataBase::PgDoExec(string &strQuery)
{
return this->PgDoExec((char *)strQuery.c_str(), NOT_CLEAR);
}
int DataBase::PgDoExec(char *pszQuery, CFLAG flag)
{
if(m_PGconn == NULL) return -1;
m_pRes = PQexec(m_PGconn, pszQuery);
return PgResult(flag);
}
int DataBase::PgEscapeString(char *to, const char *from, size_t length)
{
int retval = 0;
//PQescapeStringConn(m_PGconn, to, from, length, &retval);
PQescapeString(to, from, length);
return retval;
}
+55
View File
@@ -0,0 +1,55 @@
/***************************************************************************
Database Class
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __DATABASE_H__
#define __DATABASE_H__
#include <iostream>
#include <string>
#include "libpq-fe.h"
#define MaxSizeOfDBQuery 1024*9
using namespace std;
class DataBase
{
public:
enum CFLAG { CLEAR = 1, NOT_CLEAR };
DataBase() { m_PGconn = NULL; m_pRes = NULL;}
~DataBase();
PGconn *PgOpenDB(string &strHost, int Port, string &strDBName, string &strAcct, string &strPasswd);
PGconn *PgOpenDB(const char *pszDBName);
void PgCloseDB();
int PgResult(CFLAG flag);
PGconn *GetPgConn();
PGresult *GetRes();
int GetCmdTuples();
int GetNoTuples();
int GetNoFields();
int GetResultCode() { return m_ResultCode; }
char *GetValue(int tuple, int field);
void PgClear();
int PgDoExec(string &strQuery);
int PgDoExec(char *pszQuery);
int PgDoExec(char *pszQuery, CFLAG flag);
int PgEscapeString(char *to, const char *from, size_t length);
string &GetErrorMessage();
private:
int m_ResultCode;
PGconn *m_PGconn;
PGresult *m_pRes;
string m_ErrorMessage;
};
#endif // ~__DATABASE_H__
+481
View File
@@ -0,0 +1,481 @@
/***************************************************************************
Interface Processor Class
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "InterfaceProcessor.h"
#include "Logger.h"
#include "protocol.h"
#include "global.h"
#include "md5.h"
#include "Configs.h"
#define AuthPrime 137897
#define MaxSizeOfRcvBuffer 1024
#define MD_CTX MD5_CTX
#define MDInit MD5Init
#define MDUpdate MD5Update
#define MDFinal MD5Final
void getHashedStr(char *pszPlain, char *pszHashed)
{
unsigned char szDigest[16];
char szHexBuffer[3];
string szResult;
MD_CTX md5Context;
MDInit( &md5Context );
MDUpdate( &md5Context, (unsigned char*)pszPlain, ::strlen(pszPlain));
MDFinal( szDigest, &md5Context );
// 해시값을 hex_digest 값으로 바꿔준다.
for(int i = 0; i<16 ; i++ )
{
memset( szHexBuffer, 0x00, sizeof( szHexBuffer ) );
sprintf( szHexBuffer, "%02x", szDigest[i] );
szResult.append( (char*)szHexBuffer);
}
::snprintf(pszHashed, 33, "%s", szResult.c_str());
}
CInterfaceProcessor::CInterfaceProcessor()
: CBaseSocket( SOCKET_NOT_VALID )
{
}
CInterfaceProcessor::CInterfaceProcessor(int clientsd, string szClientIP,
CQueue<CLoginInfo> *pQueueLoginInfo, CServiceInfoUpdater *pobjServiceInfoUpdater)
: CBaseSocket( clientsd ), m_szClientIP(szClientIP)
,m_pQueueLoginInfo(pQueueLoginInfo), m_pobjServiceInfoUpdater(pobjServiceInfoUpdater)
{
m_responseBody = NULL;
}
CInterfaceProcessor::~CInterfaceProcessor()
{
LOG(LDEV, "~CInterfaceProcessor ");
if ( m_responseBody != NULL )
delete m_responseBody;
Close();
}
int CInterfaceProcessor::Respose_cctimed(char *_pszRcvdReq )
{
int nWrite = 0;
time_sync_t current_time;
time_sync_t *pAuthVal = NULL;
pAuthVal = (time_sync_t *)_pszRcvdReq;
if((ntohl(pAuthVal->sync_info) % AuthPrime) > 0) {
LOG( LERR, "<Time Request> AuthPrime value is not valid.[%d]", ntohl(pAuthVal->sync_info) % AuthPrime );
return -2;
}
current_time.sync_info = htonl(time(NULL));
nWrite = WriteN((char *)&current_time, sizeof(current_time));
if(nWrite <= 0) {
LOG( LERR, "<Time Request> Socket Write Error. (errmsg: %s) " , strerror(errno) );
return -3;
}
return 1;
}
void *CInterfaceProcessor::_entry_func(void *arg)
{
CInterfaceProcessor* pObject = reinterpret_cast<CInterfaceProcessor *>(arg);
pthread_detach(pthread_self());
MsgHeader *msgHeader;
int nResult;
while ( 1 )
{
// 헤더 부분을 읽는다.
// 단, 본 프로그램은 cc_timed와 cc_tsd 역할을 모두 수행하는데도 불구하고...
// 가cc_timed 과거에 개발될때 Header가 명확히 정의되지 않고 개발되었다.
// 읽기 요청했을 때 readsize가
// buffer size는 Header 만큼버퍼 생성
char recvBuffer[sizeof(MsgHeader)];
// 버퍼 초기화
memset(recvBuffer, 0x00, sizeof(MsgHeader));
// 2차 읽기 크기
int nReadCnt = 0;
// 1차 읽기 시도.
int nRead = pObject->Read(recvBuffer, sizeof(MsgHeader));
if( nRead == sizeof(time_sync_t) )
{
_LOG( LINF, "<Time Request> Client IP : %s.", pObject->m_szClientIP.c_str());
//cc_timed의 요청이면...
pObject->Respose_cctimed(recvBuffer);
break;
}
else
{
if( nRead <= 0 )
{
//읽기 실패 또는 관제를 위한 연결로 간주하고 중단.
// close() 처리함.
break;
}
else
{
//cc_timed의 요청이 아니면..
_LOG(LDBG, "Request of Service Info. Client IP : %s.", pObject->m_szClientIP.c_str());
// MsgHeader를 추가로 읽을 필요가 있는지를 확인한다.
if( nRead != sizeof(MsgHeader) )
{
// 2차 읽기 시도...
nReadCnt = pObject->ReadNTimeout((recvBuffer+nRead), (sizeof(MsgHeader) - nRead));
// nRead 0: Socket Closed, -1: error , -2: Timeout 이므로
if( nReadCnt <= 0 )
{
LOG(LERR, "Header read failed.");
break;
}
}
msgHeader = (MsgHeader* )&recvBuffer;
}
}
// process body
//
nResult = pObject->CheckRequestMode(msgHeader);
// 잘못된 요청일 경우
if( nResult == -1 )
{
// 지원되지 않는 요청을 한 경우는 response를 줄 필요 없이 종료한다.
break;
}
// 요청에 대한 응답 구조체를 생성한다.
nResult = pObject->ProcessingJob(msgHeader);
// 잘못된 요청일 경우
if( nResult == -1 )
{
// 지원되지 않는 요청을 한 경우는 response를 줄 필요 없이 종료한다.
break;
}
// 결과를 보내준다.
// 내부에서 모두 만들어 줌.
pObject->SendResult(nResult, msgHeader);
break;
}
if(pObject)
{
delete pObject;
}
return 0;
}
int CInterfaceProcessor::Run()
{
pthread_t workerthread = 0;
// start thread
int ret = pthread_create(&workerthread, 0, _entry_func, (void*)this);
if (ret != 0)
{
ostringstream msg;
msg << "Client Thread create failed.[" << errno << "]";
_LOG(LINF, "%s", msg.str().c_str());
return -1;
}
sleep(0);
return ret;
}
int CInterfaceProcessor::CheckRequestMode(MsgHeader *msgHeader)
{
LOG(LDEV, "-----MsgHeader --------------");
LOG(LDEV, "!m_msgHeader->m_szTID : %s", msgHeader->m_szTID);
LOG(LDEV, "!m_msgHeader->m_ulMode : %x", ntohl(msgHeader->m_ulMode));
LOG(LDEV, "!m_msgHeader->m_szIssuer : %s", msgHeader->m_szIssuer);
LOG(LDEV, "!m_msgHeader->m_szServiceID : %s", msgHeader->m_szServiceID);
LOG(LDEV, "!m_msgHeader->m_ulResult : %d", ntohl(msgHeader->m_ulResult));
LOG(LDEV, "!m_msgHeader->m_ulBodyLength : %d", ntohl(msgHeader->m_ulBodyLength));
LOG(LDEV, "!-----MsgHeader END-----------");
switch(ntohl(msgHeader->m_ulMode))
{
case MODE_SRV_LST_2ND_REQUEST :
return 0;
break;
case MODE_SRV_LST_REQUEST :
case MODE_USER_DATA_MODIFIER_REQ :
case MODE_APACHE_ERROR_LOG_REQ :
case MODE_APACHE_ACCESS_LOG_REQ :
case MODE_DEFAULT :
case MODE_SRV_TRAFFIC_REQUEST :
_LOG(LINF, "Currently, the protocol is not supported. code : %x Client IP : %s", ntohl(msgHeader->m_ulMode), m_szClientIP.c_str());
break;
default :
_LOG(LINF, "Invalid request. Client IP : %s", m_szClientIP.c_str());
break;
}
return -1;
}
bool CInterfaceProcessor::ParseUserInfo(const char *pszRcvd, user_auth_t *pUserAuthInfo)
{
int nFlag = 0;
int nElement = 0;
char szTmpBuffer[52];
if((pszRcvd == NULL) || (pUserAuthInfo == NULL)) {
return false;
}
while(*pszRcvd != '\0') {
if(*pszRcvd != CODE_ESC) {
if(*pszRcvd != '\0') {
szTmpBuffer[nFlag++] = *pszRcvd++;
}
} else {
szTmpBuffer[nFlag] = '\0';
if(nElement == 0) {
::snprintf(pUserAuthInfo->szUserID, sizeof(pUserAuthInfo->szUserID), "%s", szTmpBuffer);
} else if (nElement == 1) {
::snprintf(pUserAuthInfo->szHashed, sizeof(pUserAuthInfo->szHashed), "%s", szTmpBuffer);
}
::memset(szTmpBuffer, 0, 52);
*pszRcvd++;
nFlag = 0;
nElement++;
}
}
szTmpBuffer[nFlag] = '\0';
pUserAuthInfo->reqTime = (time_t)::atol(szTmpBuffer);
return true;
}
int CInterfaceProcessor::ProcessingJob(MsgHeader *msgHeader)
{
int nReadCnt = 0;
// body의 내용은 user_auth_t 구조체의 내용들을 포함한다.
user_auth_t stUserAuthInfo;
char recvBuffer[MaxSizeOfRcvBuffer];
char szUserVerInfo[MaxSizeOfRcvBuffer];
char szHashedUserInfo[MaxSizeOfRcvBuffer];
::memset(recvBuffer, 0, MaxSizeOfRcvBuffer);
// 1. body 정보를 읽는다.
nReadCnt = ReadNTimeout(recvBuffer, ntohl(msgHeader->m_ulBodyLength));
// nRead 0: Socket Closed, -1: error , -2: Timeout 이므로
if( nReadCnt <= 0 )
{
LOG(LERR, "Body read failed.");
return -1;
}
if ( ParseUserInfo(recvBuffer, &stUserAuthInfo) == false )
{
LOG(LERR, "Body Parsing failed.");
return -1;
}
LOG(LDEV, "-----stUserAuthInfo --------------");
LOG(LDEV, "!sp_user_id : %s", stUserAuthInfo.szUserID);
LOG(LDEV, "!sp_hash_value : %s (%d)", stUserAuthInfo.szHashed,(int) strlen(stUserAuthInfo.szHashed));
LOG(LDEV, "!reqTime : %ld", stUserAuthInfo.reqTime);
LOG(LDEV, "!-----stUserAuthInfo END-----------");
// 2. 고객 ID를 이용해 user_seq 값을 얻는다.
CCustomerInfo objCustomerInfo;
if( m_pobjServiceInfoUpdater->GetUserServiceData(stUserAuthInfo.szUserID, objCustomerInfo) == false )
{
LOG(LERR, "Not Found User's(ID:%s) Info: ", stUserAuthInfo.szUserID);
return PROTO_FAILURE_AUTH;
}
// 사용자 아이디를 저장해둔다.
m_szUserID = objCustomerInfo.m_szUserID;
LOG(LDEV, "xxx666_m_szUserSeq :%s", objCustomerInfo.m_szUserSeq.c_str());
LOG(LDEV, "xxx666_m_szUserID :%s", objCustomerInfo.m_szUserID.c_str());
LOG(LDEV, "xxx666_m_szPassWord :%s", objCustomerInfo.m_szPassWord.c_str());
// 3. hash 고객에 해당하는 패스워드를 가지고 md5 hash를 생성한다.
::snprintf(szUserVerInfo, sizeof(szUserVerInfo), "%s%s%ld", stUserAuthInfo.szUserID
, objCustomerInfo.m_szPassWord.c_str()
, stUserAuthInfo.reqTime);
getHashedStr(szUserVerInfo, szHashedUserInfo);
LOG(LDEV, "Hashed value11: %s", szHashedUserInfo);
LOG(LDEV, "Hashed value22: %s", stUserAuthInfo.szHashed);
// 4. 요청된 hash와 생성된 hash로 auth를 체크한다.
if( strcmp(stUserAuthInfo.szHashed, szHashedUserInfo) != 0 )
{
LOG(LERR, "Do not match. Pass word.");
return PROTO_FAILURE_AUTH;
}
// 5. 본 클래스의 멤버 변수인
// m_responseHeader와 m_responseBody를 생성한다.
if( MakeResponseMessage(msgHeader, &objCustomerInfo.mapServiceInfo) == false )
{
LOG(LERR, "Failed to create response messages.");
return PROTO_INTERNAL_ERROR;
}
LOG(LDEV, "xxxxxxxx22");
return PROTO_SUCCESS;
}
// 응답메세지의 구조는 아래와 같다.
// [서비스개수][서비스개수*sizeof(sp_service_info)]
// 버퍼는 위의 크기 +1 을 할당해야한다.
bool CInterfaceProcessor::MakeResponseMessage(MsgHeader *pmsgHeader, CServiceInfoMap *pmapServiceInfo)
{
uint32_t nCount = 0;
uint32_t nhtonl= 0;
uint32_t nBodyPos = 0;
// 1. body 생성을 한다.
// 1-1. response body의 크기만큼 메모리할당을 한다.
nCount = (uint32_t)pmapServiceInfo->size();
m_nBodyLen = nCount * sizeof(sp_service_info) + sizeof(uint32_t) + 5;
m_responseBody = new char[m_nBodyLen];
LOG(LDEV, "xxxxxxxxxxxxxxxxxxxx11 xxxxx %d", m_nBodyLen);
memset(m_responseBody, 0x00, nCount * sizeof(sp_service_info) + sizeof(uint32_t) + 5);
// 1-2. 서비스 개수를 맨앞에 4바이트에 기록한다.
nhtonl = htonl(nCount);
LOG(LDEV, "Service Count: %d", nCount);
memcpy(m_responseBody, (char *)&nhtonl, sizeof(uint32_t));
nBodyPos += sizeof(uint32_t);
for (CServiceInfoMap::iterator it=pmapServiceInfo->begin(); it!=pmapServiceInfo->end(); ++it)
{
LOG(LDEV, "ServiceSeq :%s", it->first.c_str());
CServiceInfo objServiceInfo = it->second;
LOG(LDBG, "m_szServiceID :%s", objServiceInfo.m_szServiceID.c_str());
sp_service_info stServiceInfo;
::memset(&stServiceInfo, 0x00, sizeof(sp_service_info));
snprintf(stServiceInfo.sp_svc_id, MaxSizeOfSvcID, "%s", (const char *)objServiceInfo.m_szServiceID.c_str());
snprintf(stServiceInfo.svc_rcts_url, MaxSizeOfRCURL, "%s", (const char *)objServiceInfo.m_szRctsDomain.c_str());
if( strcmp(pmsgHeader->m_szIssuer, ISSUER_SP_CONSOLE) == 0 || strcmp(pmsgHeader->m_szIssuer, ISSUER_SP_CONSOLE3) == 0 )
{
snprintf(stServiceInfo.vol_url, MaxSizeOfRCURL, "%s", (const char *)objServiceInfo.m_szRcDomain.c_str());
}
else
{
snprintf(stServiceInfo.vol_url, MaxSizeOfRCURL, "%s", (const char *)objServiceInfo.m_szServiceDomain.c_str());
}
LOG(LDEV, "ServiceID :%s", stServiceInfo.sp_svc_id);
LOG(LDEV, "rcts domain :%s", stServiceInfo.svc_rcts_url);
LOG(LDEV, "Volume(rc) domain :%s", stServiceInfo.vol_url);
// 1-3. body에 추가한 후
memcpy((m_responseBody + nBodyPos), (char *)&stServiceInfo, sizeof(sp_service_info));
nBodyPos += sizeof(sp_service_info);
}
return true;
}
void CInterfaceProcessor::SendResult(int nCode, MsgHeader *pmsgHeader)
{
//nCode가 성공이 아니면 에러코드를 넣어서 결과를 주고..
// 성공이면 body를 만들어서 헤더와 함께 response를 준다.
// cc_tsd response를 위한 헤더 구조체
MsgHeader responseHeader;
// 2. header 생성을 한다.
::snprintf(responseHeader.m_szTID, MaxSizeOfTID, "%s", pmsgHeader->m_szTID);
responseHeader.m_ulMode = htonl(MODE_SRV_LST_2ND_RESPONSE);
::snprintf(responseHeader.m_szIssuer, MaxSizeOfIssuer, "%s", ISSUER_SERVER);
::snprintf(responseHeader.m_szServiceID, MaxSizeOfServiceID, "%s", pmsgHeader->m_szServiceID);
responseHeader.m_ulResult = htonl(nCode);
if( nCode == PROTO_SUCCESS )
responseHeader.m_ulBodyLength = htonl(m_nBodyLen);
// responseHeader.m_ulBodyLength = htonl(sizeof(m_responseBody));
else
responseHeader.m_ulBodyLength = htonl(0);
if( WriteN(&responseHeader, sizeof(MsgHeader)) != sizeof(MsgHeader) )
{
LOG( LERR, "Header data write failed.");
return;
}
// 성공이 아니면 body를 보낼필요가 없다.
if( nCode != PROTO_SUCCESS )
{
return;
}
// 3. header와 body를 socket wirte한다.
if( WriteN(m_responseBody, m_nBodyLen) != m_nBodyLen )
{
LOG( LERR, "Body data write failed.");
return;
}
if ( m_responseBody != NULL )
{
delete m_responseBody;
m_responseBody = NULL;
}
_LOG( LDBG, "Send Response Message.");
_LOG( LINF, "ISSUER : %s, Client IP : %s",pmsgHeader->m_szIssuer, m_szClientIP.c_str());
// LOGIN_INFO_INSERT 기능이 on인 경우만 queue에 등록한다.
if( CMyConfig::GetInstance()->GetLoginInfo() == false)
{
return;
}
// 4. Login info 를 생성한다.
CLoginInfo objLoginInfo;
objLoginInfo.m_szUserID = m_szUserID;
objLoginInfo.m_szIssuer = pmsgHeader->m_szIssuer;
objLoginInfo.m_szClientIP = m_szClientIP;
// 현재 시각 설정
char szTime[40];
time_t ltime = time(0);;
struct tm *pTm = NULL;
pTm = ::localtime((time_t *)&ltime);
::memset(szTime, 0, sizeof(szTime));
::snprintf(szTime, 40, "%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( LDEV, "m_szUserID : %s", objLoginInfo.m_szUserID.c_str());
LOG( LDEV, "m_szIssuer : %s", objLoginInfo.m_szIssuer.c_str());
LOG( LDEV, "m_szClientIP : %s", objLoginInfo.m_szClientIP.c_str());
LOG( LDEV, "time : %s", szTime);
objLoginInfo.m_szLoginDate = szTime;
m_pQueueLoginInfo->Push(objLoginInfo);
}
+65
View File
@@ -0,0 +1,65 @@
/***************************************************************************
cc_tsd
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __INTERFACE_PROCESSOR_H__
#define __INTERFACE_PROCESSOR_H__
#include "BaseSocket.h"
#include "cc_tsd.h"
#include "protocol.h"
#include "ServiceInfoUpdater.h"
#include "DataQueue.h"
class CInterfaceProcessor : public CBaseSocket
{
public:
CInterfaceProcessor();
CInterfaceProcessor(int clientsd, string szClientIP,CQueue<CLoginInfo> *pQueueLoginInfo, CServiceInfoUpdater *pobjServiceInfoUpdater);
~CInterfaceProcessor();
int Run();
// cc_timed 의 요청에 대한 응답처리
int Respose_cctimed(char *_pszRcvdReq );
// 현재 지원하는 모드인지 확인함.
int CheckRequestMode(MsgHeader* msgHeader);
// cc_tsd의 요청에 대한 내용을 확인한다.
// 적당한 응답을 위한 정보를 생성한다.
int ProcessingJob(MsgHeader *msgHeader);
// cc_tsd 요청에 대한 응답을 처리한다.
void SendResult(int nCode, MsgHeader *pmsgHeader);
string m_szClientIP;
string m_szUserID;
protected:
private:
static void *_entry_func(void *arg);
bool ParseUserInfo(const char *pszRcvd, user_auth_t *pUserAuthInfo);
bool MakeResponseMessage(MsgHeader *pmsgHeader, CServiceInfoMap *pmapServiceInfo);
int m_sfd;
// cc_tsd response를 위한 body 구조체
int m_nBodyLen;
char* m_responseBody;
CQueue<CLoginInfo> *m_pQueueLoginInfo;
CServiceInfoUpdater *m_pobjServiceInfoUpdater;
};
#endif // __INTERFACE_PROCESSOR_H__
+352
View File
@@ -0,0 +1,352 @@
/***************************************************************************
Interface Server ( InterfaceServer.cpp )
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "cc_tsd.h"
#include "InterfaceServer.h"
#include "Logger.h"
#include "InterfaceProcessor.h"
#define DEFAULT_ACCEPT_WAIT_COUNT 30
#define ACCEPT_TIMEOUT 60
CInterfaceServer::CInterfaceServer()
: m_ipv6(false), m_listenfd(-1), m_threadid(0), m_done(false), m_port(0)
{
}
CInterfaceServer::~CInterfaceServer( )
{
}
int CInterfaceServer::bind( int nPort )
{
ostringstream msg;
m_port = nPort;
#ifdef AF_INET6
m_listenfd = ::socket( AF_INET6, SOCK_STREAM, 0 );
if(m_listenfd >= 0)
{
msg << "Enable IPv6 Socket.";
_LOG(LINF, "%s", msg.str().c_str());
m_ipv6 = true;
}
#endif // AF_INET6
if(m_ipv6 == false)
m_listenfd = ::socket( AF_INET, SOCK_STREAM, 0 );
if( m_listenfd == -1 )
{
msg << "Listen socket create failed.[" << errno << "]["
<< strerror(errno) << "]";
LOG( LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
return -1;
}
int result = 0;
// Socket Port Reuse Option Set
int opt = 1;
result = ::setsockopt( m_listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt) );
if( result != 0 )
{
msg << "Listen socket option[SO_REUSEADDR] set failed. [" << errno
<< "][" << strerror(errno) << "]";
LOG( LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
return -1;
}
// Keep Alive Option set
opt = 1;
result = ::setsockopt( m_listenfd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt) );
if( result != 0 )
{
msg << "Listen socket option[SO_KEEPALIVE] set failed. [" << errno
<< "][" << strerror(errno) << "]";
LOG( LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
return -1;
}
#ifdef AF_INET6
if(m_ipv6)
{
struct sockaddr_in6 listenSockAddrv6;
socklen_t listenSockLen = 0;
memset(&listenSockAddrv6, 0x00, sizeof(listenSockAddrv6));
listenSockAddrv6.sin6_family = AF_INET;
listenSockAddrv6.sin6_flowinfo = 0;
listenSockAddrv6.sin6_port = htons( m_port );
listenSockAddrv6.sin6_addr = in6addr_any;
listenSockLen = sizeof(listenSockAddrv6);
// Socket Bind
result = ::bind( m_listenfd, (struct sockaddr *)&listenSockAddrv6, listenSockLen);
if( result != 0 )
{
msg << "Listen socket bind failed. [" << errno << "][" << strerror(errno)
<< "][Port : " << m_port << "]";
LOG(LERR, "%s", msg.str().c_str());
return -1;
}
}
else
#endif //AF_INET6
{
struct sockaddr_in listenSockAddr;
socklen_t listenSockLen = 0;
bzero(&listenSockAddr,sizeof(listenSockAddr));
listenSockAddr.sin_family = AF_INET;
listenSockAddr.sin_port = htons( m_port);
listenSockAddr.sin_addr.s_addr = htonl( INADDR_ANY );
listenSockLen = sizeof(listenSockAddr);
// Socket Bind
result = ::bind( m_listenfd, (struct sockaddr *)&listenSockAddr, listenSockLen);
if( result != 0 )
{
msg << "Listen socket bind failed. [" << errno << "][" << strerror(errno)
<< "][Port : " << m_port<< "]";
LOG(LERR, "%s", msg.str().c_str());
return -1;
}
}
// Socket Listen
result = ::listen( m_listenfd, DEFAULT_ACCEPT_WAIT_COUNT );
if( result != 0 )
{
msg << "Listen socket listen failed. [" << errno << "][" << strerror(errno) << "]";
LOG( LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
return -1;
}
return 0;
}
int CInterfaceServer::Accept()
{
ostringstream msg;
// 접속 요청을 변수 생성 및 초기화.
int nClientfd;
struct sockaddr_in clientSockAddr;
socklen_t clientSockLen = sizeof(clientSockAddr);
while(!m_done)
{
msg << "Client Waiting...IPv4 [Port:" << m_port << "]";
LOG(LDBG, "%s", msg.str().c_str());
nClientfd = ::accept( m_listenfd, (struct sockaddr *) &clientSockAddr, &clientSockLen );
if( nClientfd == -1 )
{
if( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK )
{
msg << "Service : client accept Warning. [" << errno << "]["
<< strerror(errno) << "][Port : " << m_port << "]";
LOG(LDBG, "%s", msg.str().c_str());
continue;
}
// 오류발생시 해당 내역 로깅처리.
msg << "Service : client accept failed. [" << errno << "]["
<< strerror(errno) << "][Port : " << m_port << "]";
LOG(LERR, "%s", msg.str().c_str());
}
else
{
// 정상적인 Client 인 경우
#ifdef _DEBUG
cout << "Connection from " << nClientfd << "," <<
clientSockAddr.sin_addr.s_addr << ", Port " << clientSockAddr.sin_port<< endl;
#endif // _DEBUG
string szClientIP = inet_ntoa(clientSockAddr.sin_addr);
_LOG( LDBG, "Client IP : %s", szClientIP.c_str() );
RunClient(nClientfd, szClientIP);
}
}
// exit
if(m_listenfd >= 0)
{
::close(m_listenfd);
m_listenfd = -1;
}
msg << "Service end.[Port : " << m_port << ",Type: " ;
LOG(LDBG, "%s", msg.str().c_str());
return 0;
}
int CInterfaceServer::Acceptv6()
{
ostringstream msg;
#ifdef AF_INET6
// 접속 요청을 변수 생성 및 초기화.
int nClientfd;
struct sockaddr_in6 clientSockAddr;
socklen_t clientSockLen = sizeof(clientSockAddr);
while(!m_done)
{
LOG(LDBG, "Client(v6) Waiting... IPv6[Port:%d]", m_port);
nClientfd = ::accept( m_listenfd, (struct sockaddr *) &clientSockAddr, &clientSockLen );
if( nClientfd == -1 )
{
if( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK )
{
msg << "Service(v6) : client accept Warning. [" << errno << "]["
<< strerror(errno) << "][Port : " << m_port << "]";
LOG(LDBG, "%s", msg.str().c_str());
continue;
}
// 오류발생시 해당 내역 로깅처리.
msg << "Service(v6) : client accept failed. [" << errno << "]["
<< strerror(errno) << "][Port : " << m_port << "]";
LOG(LERR, "%s", msg.str().c_str());
}
else
{
// 정상적인 Client 인 경우
#ifdef _DEBUG
cout << "Connection(v6) from " << nClientfd;
#endif // _DEBUG
char buffer[5*8];
memset(buffer, 0x00, 40);
/*inet_ntop(AF_INET6,
&clientSockAddr.sin6_addr.s6_addr[0],
buffer,
sizeof(clientSockAddr.sin6_addr.s6_addr));*/
inet_ntop(AF_INET6,
&clientSockAddr.sin6_addr,
buffer,
INET6_ADDRSTRLEN);
string szClientIP = buffer;
_LOG( LDBG, "Client IP : %s", szClientIP.c_str());
RunClient(nClientfd, szClientIP);
}
}
// exit
if(m_listenfd >= 0)
{
::close(m_listenfd);
m_listenfd = -1;
}
msg << "Service(v6) end.[Port : " << m_port ;
LOG(LDBG, "%s", msg.str().c_str());
#endif //AF_INET6
return 0;
}
void *CInterfaceServer::_entry_func(void *arg)
{
void *r = ((CInterfaceServer*)arg)->entry();
return r;
}
void CInterfaceServer::Init(CQueue<CLoginInfo> *pQueueLoginInfo, CServiceInfoUpdater *pobjServiceInfoUpdater)
{
m_pQueueLoginInfo = pQueueLoginInfo;
m_pobjServiceInfoUpdater = pobjServiceInfoUpdater;
}
int CInterfaceServer::start()
{
// start thread
int ret = pthread_create(&m_threadid, 0, _entry_func, (void*)this);
if (ret != 0)
{
ostringstream msg;
msg << "Thread create failed.[" << errno << "]";
LOG( LERR, "%s", msg.str().c_str());
cerr << msg.str() << endl;
return -1;
}
return 0;
}
void *CInterfaceServer::entry()
{
ostringstream msg;
msg << "Service start.[Port : " << m_port << "]";
LOG(LDBG, "%s", msg.str().c_str());
if(m_ipv6)
Acceptv6();
else
Accept();
LOG(LDBG, "xxxx here????");
return 0;
}
void CInterfaceServer::stop()
{
m_done = true;
if (m_listenfd >= 0)
{
::shutdown(m_listenfd, SHUT_RDWR);
}
if( m_threadid > 0 )
{
int status = pthread_join(m_threadid, NULL);
m_threadid = 0;
}
if (m_listenfd >= 0)
{
::close(m_listenfd);
m_listenfd = -1;
}
m_done = false;
}
int CInterfaceServer::RunClient(int nClientfd, string szClientIP)
{
ostringstream msg;
LOG(LDBG, "RunClient");
CInterfaceProcessor* objServer = new CInterfaceProcessor(nClientfd, szClientIP, m_pQueueLoginInfo, m_pobjServiceInfoUpdater);
if( objServer->Run() != 0 )
delete objServer;
return 0;
}
+57
View File
@@ -0,0 +1,57 @@
/***************************************************************************
Interface Server Header ( InterfaceServer.h )
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __INTERFACE_SERVER_H__
#define __INTERFACE_SERVER_H__
#include <pthread.h>
#include "ServiceInfoUpdater.h"
#include "DataQueue.h"
class CInterfaceServer
{
public:
CInterfaceServer ();
~CInterfaceServer();
int bind(int nPort );
void Init(CQueue<CLoginInfo> *pQueueLoginInfo, CServiceInfoUpdater *pobjServiceInfoUpdater);
int start();
void stop();
void SslCtx_Free();
protected:
virtual void *entry();
int RunClient(int nClientfd, string sz_ClientIP);
int Accept();
int Acceptv6();
bool m_ipv6;
int m_listenfd;
private:
static void *_entry_func(void *arg);
private:
pthread_t m_threadid;
bool m_done;
int m_port;
CQueue<CLoginInfo> *m_pQueueLoginInfo;
CServiceInfoUpdater *m_pobjServiceInfoUpdater;
};
#endif // __INTERFACE_SERVER_H__
+214
View File
@@ -0,0 +1,214 @@
/***************************************************************************
Login Info Inserter class
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include <fcntl.h>
#include <errno.h>
#include "Database.h"
#include "pthread.h"
#include "time.h"
#include "LoginInfoInserter.h"
extern struct st_config g_envConfig;
#define DEFAULT_INSERT_INTERVAL ((1) * (300) ) // 300sec
//#define DEFAULT_INSERT_INTERVAL ((1) * (3) ) // 300sec
#define DEFAULT_BUFFER_SIZE 2048
CLoginInfoInserter::CLoginInfoInserter(CQueue<CLoginInfo> *pLoginInfo )
: m_pLoginInfo (pLoginInfo)
{
}
CLoginInfoInserter::~CLoginInfoInserter()
{
if( m_pThreadHandle != NULL )
{
pthread_cancel( *m_pThreadHandle );
delete m_pThreadHandle;
m_pThreadHandle = NULL;
}
//pthread_cancel(m_threadHandle);
}
/// @brief
/// 입력받은 데이터가 유효한지만 확인 하기 위해 DataBase를 로컬로 선언한다.
bool CLoginInfoInserter::Init(const std::string &szHost, const int nPort, const std::string &szDBName, const std::string &szAcct, const std::string &szPasswd)
{
DataBase * pPgSQL = new DataBase;
if( szHost.empty()
|| nPort < 0
|| szDBName.empty()
|| szAcct.empty()
|| szPasswd.empty() )
{
// invalid argument
return false;
}
/// @brief DB connection information
m_szHost = szHost;
m_nPort = nPort;
m_szDBName = szDBName;
m_szAcct = szAcct;
m_szPasswd = szPasswd;
if( pPgSQL == NULL )
{
LOG( LERR, "Creating new Database has failed.");
return false;
}
if( pPgSQL->PgOpenDB(m_szHost, m_nPort, m_szDBName, m_szAcct, m_szPasswd) == NULL )
{
LOG( LERR, "Connecting to Database has failed");
if (pPgSQL != NULL)
{
delete pPgSQL;
pPgSQL = NULL;
}
return false;
}
if (pPgSQL != NULL)
{
delete pPgSQL;
pPgSQL = NULL;
}
return true;
}
/// @brief DB 연결 함수.
bool CLoginInfoInserter::DbConnect()
{
m_pPgSQL = new DataBase;
if( m_pPgSQL == NULL )
{
LOG( LERR, "Creating new Database has failed.");
return false;
}
if( m_pPgSQL->PgOpenDB(m_szHost, m_nPort, m_szDBName, m_szAcct, m_szPasswd) == NULL )
{
LOG( LERR, "Connecting to Database has failed.");
DbClose();
return false;
}
return true;
}
/// @breif DB close 함수.
void CLoginInfoInserter::DbClose()
{
if( m_pPgSQL != NULL )
{
delete m_pPgSQL;
m_pPgSQL = NULL;
}
}
bool CLoginInfoInserter::Execute()
{
char szQuery[DEFAULT_BUFFER_SIZE];
if ( DbConnect() == false)
{
LOG(LERR, "DbConnect() has returned false, so Execute() return false." );
return false;
}
while(m_pLoginInfo->GetDepth() > 0)
{
CLoginInfo objLoginInfo = m_pLoginInfo->Front();
// 1. 인서트 쿼리를 생성.
snprintf(szQuery, DEFAULT_BUFFER_SIZE - 1,
"INSERT INTO cs_service.cs_login_log( "
"id, module, client_ip, login_date) "
"VALUES ('%s', '%s', '%s', '%s');"
,objLoginInfo.m_szUserID.c_str(), objLoginInfo.m_szIssuer.c_str(), objLoginInfo.m_szClientIP.c_str(), objLoginInfo.m_szLoginDate.c_str());
// 2. 인서트 쿼리 수행.
m_pPgSQL->PgDoExec(szQuery);
if ((m_pPgSQL->PgResult(DataBase::CLEAR)) < 0)
{
LOG(LERR, "Query failed. errmsg:%s\nQuery:%s", m_pPgSQL->GetErrorMessage().c_str(), szQuery);
if (m_pPgSQL != NULL)
{
delete m_pPgSQL;
m_pPgSQL = NULL;
}
// 실패 한 경우는 DB Connect 부터 다시 하도록 종료 한다.
break;
}
// 3. 쿼리가 정상처리 되었다면 pop()함수를 이용해서 Queue에서 제거한다.
m_pLoginInfo->Pop();
}
DbClose();
return true;
}
void* CLoginInfoInserter::EntryPoint(void* arg)
{
CLoginInfoInserter* pObject = reinterpret_cast<CLoginInfoInserter *>(arg);
pthread_detach( pthread_self() );
while( 1 )
{
pthread_testcancel();
//LoginData가 0개이하면 다시 대기
if (pObject->m_pLoginInfo->GetDepth() <= 0)
{
LOG( LDBG, "Empty Queue!");
sleep( DEFAULT_INSERT_INTERVAL );
continue;
}
if( pObject->Execute() == false )
{
LOG( LWAR, "Execute() has returned false, so retry Execute() after 10 second.");
}
sleep(DEFAULT_INSERT_INTERVAL );
pthread_testcancel();
}
// pthread_exit();
return NULL;
}
// DO *NOT* FIX IT
bool CLoginInfoInserter::Start()
{
m_pThreadHandle = new pthread_t;
//int nRet = ::pthread_create(&m_threadHandle, 0, CLoginInfoInserter::EntryPoint, this);
int nRet = ::pthread_create(m_pThreadHandle, 0, CLoginInfoInserter::EntryPoint, this);
if( nRet )
{
LOG( LERR,"Thread create failed: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG( LDBG,"Thread create succeed");
sleep(0);
return true;
}
+89
View File
@@ -0,0 +1,89 @@
/***************************************************************************
Login Info Inserter class
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __PROPER_FHS_UDATER__
#define __PROPER_FHS_UDATER__
#include <pthread.h>
#include "Logger.h"
#include "Database.h"
#include "Data.h"
#include "DataQueue.h"
/// @brief CLoginInfoInserter
/// 서비스 리스트를 요청 할 때 Login Info를 생성해서 Queue에 담아두게 되는데..
/// 그 Queue의 정보를 가지고 cs_service.cs_login_log table에 Instert 하는 역할을 한다.
/// 주기는 5분에 한번씩 Insert처리 할 것이 있는지 확인후 있다면 Instert 한다.
///
/// 내부적으로 Thread를 사용하고있다.
class CLoginInfoInserter
{
// Attributes
private:
// 로깅 파일
DataBase* m_pPgSQL;
CQueue<CLoginInfo> *m_pLoginInfo;
// 쓰레드 핸들
//pthread_t m_threadHandle;
pthread_t* m_pThreadHandle;
/// @brief DB connection information
std::string m_szHost;
int m_nPort;
std::string m_szDBName;
std::string m_szAcct;
std::string m_szPasswd;
protected:
public:
// Operations
private:
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
// 해당 함수의 내용은 수정하지 말것.
bool Execute();
// 내부기능 함수들
bool DbConnect();
void DbClose();
protected:
public:
/// @brief 생성자
/// @param [in] pLogger 로깅을 위한 클래스.
CLoginInfoInserter( CQueue<CLoginInfo> *pLoginInfo );
~CLoginInfoInserter();
/// @brief 생성자
/// @param [in] db info
/// @return 성공하면 return true 실패하면 return false
bool Init(const std::string &szHost, const int nPort, const std::string &szDBName, const std::string &szAcct, const std::string &szPasswd);
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공은 return true 실패는 return false
bool Start();
};
#endif //__PROPER_FHS_UDATER__
+80
View File
@@ -0,0 +1,80 @@
#****************************************************************************
# Makefile for RC Content Check daemon
# -----------------------------------------
#
# begin : 2013/09/16
# copyright : (C) 2005 SolutionBox Inc.
# author : Development 1 Team
# - 2013/09/16
# email : svc1@solbox.com
# version : 3.2.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 = cc_tsd
REVISION = 0966
BUILD_DATE = `date +%Y%m%d%H%M%S`
PROG_VERSION = 3.3.0.$(REVISION)-$(BUILD_DATE)
DEFAULT_CONFIG_FILE = /user/service/etc/gts.conf
#DEBUG = yes
# Compiler info
CC = /usr/bin/g++
CFLAGS = -Wall -O3 -g -Wimplicit -Wreturn-type -Wunused -Wuninitialized\
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-fno-rtti -D_THREAD_SAFE -D_REENTRANT -D_PTHREADS -Wno-unused -Wno-non-virtual-dtor
LFLAGS = -lpthread
# DEBUG or RELEASE Mode select
ifeq ($(DEBUG), yes)
PROG_VERSION = 3.2.0.$(REVISION)D-$(BUILD_DATE)
CFLAGS = -Wall -O0 -g -Wimplicit -Wreturn-type -Wunused -Wuninitialized\
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-fno-rtti -D_THREAD_SAFE -D_REENTRANT -D_PTHREADS -Wno-unused -Wno-non-virtual-dtor
DFLAGS = -D_DEBUG -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
else
DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
endif
# Application Enviroment
APP = $(PROG_NAME)
DIR_LIB = -L../lib
DIR_INCLUDE = -I./. -I../lib -I/user/service/lib/pgsql/include
LIBS = ../lib/libInterCommon.a /user/service/lib/pgsql/lib/libpq.a
OBJ = main.o Worker.o Configs.o Database.o LoginInfoInserter.o DataQueue.o ServiceInfoUpdater.o InterfaceServer.o InterfaceProcessor.o
############################
all:$(APP)
sync
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
$(PROG_NAME): $(OBJ)
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
clean:
-rm -f *.o core *.out *.log
-rm -f $(APP)
sync
install : $(APP)
-cp $(APP) $(INSTALL_BIN)/$(APP)
-cp -n ../$(PROG_NAME).conf $(INSTALL_CONF)/$(PROG_NAME).conf
sync
# End of Makefile
+507
View File
@@ -0,0 +1,507 @@
/***************************************************************************
Service Info Updater
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include <fcntl.h>
#include <errno.h>
#include "Database.h"
#include "pthread.h"
#include "time.h"
#include "ServiceInfoUpdater.h"
extern struct st_config g_envConfig;
#define MX_LOCK_DATA()\
do \
{\
pthread_mutex_lock(&m_mxData);\
} while( 0 )
#define MX_UNLOCK_DATA()\
do \
{\
pthread_mutex_unlock(&m_mxData);\
} while( 0 )
#define DEFAULT_INSERT_INTERVAL ((1) * (180) ) // 180sec
//#define DEFAULT_INSERT_INTERVAL ((1) * (10) ) // 5sec
#define DEFAULT_BUFFER_SIZE 2048
CServiceInfoUpdater::CServiceInfoUpdater()
{
m_mapCustomerInfoTemp = NULL;
m_mapCustomerInfo = NULL;
pthread_mutex_init(&m_mxData, NULL);
}
CServiceInfoUpdater::~CServiceInfoUpdater()
{
if( m_pThreadHandle != NULL )
{
pthread_cancel( *m_pThreadHandle );
delete m_pThreadHandle;
m_pThreadHandle = NULL;
}
pthread_mutex_destroy(&m_mxData);
//pthread_cancel(m_threadHandle);
}
/// @brief
/// 입력받은 데이터가 유효한지만 확인 하기 위해 DataBase를 로컬로 선언한다.
bool CServiceInfoUpdater::Init(const std::string &szHost, const int nPort, const std::string &szDBName, const std::string &szAcct, const std::string &szPasswd)
{
DataBase * pPgSQL = new DataBase;
char szQuery[DEFAULT_BUFFER_SIZE];
if( szHost.empty()
|| nPort < 0
|| szDBName.empty()
|| szAcct.empty()
|| szPasswd.empty() )
{
// invalid argument
return false;
}
/// @brief DB connection information
m_szHost = szHost;
m_nPort = nPort;
m_szDBName = szDBName;
m_szAcct = szAcct;
m_szPasswd = szPasswd;
if( pPgSQL == NULL )
{
LOG( LERR, "Creating new Database has failed.");
return false;
}
if( pPgSQL->PgOpenDB(m_szHost, m_nPort, m_szDBName, m_szAcct, m_szPasswd) == NULL )
{
LOG( LERR, "Connecting to Database has failed");
if (pPgSQL != NULL)
{
delete pPgSQL;
pPgSQL = NULL;
}
return false;
}
// 이부분에서 cs_ccinfo의 base_domain값을 멤버로 갖고 있도록 한다.
// 1. 쿼리를 생성.
snprintf(szQuery, DEFAULT_BUFFER_SIZE - 1,
"SELECT base_domain FROM cs_service.cs_cc_info limit1;");
// 2. 쿼리 수행.
pPgSQL->PgDoExec(szQuery);
if ((pPgSQL->PgResult(DataBase::NOT_CLEAR)) < 0)
{
LOG(LERR, "Query failed. errmsg:%s\nQuery:%s", pPgSQL->GetErrorMessage().c_str(), szQuery);
if (pPgSQL != NULL)
{
delete pPgSQL;
pPgSQL = NULL;
}
// 실패 한 경우는 DB Connect 부터 다시 하도록 종료 한다.
return false;
}
if( pPgSQL->GetNoTuples() <= 0 )
{
LOG(LERR,"cs_cc_info is not exist.");
if( pPgSQL != NULL )
{
pPgSQL->PgClear();
delete pPgSQL;
pPgSQL = NULL;
}
return false;
}
m_szBaseDomain = pPgSQL->GetValue(0,0);
LOG(LDEV,"BaseDomain : %s", m_szBaseDomain.c_str());
if (pPgSQL != NULL)
{
delete pPgSQL;
pPgSQL = NULL;
}
return true;
}
/// @brief DB 연결 함수.
bool CServiceInfoUpdater::DbConnect()
{
m_pPgSQL = new DataBase;
if( m_pPgSQL == NULL )
{
LOG( LERR, "Creating new Database has failed.");
return false;
}
if( m_pPgSQL->PgOpenDB(m_szHost, m_nPort, m_szDBName, m_szAcct, m_szPasswd) == NULL )
{
LOG( LERR, "Connecting to Database has failed.");
DbClose();
return false;
}
return true;
}
/// @breif DB close 함수.
void CServiceInfoUpdater::DbClose()
{
if( m_pPgSQL != NULL )
{
delete m_pPgSQL;
m_pPgSQL = NULL;
}
}
bool CServiceInfoUpdater::Execute()
{
char szQuery[DEFAULT_BUFFER_SIZE];
int nResult = 0;
if ( DbConnect() == false)
{
LOG(LERR, "DbConnect() has returned false, so Execute() return false." );
return false;
}
m_mapCustomerInfoTemp = new CCustomerInfoMap;
// 1. CCDB에 등록된 고객정보중 삭제되지 않은 고객정보를 가져온다.
// 1-1. 쿼리 생성
memset(szQuery, 0x00, DEFAULT_BUFFER_SIZE);
snprintf(szQuery, DEFAULT_BUFFER_SIZE - 1,
"SELECT user_seq, id, passwd "
"FROM cs_service.cs_customer "
"WHERE del_yn = 'N';");
// 1-2. 쿼리 수행
m_pPgSQL->PgDoExec(szQuery);
// 1-3. 쿼리 결과확인
if ((m_pPgSQL->PgResult(DataBase::NOT_CLEAR)) < 0)
{
LOG(LERR, "Query failed. errmsg:%s\nQuery:%s", m_pPgSQL->GetErrorMessage().c_str(), szQuery);
if (m_pPgSQL != NULL)
{
delete m_pPgSQL;
m_pPgSQL = NULL;
}
// 실패 한 경우는 DB Connect 부터 다시 하도록 종료 한다.
return false;
}
// 1-3. 쿼리 결과확인
nResult = m_pPgSQL->GetNoTuples();
if( nResult <= 0 )
{
LOG(LERR,"cs_cc_info is not exist.");
if( m_pPgSQL != NULL )
{
m_pPgSQL->PgClear();
delete m_pPgSQL;
m_pPgSQL = NULL;
}
return false;
}
// 1-4. Data object에 담아야 한다.
for(int i = 0; i < nResult; i++ )
{
CCustomerInfo objCustomerInfo;
objCustomerInfo.m_szUserSeq = m_pPgSQL->GetValue(i,0) ;
objCustomerInfo.m_szUserID = m_pPgSQL->GetValue(i,1) ;
objCustomerInfo.m_szPassWord = m_pPgSQL->GetValue(i,2) ;
LOG(LDEV, "m_szUserSeq :%s", objCustomerInfo.m_szUserSeq.c_str());
LOG(LDEV, "m_szUserID :%s", objCustomerInfo.m_szUserID.c_str());
LOG(LDEV, "m_szPassWord :%s", objCustomerInfo.m_szPassWord.c_str());
m_mapCustomerInfoTemp->insert(CCustomerInfoPair(objCustomerInfo.m_szUserID, objCustomerInfo));
}
// 1-5. 쿼리의 결과를 정리한다.
m_pPgSQL->PgClear();
// 1-6. DB에서 고객정보로 각 고객의 ServiceList를 얻어온다.
LOG(LDEV, "------------------ Get Service Info -------------------------------" );
for (CCustomerInfoMap::iterator it=m_mapCustomerInfoTemp->begin(); it!=m_mapCustomerInfoTemp->end(); ++it)
{
LOG(LDEV, "UserID :%s", it->first.c_str());
CCustomerInfo* pobjCustomerInfo = &it->second;
LOG(LDEV, "xxx_m_szUserSeq :%s", pobjCustomerInfo->m_szUserSeq.c_str());
LOG(LDEV, "xxx_m_szUserID :%s", pobjCustomerInfo->m_szUserID.c_str());
LOG(LDEV, "xxx_m_szPassWord :%s", pobjCustomerInfo->m_szPassWord.c_str());
//고객의 서비스들을 DB로 부터 얻어온다.
if( GetServiceInfo(pobjCustomerInfo->m_szUserSeq, &pobjCustomerInfo->mapServiceInfo) == false)
{
LOG(LDBG, "DB connection is not normal.");
return false;
}
for (CServiceInfoMap::iterator iter=pobjCustomerInfo->mapServiceInfo.begin(); iter!=pobjCustomerInfo->mapServiceInfo.end(); ++iter)
{
CServiceInfo objServiceInfo = iter->second;
LOG(LDBG, "m_szServiceID :%s", objServiceInfo.m_szServiceID.c_str());
}
}
// 1-7 m_mapCustomerInfoTemp, 와 m_mapCustomerInfo를 바꿔준다.
MX_LOCK_DATA();
swap(m_mapCustomerInfoTemp, m_mapCustomerInfo);
MX_UNLOCK_DATA();
if( m_mapCustomerInfoTemp == NULL )
{
LOG(LDBG, "It's First Time");
}
else
{
if( m_mapCustomerInfoTemp->size() > 0 )
{
m_mapCustomerInfoTemp->clear();
delete m_mapCustomerInfoTemp;
}
}
DbClose();
return true;
}
bool CServiceInfoUpdater::GetServiceInfo(string szUserSeq, CServiceInfoMap *pmapServiceInfo)
{
char szQuery[DEFAULT_BUFFER_SIZE];
int nResult = 0;
// 2. 각 고객별로
// 2-1. 쿼리 생성
memset(szQuery, 0x00, DEFAULT_BUFFER_SIZE);
snprintf(szQuery, DEFAULT_BUFFER_SIZE - 1,
"SELECT svc_seq, svc_id, status_code, code "
"FROM cs_service.cs_service "
"WHERE del_yn = 'N' AND status_code != 'SVC_STATUS_REQUEST' AND status_code != 'SVC_STATUS_CLOSE' AND user_seq= '%s';", szUserSeq.c_str());
// 2-2. 쿼리 수행
m_pPgSQL->PgDoExec(szQuery);
// 2-3. 쿼리 결과확인
if ((m_pPgSQL->PgResult(DataBase::NOT_CLEAR)) < 0)
{
LOG(LERR, "Query failed. errmsg:%s\nQuery:%s", m_pPgSQL->GetErrorMessage().c_str(), szQuery);
if (m_pPgSQL != NULL)
{
delete m_pPgSQL;
m_pPgSQL = NULL;
}
// 실패 한 경우는 DB Connect 부터 다시 하도록 종료 한다.
return false;
}
// 2-3. 쿼리 결과확인
nResult = m_pPgSQL->GetNoTuples();
if( nResult <= 0 )
{
LOG(LWAR,"%s user is no have data.", szUserSeq.c_str());
return true;
}
LOG(LDEV, "xxxxxxx Result : %d", nResult);
// 2-4. Data object에 담아야 한다.
for(int i = 0; i < nResult; i++ )
{
CServiceInfo objServiceInfo;
objServiceInfo.m_szServiceSeq = m_pPgSQL->GetValue(i,0) ;
objServiceInfo.m_szServiceID = m_pPgSQL->GetValue(i,1) ;
objServiceInfo.m_szServiceDomain = m_pPgSQL->GetValue(i,1) + string(".") + m_szBaseDomain;
objServiceInfo.m_szStatusCode = m_pPgSQL->GetValue(i,2) ;
objServiceInfo.m_szCode = m_pPgSQL->GetValue(i,3) ;
LOG(LDEV, "m_szServiceSeq :%s", objServiceInfo.m_szServiceSeq.c_str());
LOG(LDEV, "m_szServiceID :%s", objServiceInfo.m_szServiceID.c_str());
LOG(LDEV, "m_szServiceDomain :%s", objServiceInfo.m_szServiceDomain.c_str());
LOG(LDEV, "m_szStatusCode :%s", objServiceInfo.m_szStatusCode.c_str());
pmapServiceInfo->insert(CServiceInfoPair(objServiceInfo.m_szServiceID, objServiceInfo));
}
// 이전 쿼리 결과를 지워준다.
m_pPgSQL->PgClear();
for (CServiceInfoMap::iterator it=pmapServiceInfo->begin(); it!=pmapServiceInfo->end(); ++it)
{
LOG(LDEV, "ServiceSeq :%s", it->first.c_str());
CServiceInfo* pobjServiceInfo = &it->second;
LOG(LDBG, "m_szServiceID :%s", pobjServiceInfo->m_szServiceID.c_str());
// Cloud Streaming은 cs_service_config table에 정보가 두개 있다.
memset(szQuery, 0x00, DEFAULT_BUFFER_SIZE);
snprintf(szQuery, DEFAULT_BUFFER_SIZE - 1,
"SELECT * FROM cs_service.cs_service_config WHERE svc_seq = '%s';"
, pobjServiceInfo->m_szServiceSeq.c_str() );
// 3-2. 쿼리 수행
m_pPgSQL->PgDoExec(szQuery);
// 3-3. 쿼리 결과확인
if ((m_pPgSQL->PgResult(DataBase::NOT_CLEAR)) < 0)
{
LOG(LERR, "Query failed. errmsg:%s\nQuery:%s", m_pPgSQL->GetErrorMessage().c_str(), szQuery);
if (m_pPgSQL != NULL)
{
delete m_pPgSQL;
m_pPgSQL = NULL;
}
// 실패 한 경우는 DB Connect 부터 다시 하도록 종료 한다.
return false;
}
int nServiceCount = m_pPgSQL->GetNoTuples();
// 이전 쿼리 결과를 지워준다.
m_pPgSQL->PgClear();
LOG(LDEV, "Service Count : %d ", nServiceCount );
// Cloud Streaming 서비스 타입이고, upload url에 정보가 없을 경우에는..
// Cloud Streaming의 경우에는 Master 정보만 전달 해주면 된다.
// 그러므로, Slave 서비스 이므로 서비스 정보를 map에서 지워버린다.
// if( strcmp(pobjServiceInfo->m_szCode.c_str(), "SVC_TYPE_C_01") == 0 )
if( nServiceCount > 1)
{
LOG(LDEV, "kkkkkkkkkkkkkkkkkkkkkkkk");
// 3-1. 쿼리 생성
memset(szQuery, 0x00, DEFAULT_BUFFER_SIZE);
snprintf(szQuery, DEFAULT_BUFFER_SIZE - 1,
"SELECT rc_domain, rcts_domain, upload_domain "
"FROM cs_service.cs_service_config "
"WHERE svc_seq = '%s' AND slave_svc_seq = '%s' "
, pobjServiceInfo->m_szServiceSeq.c_str()
, pobjServiceInfo->m_szServiceSeq.c_str() );
}
else
{
// 3-1. 쿼리 생성
memset(szQuery, 0x00, DEFAULT_BUFFER_SIZE);
snprintf(szQuery, DEFAULT_BUFFER_SIZE - 1,
"SELECT rc_domain, rcts_domain, upload_domain "
"FROM cs_service.cs_service_config "
"WHERE svc_seq = '%s';", pobjServiceInfo->m_szServiceSeq.c_str() );
}
LOG(LDEV, "kkkkkkkkkkkkkkkkkkkkkkkk, %s", szQuery);
// 3-2. 쿼리 수행
m_pPgSQL->PgDoExec(szQuery);
// 3-3. 쿼리 결과확인
if ((m_pPgSQL->PgResult(DataBase::NOT_CLEAR)) < 0)
{
LOG(LERR, "Query failed. errmsg:%s\nQuery:%s", m_pPgSQL->GetErrorMessage().c_str(), szQuery);
if (m_pPgSQL != NULL)
{
delete m_pPgSQL;
m_pPgSQL = NULL;
}
// 실패 한 경우는 DB Connect 부터 다시 하도록 종료 한다.
return false;
}
// 3-3. 쿼리 결과확인
if( m_pPgSQL->GetNoTuples() <= 0 )
{
LOG(LWAR,"%s service is no have data on cs_service_config tables.", pobjServiceInfo->m_szServiceID.c_str());
m_pPgSQL->PgClear();
continue;
}
pobjServiceInfo->m_szRcDomain = m_pPgSQL->GetValue(0,0);
pobjServiceInfo->m_szRctsDomain = m_pPgSQL->GetValue(0,1);
string szUploadUrl = m_pPgSQL->GetValue(0,2);
m_pPgSQL->PgClear();
LOG(LDEV, "m_szRcDomain :%s", pobjServiceInfo->m_szRcDomain.c_str());
LOG(LDEV, "m_szRctsDomain :%s", pobjServiceInfo->m_szRctsDomain.c_str());
}
return true;
}
void* CServiceInfoUpdater::EntryPoint(void* arg)
{
CServiceInfoUpdater* pObject = reinterpret_cast<CServiceInfoUpdater *>(arg);
pthread_detach( pthread_self() );
while( 1 )
{
pthread_testcancel();
if( pObject->Execute() == false )
{
LOG( LWAR, "Execute() has returned false, so retry Execute() after 10 second.");
}
sleep(DEFAULT_INSERT_INTERVAL );
pthread_testcancel();
}
// pthread_exit();
return NULL;
}
// DO *NOT* FIX IT
bool CServiceInfoUpdater::Start()
{
m_pThreadHandle = new pthread_t;
//int nRet = ::pthread_create(&m_threadHandle, 0, CServiceInfoUpdater::EntryPoint, this);
int nRet = ::pthread_create(m_pThreadHandle, 0, CServiceInfoUpdater::EntryPoint, this);
if( nRet )
{
LOG( LERR,"Thread create failed: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG( LDBG,"Thread create succeed");
sleep(0);
return true;
}
bool CServiceInfoUpdater::GetUserServiceData(string szUserID, CCustomerInfo &objCustomerInfo)
{
MX_LOCK_DATA();
CCustomerInfoMap::iterator it = m_mapCustomerInfo->find(szUserID);
if (it == m_mapCustomerInfo->end() )
{
MX_UNLOCK_DATA();
return false;
}
objCustomerInfo = it->second;
LOG(LDEV, "xxx555_m_szUserSeq :%s", objCustomerInfo.m_szUserSeq.c_str());
LOG(LDEV, "xxx555_m_szUserID :%s", objCustomerInfo.m_szUserID.c_str());
LOG(LDEV, "xxx555_m_szPassWord :%s", objCustomerInfo.m_szPassWord.c_str());
MX_UNLOCK_DATA();
for (CServiceInfoMap::iterator iter=objCustomerInfo.mapServiceInfo.begin(); iter!=objCustomerInfo.mapServiceInfo.end(); ++iter)
{
LOG(LDEV, "ServiceSeq :%s", iter->first.c_str());
CServiceInfo objServiceInfo = iter->second;
LOG(LDBG, "m_szServiceID :%s", objServiceInfo.m_szServiceID.c_str());
}
return true;
}
+106
View File
@@ -0,0 +1,106 @@
/***************************************************************************
Service Info Updater
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __CSERVICE_INFO_UPDATER__
#define __CSERVICE_INFO_UPDATER__
#include <pthread.h>
#include "Logger.h"
#include "Database.h"
#include "Data.h"
#include "DataQueue.h"
/// @brief CServiceInfoUpdater
/// 서비스 리스트를 요청 할 때 Login Info를 생성해서 Queue에 담아두게 되는데..
/// 그 Queue의 정보를 가지고 cs_service.cs_login_log table에 Instert 하는 역할을 한다.
/// 주기는 5분에 한번씩 Insert처리 할 것이 있는지 확인후 있다면 Instert 한다.
///
/// 내부적으로 Thread를 사용하고있다.
class CServiceInfoUpdater
{
// Attributes
private:
// 로깅 파일
DataBase* m_pPgSQL;
CQueue<CLoginInfo> *m_pLoginInfo;
// 쓰레드 핸들
//pthread_t m_threadHandle;
pthread_t* m_pThreadHandle;
/// @brief DB connection information
std::string m_szHost;
int m_nPort;
std::string m_szDBName;
std::string m_szAcct;
std::string m_szPasswd;
std::string m_szBaseDomain;
protected:
public:
// Operations
private:
// 쓰레드 시작 루틴이다.
static void* EntryPoint(void* arg);
// DB에서 데이터를 가져올때 임시로 저장해두는 역할을 한다.
CCustomerInfoMap *m_mapCustomerInfoTemp;
// Worker에서 정보 조회를 할 수 있도록 Data를 저장해두는 역할을 한다.
CCustomerInfoMap *m_mapCustomerInfo;
// DB에서 주기적으로 전체 유저들의 정보들을 가져온다.
bool Execute();
// 내부기능 함수들
bool DbConnect();
void DbClose();
/// @brief Data에 대한 뮤텍스 변수
pthread_mutex_t m_mxData;
protected:
public:
/// @brief 생성자
/// @param [in] pLogger 로깅을 위한 클래스.
CServiceInfoUpdater();
~CServiceInfoUpdater();
/// @brief 생성자
/// @param [in] db info
/// @return 성공하면 return true 실패하면 return false
bool Init(const std::string &szHost, const int nPort, const std::string &szDBName, const std::string &szAcct, const std::string &szPasswd);
/// @brief Thread를 생성하고, 이를 시작한다.
/// @param none
/// @return 성공은 return true 실패는 return false
bool Start();
// DB에서 유저별 서비스 정보를 얻어 온다.
bool GetServiceInfo(string szUserSeq, CServiceInfoMap *pmapServiceInfo);
// Interface 함수 들이다.
// 유저에 대한 Map Data를 얻는다.
bool GetUserServiceData(string szUserID, CCustomerInfo &objCustomerInfo);
};
#endif //__CSERVICE_INFO_UPDATER__
+181
View File
@@ -0,0 +1,181 @@
/***************************************************************************
Worker (cc_tsd)
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "Worker.h"
#include <signal.h>
#include <stdlib.h>
#include "Logger.h"
#include "Configs.h"
#include "LoginInfoInserter.h"
#include "ServiceInfoUpdater.h"
#include "DataQueue.h"
#include "InterfaceServer.h"
extern CInterfaceServer _iServer;
/// @brief Worker Process 의 main 함수
int WorkerMain( )
{
// Set Signal Handler
SetSignalWorker();
#if defined(__FreeBSD__)
setproctitle( "Worker [initialize process]");
#endif
CQueue<CLoginInfo> queueLoginInfo;
// 1. 서비스 정보를 주기적으로 가져오는 클래스를 생성한다.
// Global
CServiceInfoUpdater objServiceInfoUpdater;
if ( objServiceInfoUpdater.Init(CMyConfig::GetInstance()->GetDBIP(),
CMyConfig::GetInstance()->GetDBPort(),
CMyConfig::GetInstance()->GetDBName(),
CMyConfig::GetInstance()->GetDBAccount(),
CMyConfig::GetInstance()->GetDBPwd()) == false)
{
LOG(LERR, "Worker[%d]: CLoginInfoInserter init failed => Worker Exit", getpid() );
exit( EXIT_FAILURE ); // EXIT_FAILURE 를 반환하여 재생성 처리 방지.
}
objServiceInfoUpdater.Start();
CLoginInfoInserter objLoginInfoInserter(&queueLoginInfo);
// LOGIN_INFO_INSERT 기능이 on인 경우만 CLoginInfoInserter thread가 구동되도록한다.
if( CMyConfig::GetInstance()->GetLoginInfo() == true)
{
// 2. Login Info 정보를 주기적으로 insert할 클래스를 생성한다.
//-- 각 객체에 대해 초기화 및 시작 할 수 있는지 먼저 확인한다.
if ( objLoginInfoInserter.Init(CMyConfig::GetInstance()->GetDBIP(),
CMyConfig::GetInstance()->GetDBPort(),
CMyConfig::GetInstance()->GetDBName(),
CMyConfig::GetInstance()->GetDBAccount(),
CMyConfig::GetInstance()->GetDBPwd()) == false)
{
LOG(LERR, "Worker[%d]: CLoginInfoInserter init failed => Worker Exit", getpid() );
exit( EXIT_FAILURE ); // EXIT_FAILURE 를 반환하여 재생성 처리 방지.
}
objLoginInfoInserter.Start();
}
// 3. socket 생성 후 accept가 되면 Job Thread를 생성하여 socket을 이관한다.
_iServer.Init(&queueLoginInfo, &objServiceInfoUpdater);
_iServer.start();
// 생성된 Thread 의 Join 처리 ???
while( 1 )
{
// 그냥 시그널 대기
pause();
}
// Process 종료 처리.
LOG( LWAR, "Worker Process[%d] exit.. Good Bye..", getpid());
//잠시 대기 후 종료처리.
usleep(500000);
// exit( EXIT_SUCCESS );
return EXIT_SUCCESS; // fork 를 수행한 함수에서 exit 함수 호출을 통한 종료처리 (Guard.cpp)
}
/// @brief Worker Process 종료 Signal 을 전달받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigTermWorker( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
LOG( LWAR, "Worker Process[%d] exit job start by user signal [SIGTERM]", getpid() );
}
else
{
LOG( LWAR, "Worker Process[%d] exit job start by abnormal signal [%d]", getpid(), nSignalNumber );
}
LOG( LWAR, "Worker Process[%d] exit job end. Good Bye..", getpid());
CLogger::Exit();
CMyConfig::Exit();
usleep(500000);
exit( EXIT_SUCCESS );
}
/// @brief Worker Process 에서 Core 생성 관련 Signal 을 받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigCoreWorker( int nSignalNumber )
{
LOG( LERR, "Worker Process[%d] abnoraml exit. Check Core file. Receive signal [%d]", getpid(), nSignalNumber );
LOG( LERR, "Core file path : [%s/%s.core]", CMyConfig::GetInstance()->GetAppLogRoot(), PROG_NAME );
// Process 종료관련 작업 추가
CLogger::Exit();
CMyConfig::Exit();
// Log Directory 상에 Core 파일 생성처리.
chdir( CMyConfig::GetInstance()->GetAppLogRoot() );
signal( nSignalNumber, SIG_DFL );
// Core dump 생성을 위한 신호 발생처리.=> ?
raise( nSignalNumber );
}
/// @brief Worker 프로세스 signal 처리 설정을 위한 함수
/// @return void
void SetSignalWorker( void )
{
sigset_t set;
struct sigaction act;
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
memset( &act, 0x00, sizeof(act) );
sigfillset( &act.sa_mask );
/* 무시할 신호 목록 */
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL); /* 파이프 디스크립터 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP , &act, NULL); /* Process를 기동시킨 관리자의 로그아웃시 발생 시그널 */
sigaction( SIGINT , &act, NULL); /* ^C 키를 누른 경우 받는 신호 => daemon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
//act.sa_handler = SigChldWorker;
sigaction( SIGCHLD, &act, NULL);
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SigTermWorker;
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
/* Core 관련 signal 처리 : 오류 처리 및 Debug(core dump) 목적 */
act.sa_handler = SigCoreWorker;
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);
}
+50
View File
@@ -0,0 +1,50 @@
/***************************************************************************
Worker (cc_tsd)
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __WORKER_PROCESS_H__
#define __WORKER_PROCESS_H__
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <vector>
#ifdef __cplusplus
extern "C" {
#endif
/// @brief Worker Process 의 main 함수
/// @return
int WorkerMain( void );
/// @brief Worker 프로세스 signal 처리 설정을 위한 함수
/// @return void
void SetSignalWorker( void );
/* Signal 처리를 위한 각 Signal Handler 함수는
* 다른 Code 에서 Include 처리시 Static 관련 문제로 인해
* 본 Header 에서 선언처리 하지 않음. cpp 에만 존재
*/
#ifdef __cplusplus
}
#endif
#endif /* __WORKER_PROCESS_H__ */
+43
View File
@@ -0,0 +1,43 @@
/***************************************************************************
cc_tsd
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __CC_TSD_H__
#define __CC_TSD_H__
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <iostream>
#include <vector>
#include <map>
#include <sstream>
#include <limits.h>
#include <algorithm>
#include <time.h>
using namespace std;
#endif // __CC_TSD_H__
+390
View File
@@ -0,0 +1,390 @@
/***************************************************************************
main.cpp (cc_tsd)
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include <errno.h>
#include <iostream>
#include <string>
#include <signal.h>
#include <sys/wait.h>
#include "Logger.h"
#include "Config.h"
#include "Worker.h"
#include "Configs.h"
#include "InterfaceServer.h"
CInterfaceServer _iServer;
using namespace std;
/// @brief std 상에 trim 함수가 없어서 직접 구현 아니면 boost/algorithm/string.hpp 상의 boost::trim 함수 사용
/// @return void
void Trim( string & str )
{
if( str.length() == 0 )
return ;
// 문자열 뒤의 공백, TAB, CR 등의 문자 제거처리.
string::size_type pos = str.find_last_not_of(" \a\b\f\n\r\t\v");
if( pos != string::npos )
str.erase( pos + 1 );
// 문자열 앞의 공백, TAB, CR 등의 문자 제거처리.
pos = str.find_first_not_of(" \a\b\f\n\r\t\v");
if( pos != string::npos )
str.erase( 0, pos );
}
/// @brief 현재 Process가 기동중인지 여부를 판단하기 위한 함수( 프로세스 중복 실행 체크)
/// @return 이미 해당 프로세스가 기동 중인 경우 true 반환, 그렇지 않으면 false 반환.
bool IsCurrentProcessRun()
{
char tempBuffer[512];
FILE * fd = NULL;
bool bRun = false;
snprintf( tempBuffer, sizeof(tempBuffer), "pgrep -x %s | sort", PROG_NAME );
fd = popen( tempBuffer, "r" );
if( fd == NULL )
{
cerr << "[error] Process duplication check failed.[popen error][" << strerror(errno) << "]" << endl;
// 오류 발생시 true 반환하여 프로세스 실행 방지처리
return true;
}
else
{
memset( tempBuffer, 0x00, sizeof(tempBuffer) );
while( fgets( tempBuffer, sizeof(tempBuffer)-1, fd) != NULL )
{
string tempPid( tempBuffer );
Trim(tempPid);
if( atoi( tempPid.c_str() ) != getpid() )
{
cout << "[info] Process duplication found. pid[" << atoi( tempPid.c_str() ) << "]" << endl;
bRun = true;
break;
}
}
pclose( fd );
return bRun;
}
}
int MakeDaemon()
{
pid_t processId;
processId = fork();
if( processId == -1 )
{
int errorNum = errno;
cout << "[error] " << PROG_NAME << ": daemon fork fail.[" << strerror(errorNum) << "]" << endl;
LOG(LERR, "Daemon fork failed. [%d][%s]", errorNum, strerror(errorNum));
return -1;
}
// Parent Process => exit
if( processId != 0 )
exit( EXIT_SUCCESS );
else
setsid();
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
return 0;
}
/// @brief Guard Process 종료 Signal 을 전달받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigTermGuard( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
LOG(LWAR,"Guard Process[%d] exit job start by user signal [SIGTERM]", getpid());
}
else
{
LOG(LWAR, "Guard Process[%d] exit job start by abnormal signal [%d]", getpid(), nSignalNumber);
}
// Process 종료관련 작업 추가
LOG(LWAR, "Guard Process[%d] exit job end. Good Bye..", getpid());
usleep(500000);
exit( EXIT_SUCCESS );
}
/// @brief Guard Process 에서 Core 생성 관련 Signal 을 받은 경우 이를 처리하기 위한 함수.
/// @param nSignalNumber [in] 발생한 시그널 Number
/// @return void
static void SigCoreGuard( int nSignalNumber )
{
LOG(LERR, "Guard Process[%d] abnoraml exit. Check Core file. Receive signal [%d]", getpid(), nSignalNumber );
LOG(LERR, "Core file path : [%s/%s.core]", CMyConfig::GetInstance()->GetAppLogRoot(), PROG_NAME );
// Process 종료관련 작업 추가
CLogger::Exit();
CMyConfig::Exit();
// Log Directory 상에 Core 파일 생성처리.
chdir( CMyConfig::GetInstance()->GetAppLogRoot() );
signal( nSignalNumber, SIG_DFL );
// Core dump 생성을 위한 신호 발생처리.=> ?
raise( nSignalNumber );
}
/// @brief Worker Process 생성(fork) 처리 함수
/// @return 생성 성공시 true, 실패시에는 false 를 반환.
bool MakeProcessWorker()
{
pid_t processId;
// Worker 프로세스 fork
processId = fork();
if( processId < 0 ) // Fork fail
{
int errorNum = errno;
LOG(LERR, "Worker Process create failed. [%d][%s]", errorNum, strerror(errorNum) );
return false;
}
else if( processId == 0 ) // Child Process => Worker Process
{
// Worker Process Main 함수 호출 및 종료처리.
WorkerMain();
exit( EXIT_SUCCESS );
}
else
{
// Parent Process => Logging
LOG(LNOT, "Worker Process create success. PID[%d]" , processId);
// 잠시 대기
usleep(100000);
}
return true;
}
static void SigChldGuard( int nSignalNumber )
{
pid_t killPid;
int nKillStatus;
while( ( killPid = waitpid( -1, &nKillStatus, WNOHANG ) ) > 0 )
{
// 자식 프로세스가 Signal 에 의해 종료되었는지 검사.
if( WIFSIGNALED( nKillStatus ) )
{
LOG(LWAR, "Worker process[%d] killed by signal[%d]", killPid, WTERMSIG( nKillStatus ) );
}
else
{
LOG(LWAR, "Worker process[%d] killed. Not signal", killPid );
// Worker 프로세스가 EXIT_FAILURE 반환 ( 초기화 실패시 )
// 해당 내역을 화면 및 로그 상에 출력하고
// 자식 프로세스를 재생성 처리하지 않는다.
if( WIFEXITED( nKillStatus ) )
{
if( WEXITSTATUS( nKillStatus ) == EXIT_FAILURE )
{
LOG(LERR, "Worker Process[%d] initilaize failed.", killPid );
LOG(LERR, "Guard Process[%d] exit by worker. Good Bye..", getpid());
cerr << "[error] " << PROG_NAME << ": Process exit by worker process initialize failed. check log file." << endl;
CLogger::Exit();
CMyConfig::Exit();
usleep(500000);
exit( EXIT_SUCCESS );
}
}
}
// Worker Process 재생성 처리.
if( MakeProcessWorker() == false )
{
// Worker Process 재성성 실패시 => 그냥 로깅
LOG(LERR, "Worker process recreate failed.");
}
else
{
LOG(LNOT, "Worker process recreate success by SIGCHLD");
}
}
// 오류 발생시 해당 내역 로깅
if( killPid < 0 )
{
int errorNum = errno;
LOG(LERR, "Guard process error: SIG_CHLD receive but waitpid return error[%d][%s]", errorNum, strerror(errorNum));
}
return;
}
/// @brief Guard프로세스 signal 처리 설정을 위한 함수
/// @return void
void SetSignalGuard()
{
sigset_t set;
struct sigaction act;
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
memset( &act, 0x00, sizeof(act) );
sigfillset( &act.sa_mask );
/* 무시할 신호 목록 */
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL); /* 파이프 디스크립터 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP , &act, NULL); /* Process를 기동시킨 관리자의 로그아웃시 발생 시그널 */
sigaction( SIGINT , &act, NULL); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
// Child Process 인 Worker 프로세스 종료에 대한 처리기 설정.
act.sa_handler = SigChldGuard;
sigaction( SIGCHLD, &act, NULL);
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SigTermGuard;
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
/* Core 관련 signal 처리 : 오류 처리 및 Debug(core dump) 목적 */
act.sa_handler = SigCoreGuard;
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);
}
int main( int argc, char * argv[] )
{
std::string szConfFilename = DEFAULT_CONFIG_FILE;
std::string szProgramName = PROG_NAME;
std::string szProgVer = PROG_VERSION;
std::string szStartPeriod = "";
// Version 정보 표시
if( argc == 2 && strcmp( argv[1], "-v") == 0)
{
cerr << "[info] " << PROG_NAME << " Version : " << PROG_VERSION << endl;
return EXIT_SUCCESS;
}
// 프로그램 중복 실행 체크
if( IsCurrentProcessRun() == true )
{
cerr << "[warning] Process[" << PROG_NAME << "] is already running...." << endl;
return EXIT_SUCCESS;
}
//initialized Config object
if(CMyConfig::Init( PROG_NAME, szConfFilename) == false)
{
cerr << "[error] Failed to initialize the config object." << endl;
return EXIT_FAILURE;
}
// load config
if( CMyConfig::GetInstance()->LoadConf() == false )
{
cerr << "[error] Config load error." << CMyConfig::GetInstance()->GetErrMessage() << endl;
return EXIT_FAILURE;
}
if (CMyConfig::GetInstance()->CheckValue() == false)
{
cerr << "[error] Config load error." << CMyConfig::GetInstance()->GetErrMessage() << endl;
return EXIT_FAILURE;
}
// initialized Log object
if( CLogger::Init( PROG_NAME, CMyConfig::GetInstance()->GetAppLogRoot(),
CMyConfig::GetInstance()->GetAppLogLevel() ) == false )
{
cerr << "[error] Failed to initialize the log object." << endl;
return EXIT_FAILURE;
}
// 프로그램 Daemonize
if( MakeDaemon() != 0 )
{
LOG(LERR, "Process[%s] Daemonize failed.", PROG_NAME);
cerr << "[error] Process[" << PROG_NAME << "] Daemonize failed." << endl;
return EXIT_FAILURE;
}
// Guard 프로세스의 Signal 처리기 설정
SetSignalGuard();
// Interface server socket bind
if(_iServer.bind(80) == 0)
{
// Worker Process 생성
if( MakeProcessWorker() == false )
{
LOG(LERR, "Worker Process make failed. => Guard Process exit. Goob Bye..");
cerr << "Worker Process make failed. => Guard Process exit. Goob Bye.." << endl;
return EXIT_FAILURE;
}
}
else
{
_LOG(LERR, "Interface server socket bind failed");
return EXIT_FAILURE;
}
// Guard Process : 그냥 대기
#if defined(__FreeBSD__)
setproctitle( "Main(Guard Procss) [monitor worker process]" );
#endif
while( 1 )
{
// Guard Process 는 할 일이 없다.
// => Worker 프로세스 종료시 SIGCHLD 신호로 인해 신호처리기에서 Worker Process 재성성 수행함.
// => 따라서 그냥 시그널 대기
pause();
}
// 다음의 코드는 Daemon 으로 동작하기 때문에 수행되지 않는다.
CLogger::Exit();
CMyConfig::Exit();
return EXIT_SUCCESS;
}
+96
View File
@@ -0,0 +1,96 @@
/***************************************************************************
protocol define (cc_tsd)
-----------------------------------------
begin : 2013/09/16
copyright : (C) 2005 Solbox Inc.
author : Development 1 Team
- 2013/09/16
email : dev1@solbox.com
version : 3.2.0
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __PROTOCOL_H__
#define __PROTOCOL_H__
#include <iostream>
using namespace std;
#define MaxSizeOfTID 52
#define MaxSizeOfIssuer 128
#define MaxSizeOfServiceID 128
#define MaxSizeOfSvcID 32
#define MaxSizeOfRCURL 128
#define CODE_ESC 0x1b
#define MODE_DEFAULT 0x0000
#define MODE_SYNC_NOTICE 0x0001
#define MODE_SP_DATA 0x0002
#define MODE_SYNC_RESPONSE 0x0009
#define MODE_SRV_LST_REQUEST 0x0010
#define MODE_SRV_LST_RESPONSE 0x0011
#define MODE_SRV_LST_2ND_REQUEST 0x0080
#define MODE_SRV_LST_2ND_RESPONSE 0x0081
#define MODE_SRV_TRAFFIC_REQUEST 0x0082
#define MODE_SRV_TRAFFIC_RESPONSE 0x0083
#define PROTO_SUCCESS 0x1000
#define PROTO_FAILURE 0x3000
#define PROTO_FAILURE_AUTH 0x3001
#define PROTO_INTERNAL_ERROR 0x9000
#define MODE_USER_DATA_MODIFIER_REQ 0x0301
#define MODE_USER_DATE_MODIFIER_RESP 0x0302
#define MODE_APACHE_ERROR_LOG_REQ 0x0401
#define MODE_APACHE_ERROR_LOG_RESP 0x0402
#define MODE_APACHE_ACCESS_LOG_REQ 0x0403
#define MODE_APACHE_ACCESS_LOG_RESP 0x0404
#define ISSUER_SP_CONSOLE "SP-Console"
#define ISSUER_SP_CONSOLE3 "SP-Console3"
#define ISSUER_SERVER "cc_tsd"
typedef struct _s_time_sync_t
{
int32_t sync_info;
} time_sync_t;
typedef struct _s_msg_header {
char m_szTID[MaxSizeOfTID];
uint32_t m_ulMode;
char m_szIssuer[MaxSizeOfIssuer];
char m_szServiceID[MaxSizeOfServiceID];
uint32_t m_ulResult;
uint32_t m_ulBodyLength;
} MsgHeader;
typedef struct _s_t_service_info {
char sp_svc_id[MaxSizeOfSvcID];
char svc_rcts_url[MaxSizeOfRCURL];
char vol_url[MaxSizeOfRCURL];
} sp_service_info;
typedef struct _s_user_auth {
char szUserID[32];
char szHashed[33];
time_t reqTime; // 32/64 bit not equeal data size... !!!
} user_auth_t;
#define SizeOfMsgHeader sizeof(MsgHeader)
extern int fillMsgHeader(MsgHeader *pMsgHeader, const char *pszTID,
const unsigned long m_ulMode, const char *pszIssuer,
const char *pszServiceID, const unsigned long m_ulResult,
const long m_ulBodyLength);
#endif