257 lines
6.1 KiB
C++
257 lines
6.1 KiB
C++
#include <sys/socket.h>
|
|
#include <arpa/inet.h>
|
|
#include <netinet/in.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include "SmsSender.h"
|
|
#include <iterator>
|
|
|
|
#define DEFAULT_BUFFER_SIZE 9216
|
|
#define MaxSizeOfTRxBuffer 1024
|
|
|
|
|
|
string CSmsSender::RemoveBlankSpace(const char* pszData, size_t nLength)
|
|
{
|
|
char * szTemp = NULL;
|
|
string strReturn;
|
|
const char * src;
|
|
char * dest;
|
|
|
|
|
|
szTemp = (char*) ::malloc(sizeof(char) * nLength +1);
|
|
::memset(szTemp, 0 , sizeof(char)*nLength +1);
|
|
|
|
src = pszData;
|
|
dest = szTemp;
|
|
|
|
if( pszData == NULL )
|
|
{
|
|
strReturn.clear();
|
|
return strReturn;
|
|
}
|
|
|
|
if( *src == '\0' )
|
|
{
|
|
strReturn = src;
|
|
return strReturn;
|
|
}
|
|
// start with 2nd position
|
|
src++;
|
|
while ( src <= (pszData + nLength) && *(src-1) != '\0' )
|
|
{
|
|
if( *(src-1) == ' ' && *(src) == ' ' )
|
|
{ // 연속된 공백이 발견되면, 스킵한다.
|
|
src++;
|
|
continue;
|
|
}
|
|
*dest = *(src-1);
|
|
src++;
|
|
dest++;
|
|
}
|
|
// 종료표기
|
|
dest++;
|
|
*(dest) = '\0';
|
|
|
|
strReturn = szTemp;
|
|
if (szTemp != NULL)
|
|
{
|
|
free(szTemp);
|
|
szTemp = NULL;
|
|
}
|
|
return strReturn;
|
|
}
|
|
char hexchars[] = "0123456789ABCDEF";
|
|
string CSmsSender::PostDataEncode(const char *pszCommand, size_t length)
|
|
{
|
|
int i;
|
|
char tmpBuffer[MaxSizeOfTRxBuffer];
|
|
string strReturn;
|
|
|
|
if( pszCommand == NULL )
|
|
{
|
|
strReturn.clear();
|
|
return strReturn;
|
|
}
|
|
|
|
::memset(tmpBuffer, 0 , MaxSizeOfTRxBuffer);
|
|
i = 0;
|
|
while( *pszCommand != '\0' )
|
|
{
|
|
if( *pszCommand == ' ' )
|
|
{ // ' ' => '+'
|
|
tmpBuffer[i++] = '+';
|
|
pszCommand++;
|
|
}
|
|
else if(*pszCommand == '%')
|
|
{ // % => %%
|
|
tmpBuffer[i++] = '%';
|
|
tmpBuffer[i++] = '%';
|
|
pszCommand++;
|
|
}
|
|
else if( (*pszCommand < '0' && *pszCommand != '-' && *pszCommand != '.' )
|
|
|| (*pszCommand < 'A' && *pszCommand > '9' )
|
|
|| (*pszCommand > 'Z' && *pszCommand < 'a' && *pszCommand != '_' )
|
|
|| (*pszCommand > 'z' ) )
|
|
{
|
|
tmpBuffer[i++] = '%';
|
|
tmpBuffer[i++] = hexchars[(unsigned char)*pszCommand >> 4];
|
|
tmpBuffer[i++] = hexchars[(unsigned char)*pszCommand & 15];
|
|
pszCommand++;
|
|
}
|
|
else
|
|
{
|
|
tmpBuffer[i++] = *pszCommand++;
|
|
}
|
|
}
|
|
tmpBuffer[i] = '\0';
|
|
|
|
strReturn = tmpBuffer;
|
|
return strReturn;
|
|
}
|
|
|
|
|
|
|
|
CSmsSender::CSmsSender(const std::string& szHost, const int nPort, const std::string& szPath)
|
|
: CBaseSocket( SOCKET_NOT_VALID), m_szHost(szHost), m_nPort(nPort), m_szPath(szPath)
|
|
{
|
|
// 생성자
|
|
}
|
|
|
|
CSmsSender::~CSmsSender()
|
|
{
|
|
// 소멸자에 BaseSocket의 명시적 Close 처리를 한다.
|
|
Close();
|
|
}
|
|
|
|
bool CSmsSender::Init(void)
|
|
{
|
|
bool bRet = false;
|
|
|
|
// 데이터 체크
|
|
if( m_szHost.empty() || m_nPort < 0 || m_szPath.empty() )
|
|
{
|
|
LOG(LERR, "Invalid Parameter.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CSmsSender::SendToWebServ(const string& pszHost, const string& pszTime, const string& pszMsg)
|
|
{
|
|
string szHost;
|
|
string szTime;
|
|
string szMsg;
|
|
char szSndBuffer[DEFAULT_BUFFER_SIZE];
|
|
char szRcvBuffer[DEFAULT_BUFFER_SIZE];
|
|
bool bRet = false;
|
|
int nRet = 0;
|
|
|
|
|
|
if( pszHost.empty() || pszMsg.empty() || pszTime.empty() )
|
|
{
|
|
LOG(LERR, "Invalid Parameter.");
|
|
Close();
|
|
return false;
|
|
}
|
|
|
|
// Connect
|
|
bRet = Connect(m_szHost, m_nPort);
|
|
if( bRet == false )
|
|
{
|
|
LOG(LERR, "Socket Connect Error.[%s:%d]", m_szHost.c_str(), m_nPort);
|
|
return false;
|
|
}
|
|
if( IsValidSocket() == false )
|
|
{
|
|
LOG(LERR, "Invalid Socket.");
|
|
Close();
|
|
return false;
|
|
}
|
|
|
|
::bzero(szSndBuffer, DEFAULT_BUFFER_SIZE);
|
|
::bzero(szRcvBuffer, DEFAULT_BUFFER_SIZE);
|
|
|
|
szHost = PostDataEncode(pszHost.c_str(), pszHost.size());
|
|
szTime = PostDataEncode(pszTime.c_str(), pszTime.size());
|
|
szMsg = RemoveBlankSpace(pszMsg.c_str(), pszMsg.size());
|
|
LOG(LDBG, "SMSMsg = [%s]", szMsg.c_str());
|
|
szMsg = PostDataEncode(szMsg.c_str(), szMsg.size());
|
|
|
|
|
|
// CHG 2019-09-16 huibong HTTP 관련 줄바꿈문자 LF->CR+LF 변경 (#32794)
|
|
// - CVE-2016-8743 이슈에 따라 Apache 2.2.32 버전부터 HTTP header 상에서
|
|
// - 줄바꿈문자가 CR+LF 가 아닌 경우 HTTP 400 응답 발생
|
|
// - 이를 해결하기 위해 기존 줄바꿈 문자 \n -> \r\n 으로 변경처리한다.
|
|
::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "GET %s?host=%s&time=%s&msg=%s HTTP/1.0\r\n"\
|
|
"Content-Type: text/plain\r\n"\
|
|
"User-Agent: Arcmond\r\n"\
|
|
"Host: %s\r\n"\
|
|
"Connection: close\r\n"\
|
|
"Cache-Control: no-cache\r\n\r\n"
|
|
,m_szPath.c_str(), szHost.c_str(), szTime.c_str(), szMsg.c_str() ,m_szHost.c_str());
|
|
|
|
//DEBUG_LOG("%s", szSndBuffer);
|
|
//요청 전송 시작
|
|
nRet = WriteN(&szSndBuffer, ::strlen(szSndBuffer)+1);
|
|
// MAX_SEND_RETRY_COUNT 회수만큼 재시도 후 실패처리된다.
|
|
if( nRet == 0 )
|
|
{
|
|
LOG(LERR, "write socket closed.");
|
|
Close();
|
|
return false;
|
|
}
|
|
else if( nRet == -1 )
|
|
{
|
|
LOG(LERR, "write socket error.(%s)",strerror(errno));
|
|
Close();
|
|
return false;
|
|
}
|
|
|
|
// 응답 결과 받기.
|
|
nRet = ReadNTimeout(szRcvBuffer, DEFAULT_BUFFER_SIZE);
|
|
if( nRet == 0 )
|
|
{
|
|
// Remain이 0일 경우가 모두 받은 상황인데, 그것을 알 수 없다면,
|
|
// Ret==0일 때가 다 준 상황으로 판단해야 하지 않을까? 그렇다면 에러가 아니다.
|
|
LOG(LDBG, "read socket closed.");
|
|
}
|
|
else if( nRet == -1 )
|
|
{ // 단순 소켓 에러.
|
|
LOG(LERR, "read socket error.(%s)",strerror(errno));
|
|
Close();
|
|
return false;
|
|
}
|
|
else if( nRet == -2 )
|
|
{ // 타임아웃.
|
|
LOG(LERR, "read socket timed out.");
|
|
Close();
|
|
return false;
|
|
}
|
|
// 정상 결과는 아래와 같은 형태이다.
|
|
//----------------------------------------------------------------
|
|
// HTTP/1.1 200 OK
|
|
// Date: Thu, 10 Jun 2010 03:59:23 GMT
|
|
// Server: Apache/2.0.55 (Unix) DAV/2 PHP/5.2.1
|
|
// X-Powered-By: PHP/5.2.1
|
|
// Content-Length: 87
|
|
// Connection: close
|
|
// Content-Type: text/html; charset=EUC-KR
|
|
//
|
|
// [RAID:qcrts4.ktsh.co.kr]::2010-07-09 12:59:19:Controller#1: SW API Interface API Log In
|
|
//----------------------------------------------------------------
|
|
|
|
// 첫번째 라인만 출력하기 위해서 \n을 \0으로 바꾸고 출력한다.
|
|
char* pEnd = strchr(szRcvBuffer, '\n');
|
|
*pEnd = '\0';
|
|
|
|
LOG(LINF, "Result:%s", szRcvBuffer);
|
|
|
|
// Close()는 return값이 없음.
|
|
Close();
|
|
return true;
|
|
}
|