#include #include #include #include #include #include #include #include #include "SmsSender.h" #include #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; }