최종완료보고 버전
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
#ifndef BAIL_BUFFER__H_
|
||||
#define BAIL_BUFFER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HBailBuffer : public HObject
|
||||
{
|
||||
public:
|
||||
HBailBuffer(size_t nSize)
|
||||
{
|
||||
m_pBuffer = (char *)malloc(nSize);
|
||||
m_nBufferSize = nSize;
|
||||
|
||||
m_pBufferOffset = m_pBuffer;
|
||||
m_nStoredSize = 0;
|
||||
}
|
||||
|
||||
~HBailBuffer()
|
||||
{
|
||||
free(m_pBuffer);
|
||||
}
|
||||
|
||||
inline char * Offset() { return m_pBufferOffset; }
|
||||
inline void MoveOffset(size_t nSize)
|
||||
{
|
||||
m_pBufferOffset += nSize;
|
||||
m_nStoredSize += nSize;
|
||||
}
|
||||
|
||||
inline void Reset()
|
||||
{
|
||||
m_pBufferOffset = m_pBuffer;
|
||||
m_nStoredSize = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
char * m_pBuffer;
|
||||
size_t m_nBufferSize;
|
||||
size_t m_nStoredSize;
|
||||
|
||||
protected:
|
||||
char * m_pBufferOffset;
|
||||
};
|
||||
|
||||
#endif // BAIL_BUFFER__H_
|
||||
@@ -0,0 +1,397 @@
|
||||
#ifndef BLOCK_LIST_BUFFER__H_
|
||||
#define BLOCK_LIST_BUFFER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
struct _TBinaryBlock
|
||||
{
|
||||
char * pData;
|
||||
char * pDataOffset;
|
||||
int nSize;
|
||||
};
|
||||
typedef struct _TBinaryBlock TBinaryBlock;
|
||||
|
||||
|
||||
class HBlockListBuffer : public HObject
|
||||
{
|
||||
public:
|
||||
HBlockListBuffer(int nBlockSize)
|
||||
{
|
||||
m_nBlockSize = nBlockSize;
|
||||
m_nTotalSize = 0; //...
|
||||
}
|
||||
|
||||
~HBlockListBuffer()
|
||||
{
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
inline size_t GetCount() { return listBinaryBlock.size(); }
|
||||
|
||||
inline int GetTotalSize()
|
||||
{
|
||||
int nTotalSize = 0;
|
||||
for (std::list<TBinaryBlock>::iterator iter = listBinaryBlock.begin();
|
||||
iter != listBinaryBlock.end(); iter++)
|
||||
{
|
||||
if (iter->nSize > 0)
|
||||
nTotalSize += iter->nSize;
|
||||
}
|
||||
|
||||
return nTotalSize;
|
||||
}
|
||||
|
||||
inline bool Enqueue(const char * pData, int nSize)
|
||||
{
|
||||
if (nSize <= 0) //... command, -1 = end mark
|
||||
{
|
||||
TBinaryBlock blockNew;
|
||||
blockNew.nSize = nSize;
|
||||
listBinaryBlock.push_back(blockNew);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (listBinaryBlock.empty() == false)
|
||||
{
|
||||
#if 1
|
||||
std::list<TBinaryBlock>::iterator iter = listBinaryBlock.end();
|
||||
iter--;
|
||||
|
||||
if (iter->nSize <= 0)
|
||||
return false;
|
||||
|
||||
int nRemainBufer = m_nBlockSize - iter->nSize - (iter->pDataOffset - iter->pData);
|
||||
if (nRemainBufer > nSize)
|
||||
{
|
||||
memcpy(iter->pDataOffset + iter->nSize, pData, nSize);
|
||||
iter->nSize += nSize;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nRemainBufer > 0)
|
||||
{
|
||||
memcpy(iter->pDataOffset + iter->nSize, pData, nRemainBufer);
|
||||
iter->nSize += nRemainBufer;
|
||||
pData += nRemainBufer;
|
||||
nSize -= nRemainBufer;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while (nSize > 0)
|
||||
{
|
||||
TBinaryBlock blockNew;
|
||||
blockNew.pData = (char *)malloc(m_nBlockSize);
|
||||
blockNew.pDataOffset = blockNew.pData;
|
||||
|
||||
if (nSize <= m_nBlockSize)
|
||||
{
|
||||
memcpy(blockNew.pDataOffset, pData, nSize);
|
||||
blockNew.nSize = nSize;
|
||||
nSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(blockNew.pDataOffset, pData, m_nBlockSize);
|
||||
blockNew.nSize = m_nBlockSize;
|
||||
pData += m_nBlockSize;
|
||||
nSize -= m_nBlockSize;
|
||||
}
|
||||
|
||||
listBinaryBlock.push_back(blockNew);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Dequeue(char * pDst, int nCount)
|
||||
{
|
||||
if (nCount > GetTotalSize())
|
||||
return false;
|
||||
|
||||
int nRemainSize = nCount;
|
||||
|
||||
std::list<TBinaryBlock>::iterator iter = listBinaryBlock.begin();
|
||||
while (iter != listBinaryBlock.end())
|
||||
{
|
||||
if (iter->nSize < 0)
|
||||
return false;
|
||||
|
||||
if (nRemainSize < nCount)
|
||||
{
|
||||
if (iter->nSize < nRemainSize)
|
||||
{
|
||||
memcpy(pDst, iter->pDataOffset, iter->nSize);
|
||||
pDst += iter->nSize;
|
||||
nRemainSize -= iter->nSize;
|
||||
free(iter->pData);
|
||||
iter = listBinaryBlock.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pDst, iter->pDataOffset, nRemainSize);
|
||||
|
||||
if (iter->nSize == nRemainSize)
|
||||
{
|
||||
free(iter->pData);
|
||||
listBinaryBlock.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->pDataOffset += nRemainSize;
|
||||
iter->nSize -= nRemainSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (iter->nSize > 0)
|
||||
{
|
||||
if (iter->nSize < nCount)
|
||||
{
|
||||
memcpy(pDst, iter->pDataOffset, iter->nSize);
|
||||
pDst += iter->nSize;
|
||||
nRemainSize -= iter->nSize;
|
||||
free(iter->pData);
|
||||
iter = listBinaryBlock.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pDst, iter->pDataOffset, nCount);
|
||||
|
||||
if (iter->nSize == nCount)
|
||||
{
|
||||
free(iter->pData);
|
||||
listBinaryBlock.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->pDataOffset += nCount;
|
||||
iter->nSize -= nCount;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DequeueAll(char * pDst)
|
||||
{
|
||||
std::list<TBinaryBlock>::iterator iter = listBinaryBlock.begin();
|
||||
while (iter != listBinaryBlock.end())
|
||||
{
|
||||
if (iter->nSize <= 0) //...
|
||||
return false;
|
||||
|
||||
memcpy(pDst, iter->pDataOffset, iter->nSize);
|
||||
pDst += iter->nSize;
|
||||
free(iter->pData);
|
||||
iter = listBinaryBlock.erase(iter);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool GetFront(char ** ppData, int * pnSize)
|
||||
{
|
||||
std::list<TBinaryBlock>::iterator iter = listBinaryBlock.begin();
|
||||
if (iter == listBinaryBlock.end())
|
||||
return false;
|
||||
|
||||
if (iter->nSize > 0)
|
||||
*ppData = iter->pDataOffset;
|
||||
|
||||
*pnSize = iter->nSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void PopFront()
|
||||
{
|
||||
std::list<TBinaryBlock>::iterator iter = listBinaryBlock.begin();
|
||||
if (iter == listBinaryBlock.end())
|
||||
return;
|
||||
|
||||
if (iter->nSize > 0)
|
||||
free(iter->pData);
|
||||
listBinaryBlock.erase(iter);
|
||||
}
|
||||
|
||||
inline bool ReduceFront(int nSize)
|
||||
{
|
||||
if (nSize > m_nBlockSize)
|
||||
return false;
|
||||
|
||||
std::list<TBinaryBlock>::iterator iter = listBinaryBlock.begin();
|
||||
if (iter == listBinaryBlock.end())
|
||||
return false;
|
||||
|
||||
if (iter->nSize <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (nSize > iter->nSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (nSize == iter->nSize)
|
||||
{
|
||||
free(iter->pData);
|
||||
listBinaryBlock.erase(iter);
|
||||
return true;
|
||||
}
|
||||
|
||||
iter->pDataOffset += nSize;
|
||||
iter->nSize -= nSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void RemoveAll()
|
||||
{
|
||||
for (std::list<TBinaryBlock>::iterator iter = listBinaryBlock.begin();
|
||||
iter != listBinaryBlock.end(); iter++)
|
||||
{
|
||||
if (iter->nSize > 0)
|
||||
free(iter->pData);
|
||||
}
|
||||
listBinaryBlock.clear();
|
||||
}
|
||||
|
||||
HDynamicArray<char> ChangeAndClear(int * pnSize, int nExtra)
|
||||
{
|
||||
*pnSize = GetTotalSize();
|
||||
if (*pnSize <= 0)
|
||||
return (char *)NULL;
|
||||
|
||||
char * pBuffer = (char *)malloc(*pnSize + nExtra);
|
||||
char * pOffset = pBuffer;
|
||||
|
||||
for (std::list<TBinaryBlock>::iterator iter = listBinaryBlock.begin();
|
||||
iter != listBinaryBlock.end(); iter++)
|
||||
{
|
||||
if (iter->nSize > 0) //...
|
||||
{
|
||||
memcpy(pOffset, iter->pDataOffset, iter->nSize);
|
||||
pOffset += iter->nSize;
|
||||
}
|
||||
|
||||
free(iter->pData);
|
||||
}
|
||||
listBinaryBlock.clear();
|
||||
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
inline bool Copy(char * pDst, int nStartPos, int nCount)
|
||||
{
|
||||
int nRemainSize = nCount;
|
||||
int i = 0;
|
||||
for (std::list<TBinaryBlock>::iterator iter = listBinaryBlock.begin();
|
||||
iter != listBinaryBlock.end(); iter++)
|
||||
{
|
||||
if (iter->nSize < 0)
|
||||
return false;
|
||||
|
||||
i += iter->nSize;
|
||||
|
||||
if (nRemainSize < nCount)
|
||||
{
|
||||
if (iter->nSize < nRemainSize)
|
||||
{
|
||||
memcpy(pDst, iter->pDataOffset, iter->nSize);
|
||||
pDst += iter->nSize;
|
||||
nRemainSize -= iter->nSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pDst, iter->pDataOffset, nRemainSize);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (i > nStartPos) //...
|
||||
{
|
||||
int nBlockRemain = i - nStartPos;
|
||||
int nBlockStartIndex = iter->nSize - nBlockRemain;
|
||||
|
||||
if (nBlockRemain < nCount)
|
||||
{
|
||||
memcpy(pDst, iter->pDataOffset + nBlockStartIndex, nBlockRemain);
|
||||
pDst += nBlockRemain;
|
||||
nRemainSize -= nBlockRemain;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pDst, iter->pDataOffset + nBlockStartIndex, nCount);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int SearchChr(int nStartPos, char ch)
|
||||
{
|
||||
int i = 0, j;
|
||||
for (std::list<TBinaryBlock>::iterator iter = listBinaryBlock.begin();
|
||||
iter != listBinaryBlock.end(); iter++)
|
||||
{
|
||||
if (iter->nSize < 0)
|
||||
return -1;
|
||||
|
||||
if (i + iter->nSize > nStartPos)
|
||||
{
|
||||
for (j = 0; j < iter->nSize; j++)
|
||||
{
|
||||
if (i >= nStartPos && iter->pDataOffset[j] == ch)
|
||||
return i;
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
i += iter->nSize;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
void Print()
|
||||
{
|
||||
printf("Print, count = %d\n", listBinaryBlock.size());
|
||||
|
||||
int i = 0;
|
||||
for (std::list<TBinaryBlock>::iterator iter = listBinaryBlock.begin();
|
||||
iter != listBinaryBlock.end(); iter++)
|
||||
{
|
||||
printf("%d, ", i++);
|
||||
|
||||
if (iter->nSize > 0)
|
||||
{
|
||||
for (int j = 0; j < iter->nSize; j++)
|
||||
putchar(iter->pDataOffset[j]);
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::list<TBinaryBlock> listBinaryBlock;
|
||||
int m_nBlockSize;
|
||||
int m_nTotalSize;
|
||||
};
|
||||
|
||||
#endif // BLOCK_LIST_BUFFER__H_
|
||||
@@ -0,0 +1,109 @@
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
|
||||
unsigned int ELFHash(const char * str, unsigned int len)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
unsigned int x = 0;
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i = 0; i < len; str++, i++)
|
||||
{
|
||||
hash = (hash << 4) + (*str);
|
||||
if ((x = hash & 0xF0000000L) != 0)
|
||||
{
|
||||
hash ^= (x >> 24);
|
||||
}
|
||||
hash &= ~x;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Caution! : 0 ~ RAND_MAX
|
||||
unsigned _GetRandNum(unsigned nMin, unsigned nMax)
|
||||
{
|
||||
if ((nMin == 0 && nMax == 0) ||
|
||||
nMin > nMax)
|
||||
{
|
||||
//printf("[WARN] Invalide parameter.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nMax > RAND_MAX)
|
||||
{
|
||||
nMax = RAND_MAX;
|
||||
//printf("[WARN] Invalide parameter.\n");
|
||||
}
|
||||
|
||||
static bool bRandInit = false;
|
||||
if (bRandInit == false)
|
||||
{
|
||||
bRandInit = true;
|
||||
srand((unsigned)time(NULL));
|
||||
}
|
||||
|
||||
unsigned nRandNum;
|
||||
for (;;)
|
||||
{
|
||||
nRandNum = (unsigned)rand();
|
||||
|
||||
if (nRandNum >= nMin && nRandNum <= nMax)
|
||||
break;
|
||||
}
|
||||
|
||||
return nRandNum;
|
||||
}
|
||||
|
||||
bool RealignPathDepth(const char * pszSrc, char * pszDst)
|
||||
{
|
||||
if (pszSrc == NULL || pszDst == NULL)
|
||||
return false;
|
||||
|
||||
if (pszSrc[0] == '\0')
|
||||
{
|
||||
pszDst[0] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
const char * p1 = pszSrc;
|
||||
char * p2 = pszDst;
|
||||
|
||||
do
|
||||
{
|
||||
if (p1[0] == '.' && p1[1] == '.' && p1[2] == '.')
|
||||
{
|
||||
do
|
||||
{
|
||||
if (*p1 == '/' || *p1 == '\\' || *p1 == '\0')
|
||||
break;
|
||||
|
||||
*p2++ = *p1;
|
||||
} while (p1++);
|
||||
}
|
||||
|
||||
if (*p1 == '\0')
|
||||
break;
|
||||
|
||||
if (p1[0] == '.' && p1[1] == '.' && (p1[2] == '/' || p1[2] == '\\'))
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
while (p2 != pszDst && p2--)
|
||||
{
|
||||
if (*p2 == '/' || *p2 == '\\' || p2 == pszDst)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p1 += 2;
|
||||
}
|
||||
|
||||
*p2++ = *p1;
|
||||
} while (p1++);
|
||||
|
||||
*p2 = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
|
||||
#ifndef COMMON__H_
|
||||
#define COMMON__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#pragma once
|
||||
|
||||
//#define FD_SETSIZE 1024
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
#pragma comment(lib, "winmm.lib")
|
||||
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
#include <io.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h> // fork
|
||||
#include <errno.h> // errno
|
||||
#include <sys/wait.h> // wait
|
||||
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/timeb.h> // ftime
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef USE_STD_ASSERT
|
||||
#include <assert.h>
|
||||
#elif USE_TENMIN_ASSERT
|
||||
|
||||
#define assert(EXP) (void)((!!(EXP)) || (tmassert((#EXP), __FILE__, __LINE__), 0))
|
||||
|
||||
inline void tmassert(const char * psz, const char * pszFileName, unsigned nLine)
|
||||
{
|
||||
//ALOG(1, "[FATAL ERROR], Assertion failed : %s, file : %s, line : %d\n", psz, pszFileName, nLine);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
#else
|
||||
#if _MSC_VER <= 1200
|
||||
#define assert(EXP) ((void)0)
|
||||
#else
|
||||
#define assert(EXP) __noop
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#pragma once
|
||||
|
||||
#else
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
typedef unsigned int DWORD;
|
||||
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
#define TENMIN_FAILED 0
|
||||
#define TENMIN_SUCCESS 1
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#if _MSC_VER <= 1200
|
||||
#ifdef _DEBUG
|
||||
#include <crtdbg.h>
|
||||
#include <malloc.h>
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
// add stl header ...
|
||||
|
||||
inline void * operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
|
||||
{
|
||||
return _malloc_dbg(nSize, _NORMAL_BLOCK, lpszFileName, nLine);
|
||||
}
|
||||
|
||||
inline void operator delete(void * p)
|
||||
{
|
||||
_free_dbg(p, _NORMAL_BLOCK);
|
||||
}
|
||||
|
||||
inline void operator delete(void * p, LPCSTR, int)
|
||||
{
|
||||
_free_dbg(p, _NORMAL_BLOCK);
|
||||
}
|
||||
|
||||
#define new new(__FILE__, __LINE__)
|
||||
|
||||
#define malloc(SIZE) _malloc_dbg(SIZE, _NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#define free(PTR) _free_dbg(PTR, _NORMAL_BLOCK)
|
||||
|
||||
#endif // _DEBUG
|
||||
#endif // _MSC_VER <= 1200
|
||||
|
||||
#ifndef snprintf
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#ifndef strcasecmp
|
||||
#define strcasecmp stricmp
|
||||
#endif
|
||||
|
||||
#define sched_yield() Sleep(0)
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
unsigned GetRandNum(unsigned nMin, unsigned nMax); // return 0 ~ RAND_MAX
|
||||
unsigned int ELFHash(const char * str, unsigned int len);
|
||||
|
||||
extern inline int GetLastDayOfTheMonth(int nYear, int nMonth)
|
||||
{
|
||||
struct tm tmTmp = { 0, 0, 0, 1, nMonth, nYear - 1900 };
|
||||
time_t timeTmp = mktime(&tmTmp) - 86400;
|
||||
|
||||
if (timeTmp < 0)
|
||||
return -1;
|
||||
|
||||
struct tm * ptmNewTmp = localtime(&timeTmp);
|
||||
|
||||
return ptmNewTmp->tm_mday;
|
||||
}
|
||||
|
||||
extern inline unsigned int TimeDiff(unsigned int nTimePrev, unsigned int nTimeCurr)
|
||||
{
|
||||
if (nTimePrev <= nTimeCurr)
|
||||
return nTimeCurr - nTimePrev;
|
||||
|
||||
return nTimeCurr + (0xFFFFFFFFU - nTimePrev) + 1U;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
#define TERR_INVALID_PROCESSNAME 2 // Failed to access()
|
||||
#define TERR_FAILED_FORK 3 // Failed to fork()
|
||||
#define TERR_FAILED_WAIT 4 // Failed to wait()
|
||||
|
||||
extern inline int ExecuteProcess(const char * pszProcessName,
|
||||
const char * pszCommandLine, bool bWaiting = false, int * pnExitCode = NULL)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
STARTUPINFO startUpInfo;
|
||||
memset(&startUpInfo, 0, sizeof startUpInfo);
|
||||
startUpInfo.cb = sizeof(STARTUPINFO);
|
||||
|
||||
//char cmdline[] = "dir /w";
|
||||
char cmdline[] = "calc";
|
||||
|
||||
PROCESS_INFORMATION processInfo;
|
||||
memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
|
||||
BOOL b = CreateProcess( NULL, cmdline, NULL, NULL, false,
|
||||
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &startUpInfo, &processInfo);
|
||||
DWORD dwErr = 0;
|
||||
if( b ) {
|
||||
WaitForSingleObject( processInfo.hProcess, INFINITE );
|
||||
GetExitCodeProcess( processInfo.hProcess, &dwErr );
|
||||
CloseHandle( processInfo.hProcess );
|
||||
printf("\n\n ------- ExecuteProcess error1 --------\n\n");
|
||||
} else {
|
||||
dwErr = GetLastError();
|
||||
printf("\n\n ------- ExecuteProcess error2 --------\n\n");
|
||||
}
|
||||
if( dwErr ) {
|
||||
// deal with error here
|
||||
printf("\n\n ------- ExecuteProcess error3 --------\n\n");
|
||||
}
|
||||
|
||||
return TENMIN_SUCCESS;
|
||||
#else
|
||||
if (pszProcessName == NULL || pszProcessName[0] == '\0' || access(pszProcessName, X_OK) == -1)
|
||||
return TERR_INVALID_PROCESSNAME;
|
||||
|
||||
int nPid = fork();
|
||||
if (nPid == -1)
|
||||
{
|
||||
return TERR_FAILED_FORK;
|
||||
}
|
||||
else if (nPid == 0)
|
||||
{
|
||||
//if (execvp(pszProcessName, (char* const*)lpszArgList) == -1)
|
||||
{
|
||||
if (errno)
|
||||
_exit(errno);
|
||||
}
|
||||
|
||||
_exit(255);
|
||||
}
|
||||
|
||||
if (bWaiting)
|
||||
{
|
||||
int nStatVal;
|
||||
if (wait(&nStatVal) == -1)
|
||||
return TERR_FAILED_WAIT;
|
||||
|
||||
if (pnExitCode)
|
||||
{
|
||||
if (WIFEXITED(nStatVal))
|
||||
*pnExitCode = WEXITSTATUS(nStatVal);
|
||||
}
|
||||
}
|
||||
|
||||
return TENMIN_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
#ifndef S_IREAD
|
||||
#define S_IREAD S_IRUSR
|
||||
#endif
|
||||
|
||||
#ifndef S_IWRITE
|
||||
#define S_IWRITE S_IWUSR
|
||||
#endif
|
||||
|
||||
#ifndef S_IEXEC
|
||||
#define S_IEXEC S_IXUSR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
extern inline DWORD timeGetTime()
|
||||
{
|
||||
#if 0
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL); // obsolescent at 2008
|
||||
|
||||
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
|
||||
#else
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
|
||||
#endif
|
||||
}
|
||||
#define GetTickCount timeGetTime
|
||||
|
||||
extern inline void Sleep(DWORD nTime)
|
||||
{
|
||||
#if 0
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = nTime / 1000;
|
||||
tv.tv_usec = (nTime % 1000) * 1000; // msec
|
||||
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
#else
|
||||
struct timespec ts;
|
||||
|
||||
ts.tv_sec = nTime / 1000;
|
||||
ts.tv_nsec = (nTime % 1000) * 1000000; // nsec
|
||||
|
||||
nanosleep(&ts, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct tagSYSTEMTIME
|
||||
{
|
||||
DWORD wYear;
|
||||
DWORD wMonth;
|
||||
DWORD wDay;
|
||||
DWORD wHour;
|
||||
DWORD wMinute;
|
||||
DWORD wSecond;
|
||||
DWORD wMilliseconds;
|
||||
} SYSTEMTIME, *PSYSTEMTIME;
|
||||
|
||||
extern inline void GetLocalTime(PSYSTEMTIME lpSystemTime)
|
||||
{
|
||||
struct tm * tmTmp;
|
||||
struct timeb tTimeb;
|
||||
|
||||
ftime(&tTimeb);
|
||||
tmTmp = localtime(&tTimeb.time);
|
||||
|
||||
lpSystemTime->wYear = tmTmp->tm_year + 1900;
|
||||
lpSystemTime->wMonth = tmTmp->tm_mon + 1;
|
||||
lpSystemTime->wDay = tmTmp->tm_mday;
|
||||
lpSystemTime->wHour = tmTmp->tm_hour;
|
||||
lpSystemTime->wMinute = tmTmp->tm_min;
|
||||
lpSystemTime->wSecond = tmTmp->tm_sec;
|
||||
lpSystemTime->wMilliseconds = tTimeb.millitm;
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
extern inline void GetCurrentDatetime(char * pszDst, int nType = 0)
|
||||
{
|
||||
SYSTEMTIME systemTime;
|
||||
GetLocalTime(&systemTime);
|
||||
|
||||
if (nType == 0) // YYYY-MM-DD hh:mm:ss
|
||||
sprintf(pszDst, "%.4ld-%.2ld-%.2ld %.2ld:%.2ld:%.2ld", systemTime.wYear, systemTime.wMonth, systemTime.wDay,
|
||||
systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
|
||||
else if (nType == 1) // YYYYMMDDhhmmss
|
||||
sprintf(pszDst, "%.4ld%.2ld%.2ld%.2ld%.2ld%.2ld", systemTime.wYear, systemTime.wMonth, systemTime.wDay,
|
||||
systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
|
||||
else if (nType == 2) // YYYYMMDDhhmmss.msec
|
||||
sprintf(pszDst, "%.4ld%.2ld%.2ld%.2ld%.2ld%.2ld.%.3ld", systemTime.wYear,
|
||||
systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
|
||||
}
|
||||
|
||||
extern inline void GetDateTimeNum(char * pszDst)
|
||||
{
|
||||
SYSTEMTIME systemTime;
|
||||
GetLocalTime(&systemTime);
|
||||
sprintf(pszDst, "%.4ld%.2ld%.2ld%.2ld%.2ld%.2ld.%.3ld", systemTime.wYear,
|
||||
systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
|
||||
}
|
||||
|
||||
extern inline void GetDateTimeNum2(char * pszDst)
|
||||
{
|
||||
SYSTEMTIME systemTime;
|
||||
GetLocalTime(&systemTime);
|
||||
sprintf(pszDst, "%.4ld%.2ld%.2ld%.2ld%.2ld%.2ld", systemTime.wYear,
|
||||
systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
|
||||
}
|
||||
|
||||
|
||||
bool RealignPathDepth(const char * pszSrc, char * pszDst);
|
||||
|
||||
extern inline bool GetProcessDirectory(char * pszDir, DWORD nBufferLength)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (::GetModuleFileName(NULL, pszDir, nBufferLength) == FALSE)
|
||||
return false;
|
||||
|
||||
if (::GetLongPathName(pszDir, pszDir, nBufferLength) == FALSE)
|
||||
return false;
|
||||
|
||||
char * pTemp;
|
||||
if ((pTemp = strrchr(pszDir, '\\')) != NULL ||
|
||||
(pTemp = strrchr(pszDir, '/')) != NULL)
|
||||
{
|
||||
size_t nLen = strlen(pszDir) - strlen(pTemp);
|
||||
pszDir[nLen + 1] = '\0';
|
||||
}
|
||||
#else
|
||||
//...
|
||||
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
extern inline void Hassert(bool b)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // COMMON__H_
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
#include "stringex.h"
|
||||
#include "Defines.h"
|
||||
#include "Common.h"
|
||||
#include "Object.h"
|
||||
#include "String.h"
|
||||
#include "File.h"
|
||||
#include "Config.h"
|
||||
|
||||
#include "inifile.h"
|
||||
|
||||
|
||||
|
||||
HConfig::HConfig()
|
||||
{
|
||||
m_pIniFile = new HIniFile;
|
||||
}
|
||||
|
||||
HConfig::~HConfig()
|
||||
{
|
||||
delete m_pIniFile;
|
||||
}
|
||||
|
||||
bool HConfig::OpenConfig(const char * pszPathName)
|
||||
{
|
||||
HFile file;
|
||||
if (file.Open(pszPathName, HFile::FMODE_RDONLY) == false)
|
||||
return false;
|
||||
|
||||
m_pIniFile->SetIniFile(pszPathName);
|
||||
|
||||
m_strConfigFile = pszPathName;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HConfig::CloseConfig()
|
||||
{
|
||||
}
|
||||
|
||||
HString HConfig::ReadString(const char * pszSetionName, const char * pszKeyName, const char * pszDefault)
|
||||
{
|
||||
return m_pIniFile->ReadString(pszSetionName, pszKeyName, pszDefault);
|
||||
}
|
||||
|
||||
bool HConfig::WriteString(const char * pszSetionName, const char * pszKeyName, const char * pszString)
|
||||
{
|
||||
return m_pIniFile->WriteString(pszSetionName, pszKeyName, pszString);
|
||||
}
|
||||
|
||||
int HConfig::ReadNumber(const char * pszSetionName, const char * pszKeyName, int nDefault)
|
||||
{
|
||||
return m_pIniFile->ReadNumber(pszSetionName, pszKeyName, nDefault);
|
||||
}
|
||||
|
||||
bool HConfig::WriteNumber(const char * pszSetionName, const char * pszKeyName, int nNumber)
|
||||
{
|
||||
return m_pIniFile->WriteNumber(pszSetionName, pszKeyName, nNumber);
|
||||
}
|
||||
|
||||
bool HConfig::ReadBoolean(const char * pszSetionName, const char * pszKeyName, bool bDefault)
|
||||
{
|
||||
return m_pIniFile->ReadBoolean(pszSetionName, pszKeyName, bDefault);
|
||||
}
|
||||
|
||||
bool HConfig::WriteBoolean(const char * pszSetionName, const char * pszKeyName, bool bValue)
|
||||
{
|
||||
return m_pIniFile->WriteBoolean(pszSetionName, pszKeyName, bValue);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef CONFIG__H_
|
||||
#define CONFIG__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HIniFile;
|
||||
|
||||
|
||||
class HConfig : public HObject
|
||||
{
|
||||
public:
|
||||
HConfig();
|
||||
~HConfig();
|
||||
|
||||
virtual bool OpenConfig(const char * pszPathName);
|
||||
virtual void CloseConfig();
|
||||
virtual inline const char * GetConfigPathName() { return m_strConfigFile; }
|
||||
|
||||
virtual HString ReadString(const char * pszSetionName, const char * pszKeyName, const char * pszDefault);
|
||||
virtual bool WriteString(const char * pszSetionName, const char * pszKeyName, const char * pszString);
|
||||
|
||||
virtual int ReadNumber(const char * pszSetionName, const char * pszKeyName, int nDefault);
|
||||
virtual bool WriteNumber(const char * pszSetionName, const char * pszKeyName, int nNumber);
|
||||
|
||||
virtual bool ReadBoolean(const char * pszSetionName, const char * pszKeyName, bool bDefault);
|
||||
virtual bool WriteBoolean(const char * pszSetionName, const char * pszKeyName, bool bValue);
|
||||
|
||||
private:
|
||||
HString m_strConfigFile;
|
||||
HIniFile * m_pIniFile;
|
||||
};
|
||||
|
||||
#endif // CONFIG__H_
|
||||
@@ -0,0 +1,111 @@
|
||||
|
||||
#ifndef DATA_STRUCT__H_
|
||||
#define DATA_STRUCT__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#if 0
|
||||
template<class _T>
|
||||
class HBuffer
|
||||
{
|
||||
public:
|
||||
HBuffer() { m_pBuf = NULL; m_nSize = 0; }
|
||||
HBuffer(size_t n) { if (n) m_pBuf = (_T *)malloc(n * sizeof(_T)); else m_pBuf = NULL; m_nSize = n; }
|
||||
virtual ~HBuffer() { if (m_pBuf) free(m_pBuf); }
|
||||
|
||||
inline _T * GetPtr() { return m_pBuf; }
|
||||
inline size_t GetSize() { return m_nSize; }
|
||||
|
||||
inline void Create(size_t n)
|
||||
{
|
||||
if (n)
|
||||
m_pBuf = (_T *)malloc(n * sizeof(_T));
|
||||
|
||||
m_nSize = n;
|
||||
}
|
||||
|
||||
inline bool Copy(_T * pData, size_t nSize)
|
||||
{
|
||||
if (pData == NULL || nSize <= 0)
|
||||
return false;
|
||||
|
||||
memcpy(m_pBuf, pData, nSize);
|
||||
}
|
||||
|
||||
protected:
|
||||
_T * m_pBuf;
|
||||
size_t m_nSize;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<class _T>
|
||||
class HDynamicArray
|
||||
{
|
||||
public:
|
||||
HDynamicArray(size_t n) { if (n) m_p = (_T *)malloc(n * sizeof(_T)); else m_p = NULL; }
|
||||
HDynamicArray(_T * p) { m_p = p; }
|
||||
~HDynamicArray() { if (m_p) free(m_p); }
|
||||
|
||||
inline void Attach(_T * p) { m_p = p; }
|
||||
inline void Detatch() { m_p = NULL; }
|
||||
|
||||
inline void Realloc(size_t n) { free(m_p); m_p = (_T *)malloc(n * sizeof(_T)); }
|
||||
inline void Restruct(_T * p) { free(m_p); m_p = p; }
|
||||
|
||||
_T * m_p;
|
||||
};
|
||||
|
||||
class HStrList : public std::list<HString>
|
||||
{
|
||||
public:
|
||||
HStrList() {}
|
||||
~HStrList() {}
|
||||
|
||||
inline void SplitAdd(const HString & str, char chDelimiter)
|
||||
{
|
||||
HStringTokenizer token(str, chDelimiter);
|
||||
for (size_t i = 0; i < token.GetCount(); i++)
|
||||
{
|
||||
push_back(token[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class HStrVector : public std::vector<HString>
|
||||
{
|
||||
public:
|
||||
HStrVector() {}
|
||||
~HStrVector() {}
|
||||
|
||||
inline void Remove(const char * psz)
|
||||
{
|
||||
erase(std::remove(begin(), end(), psz), end());
|
||||
}
|
||||
|
||||
inline bool IsExist(const char * psz)
|
||||
{
|
||||
HString str = psz;
|
||||
return std::find(begin(), end(), str) != end();
|
||||
}
|
||||
};
|
||||
|
||||
class HStrStrMap : public std::map<HString, HString>
|
||||
{
|
||||
public:
|
||||
HStrStrMap() {}
|
||||
~HStrStrMap() {}
|
||||
|
||||
inline void Insert(const char * pszKey, const char * pszValue)
|
||||
{
|
||||
insert(std::pair<HString, HString>(pszKey, pszValue));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // DATA_STRUCT__H
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef DEFINES__H_
|
||||
#define DEFINES__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#define HLOG_ERROR 1
|
||||
#define HLOG_WARNING 3
|
||||
#define HLOG_INFO1 5
|
||||
#define HLOG_INFO2 6
|
||||
#define HLOG_INFO3 7
|
||||
#define HLOG_INFO4 9
|
||||
#define HLOG_INFO5 11
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,180 @@
|
||||
#ifndef EMAIL_SENDER__H_
|
||||
#define EMAIL_SENDER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HEmailSender : public HThread
|
||||
{
|
||||
public:
|
||||
HEmailSender(const HString & strIp, u_short nPort, const HString & strSubject, const HString & strMessage, const HString & strFrom, const HStrList & listTo)
|
||||
: HThread(true)
|
||||
{
|
||||
HLOGF(HLOG_INFO5, "INFO, EmailSender, new, %s, %d, %s, %s, %s\n", strIp.psz(), nPort, strFrom.psz(), strSubject.psz(), strMessage.psz());
|
||||
|
||||
m_strIp = strIp;
|
||||
m_nPort = nPort;
|
||||
m_strSubject = strSubject;
|
||||
m_strMessage = strMessage;
|
||||
m_strFrom = strFrom;
|
||||
m_listTo = listTo;
|
||||
|
||||
Begin();
|
||||
}
|
||||
|
||||
~HEmailSender() {}
|
||||
|
||||
bool SendCompleteSize(SOCKET sock, const char * pszPacket, size_t nPacketSize)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[TRACE], EmailSender, tx, %s", pszPacket);
|
||||
|
||||
off_t nSentSize;
|
||||
const char * pszPacketOffset = pszPacket;
|
||||
while (nPacketSize > 0)
|
||||
{
|
||||
nSentSize = send(sock, pszPacketOffset, nPacketSize, 0);
|
||||
if (nSentSize <= 0)
|
||||
{
|
||||
HLOG(HLOG_ERROR, "[ERROR], EmailSender, Failed to send.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
nPacketSize -= nSentSize;
|
||||
pszPacketOffset += nSentSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecvCompleteResponse(SOCKET sock)
|
||||
{
|
||||
int nRecvSize;
|
||||
char pBuffer[8192];
|
||||
char * pBufferOffset = pBuffer;
|
||||
for (;;)
|
||||
{
|
||||
nRecvSize = recv(sock, pBufferOffset, 8191, 0);
|
||||
if (nRecvSize <= 0 || (pBuffer[0] != '2' && pBuffer[0] != '3')) // '2' is error return
|
||||
break;
|
||||
|
||||
pBufferOffset[nRecvSize] = '\0';
|
||||
|
||||
if (strstr(pBuffer, "\r\n"))
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[TRACE], EmailSender, rx, %s", pBuffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
pBufferOffset += nRecvSize;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Main()
|
||||
{
|
||||
// send message /////////////////////////////////////
|
||||
SOCKET sockClient;
|
||||
|
||||
// create socket
|
||||
sockClient = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockClient == INVALID_SOCKET)
|
||||
{
|
||||
HLOG(HLOG_ERROR, "[ERROR], EmailSender, Failed to socket()\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// set destination address
|
||||
struct sockaddr_in sai;
|
||||
memset(&sai, '\0', sizeof(struct sockaddr_in));
|
||||
|
||||
sai.sin_addr.s_addr = inet_addr(m_strIp);
|
||||
sai.sin_family = AF_INET;
|
||||
sai.sin_port = htons(m_nPort);
|
||||
|
||||
HLOG(HLOG_INFO5, "INFO, EmailSender, Trying to connect...\n");
|
||||
|
||||
if (connect(sockClient, (struct sockaddr *)&sai, sizeof(struct sockaddr)) == SOCKET_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], EmailSender, connect timeout. socket = %d\n", sockClient);
|
||||
return;
|
||||
}
|
||||
|
||||
HLOG(HLOG_INFO5, "INFO, EmailSender, Connected\n");
|
||||
|
||||
//HELO 14.34.59.93
|
||||
//MAIL FROM: sender@nate.com
|
||||
//RCPT TO: comicgum@nate.com
|
||||
//DATA
|
||||
//From: tester<sender@nate.com>
|
||||
//To: comicgum<comicgum@nate.com>
|
||||
//Subject: test subject
|
||||
//Test Message...
|
||||
//.
|
||||
//QUIT
|
||||
|
||||
size_t nSendSize;
|
||||
char szCommand[16384];
|
||||
|
||||
if (RecvCompleteResponse(sockClient) == false)
|
||||
return;
|
||||
|
||||
nSendSize = sprintf(szCommand, "HELO %s\r\n", m_strIp.psz()); // SMTP server address
|
||||
if (SendCompleteSize(sockClient, szCommand, nSendSize) == false || RecvCompleteResponse(sockClient) == false)
|
||||
return;
|
||||
|
||||
nSendSize = sprintf(szCommand, "MAIL FROM: %s\r\n", m_strFrom.psz()); // sender email address
|
||||
if (SendCompleteSize(sockClient, szCommand, nSendSize) == false || RecvCompleteResponse(sockClient) == false)
|
||||
return;
|
||||
|
||||
HString strTo;
|
||||
HStrList::iterator iter = m_listTo.begin();
|
||||
for (;;)
|
||||
{
|
||||
nSendSize = sprintf(szCommand, "RCPT TO: %s\r\n", iter->psz()); // return email address
|
||||
if (SendCompleteSize(sockClient, szCommand, nSendSize) == false || RecvCompleteResponse(sockClient) == false)
|
||||
return;
|
||||
|
||||
strTo += iter->psz();
|
||||
|
||||
if (++iter == m_listTo.end())
|
||||
break;
|
||||
|
||||
strTo += ",";
|
||||
}
|
||||
|
||||
nSendSize = sprintf(szCommand, "DATA\r\n"); // messgae start
|
||||
if (SendCompleteSize(sockClient, szCommand, nSendSize) == false || RecvCompleteResponse(sockClient) == false)
|
||||
return;
|
||||
|
||||
nSendSize = sprintf(szCommand, //"%s\r\n",
|
||||
"From: LibProxy3<%s>\r\n"
|
||||
"To: %s\r\n"
|
||||
"Subject: %s\r\n"
|
||||
"%s\r\n.\r\n", m_strFrom.psz(), strTo.psz(), m_strSubject.psz(), m_strMessage.psz()); // message
|
||||
if (SendCompleteSize(sockClient, szCommand, nSendSize) == false || RecvCompleteResponse(sockClient) == false)
|
||||
return;
|
||||
|
||||
nSendSize = sprintf(szCommand, "QUIT\r\n"); // end
|
||||
if (SendCompleteSize(sockClient, szCommand, nSendSize) == false || RecvCompleteResponse(sockClient) == false)
|
||||
return;
|
||||
|
||||
#ifdef _WIN32
|
||||
closesocket(sockClient);
|
||||
#else
|
||||
closesocket(sockClient);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
HString m_strIp;
|
||||
u_short m_nPort;
|
||||
HString m_strSubject;
|
||||
HString m_strMessage;
|
||||
HString m_strFrom;
|
||||
HStrList m_listTo;
|
||||
};
|
||||
|
||||
#endif // EMAIL_SENDER__H_
|
||||
@@ -0,0 +1,130 @@
|
||||
|
||||
#ifndef FILE__H_
|
||||
#define FILE__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HFile
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
FMODE_CREATE = 0x0001,
|
||||
FMODE_RDONLY = 0x0002,
|
||||
FMODE_WRONLY = 0x0004,
|
||||
FMODE_RW = 0x0008
|
||||
};
|
||||
|
||||
static off_t GetSize(const char * pszFileName)
|
||||
{
|
||||
struct stat statTemp;
|
||||
stat(pszFileName, &statTemp);
|
||||
|
||||
return statTemp.st_size;
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
HFile()
|
||||
{
|
||||
m_fdFile = -1;
|
||||
}
|
||||
|
||||
~HFile()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
inline int GetFile();
|
||||
|
||||
inline bool Open(const char * pszFileName, int nMode, bool bIsContinue = false, bool bIsBinary = true);
|
||||
inline void Close();
|
||||
|
||||
inline int Read(void * buffer, unsigned int count);
|
||||
inline int ReadString(char * buffer, unsigned int count);
|
||||
inline int Write(const void * buffer, unsigned int count);
|
||||
|
||||
private:
|
||||
int m_fdFile;
|
||||
};
|
||||
|
||||
inline int HFile::GetFile() { return m_fdFile; }
|
||||
|
||||
inline bool HFile::Open(const char * pszFileName, int nMode, bool bIsContinue, bool bIsBinary)
|
||||
{
|
||||
int oflag = 0;
|
||||
|
||||
if ((nMode & FMODE_CREATE) == FMODE_CREATE)
|
||||
oflag = O_CREAT;
|
||||
|
||||
if ((nMode & FMODE_RDONLY) == FMODE_RDONLY)
|
||||
oflag |= O_RDONLY;
|
||||
else if ((nMode & FMODE_WRONLY) == FMODE_WRONLY)
|
||||
oflag |= O_WRONLY;
|
||||
else
|
||||
oflag |= O_RDWR;
|
||||
|
||||
if (bIsContinue == false && ((nMode & FMODE_CREATE) == FMODE_CREATE))
|
||||
oflag |= O_TRUNC;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (bIsBinary)
|
||||
oflag |= O_BINARY;
|
||||
else
|
||||
oflag |= O_TEXT;
|
||||
|
||||
m_fdFile = open(pszFileName, oflag, S_IREAD | S_IWRITE);
|
||||
#else
|
||||
m_fdFile = open(pszFileName, oflag, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH);
|
||||
#endif
|
||||
|
||||
if (m_fdFile == -1)
|
||||
return false;
|
||||
|
||||
if (bIsContinue && ((nMode & FMODE_WRONLY) == FMODE_WRONLY || (nMode & FMODE_RW) == FMODE_RW))
|
||||
lseek(m_fdFile, 0L, SEEK_END);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void HFile::Close()
|
||||
{
|
||||
if (m_fdFile != -1)
|
||||
{
|
||||
close(m_fdFile);
|
||||
m_fdFile = -1;
|
||||
}
|
||||
}
|
||||
|
||||
inline int HFile::Read(void * buffer, unsigned int count)
|
||||
{
|
||||
if (m_fdFile == -1)
|
||||
return -1;
|
||||
|
||||
return read(m_fdFile, buffer, count);
|
||||
}
|
||||
|
||||
inline int HFile::ReadString(char * buffer, unsigned int count)
|
||||
{
|
||||
if (m_fdFile == -1)
|
||||
return -1;
|
||||
|
||||
int nResult = read(m_fdFile, buffer, count);
|
||||
if (nResult > 0)
|
||||
buffer[nResult] = '\0';
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
inline int HFile::Write(const void * buffer, unsigned int count)
|
||||
{
|
||||
if (m_fdFile == -1)
|
||||
return -1;
|
||||
|
||||
return write(m_fdFile, buffer, count);
|
||||
}
|
||||
|
||||
#endif // FILE__H_
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "Global.h"
|
||||
|
||||
size_t g_nMaxPathNameLength = 4096;
|
||||
|
||||
//size_t g_nSocketReceiveBlockSize = 8192;
|
||||
size_t g_nSocketReceiveBlockSize = 32768;
|
||||
//size_t g_nSocketSendingBlockSize = 1200; // for MTU
|
||||
//size_t g_nSocketSendingBlockSize = 8192;
|
||||
size_t g_nSocketSendingBlockSize = 32768;
|
||||
|
||||
|
||||
//size_t g_nMaxHsHeaderSize = 16384; // in Apache default limit is 8KB, in IIS it's 16K.
|
||||
size_t g_nMaxHsHeaderSize = 32768; // because of elsevier.com
|
||||
|
||||
|
||||
unsigned long g_nTcpConnectTimeout = 15000;
|
||||
//unsigned long g_nTcpConnectTimeout = 3000;
|
||||
//unsigned long g_nTcpAutoReconnectTime = 15000;
|
||||
|
||||
unsigned long g_nTcpKeepAliveTime = 3000;
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef GLOBAL__H_
|
||||
#define GLOBAL__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
extern size_t g_nMaxPathNameLength;
|
||||
|
||||
extern size_t g_nSocketReceiveBlockSize;
|
||||
extern size_t g_nSocketSendingBlockSize;
|
||||
|
||||
extern size_t g_nMaxHsHeaderSize;
|
||||
|
||||
extern unsigned long g_nTcpConnectTimeout;
|
||||
//extern unsigned long g_nTcpAutoReconnectTime;
|
||||
|
||||
extern unsigned long g_nTcpKeepAliveTime;
|
||||
|
||||
|
||||
#endif // GLOBAL__H_
|
||||
@@ -0,0 +1,550 @@
|
||||
|
||||
#include "huslib.h"
|
||||
#include "huslibex.h"
|
||||
|
||||
|
||||
bool HHttpHandler::UriCmp(const char * pszRequestUri, const char * pszPrefix)
|
||||
{
|
||||
const char * p1 = pszRequestUri;
|
||||
const char * p2 = pszPrefix;
|
||||
for (;;)
|
||||
{
|
||||
if (*p1 == '?' && *p2 == '\0')
|
||||
break;
|
||||
else if (strcmp(p1, "/") == 0 && *p2 == '\0')
|
||||
break;
|
||||
else if (*p1 != '\0' && *p2 == '*')
|
||||
break;
|
||||
else if (*p1 != *p2)
|
||||
return false;
|
||||
else if (*p1 == '\0' && *p2 == '\0')
|
||||
break;
|
||||
else if (*p1 == '\0' || *p2 == '\0')
|
||||
return false;
|
||||
|
||||
p1++;
|
||||
p2++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HHttpHandler::GetParamValue(const char * pszString, const char * pszKey, char * pszValue)
|
||||
{
|
||||
pszValue[0] = '\0';
|
||||
|
||||
char * pszKeyString = (char *)malloc(strlen(pszKey) + 2);
|
||||
strcpy(pszKeyString, pszKey);
|
||||
strcat(pszKeyString, "=");
|
||||
|
||||
const char * pszSearch = strstr(pszString, pszKeyString);
|
||||
free(pszKeyString);
|
||||
|
||||
if (pszSearch == NULL)
|
||||
return false;
|
||||
|
||||
int nIndex = (int)(pszSearch - pszString);
|
||||
if (nIndex > 0 &&
|
||||
pszString[nIndex - 1] != '?' &&
|
||||
pszString[nIndex - 1] != '&' &&
|
||||
#if 0
|
||||
pszString[nIndex - 1] != ' ' && pszString[nIndex - 1] != '\\' &&
|
||||
pszString[nIndex - 1] != '/' && pszString[nIndex - 1] != ':' &&
|
||||
pszString[nIndex - 1] != '\"' && pszString[nIndex - 1] != '\'' &&
|
||||
#endif
|
||||
pszString[nIndex - 1] != ';')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int nStart = strlen(pszKey) + 1;
|
||||
int nCount = strlen(pszSearch);
|
||||
int i;
|
||||
for (i = nStart; i < nCount; i++)
|
||||
{
|
||||
if (pszSearch[i] == '?' ||
|
||||
pszSearch[i] == '&' ||
|
||||
#if 0
|
||||
pszSearch[i] == ' ' || pszSearch[i] == '\\' ||
|
||||
pszSearch[i] == '/' || pszSearch[i] == ':' ||
|
||||
pszSearch[i] == '\"' || pszSearch[i] == '\'' ||
|
||||
#endif
|
||||
pszSearch[i] == ';')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nStart == i)
|
||||
{
|
||||
pszValue[0] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
strncpy(pszValue, pszSearch + nStart, i - nStart);
|
||||
pszValue[i - nStart] = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HHttpHandler::GetCookieValue(const char * pszCookie, const char * pszKeyName, char * pszValue)
|
||||
{
|
||||
*pszValue = '\0';
|
||||
|
||||
const char * pszOffset = stristr(pszCookie, pszKeyName);
|
||||
if (pszOffset == NULL)
|
||||
return false;
|
||||
|
||||
pszOffset += strlen(pszKeyName);
|
||||
|
||||
while (*pszOffset)
|
||||
{
|
||||
if (*pszOffset == '=')
|
||||
{
|
||||
pszOffset++;
|
||||
break;
|
||||
}
|
||||
else if (*pszOffset == ' ' || *pszOffset == '\t')
|
||||
;
|
||||
else if (*pszOffset == '\0')
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
pszOffset++;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (*pszOffset)
|
||||
{
|
||||
if (*pszOffset == ';' || *pszOffset == '\r' || *pszOffset == '\n' || *pszOffset == '\0')
|
||||
{
|
||||
pszValue[i] = '\0';
|
||||
return true;
|
||||
}
|
||||
else if (*pszOffset == '\t' || *pszOffset == ' ')
|
||||
;
|
||||
else
|
||||
pszValue[i++] = *pszOffset;
|
||||
|
||||
pszOffset++;
|
||||
}
|
||||
|
||||
pszValue[i] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HHttpHandler::SetCookieValue(char * pszNewCookie, const char * pszCookie, const char * pszKeyName, const char * pszValue)
|
||||
{
|
||||
*pszNewCookie = '\0';
|
||||
bool bIsSearch = false;
|
||||
const char * pFirst = NULL;
|
||||
const char * pSecond = NULL;
|
||||
|
||||
const char * pszOffset = pszCookie;
|
||||
for (;;)
|
||||
{
|
||||
pszOffset = stristr(pszOffset, pszKeyName);
|
||||
if (pszOffset == NULL)
|
||||
break;
|
||||
|
||||
if (pszOffset != pszCookie)
|
||||
{
|
||||
const char * pTemp = pszOffset - 1;
|
||||
if (*pTemp != ' ' && *pTemp != ';' && *pTemp != '\t')
|
||||
{
|
||||
pszOffset += strlen(pszKeyName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
pszOffset += strlen(pszKeyName);
|
||||
|
||||
for (; *pszOffset; pszOffset++)
|
||||
{
|
||||
if (bIsSearch == false)
|
||||
{
|
||||
if (*pszOffset == '=')
|
||||
{
|
||||
bIsSearch = true;
|
||||
pFirst = pszOffset + 1;
|
||||
}
|
||||
else if (*pszOffset != ' ' && *pszOffset != '\t' && *pszOffset != '\r' && *pszOffset != '\n')
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*pszOffset == ';')
|
||||
{
|
||||
pSecond = pszOffset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bIsSearch == true)
|
||||
break;
|
||||
}
|
||||
|
||||
if (bIsSearch == true)
|
||||
{
|
||||
int nCopySize = pFirst - pszCookie;
|
||||
strncpy(pszNewCookie, pszCookie, nCopySize);
|
||||
pszNewCookie[nCopySize] = '\0';
|
||||
strcat(pszNewCookie, pszValue);
|
||||
|
||||
if (pSecond)
|
||||
strcat(pszNewCookie, pSecond);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bAddSemiColon = true;
|
||||
|
||||
int nTotalLength = strlen(pszCookie);
|
||||
for (int i = nTotalLength; i > 0; i--)
|
||||
{
|
||||
if (pszCookie[i - 1] == ';')
|
||||
{
|
||||
bAddSemiColon = false;
|
||||
break;
|
||||
}
|
||||
else if (pszCookie[i - 1] == ' ' || pszCookie[i - 1] == '\t' ||
|
||||
pszCookie[i - 1] == '\r' || pszCookie[i - 1] == '\n')
|
||||
{
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(pszNewCookie, pszCookie);
|
||||
|
||||
if (bAddSemiColon == true)
|
||||
strcat(pszNewCookie, "; ");
|
||||
|
||||
strcat(pszNewCookie, pszKeyName);
|
||||
strcat(pszNewCookie, "=");
|
||||
strcat(pszNewCookie, pszValue);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int HHttpHandler::RemoveCookieValue(char * pszCookie, const char * pszKeyName, int nIndex)
|
||||
{
|
||||
const char * pszOffset = pszCookie;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
pszOffset = stristr(pszOffset, pszKeyName);
|
||||
if (pszOffset == NULL || pszOffset[strlen(pszKeyName)] != '=')
|
||||
return 0;
|
||||
|
||||
if (nIndex-- > 0)
|
||||
{
|
||||
pszOffset += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
char * pszFront = (char *)pszOffset;
|
||||
while (*pszOffset)
|
||||
{
|
||||
if (*pszOffset == ';' || *pszOffset == '\r' || *pszOffset == '\n' || *pszOffset == '\0')
|
||||
break;
|
||||
|
||||
pszOffset++;
|
||||
}
|
||||
|
||||
if (*pszOffset == ';')
|
||||
pszOffset++;
|
||||
|
||||
if (*pszOffset == '\r' || *pszOffset == '\n' || *pszOffset == '\0')
|
||||
{
|
||||
if (pszCookie == pszFront) // empty cookie
|
||||
{
|
||||
*pszFront = '\0';
|
||||
return 2;
|
||||
}
|
||||
|
||||
*pszFront = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (*pszOffset == ' ')
|
||||
pszOffset++;
|
||||
|
||||
char * pszTemp = (char *)malloc(strlen(pszOffset) + 1);
|
||||
strcpy(pszTemp, pszOffset);
|
||||
strcpy(pszFront, pszTemp);
|
||||
free(pszTemp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int HHttpHandler::MakeCookie(char * pszSetCookie, const char * pszKeyName,
|
||||
const char * pszKeyValue, const char * pszDomain, const char * pszPath, long nExpireMinute)
|
||||
{
|
||||
if (nExpireMinute < 0)
|
||||
{
|
||||
return sprintf(pszSetCookie, "%s=%s; expires=Thu, 01 Jan 1970 23:59:59 GMT%s%s%s%s",
|
||||
pszKeyName, pszKeyValue,
|
||||
pszDomain ? "; domain=" : "", pszDomain ? pszDomain : "",
|
||||
pszPath ? "; path=" : "", pszPath ? pszPath : "");
|
||||
}
|
||||
else if (nExpireMinute == 0)
|
||||
{
|
||||
return sprintf(pszSetCookie, "%s=%s%s%s%s%s",
|
||||
pszKeyName, pszKeyValue,
|
||||
pszDomain ? "; domain=" : "", pszDomain ? pszDomain : "",
|
||||
pszPath ? "; path=" : "", pszPath ? pszPath : "");
|
||||
}
|
||||
|
||||
char szDateTime[32];
|
||||
struct tm * tmTmp;
|
||||
timeb tTimeb;
|
||||
|
||||
ftime(&tTimeb);
|
||||
tTimeb.time += nExpireMinute;
|
||||
tmTmp = localtime(&tTimeb.time);
|
||||
strftime(szDateTime, 32, "%a, %d-%b-%Y %H:%M:%S", tmTmp);
|
||||
|
||||
return sprintf(pszSetCookie, "%s=%s; expires=%s GMT%s%s%s%s",
|
||||
pszKeyName, pszKeyValue, szDateTime,
|
||||
pszDomain ? "; domain=" : "", pszDomain ? pszDomain : "",
|
||||
pszPath ? "; path=" : "", pszPath ? pszPath : "");
|
||||
}
|
||||
|
||||
const char * HHttpHandler::EnumExtractCookie(const char * pszCookie, char ** ppName, char ** ppValue)
|
||||
{
|
||||
*ppName = NULL;
|
||||
*ppValue = NULL;
|
||||
|
||||
if (pszCookie == NULL || pszCookie[0] == '\0')
|
||||
return NULL;
|
||||
|
||||
const char * pOffset1 = strchr(pszCookie, ';');
|
||||
const char * pOffset2 = strchr(pszCookie, '=');
|
||||
if (pOffset1 == NULL && pOffset2 == NULL)
|
||||
return NULL;
|
||||
else if (pOffset2 == NULL || (pOffset1 && pOffset1 <= pOffset2 + 1))
|
||||
return pOffset1 + 1;
|
||||
|
||||
int nNameSize = pOffset2 - pszCookie;
|
||||
*ppName = (char *)malloc(nNameSize + 1);
|
||||
StrNTrimCpy(*ppName, pszCookie, nNameSize);
|
||||
|
||||
int nValueSize;
|
||||
if (pOffset1)
|
||||
nValueSize = pOffset1 - (pOffset2 + 1);
|
||||
else
|
||||
nValueSize = strlen(pOffset2 + 1);
|
||||
|
||||
*ppValue = (char *)malloc(nValueSize + 1);
|
||||
StrNTrimCpy(*ppValue, pOffset2 + 1, nValueSize);
|
||||
|
||||
if (pOffset1)
|
||||
return pOffset1 + 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int HHttpHandler::MakeResponse(char * pszResponse, const char * pszResponseType, const char * pszHtml)
|
||||
{
|
||||
HString strRear;
|
||||
if (pszHtml)
|
||||
{
|
||||
strRear = "Content-Length: ";
|
||||
strRear += strlen(pszHtml);
|
||||
strRear += "\r\n\r\n";
|
||||
strRear += pszHtml;
|
||||
}
|
||||
|
||||
size_t nSize = sprintf(pszResponse, "HTTP/1.1 %s\n"
|
||||
"Server: HUSS/2.0\r\n"
|
||||
"X-UA-Compatible: IE=Edge\r\n"
|
||||
"Content-Security-Policy: script-src 'self' 'unsafe-inline'; object-src 'self';\r\n"
|
||||
"X-Content-Type-Options: nosniff\r\n"
|
||||
"X-XSS-Protection: 1; mode=block\r\n"
|
||||
"Connection: close\r\n"
|
||||
"%s", pszResponseType, pszHtml ? strRear.psz() : "\r\n");
|
||||
|
||||
return nSize;
|
||||
}
|
||||
|
||||
int HHttpHandler::Make200Header(char * pszResponse, const char * pszContentType, unsigned long nBodySize, const char * pszAddtionalHeaders)
|
||||
{
|
||||
size_t nSize = sprintf(pszResponse, "HTTP/1.1 200 OK\r\n"
|
||||
"Server: HUSS/2.0\r\n"
|
||||
"X-UA-Compatible: IE=Edge\r\n"
|
||||
"Content-Security-Policy: script-src 'self' 'unsafe-inline'; object-src 'self';\r\n"
|
||||
"X-Content-Type-Options: nosniff\r\n"
|
||||
"X-XSS-Protection: 1; mode=block\r\n"
|
||||
"%s%s"
|
||||
"Content-Type: %s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Length: %ld\r\n"
|
||||
"\r\n", pszAddtionalHeaders && pszAddtionalHeaders[0] != '\0' ? pszAddtionalHeaders : "",
|
||||
pszAddtionalHeaders && pszAddtionalHeaders[0] != '\0' ? "\r\n" : "",
|
||||
pszContentType, nBodySize);
|
||||
|
||||
return nSize;
|
||||
}
|
||||
|
||||
int HHttpHandler::Make302Response(char * pszResponse, const char * pszLocation, const char * pszSetCookie)
|
||||
{
|
||||
size_t nSize = sprintf(pszResponse, "HTTP/1.1 302 Moved Temporarily\r\n"
|
||||
"Server: HUSS/2.0\r\n"
|
||||
"Location: %s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"%s%s%s"
|
||||
"\r\n", pszLocation, pszSetCookie ? "Set-Cookie: " : "",
|
||||
pszSetCookie ? pszSetCookie : "", pszSetCookie ? "\r\n" : "");
|
||||
|
||||
return nSize;
|
||||
}
|
||||
|
||||
int HHttpHandler::Make307Response(char * pszResponse, const char * pszLocation, const char * pszSetCookie)
|
||||
{
|
||||
size_t nSize = sprintf(pszResponse, "HTTP/1.1 307 Temporary Redirect\r\n"
|
||||
"Server: HUSS/2.0\r\n"
|
||||
"Location: %s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"%s%s%s"
|
||||
"\r\n", pszLocation, pszSetCookie ? "Set-Cookie: " : "",
|
||||
pszSetCookie ? pszSetCookie : "", pszSetCookie ? "\r\n" : "");
|
||||
|
||||
return nSize;
|
||||
}
|
||||
|
||||
void HHttpHandler::MakeRedirectBody(HString * pstrBody, const char * pszUrl)
|
||||
{
|
||||
*pstrBody = "<html><head><META HTTP-EQUIV=Refresh CONTENT=\"0; URL='";
|
||||
*pstrBody += pszUrl;
|
||||
*pstrBody += "'\"></head></html>";
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HHttpHandler::HHttpHandler()
|
||||
{
|
||||
m_pRecvStreamBuffer = new HStreamBuffer(g_nMaxHsHeaderSize + g_nSocketReceiveBlockSize);
|
||||
m_pHttpParser = NULL;
|
||||
m_nProtocolStatus = HHsParser::HP_NOT_HTTP_PACKET;
|
||||
|
||||
m_nRemainBodySize = 0;
|
||||
}
|
||||
|
||||
HHttpHandler::~HHttpHandler()
|
||||
{
|
||||
if (m_pHttpParser)
|
||||
delete m_pHttpParser;
|
||||
|
||||
delete m_pRecvStreamBuffer;
|
||||
}
|
||||
|
||||
void HHttpHandler::InitParser()
|
||||
{
|
||||
if (m_pHttpParser)
|
||||
{
|
||||
m_pRecvStreamBuffer->Reset();
|
||||
m_nProtocolStatus = HHsParser::HP_NOT_HTTP_PACKET;
|
||||
delete m_pHttpParser;
|
||||
m_pHttpParser = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void HHttpHandler::WriteStreamPacket(const char * pszDir, const char * pszPrefix)
|
||||
{
|
||||
HString strFileName = pszDir;
|
||||
strFileName += pszPrefix;
|
||||
char szDateTime[32];
|
||||
GetDateTimeNum(szDateTime);
|
||||
strFileName += szDateTime;
|
||||
|
||||
HFile file;
|
||||
if (file.Open(strFileName, HFile::FMODE_CREATE | HFile::FMODE_WRONLY) == false)
|
||||
return;
|
||||
file.Write(m_pRecvStreamBuffer->Head(), m_pRecvStreamBuffer->StoredSize());
|
||||
}
|
||||
|
||||
int HHttpHandler::OnReceivedFromTransport(const char * pData, int nSize)
|
||||
{
|
||||
//HLOGF(HLOG_WARNING, "TestLog, HttpHdler, inst = 0x%x, recv size = %d\n", this, nSize);
|
||||
//HLOGD(HLOG_WARNING, pData, 40, true);
|
||||
|
||||
if (m_nProtocolStatus == HHsParser::HP_BODY_REMAIN_PACKET)
|
||||
{
|
||||
m_nRemainBodySize -= nSize;
|
||||
|
||||
int nResult = OnReceivedBodyStream(pData, nSize);
|
||||
|
||||
if (m_nRemainBodySize <= 0)
|
||||
{
|
||||
m_pRecvStreamBuffer->Reset();
|
||||
m_nProtocolStatus = HHsParser::HP_NOT_HTTP_PACKET;
|
||||
delete m_pHttpParser;
|
||||
m_pHttpParser = NULL;
|
||||
}
|
||||
|
||||
return nResult;
|
||||
}
|
||||
else if (m_nProtocolStatus == HHsParser::HP_BODYSIZE_UNKNOWN_PACKET)
|
||||
{
|
||||
return OnReceivedBodyStream(pData, nSize);
|
||||
}
|
||||
|
||||
if (m_pRecvStreamBuffer->Store(pData, nSize) == false)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], HttpHdler, Failed to insert data, inst = 0x%x, buffer = %d, stored = %d, recv size = %d\n", this, m_pRecvStreamBuffer->Size(), m_pRecvStreamBuffer->StoredSize(), nSize);
|
||||
return -1; // disconnect
|
||||
}
|
||||
|
||||
// simply verify header
|
||||
if (isalnum(m_pRecvStreamBuffer->Head()[0]) == 0)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], HttpHdler, Invalid http protocol 1, inst = 0x%x, buffer = %d, stored = %d, recv size = %d\n", this, m_pRecvStreamBuffer->Size(), m_pRecvStreamBuffer->StoredSize(), nSize);
|
||||
HLOGD(HLOG_WARNING, m_pRecvStreamBuffer->Head(), 20, false);
|
||||
return -1; // disconnect
|
||||
}
|
||||
|
||||
m_pRecvStreamBuffer->Head()[m_pRecvStreamBuffer->StoredSize()] = '\0'; // for using string operation
|
||||
|
||||
char * pszBodyPtr = HHsParser::SearchBodyPtr((char *)pData, nSize); //... search "\r\n\r\n" or "\n\n"
|
||||
if (pszBodyPtr == NULL)
|
||||
return 0; // continue received (remain header)
|
||||
|
||||
m_pHttpParser = new HHsParser("HTTP");
|
||||
m_nProtocolStatus = m_pHttpParser->Parse(m_pRecvStreamBuffer->Head(), m_pRecvStreamBuffer->StoredSize());
|
||||
|
||||
if (m_nProtocolStatus == HHsParser::HP_NOT_HTTP_PACKET ||
|
||||
m_nProtocolStatus == HHsParser::HP_PARAMETER_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], HttpHdler, Invalid http protocol 2, inst = 0x%x, buffer = %d, stored = %d, recv size = %d\n", this, m_pRecvStreamBuffer->Size(), m_pRecvStreamBuffer->StoredSize(), nSize);
|
||||
HLOGD(HLOG_WARNING, m_pRecvStreamBuffer->Head(), 20, false);
|
||||
return -1; // disconnect
|
||||
}
|
||||
else if (m_nProtocolStatus == HHsParser::HP_BODY_REMAIN_PACKET)
|
||||
{
|
||||
m_nRemainBodySize = m_pHttpParser->GetContentLength() - m_pHttpParser->GetBodySize();
|
||||
return OnPacketProcessing(m_pHttpParser->GetBodyPtr(), m_pHttpParser->GetBodySize());
|
||||
}
|
||||
else if (m_nProtocolStatus == HHsParser::HP_BODYSIZE_UNKNOWN_PACKET)
|
||||
{
|
||||
return OnPacketProcessing(m_pHttpParser->GetBodyPtr(), m_pHttpParser->GetBodySize());
|
||||
}
|
||||
else if (m_nProtocolStatus == HHsParser::HP_COMPLETE_PACKET)
|
||||
{
|
||||
int nResult = OnPacketProcessing(m_pHttpParser->GetBodyPtr(), m_pHttpParser->GetBodySize());
|
||||
|
||||
m_pRecvStreamBuffer->Reset();
|
||||
m_nProtocolStatus = HHsParser::HP_NOT_HTTP_PACKET;
|
||||
delete m_pHttpParser;
|
||||
m_pHttpParser = NULL;
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef HTTP_HANDLER__H
|
||||
#define HTTP_HANDLER__H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#define ON_HTTP_REQUEST(RURI, FN) if (HHttpHandler::UriCmp(m_pHttpParser->GetRequestUri(), RURI)) { return FN(pBodyData, nBodySize); }
|
||||
|
||||
|
||||
class HHttpHandler : public HProtocolHandler
|
||||
{
|
||||
public:
|
||||
static bool UriCmp(const char * pszRequestUri, const char * pszPrefix);
|
||||
static bool GetParamValue(const char * pszString, const char * pszKey, char * pszValue);
|
||||
|
||||
static bool GetCookieValue(const char * pszCookie, const char * pszKeyName, char * pszValue);
|
||||
static bool SetCookieValue(char * pszNewCookie, const char * pszCookie, const char * pszKeyName, const char * pszValue);
|
||||
static int RemoveCookieValue(char * pszCookie, const char * pszKeyName, int nIndex = 0); // return 0 : not found key, 1 : delete, 2 : delete and empty cookie string
|
||||
static int MakeCookie(char * pszSetCookie, const char * pszKeyName, const char * pszKeyValue, const char * pszDomain, const char * pszPath, long nExpireMinute = 0); // nExpireMinute = -1 : delete, 0 : not set expire, (86400 * 10) : 10 days
|
||||
static const char * EnumExtractCookie(const char * pszCookie, char ** ppName, char ** ppValue);
|
||||
|
||||
static int MakeResponse(char * pszResponse, const char * pszResponseType, const char * pszHtml);
|
||||
static int Make200Header(char * pszResponse, const char * pszContentType, unsigned long nBodySize, const char * pszAddtionalHeaders = NULL);
|
||||
static int Make302Response(char * pszResponse, const char * pszLocation, const char * pszSetCookie = NULL);
|
||||
static int Make307Response(char * pszResponse, const char * pszLocation, const char * pszSetCookie = NULL);
|
||||
|
||||
static void MakeRedirectBody(HString * pstrBody, const char * pszUrl);
|
||||
//
|
||||
|
||||
HHttpHandler();
|
||||
~HHttpHandler();
|
||||
|
||||
protected:
|
||||
void InitParser();
|
||||
|
||||
void WriteStreamPacket(const char * pszDir, const char * pszPrefix);
|
||||
|
||||
virtual void OnReceivedStatusFromTransport(int nStatus) {}
|
||||
|
||||
bool OnPrepareReceive() { return true; }
|
||||
virtual int OnReceivedFromTransport(const char * pData, int nSize);
|
||||
|
||||
virtual int OnPacketProcessing(const char * pBodyData, int nBodySize) { return -1; }
|
||||
virtual int OnReceivedBodyStream(const char * pData, int nSize) { return -1; }
|
||||
|
||||
protected:
|
||||
HHsParser * m_pHttpParser;
|
||||
int m_nProtocolStatus;
|
||||
|
||||
long m_nRemainBodySize;
|
||||
|
||||
private:
|
||||
HStreamBuffer * m_pRecvStreamBuffer;
|
||||
};
|
||||
|
||||
#endif // HTTP_HANDLER__H
|
||||
@@ -0,0 +1,111 @@
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "huslib/huslib.h"
|
||||
#include "huslib/huslibex.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <crtdbg.h>
|
||||
#endif // _DEBUG
|
||||
|
||||
#include "windows/WinService.h"
|
||||
|
||||
#define WRITE_MINI_DUMP
|
||||
#if defined(_WIN32) && !defined(_DEBUG) && defined(WRITE_MINI_DUMP)
|
||||
#include "windows/DebugAssist.h"
|
||||
#endif // WRITE_MINI_DUMP
|
||||
|
||||
#else
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#include <stdio.h>
|
||||
#include "Object.h"
|
||||
#include "HusApp.h"
|
||||
|
||||
|
||||
|
||||
HApp * HApp::m_pApp = NULL;
|
||||
|
||||
|
||||
HApp::HApp()
|
||||
{
|
||||
m_pApp = this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define TIMEOUT_SERVICE_START_PENDING 5000
|
||||
|
||||
|
||||
VOID ServiceStart(DWORD nArgc, LPTSTR *pArgv, BOOL bConsoleMode)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_DEBUG)
|
||||
InitialDumpWriting(); // for Windows Dump File
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
|
||||
#endif // _DEBUG
|
||||
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
if (WSAStartup(wVersionRequested, &wsaData) != 0)
|
||||
{
|
||||
printf("[ERROR] Windows sockets initialization failed. WSAGetLastError = %d\n", WSAGetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
|
||||
{
|
||||
printf("[ERROR] Could not find a usable WinSock DLL.\n");
|
||||
WSACleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, TIMEOUT_SERVICE_START_PENDING))
|
||||
return;
|
||||
|
||||
if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
|
||||
return;
|
||||
|
||||
HApp::m_pApp->OnMain(nArgc, pArgv);
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
VOID ServiceStop()
|
||||
{
|
||||
HApp::m_pApp->OnExit(0);
|
||||
|
||||
if (!ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, TIMEOUT_SERVICE_START_PENDING))
|
||||
return;
|
||||
|
||||
if (!ReportStatusToSCMgr(SERVICE_STOPPED, NO_ERROR, 0))
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
int main(int nArgc, char ** pArgv)
|
||||
{
|
||||
if (HApp::m_pApp == NULL)
|
||||
{
|
||||
printf("ERROR: Can't find an object that derives from HApp.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
WinServiceMain(nArgc, pArgv);
|
||||
return 0;
|
||||
#else
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif // _WIN32
|
||||
|
||||
return HApp::m_pApp->OnMain(nArgc, pArgv);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef APP__H_
|
||||
#define APP__H_
|
||||
|
||||
|
||||
class HApp : public HObject
|
||||
{
|
||||
public:
|
||||
static HApp * m_pApp;
|
||||
//
|
||||
|
||||
HApp();
|
||||
virtual ~HApp() {}
|
||||
|
||||
virtual int OnMain(int nArgc, char ** pArgv) = 0;
|
||||
virtual void OnExit(int nCode) = 0;
|
||||
};
|
||||
|
||||
#define APPINIT(APP_CLASS_NAME) APP_CLASS_NAME __g_main$Application$Instance_;
|
||||
#define HAPP() (&__g_main$Application$Instance_)
|
||||
|
||||
#endif // APP__H_
|
||||
@@ -0,0 +1,535 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "Object.h"
|
||||
#include "Thread.h"
|
||||
#include "Timer.h"
|
||||
#include "Logger.h"
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
//#include <io.h>
|
||||
//#pragma warning(disable:4201)
|
||||
//#include <mmsystem.h>
|
||||
//#pragma warning(default:4201)
|
||||
//#pragma comment(lib, "winmm.lib")
|
||||
#include <time.h>
|
||||
#else
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
|
||||
|
||||
// my defines for portablity
|
||||
#ifdef _WIN32
|
||||
|
||||
#define ftime _ftime
|
||||
#define timeb _timeb
|
||||
#define vsnprintf _vsnprintf
|
||||
#define snprintf _snprintf
|
||||
|
||||
#define FILECRETEFAIL_CAPTION "HLogger Message"
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#ifdef SINGLE_THREADED_MODEL
|
||||
#if _MSC_VER <= 1200
|
||||
#define Lock() ((void)0)
|
||||
#define Unlock() ((void)0)
|
||||
#else
|
||||
#define Lock() __noop
|
||||
#define Unlock() __noop
|
||||
#endif
|
||||
#endif // SINGLE_THREADED_MODEL
|
||||
|
||||
|
||||
|
||||
HLogger * g_pLogFile__Logger = NULL;
|
||||
|
||||
|
||||
HLogger::HLogger()
|
||||
{
|
||||
m_fhLog = -1;
|
||||
m_nLevel = 0;
|
||||
m_flagOption = dayWrite | timeWrite;
|
||||
m_bIsContinue = false;
|
||||
m_nFileSplitSize = 0;
|
||||
m_nFileLimitSize = 0;
|
||||
m_nLogFileNameExt = 0;
|
||||
m_bIsFileNameChange = false;
|
||||
m_nSrcLine = 0;
|
||||
m_szPathName[0] = '\0';
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
#ifdef _WIN32
|
||||
InitializeCriticalSection(&m_csInstance);
|
||||
#else
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
#endif // _WIN32
|
||||
#endif // SINGLE_THREADED_MODEL
|
||||
|
||||
m_pExtension = NULL;
|
||||
|
||||
m_szWriteString = (char *)malloc(MD_MAX_STRING);
|
||||
m_szLogString = (char *)malloc(MD_MAX_STRING);
|
||||
m_szTmpString = (char *)malloc(MD_MAX_STRING);
|
||||
}
|
||||
|
||||
HLogger::~HLogger()
|
||||
{
|
||||
free(m_szWriteString);
|
||||
free(m_szLogString);
|
||||
free(m_szTmpString);
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
#ifdef _WIN32
|
||||
DeleteCriticalSection(&m_csInstance);
|
||||
#else
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
#endif // _WIN32
|
||||
#endif // SINGLE_THREADED_MODEL
|
||||
}
|
||||
|
||||
bool HLogger::Create(unsigned nLevel, bool bContinue,
|
||||
const char * szPathName, bool bIsBinary)
|
||||
{
|
||||
Lock();
|
||||
|
||||
m_bIsContinue = bContinue;
|
||||
m_bIsBinary = bIsBinary;
|
||||
bool bSuccess = OpenFile(nLevel, szPathName);
|
||||
|
||||
Unlock();
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
void HLogger::Release()
|
||||
{
|
||||
Lock();
|
||||
|
||||
CloseFile();
|
||||
|
||||
m_nFileSplitSize = 0;
|
||||
m_nFileLimitSize = 0;
|
||||
m_nLogFileNameExt = 0;
|
||||
m_bIsFileNameChange = false;
|
||||
|
||||
if (m_pExtension)
|
||||
{
|
||||
delete m_pExtension;
|
||||
m_pExtension = NULL;
|
||||
}
|
||||
|
||||
Unlock();
|
||||
}
|
||||
|
||||
bool HLogger::OpenFile(unsigned nLevel, const char * szPathName)
|
||||
{
|
||||
if (m_fhLog != -1) return false;
|
||||
|
||||
m_nLevel = nLevel;
|
||||
|
||||
if (szPathName != NULL && !(szPathName[strlen(szPathName) - 1] == '/' ||
|
||||
szPathName[strlen(szPathName) - 1] == '\\'))
|
||||
{
|
||||
// Full Path Name ==> equal.
|
||||
if (m_szPathName[0] == '\0')
|
||||
{
|
||||
strncpy(m_szPathName, szPathName, MD_MAX_PATH - 1);
|
||||
m_szPathName[MD_MAX_PATH - 1] = '\0';
|
||||
}
|
||||
|
||||
strncpy(m_szLogFileName, szPathName, MD_MAX_PATH - 1);
|
||||
m_szLogFileName[MD_MAX_PATH - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bIsFileNameChange = true;
|
||||
|
||||
// Directory ==> log name is date. ex) Start("log/") = log/20030201.log
|
||||
if (szPathName != NULL && m_szPathName[0] == '\0')
|
||||
{
|
||||
strncpy(m_szPathName, szPathName, MD_MAX_PATH - 1);
|
||||
m_szPathName[MD_MAX_PATH - 1] = '\0';
|
||||
}
|
||||
|
||||
char szDay[MD_MAX_DATE];
|
||||
|
||||
GetDateTime(szDay, NULL);
|
||||
sprintf(m_szLogFileName, "%s%s.log", m_szPathName, szDay);
|
||||
|
||||
strncpy(m_szPrevDate, szDay, MD_MAX_DATE - 1);
|
||||
m_szPrevDate[MD_MAX_DATE - 1] = '\0';
|
||||
|
||||
//#ifdef _WIN32
|
||||
// CreateDirectory(m_szPathName, NULL);
|
||||
//#else
|
||||
// mkdir(m_szPathName, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
//#endif
|
||||
}
|
||||
|
||||
int oflag = O_CREAT | O_RDWR;
|
||||
|
||||
if (m_bIsContinue == false)
|
||||
oflag |= O_TRUNC;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (m_bIsBinary)
|
||||
oflag |= O_BINARY;
|
||||
else
|
||||
oflag |= O_TEXT;
|
||||
|
||||
m_fhLog = open(m_szLogFileName, oflag, S_IREAD | S_IWRITE);
|
||||
#else
|
||||
m_fhLog = open(m_szLogFileName, oflag, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH);
|
||||
#endif
|
||||
|
||||
if (m_fhLog == -1)
|
||||
{
|
||||
char szMessage[MD_MAX_PATH + 32];
|
||||
sprintf(szMessage, "[ERROR], Failed to create log file, [%s]\n", m_szLogFileName);
|
||||
|
||||
#ifdef _WIN32
|
||||
MessageBoxA(HWND_TOP, szMessage, FILECRETEFAIL_CAPTION, MB_OK | MB_ICONERROR);
|
||||
#else
|
||||
printf(szMessage);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_bIsContinue)
|
||||
lseek(m_fhLog, 0L, SEEK_END);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HLogger::CloseFile()
|
||||
{
|
||||
if (m_fhLog == -1) return;
|
||||
|
||||
if (m_nFileLimitSize > 0)
|
||||
{
|
||||
const char * pszEndTxt = "--------------------------------\nEnd of log writing.\n--------------------------------\n\n";
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable:4267)
|
||||
#endif
|
||||
write(m_fhLog, pszEndTxt, strlen(pszEndTxt));
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(default:4267)
|
||||
#endif
|
||||
}
|
||||
|
||||
close(m_fhLog);
|
||||
m_fhLog = -1;
|
||||
}
|
||||
|
||||
void HLogger::GetDateTime(char * szDate, char * szTime)
|
||||
{
|
||||
SYSTEMTIME systemTime;
|
||||
HTIMER()->GetSystemTime(&systemTime);
|
||||
|
||||
if (szDate != NULL)
|
||||
sprintf(szDate, "%.4ld%.2ld%.2ld", systemTime.wYear, systemTime.wMonth, systemTime.wDay);
|
||||
|
||||
if (szTime != NULL)
|
||||
sprintf(szTime, "%.2ld:%.2ld:%.2ld.%.3ld", systemTime.wHour, systemTime.wMinute, systemTime.wSecond,
|
||||
systemTime.wMilliseconds);
|
||||
}
|
||||
|
||||
void HLogger::Write(int nLevel, const char * pszLog)
|
||||
{
|
||||
Lock();
|
||||
|
||||
if (m_fhLog == -1 || nLevel > m_nLevel ||
|
||||
((m_flagOption & onlyLevel) == onlyLevel && m_nLevel != nLevel))
|
||||
{
|
||||
Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
char * pszSwap = m_szLogString;
|
||||
m_szLogString = (char *)pszLog;
|
||||
|
||||
m_nLogLength = (int)strlen(pszLog);
|
||||
|
||||
WriteLog(false);
|
||||
m_szLogString = pszSwap;
|
||||
|
||||
Unlock();
|
||||
}
|
||||
|
||||
void HLogger::Dump(int nLevel, const char * pszLog, size_t nSize, bool bWithHex)
|
||||
{
|
||||
Lock();
|
||||
|
||||
if (m_fhLog == -1 || nLevel > m_nLevel ||
|
||||
((m_flagOption & onlyLevel) == onlyLevel && m_nLevel != nLevel))
|
||||
{
|
||||
Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (nSize > MD_MAX_STRING - 3)
|
||||
nSize = MD_MAX_STRING - 3;
|
||||
|
||||
strncpy(m_szLogString, pszLog, nSize);
|
||||
m_szLogString[nSize] = '\0';
|
||||
m_nLogLength = (int)nSize;
|
||||
|
||||
if (bWithHex)
|
||||
{
|
||||
char * pszTemp = m_szLogString + nSize;
|
||||
pszTemp[0] = '\n';
|
||||
|
||||
const char HEX[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
char cByte;
|
||||
unsigned i = 0, j = 1;
|
||||
for (; i < nSize; i++)
|
||||
{
|
||||
cByte = pszLog[i];
|
||||
|
||||
pszTemp[j++] = HEX[(cByte & 0xF0) >> 4];
|
||||
pszTemp[j++] = HEX[(cByte & 0x0F) >> 0];
|
||||
pszTemp[j++] = ' ';
|
||||
}
|
||||
|
||||
m_nLogLength += j;
|
||||
}
|
||||
|
||||
m_szLogString[m_nLogLength] = '\n';
|
||||
m_szLogString[m_nLogLength + 1] = '\0';
|
||||
m_nLogLength += 1;
|
||||
|
||||
WriteLog(false);
|
||||
|
||||
Unlock();
|
||||
}
|
||||
|
||||
void HLogger::Format(int nLevel, const char *fmt, ...)
|
||||
{
|
||||
Lock();
|
||||
|
||||
if (m_fhLog == -1 || nLevel > m_nLevel ||
|
||||
((m_flagOption & onlyLevel) == onlyLevel && m_nLevel != nLevel))
|
||||
{
|
||||
Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
va_list vaList;
|
||||
va_start(vaList, fmt);
|
||||
|
||||
m_nLogLength = vsnprintf(m_szLogString, MD_MAX_STRING - 1, fmt, vaList);
|
||||
if (m_nLogLength < 0 || m_nLogLength >= MD_MAX_STRING)
|
||||
{
|
||||
m_nLogLength = MD_MAX_STRING;
|
||||
m_szLogString[MD_MAX_STRING - 1] = '\0';
|
||||
}
|
||||
|
||||
va_end(vaList);
|
||||
|
||||
WriteLog(false);
|
||||
|
||||
Unlock();
|
||||
}
|
||||
|
||||
void HLogger::Trace(const char * szSrcFileName, const unsigned nSrcLine, int nLevel, const char *fmt, ...)
|
||||
{
|
||||
Lock();
|
||||
|
||||
if (m_fhLog == -1 || nLevel > m_nLevel ||
|
||||
((m_flagOption & onlyLevel) == onlyLevel && m_nLevel != nLevel))
|
||||
{
|
||||
Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// remove path name
|
||||
const char * pPos = strrchr(szSrcFileName, '\\');
|
||||
|
||||
if (pPos == NULL)
|
||||
pPos = strrchr(szSrcFileName, '/');
|
||||
|
||||
if (pPos != NULL)
|
||||
{
|
||||
strncpy(m_szSrcFileName, ++pPos, MD_MAX_PATH);
|
||||
m_szSrcFileName[MD_MAX_PATH - 1] = '\0';
|
||||
}
|
||||
else
|
||||
#endif // _WIN32
|
||||
strncpy(m_szSrcFileName, szSrcFileName, MD_MAX_PATH - 1);
|
||||
m_szSrcFileName[MD_MAX_PATH - 1] = '\0';
|
||||
m_nSrcLine = nSrcLine;
|
||||
|
||||
|
||||
va_list vaList;
|
||||
va_start(vaList, fmt);
|
||||
|
||||
m_nLogLength = vsnprintf(m_szLogString, MD_MAX_STRING - 1, fmt, vaList);
|
||||
if (m_nLogLength < 0 || m_nLogLength >= MD_MAX_STRING)
|
||||
{
|
||||
m_nLogLength = MD_MAX_STRING;
|
||||
m_szLogString[MD_MAX_STRING - 1] = '\0';
|
||||
}
|
||||
|
||||
va_end(vaList);
|
||||
|
||||
WriteLog(true);
|
||||
|
||||
Unlock();
|
||||
}
|
||||
|
||||
void HLogger::SetSrcInfoWithLock(const char * szSrcFileName, const unsigned nSrcLine)
|
||||
{
|
||||
Lock();
|
||||
|
||||
#ifdef _WIN32
|
||||
// remove path name
|
||||
const char * pPos = strrchr(szSrcFileName, '\\');
|
||||
|
||||
if (pPos == NULL)
|
||||
pPos = strrchr(szSrcFileName, '/');
|
||||
|
||||
if (pPos != NULL)
|
||||
{
|
||||
strncpy(m_szSrcFileName, ++pPos, MD_MAX_PATH);
|
||||
m_szSrcFileName[MD_MAX_PATH - 1] = '\0';
|
||||
}
|
||||
else
|
||||
#endif // _WIN32
|
||||
strncpy(m_szSrcFileName, szSrcFileName, MD_MAX_PATH - 1);
|
||||
m_szSrcFileName[MD_MAX_PATH - 1] = '\0';
|
||||
m_nSrcLine = nSrcLine;
|
||||
}
|
||||
|
||||
void HLogger::TraceWithUnlock(int nLevel)
|
||||
{
|
||||
if (m_fhLog == -1 || nLevel > m_nLevel ||
|
||||
((m_flagOption & onlyLevel) == onlyLevel && m_nLevel != nLevel))
|
||||
{
|
||||
Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
WriteLog(true);
|
||||
|
||||
Unlock();
|
||||
}
|
||||
|
||||
inline void HLogger::WriteLog(const bool bIsTrace)
|
||||
{
|
||||
m_szWriteString[0] = '\0';
|
||||
m_nWriteLength = 0;
|
||||
|
||||
if (m_bIsFileNameChange)
|
||||
{
|
||||
char szDate[MD_MAX_DATE];
|
||||
|
||||
GetDateTime(szDate, NULL);
|
||||
if (strcmp(m_szPrevDate, szDate) != 0)
|
||||
{
|
||||
CloseFile();
|
||||
OpenFile(m_nLevel, NULL);
|
||||
m_nLogFileNameExt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_nFileSplitSize > 0 && m_nFileSplitSize <= lseek(m_fhLog, 0L, SEEK_CUR))
|
||||
{
|
||||
// file split : filename.001, filename.002, ...
|
||||
char szLogFileName[MD_MAX_PATH], szFileName[MD_MAX_PATH];
|
||||
char * pRear;
|
||||
|
||||
pRear = strrchr(m_szLogFileName, '.');
|
||||
strncpy(szFileName, m_szLogFileName, pRear - m_szLogFileName);
|
||||
szFileName[pRear - m_szLogFileName] = '\0';
|
||||
sprintf(szLogFileName, "%s.%.3d", szFileName, ++m_nLogFileNameExt);
|
||||
|
||||
CloseFile();
|
||||
OpenFile(m_nLevel, szLogFileName);
|
||||
}
|
||||
|
||||
if ((m_flagOption & dayWrite) == dayWrite)
|
||||
{
|
||||
GetDateTime(m_szWriteString, NULL);
|
||||
m_szWriteString[8] = ' ';
|
||||
m_szWriteString[9] = '\0';
|
||||
m_nWriteLength += 9;
|
||||
}
|
||||
|
||||
if ((m_flagOption & timeWrite) == timeWrite)
|
||||
{
|
||||
GetDateTime(NULL, m_szTmpString);
|
||||
memcpy(m_szWriteString + m_nWriteLength, m_szTmpString, 12);
|
||||
m_szWriteString[m_nWriteLength + 12] = '\t';
|
||||
m_szWriteString[m_nWriteLength + 13] = '\0';
|
||||
m_nWriteLength += 13;
|
||||
}
|
||||
|
||||
if (bIsTrace)
|
||||
{
|
||||
m_nTracePathLength = sprintf(m_szTracePathName, "%s(%d)", m_szSrcFileName, m_nSrcLine);
|
||||
|
||||
if (m_nTracePathLength < 26)
|
||||
m_nTracePathLength = sprintf(m_szTmpString, "%25s\t", m_szTracePathName);
|
||||
else if (m_nTracePathLength < 32)
|
||||
m_nTracePathLength = sprintf(m_szTmpString, "%31s\t", m_szTracePathName);
|
||||
else if (m_nTracePathLength < 38)
|
||||
m_nTracePathLength = sprintf(m_szTmpString, "%37s\t", m_szTracePathName);
|
||||
else
|
||||
m_nTracePathLength = sprintf(m_szTmpString, "%43s\t", m_szTracePathName);
|
||||
|
||||
memcpy(m_szWriteString + m_nWriteLength, m_szTmpString, m_nTracePathLength + 1);
|
||||
m_nWriteLength += m_nTracePathLength;
|
||||
}
|
||||
|
||||
if (m_nLogLength + m_nWriteLength > MD_MAX_STRING - 1)
|
||||
m_nLogLength = MD_MAX_STRING - m_nWriteLength - 1;
|
||||
|
||||
memcpy(m_szWriteString + m_nWriteLength, m_szLogString, m_nLogLength);
|
||||
m_nWriteLength += m_nLogLength;
|
||||
|
||||
if (m_nWriteLength >= MD_MAX_STRING - 1 || (m_flagOption & autoNewLine) == autoNewLine)
|
||||
{
|
||||
if (m_nWriteLength >= MD_MAX_STRING - 1)
|
||||
m_nWriteLength--;
|
||||
|
||||
m_szWriteString[m_nWriteLength++] = '\n';
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable:4267)
|
||||
#endif
|
||||
if (m_nFileLimitSize > 0 && m_nFileLimitSize <= lseek(m_fhLog, 0L, SEEK_CUR))
|
||||
{
|
||||
const static char * pszFirstTxt = "Log writing was contiued from file end. See date and time of end line.\n--------------------------------\n";
|
||||
|
||||
#ifdef _WIN32
|
||||
_chsize(m_fhLog, m_nFileLimitSize / 4);
|
||||
#else
|
||||
ftruncate(m_fhLog, m_nFileLimitSize / 4);
|
||||
#endif
|
||||
|
||||
lseek(m_fhLog, 0L, SEEK_SET);
|
||||
write(m_fhLog, pszFirstTxt, strlen(pszFirstTxt));
|
||||
}
|
||||
|
||||
OnWrite(m_szWriteString, m_nWriteLength);
|
||||
|
||||
if ((m_flagOption & consoleWrite) == consoleWrite)
|
||||
fwrite(m_szWriteString, sizeof(char), m_nWriteLength, stdout);
|
||||
|
||||
//#ifdef _WIN32
|
||||
//#pragma warning(default:4267)
|
||||
// _commit(m_fhLog);
|
||||
//#endif
|
||||
|
||||
if (m_pExtension)
|
||||
m_pExtension->OnWrite(m_szWriteString, m_nWriteLength);
|
||||
}
|
||||
@@ -0,0 +1,389 @@
|
||||
#ifndef LOGGER__H_
|
||||
#define LOGGER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#pragma once
|
||||
|
||||
//#pragma warning(disable:4710)
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
#include <io.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
#else
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
|
||||
class HLoggerExtension
|
||||
{
|
||||
public:
|
||||
HLoggerExtension() {}
|
||||
virtual ~HLoggerExtension() {}
|
||||
|
||||
protected:
|
||||
virtual void OnWrite(const char * pszText, unsigned nLength) = 0;
|
||||
|
||||
friend class HLogger;
|
||||
};
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
class HLogger
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
MD_MAX_STRING = 1024, // max one-line log length
|
||||
MD_MAX_PATH = 1024, // max path name length
|
||||
MD_MAX_DATE = 16, // max date string length
|
||||
MIN_LIMIT_SIZE = 4096
|
||||
};
|
||||
|
||||
enum Options
|
||||
{
|
||||
dayWrite = 0x0001, // add day : default
|
||||
timeWrite = 0x0002, // add time : default
|
||||
autoNewLine = 0x0004, // ...
|
||||
onlyLevel = 0x0008,
|
||||
consoleWrite = 0x0010
|
||||
};
|
||||
|
||||
HLogger();
|
||||
virtual ~HLogger();
|
||||
|
||||
bool Create(unsigned nLevel, bool bContinue, const char * szPathName = NULL, bool bIsBinary = false);
|
||||
// nLevel : max write level
|
||||
// bContinue : true is contiue writing to exist log file.
|
||||
// szPathName : NULL ==> log name is date. ex) 20030201.log
|
||||
// szPathName : Directory ==> log name is date. ex) Create("log/") = log/20030201.log
|
||||
// szPathName : full path name or file name ==> equal.
|
||||
|
||||
void Release(); // for log file close.
|
||||
|
||||
inline int GetLevel();
|
||||
inline void SetLevel(unsigned nLevel);
|
||||
inline int GetOption();
|
||||
inline void SetOption(int flagOption);
|
||||
inline void SetFileSplitSize(off_t nFileSize);
|
||||
inline off_t GetFileSplitSize();
|
||||
inline off_t GetFileLimitSize();
|
||||
inline void SetFileLimitSize(off_t nFileSize);
|
||||
inline void SetExtension(HLoggerExtension * pExtension); // auto delete instance
|
||||
|
||||
void Write(int nLevel, const char * pszLog);
|
||||
void Dump(int nLevel, const char * pszLog, size_t nSize, bool bWithHex);
|
||||
void Format(int nLevel, const char * fmt, ...);
|
||||
void Trace(const char * szSrcFileName, const unsigned nSrcLine, int nLevel, const char *fmt, ...);
|
||||
|
||||
protected:
|
||||
inline char * GetLogStringBuffer();
|
||||
inline void SetLogStringBuffer(const char * pszLog);
|
||||
|
||||
bool OpenFile(unsigned nLevel, const char * szPathName);
|
||||
void CloseFile();
|
||||
|
||||
void GetDateTime(char *szDate, char *szTime);
|
||||
void WriteLog(const bool bIsTrace);
|
||||
|
||||
virtual inline void OnWrite(const char * pszText, unsigned nLength);
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
inline void Lock();
|
||||
inline void Unlock();
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Two pair fuctions for source file name and line
|
||||
// Must be called pair.
|
||||
void SetSrcInfoWithLock(const char * szSrcFileName, const unsigned nSrcLine);
|
||||
void TraceWithUnlock(int nLevel);
|
||||
|
||||
friend void __Logger_Format(int nLevel, const char *fmt, ...);
|
||||
friend void __Logger_SetSrcInfoWithLock(const char * szSrcFileName, const unsigned nSrcLine);
|
||||
friend void __Logger_TraceWithUnlock(int nLevel, const char *fmt, ...);
|
||||
|
||||
public:
|
||||
int m_nLogLength;
|
||||
|
||||
private:
|
||||
char * m_szWriteString;
|
||||
char * m_szLogString;
|
||||
char * m_szTmpString;
|
||||
|
||||
int m_fhLog;
|
||||
int m_nLevel;
|
||||
int m_flagOption;
|
||||
bool m_bIsContinue;
|
||||
bool m_bIsBinary;
|
||||
off_t m_nFileSplitSize; // bytes
|
||||
off_t m_nFileLimitSize; // bytes
|
||||
char m_szPathName[MD_MAX_PATH];
|
||||
char m_szLogFileName[MD_MAX_PATH];
|
||||
unsigned m_nLogFileNameExt;
|
||||
bool m_bIsFileNameChange;
|
||||
char m_szPrevDate[MD_MAX_DATE];
|
||||
char m_szSrcFileName[MD_MAX_PATH];
|
||||
unsigned m_nSrcLine;
|
||||
|
||||
int m_nWriteLength;
|
||||
|
||||
#ifdef _WIN32
|
||||
struct _timeb m_tTimeb;
|
||||
#else
|
||||
struct timeb m_tTimeb;
|
||||
#endif
|
||||
|
||||
char m_szMiliSec[8];
|
||||
char m_szTracePathName[MD_MAX_PATH];
|
||||
int m_nTracePathLength;
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
#ifdef _WIN32
|
||||
CRITICAL_SECTION m_csInstance;
|
||||
#else
|
||||
pthread_mutex_t m_mutex;
|
||||
#endif // _WIN32
|
||||
#endif // SINGLE_THREADED_MODEL
|
||||
|
||||
HLoggerExtension * m_pExtension;
|
||||
};
|
||||
|
||||
inline int HLogger::GetLevel()
|
||||
{
|
||||
return m_nLevel;
|
||||
}
|
||||
inline void HLogger::SetLevel(unsigned nLevel)
|
||||
{
|
||||
m_nLevel = nLevel;
|
||||
}
|
||||
inline int HLogger::GetOption()
|
||||
{
|
||||
return m_flagOption;
|
||||
}
|
||||
inline void HLogger::SetOption(int flagOption)
|
||||
{
|
||||
m_flagOption = flagOption;
|
||||
}
|
||||
inline void HLogger::SetFileSplitSize(off_t nFileSize)
|
||||
{
|
||||
m_nFileSplitSize = nFileSize;
|
||||
}
|
||||
inline off_t HLogger::GetFileSplitSize()
|
||||
{
|
||||
return m_nFileSplitSize;
|
||||
}
|
||||
inline off_t HLogger::GetFileLimitSize()
|
||||
{
|
||||
return m_nFileLimitSize;
|
||||
}
|
||||
inline void HLogger::SetFileLimitSize(off_t nFileSize)
|
||||
{
|
||||
if (nFileSize < MIN_LIMIT_SIZE)
|
||||
m_nFileLimitSize = MIN_LIMIT_SIZE;
|
||||
else
|
||||
m_nFileLimitSize = nFileSize;
|
||||
}
|
||||
inline char * HLogger::GetLogStringBuffer()
|
||||
{
|
||||
return m_szLogString;
|
||||
}
|
||||
inline void HLogger::SetLogStringBuffer(const char * pszLog)
|
||||
{
|
||||
m_szLogString = (char *)pszLog;
|
||||
}
|
||||
inline void HLogger::OnWrite(const char * pszText, unsigned nLength)
|
||||
{
|
||||
write(m_fhLog, pszText, nLength);
|
||||
}
|
||||
inline void HLogger::SetExtension(HLoggerExtension * pExtension)
|
||||
{
|
||||
if (m_pExtension)
|
||||
delete m_pExtension;
|
||||
|
||||
m_pExtension = pExtension;
|
||||
}
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
inline void HLogger::Lock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
EnterCriticalSection(&m_csInstance);
|
||||
#else
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
#endif
|
||||
}
|
||||
inline void HLogger::Unlock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
LeaveCriticalSection(&m_csInstance);
|
||||
#else
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif
|
||||
}
|
||||
#endif // SINGLE_THREADED_MODEL
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
extern HLogger * g_pLogFile__Logger;
|
||||
|
||||
|
||||
extern inline int __Logger_GetLevel()
|
||||
{
|
||||
if (g_pLogFile__Logger == NULL)
|
||||
return 0;
|
||||
|
||||
return g_pLogFile__Logger->GetLevel();
|
||||
}
|
||||
|
||||
extern inline void __Logger_SetLevel(unsigned nLevel)
|
||||
{
|
||||
if (g_pLogFile__Logger == NULL)
|
||||
return;
|
||||
|
||||
g_pLogFile__Logger->SetLevel(nLevel);
|
||||
}
|
||||
|
||||
extern inline int __Logger_GetOption()
|
||||
{
|
||||
if (g_pLogFile__Logger == NULL)
|
||||
return 0;
|
||||
|
||||
return g_pLogFile__Logger->GetOption();
|
||||
}
|
||||
|
||||
extern inline void __Logger_SetOption(int flagOption)
|
||||
{
|
||||
if (g_pLogFile__Logger == NULL)
|
||||
return;
|
||||
|
||||
g_pLogFile__Logger->SetOption(flagOption);
|
||||
}
|
||||
|
||||
extern inline void __Logger_SetExtension(HLoggerExtension * pExtension)
|
||||
{
|
||||
if (g_pLogFile__Logger == NULL)
|
||||
return;
|
||||
|
||||
g_pLogFile__Logger->SetExtension(pExtension);
|
||||
}
|
||||
|
||||
extern inline void __Logger_Write(int nLevel, const char * pszLog)
|
||||
{
|
||||
if (g_pLogFile__Logger == NULL)
|
||||
return;
|
||||
|
||||
g_pLogFile__Logger->Write(nLevel, pszLog);
|
||||
}
|
||||
|
||||
extern inline void __Logger_Dump(int nLevel, const char * pszLog, size_t nSize, bool bWithHex)
|
||||
{
|
||||
if (g_pLogFile__Logger == NULL)
|
||||
return;
|
||||
|
||||
g_pLogFile__Logger->Dump(nLevel, pszLog, nSize, bWithHex);
|
||||
}
|
||||
|
||||
extern inline void __Logger_Format(int nLevel, const char * fmt, ...)
|
||||
{
|
||||
if (g_pLogFile__Logger == NULL)
|
||||
return;
|
||||
|
||||
if (nLevel > g_pLogFile__Logger->GetLevel() ||
|
||||
((g_pLogFile__Logger->GetOption() & HLogger::onlyLevel) == HLogger::onlyLevel && g_pLogFile__Logger->GetLevel() != nLevel))
|
||||
return;
|
||||
|
||||
va_list vaList;
|
||||
va_start(vaList, fmt);
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
g_pLogFile__Logger->Lock();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
g_pLogFile__Logger->m_nLogLength = _vsnprintf(g_pLogFile__Logger->GetLogStringBuffer(), HLogger::MD_MAX_STRING - 1, fmt, vaList);
|
||||
#else
|
||||
g_pLogFile__Logger->m_nLogLength = vsnprintf(g_pLogFile__Logger->GetLogStringBuffer(), HLogger::MD_MAX_STRING - 1, fmt, vaList);
|
||||
#endif
|
||||
if (g_pLogFile__Logger->m_nLogLength < 0 || g_pLogFile__Logger->m_nLogLength >= HLogger::MD_MAX_STRING)
|
||||
{
|
||||
g_pLogFile__Logger->m_nLogLength = HLogger::MD_MAX_STRING;
|
||||
g_pLogFile__Logger->GetLogStringBuffer()[HLogger::MD_MAX_STRING - 1] = '\0';
|
||||
}
|
||||
|
||||
va_end(vaList);
|
||||
|
||||
g_pLogFile__Logger->WriteLog(false);
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
g_pLogFile__Logger->Unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
extern inline void __Logger_SetSrcInfoWithLock(const char * szSrcFileName, const unsigned nSrcLine)
|
||||
{
|
||||
if (g_pLogFile__Logger == NULL)
|
||||
return;
|
||||
|
||||
g_pLogFile__Logger->SetSrcInfoWithLock(szSrcFileName, nSrcLine);
|
||||
}
|
||||
|
||||
extern inline void __Logger_TraceWithUnlock(int nLevel, const char *fmt, ...)
|
||||
{
|
||||
if (g_pLogFile__Logger == NULL)
|
||||
return;
|
||||
|
||||
if (nLevel > g_pLogFile__Logger->GetLevel() ||
|
||||
((g_pLogFile__Logger->GetLevel() & HLogger::onlyLevel) == HLogger::onlyLevel && g_pLogFile__Logger->GetLevel() != nLevel))
|
||||
{
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
g_pLogFile__Logger->Unlock();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
va_list vaList;
|
||||
va_start(vaList, fmt);
|
||||
|
||||
#ifdef _WIN32
|
||||
g_pLogFile__Logger->m_nLogLength = _vsnprintf(g_pLogFile__Logger->GetLogStringBuffer(), HLogger::MD_MAX_STRING - 1, fmt, vaList);
|
||||
#else
|
||||
g_pLogFile__Logger->m_nLogLength = vsnprintf(g_pLogFile__Logger->GetLogStringBuffer(), HLogger::MD_MAX_STRING - 1, fmt, vaList);
|
||||
#endif
|
||||
if (g_pLogFile__Logger->m_nLogLength < 0 || g_pLogFile__Logger->m_nLogLength >= HLogger::MD_MAX_STRING)
|
||||
{
|
||||
g_pLogFile__Logger->m_nLogLength = HLogger::MD_MAX_STRING;
|
||||
g_pLogFile__Logger->GetLogStringBuffer()[HLogger::MD_MAX_STRING - 1] = '\0';
|
||||
}
|
||||
|
||||
va_end(vaList);
|
||||
|
||||
g_pLogFile__Logger->TraceWithUnlock(nLevel);
|
||||
}
|
||||
|
||||
|
||||
#define HLOG_OPEN(LEVEL, CONTINUE, FILENAME) { if (g_pLogFile__Logger == NULL) { g_pLogFile__Logger = new HLogger; if (g_pLogFile__Logger->Create(LEVEL, CONTINUE, FILENAME) == false) g_pLogFile__Logger = NULL; } }
|
||||
#define HLOG_CLOSE() { if (g_pLogFile__Logger) { delete g_pLogFile__Logger; g_pLogFile__Logger = NULL; } }
|
||||
#define HLOG_GETLEVEL __Logger_GetLevel
|
||||
#define HLOG_SETLEVEL __Logger_SetLevel
|
||||
#define HLOG_GETOPTION __Logger_GetOption
|
||||
#define HLOG_SETOPTION __Logger_SetOption
|
||||
#define HLOG_SETEXTENSION __Logger_SetExtension
|
||||
|
||||
#define HLOG __Logger_Write
|
||||
#define HLOGD __Logger_Dump
|
||||
#define HLOGF __Logger_Format
|
||||
#define PSTRACE __Logger_SetSrcInfoWithLock(__FILE__, __LINE__),__Logger_TraceWithUnlock
|
||||
|
||||
#endif // LOGGER__H_
|
||||
@@ -0,0 +1,125 @@
|
||||
################################################################################
|
||||
# Common settings
|
||||
AR = ar
|
||||
RANLIB = ranlib
|
||||
CC = g++
|
||||
C = gcc
|
||||
PREC = cpp
|
||||
LD = g++
|
||||
MAKE = make
|
||||
|
||||
|
||||
################################################################################
|
||||
# OS definition
|
||||
# LINUX, FREEBSD, OSX55, SOLARIS
|
||||
ifndef os
|
||||
os = LINUX
|
||||
endif
|
||||
|
||||
|
||||
################################################################################
|
||||
# Standard Configuration
|
||||
STD_CCFLAGS += -O2 -Wall -fPIC
|
||||
STD_CCFLAGS += -D_REENTRANT
|
||||
STD_INC += -I/usr/local/include
|
||||
STD_LIBS += -L/usr/local/lib
|
||||
|
||||
################################################################################
|
||||
# External Library Definitions
|
||||
ifeq ($(os), LINUX)
|
||||
OPENSSLDIR = ../external/linux/openssl-1.0.2j
|
||||
else ifeq ($(os), SOLARIS)
|
||||
OPENSSLDIR = ../external/solaris/openssl-1.0.2j
|
||||
endif
|
||||
|
||||
OPENSSL_INCDIR = $(OPENSSLDIR)/include
|
||||
|
||||
|
||||
################################################################################
|
||||
# Include Definitions
|
||||
INCDIR += $(STD_INC)
|
||||
INCDIR += -I$(OPENSSL_INCDIR)
|
||||
|
||||
#ifeq ($(use_curl), true)
|
||||
#INCDIR += -I../external/curl/include
|
||||
#endif
|
||||
|
||||
################################################################################
|
||||
# c++ flags Definitions
|
||||
CCFLAGS += $(INCDIR)
|
||||
CCFLAGS += $(STD_CCFLAGS)
|
||||
|
||||
|
||||
################################################################################
|
||||
# Library Definitions
|
||||
LIBS += $(STD_LIBS)
|
||||
|
||||
ifeq ($(use_curl), true)
|
||||
#LIBS += -L../external/curl/lib -lcurl
|
||||
#LIBS += -lcurl
|
||||
endif
|
||||
|
||||
|
||||
################################################################################
|
||||
# obj generation directory flags Definitions
|
||||
OBJDIR = huslib
|
||||
OBJDIR_PATH = ../tmp/obj/$(OBJDIR)
|
||||
|
||||
|
||||
################################################################################
|
||||
# Source file names
|
||||
SOURCES = Common.cpp Config.cpp Global.cpp hsparser.cpp HttpHandler.cpp HusApp.cpp inifile.cpp Logger.cpp MultiplexSocket.cpp MultiplexSslSocket.cpp NetUtil.cpp stringex.cpp TelnetHandler.cpp TelnetServer.cpp Timer.cpp WebServer.cpp VspHandler.cpp SohHandler.cpp
|
||||
|
||||
ifeq ($(use_curl), true)
|
||||
SOURCES += curl_manager.cpp
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Target file names
|
||||
LIB_TOOL = libhuslib.a
|
||||
LIB_SHARED = libhuslib.so
|
||||
|
||||
|
||||
OBJS := $(SOURCES:%.c=$(OBJDIR_PATH)/%.o)
|
||||
OBJS := $(OBJS:%.cxx=$(OBJDIR_PATH)/%.o)
|
||||
OBJS := $(OBJS:%.cpp=$(OBJDIR_PATH)/%.o)
|
||||
|
||||
DEPENDS := $(SOURCES:%.c=$(OBJDIR_PATH)/%.dep)
|
||||
DEPENDS := $(DEPENDS:%.cxx=$(OBJDIR_PATH)/%.dep)
|
||||
DEPENDS := $(DEPENDS:%.cpp=$(OBJDIR_PATH)/%.dep)
|
||||
|
||||
$(OBJDIR_PATH)/%.o:%.c
|
||||
$(CC) $(CCFLAGS) -c -o $@ -g $<
|
||||
$(OBJDIR_PATH)/%.o:%.cxx
|
||||
$(CC) $(CCFLAGS) -c -o $@ -g $<
|
||||
$(OBJDIR_PATH)/%.o:%.cpp
|
||||
$(CC) $(CCFLAGS) -c -o $@ -g $<
|
||||
$(OBJDIR_PATH)/%.dep:%.c
|
||||
@mkdir -p $(OBJDIR_PATH)
|
||||
$(CC) -c $(CCFLAGS) -MM $< > $@
|
||||
@sed -e "s/.o:/.c:/" $@ | sed -e "s/$<:/$(OBJDIR)\/$<:/" | sed -e "s/.c:/.o:/" > $@
|
||||
@rm $@
|
||||
$(OBJDIR_PATH)/%.dep:%.cxx
|
||||
@mkdir -p $(OBJDIR_PATH)
|
||||
$(CC) -c $(CCFLAGS) -MM $< > $@
|
||||
@sed -e "s/.o:/.cxx:/" $@ | sed -e "s/$<:/$(OBJDIR)\/$<:/" | sed -e "s/.cxx:/.o:/" > $@
|
||||
@rm $@
|
||||
$(OBJDIR_PATH)/%.dep:%.cpp
|
||||
@mkdir -p $(OBJDIR_PATH)
|
||||
$(CC) -c $(CCFLAGS) -MM $< > $@
|
||||
@sed -e "s/.o:/.cpp:/" $@ | sed -e "s/$<:/$(OBJDIR)\/$<:/" | sed -e "s/.cpp:/.o:/" > $@
|
||||
@rm $@
|
||||
|
||||
|
||||
#all : $(LIB_TOOL) $(LIB_SHARED)
|
||||
all : $(LIB_TOOL)
|
||||
|
||||
$(LIB_TOOL) : $(DEPENDS) $(OBJS)
|
||||
$(AR) rcv $@ $(OBJS)
|
||||
|
||||
$(LIB_SHARED) : $(DEPENDS) $(OBJS)
|
||||
$(LD) -shared -o $(LIB_SHARED) $(OBJS) $(LIBS)
|
||||
|
||||
clean :
|
||||
rm -f $(DEPENDS) $(OBJS)
|
||||
rm -f $(LIB_TOOL) $(LIB_SHARED)
|
||||
@@ -0,0 +1,765 @@
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <fcntl.h> // fcntl()
|
||||
#include <netinet/tcp.h> // TCP_NODELAY
|
||||
|
||||
#endif
|
||||
|
||||
#include "stringex.h"
|
||||
#include "Defines.h"
|
||||
#include "Common.h"
|
||||
#include "Object.h"
|
||||
#include "String.h"
|
||||
#include "Logger.h"
|
||||
#include "Socket.h"
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
#include "Thread.h"
|
||||
#endif
|
||||
#include "Timer.h"
|
||||
|
||||
#include "Global.h"
|
||||
#include "MultiplexSocket.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
typedef int socklen_t;
|
||||
|
||||
#else
|
||||
|
||||
#define SD_BOTH SHUT_RDWR
|
||||
#define FD_READ SHUT_RD
|
||||
#define FD_WRITE SHUT_WR
|
||||
#define closesocket close
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
HMultiplexSocket::HMultiplexSocket()
|
||||
{
|
||||
m_fdSocket = INVALID_SOCKET;
|
||||
m_nState = MPS_DISABLE;
|
||||
m_bSendRetry = false;
|
||||
m_nLastReceivedTime = 0;
|
||||
m_pDispatcher = NULL;
|
||||
|
||||
m_nConnectTime = g_nTcpConnectTimeout;
|
||||
|
||||
memset(&m_saiRemote, 0, sizeof(m_saiRemote));
|
||||
}
|
||||
|
||||
HMultiplexSocket::HMultiplexSocket(SOCKET sock, struct sockaddr_in * psaiRemote, HMpsDispatcher * pDispatcher)
|
||||
{
|
||||
m_fdSocket = sock;
|
||||
m_nState = MPS_READY;
|
||||
m_bSendRetry = false;
|
||||
m_nLastReceivedTime = 0;
|
||||
m_pDispatcher = pDispatcher;
|
||||
|
||||
m_nConnectTime = g_nTcpConnectTimeout;
|
||||
|
||||
memcpy(&m_saiRemote, psaiRemote, sizeof(m_saiRemote));
|
||||
}
|
||||
|
||||
HMultiplexSocket::~HMultiplexSocket()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool HMultiplexSocket::Close()
|
||||
{
|
||||
if (m_nState == MPS_DISABLE ||
|
||||
(m_nState == MPS_DELETE && m_fdSocket == INVALID_SOCKET))
|
||||
//if (m_fdSocket == INVALID_SOCKET)
|
||||
return false;
|
||||
|
||||
OnClose();
|
||||
|
||||
if (m_nState != MPS_LISTENING)
|
||||
shutdown(m_fdSocket, SD_BOTH);
|
||||
|
||||
if (m_nState != MPS_DELETE)
|
||||
m_nState = MPS_DISABLE;
|
||||
|
||||
closesocket(m_fdSocket);
|
||||
|
||||
HLOGF(HLOG_INFO5, "INFO, MpSock, socket closed, socket = %d\n", m_fdSocket);
|
||||
|
||||
m_fdSocket = INVALID_SOCKET;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMultiplexSocket::Connect(unsigned nConnectTime)
|
||||
{
|
||||
if (m_fdSocket == INVALID_SOCKET)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MpSock, This socket did not created.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_nLastTryConnectTime = 0;
|
||||
|
||||
if (nConnectTime)
|
||||
m_nConnectTime = nConnectTime;
|
||||
|
||||
int nResult = connect(m_fdSocket, (struct sockaddr *)&m_saiRemote, sizeof(struct sockaddr));
|
||||
if (nResult == SOCKET_ERROR &&
|
||||
#ifdef _WIN32
|
||||
SockErrorNo() != WSAEWOULDBLOCK)
|
||||
#else
|
||||
SockErrorNo() != EWOULDBLOCK && SockErrorNo() != EINPROGRESS)
|
||||
#endif
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MpSock, Failed to connect. socket = %d, error = %d\n", m_fdSocket, SockErrorNo());
|
||||
OnConnect(false);
|
||||
m_nState = MPS_CLOSING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
HLOGF(HLOG_INFO4, "INFO, MpSock, TCP connecting... to %s:%d (socket = %d)\n", inet_ntoa(m_saiRemote.sin_addr), ntohs(m_saiRemote.sin_port), m_fdSocket);
|
||||
m_nState = MPS_CONNECTING;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMultiplexSocket::IsConnectTimeout(DWORD nCurrTime)
|
||||
{
|
||||
if (m_nConnectTime <= 0)
|
||||
return false;
|
||||
|
||||
if (m_nLastTryConnectTime == 0)
|
||||
m_nLastTryConnectTime = nCurrTime;
|
||||
|
||||
if (m_nConnectTime <= TimeDiff(m_nLastTryConnectTime, nCurrTime))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HMultiplexSocket::Bind(struct sockaddr_in * psaiLocal)
|
||||
{
|
||||
if (m_fdSocket == INVALID_SOCKET)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, This socket did not created.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bind(m_fdSocket, (struct sockaddr *)psaiLocal, sizeof(struct sockaddr)) == SOCKET_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed to bind, (%s:%d), error = %d\n", inet_ntoa(psaiLocal->sin_addr), ntohs(psaiLocal->sin_port), SockErrorNo());
|
||||
return false;
|
||||
}
|
||||
|
||||
HLOGF(HLOG_INFO4, "INFO, MpSock, Succeed to bind, (%s:%d), socket = %d\n", inet_ntoa(psaiLocal->sin_addr), ntohs(psaiLocal->sin_port), m_fdSocket);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMultiplexSocket::Bind(const char * pszAddress, u_short nPort)
|
||||
{
|
||||
if (m_fdSocket == INVALID_SOCKET)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, This socket did not created.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in sai;
|
||||
|
||||
sai.sin_family = AF_INET;
|
||||
sai.sin_addr.s_addr = inet_addr(pszAddress);
|
||||
sai.sin_port = htons(nPort);
|
||||
|
||||
return HMultiplexSocket::Bind(&sai);
|
||||
}
|
||||
|
||||
bool HMultiplexSocket::GetRemoteAddress(char * pBuf, u_short * pnPort)
|
||||
{
|
||||
if (pBuf)
|
||||
strcpy(pBuf, inet_ntoa(m_saiRemote.sin_addr));
|
||||
|
||||
if (pnPort)
|
||||
*pnPort = ntohs(m_saiRemote.sin_port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMultiplexSocket::SetRemoteAddress(struct sockaddr_in * psaiLocal)
|
||||
{
|
||||
memcpy(&m_saiRemote, psaiLocal, sizeof(struct sockaddr_in));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMultiplexSocket::SetRemoteAddress(const char * pszAddress, u_short nPort)
|
||||
{
|
||||
m_saiRemote.sin_family = AF_INET;
|
||||
m_saiRemote.sin_addr.s_addr = inet_addr(pszAddress);
|
||||
m_saiRemote.sin_port = htons(nPort);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMultiplexSocket::SetRemoteAddressHostByName(const char * pszHostName, u_short nPort)
|
||||
{
|
||||
struct hostent * pHE;
|
||||
|
||||
// resolve host address
|
||||
if ((pHE = gethostbyname(pszHostName)) == NULL)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed to gethostbyname, socket = %d, error = %d\n", m_fdSocket, SockErrorNo());
|
||||
#if _MSC_VER <= 1200
|
||||
return false;
|
||||
#else
|
||||
char szPort[16];
|
||||
struct addrinfo aiHints;
|
||||
struct addrinfo *aiList = NULL;
|
||||
struct addrinfo *aiPtr = NULL;
|
||||
int retVal;
|
||||
|
||||
memset(&aiHints, 0, sizeof(aiHints));
|
||||
aiHints.ai_family = AF_INET;
|
||||
aiHints.ai_socktype = SOCK_STREAM;
|
||||
aiHints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
sprintf(szPort, "%d", nPort);
|
||||
|
||||
if ((retVal = getaddrinfo(pszHostName, szPort, &aiHints, &aiList)) != 0)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed to getaddrinfo, socket = %d, error = %d, retVal = %d\n", m_fdSocket, SockErrorNo(), retVal);
|
||||
return false;
|
||||
}
|
||||
|
||||
for(aiPtr = aiList; aiPtr != NULL; aiPtr=aiPtr->ai_next)
|
||||
{
|
||||
if (aiPtr->ai_family == AF_INET)
|
||||
{
|
||||
memcpy(&m_saiRemote, aiPtr->ai_addr, sizeof(struct sockaddr_in));
|
||||
freeaddrinfo(aiList);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
memcpy(&m_saiRemote.sin_addr, pHE->h_addr_list[0], pHE->h_length);
|
||||
m_saiRemote.sin_port = htons(nPort); // short, network byte order
|
||||
m_saiRemote.sin_family = AF_INET; // host byte order
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HMultiplexSocket::OnConnect(bool /* bIsSuccess */)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MpSock, Called to OnConnect of parent class, socket = %d\n", m_fdSocket);
|
||||
}
|
||||
|
||||
void HMultiplexSocket::OnReceive()
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MpSock, Called to OnReceive of parent class, socket = %d\n", m_fdSocket);
|
||||
}
|
||||
|
||||
int HMultiplexSocket::OnSendRetry()
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MpSock, Called to OnReceive of parent class, socket = %d\n", m_fdSocket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool HMultiplexTcpSocket::Create(bool bIsTcpNoDelay)
|
||||
{
|
||||
if (m_fdSocket != INVALID_SOCKET)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, This socket aleady created. socket = %d\n", m_fdSocket);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((m_fdSocket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Don't create socket. error = %d\n", SockErrorNo());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set non blocking mode
|
||||
#ifdef _WIN32
|
||||
ULONG nNonBlock = 1;
|
||||
if (ioctlsocket(m_fdSocket, FIONBIO, &nNonBlock) == SOCKET_ERROR)
|
||||
{
|
||||
m_fdSocket = INVALID_SOCKET;
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed to ioctlsocket. socket = %d, WSAGetLastError = %d\n", m_fdSocket, SockErrorNo());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
int nFlags = fcntl(m_fdSocket, F_GETFL, 0);
|
||||
fcntl(m_fdSocket, F_SETFL, nFlags | O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
int nBuffSize = MPS_MAX_SOCKET_BUFFER;
|
||||
if (setsockopt(m_fdSocket, SOL_SOCKET, SO_SNDBUF, (const char *)&nBuffSize, sizeof(nBuffSize)) == SOCKET_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed to setsockopt SO_SNDBUF. socket = %d, error = %d\n", m_fdSocket, SockErrorNo());
|
||||
}
|
||||
|
||||
if (setsockopt(m_fdSocket, SOL_SOCKET, SO_RCVBUF, (const char *)&nBuffSize, sizeof(nBuffSize)) == SOCKET_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed to setsockopt SO_RCVBUF. socket = %d, error = %d\n", m_fdSocket, SockErrorNo());
|
||||
}
|
||||
|
||||
if (bIsTcpNoDelay) //... linux error
|
||||
{
|
||||
bool bNoDelay = false;
|
||||
if (setsockopt(m_fdSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&bNoDelay, sizeof(bNoDelay)) == SOCKET_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed setsockopt TCP_NODELAY. socket = %d, error = %d\n", m_fdSocket, SockErrorNo());
|
||||
}
|
||||
}
|
||||
|
||||
int nKeepAlive = 1;
|
||||
if (setsockopt(m_fdSocket, SOL_SOCKET, SO_KEEPALIVE, (const char *)&nKeepAlive, sizeof(nKeepAlive)) == SOCKET_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed to setsockopt SO_KEEPALIVE. socket = %d, error = %d\n", m_fdSocket, SockErrorNo());
|
||||
}
|
||||
|
||||
HLOGF(HLOG_INFO5, "INFO, MpSock, TCP socket created. socket = %d\n", m_fdSocket);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int HMultiplexTcpSocket::Send(const char * pData, int nSize)
|
||||
{
|
||||
int nSentSize = send(m_fdSocket, pData, nSize, 0);
|
||||
if (nSentSize == SOCKET_ERROR)
|
||||
{
|
||||
int nError = SockErrorNo();
|
||||
|
||||
#ifdef _WIN32
|
||||
if (nError != WSAEWOULDBLOCK)
|
||||
#else
|
||||
if (nError != EWOULDBLOCK && nError != EAGAIN)
|
||||
#endif
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MpSock, Failed to send, socket = %d, error = %d\n", m_fdSocket, nError);
|
||||
m_nState = MPS_CLOSING;
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_bSendRetry = true;
|
||||
return 0;
|
||||
}
|
||||
else if (nSentSize < nSize)
|
||||
{
|
||||
m_bSendRetry = true;
|
||||
return nSentSize;
|
||||
}
|
||||
|
||||
if (m_bSendRetry)
|
||||
m_bSendRetry = false;
|
||||
|
||||
return nSentSize;
|
||||
}
|
||||
|
||||
int HMultiplexTcpSocket::Receive(char * pBuffer, int nSize)
|
||||
{
|
||||
int nReceivedSize = recv(m_fdSocket, pBuffer, nSize, 0);
|
||||
if (nReceivedSize == SOCKET_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_INFO4, "INFO, MpSock, The virtual circuit was reset by the remote side executing a \"hard\" or \"abortive\" close, socket = %d, error = %d\n", m_fdSocket, SockErrorNo());
|
||||
m_nState = MPS_CLOSING;
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
else if (nReceivedSize == 0)
|
||||
{
|
||||
HLOGF(HLOG_INFO4, "INFO, MpSock, The virtual circuit was reset by the remote side executing a \"gracefull\" shutdown, socket = %d\n", m_fdSocket);
|
||||
m_nState = MPS_CLOSING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return nReceivedSize;
|
||||
}
|
||||
|
||||
void HMultiplexTcpSocket::FinishTcp()
|
||||
{
|
||||
shutdown(m_fdSocket, FD_WRITE);
|
||||
|
||||
HLOGF(HLOG_INFO5, "INFO, MPSock, write shutdown, socket = %d\n", m_fdSocket);
|
||||
m_nState = MPS_CLOSING;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool HMultiplexUdpSocket::Create()
|
||||
{
|
||||
if (m_fdSocket != INVALID_SOCKET)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, This socket aleady created. socket = %d\n", m_fdSocket);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((m_fdSocket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Don't create socket. error = %d\n", SockErrorNo());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set non blocking mode
|
||||
#ifdef _WIN32
|
||||
ULONG nNonBlock = 1;
|
||||
if (ioctlsocket(m_fdSocket, FIONBIO, &nNonBlock) == SOCKET_ERROR)
|
||||
{
|
||||
m_fdSocket = INVALID_SOCKET;
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed to ioctlsocket. socket = %d, WSAGetLastError = %d\n", m_fdSocket, SockErrorNo());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
int nFlags = fcntl(m_fdSocket, F_GETFL, 0);
|
||||
fcntl(m_fdSocket, F_SETFL, nFlags | O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
int nBuffSize = MPS_MAX_SOCKET_BUFFER;
|
||||
if (setsockopt(m_fdSocket, SOL_SOCKET, SO_SNDBUF, (const char *)&nBuffSize, sizeof(nBuffSize)) == SOCKET_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed to setsockopt SO_SNDBUF. socket = %d, error = %d\n", m_fdSocket, SockErrorNo());
|
||||
}
|
||||
|
||||
if (setsockopt(m_fdSocket, SOL_SOCKET, SO_RCVBUF, (const char *)&nBuffSize, sizeof(nBuffSize)) == SOCKET_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed to setsockopt SO_RCVBUF. socket = %d, error = %d\n", m_fdSocket, SockErrorNo());
|
||||
}
|
||||
|
||||
HLOGF(HLOG_INFO5, "INFO, MpSock, UDP socket created. socket = %d\n", m_fdSocket);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMultiplexUdpSocket::Bind(struct sockaddr_in * psaiLocal)
|
||||
{
|
||||
if (HMultiplexSocket::Bind(psaiLocal) == false)
|
||||
return false;
|
||||
|
||||
m_nState = MPS_READY;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMultiplexUdpSocket::SetRemoteAddress(struct sockaddr_in * psaiLocal)
|
||||
{
|
||||
memcpy(&m_saiRemote, psaiLocal, sizeof(struct sockaddr_in));
|
||||
m_nState = MPS_READY;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMultiplexUdpSocket::SetRemoteAddress(const char * pszAddress, u_short nPort)
|
||||
{
|
||||
m_saiRemote.sin_family = AF_INET;
|
||||
m_saiRemote.sin_addr.s_addr = inet_addr(pszAddress);
|
||||
m_saiRemote.sin_port = htons(nPort);
|
||||
m_nState = MPS_READY;
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HMpsDispatcher::HMpsDispatcher()
|
||||
{
|
||||
m_nLoopInterval = 0;
|
||||
m_bTerminate = false;
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_bProecessing = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
HMpsDispatcher::~HMpsDispatcher()
|
||||
{
|
||||
RemoveAllSocket();
|
||||
}
|
||||
|
||||
bool HMpsDispatcher::Attach(HMultiplexSocket * pSocket)
|
||||
{
|
||||
pSocket->SetDispatcher(this);
|
||||
m_listSocket.push_front(pSocket);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMpsDispatcher::AttachWithLock(HMultiplexSocket * pSocket)
|
||||
{
|
||||
pSocket->SetDispatcher(this);
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_syncObject.Lock();
|
||||
#endif
|
||||
|
||||
m_listSocket.push_front(pSocket);
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_syncObject.Unlock();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HMpsDispatcher::Detach(HMultiplexSocket * pSocket)
|
||||
{
|
||||
pSocket->m_pDispatcher = NULL;
|
||||
pSocket->SetState(HMultiplexSocket::MPS_DELETE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HMpsDispatcher::RemoveAllSocket()
|
||||
{
|
||||
if (m_listSocket.empty())
|
||||
return;
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_syncObject.Lock();
|
||||
#endif
|
||||
|
||||
for (LIST_MULTIPLEX_SOCKET::iterator iter = m_listSocket.begin();
|
||||
iter != m_listSocket.end(); iter++)
|
||||
{
|
||||
HMultiplexSocket * pSocket = *iter;
|
||||
if (pSocket)
|
||||
{
|
||||
pSocket->Close();
|
||||
delete pSocket;
|
||||
}
|
||||
}
|
||||
m_listSocket.clear();
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_syncObject.Unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool HMpsDispatcher::Dispatch()
|
||||
{
|
||||
HMultiplexSocket * pSocket;
|
||||
fd_set fdSetRead, fdSetWrite;//, fdSetError;
|
||||
int nSelectResult, nFDMax, nFDCount;
|
||||
LIST_MULTIPLEX_SOCKET::iterator iter;
|
||||
struct timeval tvWait;
|
||||
|
||||
long nTimeout = m_nLoopInterval * 1000; // msec
|
||||
m_bTerminate = false;
|
||||
|
||||
while (m_bTerminate == false)
|
||||
{
|
||||
FD_ZERO(&fdSetRead);
|
||||
FD_ZERO(&fdSetWrite);
|
||||
//FD_ZERO(&fdSetError);
|
||||
|
||||
tvWait.tv_sec = 0;
|
||||
tvWait.tv_usec = nTimeout;
|
||||
|
||||
nFDMax = 0;
|
||||
nFDCount = 0;
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_bProecessing = true;
|
||||
m_syncObject.Lock();
|
||||
#endif
|
||||
for (iter = m_listSocket.begin(); iter != m_listSocket.end(); iter++)
|
||||
{
|
||||
pSocket = *iter;
|
||||
|
||||
if (pSocket->GetState() == HMultiplexSocket::MPS_CLOSING ||
|
||||
pSocket->GetState() == HMultiplexSocket::MPS_DELETE)
|
||||
{
|
||||
pSocket->Close();
|
||||
|
||||
if (pSocket->GetState() == HMultiplexSocket::MPS_DELETE)
|
||||
{
|
||||
delete pSocket;
|
||||
iter = m_listSocket.erase(iter);
|
||||
|
||||
if (m_listSocket.empty() || iter == m_listSocket.end())
|
||||
break;
|
||||
|
||||
pSocket = *iter;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSocket->GetState() == HMultiplexSocket::MPS_READY ||
|
||||
pSocket->GetState() == HMultiplexSocket::MPS_LISTENING)
|
||||
{
|
||||
FD_SET(pSocket->GetSocket(), &fdSetRead);
|
||||
//FD_SET(pSocket->GetSocket(), &fdSetError);
|
||||
nFDCount++;
|
||||
#ifndef _WIN32
|
||||
if (nFDMax < pSocket->GetSocket())
|
||||
nFDMax = pSocket->GetSocket();
|
||||
#endif
|
||||
}
|
||||
else if (pSocket->GetState() == HMultiplexSocket::MPS_CONNECTING)
|
||||
{
|
||||
if (pSocket->IsConnectTimeout(HTIMER()->GetTickCount()))
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MpsDisp, Failed to connect because of timeout. socket = %d\n", pSocket->GetSocket());
|
||||
pSocket->OnConnect(false);
|
||||
pSocket->SetState(HMultiplexSocket::MPS_CLOSING);
|
||||
}
|
||||
else
|
||||
{
|
||||
FD_SET(pSocket->GetSocket(), &fdSetRead);
|
||||
FD_SET(pSocket->GetSocket(), &fdSetWrite);
|
||||
//FD_SET(pSocket->GetSocket(), &fdSetError);
|
||||
nFDCount++;
|
||||
#ifndef _WIN32
|
||||
if (nFDMax < pSocket->GetSocket())
|
||||
nFDMax = pSocket->GetSocket();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (pSocket->IsSendRetry())
|
||||
{
|
||||
FD_SET(pSocket->GetSocket(), &fdSetWrite);
|
||||
nFDCount++;
|
||||
#ifndef _WIN32
|
||||
if (nFDMax < pSocket->GetSocket())
|
||||
nFDMax = pSocket->GetSocket();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_bProecessing = false;
|
||||
m_syncObject.Unlock();
|
||||
#endif
|
||||
|
||||
if (m_listSocket.empty() || nFDCount == 0)
|
||||
{
|
||||
Sleep(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
//if ((nSelectResult = select(nFDMax + 1, &fdSetRead, &fdSetWrite, &fdSetError, &tvWait)) == SOCKET_ERROR)
|
||||
if ((nSelectResult = select(nFDMax + 1, &fdSetRead, &fdSetWrite, NULL, m_nLoopInterval ? &tvWait : NULL)) == SOCKET_ERROR)
|
||||
{
|
||||
Sleep(10);
|
||||
continue;
|
||||
}
|
||||
//printf("nSelectResult = %d\n", nSelectResult);
|
||||
|
||||
if (nSelectResult <= 0)
|
||||
continue;
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_bProecessing = true;
|
||||
m_syncObject.Lock();
|
||||
#endif
|
||||
for (iter = m_listSocket.begin(); iter != m_listSocket.end(); iter++)
|
||||
{
|
||||
pSocket = *iter;
|
||||
|
||||
if (pSocket->GetState() == HMultiplexSocket::MPS_DISABLE ||
|
||||
pSocket->GetState() == HMultiplexSocket::MPS_CLOSING ||
|
||||
pSocket->GetState() == HMultiplexSocket::MPS_DELETE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FD_ISSET(pSocket->GetSocket(), &fdSetRead) != 0)
|
||||
{
|
||||
if (pSocket->GetState() == HMultiplexSocket::MPS_READY)
|
||||
{
|
||||
pSocket->OnReceive();
|
||||
pSocket->m_nLastReceivedTime = HTIMER()->GetTickCount();
|
||||
}
|
||||
else if (pSocket->GetState() == HMultiplexSocket::MPS_LISTENING)
|
||||
{
|
||||
SOCKET sock = INVALID_SOCKET;
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
struct sockaddr_in sai;
|
||||
|
||||
if ((sock = accept(pSocket->GetSocket(), (struct sockaddr *)&sai, &len)) == INVALID_SOCKET)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MpsDisp, Failed to accept, socket = %d, error = %d\n", pSocket->GetSocket(), SockErrorNo());
|
||||
Sleep(50);
|
||||
}
|
||||
else
|
||||
{
|
||||
char szListenIp[32];
|
||||
u_short nListenPort = 0;
|
||||
pSocket->GetLocalAddress(szListenIp, &nListenPort);
|
||||
|
||||
HLOGF(HLOG_INFO4, "INFO, MpsDisp, Succeeded to accept, (%s:%d), (%s:%d), socket = %d\n", szListenIp, nListenPort, inet_ntoa(sai.sin_addr), ntohs(sai.sin_port), sock);
|
||||
|
||||
HMultiplexSocket * pAcceptedSocket = pSocket->OnAccept(sock, &sai);
|
||||
if (pAcceptedSocket)
|
||||
{
|
||||
// Set non blocking mode
|
||||
#ifdef _WIN32
|
||||
ULONG nNonBlock = 1;
|
||||
if (ioctlsocket(pAcceptedSocket->GetSocket(), FIONBIO, &nNonBlock) == SOCKET_ERROR)
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpSock, Failed to ioctlsocket, socket = %d, WSAGetLastError = %d\n", pAcceptedSocket->GetSocket(), SockErrorNo());
|
||||
#else
|
||||
int nFlags = fcntl(pAcceptedSocket->GetSocket(), F_GETFL, 0);
|
||||
fcntl(pAcceptedSocket->GetSocket(), F_SETFL, nFlags | O_NONBLOCK);
|
||||
#endif
|
||||
m_listSocket.push_front(pAcceptedSocket);
|
||||
|
||||
pAcceptedSocket->m_nLastReceivedTime = HTIMER()->GetTickCount();
|
||||
pAcceptedSocket->OnAccepted();
|
||||
}
|
||||
else
|
||||
closesocket(sock);
|
||||
}
|
||||
}
|
||||
|
||||
FD_CLR(pSocket->GetSocket(), &fdSetRead);
|
||||
|
||||
if (--nSelectResult <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(pSocket->GetSocket(), &fdSetWrite) != 0)
|
||||
{
|
||||
if (pSocket->GetState() == HMultiplexSocket::MPS_CONNECTING)
|
||||
{
|
||||
int nSocketError = pSocket->GetSockOptError();
|
||||
if (nSocketError != 0)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MpsDisp, Failed to connect (%s:%d), socket = %d, error = %d\n",
|
||||
inet_ntoa(pSocket->GetRemoteAddress()->sin_addr), ntohs(pSocket->GetRemoteAddress()->sin_port), pSocket->GetSocket(), nSocketError);
|
||||
|
||||
pSocket->OnConnect(false);
|
||||
pSocket->SetState(HMultiplexSocket::MPS_CLOSING);
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGF(HLOG_INFO4, "INFO, MpsDisp, Succeeded to connect (%s:%d) socket = %d\n",
|
||||
inet_ntoa(pSocket->GetRemoteAddress()->sin_addr), ntohs(pSocket->GetRemoteAddress()->sin_port), pSocket->GetSocket());
|
||||
|
||||
pSocket->SetState(HMultiplexSocket::MPS_READY);
|
||||
pSocket->OnConnect(true);
|
||||
pSocket->m_nLastReceivedTime = HTIMER()->GetTickCount();
|
||||
}
|
||||
}
|
||||
else if (pSocket->GetState() == HMultiplexSocket::MPS_READY)
|
||||
{
|
||||
if (pSocket->OnSendRetry() < 0) // remain packet send
|
||||
pSocket->FinishTcp();
|
||||
}
|
||||
|
||||
FD_CLR(pSocket->GetSocket(), &fdSetWrite);
|
||||
|
||||
if (--nSelectResult <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_bProecessing = false;
|
||||
m_syncObject.Unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,486 @@
|
||||
#ifndef MULTIPLEX_SOCKET__H_
|
||||
#define MULTIPLEX_SOCKET__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
|
||||
#pragma warning(disable:4244)
|
||||
#pragma warning(disable:4267)
|
||||
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
|
||||
|
||||
|
||||
class HMpsDispatcher;
|
||||
|
||||
class HMultiplexSocket : public HSocket
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
MPS_DISABLE = 1,
|
||||
MPS_READY,
|
||||
MPS_CONNECTING,
|
||||
MPS_LISTENING,
|
||||
MPS_CLOSING,
|
||||
MPS_DELETE
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MPS_MAX_SOCKET_BUFFER = 16384
|
||||
};
|
||||
|
||||
HMultiplexSocket();
|
||||
HMultiplexSocket(SOCKET sock, struct sockaddr_in * psaiRemote, HMpsDispatcher * pDispatcher);
|
||||
~HMultiplexSocket();
|
||||
|
||||
inline int GetState() { return m_nState; }
|
||||
inline void SetState(int nState) { m_nState = nState; }
|
||||
inline unsigned int GetLastReceivedTime() { return m_nLastReceivedTime; }
|
||||
inline bool IsSendRetry() { return m_bSendRetry; }
|
||||
|
||||
HMpsDispatcher * GetDispatcher() { return m_pDispatcher; }
|
||||
void SetDispatcher(HMpsDispatcher * pDispatcher) { m_pDispatcher = pDispatcher; }
|
||||
|
||||
virtual bool Close();
|
||||
|
||||
virtual bool Connect(unsigned nConnectTime = 60000); // msec
|
||||
bool IsConnectTimeout(DWORD nCurrTime);
|
||||
|
||||
bool Bind(struct sockaddr_in * psaiLocal);
|
||||
bool Bind(const char * pszAddress, u_short nPort);
|
||||
|
||||
struct sockaddr_in * GetRemoteAddress() { return &m_saiRemote; }
|
||||
bool GetRemoteAddress(char * pBuf, u_short * pnPort);
|
||||
bool SetRemoteAddress(struct sockaddr_in * psaiLocal);
|
||||
bool SetRemoteAddress(const char * pszAddress, u_short nPort);
|
||||
bool SetRemoteAddressHostByName(const char * pszHostName, u_short nPort);
|
||||
|
||||
virtual int Send(const char * pData, int nSize) = 0;
|
||||
virtual int Receive(char * pBuffer, int nSize) = 0;
|
||||
|
||||
virtual void FinishTcp() {}
|
||||
|
||||
protected:
|
||||
virtual void OnClose() {}
|
||||
virtual void OnConnect(bool bIsSuccess); // only called for client socket
|
||||
virtual void OnReceive();
|
||||
virtual int OnSendRetry();
|
||||
virtual void OnAccepted() {} // only called for child socket
|
||||
|
||||
public:
|
||||
virtual HMultiplexSocket * OnAccept(SOCKET /* sock */, struct sockaddr_in * /* psaiRemote */) { return NULL; }
|
||||
|
||||
protected:
|
||||
int m_nState;
|
||||
bool m_bSendRetry;
|
||||
unsigned int m_nLastReceivedTime;
|
||||
struct sockaddr_in m_saiRemote;
|
||||
|
||||
HMpsDispatcher * m_pDispatcher;
|
||||
|
||||
private:
|
||||
unsigned long m_nConnectTime;
|
||||
unsigned long m_nLastTryConnectTime;
|
||||
|
||||
friend class HMpsDispatcher;
|
||||
template<class _Ty> friend class HMultiplexListenThread;
|
||||
};
|
||||
|
||||
class HMultiplexTcpSocket : public HMultiplexSocket
|
||||
{
|
||||
public:
|
||||
HMultiplexTcpSocket() {}
|
||||
HMultiplexTcpSocket(SOCKET sock, struct sockaddr_in * psaiRemote, HMpsDispatcher * pDispatcher) : HMultiplexSocket(sock, psaiRemote, pDispatcher) {}
|
||||
~HMultiplexTcpSocket() {}
|
||||
|
||||
bool Create(bool bIsTcpNoDelay = false);
|
||||
|
||||
virtual bool IsSslSocket() { return false; }
|
||||
|
||||
virtual int Send(const char * pData, int nSize);
|
||||
virtual int Receive(char * pBuffer, int nSize);
|
||||
|
||||
virtual void FinishTcp(); // remain send and shutdown
|
||||
};
|
||||
|
||||
class HMultiplexUdpSocket : public HMultiplexSocket
|
||||
{
|
||||
public:
|
||||
HMultiplexUdpSocket() {}
|
||||
~HMultiplexUdpSocket() {}
|
||||
|
||||
virtual bool Create();
|
||||
|
||||
virtual bool SetRemoteAddress(struct sockaddr_in * psaiLocal);
|
||||
virtual bool SetRemoteAddress(const char * pszAddress, u_short nPort);
|
||||
|
||||
virtual bool Bind(struct sockaddr_in * psaiLocal);
|
||||
|
||||
virtual inline int Send(const char * pData, int nSize)
|
||||
{
|
||||
return sendto(m_fdSocket, pData, nSize, 0, (struct sockaddr *)&m_saiRemote, sizeof(struct sockaddr));
|
||||
}
|
||||
virtual inline int Receive(char * pBuffer, int nSize)
|
||||
{
|
||||
return recvfrom(m_fdSocket, pBuffer, nSize, 0, NULL, 0);
|
||||
}
|
||||
virtual inline int Receive(char * pBuffer, int nSize, struct sockaddr_in * psaiUDPFrom)
|
||||
{
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
return recvfrom(m_fdSocket, pBuffer, nSize, 0, (struct sockaddr *)psaiUDPFrom, &len);
|
||||
}
|
||||
};
|
||||
|
||||
class HMultiplexListenSocket : public HMultiplexTcpSocket
|
||||
{
|
||||
public:
|
||||
HMultiplexListenSocket() {}
|
||||
~HMultiplexListenSocket() {}
|
||||
|
||||
bool Listen(const char * pszAddress, u_short nPort, int nBackLog = 10)
|
||||
{
|
||||
if (Create() == false)
|
||||
return false;
|
||||
|
||||
#ifdef REUSEADDR
|
||||
int nOptVal = 1;
|
||||
SetSockOpt(SOL_SOCKET, SO_REUSEADDR, (const char *)&nOptVal, sizeof(nOptVal)); // for multiple ip in UNIX
|
||||
#endif
|
||||
if (Bind(pszAddress, nPort) == false)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpLstnSock, Failed to bind, (%s:%d), error = %d\n", pszAddress, nPort, SockErrorNo());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (listen(m_fdSocket, nBackLog) == SOCKET_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpLstnSock, Failed to listen, (%s:%d), error = %d\n", pszAddress, nPort, SockErrorNo());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_nState = MPS_LISTENING;
|
||||
|
||||
HLOGF(HLOG_INFO1, "INFO, MpLstnSock, Succeed to listen TCP, (%s:%d), socket = %d\n", pszAddress, nPort, m_fdSocket);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual HMultiplexTcpSocket * OnAccept(SOCKET sock, struct sockaddr_in * psaiRemote) = 0;
|
||||
};
|
||||
typedef std::list<HMultiplexSocket *> LIST_MULTIPLEX_SOCKET;
|
||||
|
||||
class HMpsDispatcher
|
||||
{
|
||||
public:
|
||||
HMpsDispatcher();
|
||||
virtual ~HMpsDispatcher();
|
||||
|
||||
void Initialize(unsigned long nLoopInterval) { m_nLoopInterval = nLoopInterval; } // msec, for connect timeout
|
||||
void SetTerminateFlag() { m_bTerminate = true; }
|
||||
|
||||
LIST_MULTIPLEX_SOCKET * GetSocketList() { return &m_listSocket; }
|
||||
|
||||
bool Attach(HMultiplexSocket * pSocket);
|
||||
bool AttachWithLock(HMultiplexSocket * pSocket);
|
||||
bool Detach(HMultiplexSocket * pSocket);
|
||||
void RemoveAllSocket();
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
inline bool IsProcessing() { return m_bProecessing; }
|
||||
#endif
|
||||
|
||||
bool Dispatch();
|
||||
|
||||
//private:
|
||||
public:
|
||||
LIST_MULTIPLEX_SOCKET m_listSocket;
|
||||
unsigned long m_nLoopInterval;
|
||||
volatile bool m_bTerminate;
|
||||
|
||||
public: //...TempCode
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
HSyncObject m_syncObject;
|
||||
volatile bool m_bProecessing;
|
||||
#endif
|
||||
};
|
||||
|
||||
class HMpsDispatcherList : public std::list<HMpsDispatcher *>
|
||||
{
|
||||
public:
|
||||
HMpsDispatcherList() { m_nLazyIndex = 0; }
|
||||
~HMpsDispatcherList() {}
|
||||
|
||||
HMpsDispatcher * GetLazyDispatcher()
|
||||
{
|
||||
iterator iter;
|
||||
int i = 0;
|
||||
|
||||
for (iter = begin(); iter != end(); iter++)
|
||||
{
|
||||
if ((*iter)->IsProcessing() == false)
|
||||
i++;
|
||||
}
|
||||
//HLOGF(HLOG_WARNING, "[TRACE], DispatcherList_0x%x, lazy count = %d\n", this, i);
|
||||
|
||||
i = 0;
|
||||
for (iter = begin(); iter != end(); iter++)
|
||||
{
|
||||
if (i == m_nLazyIndex)
|
||||
{
|
||||
m_nLazyIndex++;
|
||||
if (m_nLazyIndex >= (int)size())
|
||||
m_nLazyIndex = 0;
|
||||
|
||||
return *iter;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
volatile int m_nLazyIndex;
|
||||
};
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
class HMultiplexSocketDispatchThread : public HThread
|
||||
{
|
||||
public:
|
||||
HMultiplexSocketDispatchThread()
|
||||
: HThread(true, 1024 * 1024 * 4) // stack size : 4MB
|
||||
{
|
||||
m_pMpsDispatcher = new HMpsDispatcher;
|
||||
}
|
||||
|
||||
~HMultiplexSocketDispatchThread()
|
||||
{
|
||||
delete m_pMpsDispatcher;
|
||||
}
|
||||
|
||||
inline HMpsDispatcher * GetDispatcher() { return m_pMpsDispatcher; }
|
||||
|
||||
inline void DispatchLock() { m_pMpsDispatcher->m_syncObject.Lock(); }
|
||||
inline void DispatchUnlock() { m_pMpsDispatcher->m_syncObject.Unlock(); }
|
||||
|
||||
inline unsigned long BeginDispatch(unsigned long nLoopInterval = 50)
|
||||
{
|
||||
m_pMpsDispatcher->Initialize(nLoopInterval);
|
||||
return HThread::Begin();
|
||||
}
|
||||
|
||||
void Terminate()
|
||||
{
|
||||
m_pMpsDispatcher->SetTerminateFlag();
|
||||
}
|
||||
|
||||
protected:
|
||||
void Main() { m_pMpsDispatcher->Dispatch(); }
|
||||
|
||||
private:
|
||||
inline unsigned long Begin() { return 0; } // do not use
|
||||
|
||||
private:
|
||||
HMpsDispatcher * m_pMpsDispatcher;
|
||||
};
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
template<class _Ty>
|
||||
class HMultiplexListenThread : public HThread
|
||||
{
|
||||
public:
|
||||
HMultiplexListenThread()
|
||||
: HThread(true, 0)
|
||||
{
|
||||
m_sockListen = INVALID_SOCKET;
|
||||
m_bTerminate = false;
|
||||
}
|
||||
|
||||
~HMultiplexListenThread() {}
|
||||
|
||||
inline void SetDispatcherList(HMpsDispatcherList * pList) { m_pListDispatcher = pList; }
|
||||
|
||||
bool Listen(const char * pszAddress, u_short nPort, int nBackLog = 10)
|
||||
{
|
||||
if (m_sockListen != INVALID_SOCKET)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpLstnThr, This socket aleady created. socket = %d\n", m_sockListen);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((m_sockListen = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpLstnThr, Don't create socket. Error = %d\n", SockErrorNo());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set non blocking mode
|
||||
#ifdef _WIN32
|
||||
ULONG nNonBlock = 1;
|
||||
if (ioctlsocket(m_sockListen, FIONBIO, &nNonBlock) == SOCKET_ERROR)
|
||||
{
|
||||
m_sockListen = INVALID_SOCKET;
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpLstnThrd, Failed to ioctlsocket, socket = %d, error = %d\n", m_sockListen, SockErrorNo());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
int nFlags = fcntl(m_sockListen, F_GETFL, 0);
|
||||
fcntl(m_sockListen, F_SETFL, nFlags | O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
struct sockaddr_in sai;
|
||||
memset(&sai, 0, sizeof(struct sockaddr_in));
|
||||
|
||||
if (pszAddress == NULL || pszAddress[0] == '\0')
|
||||
sai.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
else
|
||||
sai.sin_addr.s_addr = inet_addr(pszAddress);
|
||||
|
||||
sai.sin_family = AF_INET;
|
||||
sai.sin_port = htons(nPort);
|
||||
|
||||
#ifdef REUSEADDR
|
||||
int nOptVal = 1;
|
||||
setsockopt(m_sockListen, SOL_SOCKET, SO_REUSEADDR, (const char *)&nOptVal, sizeof(nOptVal)); // for multiple ip in UNIX
|
||||
#endif
|
||||
if (bind(m_sockListen, (struct sockaddr *)&sai, sizeof(struct sockaddr)) < 0)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpLstnThrd, Failed to bind, (%s:%d), socket = %d, error = %d\n", pszAddress, nPort, m_sockListen, SockErrorNo());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (listen(m_sockListen, nBackLog) == SOCKET_ERROR)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpLstnThrd, Failed to listen, (%s:%d), socket = %d, error = %d\n", pszAddress, nPort, m_sockListen, SockErrorNo());
|
||||
return false;
|
||||
}
|
||||
|
||||
HLOGF(HLOG_INFO1, "INFO, MpLstnThrd, Succeed to listen TCP, (%s:%d), socket = %d\n", pszAddress, nPort, m_sockListen);
|
||||
|
||||
m_strListenIp = pszAddress;
|
||||
m_nListenPort = nPort;
|
||||
|
||||
Begin();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Terminate()
|
||||
{
|
||||
closesocket(m_sockListen);
|
||||
|
||||
for (HMpsDispatcherList::iterator iter = m_pListDispatcher->begin(); iter != m_pListDispatcher->end(); iter++)
|
||||
{
|
||||
(*iter)->SetTerminateFlag(); // auto delete
|
||||
}
|
||||
|
||||
m_bTerminate = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
void Main()
|
||||
{
|
||||
HLOGF(HLOG_INFO5, "INFO, MpLstnThrd, listen thread begins, (%s:%d)\n", m_strListenIp.psz(), m_nListenPort);
|
||||
|
||||
fd_set fdSetRead;//, fdSetError;
|
||||
int nSelectResult;
|
||||
|
||||
SOCKET sockClient = INVALID_SOCKET;
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
struct sockaddr_in sai;
|
||||
|
||||
FD_ZERO(&fdSetRead);
|
||||
//FD_ZERO(&fdSetError);
|
||||
|
||||
while (m_bTerminate == false)
|
||||
{
|
||||
FD_SET(m_sockListen, &fdSetRead);
|
||||
//FD_SET(m_sockListen, &fdSetError);
|
||||
|
||||
if ((nSelectResult = select(m_sockListen + 1, &fdSetRead, NULL, NULL, NULL)) == SOCKET_ERROR)
|
||||
{
|
||||
Sleep(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((sockClient = accept(m_sockListen, (struct sockaddr *)&sai, &len)) == INVALID_SOCKET)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MpLstnThrd, Failed to accept, (%s:%d), socket = %d, error = %d\n", m_strListenIp.psz(), m_nListenPort, m_sockListen, SockErrorNo());
|
||||
Sleep(50);
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGF(HLOG_INFO4, "INFO, MpLstnThrd, Succeeded to accept, (%s:%d), (%s:%d), socket = %d\n", m_strListenIp.psz(), m_nListenPort, inet_ntoa(sai.sin_addr), ntohs(sai.sin_port), sockClient);
|
||||
|
||||
// Set non blocking mode
|
||||
#ifdef _WIN32
|
||||
ULONG nNonBlock = 1;
|
||||
if (ioctlsocket(sockClient, FIONBIO, &nNonBlock) == SOCKET_ERROR)
|
||||
HLOGF(HLOG_ERROR, "[ERROR], MpLstnThrd, Failed to ioctlsocket, socket = %d, error = %d\n", sockClient, SockErrorNo());
|
||||
#else
|
||||
int nFlags = fcntl(sockClient, F_GETFL, 0);
|
||||
fcntl(sockClient, F_SETFL, nFlags | O_NONBLOCK);
|
||||
#endif
|
||||
HMultiplexTcpSocket * pAcceptedSocket = OnAccept(sockClient, &sai);
|
||||
if (pAcceptedSocket)
|
||||
{
|
||||
pAcceptedSocket->m_nLastReceivedTime = HTIMER()->GetTickCount();
|
||||
pAcceptedSocket->OnAccepted();
|
||||
}
|
||||
else
|
||||
closesocket(sockClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
virtual HMultiplexTcpSocket * OnAccept(SOCKET sock, struct sockaddr_in * psaiRemote)
|
||||
{
|
||||
#if 1
|
||||
HMpsDispatcher * pDispatcher = m_pListDispatcher->GetLazyDispatcher();
|
||||
HMultiplexTcpSocket * pMpSocket = new _Ty(sock, psaiRemote, pDispatcher);
|
||||
pDispatcher->Attach(pMpSocket);
|
||||
return pMpSocket;
|
||||
#else
|
||||
HMpsDispatcherList::iterator iter;
|
||||
int i = 0;
|
||||
for (iter = m_pListDispatcher->begin(); iter != m_pListDispatcher->end(); iter++)
|
||||
{
|
||||
if ((*iter)->IsProcessing() == false)
|
||||
i++;
|
||||
}
|
||||
//HLOGF(HLOG_WARNING, "[TRACE], MplxLstnThr_0x%x, lazy dispatcher count = %d\n", this, i);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
for (iter = m_pListDispatcher->begin(); iter != m_pListDispatcher->end(); iter++)
|
||||
{
|
||||
if ((*iter)->IsProcessing() == false)
|
||||
{
|
||||
HMultiplexTcpSocket * pMpSocket = new _Ty(sock, psaiRemote, *iter);
|
||||
(*iter)->Attach(pMpSocket);
|
||||
return pMpSocket;
|
||||
}
|
||||
}
|
||||
|
||||
Sleep(10);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
HMpsDispatcherList * m_pListDispatcher;
|
||||
SOCKET m_sockListen;
|
||||
HString m_strListenIp;
|
||||
u_short m_nListenPort;
|
||||
volatile bool m_bTerminate;
|
||||
};
|
||||
|
||||
#endif // MULTIPLEX_SOCKET__H_
|
||||
@@ -0,0 +1,627 @@
|
||||
|
||||
#include "stringex.h"
|
||||
#include "Defines.h"
|
||||
#include "Common.h"
|
||||
#include "Object.h"
|
||||
#include "String.h"
|
||||
#include "Logger.h"
|
||||
#include "Socket.h"
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
#include "Thread.h"
|
||||
#endif
|
||||
|
||||
#include "Timer.h"
|
||||
#include "NetUtil.h"
|
||||
|
||||
#include "Global.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "MultiplexSocket.h"
|
||||
#include "MultiplexSslSocket.h"
|
||||
|
||||
|
||||
|
||||
//#include <limits.h>
|
||||
|
||||
/* common define */
|
||||
typedef int bool_t;
|
||||
//#define errlog printf
|
||||
|
||||
#if defined(_WIN32) /* Windows specific #includes and #defines */
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0400 /* To make it link in VS2005 */
|
||||
#endif
|
||||
|
||||
//#include <windows.h>
|
||||
#define SSL_LIB "ssleay32.dll"
|
||||
#define CRYPTO_LIB "libeay32.dll"
|
||||
|
||||
static HANDLE dlopen(const char *dll_name, int flags)
|
||||
{
|
||||
return (LoadLibraryA(dll_name));
|
||||
}
|
||||
|
||||
#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
|
||||
|
||||
#define RTLD_LAZY 0
|
||||
|
||||
#if _MSC_VER <= 1200
|
||||
#define __func__ ""
|
||||
#else
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/mman.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
|
||||
#define SSL_LIB "libssl.so"
|
||||
#define CRYPTO_LIB "libcrypto.so"
|
||||
|
||||
typedef int SOCKET;
|
||||
//#define false 0
|
||||
//#define true 1
|
||||
#define closesocket close
|
||||
|
||||
#endif
|
||||
|
||||
#include "openssl/ssl.h"
|
||||
#include "openssl/tls1.h"
|
||||
#include "openssl/err.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "libeay32.lib")
|
||||
#pragma comment(lib, "ssleay32.lib")
|
||||
#endif
|
||||
|
||||
|
||||
HSyncObject * g_arrSyncObject;
|
||||
void ssl_locking_callback(int mode, int n, const char *file, int line)
|
||||
{
|
||||
if (mode & CRYPTO_LOCK)
|
||||
g_arrSyncObject[n].Lock();
|
||||
else
|
||||
g_arrSyncObject[n].Unlock();
|
||||
}
|
||||
|
||||
/* This is a context that we pass to callbacks */
|
||||
typedef struct tlsextctx_st {
|
||||
BIO *biodebug;
|
||||
int ack;
|
||||
} tlsextctx;
|
||||
|
||||
static int ssl_servername_cb(SSL *s, int *ad, void *arg)
|
||||
{
|
||||
tlsextctx *p = (tlsextctx *) arg;
|
||||
const char *hn = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
|
||||
if (SSL_get_servername_type(s) != -1)
|
||||
p->ack = !SSL_session_reused(s) && hn != NULL;
|
||||
//else
|
||||
// BIO_printf(bio_err, "Can't use SSL_get_servername\n");
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
void ssl_init()
|
||||
{
|
||||
int nLockCount = CRYPTO_num_locks();
|
||||
g_arrSyncObject = new HSyncObject[nLockCount];
|
||||
|
||||
CRYPTO_set_locking_callback((void (*)(int, int, const char *, int))ssl_locking_callback);
|
||||
|
||||
/* Initialize SSL crap */
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
ERR_load_BIO_strings();
|
||||
ERR_load_crypto_strings();
|
||||
}
|
||||
|
||||
SSL_CTX * ssl_client_init(const char * pszHostName) //...
|
||||
{
|
||||
if (pszHostName[0])
|
||||
{
|
||||
//if (strcmp(GetDomainNamePtr(pszHostName), "igi-global.com") == 0) // www.igi-global.com
|
||||
// return SSL_CTX_new(TLSv1_1_client_method());
|
||||
if (strcmp(GetDomainNamePtr(pszHostName), "wipson.com") == 0 || // www.wipson.com
|
||||
strcmp(GetDomainNamePtr(pszHostName), "ibfd.org") == 0 || // www.ibfd.org
|
||||
strcmp(GetDomainNamePtr(pszHostName), "igi-global.com") == 0 || // www.igi-global.com
|
||||
strcmp(GetDomainNamePtr(pszHostName), "wisdomain.com") == 0 || // www.igi-global.com
|
||||
strcmp(GetDomainNamePtr(pszHostName), "tobaccojournal.com") == 0 || // www.tobaccojournal.com
|
||||
strcmp(GetDomainNamePtr(pszHostName), "cabdirect.org") == 0 || // www.tobaccojournal.com
|
||||
strcmp(GetDomainNamePtr(pszHostName), "ebsco.com") == 0)// || // atoz.ebsco.com
|
||||
//strcmp(GetDomainNamePtr(pszHostName), "refworks.com") == 0) // www.refworks.com
|
||||
return SSL_CTX_new(TLSv1_client_method());
|
||||
else if (strcmp(GetDomainNamePtr(pszHostName), "dbpia.co.kr") == 0)
|
||||
return SSL_CTX_new(SSLv23_client_method());
|
||||
//else if (strcmp(pszHostName, "saemobilus.sae.org") == 0 ||
|
||||
// strcmp(pszHostName, "www.samsungdesign.net") == 0)
|
||||
// return SSL_CTX_new(TLSv1_2_client_method());
|
||||
|
||||
//return SSL_CTX_new(SSLv23_client_method()); // www.samsungdesign.net, hb8xw4yu6z.search.serialssolutions.com fail
|
||||
//return SSL_CTX_new(TLSv1_client_method()); // saemobilus.sae.org fail
|
||||
}
|
||||
|
||||
return SSL_CTX_new(TLSv1_2_client_method());
|
||||
}
|
||||
|
||||
int verify_callback(int ok, X509_STORE_CTX *store)
|
||||
{
|
||||
char data[256];
|
||||
|
||||
/* if (ok) to debug */
|
||||
if (!ok)
|
||||
{
|
||||
X509 *cert = X509_STORE_CTX_get_current_cert(store);
|
||||
int depth = X509_STORE_CTX_get_error_depth(store);
|
||||
int err = X509_STORE_CTX_get_error(store);
|
||||
|
||||
fprintf(stderr, "-Error with certificate at depth: %i\n", depth);
|
||||
X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
|
||||
fprintf(stderr, " issuer = %s\n", data);
|
||||
X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
|
||||
fprintf(stderr, " subject = %s\n", data);
|
||||
fprintf(stderr, " err %i:%s\n", err, X509_verify_cert_error_string(err) );
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
SSL_CTX * ssl_server_init(const char * pszCertPath, const char * pszKeyPath, const char * pszCaPath)
|
||||
{
|
||||
SSL_CTX * ssl_ctx = SSL_CTX_new(SSLv23_server_method());
|
||||
if (ssl_ctx == NULL)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Failed to SSL_CTX_new in ssl_server_init\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//if (ctx->ssl_password_callback != NULL)
|
||||
// SSL_CTX_set_default_passwd_cb(CTX, ctx->ssl_password_callback);
|
||||
|
||||
if (SSL_CTX_use_certificate_file(ssl_ctx, pszCertPath, SSL_FILETYPE_PEM) == 0)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Failed to SSL_CTX_use_certificate_file, %s\n", pszCertPath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, pszKeyPath, SSL_FILETYPE_PEM) == 0)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Failed to SSL_CTX_use_certificate_file, %s\n", pszKeyPath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
sprintf(szPemFile, "%slibproxy_chain.pem", pszAppDir);
|
||||
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, szPemFile) == 0)
|
||||
{
|
||||
HLOGF(2, "openssl\t[ERROR] Failed to SSL_CTX_use_certificate_chain_file, %s\n", szPemFile);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
/* Load the CAs we trust*/
|
||||
if (SSL_CTX_load_verify_locations(ssl_ctx, pszCaPath, 0) == 0)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Failed to SSL_CTX_load_verify_locations, %s\n", pszCaPath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//SSL_CTX_set_verify_depth(ssl_ctx, 1);
|
||||
//SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, verify_callback);
|
||||
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
void ssl_ctx_destroy(SSL_CTX * ssl_ctx)
|
||||
{
|
||||
if (!ssl_ctx)
|
||||
return;
|
||||
|
||||
SSL_CTX_free(ssl_ctx);
|
||||
}
|
||||
|
||||
int ssl_send(SSL * ssl, char * buf, int len, int flags)
|
||||
{
|
||||
if (!ssl)
|
||||
return -1;
|
||||
|
||||
return SSL_write(ssl, buf, len);
|
||||
}
|
||||
|
||||
int ssl_recv(SSL * ssl, char * buf, int len, int flags)
|
||||
{
|
||||
if (!ssl)
|
||||
return -1;
|
||||
|
||||
return SSL_read(ssl, buf, len);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SSL_CTX * HMultiplexSslSocket::m_sslCtxServer = NULL;
|
||||
|
||||
void HMultiplexSslSocket::SslInit(const char * pszCertPath, const char * pszKeyPath, const char * pszCaPath)
|
||||
{
|
||||
static bool bIsSslInit = false;
|
||||
if (bIsSslInit == false)
|
||||
{
|
||||
bIsSslInit = true;
|
||||
|
||||
ssl_init();
|
||||
|
||||
HMultiplexSslSocket::m_sslCtxServer = ssl_server_init(pszCertPath, pszKeyPath, pszCaPath);
|
||||
}
|
||||
}
|
||||
|
||||
void HMultiplexSslSocket::SslDestroy()
|
||||
{
|
||||
ssl_ctx_destroy(m_sslCtxServer);
|
||||
m_sslCtxServer = NULL;
|
||||
|
||||
ERR_remove_state(0);
|
||||
//ENGINE_cleanup();
|
||||
//CONF_modules_unload(1);
|
||||
ERR_free_strings();
|
||||
EVP_cleanup();
|
||||
sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
|
||||
delete [] g_arrSyncObject;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
HMultiplexSslSocket::HMultiplexSslSocket()
|
||||
{
|
||||
m_ssl_ctx = NULL;
|
||||
m_ssl = NULL;
|
||||
m_rbio = NULL;
|
||||
m_pStreamBufferForDecrypt = new HStreamBuffer(65536);
|
||||
m_wbio = NULL;
|
||||
m_pStreamBufferForSend = new HStreamBuffer(SSL3_RT_MAX_PACKET_SIZE);
|
||||
|
||||
m_pBufferForRecv = (char *)malloc(g_nSocketReceiveBlockSize);
|
||||
|
||||
m_szDstServerName[0] = '\0';
|
||||
m_bIsSslConnecting = false;
|
||||
|
||||
m_bEncryptRetry = false;
|
||||
}
|
||||
|
||||
HMultiplexSslSocket::HMultiplexSslSocket(SOCKET sock, struct sockaddr_in * psaiRemote, HMpsDispatcher * pDispatcher)
|
||||
: HMultiplexTcpSocket(sock, psaiRemote, pDispatcher)
|
||||
{
|
||||
m_ssl_ctx = NULL;
|
||||
m_ssl = NULL;
|
||||
m_rbio = NULL;
|
||||
m_pStreamBufferForDecrypt = new HStreamBuffer(65536);
|
||||
m_wbio = NULL;
|
||||
m_pStreamBufferForSend = new HStreamBuffer(SSL3_RT_MAX_PACKET_SIZE);
|
||||
|
||||
m_pBufferForRecv = (char *)malloc(g_nSocketReceiveBlockSize);
|
||||
|
||||
m_szDstServerName[0] = '\0';
|
||||
m_bIsSslConnecting = false;
|
||||
|
||||
m_bEncryptRetry = false;
|
||||
}
|
||||
|
||||
HMultiplexSslSocket::~HMultiplexSslSocket()
|
||||
{
|
||||
if (m_ssl)
|
||||
SSL_free(m_ssl);
|
||||
|
||||
if (m_ssl_ctx != m_sslCtxServer)
|
||||
ssl_ctx_destroy(m_ssl_ctx);
|
||||
|
||||
delete m_pStreamBufferForDecrypt;
|
||||
delete m_pStreamBufferForSend;
|
||||
|
||||
free(m_pBufferForRecv);
|
||||
}
|
||||
|
||||
bool HMultiplexSslSocket::Close()
|
||||
{
|
||||
if (m_nState == MPS_DISABLE ||
|
||||
(m_nState == MPS_DELETE && m_fdSocket == INVALID_SOCKET))
|
||||
//if (m_fdSocket == INVALID_SOCKET)
|
||||
return false;
|
||||
|
||||
OnClose();
|
||||
|
||||
if (m_nState != MPS_LISTENING)
|
||||
shutdown(m_fdSocket, SD_BOTH);
|
||||
|
||||
if (m_nState != MPS_DELETE)
|
||||
m_nState = MPS_DISABLE;
|
||||
|
||||
SSL_free(m_ssl); // free the SSL object and its BIO's
|
||||
m_ssl = NULL;
|
||||
closesocket(m_fdSocket);
|
||||
|
||||
HLOGF(HLOG_INFO5, "INFO, SslSock, socket closed, socket = %d\n", m_fdSocket);
|
||||
|
||||
m_fdSocket = INVALID_SOCKET;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int HMultiplexSslSocket::Send(const char * pData, int nSize)
|
||||
{
|
||||
if ((size_t)nSize > m_pStreamBufferForSend->RemainSize())
|
||||
{
|
||||
SendBufferedData();
|
||||
|
||||
m_bEncryptRetry = true;
|
||||
m_bSendRetry = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!SSL_is_init_finished(m_ssl))
|
||||
{
|
||||
m_bEncryptRetry = true;
|
||||
m_bSendRetry = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char * pDataOffset = pData;
|
||||
int nRemainSize = nSize;
|
||||
int nResult;
|
||||
int nSslError;
|
||||
|
||||
while (nRemainSize > 0)
|
||||
{
|
||||
nResult = SSL_write(m_ssl, pDataOffset, nRemainSize);
|
||||
nSslError = SSL_get_error(m_ssl, nResult);
|
||||
|
||||
if (nResult > 0)
|
||||
{
|
||||
pDataOffset += nResult;
|
||||
nRemainSize -= nResult;
|
||||
|
||||
do
|
||||
{
|
||||
nResult = BIO_read(m_wbio, m_pStreamBufferForSend->Tail(), m_pStreamBufferForSend->RemainSize());
|
||||
if (nResult > 0)
|
||||
m_pStreamBufferForSend->MoveTail(nResult);
|
||||
else if (!BIO_should_retry(m_wbio))
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "SSL_TRACE, 1, socket = %d\n", m_fdSocket);
|
||||
m_nState = MPS_CLOSING;
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
} while (nResult > 0);
|
||||
}
|
||||
|
||||
if (nSslError != SSL_ERROR_NONE && nSslError != SSL_ERROR_WANT_WRITE && nSslError != SSL_ERROR_WANT_READ)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], SslSock, socket = %d, error = %d, %d\n", m_fdSocket, nSslError, nResult);
|
||||
m_nState = MPS_CLOSING;
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
if (nResult == 0)
|
||||
break;
|
||||
}
|
||||
m_bEncryptRetry = false;
|
||||
|
||||
if (m_pStreamBufferForSend->StoredSize() > 0)
|
||||
SendBufferedData();
|
||||
|
||||
if (nRemainSize > 0)
|
||||
{
|
||||
m_bEncryptRetry = true;
|
||||
m_bSendRetry = true;
|
||||
return nSize - nRemainSize;
|
||||
}
|
||||
|
||||
return nSize;
|
||||
}
|
||||
|
||||
int HMultiplexSslSocket::SendBufferedData()
|
||||
{
|
||||
if (m_pStreamBufferForSend->StoredSize() == 0)
|
||||
return SOCKET_ERROR;
|
||||
|
||||
int nSentSize = HMultiplexTcpSocket::Send(m_pStreamBufferForSend->Head(), m_pStreamBufferForSend->StoredSize());
|
||||
if (nSentSize <= 0)
|
||||
return nSentSize;
|
||||
|
||||
m_pStreamBufferForSend->Pop(nSentSize);
|
||||
return nSentSize;
|
||||
}
|
||||
|
||||
int HMultiplexSslSocket::Receive()
|
||||
{
|
||||
int nReceivedSize = HMultiplexTcpSocket::Receive(m_pBufferForRecv, g_nSocketReceiveBlockSize);
|
||||
if (nReceivedSize <= 0)
|
||||
return nReceivedSize;
|
||||
|
||||
char * pBufferOffset = m_pBufferForRecv;
|
||||
|
||||
int nResult;
|
||||
while (nReceivedSize > 0)
|
||||
{
|
||||
nResult = BIO_write(m_rbio, pBufferOffset, nReceivedSize);
|
||||
if (nResult <= 0)
|
||||
{
|
||||
HLOGF(HLOG_INFO4, "INFO, SslSock, assume bio write failure is unrecoverable, socket = %d\n", m_fdSocket);
|
||||
m_nState = MPS_CLOSING;
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
pBufferOffset += nResult;
|
||||
nReceivedSize -= nResult;
|
||||
|
||||
if (!SSL_is_init_finished(m_ssl))
|
||||
{
|
||||
if (ProcHandShake() == false)
|
||||
{
|
||||
if (m_bIsSslConnecting)
|
||||
OnConnectChild(false);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!SSL_is_init_finished(m_ssl))
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
nResult = SSL_read(m_ssl, m_pStreamBufferForDecrypt->Tail(), m_pStreamBufferForDecrypt->RemainSize());
|
||||
if (nResult > 0)
|
||||
m_pStreamBufferForDecrypt->MoveTail(nResult);
|
||||
} while (nResult > 0);
|
||||
|
||||
int nSslError = SSL_get_error(m_ssl, nResult);
|
||||
if (nSslError == SSL_ERROR_WANT_WRITE || nSslError == SSL_ERROR_WANT_READ)
|
||||
{
|
||||
do
|
||||
{
|
||||
nResult = BIO_read(m_wbio, m_pStreamBufferForSend->Tail(), m_pStreamBufferForSend->RemainSize());
|
||||
if (nResult > 0)
|
||||
m_pStreamBufferForSend->MoveTail(nResult);
|
||||
else if (!BIO_should_retry(m_wbio))
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "TRACE, SslSock, 1. Did SSL request to write bytes? This can happen if peer has requested SSL * renegotiation, socket = %d, %d, %d\n", m_fdSocket, nSslError, nResult);
|
||||
m_nState = MPS_CLOSING;
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
} while (nResult > 0);
|
||||
}
|
||||
else if (nSslError == SSL_ERROR_ZERO_RETURN || nSslError == SSL_ERROR_SYSCALL)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "TRACE, SslSock, 2. Did SSL request to write bytes? This can happen if peer has requested SSL * renegotiation, socket = %d, %d, %d\n", m_fdSocket, nSslError, nResult);
|
||||
//...???
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pStreamBufferForSend->StoredSize() > 0)
|
||||
SendBufferedData();
|
||||
|
||||
if (m_bIsSslConnecting)
|
||||
{
|
||||
m_bIsSslConnecting = false;
|
||||
OnConnectChild(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_pStreamBufferForDecrypt->StoredSize();
|
||||
}
|
||||
|
||||
bool HMultiplexSslSocket::SetRemoteAddressHostByName(const char * pszHostName, u_short nPort)
|
||||
{
|
||||
strcpy(m_szDstServerName, pszHostName);
|
||||
return HMultiplexTcpSocket::SetRemoteAddressHostByName(pszHostName, nPort);
|
||||
}
|
||||
|
||||
bool HMultiplexSslSocket::IsRemain()
|
||||
{
|
||||
if (m_ssl == NULL)
|
||||
return false;
|
||||
|
||||
return SSL_pending(m_ssl) > 0;
|
||||
}
|
||||
|
||||
void HMultiplexSslSocket::OnConnect(bool bIsSuccess)
|
||||
{
|
||||
if (bIsSuccess)
|
||||
{
|
||||
m_ssl_ctx = ssl_client_init(m_szDstServerName);
|
||||
//tlsextcbp.biodebug = bio_err;
|
||||
//SSL_CTX_set_tlsext_servername_callback(m_ssl_ctx, ssl_servername_cb);
|
||||
//SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp);
|
||||
|
||||
if ((m_ssl = SSL_new(m_ssl_ctx)) == NULL)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Faield to SSL_new 1, socket = %d\n", m_fdSocket);
|
||||
OnConnectChild(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_szDstServerName[0] && !SSL_set_tlsext_host_name(m_ssl, m_szDstServerName))
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Unable to set TLS servername extension, socket = %d\n", m_fdSocket);
|
||||
OnConnectChild(false);
|
||||
return;
|
||||
}
|
||||
|
||||
SSL_set_connect_state(m_ssl);
|
||||
|
||||
m_rbio = BIO_new(BIO_s_mem());
|
||||
m_wbio = BIO_new(BIO_s_mem());
|
||||
SSL_set_bio(m_ssl, m_rbio, m_wbio);
|
||||
|
||||
m_bIsSslConnecting = true;
|
||||
|
||||
ProcHandShake();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnConnectChild(false);
|
||||
}
|
||||
}
|
||||
|
||||
void HMultiplexSslSocket::OnAccepted()
|
||||
{
|
||||
if ((m_ssl = SSL_new(m_sslCtxServer)) == NULL)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Faield to SSL_new 2, socket = %d\n", m_fdSocket);
|
||||
return;
|
||||
}
|
||||
|
||||
m_ssl_ctx = m_sslCtxServer;
|
||||
|
||||
SSL_set_accept_state(m_ssl);
|
||||
|
||||
m_rbio = BIO_new(BIO_s_mem());
|
||||
m_wbio = BIO_new(BIO_s_mem());
|
||||
SSL_set_bio(m_ssl, m_rbio, m_wbio);
|
||||
|
||||
//m_bIsSslConnecting = true;
|
||||
}
|
||||
|
||||
bool HMultiplexSslSocket::ProcHandShake()
|
||||
{
|
||||
int nSslResult = SSL_do_handshake(m_ssl);
|
||||
int nSslError = SSL_get_error(m_ssl, nSslResult);
|
||||
if (nSslError == SSL_ERROR_WANT_WRITE || nSslError == SSL_ERROR_WANT_READ)
|
||||
{
|
||||
do
|
||||
{
|
||||
nSslResult = BIO_read(m_wbio, m_pStreamBufferForSend->Tail(), m_pStreamBufferForSend->RemainSize());
|
||||
if (nSslResult > 0)
|
||||
m_pStreamBufferForSend->MoveTail(nSslResult);
|
||||
else if (!BIO_should_retry(m_wbio))
|
||||
{
|
||||
m_pStreamBufferForSend->Reset();
|
||||
HLOGF(HLOG_WARNING, "[WARN], SslSock, Failed to HandShake 1, socket = %d, error = %d\n", m_fdSocket, nSslError);
|
||||
return false;
|
||||
}
|
||||
} while (nSslResult > 0);
|
||||
|
||||
if (m_pStreamBufferForSend->StoredSize() > 0)
|
||||
SendBufferedData();
|
||||
}
|
||||
else if (nSslError == SSL_ERROR_ZERO_RETURN || nSslError == SSL_ERROR_SYSCALL)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], SslSock, Failed to HandShake 2, socket = %d, error = %d\n", m_fdSocket, nSslError);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#ifndef MULTIPLEX_SSL_SOCKET__H_
|
||||
#define MULTIPLEX_SSL_SOCKET__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct ssl_ctx_st SSL_CTX;
|
||||
typedef struct ssl_st SSL;
|
||||
typedef struct bio_st BIO;
|
||||
|
||||
|
||||
class HMultiplexSslSocket : public HMultiplexTcpSocket
|
||||
{
|
||||
public:
|
||||
static SSL_CTX * m_sslCtxClient;
|
||||
static SSL_CTX * m_sslCtxServer;
|
||||
|
||||
static void SslInit(const char * pszCertPath, const char * pszKeyPath, const char * pszCaPath);
|
||||
static void SslDestroy();
|
||||
//
|
||||
|
||||
HMultiplexSslSocket();
|
||||
HMultiplexSslSocket(SOCKET sock, struct sockaddr_in * psaiRemote, HMpsDispatcher * pDispatcher);
|
||||
~HMultiplexSslSocket();
|
||||
|
||||
bool Close();
|
||||
|
||||
int Send(const char * pData, int nSize);
|
||||
int SendBufferedData();
|
||||
//int Receive(char * pBuffer, int nSize);
|
||||
int Receive();
|
||||
|
||||
bool SetRemoteAddressHostByName(const char * pszHostName, u_short nPort);
|
||||
bool IsRemain();
|
||||
|
||||
inline bool IsEncryptRetry() { return m_bEncryptRetry; }
|
||||
|
||||
virtual bool IsSslSocket() { return true; }
|
||||
|
||||
protected:
|
||||
enum {
|
||||
TIMER_CHANNEL_CLOSE = 100,
|
||||
TIMER_CHECK_RECEIVE = 101
|
||||
};
|
||||
|
||||
void OnConnect(bool bIsSuccess);
|
||||
virtual void OnConnectChild(bool bIsSuccess) {}
|
||||
|
||||
void OnAccepted();
|
||||
//virtual void OnAcceptedChild() {}
|
||||
|
||||
bool ProcHandShake();
|
||||
|
||||
protected:
|
||||
SSL_CTX * m_ssl_ctx;
|
||||
SSL * m_ssl;
|
||||
BIO * m_rbio;
|
||||
HStreamBuffer * m_pStreamBufferForDecrypt;
|
||||
BIO * m_wbio;
|
||||
HStreamBuffer * m_pStreamBufferForSend;
|
||||
|
||||
char * m_pBufferForRecv;
|
||||
|
||||
char m_szDstServerName[512];
|
||||
bool m_bIsSslConnecting; //...
|
||||
bool m_bEncryptRetry;
|
||||
};
|
||||
|
||||
#endif // MULTIPLEX_SSL_SOCKET__H_
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
#ifndef MULTIPLEX_TRANSPORT__H_
|
||||
#define MULTIPLEX_TRANSPORT__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HMultiplexTransportTcpSocket;
|
||||
|
||||
|
||||
class HMultiplexTransport : public HTransport
|
||||
{
|
||||
public:
|
||||
HMultiplexTransport() {}
|
||||
~HMultiplexTransport() {}
|
||||
|
||||
inline void SetMpSocket(HMultiplexTcpSocket * pSocket) { m_pMulplexTransportSocket = pSocket; }
|
||||
inline HMultiplexTcpSocket * GetMpSocket() { return m_pMulplexTransportSocket; }
|
||||
|
||||
inline bool GetTransportInfo(const char * pName, void * pValue);
|
||||
|
||||
inline void Terminate();
|
||||
|
||||
inline int Send(const char * pData, int nSize);
|
||||
|
||||
protected:
|
||||
HMultiplexTcpSocket * m_pMulplexTransportSocket;
|
||||
|
||||
|
||||
friend class HMultiplexTransportTcpSocket;
|
||||
friend class HMultiplexTransportSslSocket;
|
||||
};
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
class HMultiplexTransportTcpSocket : public HMultiplexTcpSocket
|
||||
{
|
||||
public:
|
||||
HMultiplexTransportTcpSocket()
|
||||
{
|
||||
m_bAutoDelete = false;
|
||||
m_nReconnectTime = 0;
|
||||
m_pReceiveBuffer = (char *)malloc(g_nSocketReceiveBlockSize + 1);
|
||||
m_pTransport = NULL;
|
||||
}
|
||||
|
||||
HMultiplexTransportTcpSocket(SOCKET sock, struct sockaddr_in * psaiRemote, HMpsDispatcher * pDispatcher)
|
||||
: HMultiplexTcpSocket(sock, psaiRemote, pDispatcher)
|
||||
{
|
||||
m_bAutoDelete = false;
|
||||
m_nReconnectTime = 0;
|
||||
m_pReceiveBuffer = (char *)malloc(g_nSocketReceiveBlockSize + 1);
|
||||
m_pTransport = NULL;
|
||||
}
|
||||
|
||||
~HMultiplexTransportTcpSocket()
|
||||
{
|
||||
if (m_pTransport)
|
||||
delete m_pTransport;
|
||||
|
||||
free(m_pReceiveBuffer);
|
||||
}
|
||||
|
||||
inline void AttachTransport(HMultiplexTransport * pTransport) { m_pTransport = pTransport; }
|
||||
inline HMultiplexTransport * GetTransport() { return m_pTransport; }
|
||||
|
||||
inline void SetAutoDelete(bool bAutoDelete) { m_bAutoDelete = bAutoDelete; }
|
||||
inline void SetAutoReconnect(DWORD nTime) { m_nReconnectTime = nTime; }
|
||||
|
||||
protected:
|
||||
inline void OnClose()
|
||||
{
|
||||
if (m_bAutoDelete)
|
||||
SetState(MPS_DELETE); // auto delete
|
||||
else if (m_nReconnectTime > 0)
|
||||
SetTimer(2181006, m_nReconnectTime);
|
||||
|
||||
m_pTransport->OnReceivedStatus(HTransport::T_END_TRANSPORT);
|
||||
}
|
||||
|
||||
inline void OnConnect(bool bIsSuccess)
|
||||
{
|
||||
if (bIsSuccess == false)
|
||||
{
|
||||
m_pTransport->OnReceivedStatus(HTransport::T_FAILED_BEGIN);
|
||||
return;
|
||||
}
|
||||
|
||||
m_pTransport->OnReceivedStatus(HTransport::T_BEGIN_TRANSPORT);
|
||||
}
|
||||
|
||||
inline void OnReceive()
|
||||
{
|
||||
if (m_pTransport == NULL)
|
||||
return;
|
||||
|
||||
if (m_pTransport->OnPrepareReceive() == false)
|
||||
return;
|
||||
|
||||
int nReceivedSize = Receive(m_pReceiveBuffer, g_nSocketReceiveBlockSize);
|
||||
if (nReceivedSize <= 0)
|
||||
return;
|
||||
|
||||
if (m_pTransport->OnReceived(m_pReceiveBuffer, nReceivedSize) < 0)
|
||||
FinishTcp();
|
||||
}
|
||||
|
||||
inline int OnSendRetry()
|
||||
{
|
||||
return m_pTransport->OnSendRetry();
|
||||
}
|
||||
|
||||
inline void OnAccepted()
|
||||
{
|
||||
m_pTransport->OnReceivedStatus(HTransport::T_BEGIN_TRANSPORT);
|
||||
}
|
||||
|
||||
ON_TIMER(HMultiplexTransportTcpSocket, OnTimer) // add void OnTimer(DWORD nTimerID) {}
|
||||
|
||||
protected:
|
||||
char * m_pReceiveBuffer;
|
||||
bool m_bAutoDelete;
|
||||
DWORD m_nReconnectTime;
|
||||
|
||||
HMultiplexTransport * m_pTransport;
|
||||
};
|
||||
|
||||
inline void HMultiplexTransportTcpSocket::OnTimer(unsigned int nTimerId)
|
||||
{
|
||||
KillTimer(2181006);
|
||||
Create();
|
||||
Connect(0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
class HMultiplexTransportSslSocket : public HMultiplexSslSocket
|
||||
{
|
||||
public:
|
||||
HMultiplexTransportSslSocket()
|
||||
{
|
||||
m_bAutoDelete = false;
|
||||
m_nReconnectTime = 0;
|
||||
m_pTransport = NULL;
|
||||
}
|
||||
|
||||
HMultiplexTransportSslSocket(SOCKET sock, struct sockaddr_in * psaiRemote, HMpsDispatcher * pDispatcher)
|
||||
: HMultiplexSslSocket(sock, psaiRemote, pDispatcher)
|
||||
{
|
||||
m_bAutoDelete = false;
|
||||
m_nReconnectTime = 0;
|
||||
m_pTransport = NULL;
|
||||
}
|
||||
|
||||
~HMultiplexTransportSslSocket()
|
||||
{
|
||||
if (m_pTransport)
|
||||
delete m_pTransport;
|
||||
}
|
||||
|
||||
inline void AttachTransport(HMultiplexTransport * pTransport) { m_pTransport = pTransport; }
|
||||
inline HMultiplexTransport * GetTransport() { return m_pTransport; }
|
||||
|
||||
inline void SetAutoDelete(bool bAutoDelete) { m_bAutoDelete = bAutoDelete; }
|
||||
inline void SetAutoReconnect(DWORD nTime) { m_nReconnectTime = nTime; }
|
||||
|
||||
inline void OnAccepted()
|
||||
{
|
||||
HMultiplexSslSocket::OnAccepted();
|
||||
|
||||
m_pTransport->OnReceivedStatus(HTransport::T_BEGIN_TRANSPORT);
|
||||
}
|
||||
|
||||
protected:
|
||||
inline void OnClose()
|
||||
{
|
||||
if (m_bAutoDelete)
|
||||
SetState(MPS_DELETE); // auto delete
|
||||
else if (m_nReconnectTime > 0)
|
||||
SetTimer(2181006, m_nReconnectTime);
|
||||
|
||||
m_pTransport->OnReceivedStatus(HTransport::T_END_TRANSPORT);
|
||||
}
|
||||
|
||||
inline void OnReceive()
|
||||
{
|
||||
if (m_pTransport == NULL)
|
||||
return;
|
||||
|
||||
if (m_pTransport->OnPrepareReceive() == false)
|
||||
return;
|
||||
|
||||
Receive();
|
||||
|
||||
while (m_pStreamBufferForDecrypt->StoredSize() > 0)
|
||||
{
|
||||
//HLOGF(HLOG_WARNING, "SSL_TRACE, recv size = %d\n", m_pStreamBufferForDecrypt->StoredSize());
|
||||
//HLOGD(HLOG_WARNING, m_pStreamBufferForDecrypt->Head(), 40, true);
|
||||
|
||||
if (m_pStreamBufferForDecrypt->StoredSize() > (size_t)g_nSocketReceiveBlockSize)
|
||||
{
|
||||
if (m_pTransport->OnReceived(m_pStreamBufferForDecrypt->Head(), g_nSocketReceiveBlockSize) < 0)
|
||||
{
|
||||
FinishTcp();
|
||||
return;
|
||||
}
|
||||
m_pStreamBufferForDecrypt->Pop(g_nSocketReceiveBlockSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_pTransport->OnReceived(m_pStreamBufferForDecrypt->Head(), m_pStreamBufferForDecrypt->StoredSize()) < 0)
|
||||
{
|
||||
FinishTcp();
|
||||
return;
|
||||
}
|
||||
m_pStreamBufferForDecrypt->Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline int OnSendRetry()
|
||||
{
|
||||
if (m_bEncryptRetry)
|
||||
return m_pTransport->OnSendRetry();
|
||||
|
||||
return SendBufferedData();
|
||||
}
|
||||
|
||||
inline void OnConnectChild(bool bIsSuccess)
|
||||
{
|
||||
if (bIsSuccess == false)
|
||||
{
|
||||
SetState(MPS_CLOSING);
|
||||
m_pTransport->OnReceivedStatus(HTransport::T_FAILED_BEGIN);
|
||||
return;
|
||||
}
|
||||
|
||||
m_pTransport->OnReceivedStatus(HTransport::T_BEGIN_TRANSPORT);
|
||||
}
|
||||
|
||||
ON_TIMER(HMultiplexTransportSslSocket, OnTimer) // add void OnTimer(DWORD nTimerID) {}
|
||||
|
||||
protected:
|
||||
bool m_bAutoDelete;
|
||||
DWORD m_nReconnectTime;
|
||||
|
||||
HMultiplexTransport * m_pTransport;
|
||||
};
|
||||
|
||||
inline void HMultiplexTransportSslSocket::OnTimer(unsigned int nTimerId)
|
||||
{
|
||||
KillTimer(2181006);
|
||||
Create();
|
||||
Connect(0);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
inline bool HMultiplexTransport::GetTransportInfo(const char * pName, void * pValue)
|
||||
{
|
||||
if (strcmp(pName, "peer_ip") == 0)
|
||||
{
|
||||
int nResult = m_pMulplexTransportSocket->GetPeerAddress((char *)pValue, NULL);
|
||||
if (nResult)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MplxTrnsp, Failed to GetPeerAddress 1, error = %d\n", nResult);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(pName, "peer_port") == 0)
|
||||
{
|
||||
int nResult = m_pMulplexTransportSocket->GetPeerAddress(NULL, (u_short *)pValue);
|
||||
if (nResult)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MplxTrnsp, Failed to GetPeerAddress 2, error = %d\n", nResult);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(pName, "peer_address") == 0)
|
||||
{
|
||||
char szIp[32];
|
||||
u_short nPort = 0;
|
||||
int nResult = m_pMulplexTransportSocket->GetPeerAddress(szIp, &nPort);
|
||||
if (nResult)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], MplxTrnsp, Failed to GetPeerAddress 3, error = %d\n", nResult);
|
||||
return false;
|
||||
}
|
||||
sprintf((char *)pValue, "%s:%d", szIp, nPort);
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(pName, "is_ssl_socket") == 0)
|
||||
{
|
||||
*((bool *)pValue) = m_pMulplexTransportSocket->IsSslSocket();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void HMultiplexTransport::Terminate()
|
||||
{
|
||||
m_pMulplexTransportSocket->FinishTcp();
|
||||
}
|
||||
|
||||
inline int HMultiplexTransport::Send(const char * pData, int nSize)
|
||||
{
|
||||
return m_pMulplexTransportSocket->Send(pData, nSize);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
template<class _THandler, class _TSocket>
|
||||
class HMulplexTransportListenSocket : public HMultiplexListenSocket
|
||||
{
|
||||
public:
|
||||
HMulplexTransportListenSocket() {}
|
||||
~HMulplexTransportListenSocket() {}
|
||||
|
||||
protected:
|
||||
HMultiplexTcpSocket * OnAccept(SOCKET sock, struct sockaddr_in * psaiRemote)
|
||||
{
|
||||
HMultiplexTransport * pMultiplexTransport = new HMultiplexTransport;
|
||||
pMultiplexTransport->AttachHandler(new _THandler);
|
||||
|
||||
_TSocket * pSocket = new _TSocket(sock, psaiRemote, GetDispatcher());
|
||||
pMultiplexTransport->SetMpSocket(pSocket);
|
||||
|
||||
pSocket->AttachTransport(pMultiplexTransport);
|
||||
pSocket->SetAutoDelete(true);
|
||||
|
||||
return pSocket;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
class HMulplexSocketConnector
|
||||
{
|
||||
public:
|
||||
HMulplexSocketConnector() { m_pVecOutboundIp = NULL; m_nOutboundIpIndex = -1; }
|
||||
virtual ~HMulplexSocketConnector() {}
|
||||
|
||||
inline void SetOutboundIpList(HStrVector * pVector) { m_pVecOutboundIp = pVector; }
|
||||
inline void SetOutboundIpIndex(int nIndex) { m_nOutboundIpIndex = nIndex; }
|
||||
|
||||
virtual bool Connect(const char * pszAddress, u_short nPort, unsigned nTimeout, HMpsDispatcher * pDispatcher) { return false; }
|
||||
|
||||
protected:
|
||||
HStrVector * m_pVecOutboundIp;
|
||||
int m_nOutboundIpIndex;
|
||||
};
|
||||
|
||||
template<class _THandler, class _TSocket>
|
||||
class HMulplexTransportConnector : public HMulplexSocketConnector
|
||||
{
|
||||
public:
|
||||
HMulplexTransportConnector() { m_pHandler = NULL; }
|
||||
~HMulplexTransportConnector() {}
|
||||
|
||||
inline _THandler * GetHandler() { return m_pHandler; }
|
||||
|
||||
inline bool Connect(const char * pszAddress, u_short nPort, unsigned nTimeout, HMpsDispatcher * pDispatcher, unsigned long nAutoReconnectTime = 0)
|
||||
{
|
||||
HMultiplexTransport * pMultiplexTransport = new HMultiplexTransport;
|
||||
|
||||
m_pHandler = new _THandler;
|
||||
pMultiplexTransport->AttachHandler(m_pHandler);
|
||||
|
||||
_TSocket * pSocket = new _TSocket;
|
||||
if (pSocket->Create() == false)
|
||||
{
|
||||
delete pSocket;
|
||||
delete pMultiplexTransport;
|
||||
return false;
|
||||
}
|
||||
pMultiplexTransport->SetMpSocket(pSocket);
|
||||
pSocket->AttachTransport(pMultiplexTransport);
|
||||
|
||||
if (nAutoReconnectTime > 0)
|
||||
pSocket->SetAutoReconnect(nAutoReconnectTime);
|
||||
else
|
||||
pSocket->SetAutoDelete(true);
|
||||
|
||||
HLOGF(HLOG_INFO3, "INFO, MpConnector, Connect, inst = 0x%x, %s:%d\n", this, pszAddress, nPort);
|
||||
|
||||
if (IsIpString(pszAddress))
|
||||
pSocket->SetRemoteAddress(pszAddress, nPort);
|
||||
else
|
||||
pSocket->SetRemoteAddressHostByName(pszAddress, nPort);
|
||||
|
||||
if (m_pVecOutboundIp && m_pVecOutboundIp->size() > 0)
|
||||
{
|
||||
// outbound load balance
|
||||
static int nIpCount = m_pVecOutboundIp->size();
|
||||
static int nIpIndex = 0;
|
||||
static u_short nPort = 20000;
|
||||
|
||||
if (nIpCount <= 0)
|
||||
return false;
|
||||
|
||||
if (++nIpIndex >= nIpCount)
|
||||
nIpIndex = 0;
|
||||
|
||||
for (int i = 20000; i < 60000; i++)
|
||||
{
|
||||
if (++nPort >= 60000)
|
||||
nPort = 20000;
|
||||
|
||||
if (m_nOutboundIpIndex != -1)
|
||||
{
|
||||
if (pSocket->Bind((*m_pVecOutboundIp)[m_nOutboundIpIndex], nPort))
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pSocket->Bind((*m_pVecOutboundIp)[nIpIndex], nPort))
|
||||
break;
|
||||
}
|
||||
|
||||
Sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
if (pSocket->Connect(nTimeout) == false)
|
||||
{
|
||||
delete pSocket;
|
||||
return false;
|
||||
}
|
||||
|
||||
pDispatcher->Attach(pSocket);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
_THandler * m_pHandler;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
template<class _THandler, class _TSocket>
|
||||
class HMulplexTransportListenThread : public HMultiplexListenThread<HMultiplexTcpSocket>
|
||||
{
|
||||
public:
|
||||
HMulplexTransportListenThread() {}
|
||||
~HMulplexTransportListenThread() {}
|
||||
|
||||
protected:
|
||||
HMultiplexTcpSocket * OnAccept(SOCKET sock, struct sockaddr_in * psaiRemote)
|
||||
{
|
||||
HMultiplexTransport * pMultiplexTransport = new HMultiplexTransport;
|
||||
pMultiplexTransport->AttachHandler(new _THandler);
|
||||
#if 1
|
||||
HMpsDispatcher * pDispatcher = m_pListDispatcher->GetLazyDispatcher();
|
||||
_TSocket * pSocket = new _TSocket(sock, psaiRemote, pDispatcher);
|
||||
pMultiplexTransport->SetMpSocket(pSocket);
|
||||
|
||||
pSocket->AttachTransport(pMultiplexTransport);
|
||||
pSocket->SetAutoDelete(true);
|
||||
|
||||
pDispatcher->AttachWithLock(pSocket);
|
||||
return pSocket;
|
||||
#else
|
||||
HMpsDispatcherList::iterator iter;
|
||||
int i = 0;
|
||||
for (iter = m_pListDispatcher->begin(); iter != m_pListDispatcher->end(); iter++)
|
||||
{
|
||||
if ((*iter)->IsProcessing() == false)
|
||||
i++;
|
||||
}
|
||||
//HLOGF(HLOG_WARNING, "[TRACE], MplxTrnspLstnThr_0x%x, lazy dispatcher count = %d\n", this, i);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
for (iter = m_pListDispatcher->begin(); iter != m_pListDispatcher->end(); iter++)
|
||||
{
|
||||
if ((*iter)->IsProcessing() == false)
|
||||
{
|
||||
_TSocket * pSocket = new _TSocket(sock, psaiRemote, *iter);
|
||||
pMultiplexTransport->SetMpSocket(pSocket);
|
||||
|
||||
pSocket->AttachTransport(pMultiplexTransport);
|
||||
pSocket->SetAutoDelete(true);
|
||||
|
||||
(*iter)->AttachWithLock(pSocket);
|
||||
return pSocket;
|
||||
}
|
||||
}
|
||||
|
||||
Sleep(10);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if 1
|
||||
typedef std::list<HMultiplexListenThread<HMultiplexTcpSocket> *> HMultiplexListenThreadList;
|
||||
#else
|
||||
class HMultiplexListenThreadList : public std::list<HMultiplexListenThread<HMultiplexTcpSocket> *>
|
||||
{
|
||||
public:
|
||||
HMultiplexListenThreadList() {}
|
||||
~HMultiplexListenThreadList() {}
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // MULTIPLEX_TRANSPORT__H_
|
||||
@@ -0,0 +1,592 @@
|
||||
|
||||
#include "stringex.h"
|
||||
#include "Defines.h"
|
||||
#include "Common.h"
|
||||
#include "Object.h"
|
||||
#include "String.h"
|
||||
#include "DataStruct.h"
|
||||
#include "NetUtil.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static struct {
|
||||
const char * pszSecondLevelDomain;
|
||||
int nBaseDot;
|
||||
} SecondLevelDomain[] = {
|
||||
{ ".com.br", 2 },
|
||||
{ ".com.cn", 2 },
|
||||
{ ".com.hk", 2 },
|
||||
{ ".com.pl", 2 },
|
||||
{ ".co.kr", 2 },
|
||||
{ ".go.kr", 2 },
|
||||
{ ".ac.kr", 2 },
|
||||
{ ".ac.uk", 2 },
|
||||
{ ".or.kr", 2 },
|
||||
{ ".re.kr", 2 },
|
||||
{ ".co.uk", 2 },
|
||||
{ ".ac.at", 2 },
|
||||
{ ".ac.id", 2 },
|
||||
{ ".ac.jp", 2 },
|
||||
{ ".ac.rs", 2 },
|
||||
{ ".co.jp", 2 },
|
||||
{ ".go.jp", 2 },
|
||||
{ ".or.jp", 2 },
|
||||
{ ".ed.gov", 2 },
|
||||
{ ".gov.pl", 2 },
|
||||
{ ".gc.ca", 2 },
|
||||
{ ".edu.au", 2 },
|
||||
{ ".edu.tw", 2 },
|
||||
{ ".gov.tr", 2 },
|
||||
{ ".gov.uk", 2 },
|
||||
{ ".org.au", 2 },
|
||||
{ ".org.in", 2 },
|
||||
{ ".gda.pl", 2 },
|
||||
{ ".org.au", 2 },
|
||||
{ ".org.uk", 2 },
|
||||
{ ".org.br", 2 },
|
||||
{ ".org.tw", 2 },
|
||||
{ ".com.sg", 2 },
|
||||
{ ".edu.pl", 2 }
|
||||
};
|
||||
#define ARRAYCOUNT(array) ((unsigned)(sizeof(array)/sizeof(array[0])))
|
||||
|
||||
|
||||
bool IsIpString(const char * psz)
|
||||
{
|
||||
int nCount = 0;
|
||||
char * pOne = (char *)psz;
|
||||
while (*pOne)
|
||||
{
|
||||
if (*pOne == '.')
|
||||
nCount++;
|
||||
else if (*pOne < 48 || *pOne > 57)
|
||||
return false;
|
||||
|
||||
pOne++;
|
||||
}
|
||||
|
||||
if (nCount != 3)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ConvertHexStrIP(char * pszDst, unsigned long nS_Addr)
|
||||
{
|
||||
if (pszDst == NULL)
|
||||
return;
|
||||
#if 0
|
||||
_snprintf(pszDst, 9, "%X", nS_Addr);
|
||||
#else
|
||||
|
||||
// 4bit number to hex character
|
||||
#define NUMTOHEXC(N) (((N) < 10) ? ((N) + '0') : ((N) - 10 + 'A'))
|
||||
|
||||
unsigned long nNum = nS_Addr;
|
||||
int nFigure;
|
||||
for(nFigure = 0; nNum != 0; nFigure++)
|
||||
nNum = nNum >> 4;
|
||||
|
||||
for (int i = 0; i < nFigure; i++)
|
||||
pszDst[i] = (char)NUMTOHEXC((nS_Addr >> ((nFigure - (i + 1)) * 4)) & 0xF);
|
||||
|
||||
pszDst[nFigure] = '\0';
|
||||
#endif
|
||||
}
|
||||
|
||||
void RestoreDotIP(char * pszDst, const char * pszSrc)
|
||||
{
|
||||
if (pszDst == NULL || pszSrc == NULL) return;
|
||||
|
||||
struct in_addr sin_addr;
|
||||
sin_addr.s_addr = strtoul(pszSrc, NULL, 16);
|
||||
//strcpy(pszDst, inet_ntoa(sin_addr));
|
||||
strncpy(pszDst, inet_ntoa(sin_addr), 16);
|
||||
}
|
||||
|
||||
bool IsInsideIp(const char * pszIpRange, const char * pszIp)
|
||||
{
|
||||
const char * pTild;
|
||||
const char * pLastDot;
|
||||
|
||||
if ((pTild = strchr(pszIpRange, '~')))
|
||||
{
|
||||
if ((pLastDot = strrchr(pszIpRange, '.')) && pLastDot + 1 < pTild)
|
||||
{
|
||||
size_t nFrontSize = (size_t)(pLastDot - pszIpRange);
|
||||
if (strncmp(pszIpRange, pszIp, nFrontSize) == 0)
|
||||
{
|
||||
char szStartRange[128], szEndRange[128];
|
||||
StrNCpy(szStartRange, pLastDot + 1, pTild - pLastDot - 1);
|
||||
strcpy(szEndRange, pTild + 1);
|
||||
|
||||
int nDotCount = 0;
|
||||
const char * pOne = pszIpRange;
|
||||
while (*pOne)
|
||||
{
|
||||
if (*pOne == '.')
|
||||
nDotCount++;
|
||||
|
||||
pOne++;
|
||||
}
|
||||
|
||||
pOne = pszIp;
|
||||
while (*pOne)
|
||||
{
|
||||
if (*pOne == '.')
|
||||
{
|
||||
if (--nDotCount <= 0)
|
||||
{
|
||||
pOne++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pOne++;
|
||||
}
|
||||
|
||||
int nCompare;
|
||||
if ((pLastDot = strchr(pOne, '.')))
|
||||
{
|
||||
char szCompare[128];
|
||||
StrNCpy(szCompare, pOne, pLastDot - pOne);
|
||||
nCompare = atoi(szCompare);
|
||||
}
|
||||
else
|
||||
{
|
||||
nCompare = atoi(pOne);
|
||||
}
|
||||
|
||||
if (nCompare >= atoi(szStartRange) && nCompare <= atoi(szEndRange))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsDomainName(const char * pszName)
|
||||
{
|
||||
if (IsIpString(pszName) == true)
|
||||
return false;
|
||||
|
||||
//if (IsFileLinkString(pszName))
|
||||
// return false;
|
||||
|
||||
int nDotCount = 0;
|
||||
char * pOne = (char *)pszName;
|
||||
while (*pOne)
|
||||
{
|
||||
if (*pOne == '.')
|
||||
nDotCount++;
|
||||
|
||||
pOne++;
|
||||
}
|
||||
|
||||
if (nDotCount == 1)
|
||||
return true;
|
||||
|
||||
int nBaseDot = 0;
|
||||
for (unsigned i = 0; i < ARRAYCOUNT(SecondLevelDomain); i++)
|
||||
{
|
||||
if (strstr(pszName, SecondLevelDomain[i].pszSecondLevelDomain) != NULL)
|
||||
{
|
||||
nBaseDot = SecondLevelDomain[i].nBaseDot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nDotCount == nBaseDot)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsHostName(const char * pszName)
|
||||
{
|
||||
const char * p = pszName;
|
||||
for (; *p; p++)
|
||||
{
|
||||
if (!isalnum(*p) && *p != '.' && *p != '-' && *p != ':')
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExtractDomainName(char * pszDest, const char * pszHostName)
|
||||
{
|
||||
if (IsIpString(pszHostName))
|
||||
{
|
||||
const char * pszTemp = strstr(pszHostName, ":");
|
||||
if (pszTemp)
|
||||
{
|
||||
// ex) 192.168.0.1:8080 -> 192.168.0.1
|
||||
size_t nFrontLength = pszTemp - pszHostName;
|
||||
memcpy(pszDest, pszHostName, nFrontLength);
|
||||
pszDest[nFrontLength] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(pszDest, pszHostName); // ex) 192.168.0.1 -> 192.168.0.1
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int nDotCount = 0;
|
||||
char * pOne = (char *)pszHostName;
|
||||
while (*pOne)
|
||||
{
|
||||
if (*pOne == '.')
|
||||
nDotCount++;
|
||||
|
||||
pOne++;
|
||||
}
|
||||
|
||||
if (nDotCount <= 1)
|
||||
{
|
||||
strcpy(pszDest, pszHostName);
|
||||
return;
|
||||
}
|
||||
|
||||
int nBaseDot = 1;
|
||||
for (unsigned i = 0; i < ARRAYCOUNT(SecondLevelDomain); i++)
|
||||
{
|
||||
if (strstr(pszHostName, SecondLevelDomain[i].pszSecondLevelDomain) != NULL)
|
||||
{
|
||||
nBaseDot = SecondLevelDomain[i].nBaseDot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pOne = (char *)pszHostName;
|
||||
while (*pOne)
|
||||
{
|
||||
if (nDotCount == nBaseDot)
|
||||
{
|
||||
pszHostName = pOne;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*pOne == '.')
|
||||
nDotCount--;
|
||||
|
||||
pOne++;
|
||||
}
|
||||
|
||||
#ifdef WITH_PORT
|
||||
strcpy(pszDest, pszHostName); // ex) www.domain.com:8080 -> domain.com:8080
|
||||
#else
|
||||
const char * pOffset = strchr(pszHostName, ':');
|
||||
if (pOffset)
|
||||
{
|
||||
// ex) www.domain.com:8080 -> domain.com
|
||||
size_t nLength = pOffset - pszHostName;
|
||||
strncpy(pszDest, pszHostName, nLength);
|
||||
pszDest[nLength] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(pszDest, pszHostName);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const char * GetDomainNamePtr(const char * pszHostName)
|
||||
{
|
||||
if (IsIpString(pszHostName))
|
||||
return pszHostName;
|
||||
|
||||
int nDotCount = 0;
|
||||
char * pOne = (char *)pszHostName;
|
||||
while (*pOne)
|
||||
{
|
||||
if (*pOne == '.')
|
||||
nDotCount++;
|
||||
|
||||
pOne++;
|
||||
}
|
||||
|
||||
if (nDotCount <= 1)
|
||||
return pszHostName;
|
||||
|
||||
int nBaseDot = 1;
|
||||
for (unsigned i = 0; i < ARRAYCOUNT(SecondLevelDomain); i++)
|
||||
{
|
||||
if (strstr(pszHostName, SecondLevelDomain[i].pszSecondLevelDomain) != NULL)
|
||||
{
|
||||
nBaseDot = SecondLevelDomain[i].nBaseDot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pOne = (char *)pszHostName;
|
||||
while (*pOne)
|
||||
{
|
||||
if (nDotCount == nBaseDot)
|
||||
{
|
||||
pszHostName = pOne;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*pOne == '.')
|
||||
nDotCount--;
|
||||
|
||||
pOne++;
|
||||
}
|
||||
|
||||
return pszHostName;
|
||||
}
|
||||
|
||||
const char * GetRequestUriPtr(const char * pszUrl)
|
||||
{
|
||||
int nCount = 0;
|
||||
if (strnicmp(pszUrl, "http", 4) != 0 && pszUrl[0] != '/' && pszUrl[1] != '/')
|
||||
nCount = 2;
|
||||
|
||||
for (const char * p = pszUrl; *p; p++)
|
||||
{
|
||||
if (*p == '/')
|
||||
{
|
||||
if (nCount++ == 2)
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
return pszUrl;
|
||||
}
|
||||
|
||||
bool ExtractHostNameFromUrl(HString * pstrHostName, const char * pszUrl)
|
||||
{
|
||||
const char * pszRequestUri = GetRequestUriPtr(pszUrl);
|
||||
|
||||
if (strnicmp(pszUrl, "http://", 7) == 0)
|
||||
pszUrl += 7;
|
||||
else if (strnicmp(pszUrl, "https://", 8) == 0)
|
||||
pszUrl += 8;
|
||||
else if (strncmp(pszUrl, "//", 2) == 0)
|
||||
pszUrl += 2;
|
||||
|
||||
if (pszUrl >= pszRequestUri)
|
||||
return false;
|
||||
|
||||
pstrHostName->Assign(pszUrl, pszRequestUri - pszUrl);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char * GetNextLevelHostName(const char * pszHostName, bool bIncludeDot)
|
||||
{
|
||||
const char * p = pszHostName;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '.')
|
||||
{
|
||||
if (bIncludeDot)
|
||||
return p;
|
||||
|
||||
return ++p;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
return pszHostName;
|
||||
}
|
||||
|
||||
int EncodeURIComponent(char * pszDst, const char * pszSrc)
|
||||
{
|
||||
int nLength = 0;
|
||||
char * pOffset = pszDst;
|
||||
|
||||
while (*pszSrc)
|
||||
{
|
||||
if ((*pszSrc > 47 && *pszSrc < 57) ||
|
||||
(*pszSrc > 64 && *pszSrc < 92) ||
|
||||
(*pszSrc > 96 && *pszSrc < 123) ||
|
||||
*pszSrc == '-' || *pszSrc == '.' || *pszSrc == '_')
|
||||
{
|
||||
*pOffset = *pszSrc;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(pOffset, "%%%02X", *pszSrc);
|
||||
pOffset += 2;
|
||||
nLength += 2;
|
||||
}
|
||||
pszSrc++;
|
||||
pOffset++;
|
||||
nLength++;
|
||||
}
|
||||
pszDst[nLength] = '\0';
|
||||
|
||||
return nLength;
|
||||
}
|
||||
|
||||
int DecodeURIComponent(char * pszDst, char * pszSrc)
|
||||
{
|
||||
int i, nNum = 0, nLength = 0;
|
||||
int nTemp = 0;
|
||||
|
||||
while (*pszSrc)
|
||||
{
|
||||
if (*pszSrc == '%')
|
||||
{
|
||||
nNum = 0;
|
||||
nTemp = 0;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
pszSrc++;
|
||||
if (*(pszSrc) < ':')
|
||||
{
|
||||
nNum = *(pszSrc) - 48;
|
||||
}
|
||||
else if (*(pszSrc) > '@' && *(pszSrc) < '[')
|
||||
{
|
||||
nNum = (*(pszSrc) - 'A') + 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
nNum = (*(pszSrc) - 'a') + 10;
|
||||
}
|
||||
|
||||
if ((16*(1-i)))
|
||||
nNum = (nNum*16);
|
||||
nTemp += nNum;
|
||||
}
|
||||
pszDst[nLength] = nTemp;
|
||||
nLength++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pszDst[nLength] = *pszSrc;
|
||||
nLength++;
|
||||
}
|
||||
pszSrc++;
|
||||
}
|
||||
pszDst[nLength] = '\0';
|
||||
|
||||
return nLength;
|
||||
}
|
||||
|
||||
// base64 part
|
||||
static const std::string strBase64Char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static inline bool IsBase64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
int EncodeBase64(std::string * pstrEncoded, const unsigned char * pszSrc, unsigned int nSrcLen)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
unsigned char bufTemp1[3], bufTemp2[4];
|
||||
*pstrEncoded = "";
|
||||
|
||||
while (nSrcLen--) {
|
||||
bufTemp1[i++] = *(pszSrc++);
|
||||
if (i == 3) {
|
||||
bufTemp2[0] = (bufTemp1[0] & 0xfc) >> 2;
|
||||
bufTemp2[1] = ((bufTemp1[0] & 0x03) << 4) + ((bufTemp1[1] & 0xf0) >> 4);
|
||||
bufTemp2[2] = ((bufTemp1[1] & 0x0f) << 2) + ((bufTemp1[2] & 0xc0) >> 6);
|
||||
bufTemp2[3] = bufTemp1[2] & 0x3f;
|
||||
|
||||
for(i = 0; (i <4) ; i++)
|
||||
*pstrEncoded += strBase64Char[bufTemp2[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
bufTemp1[j] = '\0';
|
||||
|
||||
bufTemp2[0] = (bufTemp1[0] & 0xfc) >> 2;
|
||||
bufTemp2[1] = ((bufTemp1[0] & 0x03) << 4) + ((bufTemp1[1] & 0xf0) >> 4);
|
||||
bufTemp2[2] = ((bufTemp1[1] & 0x0f) << 2) + ((bufTemp1[2] & 0xc0) >> 6);
|
||||
bufTemp2[3] = bufTemp1[2] & 0x3f;
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
*pstrEncoded += strBase64Char[bufTemp2[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
*pstrEncoded += '=';
|
||||
|
||||
}
|
||||
|
||||
return pstrEncoded->length();
|
||||
}
|
||||
|
||||
int DecodeBase64(std::string * pstrDecoded, const unsigned char * pszSrc, unsigned int nSrcLen)
|
||||
{
|
||||
int i = 0, j = 0, pos = 0;
|
||||
unsigned char bufTemp2[4], bufTemp1[3];
|
||||
*pstrDecoded = "";
|
||||
|
||||
while (nSrcLen-- && ( pszSrc[pos] != '=') && IsBase64(pszSrc[pos])) {
|
||||
bufTemp2[i++] = pszSrc[pos]; pos++;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++)
|
||||
bufTemp2[i] = strBase64Char.find(bufTemp2[i]);
|
||||
|
||||
bufTemp1[0] = (bufTemp2[0] << 2) + ((bufTemp2[1] & 0x30) >> 4);
|
||||
bufTemp1[1] = ((bufTemp2[1] & 0xf) << 4) + ((bufTemp2[2] & 0x3c) >> 2);
|
||||
bufTemp1[2] = ((bufTemp2[2] & 0x3) << 6) + bufTemp2[3];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
*pstrDecoded += bufTemp1[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j <4; j++)
|
||||
bufTemp2[j] = 0;
|
||||
|
||||
for (j = 0; j <4; j++)
|
||||
bufTemp2[j] = strBase64Char.find(bufTemp2[j]);
|
||||
|
||||
bufTemp1[0] = (bufTemp2[0] << 2) + ((bufTemp2[1] & 0x30) >> 4);
|
||||
bufTemp1[1] = ((bufTemp2[1] & 0xf) << 4) + ((bufTemp2[2] & 0x3c) >> 2);
|
||||
bufTemp1[2] = ((bufTemp2[2] & 0x3) << 6) + bufTemp2[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++) *pstrDecoded += bufTemp1[j];
|
||||
}
|
||||
|
||||
return pstrDecoded->length();
|
||||
}
|
||||
|
||||
void DecodeUriBase64(HString & strDst, const HString & strSrc)
|
||||
{
|
||||
if (strSrc.GetLength() <= 0)
|
||||
return;
|
||||
|
||||
std::string strTemp;
|
||||
|
||||
DecodeBase64(&strTemp, (const unsigned char *)strSrc.psz(), strSrc.GetLength());
|
||||
HDynamicArray<char> dszUriDecode(strTemp.length() * 2);
|
||||
DecodeURIComponent(dszUriDecode.m_p, (char *)strTemp.c_str());
|
||||
strDst = dszUriDecode.m_p;
|
||||
}
|
||||
|
||||
void DecodeUriBase64(HString & strSelf)
|
||||
{
|
||||
if (strSelf.GetLength() <= 0)
|
||||
return;
|
||||
|
||||
std::string strTemp;
|
||||
|
||||
DecodeBase64(&strTemp, (const unsigned char *)strSelf.psz(), strSelf.GetLength());
|
||||
HDynamicArray<char> dszUriDecode(strTemp.length() * 2);
|
||||
DecodeURIComponent(dszUriDecode.m_p, (char *)strTemp.c_str());
|
||||
strSelf = dszUriDecode.m_p;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef NET_UTIL__H_
|
||||
#define NET_UTIL__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
bool IsIpString(const char * psz);
|
||||
void ConvertHexStrIP(char * pszDst, unsigned long nS_Addr);
|
||||
void RestoreDotIP(char * pszDst, const char * pszSrc);
|
||||
bool IsInsideIp(const char * pszIpRange, const char * pszIp);
|
||||
|
||||
bool IsDomainName(const char * pszName);
|
||||
bool IsHostName(const char * pszName);
|
||||
|
||||
void ExtractDomainName(char * pszDest, const char * pszHostName); // pszHostName : hostname or hostname:port
|
||||
const char * GetDomainNamePtr(const char * pszHostName); // pszHostName : without port - hostname(o), hostname:port(x)
|
||||
const char * GetRequestUriPtr(const char * pszUrl);
|
||||
|
||||
bool ExtractHostNameFromUrl(HString * pstrHostName, const char * pszUrl);
|
||||
|
||||
const char * GetNextLevelHostName(const char * pszHostName, bool bIncludeDot); // www.aaa.bbb.ccc.com -> aaa.bbb.ccc.com or .aaa.bbb.ccc.com
|
||||
|
||||
|
||||
int EncodeURIComponent(char * pszDst, const char * pszSrc);
|
||||
int DecodeURIComponent(char * pszDst, char * pszSrc);
|
||||
|
||||
int EncodeBase64(std::string * pstrEncoded, const unsigned char * pszSrc, unsigned int nSrcLen);
|
||||
int DecodeBase64(std::string * pstrDecoded, const unsigned char * pszSrc, unsigned int nSrcLen);
|
||||
|
||||
void DecodeUriBase64(HString & strDst, const HString & strSrc);
|
||||
void DecodeUriBase64(HString & strSelf);
|
||||
|
||||
#endif // NET_UTIL__H_
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef OBJECT__H_
|
||||
#define OBJECT__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HObject
|
||||
{
|
||||
public:
|
||||
HObject() {}
|
||||
virtual ~HObject() {}
|
||||
};
|
||||
|
||||
#endif // OBJECT__H_
|
||||
@@ -0,0 +1,93 @@
|
||||
#ifndef PROTOCOL_HANDLER__H_
|
||||
#define PROTOCOL_HANDLER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HTransport;
|
||||
|
||||
|
||||
class HProtocolHandler : public HObject
|
||||
{
|
||||
public:
|
||||
HProtocolHandler() {}
|
||||
~HProtocolHandler() {}
|
||||
|
||||
virtual inline void SetTransport(HTransport * pTransport);
|
||||
virtual inline int SendToTransport(const char * pData, int nSize);
|
||||
virtual inline void TerminateTransport();
|
||||
|
||||
virtual inline bool GetTransportInfo(const char * pName, void * pValue);
|
||||
|
||||
protected:
|
||||
virtual void OnReceivedStatusFromTransport(int nStatus) = 0;
|
||||
|
||||
virtual int OnSendRetryToTransport() = 0;
|
||||
virtual bool OnPrepareReceive() = 0;
|
||||
virtual int OnReceivedFromTransport(const char * pData, int nSize) = 0;
|
||||
|
||||
protected:
|
||||
HTransport * m_pTransport;
|
||||
|
||||
|
||||
friend class HTransport;
|
||||
};
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
class HTransport : public HObject
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
T_BEGIN_TRANSPORT = 1,
|
||||
T_END_TRANSPORT,
|
||||
T_FAILED_BEGIN
|
||||
};
|
||||
|
||||
HTransport() {}
|
||||
~HTransport() { delete m_pHandler; }
|
||||
|
||||
virtual inline void AttachHandler(HProtocolHandler * pHandler);
|
||||
virtual inline HProtocolHandler * GetHandler();
|
||||
|
||||
virtual inline bool GetTransportInfo(const char * pName, void * pValue) { return false; }
|
||||
|
||||
virtual inline void Terminate() {}
|
||||
|
||||
virtual int Send(const char * pData, int nSize) = 0;
|
||||
|
||||
protected:
|
||||
inline void OnReceivedStatus(int nStatus);
|
||||
inline bool OnPrepareReceive();
|
||||
inline int OnReceived(const char * pData, int nSize);
|
||||
inline int OnSendRetry();
|
||||
|
||||
protected:
|
||||
HProtocolHandler * m_pHandler;
|
||||
|
||||
|
||||
friend class HProtocolHandler;
|
||||
};
|
||||
|
||||
inline void HProtocolHandler::SetTransport(HTransport * pTransport) { m_pTransport = pTransport; }
|
||||
inline int HProtocolHandler::SendToTransport(const char * pData, int nSize) { return m_pTransport->Send(pData, nSize); }
|
||||
inline void HProtocolHandler::TerminateTransport() { m_pTransport->Terminate(); }
|
||||
inline bool HProtocolHandler::GetTransportInfo(const char * pName, void * pValue) { return m_pTransport->GetTransportInfo(pName, pValue); }
|
||||
|
||||
inline void HTransport::AttachHandler(HProtocolHandler * pHandler)
|
||||
{
|
||||
pHandler->SetTransport(this);
|
||||
m_pHandler = pHandler;
|
||||
}
|
||||
inline HProtocolHandler * HTransport::GetHandler() { return m_pHandler; }
|
||||
|
||||
inline void HTransport::OnReceivedStatus(int nStatus) { m_pHandler->OnReceivedStatusFromTransport(nStatus); }
|
||||
inline bool HTransport::OnPrepareReceive() { return m_pHandler->OnPrepareReceive(); }
|
||||
inline int HTransport::OnReceived(const char * pData, int nSize) { return m_pHandler->OnReceivedFromTransport(pData, nSize); }
|
||||
inline int HTransport::OnSendRetry() { return m_pHandler->OnSendRetryToTransport(); }
|
||||
|
||||
#endif // PROTOCOL_HANDLER__H_
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef ROUTER__H_
|
||||
#define ROUTER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HRouter : public HObject
|
||||
{
|
||||
public:
|
||||
HRouter() {}
|
||||
~HRouter() {}
|
||||
}
|
||||
|
||||
#endif // ROUTER__H_
|
||||
@@ -0,0 +1,537 @@
|
||||
#ifndef SOCKET__H_
|
||||
#define SOCKET__H_
|
||||
|
||||
#ifdef MASS_SERVICE_SERVER
|
||||
#define FD_SETSIZE 2048
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#pragma once
|
||||
|
||||
//#pragma comment(lib, "wsock32.lib") // old ver
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
|
||||
#if _MSC_VER <= 1200
|
||||
typedef int socklen_t;
|
||||
#else
|
||||
#include <ws2tcpip.h> // getaddrinfo
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h> // sockaddr_in
|
||||
#include <arpa/inet.h> // inet_ntoa()
|
||||
#include <netdb.h> // gethostbyname()
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
typedef int SOCKET;
|
||||
|
||||
#define INVALID_SOCKET -1
|
||||
#define SOCKET_ERROR -1
|
||||
|
||||
#define closesocket close
|
||||
|
||||
#define SD_BOTH SHUT_RDWR
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
extern inline int SockErrorNo()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return WSAGetLastError();
|
||||
#else
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
extern inline int GetAddrByHostName(const char * pAddress, struct sockaddr_in * pSai) // blocking operation
|
||||
{
|
||||
struct hostent * pHe;
|
||||
|
||||
// resolve host address
|
||||
if ((pHe = gethostbyname(pAddress)) == NULL)
|
||||
{
|
||||
#if defined(_WIN32) && _MSC_VER <= 1200
|
||||
return WSAGetLastError();
|
||||
#else
|
||||
struct addrinfo aiHints;
|
||||
struct addrinfo *aiList = NULL;
|
||||
struct addrinfo *aiPtr = NULL;
|
||||
int retVal;
|
||||
|
||||
memset(&aiHints, 0, sizeof(aiHints));
|
||||
aiHints.ai_family = AF_INET;
|
||||
aiHints.ai_socktype = SOCK_STREAM;
|
||||
aiHints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
if ((retVal = getaddrinfo(pAddress, NULL, &aiHints, &aiList)))
|
||||
return SockErrorNo();
|
||||
|
||||
for(aiPtr = aiList; aiPtr != NULL; aiPtr = aiPtr->ai_next)
|
||||
{
|
||||
if (aiPtr->ai_family == AF_INET)
|
||||
{
|
||||
memset(pSai, 0, sizeof(struct sockaddr_in));
|
||||
memcpy(pSai, aiPtr->ai_addr, sizeof(struct sockaddr_in));
|
||||
freeaddrinfo(aiList);
|
||||
return 0; // success
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(aiList);
|
||||
return SOCKET_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
memset(pSai, 0, sizeof(struct sockaddr_in));
|
||||
pSai->sin_addr.s_addr = *(u_long *)pHe->h_addr_list[0];
|
||||
pSai->sin_family = AF_INET;
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
extern inline void SetSockAddr(struct sockaddr_in * pSai, const char * pIp, u_short nPort)
|
||||
{
|
||||
memset(pSai, 0, sizeof(struct sockaddr_in));
|
||||
|
||||
pSai->sin_addr.s_addr = inet_addr(pIp);
|
||||
pSai->sin_family = AF_INET;
|
||||
pSai->sin_port = htons(nPort);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class HSocket : public HObject
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ERR_TIMEOUT = WSAETIMEDOUT
|
||||
#else
|
||||
ERR_TIMEOUT = ETIMEDOUT
|
||||
#endif
|
||||
};
|
||||
|
||||
public:
|
||||
HSocket()
|
||||
{
|
||||
m_fdSocket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
virtual ~HSocket()
|
||||
{
|
||||
if (m_fdSocket != INVALID_SOCKET)
|
||||
closesocket(m_fdSocket);
|
||||
}
|
||||
|
||||
inline SOCKET GetSocket();
|
||||
inline void SetSocket(SOCKET sock);
|
||||
|
||||
inline SOCKET Create(int nDomain, int nType, int nProtocol = 0);
|
||||
inline int Close();
|
||||
|
||||
inline int Bind(u_short nPort);
|
||||
inline int Bind(struct sockaddr_in * psaiLocal);
|
||||
inline int Bind(const char * pAddress, u_short nPort);
|
||||
|
||||
inline int Listen(int nBackLog);
|
||||
inline SOCKET Accept(HSocket & sockClient, char * pszPeerIp = NULL, u_short * pnPeerPort = NULL);
|
||||
|
||||
inline int Connect(struct sockaddr_in * psaiRemote);
|
||||
inline int Connect(const char * pHostAddress, u_short nPort);
|
||||
|
||||
inline int Send(const char * pData, int nLen, int nFlags = 0);
|
||||
inline int Receive(char * pBuf, int nLen, int nFlags = 0);
|
||||
inline int SendTo(const char * pData, int nLen, int flags, struct sockaddr_in * pSaiRemote);
|
||||
inline int ReceiveFrom(char * pBuf, int nLen, int nFlags = 0, struct sockaddr_in * pSaiRemote = NULL, socklen_t * pnSaiLen = NULL);
|
||||
|
||||
inline int GetLocalAddress(struct sockaddr_in * psai);
|
||||
inline int GetLocalAddress(char * pBuf, u_short * pnPort);
|
||||
|
||||
inline int GetPeerAddress(struct sockaddr_in * psai);
|
||||
inline int GetPeerAddress(char * pBuf, u_short * pnPort);
|
||||
|
||||
inline int SetSockOpt(int nLevel, int nOptname, const char * pOptval,
|
||||
int nOptlen);
|
||||
inline int GetSockOpt(int nLevel, int nOptname, char * pOptval,
|
||||
int * pnOptlen);
|
||||
|
||||
inline int GetSockOptError();
|
||||
|
||||
inline int SetNonBlockMode(bool bNonBlock);
|
||||
|
||||
//
|
||||
inline bool TimoutConnect(struct sockaddr_in * psaiRemote, unsigned long nTimeout, bool bRestoreSyncMode, int * pnError);
|
||||
inline bool TimoutConnect(const char * pHostAddress, u_short nPort, unsigned long nTimeout, bool bRestoreSyncMode, int * pnError);
|
||||
inline bool WaitForSending(unsigned long nTimeout, int * pnError); // for non-block mode, *pnError = errno or WSAGetLastError()
|
||||
inline bool WaitForReceiving(unsigned long nTimeout, int * pnError); // for non-block mode, *pnError = errno or WSAGetLastError()
|
||||
|
||||
protected:
|
||||
SOCKET m_fdSocket;
|
||||
};
|
||||
|
||||
inline SOCKET HSocket::GetSocket()
|
||||
{
|
||||
return m_fdSocket;
|
||||
}
|
||||
|
||||
inline void HSocket::SetSocket(SOCKET sock)
|
||||
{
|
||||
m_fdSocket = sock;
|
||||
}
|
||||
|
||||
inline SOCKET HSocket::Create(int nDomain, int nType, int nProtocol)
|
||||
{
|
||||
return (m_fdSocket = socket(nDomain, nType, nProtocol));
|
||||
}
|
||||
|
||||
inline int HSocket::Close()
|
||||
{
|
||||
int nResult = closesocket(m_fdSocket);
|
||||
m_fdSocket = INVALID_SOCKET;
|
||||
return nResult;
|
||||
}
|
||||
|
||||
inline int HSocket::Bind(u_short nPort)
|
||||
{
|
||||
return Bind(NULL, nPort);
|
||||
}
|
||||
|
||||
inline int HSocket::Bind(struct sockaddr_in * psaiLocal)
|
||||
{
|
||||
return bind(m_fdSocket, (struct sockaddr *)psaiLocal, sizeof(struct sockaddr));
|
||||
}
|
||||
|
||||
inline int HSocket::Bind(const char * pAddress, u_short nPort)
|
||||
{
|
||||
struct sockaddr_in sai;
|
||||
memset(&sai, 0, sizeof(struct sockaddr_in));
|
||||
|
||||
if (pAddress == NULL || pAddress[0] == '\0')
|
||||
sai.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
else
|
||||
sai.sin_addr.s_addr = inet_addr(pAddress);
|
||||
|
||||
sai.sin_family = AF_INET;
|
||||
sai.sin_port = htons(nPort);
|
||||
|
||||
return bind(m_fdSocket, (struct sockaddr *)&sai, sizeof(struct sockaddr));
|
||||
}
|
||||
|
||||
inline int HSocket::Listen(int nBackLog)
|
||||
{
|
||||
return listen(m_fdSocket, nBackLog);
|
||||
}
|
||||
|
||||
inline SOCKET HSocket::Accept(HSocket & sockClient, char * pszPeerIp, u_short * pnPeerPort)
|
||||
{
|
||||
if (pszPeerIp != NULL || pnPeerPort != NULL)
|
||||
{
|
||||
struct sockaddr_in sai;
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
|
||||
SOCKET sock = (sockClient.m_fdSocket = accept(m_fdSocket, (struct sockaddr *)&sai, &len));
|
||||
|
||||
if (pszPeerIp != NULL)
|
||||
strcpy(pszPeerIp, inet_ntoa(sai.sin_addr));
|
||||
if (pnPeerPort != NULL)
|
||||
*pnPeerPort = ntohs(sai.sin_port);
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
return (sockClient.m_fdSocket = accept(m_fdSocket, NULL, NULL));
|
||||
}
|
||||
|
||||
inline int HSocket::Connect(struct sockaddr_in * psaiRemote)
|
||||
{
|
||||
return connect(m_fdSocket, (struct sockaddr *)psaiRemote, sizeof(struct sockaddr));
|
||||
}
|
||||
|
||||
inline int HSocket::Connect(const char * pHostAddress, u_short nPort)
|
||||
{
|
||||
struct sockaddr_in sai;
|
||||
memset(&sai, 0, sizeof(struct sockaddr_in));
|
||||
|
||||
sai.sin_addr.s_addr = inet_addr(pHostAddress);
|
||||
sai.sin_family = AF_INET;
|
||||
sai.sin_port = htons(nPort);
|
||||
|
||||
return connect(m_fdSocket, (struct sockaddr *)&sai, sizeof(struct sockaddr));
|
||||
}
|
||||
|
||||
inline int HSocket::Send(const char * pData, int nLen, int nFlags)
|
||||
{
|
||||
return send(m_fdSocket, pData, nLen, nFlags);
|
||||
}
|
||||
|
||||
inline int HSocket::Receive(char * pBuf, int nLen, int nFlags)
|
||||
{
|
||||
return recv(m_fdSocket, pBuf, nLen, nFlags);
|
||||
}
|
||||
|
||||
inline int HSocket::SendTo(const char * pData, int nLen, int flags, struct sockaddr_in * pSaiRemote)
|
||||
{
|
||||
return sendto(m_fdSocket, pData, nLen, flags, (struct sockaddr *)pSaiRemote, sizeof(struct sockaddr));
|
||||
}
|
||||
|
||||
inline int HSocket::ReceiveFrom(char * pBuf, int nLen, int nFlags, struct sockaddr_in * pSaiRemote, socklen_t * pnSaiLen)
|
||||
{
|
||||
return recvfrom(m_fdSocket, pBuf, nLen, nFlags, (struct sockaddr *)pSaiRemote, pnSaiLen);
|
||||
}
|
||||
|
||||
inline int HSocket::GetLocalAddress(struct sockaddr_in * psai)
|
||||
{
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
return getsockname(m_fdSocket, (struct sockaddr *)psai, &len);
|
||||
}
|
||||
|
||||
inline int HSocket::GetLocalAddress(char * pBuf, u_short * pnPort)
|
||||
{
|
||||
struct sockaddr_in sai;
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
|
||||
if (getsockname(m_fdSocket, (struct sockaddr *)&sai, &len) < 0)
|
||||
return SockErrorNo();
|
||||
|
||||
if (pBuf)
|
||||
strcpy(pBuf, inet_ntoa(sai.sin_addr));
|
||||
|
||||
if (pnPort)
|
||||
*pnPort = ntohs(sai.sin_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int HSocket::GetPeerAddress(struct sockaddr_in * psai)
|
||||
{
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
|
||||
return getpeername(m_fdSocket, (struct sockaddr *)psai, &len);
|
||||
}
|
||||
|
||||
inline int HSocket::GetPeerAddress(char * pBuf, u_short * pnPort)
|
||||
{
|
||||
struct sockaddr_in sai;
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
|
||||
if (getpeername(m_fdSocket, (struct sockaddr *)&sai, &len) < 0)
|
||||
return SockErrorNo();
|
||||
|
||||
if (pBuf)
|
||||
strcpy(pBuf, inet_ntoa(sai.sin_addr));
|
||||
|
||||
if (pnPort)
|
||||
*pnPort = ntohs(sai.sin_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int HSocket::SetSockOpt(int nLevel, int nOptname, const char * pOptval, int nOptlen)
|
||||
{
|
||||
return setsockopt(m_fdSocket, nLevel, nOptname, pOptval, nOptlen);
|
||||
}
|
||||
|
||||
inline int HSocket::GetSockOpt(int nLevel, int nOptname, char * pOptval, int * pnOptlen)
|
||||
{
|
||||
return getsockopt(m_fdSocket, nLevel, nOptname, pOptval, (socklen_t *)pnOptlen);
|
||||
}
|
||||
|
||||
inline int HSocket::GetSockOptError()
|
||||
{
|
||||
int nOptVal;
|
||||
int nOptLen = sizeof(int);
|
||||
if (getsockopt(m_fdSocket, SOL_SOCKET, SO_ERROR, (char *)(&nOptVal), (socklen_t *)&nOptLen) < 0)
|
||||
return SockErrorNo();
|
||||
|
||||
return nOptVal;
|
||||
}
|
||||
|
||||
inline int HSocket::SetNonBlockMode(bool bNonBlock)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ULONG nFlags = bNonBlock;
|
||||
return ioctlsocket(m_fdSocket, FIONBIO, &nFlags);
|
||||
#else
|
||||
int nFlags = fcntl(m_fdSocket, F_GETFL, 0);
|
||||
return fcntl(m_fdSocket, F_SETFL, (bNonBlock ? nFlags | O_NONBLOCK : nFlags & ~O_NONBLOCK));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool HSocket::TimoutConnect(struct sockaddr_in * psaiRemote,
|
||||
unsigned long nTimeout, bool bRestoreSyncMode, int * pnError)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ULONG nFlags = 1;
|
||||
if (ioctlsocket(m_fdSocket, FIONBIO, &nFlags) < 0)
|
||||
#else
|
||||
int nFlags = fcntl(m_fdSocket, F_GETFL, 0);
|
||||
if (fcntl(m_fdSocket, F_SETFL, nFlags | O_NONBLOCK) < 0)
|
||||
#endif
|
||||
{
|
||||
*pnError = SockErrorNo();
|
||||
return false;
|
||||
}
|
||||
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
int nResult;
|
||||
if ((nResult = connect(m_fdSocket, (struct sockaddr *)psaiRemote, len)) < 0)
|
||||
{
|
||||
*pnError = SockErrorNo();
|
||||
#ifdef _WIN32
|
||||
if (*pnError != WSAEINPROGRESS && *pnError != WSAEWOULDBLOCK)
|
||||
#else
|
||||
if (*pnError != EINPROGRESS)
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
fd_set fsRead, fsWrite;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&fsRead);
|
||||
FD_SET(m_fdSocket, &fsRead);
|
||||
fsWrite = fsRead;
|
||||
|
||||
tv.tv_sec = nTimeout / 1000;
|
||||
tv.tv_usec = (nTimeout % 1000) * 1000;
|
||||
|
||||
if ((nResult = select((int)(m_fdSocket + 1), &fsRead, &fsWrite, NULL, &tv)) == 0)
|
||||
{
|
||||
*pnError = ERR_TIMEOUT;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FD_ISSET(m_fdSocket, &fsRead) || FD_ISSET(m_fdSocket, &fsWrite))
|
||||
{
|
||||
len = sizeof(nResult);
|
||||
if (getsockopt(m_fdSocket, SOL_SOCKET, SO_ERROR, (char *)&nResult, &len) < 0)
|
||||
{
|
||||
*pnError = SOCKET_ERROR;
|
||||
return false; // Solaris pending error
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*pnError = SOCKET_ERROR; // select error: m_fdSocket not set
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bRestoreSyncMode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
nFlags = 0;
|
||||
if (ioctlsocket(m_fdSocket, FIONBIO, &nFlags) < 0)
|
||||
#else
|
||||
if (fcntl(m_fdSocket, F_SETFL, nFlags) < 0)
|
||||
#endif
|
||||
{
|
||||
*pnError = SockErrorNo();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*pnError = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool HSocket::TimoutConnect(const char * pHostAddress, u_short nPort, unsigned long nTimeout, bool bRestoreSyncMode, int * pnError)
|
||||
{
|
||||
struct sockaddr_in sai;
|
||||
memset(&sai, 0, sizeof(struct sockaddr_in));
|
||||
|
||||
sai.sin_addr.s_addr = inet_addr(pHostAddress);
|
||||
sai.sin_family = AF_INET;
|
||||
sai.sin_port = htons(nPort);
|
||||
|
||||
return TimoutConnect(&sai, nTimeout, bRestoreSyncMode, pnError);
|
||||
}
|
||||
|
||||
inline bool HSocket::WaitForSending(unsigned long nTimeout, int * pnError)
|
||||
{
|
||||
fd_set fsWrite;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&fsWrite);
|
||||
FD_SET(m_fdSocket, &fsWrite);
|
||||
|
||||
tv.tv_sec = nTimeout / 1000;
|
||||
tv.tv_usec = (nTimeout % 1000) * 1000;
|
||||
|
||||
int nResult = select((int)m_fdSocket + 1, NULL, &fsWrite, NULL, nTimeout ? &tv : NULL);
|
||||
if (nResult < 0)
|
||||
{
|
||||
*pnError = SockErrorNo();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nResult == 0 || FD_ISSET(m_fdSocket, &fsWrite) == 0)
|
||||
{
|
||||
*pnError = ERR_TIMEOUT;
|
||||
return false;
|
||||
}
|
||||
|
||||
*pnError = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool HSocket::WaitForReceiving(unsigned long nTimeout, int * pnError)
|
||||
{
|
||||
fd_set fsRead;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&fsRead);
|
||||
FD_SET(m_fdSocket, &fsRead);
|
||||
|
||||
tv.tv_sec = nTimeout / 1000;
|
||||
tv.tv_usec = (nTimeout % 1000) * 1000;
|
||||
|
||||
int nResult = select((int)m_fdSocket + 1, &fsRead, NULL, NULL, nTimeout ? &tv : NULL);
|
||||
if (nResult < 0)
|
||||
{
|
||||
*pnError = SockErrorNo();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nResult == 0 || FD_ISSET(m_fdSocket, &fsRead) == 0)
|
||||
{
|
||||
*pnError = ERR_TIMEOUT;
|
||||
return false;
|
||||
}
|
||||
|
||||
*pnError = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern inline int TcpCompleteSend(SOCKET sock, const char * pszPacket, int nPacketSize)
|
||||
{
|
||||
int nSentSize;
|
||||
const char * pszPacketOffset = pszPacket;
|
||||
while (nPacketSize > 0)
|
||||
{
|
||||
nSentSize = send(sock, pszPacketOffset, nPacketSize, 0);
|
||||
if (nSentSize <= 0)
|
||||
{
|
||||
//HLOG(HLOG_ERROR, "[ERROR], EmailSender, Failed to send.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nPacketSize -= nSentSize;
|
||||
pszPacketOffset += nSentSize;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // SOCKET__H_
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
#include "huslib.h"
|
||||
#include "huslibex.h"
|
||||
#include "SohHandler.h"
|
||||
|
||||
|
||||
|
||||
HSohHandler::HSohHandler()
|
||||
{
|
||||
m_pRecvBuffer = new HStreamBuffer(HH_SOH_MAX_COMMAND_PACKET_SIZE);
|
||||
m_nBodySize = 0;
|
||||
|
||||
m_pSendBuffer = new HStreamBuffer(HH_SOH_MAX_COMMAND_PACKET_SIZE);
|
||||
}
|
||||
|
||||
HSohHandler::~HSohHandler()
|
||||
{
|
||||
delete m_pRecvBuffer;
|
||||
delete m_pSendBuffer;
|
||||
}
|
||||
|
||||
int HSohHandler::SendBufferedPacket()
|
||||
{
|
||||
int nSentSize = SendToTransport(m_pSendBuffer->Head(), m_pSendBuffer->StoredSize());
|
||||
if (nSentSize <= 0)
|
||||
return nSentSize;
|
||||
|
||||
m_pSendBuffer->Pop(nSentSize);
|
||||
|
||||
return nSentSize;
|
||||
}
|
||||
|
||||
int HSohHandler::SendPacket(const char * pData, size_t nSize)
|
||||
{
|
||||
if (m_pSendBuffer->StoredSize() == 0)
|
||||
{
|
||||
int nSentSize = SendToTransport(pData, nSize);
|
||||
if (nSentSize < 0)
|
||||
return -1;
|
||||
|
||||
if (nSentSize != nSize)
|
||||
m_pSendBuffer->Store(pData + nSentSize, nSize - nSentSize);
|
||||
|
||||
return nSentSize;
|
||||
}
|
||||
|
||||
m_pSendBuffer->Store(pData, nSize);
|
||||
return SendBufferedPacket();
|
||||
}
|
||||
|
||||
void HSohHandler::OnReceivedStatusFromTransport(int nStatus)
|
||||
{
|
||||
if (nStatus == HTransport::T_BEGIN_TRANSPORT)
|
||||
{
|
||||
OnInitialize(true);
|
||||
}
|
||||
else if (nStatus == HTransport::T_FAILED_BEGIN)
|
||||
{
|
||||
OnInitialize(false);
|
||||
}
|
||||
else if (nStatus == HTransport::T_END_TRANSPORT)
|
||||
{
|
||||
OnTerminate();
|
||||
}
|
||||
}
|
||||
|
||||
int HSohHandler::OnReceivedFromTransport(const char * pData, int nSize)
|
||||
{
|
||||
if (m_pRecvBuffer->Store(pData, nSize) == false)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], SohHdler, Failed to insert data, buffer = %d, stored = %d, recv size = %d\n", m_pRecvBuffer->Size(), m_pRecvBuffer->StoredSize(), nSize);
|
||||
return -1; // close connection
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (m_nBodySize > 0)
|
||||
{
|
||||
if (m_nBodySize > m_pRecvBuffer->StoredSize())
|
||||
return 0; // receive remain packet
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_pRecvBuffer->StoredSize() < 4)
|
||||
return 0; // receive remain packet
|
||||
|
||||
// get body size
|
||||
m_nBodySize = ntohs(*((u_short *)(m_pRecvBuffer->Head() + 2)));
|
||||
m_pRecvBuffer->Pop(4); // pop header
|
||||
|
||||
//
|
||||
/*static int i = 0;
|
||||
if (i++ == 0)
|
||||
m_nBodySize = 69; //TestCode
|
||||
else
|
||||
m_nBodySize = 197; //TestCode*/
|
||||
|
||||
HLOGF(HLOG_ERROR, "[TRACE], SohHdler, m_nBodySize = %d\n", m_nBodySize);
|
||||
|
||||
if (m_nBodySize > m_pRecvBuffer->StoredSize())
|
||||
return 0; // receive remain packet
|
||||
}
|
||||
|
||||
m_pRecvBuffer->Head()[m_nBodySize] = '\0';
|
||||
if (OnReceivedBody(m_pRecvBuffer->Head(), m_nBodySize) < 0)
|
||||
return -1; // close connection
|
||||
|
||||
m_pRecvBuffer->Pop(m_nBodySize);
|
||||
m_nBodySize = 0;
|
||||
}
|
||||
|
||||
return -1; // close connection
|
||||
}
|
||||
|
||||
int HSohHandler::OnSendRetryToTransport()
|
||||
{
|
||||
return SendBufferedPacket();
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
#ifndef SOH_HANDLER__H_
|
||||
#define SOH_HANDLER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// size only in header
|
||||
class HSohHandler : public HProtocolHandler
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
HH_SOH_MAX_COMMAND_PACKET_SIZE = 65536
|
||||
};
|
||||
|
||||
HSohHandler();
|
||||
~HSohHandler();
|
||||
|
||||
int SendPacket(const char * pData, size_t nSize);
|
||||
|
||||
// for zero copy
|
||||
char * GetSBufPtr() { return m_pSendBuffer->Tail(); }
|
||||
size_t GetSBufSize() { return m_pSendBuffer->RemainSize(); }
|
||||
bool MarkUsedSBuf(size_t nSize) { return m_pSendBuffer->MoveTail(nSize); }
|
||||
int SendBufferedPacket();
|
||||
|
||||
protected:
|
||||
int SendBufferCommand();
|
||||
|
||||
void OnReceivedStatusFromTransport(int nStatus);
|
||||
int OnReceivedFromTransport(const char * pData, int nSize);
|
||||
|
||||
int OnSendRetryToTransport();
|
||||
bool OnPrepareReceive() { return true; }
|
||||
|
||||
virtual void OnInitialize(bool bIsSuccess) = 0;
|
||||
virtual void OnTerminate() = 0;
|
||||
virtual int OnReceivedBody(const char * pBody, int nSize) = 0;
|
||||
|
||||
protected:
|
||||
HStreamBuffer * m_pRecvBuffer;
|
||||
size_t m_nBodySize;
|
||||
|
||||
HStreamBuffer * m_pSendBuffer;
|
||||
};
|
||||
|
||||
|
||||
#endif // REDUNDANCY__H_
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
#ifndef STREAM_BUFFER__H_
|
||||
#define STREAM_BUFFER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HStreamBuffer : public HObject
|
||||
{
|
||||
public:
|
||||
HStreamBuffer(size_t nSize)
|
||||
{
|
||||
m_pBuffer = (char *)malloc(nSize); //...??? 2048 : because of openssl buffer overflow?
|
||||
m_nBufferSize = nSize;
|
||||
|
||||
m_pBufferHead = m_pBuffer;
|
||||
m_pBufferTail = m_pBuffer;
|
||||
m_nStoredSize = 0;
|
||||
m_nRemainSize = m_nBufferSize;
|
||||
}
|
||||
|
||||
~HStreamBuffer()
|
||||
{
|
||||
free(m_pBuffer);
|
||||
}
|
||||
|
||||
inline char * Head() { return m_pBufferHead; }
|
||||
inline char * Tail() { return m_pBufferTail; }
|
||||
inline size_t Size() { return m_nBufferSize; }
|
||||
inline size_t StoredSize() { return m_nStoredSize; }
|
||||
inline size_t RemainSize() { return m_nRemainSize; }
|
||||
|
||||
inline bool MoveTail(size_t nSize)
|
||||
{
|
||||
if (nSize > m_nRemainSize)
|
||||
return false;
|
||||
|
||||
m_pBufferTail += nSize;
|
||||
m_nStoredSize += nSize;
|
||||
m_nRemainSize -= nSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Pop(size_t nSize)
|
||||
{
|
||||
if (nSize > m_nStoredSize)
|
||||
return false;
|
||||
|
||||
m_nStoredSize -= nSize;
|
||||
|
||||
if (m_nStoredSize == 0)
|
||||
{
|
||||
m_pBufferHead = m_pBuffer;
|
||||
m_pBufferTail = m_pBuffer;
|
||||
m_nRemainSize = m_nBufferSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pBufferHead += nSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool PopAndRewind(size_t nSize)
|
||||
{
|
||||
if (nSize > m_nStoredSize)
|
||||
return false;
|
||||
|
||||
m_nStoredSize -= nSize;
|
||||
memcpy(m_pBufferHead, m_pBufferHead + nSize, m_nStoredSize);
|
||||
m_pBufferTail = m_pBufferHead + m_nStoredSize;
|
||||
m_nRemainSize += nSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Store(const char * pData, size_t nSize)
|
||||
{
|
||||
if (nSize > m_nRemainSize)
|
||||
return false;
|
||||
|
||||
memcpy(m_pBufferTail, pData, nSize);
|
||||
m_pBufferTail += nSize;
|
||||
m_nStoredSize += nSize;
|
||||
m_nRemainSize -= nSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void Reset()
|
||||
{
|
||||
m_pBufferHead = m_pBuffer;
|
||||
m_pBufferTail = m_pBuffer;
|
||||
m_nStoredSize = 0;
|
||||
m_nRemainSize = m_nBufferSize;
|
||||
}
|
||||
|
||||
inline int MemCmp(const void * p, size_t n)
|
||||
{
|
||||
return memcmp(m_pBufferHead, p, n);
|
||||
}
|
||||
|
||||
inline int Find(const char ch, size_t offset, size_t n = 0)
|
||||
{
|
||||
if (n == 0)
|
||||
n = m_nStoredSize;
|
||||
|
||||
for (size_t i = offset; i < n; i++)
|
||||
{
|
||||
if (m_pBufferHead[i] == ch)
|
||||
return (int)i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected:
|
||||
char * m_pBuffer;
|
||||
char * m_pBufferHead;
|
||||
char * m_pBufferTail;
|
||||
|
||||
size_t m_nBufferSize;
|
||||
size_t m_nStoredSize;
|
||||
size_t m_nRemainSize;
|
||||
};
|
||||
|
||||
#endif // STREAM_BUFFER__H_
|
||||
@@ -0,0 +1,983 @@
|
||||
|
||||
#ifndef STRING__H_
|
||||
#define STRING__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
class HString : public std::string
|
||||
{
|
||||
public:
|
||||
static int ReadOneLine(HString * pstrDst, const char * pszSrc, int nStartOffset)
|
||||
{
|
||||
const char * p = pszSrc + nStartOffset;
|
||||
|
||||
int i, nResult = -1;
|
||||
for (i = 0; *p != '\0' ; i++)
|
||||
{
|
||||
if (*p == '\r')
|
||||
{
|
||||
nResult = nStartOffset + i + 1;
|
||||
if (*(p + 1) == '\n')
|
||||
nResult++;
|
||||
|
||||
pstrDst->Assign(pszSrc + nStartOffset, i);
|
||||
break;
|
||||
}
|
||||
else if (*p == '\n')
|
||||
{
|
||||
nResult = nStartOffset + i + 1;
|
||||
pstrDst->Assign(pszSrc + nStartOffset, i);
|
||||
break;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
if (nResult == -1 && i > 0)
|
||||
{
|
||||
nResult = nStartOffset + i;
|
||||
pstrDst->Assign(pszSrc + nStartOffset, i);
|
||||
}
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
public:
|
||||
HString() {}
|
||||
HString(char ch) { operator=(ch); }
|
||||
//HString(const char * psz) : std::string(psz) {}
|
||||
HString(const char * psz) { if (psz) std::string::operator=(psz); }
|
||||
HString(const char * p, size_t nSize) : std::string(p, nSize) {}
|
||||
HString(const std::string & str) : std::string(str) {}
|
||||
|
||||
HString(short num) { operator=(num); } //??? HString * pstr = NULL; pstr ? *pstr : NULL
|
||||
HString(unsigned short num) { operator=(num); }
|
||||
HString(int num) { operator=(num); }
|
||||
HString(unsigned int num) { operator=(num); }
|
||||
HString(long num) { operator=(num); }
|
||||
HString(unsigned long num) { operator=(num); }
|
||||
HString(float num) { operator=(num); }
|
||||
HString(double num) { operator=(num); }
|
||||
#ifdef _WIN32
|
||||
HString(time_t num) { operator=(num); }
|
||||
#endif
|
||||
~HString() {}
|
||||
|
||||
inline std::string & operator=(char ch)
|
||||
{
|
||||
return std::string::operator=(ch);
|
||||
}
|
||||
|
||||
inline std::string & operator=(const char * psz)
|
||||
{
|
||||
if (psz)
|
||||
return std::string::operator=(psz);
|
||||
|
||||
return std::string::operator=("");
|
||||
}
|
||||
|
||||
inline std::string & operator=(short num) //...
|
||||
{
|
||||
char szBuf[16]; sprintf(szBuf, "%d", num);
|
||||
return std::string::operator=(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator=(unsigned short num) //...
|
||||
{
|
||||
char szBuf[16]; sprintf(szBuf, "%hd", num);
|
||||
return std::string::operator=(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator=(int num) //...
|
||||
{
|
||||
char szBuf[32]; sprintf(szBuf, "%d", num);
|
||||
return std::string::operator=(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator=(unsigned int num) //...
|
||||
{
|
||||
char szBuf[32]; sprintf(szBuf, "%u", num);
|
||||
return std::string::operator=(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator=(long num) //...
|
||||
{
|
||||
char szBuf[64]; sprintf(szBuf, "%ld", num);
|
||||
return std::string::operator=(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator=(unsigned long num) //...
|
||||
{
|
||||
char szBuf[64]; sprintf(szBuf, "%lu", num);
|
||||
return std::string::operator=(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator=(float num) //...
|
||||
{
|
||||
char szBuf[64]; sprintf(szBuf, "%f", num);
|
||||
return std::string::operator=(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator=(double num) //...
|
||||
{
|
||||
char szBuf[64]; sprintf(szBuf, "%lf", num);
|
||||
return std::string::operator=(szBuf);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
inline std::string & operator=(time_t num) //...
|
||||
{
|
||||
char szBuf[64]; sprintf(szBuf, "%lld", num);
|
||||
return std::string::operator=(szBuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline std::string & operator+=(char ch)
|
||||
{
|
||||
return std::string::operator+=(ch);
|
||||
}
|
||||
|
||||
inline std::string & operator+=(const char * psz)
|
||||
{
|
||||
if (psz == NULL)
|
||||
return *this;
|
||||
|
||||
return std::string::operator+=(psz);
|
||||
}
|
||||
|
||||
inline std::string & operator+=(const std::string & str)
|
||||
{
|
||||
return std::string::operator+=(str);
|
||||
}
|
||||
|
||||
inline std::string & operator+=(short num) //...
|
||||
{
|
||||
char szBuf[16]; sprintf(szBuf, "%d", num);
|
||||
return append(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator+=(unsigned short num) //...
|
||||
{
|
||||
char szBuf[16]; sprintf(szBuf, "%hd", num);
|
||||
return append(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator+=(int num) //...
|
||||
{
|
||||
char szBuf[32]; sprintf(szBuf, "%d", num);
|
||||
return append(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator+=(unsigned int num) //...
|
||||
{
|
||||
char szBuf[32]; sprintf(szBuf, "%u", num);
|
||||
return append(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator+=(long num) //...
|
||||
{
|
||||
char szBuf[64]; sprintf(szBuf, "%ld", num);
|
||||
return append(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator+=(unsigned long num) //...
|
||||
{
|
||||
char szBuf[64]; sprintf(szBuf, "%lu", num);
|
||||
return append(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator+=(float num) //...
|
||||
{
|
||||
char szBuf[64]; sprintf(szBuf, "%f", num);
|
||||
return append(szBuf);
|
||||
}
|
||||
|
||||
inline std::string & operator+=(double num) //...
|
||||
{
|
||||
char szBuf[64]; sprintf(szBuf, "%lf", num);
|
||||
return append(szBuf);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
inline std::string & operator+=(time_t num) //...
|
||||
{
|
||||
char szBuf[64]; sprintf(szBuf, "%lld", num);
|
||||
return append(szBuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline operator const char *() const
|
||||
{
|
||||
return c_str();
|
||||
}
|
||||
|
||||
inline operator short() const
|
||||
{
|
||||
return atoi(c_str());
|
||||
}
|
||||
|
||||
inline operator unsigned short() const
|
||||
{
|
||||
return atoi(c_str());
|
||||
}
|
||||
|
||||
inline operator int() const
|
||||
{
|
||||
return atoi(c_str());
|
||||
}
|
||||
|
||||
inline operator unsigned int() const
|
||||
{
|
||||
return atoi(c_str());
|
||||
}
|
||||
|
||||
inline operator long() const
|
||||
{
|
||||
return atol(c_str());
|
||||
}
|
||||
|
||||
inline operator unsigned long() const
|
||||
{
|
||||
return atol(c_str());
|
||||
}
|
||||
|
||||
inline const char * psz() const
|
||||
{
|
||||
return c_str();
|
||||
}
|
||||
|
||||
inline size_t GetLength() const
|
||||
{
|
||||
return length();
|
||||
}
|
||||
|
||||
inline bool IsEmpty() const
|
||||
{
|
||||
return empty();
|
||||
}
|
||||
|
||||
inline void Reserve(size_t nSize)
|
||||
{
|
||||
reserve(nSize);
|
||||
}
|
||||
|
||||
inline std::string & Assign(const char * psz, size_t nOffset)
|
||||
{
|
||||
return assign(psz, nOffset);
|
||||
}
|
||||
|
||||
inline size_t Copy(char * psz, size_t len, size_t pos = 0) const
|
||||
{
|
||||
return copy(psz, len, pos);
|
||||
}
|
||||
|
||||
inline HString SubStr(const size_t pos, size_t len) const
|
||||
{
|
||||
return substr(pos, len);
|
||||
}
|
||||
|
||||
inline int StrNCmp(const char * psz, unsigned int nCount)
|
||||
{
|
||||
return ::strncmp(c_str(), psz, nCount);
|
||||
}
|
||||
|
||||
inline int StrNICmp(const char * psz, unsigned int nCount)
|
||||
{
|
||||
return ::strnicmp(c_str(), psz, nCount);
|
||||
}
|
||||
|
||||
inline const char * StrNStr(const char * psz, int nCount = -1) const
|
||||
{
|
||||
return ::StrNStr(c_str(), psz, nCount);
|
||||
}
|
||||
|
||||
inline const char * StrNIStr(const char * psz, int nCount = -1) const
|
||||
{
|
||||
return ::StrNIStr(c_str(), psz, nCount);
|
||||
}
|
||||
|
||||
inline const char * ToUpper()
|
||||
{
|
||||
char * pszDst = (char *)malloc(GetLength() + 1);
|
||||
char * pszOffset = pszDst;
|
||||
const char * pszSrc = psz();
|
||||
|
||||
while (*pszSrc)
|
||||
{
|
||||
*pszOffset++ = toupper(*pszSrc++);
|
||||
}
|
||||
*pszOffset = '\0';
|
||||
|
||||
std::string::operator=(pszDst);
|
||||
free(pszDst);
|
||||
|
||||
return c_str();
|
||||
}
|
||||
|
||||
inline const char * ToLower()
|
||||
{
|
||||
char * pszDst = (char *)malloc(GetLength() + 1);
|
||||
char * pszOffset = pszDst;
|
||||
const char * pszSrc = psz();
|
||||
|
||||
while (*pszSrc)
|
||||
{
|
||||
*pszOffset++ = tolower(*pszSrc++);
|
||||
}
|
||||
*pszOffset = '\0';
|
||||
|
||||
std::string::operator=(pszDst);
|
||||
free(pszDst);
|
||||
|
||||
return c_str();
|
||||
}
|
||||
|
||||
inline int CompareNoCase(const char * p) const
|
||||
{
|
||||
return stricmp(psz(), p);
|
||||
}
|
||||
|
||||
inline char GetLast() const
|
||||
{
|
||||
if (empty())
|
||||
return -1;
|
||||
|
||||
return psz()[GetLength() - 1];
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable:4267)
|
||||
#endif
|
||||
inline long Find(const HString & str, size_t pos = 0) const
|
||||
{
|
||||
size_t nResult = find(str, pos);
|
||||
if (nResult == std::string::npos)
|
||||
return -1;
|
||||
return nResult;
|
||||
}
|
||||
|
||||
inline long Find(const char * psz, size_t pos = 0) const
|
||||
{
|
||||
size_t nResult = find(psz, pos);
|
||||
if (nResult == std::string::npos)
|
||||
return -1;
|
||||
return nResult;
|
||||
}
|
||||
|
||||
inline long Find(const char * psz, size_t pos, size_t n) const
|
||||
{
|
||||
size_t nResult = find(psz, pos, n);
|
||||
if (nResult == std::string::npos)
|
||||
return -1;
|
||||
return nResult;
|
||||
}
|
||||
|
||||
inline long Find(char c, size_t pos = 0) const
|
||||
{
|
||||
size_t nResult = find(c, pos);
|
||||
if (nResult == std::string::npos)
|
||||
return -1;
|
||||
return nResult;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
#pragma warning(default:4267)
|
||||
#endif
|
||||
|
||||
void Trim(bool bRemoveFront, bool bRemoveRear)
|
||||
{
|
||||
char * pszBuffer = (char *)malloc(GetLength() + 1);
|
||||
char * pszDst = pszBuffer;
|
||||
strcpy(pszDst, psz());
|
||||
StrTrim(&pszDst, GetLength(), bRemoveFront, bRemoveRear);
|
||||
std::string::operator=(pszDst);
|
||||
free(pszBuffer);
|
||||
}
|
||||
|
||||
bool Replace(const char * pszKeyword, const char * pszReplace, int nMode = 0, int nCount = -1) // nMode : 0 = case sensitive, 1 = no case, 2 = keyword
|
||||
{
|
||||
if (nCount == 0)
|
||||
return false;
|
||||
|
||||
const char * (*fnStrStr)(const char *, const char *);
|
||||
if (nMode == 0)
|
||||
fnStrStr = (const char*(*)(const char*, const char*))strstr;
|
||||
else if (nMode == 1)
|
||||
fnStrStr = stristr;
|
||||
else
|
||||
fnStrStr = StrIKeyword;
|
||||
|
||||
int nRepeatCount = nCount;
|
||||
size_t nKeywordLength = strlen(pszKeyword);
|
||||
const char * pszNext = psz();
|
||||
int nKeywordCount = 0;
|
||||
for (;;)
|
||||
{
|
||||
if ((pszNext = fnStrStr(pszNext, pszKeyword)) == NULL)
|
||||
break;
|
||||
|
||||
nKeywordCount++;
|
||||
|
||||
if (nRepeatCount > -1 && --nRepeatCount == 0)
|
||||
break;
|
||||
|
||||
pszNext += nKeywordLength;
|
||||
}
|
||||
|
||||
if (nKeywordCount == 0)
|
||||
return false;
|
||||
|
||||
size_t nReplaceLength = strlen(pszReplace);
|
||||
size_t nTextLength = GetLength();
|
||||
size_t nNewTextLength = nTextLength + (nReplaceLength - nKeywordLength) * nKeywordCount;
|
||||
char * pszNewText = (char *)malloc(nNewTextLength + 1);
|
||||
|
||||
size_t nCopySize;
|
||||
size_t nRemainSize = nTextLength;
|
||||
char * pszNewTextOffset = pszNewText;
|
||||
const char * pszTextOffset = psz();
|
||||
|
||||
nRepeatCount = nCount;
|
||||
for (;;)
|
||||
{
|
||||
if ((pszNext = fnStrStr(pszTextOffset, pszKeyword)) == NULL)
|
||||
break;
|
||||
|
||||
nCopySize = pszNext - pszTextOffset;
|
||||
|
||||
memcpy(pszNewTextOffset, pszTextOffset, nCopySize);
|
||||
memcpy(pszNewTextOffset + nCopySize, pszReplace, nReplaceLength);
|
||||
|
||||
pszTextOffset += nCopySize + nKeywordLength;
|
||||
pszNewTextOffset += nCopySize + nReplaceLength;
|
||||
|
||||
nRemainSize -= nCopySize + nKeywordLength;
|
||||
|
||||
if (nRepeatCount > -1 && --nRepeatCount == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nRemainSize > 0)
|
||||
memcpy(pszNewTextOffset, pszTextOffset, nRemainSize);
|
||||
|
||||
pszNewText[nNewTextLength] = '\0';
|
||||
std::string::operator=(pszNewText);
|
||||
free(pszNewText);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// " a b c " --> " a b c "
|
||||
void RemoveRedundancyChar(const char * pszSrc, size_t nLength, char ch)
|
||||
{
|
||||
*this = "";
|
||||
|
||||
if (pszSrc == NULL || nLength == 0)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < nLength; i++)
|
||||
{
|
||||
if (pszSrc[i] == ch && pszSrc[i + 1] == ch)
|
||||
continue;
|
||||
|
||||
*this += pszSrc[i];
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveRedundancyRow(const char * pszSrc, size_t nLength)
|
||||
{
|
||||
*this = "";
|
||||
|
||||
if (pszSrc == NULL || nLength == 0)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < nLength; i++)
|
||||
{
|
||||
if (pszSrc[i] == '\r' && pszSrc[i + 1] == '\n' && pszSrc[i + 2] == '\r' && pszSrc[i + 3] == '\n')
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
*this += pszSrc[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Cut(char chDelimiter)
|
||||
{
|
||||
char * p = (char *)psz();
|
||||
size_t nLength = GetLength();
|
||||
|
||||
for (size_t i = 0; i < nLength; i++)
|
||||
{
|
||||
if (p[i] == chDelimiter)
|
||||
{
|
||||
p[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PartAssign(const char * psz, char chDelimiter)
|
||||
{
|
||||
size_t i = 0;
|
||||
for (; psz[i]; i++)
|
||||
{
|
||||
if (psz[i] == chDelimiter)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
return;
|
||||
|
||||
Assign(psz, i);
|
||||
}
|
||||
|
||||
/*int Tokenize(const char * psz, size_t nSize, char chDelimiter)
|
||||
{
|
||||
for (size_t i = 0; i < nSize; i++)
|
||||
{
|
||||
if (psz[i] == ' ')
|
||||
{
|
||||
if (i > 0)
|
||||
Assign(psz, i);
|
||||
|
||||
return (int)(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}*/
|
||||
|
||||
// 2019-11-01 0:02 -> YYYY-MM-DD HH:MM
|
||||
void ConvertDateTime()
|
||||
{
|
||||
if (GetLength() == 15)
|
||||
{
|
||||
HString str(psz(), 11);
|
||||
str += "0";
|
||||
str += this->SubStr(11, 4);
|
||||
*this = str;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
class HStringTokenizer : public HObject
|
||||
{
|
||||
public:
|
||||
HStringTokenizer(const HString & str, const char cDelimiter)
|
||||
{
|
||||
Tokenize(str, cDelimiter);
|
||||
}
|
||||
|
||||
HStringTokenizer(const char * psz, const char cDelimiter)
|
||||
{
|
||||
HString str = psz;
|
||||
Tokenize(str, cDelimiter);
|
||||
}
|
||||
|
||||
~HStringTokenizer()
|
||||
{
|
||||
if (m_arr)
|
||||
delete [] m_arr;
|
||||
}
|
||||
|
||||
inline size_t GetCount() { return m_nCount; }
|
||||
|
||||
//inline HString & operator [] (int nIndex)
|
||||
inline HString & operator [] (size_t nIndex)
|
||||
{
|
||||
return m_arr[nIndex];
|
||||
}
|
||||
|
||||
protected:
|
||||
// |a|b - fail
|
||||
inline void Tokenize(const HString & str, const char cDelimiter)
|
||||
{
|
||||
if (str.IsEmpty())
|
||||
{
|
||||
m_arr = NULL;
|
||||
m_nCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
m_nCount = std::count(str.begin(), str.end(), cDelimiter) + 1;
|
||||
m_arr = new HString[m_nCount];
|
||||
|
||||
std::istringstream stream(str);
|
||||
std::string token;
|
||||
int i = 0;
|
||||
while (std::getline(stream, token, cDelimiter))
|
||||
{
|
||||
m_arr[i++] = token;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HString * m_arr;
|
||||
size_t m_nCount;
|
||||
};
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
class HUtf16ToUtf8
|
||||
{
|
||||
public:
|
||||
HUtf16ToUtf8()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
m_iconv = iconv_open("UTF-8", "UTF-16LE");
|
||||
#endif
|
||||
m_pUtf8 = NULL;
|
||||
}
|
||||
|
||||
~HUtf16ToUtf8()
|
||||
{
|
||||
if (m_pUtf8)
|
||||
free(m_pUtf8);
|
||||
|
||||
#ifndef _WIN32
|
||||
iconv_close(m_iconv);
|
||||
#endif
|
||||
}
|
||||
|
||||
char * Convert(const char * pSrc, int nLen)
|
||||
{
|
||||
if (m_pUtf8)
|
||||
free(m_pUtf8);
|
||||
|
||||
#ifndef _WIN32
|
||||
size_t nDstLen = nLen * 2;
|
||||
m_pUtf8 = (char *)calloc(nDstLen + 1, 1);
|
||||
char * pSrc2 = (char *)calloc(nLen + 1, 1);
|
||||
memcpy(pSrc2, pSrc, nLen + 1);
|
||||
|
||||
char * pUtf16 = pSrc2;
|
||||
char * pDst = m_pUtf8;
|
||||
|
||||
iconv(m_iconv, &pUtf16, (size_t *)&nLen, &pDst, &nDstLen);
|
||||
|
||||
free(pSrc2);
|
||||
#else
|
||||
int nDstLen = WideCharToMultiByte(CP_UTF8, 0, (const wchar_t *)pSrc, (int)nLen, NULL, 0, NULL, NULL);
|
||||
|
||||
if (nDstLen > 0)
|
||||
{
|
||||
m_pUtf8 = (char *)malloc(nDstLen + 1);
|
||||
WideCharToMultiByte(CP_UTF8, 0, (const wchar_t *)pSrc, (int)nLen, m_pUtf8, nDstLen, NULL, NULL);
|
||||
m_pUtf8[nDstLen] = '\0';
|
||||
}
|
||||
#endif
|
||||
return m_pUtf8;
|
||||
}
|
||||
|
||||
protected:
|
||||
#ifndef _WIN32
|
||||
iconv_t m_iconv;
|
||||
#endif
|
||||
char * m_pUtf8;
|
||||
};
|
||||
|
||||
class HUtf8ToEucKr
|
||||
{
|
||||
public:
|
||||
HUtf8ToEucKr()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
m_iconv = iconv_open("EUC-KR", "UTF-8");
|
||||
#endif
|
||||
m_pEucKr = NULL;
|
||||
}
|
||||
|
||||
~HUtf8ToEucKr()
|
||||
{
|
||||
if (m_pEucKr)
|
||||
free(m_pEucKr);
|
||||
|
||||
#ifndef _WIN32
|
||||
iconv_close(m_iconv);
|
||||
#endif
|
||||
}
|
||||
|
||||
char * Convert(const char * pSrc, int nLen)
|
||||
{
|
||||
if (pSrc == NULL || pSrc[0] == '\0' || nLen <= 0)
|
||||
return "";
|
||||
|
||||
if (m_pEucKr)
|
||||
free(m_pEucKr);
|
||||
|
||||
#ifndef _WIN32
|
||||
size_t nDstLen = nLen * 2;
|
||||
m_pEucKr = (char *)calloc(nDstLen + 1, 1);
|
||||
char * pSrc2 = (char *)calloc(nLen + 1, 1);
|
||||
strcpy(pSrc2, pSrc);
|
||||
|
||||
char * pUtf8 = pSrc2;
|
||||
char * pDst = m_pEucKr;
|
||||
|
||||
iconv(m_iconv, &pUtf8, (size_t *)&nLen, &pDst, &nDstLen);
|
||||
|
||||
free(pSrc2);
|
||||
#else
|
||||
int nLength = MultiByteToWideChar(CP_UTF8, 0, pSrc, nLen + 1, NULL, NULL);
|
||||
BSTR bstrWide = SysAllocStringLen(NULL, nLength);
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, pSrc, nLen + 1, bstrWide, nLength);
|
||||
|
||||
nLength = WideCharToMultiByte(CP_ACP, 0, bstrWide, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
m_pEucKr = (char *)malloc(nLength);
|
||||
|
||||
WideCharToMultiByte(CP_ACP, 0, bstrWide, -1, m_pEucKr, nLength, NULL, NULL);
|
||||
SysFreeString(bstrWide);
|
||||
#endif
|
||||
return m_pEucKr;
|
||||
}
|
||||
|
||||
protected:
|
||||
#ifndef _WIN32
|
||||
iconv_t m_iconv;
|
||||
#endif
|
||||
char * m_pEucKr;
|
||||
};
|
||||
|
||||
class HEucKrToUtf8
|
||||
{
|
||||
public:
|
||||
HEucKrToUtf8()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
m_iconv = iconv_open("UTF-8", "EUC-KR");
|
||||
#endif
|
||||
m_pUtf8 = NULL;
|
||||
}
|
||||
|
||||
~HEucKrToUtf8()
|
||||
{
|
||||
if (m_pUtf8)
|
||||
free(m_pUtf8);
|
||||
|
||||
#ifndef _WIN32
|
||||
iconv_close(m_iconv);
|
||||
#endif
|
||||
}
|
||||
|
||||
char * Convert(const char * pSrc, int nLen)
|
||||
{
|
||||
if (m_pUtf8)
|
||||
free(m_pUtf8);
|
||||
|
||||
#ifndef _WIN32
|
||||
size_t nDstLen = nLen * 4;
|
||||
m_pUtf8 = (char *)calloc(nDstLen + 1, 1);
|
||||
char * pSrc2 = (char *)calloc(nLen + 1, 1);
|
||||
strcpy(pSrc2, pSrc);
|
||||
|
||||
char * pUtf16 = pSrc2;
|
||||
char * pDst = m_pUtf8;
|
||||
|
||||
iconv(m_iconv, &pUtf16, (size_t *)&nLen, &pDst, &nDstLen);
|
||||
|
||||
free(pSrc2);
|
||||
#else
|
||||
int nLength = MultiByteToWideChar(CP_ACP, 0, pSrc, nLen, NULL, NULL);
|
||||
BSTR bstrCode = SysAllocStringLen(NULL, nLength);
|
||||
MultiByteToWideChar(CP_ACP, 0, pSrc, nLen, bstrCode, nLength);
|
||||
|
||||
int nLength2 = WideCharToMultiByte(CP_UTF8, 0, bstrCode, -1, m_pUtf8, 0, NULL, NULL);
|
||||
m_pUtf8 = (char*)malloc(nLength2 + 1);
|
||||
WideCharToMultiByte(CP_UTF8, 0, bstrCode, -1, m_pUtf8, nLength2, NULL, NULL);
|
||||
SysFreeString(bstrCode);
|
||||
#endif
|
||||
return m_pUtf8;
|
||||
}
|
||||
|
||||
protected:
|
||||
#ifndef _WIN32
|
||||
iconv_t m_iconv;
|
||||
#endif
|
||||
char * m_pUtf8;
|
||||
};
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
extern inline void RemoveTagElement(HString * pstrDst, const char * pszSrc, size_t nLength, const char * pszTag)
|
||||
{
|
||||
*pstrDst = "";
|
||||
|
||||
if (pszSrc == NULL || nLength == 0)
|
||||
return;
|
||||
|
||||
HString strFrontTag = "<"; strFrontTag += pszTag;
|
||||
HString strRearTag = "</"; strRearTag += pszTag; strRearTag += ">";
|
||||
|
||||
bool bSkip = false;
|
||||
for (size_t i = 0; i < nLength; i++, pszSrc++)
|
||||
{
|
||||
if (bSkip)
|
||||
{
|
||||
if (strnicmp(pszSrc, strRearTag, strRearTag.GetLength()) == 0)
|
||||
{
|
||||
bSkip = false;
|
||||
i += strRearTag.GetLength() - 1;
|
||||
pszSrc += strRearTag.GetLength() - 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (strnicmp(pszSrc, strFrontTag, strFrontTag.GetLength()) == 0)
|
||||
{
|
||||
bSkip = true;
|
||||
i += strFrontTag.GetLength() - 1;
|
||||
pszSrc += strFrontTag.GetLength() - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
*pstrDst += *pszSrc;
|
||||
}
|
||||
}
|
||||
|
||||
extern inline void RemoveMarkupTag(HString * pstrDst, const char * pszSrc, size_t nLength)
|
||||
{
|
||||
*pstrDst = "";
|
||||
|
||||
if (pszSrc == NULL || nLength == 0)
|
||||
return;
|
||||
|
||||
int nSkipMode = 0; // 0 : no skip, 1 : normal tag, 2 : comment tag
|
||||
for (size_t i = 0; i < nLength; i++)
|
||||
{
|
||||
if (nSkipMode == 1)
|
||||
{
|
||||
if (pszSrc[i] == '>')
|
||||
nSkipMode = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (nSkipMode == 2)
|
||||
{
|
||||
if (pszSrc[i] == '-' && pszSrc[i + 1] == '-' && pszSrc[i + 2] == '>')
|
||||
{
|
||||
i += 2;
|
||||
nSkipMode = 0;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (pszSrc[i] == '<')
|
||||
{
|
||||
if (pszSrc[i + 1] == '!' && pszSrc[i + 2] == '-' && pszSrc[i + 3] == '-')
|
||||
{
|
||||
i += 2;
|
||||
nSkipMode = 2;
|
||||
}
|
||||
else
|
||||
nSkipMode = 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
*pstrDst += pszSrc[i];
|
||||
}
|
||||
}
|
||||
|
||||
extern inline size_t ClearSpaceAndRow(HString * pstrDst, const char * pszSrc, size_t nLength, bool bRemoveRow)
|
||||
{
|
||||
size_t nRowCount = 0;
|
||||
*pstrDst = "";
|
||||
|
||||
if (pszSrc == NULL || nLength == 0)
|
||||
return nRowCount;
|
||||
|
||||
char * pNextLine = (char *)pszSrc;
|
||||
char * pOneLine;
|
||||
do
|
||||
{
|
||||
pOneLine = pNextLine;
|
||||
pNextLine = StrSlice(pOneLine);
|
||||
|
||||
StrTrim(&pOneLine, strlen(pOneLine), true, true);
|
||||
if (pOneLine[0] == '\0')
|
||||
continue;
|
||||
|
||||
*pstrDst += pOneLine;
|
||||
|
||||
nRowCount++;
|
||||
|
||||
if (bRemoveRow == false)
|
||||
*pstrDst += "\r\n";
|
||||
|
||||
} while (pNextLine);
|
||||
|
||||
return nRowCount;
|
||||
}
|
||||
|
||||
extern inline void StrRemoveRow(HString * pstrDst, const char * pszSrc, const char * pszKeyword)
|
||||
{
|
||||
*pstrDst = "";
|
||||
|
||||
if (pszSrc == NULL || pszKeyword == NULL)
|
||||
return;
|
||||
|
||||
char * pNextLine = (char *)pszSrc;
|
||||
char * pOneLine;
|
||||
do
|
||||
{
|
||||
pOneLine = pNextLine;
|
||||
pNextLine = StrSlice(pOneLine);
|
||||
|
||||
StrTrim(&pOneLine, strlen(pOneLine), true, true);
|
||||
if (pOneLine[0] == '\0' || stristr(pOneLine, pszKeyword))
|
||||
continue;
|
||||
|
||||
*pstrDst += pOneLine;
|
||||
*pstrDst += "\r\n";
|
||||
|
||||
} while (pNextLine);
|
||||
}
|
||||
|
||||
// nMode = 0 : between, 1 : with front, 2 : with rear, 3 : both remove
|
||||
extern inline void StrBetweenRemove(HString * pstrDst, const char * pszSrc, const char * pszFront, const char * pszRear, int nMode)
|
||||
{
|
||||
*pstrDst = "";
|
||||
|
||||
if (pszSrc == NULL || pszFront == NULL || pszRear == NULL)
|
||||
return;
|
||||
|
||||
char * pszStart, * pszEnd;
|
||||
|
||||
if ((pszStart = (char *)strstr(pszSrc, pszFront)) == NULL)
|
||||
return;
|
||||
size_t nFrontSize = strlen(pszFront);
|
||||
pszStart += nFrontSize;
|
||||
|
||||
if ((pszEnd = strstr(pszStart, pszRear)) == NULL)
|
||||
return;
|
||||
|
||||
if (nMode == 1 || nMode == 3)
|
||||
pszStart -= nFrontSize;
|
||||
|
||||
pstrDst->Assign(pszSrc, pszStart - pszSrc);
|
||||
|
||||
if (nMode == 2 || nMode == 3)
|
||||
*pstrDst += (pszEnd + strlen(pszRear));
|
||||
else
|
||||
*pstrDst += pszEnd;
|
||||
}
|
||||
|
||||
#endif // STRING__H_
|
||||
@@ -0,0 +1,106 @@
|
||||
|
||||
#include "huslib.h"
|
||||
#include "huslibex.h"
|
||||
#include "MultiplexSocket.h"
|
||||
#include "MultiplexTransport.h"
|
||||
|
||||
|
||||
HTelnetHandler::HTelnetHandler()
|
||||
{
|
||||
m_nCommandBufferedLength = 0;
|
||||
m_bInitialStep = 0;
|
||||
}
|
||||
|
||||
HTelnetHandler::~HTelnetHandler()
|
||||
{
|
||||
}
|
||||
|
||||
void HTelnetHandler::OnReceivedStatusFromTransport(int nStatus)
|
||||
{
|
||||
if (nStatus == HTransport::T_BEGIN_TRANSPORT)
|
||||
{
|
||||
char bufSend[4];
|
||||
bufSend[0] = (char)IAC;
|
||||
bufSend[1] = (char)WILL;
|
||||
bufSend[2] = (char)SGAHEAD;
|
||||
|
||||
SendToTransport(bufSend, 3);
|
||||
}
|
||||
}
|
||||
|
||||
int HTelnetHandler::OnReceivedFromTransport(const char * pData, int nSize)
|
||||
{
|
||||
if (m_bInitialStep == 0 && pData[0] == (char)IAC && pData[1] == (char)DO &&
|
||||
pData[2] == (char)SGAHEAD)
|
||||
{
|
||||
if (m_bInitialStep != 0)
|
||||
return -1; // close connection
|
||||
|
||||
m_bInitialStep = 1;
|
||||
|
||||
char bufSend[4];
|
||||
bufSend[0] = (char)IAC;
|
||||
bufSend[1] = (char)WILL;
|
||||
bufSend[2] = (char)ECHO;
|
||||
|
||||
SendToTransport(bufSend, 3);
|
||||
return 0;
|
||||
}
|
||||
else if (m_bInitialStep == 1 && pData[0] == (char)IAC && pData[1] == (char)DO &&
|
||||
pData[2] == (char)ECHO)
|
||||
{
|
||||
if (m_bInitialStep != 1)
|
||||
return -1; // close connection
|
||||
|
||||
m_bInitialStep = 2;
|
||||
|
||||
OnEstablished();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pData[0] == '\t' || ((nSize >= 3 && pData[0] == 0x1b && pData[1] == 0x5b) &&
|
||||
(pData[2] == 0x41 || // up
|
||||
pData[2] == 0x42 || // down
|
||||
pData[2] == 0x43 || // right
|
||||
pData[2] == 0x44))) // left
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (pData[0] == '\b')
|
||||
{
|
||||
if (m_nCommandBufferedLength > 0)
|
||||
m_nCommandBufferedLength--;
|
||||
|
||||
SendToTransport("\b \b", 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_bInitialStep == 2 && OnInitialReceive(pData, nSize))
|
||||
m_bInitialStep = 3;
|
||||
|
||||
if (m_bInitialStep == 3)
|
||||
SendToTransport(pData, nSize);
|
||||
|
||||
memcpy(m_pCommandBuffer + m_nCommandBufferedLength, pData, nSize);
|
||||
m_nCommandBufferedLength += nSize;
|
||||
|
||||
HString strTemp(pData, nSize);
|
||||
if (strTemp.Find('\n') > 0)
|
||||
{
|
||||
for (int i = m_nCommandBufferedLength - 1; i >= 0; i--)
|
||||
{
|
||||
if (m_pCommandBuffer[i] == '\r' || m_pCommandBuffer[i] == '\n')
|
||||
m_pCommandBuffer[i] = '\0';
|
||||
}
|
||||
|
||||
int nResult = OnReceivedCommand(m_pCommandBuffer);
|
||||
m_nCommandBufferedLength = 0;
|
||||
|
||||
if (nResult >= 0)
|
||||
SendToTransport("> ", 2);
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#ifndef TELNET_HANDLER__H_
|
||||
#define TELNET_HANDLER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HTelnetHandler : public HProtocolHandler
|
||||
{
|
||||
public:
|
||||
enum eCommand
|
||||
{
|
||||
SE = 240, // End of subnegotiation parameters.
|
||||
NOP = 241, // No operation Data mark. Indicates the position of a Synch event within the data stream.
|
||||
DM = 242, // This should always be accompanied by a TCP urgent notification.
|
||||
BRK = 243, // Break. Indicates that the "break" or "attention" key was hit.
|
||||
IP = 244, // Suspend, interrupt or abort the process to which the NVT is connected.
|
||||
AO = 245, // Abort output. Allows the current process to run to completion but donot send its output to the user.
|
||||
AYT = 246, // Are you there. Send back to the NVT some visible evidence that the AYT was received.
|
||||
EC = 247, // Erase character. The receiver should delete the last preceding undeleted character from the data stream.
|
||||
EL = 248, // Erase line. Delete characters from the data stream back to but not including the previous CRLF.
|
||||
GA = 249, // Go ahead. Used, under certain circumstances, to tell the other end that it can transmit.
|
||||
SB = 250, // Subnegotiation of the indicated option follows.
|
||||
WILL = 251, // Indicates the desire to begin performing, or confirmation that you are now performing, the indicated option.
|
||||
WONT = 252, // Indicates the refusal to perform, or continue performing, the indicated option.
|
||||
DO = 253, // Indicates the request that the other party perform, or confirmation that you are expecting the other party to perform, the indicated option.
|
||||
DONT = 254, // Indicates the demand that the other party stop performing, or confirmation that you are no longer expecting the other party to perform, the indicated option.
|
||||
IAC = 255 // Interpret as command.
|
||||
};
|
||||
|
||||
enum EOption
|
||||
{
|
||||
ECHO = 1, // echo (RFC 857)
|
||||
SGAHEAD = 3, // suppress go ahead (RFC 858)
|
||||
STATUS = 5, // status (RFC 859)
|
||||
TMARK = 6, // timing mark (RFC 860)
|
||||
TTYPE = 24, // terminal type (RFC 1091)
|
||||
WSIZE = 31, // window size (RFC 1073)
|
||||
TSPEED = 32, // terminal speed (RFC 1079)
|
||||
RFCONTROL = 33, // remote flow control (RFC 1372)
|
||||
LMODE = 34, // linemode (RFC 1184)
|
||||
EVARIABLES = 36, // environment variables (RFC 1408)
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_COMMAND_BUFFER_SIZE = 4096
|
||||
};
|
||||
|
||||
HTelnetHandler();
|
||||
~HTelnetHandler();
|
||||
|
||||
protected:
|
||||
void OnReceivedStatusFromTransport(int nStatus);
|
||||
int OnReceivedFromTransport(const char * pData, int nSize);
|
||||
|
||||
virtual void OnEstablished() {}
|
||||
virtual bool OnInitialReceive(const char * pData, unsigned nSize) { return true; }
|
||||
virtual int OnReceivedCommand(const char * pszCommand) = 0;
|
||||
|
||||
protected:
|
||||
char m_pCommandBuffer[MAX_COMMAND_BUFFER_SIZE + 1];
|
||||
unsigned int m_nCommandBufferedLength;
|
||||
|
||||
int m_bInitialStep;
|
||||
};
|
||||
|
||||
|
||||
#endif // PROTOCOL_HANDLER__H_
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
#include "huslib.h"
|
||||
#include "huslibex.h"
|
||||
|
||||
|
||||
HTelnetServer::HTelnetServer()
|
||||
{
|
||||
}
|
||||
|
||||
HTelnetServer::~HTelnetServer()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
#ifndef TELNET_SERVER__H
|
||||
#define TELNET_SERVER__H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HTelnetServer : public HTelnetHandler
|
||||
{
|
||||
public:
|
||||
HTelnetServer();
|
||||
~HTelnetServer();
|
||||
|
||||
int OnSendRetryToTransport() { return -1; }
|
||||
bool OnPrepareReceive() { return true; }
|
||||
};
|
||||
|
||||
#endif // HTTP_HANDLER__H
|
||||
@@ -0,0 +1,453 @@
|
||||
|
||||
#ifndef THREAD__H_
|
||||
#define THREAD__H_
|
||||
|
||||
|
||||
#ifndef COMMON__H_
|
||||
#include "common.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#pragma once
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
//#include <signal.h>
|
||||
|
||||
//#define WAIT_NEW_VER_
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define pthread_self GetCurrentThreadId
|
||||
#else
|
||||
#define GetCurrentThreadId pthread_self
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
class HSyncObject : public HObject
|
||||
{
|
||||
public:
|
||||
HSyncObject()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
InitializeCriticalSection(&m_instance);
|
||||
#else
|
||||
pthread_mutex_init(&m_instance, NULL);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
virtual ~HSyncObject()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DeleteCriticalSection(&m_instance);
|
||||
#else
|
||||
pthread_mutex_destroy(&m_instance);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
bool IsLocked();
|
||||
|
||||
int Lock();
|
||||
int Unlock();
|
||||
|
||||
protected:
|
||||
#ifdef _WIN32
|
||||
CRITICAL_SECTION m_instance;
|
||||
#else
|
||||
pthread_mutex_t m_instance;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline int HSyncObject::Lock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
EnterCriticalSection(&m_instance);
|
||||
return 0;
|
||||
#else
|
||||
return pthread_mutex_lock(&m_instance);
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
inline int HSyncObject::Unlock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
LeaveCriticalSection(&m_instance);
|
||||
return 0;
|
||||
#else
|
||||
return pthread_mutex_unlock(&m_instance);
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
class HAutoLock : public HObject
|
||||
{
|
||||
public:
|
||||
HAutoLock(HSyncObject * pObject) : m_pObject(pObject) { m_pObject->Lock(); }
|
||||
~HAutoLock() { m_pObject->Unlock(); }
|
||||
|
||||
private:
|
||||
HSyncObject * m_pObject;
|
||||
};
|
||||
|
||||
|
||||
class HSyncEvent : public HObject
|
||||
{
|
||||
public:
|
||||
HSyncEvent(bool bManualReset = false, bool bInitialState = false)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
m_hEvent = CreateEvent(NULL, bManualReset, bInitialState, NULL);
|
||||
#else
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_cond_init(&m_cond, NULL);
|
||||
|
||||
m_bManualReset = bManualReset;
|
||||
|
||||
if (bInitialState)
|
||||
m_bEventSet = true;
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
~HSyncEvent()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CloseHandle(m_hEvent);
|
||||
#else
|
||||
pthread_cond_destroy(&m_cond);
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
bool SetEvent()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return ::SetEvent(m_hEvent) != false;
|
||||
#else
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
m_bEventSet = true;
|
||||
pthread_cond_signal(&m_cond);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif // _WIN32
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResetEvent()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return ::ResetEvent(m_hEvent) != false;
|
||||
#else
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
m_bEventSet = false;
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif // _WIN32
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Wait(DWORD dwWaitTime) // dwTimeout : msec
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (WaitForSingleObject(m_hEvent, dwWaitTime) == WAIT_TIMEOUT)
|
||||
return false;
|
||||
#else
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
|
||||
return true;
|
||||
|
||||
ts.tv_sec += dwWaitTime / 1000; // seconds
|
||||
ts.tv_nsec += (dwWaitTime % 1000) * 1000000; // nanoseconds
|
||||
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
if (m_bEventSet)
|
||||
{
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
if (m_bManualReset == false)
|
||||
m_bEventSet = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int nResult = pthread_cond_timedwait(&m_cond, &m_mutex, &ts);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
|
||||
if (nResult == ETIMEDOUT)
|
||||
return false;
|
||||
|
||||
if (m_bManualReset == false)
|
||||
m_bEventSet = false;
|
||||
#endif // _WIN32
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
HANDLE m_hEvent;
|
||||
#else
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_cond;
|
||||
|
||||
bool m_bManualReset;
|
||||
volatile bool m_bEventSet;
|
||||
#endif // _WIN32
|
||||
};
|
||||
|
||||
|
||||
class HThread : public HObject
|
||||
{
|
||||
public:
|
||||
HThread(bool bAutoDelete = false, size_t nStackSize = 0)
|
||||
: m_bAutoDelete(bAutoDelete)
|
||||
, m_nStackSize(nStackSize)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
m_hThread = NULL;
|
||||
#else
|
||||
m_tId = 0;
|
||||
|
||||
#ifndef WAIT_NEW_VER_
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_cond_init(&m_cond, NULL);
|
||||
#endif
|
||||
#endif // WIN32
|
||||
}
|
||||
~HThread() {}
|
||||
|
||||
#ifdef _WIN32
|
||||
inline HANDLE GetThreadId() { return m_hThread; }
|
||||
#else
|
||||
inline pthread_t GetThreadId() { return m_tId; }
|
||||
#endif
|
||||
|
||||
|
||||
virtual inline unsigned long Begin();
|
||||
|
||||
bool WaitForTermination(DWORD dwWaitTime)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (m_hThread == NULL)
|
||||
return true;
|
||||
|
||||
if (WaitForSingleObject(m_hThread, dwWaitTime) == WAIT_TIMEOUT)
|
||||
return false;
|
||||
#else
|
||||
if (m_tId == 0)
|
||||
return true;
|
||||
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
|
||||
return true;
|
||||
|
||||
ts.tv_sec += dwWaitTime / 1000; // seconds
|
||||
ts.tv_nsec += (dwWaitTime % 1000) * 1000000; // nanoseconds
|
||||
|
||||
#ifndef WAIT_NEW_VER_
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
int nResult = pthread_cond_timedwait(&m_cond, &m_mutex, &ts);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
|
||||
if (nResult == ETIMEDOUT)
|
||||
return false;
|
||||
#else
|
||||
if (pthread_timedjoin_np(m_tId, NULL, &ts) == ETIMEDOUT)
|
||||
return false;
|
||||
#endif // WAIT_NEW_VER_
|
||||
#endif // WIN32
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(ANDROID)
|
||||
void TerminateThread(DWORD dwExitCode = 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (m_hThread == NULL)
|
||||
return;
|
||||
|
||||
::TerminateThread(m_hThread, dwExitCode);
|
||||
CloseHandle(m_hThread);
|
||||
m_hThread = NULL;
|
||||
#else
|
||||
if (m_tId == 0)
|
||||
return;
|
||||
|
||||
pthread_cancel(m_tId);
|
||||
m_tId = 0;
|
||||
#endif
|
||||
}
|
||||
#endif //
|
||||
|
||||
protected:
|
||||
virtual void Main() = 0;
|
||||
virtual void OnTerminated() {}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
inline static DWORD WINAPI
|
||||
#else
|
||||
inline static void *
|
||||
#endif
|
||||
BeginThread(void * lpParameter);
|
||||
|
||||
private:
|
||||
void MainCallBack();
|
||||
|
||||
private:
|
||||
bool m_bAutoDelete;
|
||||
size_t m_nStackSize; // bytes
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE m_hThread;
|
||||
#else
|
||||
pthread_t m_tId;
|
||||
|
||||
#ifndef WAIT_NEW_VER_
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_cond;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
inline unsigned long HThread::Begin()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD dwThreadId;
|
||||
if ((m_hThread = ::CreateThread(NULL, m_nStackSize, BeginThread, this, 0, &dwThreadId)) == NULL)
|
||||
return ::GetLastError();
|
||||
|
||||
return 0;
|
||||
#else
|
||||
if (m_nStackSize > 0)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setstacksize(&attr, m_nStackSize);
|
||||
#if 0 // do not use
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
#endif
|
||||
int nResult = pthread_create(&m_tId, &attr, BeginThread, (void *)this);
|
||||
pthread_attr_destroy(&attr);
|
||||
return nResult;
|
||||
}
|
||||
|
||||
return pthread_create(&m_tId, NULL, BeginThread, (void *)this);
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
inline DWORD WINAPI
|
||||
#else
|
||||
inline void *
|
||||
#endif
|
||||
HThread::BeginThread(void * lpParameter)
|
||||
{
|
||||
((HThread *)lpParameter)->MainCallBack();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline void HThread::MainCallBack()
|
||||
{
|
||||
Main();
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifndef WAIT_NEW_VER_
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
pthread_cond_broadcast(&m_cond);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
#endif // WAIT_NEW_VER_
|
||||
|
||||
pthread_detach(m_tId);
|
||||
#endif
|
||||
|
||||
OnTerminated();
|
||||
|
||||
if (m_bAutoDelete)
|
||||
delete this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
class HThreadExecuter : public HThread
|
||||
{
|
||||
public:
|
||||
HThreadExecuter()
|
||||
{
|
||||
m_fnThreadMainCallBack = NULL;
|
||||
m_pThreadMainParam = NULL;
|
||||
m_fnExitThreadCallBack = NULL;
|
||||
m_pOnExitThreadParam = NULL;
|
||||
}
|
||||
HThreadExecuter(bool bAutoDelete, size_t nStackSize) : HThread(bAutoDelete, nStackSize)
|
||||
{
|
||||
m_fnThreadMainCallBack = NULL;
|
||||
m_pThreadMainParam = NULL;
|
||||
m_fnExitThreadCallBack = NULL;
|
||||
m_pOnExitThreadParam = NULL;
|
||||
}
|
||||
~HThreadExecuter()
|
||||
{
|
||||
m_fnThreadMainCallBack = NULL;
|
||||
m_pThreadMainParam = NULL;
|
||||
m_fnExitThreadCallBack = NULL;
|
||||
m_pOnExitThreadParam = NULL;
|
||||
}
|
||||
|
||||
inline void Initialize(void (*fnThreadMainCallBack)(void * pThreadParameter), // thread main procedure
|
||||
void * pThreadMainParam, // parmeter for thread main
|
||||
void (*fnExitThreadCallBack)(void * pThreadParameter), // terminated thread call back
|
||||
void * pOnExitThreadParam) // parmeter for terminated thread
|
||||
{
|
||||
m_fnThreadMainCallBack = fnThreadMainCallBack;
|
||||
m_pThreadMainParam = pThreadMainParam;
|
||||
m_fnExitThreadCallBack = fnExitThreadCallBack;
|
||||
m_pOnExitThreadParam = pOnExitThreadParam;
|
||||
}
|
||||
|
||||
protected:
|
||||
inline void Main()
|
||||
{
|
||||
if (m_fnThreadMainCallBack)
|
||||
m_fnThreadMainCallBack(m_pThreadMainParam);
|
||||
}
|
||||
|
||||
inline void OnTerminated()
|
||||
{
|
||||
if (m_fnExitThreadCallBack)
|
||||
m_fnExitThreadCallBack(m_pOnExitThreadParam);
|
||||
}
|
||||
|
||||
protected:
|
||||
void (*m_fnThreadMainCallBack)(void * pThreadParameter);
|
||||
void * m_pThreadMainParam;
|
||||
|
||||
void (*m_fnExitThreadCallBack)(void * pThreadParameter);
|
||||
void * m_pOnExitThreadParam;
|
||||
};
|
||||
/*
|
||||
<below add to .h file>
|
||||
protected:
|
||||
// $(Name) thread part
|
||||
static inline void $(Name)ThreadCallBack(void * pParam) { return static_cast<$(ClassName) *>(pParam)->$(Name)ThreadMain(); }
|
||||
static inline void $(Name)ThreadTerminatedCallBack(void * pParam) { static_cast<$(ClassName) *>(pParam)->On$(Name)ThreadTerminated(); }
|
||||
|
||||
void $(Name)ThreadMain();
|
||||
void On$(Name)ThreadTerminated();
|
||||
|
||||
HThreadExecuter * m_p$(Name)Thread;
|
||||
//
|
||||
|
||||
|
||||
<add to constructor>
|
||||
m_p$(Name)Thread = new HThreadExecuter();
|
||||
m_p$(Name)Thread->Initialize($(Name)ThreadCallBack, this, $(Name)ThreadTerminatedCallBack, this);
|
||||
m_p$(Name)Thread->Begin();
|
||||
|
||||
<add to destructor or termination code>
|
||||
delete m_p$(Name)Thread;
|
||||
*/
|
||||
#endif // THREAD__H_
|
||||
@@ -0,0 +1,200 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "Object.h"
|
||||
#include "Thread.h"
|
||||
#include "Timer.h"
|
||||
|
||||
|
||||
HTimer g_timerGlobal;
|
||||
|
||||
|
||||
|
||||
HTimer::HTimer()
|
||||
: HThread(false, 1024 * 128) // default stack size : 128kb
|
||||
{
|
||||
m_bThreadStarted = false;
|
||||
m_bTerminate = false;
|
||||
|
||||
struct tm * tmTmp;
|
||||
struct timeb tTimeb;
|
||||
|
||||
ftime(&tTimeb);
|
||||
tmTmp = localtime(&tTimeb.time);
|
||||
|
||||
m_systemTime.wYear = tmTmp->tm_year + 1900;
|
||||
m_systemTime.wMonth = tmTmp->tm_mon + 1;
|
||||
m_systemTime.wDay = tmTmp->tm_mday;
|
||||
m_systemTime.wHour = tmTmp->tm_hour;
|
||||
m_systemTime.wMinute = tmTmp->tm_min;
|
||||
m_systemTime.wSecond = tmTmp->tm_sec;
|
||||
m_systemTime.wMilliseconds = tTimeb.millitm;
|
||||
|
||||
m_nTickCount = ::GetTickCount();
|
||||
|
||||
|
||||
Begin(); // start timer thread
|
||||
|
||||
while (m_bThreadStarted == false) // wait for thread started
|
||||
Sleep(10);
|
||||
}
|
||||
|
||||
HTimer::~HTimer()
|
||||
{
|
||||
RemoveAllTimer();
|
||||
}
|
||||
|
||||
void HTimer::GetSystemTime(PSYSTEMTIME pSystemTime)
|
||||
{
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_syncSystemTime.Lock();
|
||||
#endif
|
||||
memcpy(pSystemTime, (void *)&m_systemTime, sizeof(SYSTEMTIME));
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_syncSystemTime.Unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool HTimer::SetTimer(unsigned int nTimerID, unsigned int nElapse, void (*fnCallBack)(unsigned int, void *), void * pParam)
|
||||
{
|
||||
struct HTimerObject * pTimerObject = new struct HTimerObject;
|
||||
pTimerObject->nTimerID = nTimerID;
|
||||
pTimerObject->nElapse = nElapse;
|
||||
pTimerObject->dwLastCheckTime = m_nTickCount;
|
||||
pTimerObject->bDelete = false;
|
||||
pTimerObject->fnOnTimerCallBack = fnCallBack;
|
||||
pTimerObject->pOnTimerCallBackParam = pParam;
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
// m_sync.Lock();
|
||||
#endif
|
||||
|
||||
m_listTimer.push_front(pTimerObject);
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
// m_sync.Unlock();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HTimer::KillTimer(unsigned int nTimerID)
|
||||
{
|
||||
struct HTimerObject * pTimerObject;
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
// m_sync.Lock();
|
||||
#endif
|
||||
|
||||
for(LIST_TIMER_OBJECT::iterator iter = m_listTimer.begin();
|
||||
iter != m_listTimer.end(); iter++)
|
||||
{
|
||||
pTimerObject = *iter;
|
||||
if (pTimerObject->nTimerID == nTimerID)
|
||||
{
|
||||
#if 0
|
||||
delete pTimerObject;
|
||||
m_listTimer.erase(iter);
|
||||
#else
|
||||
pTimerObject->bDelete = true;
|
||||
#endif
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
// m_sync.Unlock();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
// m_sync.Unlock();
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void HTimer::RemoveAllTimer()
|
||||
{
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
// m_sync.Lock();
|
||||
#endif
|
||||
|
||||
struct HTimerObject * pTimerObject;
|
||||
|
||||
for(LIST_TIMER_OBJECT::iterator iter = m_listTimer.begin();
|
||||
iter != m_listTimer.end(); iter++)
|
||||
{
|
||||
pTimerObject = *iter;
|
||||
delete pTimerObject;
|
||||
}
|
||||
m_listTimer.clear();
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
// m_sync.Unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
void HTimer::Main()
|
||||
{
|
||||
m_bThreadStarted = true;
|
||||
|
||||
struct tm * tmTmp;
|
||||
struct timeb tTimeb;
|
||||
|
||||
struct HTimerObject * pTimerObject;
|
||||
|
||||
while (m_bTerminate == false)
|
||||
{
|
||||
Sleep(HTIMER_INTERVAL_TIME);
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
// m_sync.Lock();
|
||||
#endif
|
||||
|
||||
for(LIST_TIMER_OBJECT::iterator iter = m_listTimer.begin();
|
||||
iter != m_listTimer.end(); iter++)
|
||||
{
|
||||
pTimerObject = *iter;
|
||||
|
||||
if (pTimerObject->bDelete)
|
||||
{
|
||||
delete pTimerObject;
|
||||
iter = m_listTimer.erase(iter);
|
||||
if (iter == m_listTimer.end())
|
||||
break;
|
||||
}
|
||||
else if (pTimerObject->nElapse <= TimeDiff(pTimerObject->dwLastCheckTime, m_nTickCount))
|
||||
{
|
||||
if (pTimerObject->fnOnTimerCallBack)
|
||||
pTimerObject->fnOnTimerCallBack(pTimerObject->nTimerID, pTimerObject->pOnTimerCallBackParam);
|
||||
|
||||
pTimerObject->dwLastCheckTime = m_nTickCount;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
// m_sync.Unlock();
|
||||
#endif
|
||||
|
||||
ftime(&tTimeb);
|
||||
tmTmp = localtime(&tTimeb.time);
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_syncSystemTime.Lock();
|
||||
#endif
|
||||
|
||||
m_systemTime.wYear = tmTmp->tm_year + 1900;
|
||||
m_systemTime.wMonth = tmTmp->tm_mon + 1;
|
||||
m_systemTime.wDay = tmTmp->tm_mday;
|
||||
m_systemTime.wHour = tmTmp->tm_hour;
|
||||
m_systemTime.wMinute = tmTmp->tm_min;
|
||||
m_systemTime.wSecond = tmTmp->tm_sec;
|
||||
m_systemTime.wMilliseconds = tTimeb.millitm;
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
m_syncSystemTime.Unlock();
|
||||
#endif
|
||||
|
||||
m_nTickCount = ::GetTickCount();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
#ifndef TIMER__H_
|
||||
#define TIMER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
|
||||
|
||||
#define HTIMER_INTERVAL_TIME 100 // 100 ms
|
||||
#define HTIMER_TERMINATE_WAIT_TIME 300 // 300 ms
|
||||
|
||||
#define HTIMER() (&g_timerGlobal)
|
||||
|
||||
#define ON_TIMER(CLASS_NAME, FN_CALLBACK) \
|
||||
inline bool SetTimer(unsigned int nTimerID, unsigned int nElapse) { return HTIMER()->SetTimer(nTimerID, nElapse, TimerCallBack##FN_CALLBACK, this); } \
|
||||
inline bool KillTimer(unsigned int nTimerID) { return HTIMER()->KillTimer(nTimerID); } \
|
||||
static void TimerCallBack##FN_CALLBACK(unsigned int nTimerID, void * pParam) { static_cast<CLASS_NAME *>(pParam)->FN_CALLBACK(nTimerID); } \
|
||||
void FN_CALLBACK(unsigned int nTimerID);
|
||||
|
||||
|
||||
|
||||
struct HTimerObject
|
||||
{
|
||||
unsigned int nTimerID;
|
||||
unsigned int nElapse;
|
||||
unsigned int dwLastCheckTime;
|
||||
bool bDelete;
|
||||
void (*fnOnTimerCallBack)(unsigned int, void *);
|
||||
void * pOnTimerCallBackParam;
|
||||
};
|
||||
|
||||
typedef std::list<struct HTimerObject *> LIST_TIMER_OBJECT;
|
||||
|
||||
|
||||
class HTimer : public HThread
|
||||
{
|
||||
public:
|
||||
HTimer();
|
||||
~HTimer();
|
||||
|
||||
inline void Terminate() { m_bTerminate = true; Sleep(HTIMER_TERMINATE_WAIT_TIME); }
|
||||
|
||||
void GetSystemTime(PSYSTEMTIME pSystemTime);
|
||||
inline unsigned int GetTickCount() { return m_nTickCount; }
|
||||
|
||||
LIST_TIMER_OBJECT * GetTimerList() { return &m_listTimer; }
|
||||
|
||||
bool SetTimer(unsigned int nTimerID, unsigned int nElapse, void (*fnCallBack)(unsigned int, void *), void * pParam);
|
||||
bool KillTimer(unsigned int nTimerID);
|
||||
void RemoveAllTimer();
|
||||
|
||||
protected:
|
||||
void Main();
|
||||
|
||||
private:
|
||||
volatile bool m_bThreadStarted;
|
||||
volatile bool m_bTerminate;
|
||||
|
||||
#ifndef SINGLE_THREADED_MODEL
|
||||
HSyncObject m_sync;
|
||||
HSyncObject m_syncSystemTime;
|
||||
#endif
|
||||
volatile SYSTEMTIME m_systemTime;
|
||||
volatile DWORD m_nTickCount;
|
||||
|
||||
LIST_TIMER_OBJECT m_listTimer;
|
||||
};
|
||||
|
||||
extern HTimer g_timerGlobal;
|
||||
|
||||
#endif // TIMER__H_
|
||||
@@ -0,0 +1,182 @@
|
||||
|
||||
#include "huslib.h"
|
||||
#include "huslibex.h"
|
||||
|
||||
|
||||
|
||||
HVspHandler::HVspHandler()
|
||||
{
|
||||
m_pRecvBuffer = new HStreamBuffer(HH_VSP_MAX_COMMAND_PACKET_SIZE);
|
||||
m_nBodyOffset = -1;
|
||||
m_nBodySize = -1;
|
||||
m_nRemainBodySize = -1;
|
||||
|
||||
m_pSendBuffer = new HStreamBuffer(HH_VSP_MAX_COMMAND_PACKET_SIZE);
|
||||
}
|
||||
|
||||
HVspHandler::~HVspHandler()
|
||||
{
|
||||
delete m_pRecvBuffer;
|
||||
delete m_pSendBuffer;
|
||||
}
|
||||
|
||||
int HVspHandler::SendCommand(const HString & strCommand)
|
||||
{
|
||||
if (m_pSendBuffer->RemainSize() < strCommand.GetLength() + 5)
|
||||
return -1;
|
||||
|
||||
size_t nLength = sprintf(m_pSendBuffer->Tail(), "VSP %d %s", strCommand.GetLength(), strCommand.psz());
|
||||
m_pSendBuffer->MoveTail(nLength);
|
||||
|
||||
return SendBufferCommand();
|
||||
}
|
||||
|
||||
int HVspHandler::SendBinary(const char * pData, size_t nSize)
|
||||
{
|
||||
if (m_pSendBuffer->StoredSize() == 0)
|
||||
{
|
||||
int nSentSize = SendToTransport(pData, nSize);
|
||||
if (nSentSize < 0)
|
||||
return -1;
|
||||
|
||||
if (nSentSize != nSize)
|
||||
m_pSendBuffer->Store(pData + nSentSize, nSize - nSentSize);
|
||||
|
||||
return nSentSize;
|
||||
}
|
||||
|
||||
m_pSendBuffer->Store(pData, nSize);
|
||||
return SendBufferCommand();
|
||||
}
|
||||
|
||||
int HVspHandler::SendBufferCommand()
|
||||
{
|
||||
//if (m_pSendBuffer->StoredSize() == 0)
|
||||
// return SOCKET_ERROR;
|
||||
|
||||
int nSentSize = SendToTransport(m_pSendBuffer->Head(), m_pSendBuffer->StoredSize());
|
||||
if (nSentSize <= 0)
|
||||
return nSentSize;
|
||||
|
||||
m_pSendBuffer->Pop(nSentSize);
|
||||
|
||||
return nSentSize;
|
||||
}
|
||||
|
||||
void HVspHandler::OnReceivedStatusFromTransport(int nStatus)
|
||||
{
|
||||
if (nStatus == HTransport::T_BEGIN_TRANSPORT)
|
||||
{
|
||||
OnInitialize(true);
|
||||
}
|
||||
else if (nStatus == HTransport::T_FAILED_BEGIN)
|
||||
{
|
||||
OnInitialize(false);
|
||||
}
|
||||
else if (nStatus == HTransport::T_END_TRANSPORT)
|
||||
{
|
||||
OnTerminate();
|
||||
}
|
||||
}
|
||||
|
||||
int HVspHandler::OnReceivedFromTransport(const char * pData, int nSize)
|
||||
{
|
||||
if (m_pRecvBuffer->Store(pData, nSize) == false)
|
||||
{
|
||||
HLOGF(HLOG_ERROR, "[ERROR], VspHdler, Failed to insert data, buffer = %d, stored = %d, recv size = %d\n", m_pRecvBuffer->Size(), m_pRecvBuffer->StoredSize(), nSize);
|
||||
return -1; // close connection
|
||||
}
|
||||
|
||||
if (m_nRemainBodySize > 0)
|
||||
{
|
||||
int nResult = ProcPacketBodyReceive();
|
||||
if (nResult < 0)
|
||||
return -1; // close connection
|
||||
else if (nResult == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (m_pRecvBuffer->StoredSize() < 6)
|
||||
return 0;
|
||||
|
||||
// verify protocol name
|
||||
if (m_pRecvBuffer->MemCmp("VSP ", 4) != 0)
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], VspHdler, Invalid VSP protocol, buffer = %d, stored = %d, recv size = %d\n", m_pRecvBuffer->Size(), m_pRecvBuffer->StoredSize(), nSize);
|
||||
HLOGD(HLOG_WARNING, m_pRecvBuffer->Head(), m_pRecvBuffer->StoredSize(), false);
|
||||
return -1; // close connection
|
||||
}
|
||||
|
||||
// extract body size
|
||||
m_nBodyOffset = m_pRecvBuffer->Find(' ', 4);
|
||||
if (m_nBodyOffset < 0)
|
||||
return 0; // receive remain packet
|
||||
|
||||
if (m_nBodyOffset > 13) // 9 + 4
|
||||
{
|
||||
HLOGF(HLOG_WARNING, "[WARN], VspHdler, Invalid VSP body size, buffer = %d, stored = %d, recv size = %d\n", m_pRecvBuffer->Size(), m_pRecvBuffer->StoredSize(), nSize);
|
||||
HLOGD(HLOG_WARNING, m_pRecvBuffer->Head(), m_pRecvBuffer->StoredSize(), false);
|
||||
return -1; // close connection
|
||||
}
|
||||
|
||||
HString strBodySize(m_pRecvBuffer->Head() + 4, m_nBodyOffset - 4);
|
||||
|
||||
m_nBodySize = strBodySize;
|
||||
m_nBodyOffset++;
|
||||
|
||||
//if (m_nBodySize + nPos > HH_VSP_MAX_COMMAND_PACKET_SIZE)
|
||||
//{
|
||||
//... extra size packet
|
||||
//}
|
||||
|
||||
int nResult = ProcPacketBodyReceive();
|
||||
if (nResult < 0)
|
||||
return -1;
|
||||
else if (nResult == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1; // close connection
|
||||
}
|
||||
|
||||
int HVspHandler::ProcPacketBodyReceive()
|
||||
{
|
||||
int nResult = 0;
|
||||
|
||||
m_nRemainBodySize = m_nBodySize - (m_pRecvBuffer->StoredSize() - m_nBodyOffset);
|
||||
if (m_nRemainBodySize <= 0)
|
||||
{
|
||||
nResult = OnReceivedCommand(m_pRecvBuffer->Head() + m_nBodyOffset, m_nBodySize);
|
||||
if (nResult < 0)
|
||||
return -1;
|
||||
|
||||
if (m_nRemainBodySize < 0)
|
||||
nResult = 1;
|
||||
else
|
||||
nResult = 0;
|
||||
|
||||
m_pRecvBuffer->PopAndRewind(m_nBodyOffset + m_nBodySize);
|
||||
|
||||
m_nBodyOffset = -1;
|
||||
m_nBodySize = -1;
|
||||
m_nRemainBodySize = -1;
|
||||
}
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
||||
int HVspHandler::OnSendRetryToTransport()
|
||||
{
|
||||
return SendBufferCommand();
|
||||
}
|
||||
|
||||
bool HVspHandler::OnPrepareReceive()
|
||||
{
|
||||
if (m_pRecvBuffer->RemainSize() < g_nSocketReceiveBlockSize)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
#ifndef VSP_HANDLER__H_
|
||||
#define VSP_HANDLER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#define EXTRACT_NEXT_PARAM(VALIABLE, NEXT, SIZE, OFFSET) \
|
||||
if ((OFFSET = VALIABLE.Tokenize(NEXT, SIZE, ' ')) <= 1) { \
|
||||
if (SIZE > 0) { VALIABLE.Assign(NEXT, SIZE); OFFSET = SIZE; } \
|
||||
else { HLOGF(HLOG_ERROR, "[ERROR], Invalid param, %s\n", NEXT); \
|
||||
return -1; } } \
|
||||
NEXT += OFFSET; SIZE -= OFFSET;
|
||||
|
||||
|
||||
|
||||
class HVspHandler : public HProtocolHandler
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
//HH_VSP_MAX_COMMAND_PACKET_SIZE = 8192
|
||||
HH_VSP_MAX_COMMAND_PACKET_SIZE = 65536
|
||||
};
|
||||
|
||||
HVspHandler();
|
||||
~HVspHandler();
|
||||
|
||||
int SendCommand(const HString & strCommand);
|
||||
int SendBinary(const char * pData, size_t nSize);
|
||||
|
||||
protected:
|
||||
int SendBufferCommand();
|
||||
|
||||
void OnReceivedStatusFromTransport(int nStatus);
|
||||
int OnReceivedFromTransport(const char * pData, int nSize);
|
||||
int ProcPacketBodyReceive();
|
||||
|
||||
int OnSendRetryToTransport();
|
||||
bool OnPrepareReceive();
|
||||
|
||||
virtual void OnInitialize(bool bIsSuccess) = 0;
|
||||
virtual void OnTerminate() = 0;
|
||||
virtual int OnReceivedCommand(const char * pPacket, int nSize) = 0;
|
||||
|
||||
protected:
|
||||
HStreamBuffer * m_pRecvBuffer;
|
||||
int m_nBodyOffset;
|
||||
long m_nBodySize;
|
||||
long m_nRemainBodySize;
|
||||
|
||||
HStreamBuffer * m_pSendBuffer;
|
||||
};
|
||||
|
||||
|
||||
#endif // REDUNDANCY__H_
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
|
||||
#include "huslib.h"
|
||||
#include "huslibex.h"
|
||||
|
||||
|
||||
#define ARRAYCOUNT(array) ((unsigned)(sizeof(array)/sizeof(array[0])))
|
||||
|
||||
static struct {
|
||||
const char * pszExtention;
|
||||
const char * pszContentType;
|
||||
} ContentTypeTab[] = {
|
||||
{ ".htm", "text/html" },
|
||||
{ ".html", "text/html" },
|
||||
{ ".asp", "text/html" },
|
||||
{ ".php", "text/html" },
|
||||
{ ".jsp", "text/html" },
|
||||
{ ".css", "text/css" },
|
||||
{ ".js", "application/x-javascript" },
|
||||
{ ".txt", "text/plain" },
|
||||
{ ".ini", "text/plain" },
|
||||
{ ".gif", "image/gif" },
|
||||
{ ".jpg", "image/jpeg" },
|
||||
{ ".png", "image/png" },
|
||||
{ ".bmp", "image/bmp" },
|
||||
{ ".swf", "application/x-shockwave-flash" },
|
||||
{ ".zip", "application/zip" }
|
||||
};
|
||||
|
||||
|
||||
HWebServer::HWebServer()
|
||||
{
|
||||
m_pszResponse = (char *)malloc(g_nMaxHsHeaderSize);
|
||||
m_pszResponseOffset = m_pszResponse;
|
||||
m_nResponseRemainSize = 0;
|
||||
|
||||
m_pFileBuffer = (char *)malloc(WS_READ_BYTES + 1);
|
||||
m_pFileBufferOffset = m_pFileBuffer;
|
||||
m_nRemainBufferSize = 0;
|
||||
}
|
||||
|
||||
HWebServer::~HWebServer()
|
||||
{
|
||||
free(m_pszResponse);
|
||||
free(m_pFileBuffer);
|
||||
}
|
||||
|
||||
const char * HWebServer::GetContentType(const char * pszRequestUri)
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAYCOUNT(ContentTypeTab); i++)
|
||||
{
|
||||
if (stristr(pszRequestUri, ContentTypeTab[i].pszExtention))
|
||||
return ContentTypeTab[i].pszContentType;
|
||||
}
|
||||
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
void HWebServer::AddStaticDir(const char * pszDir)
|
||||
{
|
||||
m_listStaticDir.push_back(pszDir);
|
||||
}
|
||||
|
||||
int HWebServer::SendResponse()
|
||||
{
|
||||
int nSentSize = SendToTransport(m_pszResponseOffset, m_nResponseRemainSize);
|
||||
if (nSentSize <= 0)
|
||||
return nSentSize; // -1 : shutdown, 0 : buffering because of wouldblock
|
||||
else if (nSentSize < m_nResponseRemainSize)
|
||||
{
|
||||
m_pszResponseOffset += nSentSize;
|
||||
m_nResponseRemainSize -= nSentSize;
|
||||
return 0; // buffering because of wouldblock
|
||||
}
|
||||
|
||||
return -1; // shutdown
|
||||
}
|
||||
|
||||
int HWebServer::SendFileHeader()
|
||||
{
|
||||
int nSentSize = SendToTransport(m_pFileBufferOffset, m_nRemainBufferSize);
|
||||
if (nSentSize <= 0)
|
||||
return nSentSize; // -1 : shutdown, 0 : buffering because of wouldblock
|
||||
else if (nSentSize < m_nRemainBufferSize)
|
||||
{
|
||||
m_pFileBufferOffset += nSentSize;
|
||||
m_nRemainBufferSize -= nSentSize;
|
||||
return 0; // buffering because of wouldblock
|
||||
}
|
||||
|
||||
return 1; // continue
|
||||
}
|
||||
|
||||
int HWebServer::SendOpenedFile()
|
||||
{
|
||||
int nSendSize;
|
||||
int nSentSize;
|
||||
int nReadSize = WS_READ_BYTES;
|
||||
|
||||
while (m_nFileSize > 0)
|
||||
{
|
||||
while (m_nRemainBufferSize)
|
||||
{
|
||||
if (m_nRemainBufferSize > (long)g_nSocketSendingBlockSize)
|
||||
nSendSize = g_nSocketSendingBlockSize;
|
||||
else
|
||||
nSendSize = m_nRemainBufferSize;
|
||||
|
||||
nSentSize = SendToTransport(m_pFileBufferOffset, nSendSize);
|
||||
if (nSentSize <= 0)
|
||||
return nSentSize; // -1 : shutdown, 0 : buffering because of wouldblock
|
||||
|
||||
m_pFileBufferOffset += nSentSize;
|
||||
m_nRemainBufferSize -= nSentSize;
|
||||
|
||||
if (nSentSize < nSendSize)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nReadSize < WS_READ_BYTES)
|
||||
break;
|
||||
|
||||
if ((nReadSize = m_file.Read(m_pFileBuffer, WS_READ_BYTES)) <= 0)
|
||||
break;
|
||||
|
||||
m_pFileBufferOffset = m_pFileBuffer;
|
||||
m_nRemainBufferSize = nReadSize;
|
||||
}
|
||||
|
||||
m_file.Close();
|
||||
m_pFileBufferOffset = m_pFileBuffer;
|
||||
m_nRemainBufferSize = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int HWebServer::OnSendRetryToTransport()
|
||||
{
|
||||
if (m_nResponseRemainSize > 0)
|
||||
return SendResponse();
|
||||
|
||||
return SendOpenedFile();
|
||||
}
|
||||
|
||||
int HWebServer::OnPacketProcessing(const char * pBodyData, int nBodySize)
|
||||
{
|
||||
int nResult = OnPrepareRequest(pBodyData, nBodySize);
|
||||
if (nResult <= 0)
|
||||
return nResult;
|
||||
|
||||
nResult = OnReceivedRequest(pBodyData, nBodySize);
|
||||
if (nResult <= 0)
|
||||
return nResult;
|
||||
|
||||
HDynamicArray<char> darrNewPath(strlen(m_pHttpParser->GetRequestUri()) + 1);
|
||||
RealignPathDepth(m_pHttpParser->GetRequestUri(), darrNewPath.m_p);
|
||||
|
||||
int nCopySize = 0;
|
||||
const char * pOffset = strchr(darrNewPath.m_p, '?');
|
||||
if (pOffset)
|
||||
nCopySize = pOffset - darrNewPath.m_p;
|
||||
else
|
||||
nCopySize = strlen(darrNewPath.m_p);
|
||||
|
||||
size_t nPathLength = m_strHomeDir.GetLength() + nCopySize;
|
||||
if (nPathLength > (size_t)g_nMaxPathNameLength)
|
||||
{
|
||||
m_nResponseRemainSize = MakeResponse(m_pszResponse, "400 Bad Request", "<html><body>400 Bad Request</body></html>");
|
||||
return SendResponse();
|
||||
}
|
||||
|
||||
HString strCopyPath = darrNewPath.m_p;
|
||||
HString strLastPath = strCopyPath.SubStr(0, nCopySize);
|
||||
if (strLastPath == "/")
|
||||
strLastPath = "/index.htm";
|
||||
|
||||
HString strPathName = m_strHomeDir;
|
||||
strPathName += strLastPath;
|
||||
|
||||
if (m_file.Open(strPathName, HFile::FMODE_RDONLY))
|
||||
{
|
||||
m_nFileSize = HFile::GetSize(strPathName);
|
||||
m_nRemainBufferSize = Make200Header(m_pFileBufferOffset, GetContentType(strPathName), m_nFileSize);
|
||||
|
||||
int nResult = SendFileHeader();
|
||||
if (nResult <= 0)
|
||||
return nResult;
|
||||
|
||||
m_nRemainBufferSize = 0;
|
||||
return SendOpenedFile();
|
||||
}
|
||||
|
||||
// 404 Not found
|
||||
m_nResponseRemainSize = MakeResponse(m_pszResponse, "404 Not found", "<html><body>404 Not found</body></html>");
|
||||
return SendResponse();
|
||||
}
|
||||
|
||||
bool HWebServer::IsStaticRequest()
|
||||
{
|
||||
for (HStrList::iterator iter = m_listStaticDir.begin(); iter != m_listStaticDir.end(); iter++)
|
||||
{
|
||||
if (iter->StrNICmp(m_pHttpParser->GetRequestUri(), iter->GetLength()) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
#ifndef WEB_SERVER__H_
|
||||
#define WEB_SERVER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class HWebServer : public HHttpHandler
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
WS_READ_BYTES = (256 * 1024 - 1) // 256Kbyte
|
||||
};
|
||||
|
||||
HWebServer();
|
||||
~HWebServer();
|
||||
|
||||
inline void SetHomeDir(const char * pszDir) { m_strHomeDir = pszDir; }
|
||||
const char * GetContentType(const char * pszRequestUri);
|
||||
void AddStaticDir(const char * pszDir);
|
||||
|
||||
protected:
|
||||
int SendResponse();
|
||||
int SendFileHeader();
|
||||
int SendOpenedFile();
|
||||
|
||||
int OnSendRetryToTransport();
|
||||
int OnPacketProcessing(const char * pBodyData, int nBodySize);
|
||||
|
||||
virtual int OnPrepareRequest(const char * pBodyData, int nBodySize) { return 1; }
|
||||
virtual int OnReceivedRequest(const char * pBodyData, int nBodySize) { return -1; }
|
||||
|
||||
bool IsStaticRequest();
|
||||
|
||||
protected:
|
||||
HString m_strHomeDir;
|
||||
HStrList m_listStaticDir;
|
||||
|
||||
char * m_pszResponse;
|
||||
char * m_pszResponseOffset;
|
||||
int m_nResponseRemainSize;
|
||||
|
||||
|
||||
HFile m_file;
|
||||
off_t m_nFileSize;
|
||||
char * m_pFileBuffer;
|
||||
char * m_pFileBufferOffset;
|
||||
long m_nRemainBufferSize;
|
||||
};
|
||||
|
||||
#endif // WEB_SERVER__H_
|
||||
@@ -0,0 +1,65 @@
|
||||
#ifndef ZLIB_EX__H_
|
||||
#define ZLIB_EX__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "zlib.lib")
|
||||
#endif
|
||||
|
||||
extern inline bool Gunzip(const char * pSrc, unsigned long nSrcSize, HDynamicArray<char> * pdaDst, unsigned long * pnDstSize)
|
||||
{
|
||||
if (nSrcSize == 0)
|
||||
return false;
|
||||
|
||||
unsigned full_length = nSrcSize;
|
||||
unsigned half_length = nSrcSize / 2;
|
||||
|
||||
unsigned uncompLength = full_length;
|
||||
pdaDst->m_p = (char *)malloc(uncompLength + 8); // 8 : safety space for post process
|
||||
|
||||
z_stream strm;
|
||||
strm.next_in = (Bytef *)pSrc;
|
||||
strm.avail_in = nSrcSize;
|
||||
strm.total_out = 0;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
|
||||
bool done = false ;
|
||||
|
||||
if (inflateInit2(&strm, (16+MAX_WBITS)) != Z_OK)
|
||||
return false;
|
||||
|
||||
while (!done)
|
||||
{
|
||||
if (strm.total_out >= uncompLength)
|
||||
{
|
||||
char * uncomp2 = (char *)malloc(uncompLength + half_length + 8); // 8 : safety space for post process
|
||||
memcpy(uncomp2, pdaDst->m_p, uncompLength);
|
||||
uncompLength += half_length;
|
||||
pdaDst->Restruct(uncomp2);
|
||||
}
|
||||
|
||||
strm.next_out = (Bytef *) (pdaDst->m_p + strm.total_out);
|
||||
strm.avail_out = uncompLength - strm.total_out;
|
||||
|
||||
int err = inflate(&strm, Z_SYNC_FLUSH);
|
||||
if (err == Z_STREAM_END)
|
||||
done = true;
|
||||
else if (err != Z_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
if (inflateEnd(&strm) != Z_OK)
|
||||
return false;
|
||||
|
||||
*pnDstSize = strm.total_out;
|
||||
return true ;
|
||||
}
|
||||
|
||||
|
||||
#endif // ZLIB_EX__H_
|
||||
@@ -0,0 +1,551 @@
|
||||
|
||||
#include "stringex.h"
|
||||
#include "hsparser.h"
|
||||
#include <time.h>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
|
||||
static char * SliceHeader(char * pszBuffer)
|
||||
{
|
||||
for (unsigned int i = 0; pszBuffer[i]; i++)
|
||||
{
|
||||
if (pszBuffer[i] == '\r' && pszBuffer[i + 1] == '\n')
|
||||
{
|
||||
pszBuffer[i] = '\0';
|
||||
return (pszBuffer + i + 2);
|
||||
}
|
||||
else if (pszBuffer[i] == '\n')
|
||||
{
|
||||
pszBuffer[i] = '\0';
|
||||
return (pszBuffer + i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char * SliceToken(char * pszLine, char cDelimiter)
|
||||
{
|
||||
for (unsigned int i = 0; pszLine[i]; i++)
|
||||
{
|
||||
if (pszLine[i] == cDelimiter)
|
||||
{
|
||||
pszLine[i] = '\0';
|
||||
return (pszLine + i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char * HHsParser::SearchBodyPtr(char * pData, unsigned int nSize)
|
||||
{
|
||||
for (unsigned int i = 0; i < nSize; i++)
|
||||
{
|
||||
if (pData[i] == '\r' && pData[i + 1] == '\n' && pData[i + 2] == '\r' && pData[i + 3] == '\n')
|
||||
return (pData + i + 4);
|
||||
else if (pData[i] == '\n' && pData[i + 1] == '\n')
|
||||
return (pData + i + 2);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HHsHeaderElement::HHsHeaderElement(const char * pszName, bool bNameMewMemory, const char * pszValue, bool bValueNewMemory)
|
||||
{
|
||||
m_bNameNewMemory = bNameMewMemory;
|
||||
m_bValueNewMemory = bValueNewMemory;
|
||||
m_nNameLength = strlen(pszName);
|
||||
m_nValueLength = strlen(pszValue);
|
||||
|
||||
if (bNameMewMemory)
|
||||
{
|
||||
m_pszName = (char *)malloc(m_nNameLength + 1);
|
||||
strcpy(m_pszName, pszName);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pszName = (char *)pszName;
|
||||
}
|
||||
|
||||
if (bValueNewMemory)
|
||||
{
|
||||
m_pszValue = (char *)malloc(m_nValueLength + 1);
|
||||
strcpy(m_pszValue, pszValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pszValue = (char *)pszValue;
|
||||
}
|
||||
|
||||
m_pNext = NULL;
|
||||
}
|
||||
|
||||
HHsHeaderElement::~HHsHeaderElement()
|
||||
{
|
||||
if (m_bNameNewMemory)
|
||||
free(m_pszName);
|
||||
|
||||
if (m_bValueNewMemory)
|
||||
free(m_pszValue);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HHsParser::HHsParser(const char * pszProtocolName)
|
||||
{
|
||||
strcpy(m_szProtocolName, pszProtocolName);
|
||||
m_nProtocolNameLength = strlen(pszProtocolName);
|
||||
|
||||
m_pszMethod = NULL;
|
||||
|
||||
m_pszRequestUri = NULL;
|
||||
m_bRequestUriNewMemory = false;
|
||||
|
||||
m_pszVersion = NULL;
|
||||
m_nStatusCode = -1;
|
||||
|
||||
m_pszReasonPhrase = NULL;
|
||||
m_bReasonPhraseNewMemory = false;
|
||||
|
||||
m_pElementHead = NULL;
|
||||
m_pElementRear = NULL;
|
||||
|
||||
m_nHeaderSize = 0;
|
||||
m_nContentLength = 0;
|
||||
|
||||
m_pBody = NULL;
|
||||
m_bBodyNewMemory = false;
|
||||
m_nBodySize = 0;
|
||||
}
|
||||
|
||||
HHsParser::~HHsParser()
|
||||
{
|
||||
if (m_bRequestUriNewMemory)
|
||||
free(m_pszRequestUri);
|
||||
|
||||
if (m_bReasonPhraseNewMemory)
|
||||
free(m_pszReasonPhrase);
|
||||
|
||||
if (m_pElementHead)
|
||||
{
|
||||
HHsHeaderElement * pTemp;
|
||||
HHsHeaderElement * pNext = m_pElementHead;
|
||||
|
||||
do
|
||||
{
|
||||
pTemp = pNext;
|
||||
pNext = pNext->m_pNext;
|
||||
|
||||
delete pTemp;
|
||||
} while (pNext != NULL);
|
||||
}
|
||||
|
||||
if (m_bBodyNewMemory)
|
||||
free(m_pBody);
|
||||
}
|
||||
|
||||
void HHsParser::SetRequestUri(const char * pszRequestUri)
|
||||
{
|
||||
size_t oldLen = strlen(m_pszRequestUri);
|
||||
size_t newLen = strlen(pszRequestUri);
|
||||
|
||||
if (newLen > oldLen)
|
||||
{
|
||||
if (m_bRequestUriNewMemory)
|
||||
free(m_pszRequestUri);
|
||||
else
|
||||
m_bRequestUriNewMemory = true;
|
||||
|
||||
m_pszRequestUri = (char *)malloc(newLen + 1);
|
||||
}
|
||||
|
||||
strcpy(m_pszRequestUri, pszRequestUri);
|
||||
|
||||
m_nHeaderSize += (newLen - oldLen);
|
||||
}
|
||||
|
||||
void HHsParser::SetVersion(const char * pszVersion)
|
||||
{
|
||||
strcpy(m_pszVersion, pszVersion); //...
|
||||
}
|
||||
|
||||
void HHsParser::SetReasonPhrase(const char * pszReasonPhrase)
|
||||
{
|
||||
size_t oldLen = strlen(m_pszReasonPhrase);
|
||||
size_t newLen = strlen(pszReasonPhrase);
|
||||
|
||||
if (newLen > oldLen)
|
||||
{
|
||||
if (m_bReasonPhraseNewMemory)
|
||||
free(m_pszReasonPhrase);
|
||||
else
|
||||
m_bReasonPhraseNewMemory = true;
|
||||
|
||||
m_pszReasonPhrase = (char *)malloc(newLen + 1);
|
||||
}
|
||||
|
||||
strcpy(m_pszReasonPhrase, pszReasonPhrase);
|
||||
|
||||
m_nHeaderSize += (newLen - oldLen);
|
||||
}
|
||||
|
||||
void HHsParser::SetBody(char * pData, unsigned int nSize)
|
||||
{
|
||||
if (nSize > m_nBodySize)
|
||||
{
|
||||
if (m_bBodyNewMemory)
|
||||
free(m_pBody);
|
||||
else
|
||||
m_bBodyNewMemory = true;
|
||||
|
||||
m_pBody = (char *)malloc(nSize + 1);
|
||||
}
|
||||
|
||||
memcpy(m_pBody, pData, nSize);
|
||||
m_pBody[nSize] = '\0';
|
||||
m_nBodySize = nSize;
|
||||
}
|
||||
|
||||
HHsHeaderElement * HHsParser::GetHeaderElement(const char * pszHeaderName, int nIndex)
|
||||
{
|
||||
int i = 0;
|
||||
for (HHsHeaderElement * pNext = m_pElementHead; pNext != NULL; pNext = pNext->m_pNext)
|
||||
{
|
||||
if (stricmp(pszHeaderName, pNext->m_pszName) == 0)
|
||||
{
|
||||
if (nIndex != i++)
|
||||
continue;
|
||||
|
||||
return pNext;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * HHsParser::GetHeaderValue(const char * pszHeaderName, int nIndex)
|
||||
{
|
||||
int i = 0;
|
||||
for (HHsHeaderElement * pNext = m_pElementHead; pNext != NULL; pNext = pNext->m_pNext)
|
||||
{
|
||||
if (stricmp(pszHeaderName, pNext->m_pszName) == 0)
|
||||
{
|
||||
if (nIndex != i++)
|
||||
continue;
|
||||
|
||||
return pNext->m_pszValue;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool HHsParser::AddHeader(const char * pszHeaderName, const char * pszHeaderValue)
|
||||
{
|
||||
HHsHeaderElement * pElement = new HHsHeaderElement(pszHeaderName, true, pszHeaderValue, true);
|
||||
|
||||
if (m_pElementHead == NULL)
|
||||
m_pElementHead = pElement;
|
||||
|
||||
if (m_pElementRear)
|
||||
m_pElementRear->m_pNext = pElement;
|
||||
|
||||
m_pElementRear = pElement;
|
||||
|
||||
m_nHeaderSize += (pElement->m_nNameLength + pElement->m_nValueLength + 4); // 4 = ": " + "\r\n"
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HHsParser::SetHeader(const char * pszHeaderName, const char * pszHeaderValue, int nIndex)
|
||||
{
|
||||
HHsHeaderElement * pFindElement = GetHeaderElement(pszHeaderName, nIndex);
|
||||
if (pFindElement)
|
||||
{
|
||||
size_t newLen = strlen(pszHeaderValue);
|
||||
|
||||
if (newLen > pFindElement->m_nValueLength)
|
||||
{
|
||||
if (pFindElement->m_bValueNewMemory)
|
||||
free(pFindElement->m_pszValue);
|
||||
else
|
||||
pFindElement->m_bValueNewMemory = true;
|
||||
|
||||
pFindElement->m_pszValue = (char *)malloc(newLen + 1);
|
||||
}
|
||||
|
||||
strcpy(pFindElement->m_pszValue, pszHeaderValue);
|
||||
|
||||
m_nHeaderSize += (newLen - pFindElement->m_nValueLength);
|
||||
pFindElement->m_nValueLength = newLen;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return AddHeader(pszHeaderName, pszHeaderValue);
|
||||
}
|
||||
|
||||
bool HHsParser::OrganizeHeader(char * pszHeaderName, char * pszHeaderValue)
|
||||
{
|
||||
HHsHeaderElement * pElement = new HHsHeaderElement(pszHeaderName, false, pszHeaderValue, false);
|
||||
|
||||
if (m_pElementHead == NULL)
|
||||
m_pElementHead = pElement;
|
||||
|
||||
if (m_pElementRear)
|
||||
m_pElementRear->m_pNext = pElement;
|
||||
|
||||
m_pElementRear = pElement;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HHsParser::RemoveHeader(const char * pszHeaderName, const char * pszHeaderValue, int nIndex)
|
||||
{
|
||||
int i = 0;
|
||||
HHsHeaderElement * pPrevNext = m_pElementHead;
|
||||
for (HHsHeaderElement * pNext = m_pElementHead; pNext != NULL; pNext = pNext->m_pNext)
|
||||
{
|
||||
if (stricmp(pszHeaderName, pNext->m_pszName) == 0)
|
||||
{
|
||||
if (nIndex != i++)
|
||||
continue;
|
||||
|
||||
if (pszHeaderValue && stricmp(pszHeaderValue, pNext->m_pszValue) != 0)
|
||||
{
|
||||
pPrevNext = pNext;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pNext == m_pElementHead)
|
||||
{
|
||||
m_pElementHead = pNext->m_pNext;
|
||||
|
||||
if (pNext == m_pElementRear)
|
||||
m_pElementRear = m_pElementHead;
|
||||
}
|
||||
else if (pNext == m_pElementRear)
|
||||
{
|
||||
m_pElementRear = pPrevNext;
|
||||
m_pElementRear->m_pNext = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPrevNext->m_pNext = pNext->m_pNext;
|
||||
}
|
||||
|
||||
m_nHeaderSize -= (pNext->m_nNameLength + pNext->m_nValueLength + 4); // 4 = ": " + "\rn"
|
||||
delete pNext;
|
||||
break;
|
||||
}
|
||||
|
||||
pPrevNext = pNext;
|
||||
}
|
||||
}
|
||||
|
||||
size_t HHsParser::RefleshHeaderSize()
|
||||
{
|
||||
size_t nHeaderSize = 0;
|
||||
|
||||
if (m_pszMethod && m_pszRequestUri && m_pszVersion)
|
||||
{
|
||||
nHeaderSize += strlen(m_pszMethod) + 1;
|
||||
nHeaderSize += strlen(m_pszRequestUri) + 1;
|
||||
nHeaderSize += m_nProtocolNameLength + strlen(m_pszVersion) + 3; // GET / HTTP/1.1\r\n
|
||||
}
|
||||
else if (m_pszVersion && m_nStatusCode > 0 && m_pszReasonPhrase)
|
||||
{
|
||||
nHeaderSize += m_nProtocolNameLength + strlen(m_pszVersion) + 2; // HTTP/1.1 200 OK
|
||||
|
||||
int nNum = m_nStatusCode;
|
||||
int nFigure = 0;
|
||||
for (; nNum != 0; nFigure++)
|
||||
nNum = nNum / 10;
|
||||
|
||||
nHeaderSize += nFigure + 1;
|
||||
nHeaderSize += strlen(m_pszReasonPhrase) + 2;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (m_pElementHead == 0)
|
||||
return 0;
|
||||
|
||||
for (HHsHeaderElement * pNext = m_pElementHead; pNext != NULL; pNext = pNext->m_pNext)
|
||||
{
|
||||
nHeaderSize += pNext->m_nNameLength + 2;
|
||||
nHeaderSize += pNext->m_nValueLength + 2;
|
||||
}
|
||||
|
||||
nHeaderSize += 2; // + \r\n
|
||||
m_nHeaderSize = nHeaderSize;
|
||||
|
||||
return nHeaderSize;
|
||||
}
|
||||
|
||||
int HHsParser::Parse(char * pData, unsigned int nSize, char * pBodyPtr)
|
||||
{
|
||||
if (pData == NULL || pData[0] == '\0')
|
||||
return HP_PARAMETER_ERROR;
|
||||
|
||||
if (pBodyPtr == NULL)
|
||||
{
|
||||
pBodyPtr = SearchBodyPtr(pData, nSize);
|
||||
if (pBodyPtr == NULL)
|
||||
return HP_HEADER_REMAIN_PACKET;
|
||||
}
|
||||
m_nHeaderSize = pBodyPtr - pData;
|
||||
|
||||
char * pNextToken;
|
||||
char * pNextLine = SliceHeader(pData);
|
||||
if (strncmp(pData, m_szProtocolName, m_nProtocolNameLength) == 0)
|
||||
{
|
||||
// Response Start-Line (ex: HTTP/1.1 200 OK)
|
||||
m_pszVersion = pData + m_nProtocolNameLength + 1;
|
||||
if ((pNextToken = SliceToken(m_pszVersion, ' ')) == NULL)
|
||||
return HP_NOT_HTTP_PACKET;
|
||||
|
||||
char * pszStatusCode = pNextToken;
|
||||
if ((pNextToken = SliceToken(pszStatusCode, ' ')) == NULL)
|
||||
return HP_NOT_HTTP_PACKET;
|
||||
m_nStatusCode = atoi(pszStatusCode);
|
||||
|
||||
m_pszReasonPhrase = pNextToken;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Request Start-Line
|
||||
m_pszMethod = pData;
|
||||
if ((pNextToken = SliceToken(m_pszMethod, ' ')) == NULL)
|
||||
return HP_NOT_HTTP_PACKET;
|
||||
|
||||
//... check method name
|
||||
|
||||
m_pszRequestUri = pNextToken;
|
||||
if ((pNextToken = SliceToken(m_pszRequestUri, ' ')) == NULL)
|
||||
return HP_NOT_HTTP_PACKET;
|
||||
|
||||
m_pszVersion = pNextToken + m_nProtocolNameLength + 1;
|
||||
}
|
||||
|
||||
bool bHasContentLength = false;
|
||||
bool bIsChunkded = false;
|
||||
bool bIsConnectionClose = false;
|
||||
bool bHasContentType = false;
|
||||
|
||||
char * pOneLine;
|
||||
char * pszHeaderName;
|
||||
do
|
||||
{
|
||||
pOneLine = pNextLine;
|
||||
if ((pNextLine = SliceHeader(pOneLine)) == NULL)
|
||||
break;
|
||||
|
||||
pszHeaderName = pOneLine;
|
||||
if ((pNextToken = SliceToken(pszHeaderName, ':')) == NULL)
|
||||
return HP_NOT_HTTP_PACKET;
|
||||
|
||||
for (int i = 0; ; i++) // front trim
|
||||
{
|
||||
if (*pNextToken == ' ') pNextToken++;
|
||||
else break;
|
||||
}
|
||||
|
||||
if (stricmp(pszHeaderName, "Content-Length") == 0)
|
||||
{
|
||||
m_nContentLength = atol(pNextToken);
|
||||
bHasContentLength = true;
|
||||
}
|
||||
else if (stricmp(pszHeaderName, "Transfer-Encoding") == 0)
|
||||
{
|
||||
if (stricmp(pNextToken, "chunked") == 0)
|
||||
bIsChunkded = true;
|
||||
}
|
||||
else if (stricmp(pszHeaderName, "Connection") == 0)
|
||||
{
|
||||
if (stricmp(pNextToken, "close") == 0)
|
||||
bIsConnectionClose = true;
|
||||
}
|
||||
else if (stricmp(pszHeaderName, "Content-Type") == 0)
|
||||
bHasContentType = true;
|
||||
|
||||
OrganizeHeader(pszHeaderName, pNextToken);
|
||||
} while (*pNextLine != '\r' && *pNextLine != '\n'); // header end
|
||||
|
||||
if (m_nHeaderSize == nSize && m_nContentLength == 0)
|
||||
{
|
||||
if (bIsChunkded || (bHasContentType && m_pszMethod == NULL && bHasContentLength == false && bIsConnectionClose))
|
||||
return HP_BODYSIZE_UNKNOWN_PACKET;
|
||||
else
|
||||
return HP_COMPLETE_PACKET;
|
||||
}
|
||||
|
||||
unsigned int nRemainSize = nSize - m_nHeaderSize;
|
||||
if (m_nContentLength == 0 || m_nContentLength >= nRemainSize)
|
||||
m_nBodySize = nRemainSize;
|
||||
else
|
||||
m_nBodySize = m_nContentLength;
|
||||
|
||||
if (m_nBodySize > 0)
|
||||
{
|
||||
m_pBody = pBodyPtr;
|
||||
m_pBody[m_nBodySize] = '\0';
|
||||
}
|
||||
|
||||
if (m_nContentLength == 0)
|
||||
return HP_BODYSIZE_UNKNOWN_PACKET;
|
||||
else if (m_nContentLength == m_nBodySize)
|
||||
return HP_COMPLETE_PACKET;
|
||||
else if (m_nContentLength > m_nBodySize)
|
||||
return HP_BODY_REMAIN_PACKET;
|
||||
|
||||
return HP_BODYSIZE_UNKNOWN_PACKET;
|
||||
}
|
||||
|
||||
bool HHsParser::ToString(char * pBuffer, bool bOnlyHeader)
|
||||
{
|
||||
if (m_pszVersion == NULL || m_pElementHead == NULL)
|
||||
{
|
||||
pBuffer[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_pszMethod)
|
||||
sprintf(pBuffer, "%s %s %s/%s\r\n", m_pszMethod, m_pszRequestUri, m_szProtocolName, m_pszVersion);
|
||||
else
|
||||
sprintf(pBuffer, "%s/%s %d %s\r\n", m_szProtocolName, m_pszVersion, m_nStatusCode, m_pszReasonPhrase);
|
||||
|
||||
size_t nTempSize = strlen(pBuffer);
|
||||
|
||||
char * pBufferOffset = pBuffer + nTempSize;
|
||||
for (HHsHeaderElement * pNext = m_pElementHead; pNext != NULL; pNext = pNext->m_pNext)
|
||||
{
|
||||
strcpy(pBufferOffset, pNext->m_pszName);
|
||||
pBufferOffset += pNext->m_nNameLength;
|
||||
|
||||
strcpy(pBufferOffset, ": ");
|
||||
pBufferOffset += 2;
|
||||
|
||||
strcpy(pBufferOffset, pNext->m_pszValue);
|
||||
pBufferOffset += pNext->m_nValueLength;
|
||||
|
||||
strcpy(pBufferOffset, "\r\n");
|
||||
pBufferOffset += 2;
|
||||
}
|
||||
|
||||
strcpy(pBufferOffset, "\r\n");
|
||||
|
||||
if (bOnlyHeader == false && m_pBody)
|
||||
{
|
||||
pBufferOffset += 2;
|
||||
memcpy(pBufferOffset, m_pBody, m_nBodySize);
|
||||
pBufferOffset[m_nBodySize] = '\0';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#ifndef HS_PARSER__H_
|
||||
#define HS_PARSER__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#pragma once
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class HHsHeaderElement
|
||||
{
|
||||
public:
|
||||
HHsHeaderElement(const char * pszName, bool bNameMewMemory, const char * pszValue, bool bValueNewMemory);
|
||||
~HHsHeaderElement();
|
||||
|
||||
public:
|
||||
char * m_pszName;
|
||||
size_t m_nNameLength;
|
||||
bool m_bNameNewMemory;
|
||||
|
||||
char * m_pszValue;
|
||||
size_t m_nValueLength;
|
||||
bool m_bValueNewMemory;
|
||||
|
||||
HHsHeaderElement * m_pNext;
|
||||
};
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
class HHsParser
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
HP_PARAMETER_ERROR = 0,
|
||||
HP_NOT_HTTP_PACKET = 1,
|
||||
HP_HEADER_REMAIN_PACKET = 2,
|
||||
HP_BODY_REMAIN_PACKET = 3,
|
||||
HP_BODYSIZE_UNKNOWN_PACKET = 4,
|
||||
HP_COMPLETE_PACKET = 5
|
||||
};
|
||||
|
||||
static char * SearchBodyPtr(char * pData, unsigned int nSize);
|
||||
|
||||
////////////
|
||||
|
||||
HHsParser(const char * pszProtocolName);
|
||||
virtual ~HHsParser();
|
||||
|
||||
char * GetProtocolName() { return m_szProtocolName; }
|
||||
char * GetMethod() { return m_pszMethod; }
|
||||
|
||||
void SetRequestUri(const char * pszRequestUri);
|
||||
char * GetRequestUri() { return m_pszRequestUri; }
|
||||
|
||||
void SetVersion(const char * pszVersion);
|
||||
char * GetVersion() { return m_pszVersion; }
|
||||
|
||||
void SetStatusCode(int nStatusCode) { m_nStatusCode = nStatusCode; }
|
||||
int GetStatusCode() { return m_nStatusCode; }
|
||||
|
||||
void SetReasonPhrase(const char * pszReasonPhrase);
|
||||
char * GetReasonPhrase() { return m_pszReasonPhrase; }
|
||||
|
||||
size_t GetHeaderSize() { return m_nHeaderSize; }
|
||||
unsigned long GetContentLength() { return m_nContentLength; }
|
||||
|
||||
void SetBody(char * pData, unsigned int nSize);
|
||||
char * GetBodyPtr() { return m_pBody; }
|
||||
size_t GetBodySize() { return m_nBodySize; }
|
||||
|
||||
HHsHeaderElement * GetHeaderElement(const char * pszHeaderName, int nIndex = 0);
|
||||
const char * GetHeaderValue(const char * pszHeaderName, int nIndex = 0);
|
||||
|
||||
bool AddHeader(const char * pszHeaderName, const char * pszHeaderValue);
|
||||
bool SetHeader(const char * pszHeaderName, const char * pszHeaderValue, int nIndex = 0);
|
||||
|
||||
void RemoveHeader(const char * pszHeaderName, const char * pszHeaderValue = NULL, int nIndex = 0);
|
||||
|
||||
size_t RefleshHeaderSize();
|
||||
|
||||
int Parse(char * pData, unsigned int nSize, char * pBodyPtr = NULL);
|
||||
bool ToString(char * pBuffer, bool bOnlyHeader);
|
||||
|
||||
protected:
|
||||
bool OrganizeHeader(char * pszHeaderName, char * pszHeaderValue);
|
||||
|
||||
private:
|
||||
char m_szProtocolName[8];
|
||||
size_t m_nProtocolNameLength;
|
||||
|
||||
char * m_pszMethod;
|
||||
|
||||
char * m_pszRequestUri;
|
||||
bool m_bRequestUriNewMemory;
|
||||
|
||||
char * m_pszVersion;
|
||||
|
||||
int m_nStatusCode;
|
||||
|
||||
char * m_pszReasonPhrase;
|
||||
bool m_bReasonPhraseNewMemory;
|
||||
|
||||
HHsHeaderElement * m_pElementHead;
|
||||
HHsHeaderElement * m_pElementRear;
|
||||
|
||||
size_t m_nHeaderSize;
|
||||
unsigned long m_nContentLength;
|
||||
|
||||
char * m_pBody;
|
||||
bool m_bBodyNewMemory;
|
||||
size_t m_nBodySize;
|
||||
};
|
||||
|
||||
#endif // HS_PARSER__H_
|
||||
@@ -0,0 +1,66 @@
|
||||
#ifndef HUSLIB__H_
|
||||
#define HUSLIB__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef STRINGEX__H_
|
||||
#include "stringex.h"
|
||||
#endif
|
||||
|
||||
#ifndef DEFINES__H_
|
||||
#include "Defines.h"
|
||||
#endif
|
||||
|
||||
#ifndef COMMON__H_
|
||||
#include "Common.h"
|
||||
#endif
|
||||
|
||||
#ifndef OBJECT__H_
|
||||
#include "Object.h"
|
||||
#endif
|
||||
|
||||
#ifndef STRING__H_
|
||||
#include "String.h"
|
||||
#endif
|
||||
|
||||
#ifndef FILE__H_
|
||||
#include "File.h"
|
||||
#endif
|
||||
|
||||
#ifndef SOCKET__H_
|
||||
#include "Socket.h"
|
||||
#endif
|
||||
|
||||
#ifndef THREAD__H_
|
||||
#include "Thread.h"
|
||||
#endif
|
||||
|
||||
#ifndef DATA_STRUCT__H_
|
||||
#include "DataStruct.h"
|
||||
#endif
|
||||
|
||||
////
|
||||
|
||||
#ifndef TIMER__H_
|
||||
#include "Timer.h"
|
||||
#endif
|
||||
|
||||
#ifndef LOGGER__H_
|
||||
#include "Logger.h"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG__H_
|
||||
#include "Config.h"
|
||||
#endif
|
||||
|
||||
#ifndef MULTIPLEX_SOCKET__H_
|
||||
#include "MultiplexSocket.h"
|
||||
#endif
|
||||
|
||||
#ifndef APP__H_
|
||||
#include "HusApp.h"
|
||||
#endif
|
||||
|
||||
#endif // HUSLIB__H_
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef HUSLIBEX__H_
|
||||
#define HUSLIBEX__H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NET_UTIL__H_
|
||||
#include "NetUtil.h"
|
||||
#endif
|
||||
|
||||
#ifndef GLOBAL__H_
|
||||
#include "Global.h"
|
||||
#endif
|
||||
|
||||
#ifndef STREAM_BUFFER__H_
|
||||
#include "StreamBuffer.h"
|
||||
#endif
|
||||
|
||||
#ifndef BLOCK_LIST_BUFFER__H_
|
||||
#include "BlockListBuffer.h"
|
||||
#endif
|
||||
|
||||
#ifndef MULTIPLEX_SSL_SOCKET__H_
|
||||
#include "MultiplexSslSocket.h"
|
||||
#endif
|
||||
|
||||
#ifndef PROTOCOL_HANDLER__H_
|
||||
#include "ProtocolHandler.h"
|
||||
#endif
|
||||
|
||||
#ifndef MULTIPLEX_TRANSPORT__H_
|
||||
#include "MultiplexTransport.h"
|
||||
#endif
|
||||
|
||||
#ifndef HS_PARSER__H_
|
||||
#include "hsparser.h"
|
||||
#endif
|
||||
|
||||
#ifndef HTTP_HANDLER__H_
|
||||
#include "HttpHandler.h"
|
||||
#endif
|
||||
|
||||
#ifndef TELNET_HANDLER__H_
|
||||
#include "TelnetHandler.h"
|
||||
#endif
|
||||
|
||||
#ifndef VSP_HANDLER__H_
|
||||
#include "VspHandler.h"
|
||||
#endif
|
||||
|
||||
#ifndef WEB_SERVER__H_
|
||||
#include "WebServer.h"
|
||||
#endif
|
||||
|
||||
#ifndef TELNET_SERVER__H
|
||||
#include "TelnetServer.h"
|
||||
#endif
|
||||
|
||||
|
||||
#endif // HUSLIBEX__H_
|
||||
@@ -0,0 +1,716 @@
|
||||
|
||||
#include "inifile.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <io.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#ifndef BOOL
|
||||
|
||||
typedef int BOOL;
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MULTI_THREAD_MODEL
|
||||
|
||||
pthread_mutex_t g_mutex_for_ini_file;
|
||||
|
||||
#define MDF_lock() pthread_mutex_lock(&g_mutex_for_ini_file);
|
||||
#define MDF_unlock() pthread_mutex_unlock(&g_mutex_for_ini_file);
|
||||
|
||||
#else
|
||||
|
||||
#define MDF_lock() ((void)0)
|
||||
#define MDF_unlock() ((void)0)
|
||||
|
||||
#endif // MULTI_THREAD_MODEL
|
||||
|
||||
#define MAX_INI_FILE_SIZE 1024 * 1024 * 8 // 8Mb
|
||||
#define MAX_INI_SECTION_NAME_BUFFER_SIZE 512
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MD_FA_WOPEN O_RDONLY | O_BINARY, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH
|
||||
#define MD_FA_WCREATE O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH
|
||||
#else
|
||||
//#define MD_FA_WOPEN O_RDONLY, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH
|
||||
//#define MD_FA_WCREATE O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH
|
||||
#define MD_FA_WOPEN O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||
#define MD_FA_WCREATE O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#define GetPrivateProfileString_P GetPrivateProfileString
|
||||
#define GetPrivateProfileInt_P GetPrivateProfileInt
|
||||
#define WritePrivateProfileString_P WritePrivateProfileString
|
||||
|
||||
|
||||
char * __g_ini_file__search_section_ptr(const char * S1, const char * S2, int nFileSize, int * pnPos)
|
||||
{
|
||||
int j;
|
||||
char chBeforeCharacter = '\0';
|
||||
|
||||
if (S1 == NULL || S1[0] == '\0' || S2 == NULL || S2[0] == '\0')
|
||||
return NULL;
|
||||
|
||||
for (*pnPos = 0; *pnPos < nFileSize; (*pnPos)++)
|
||||
{
|
||||
if (((*pnPos) == 0 && *S1 == '[') ||
|
||||
(*S1 == '[' && (chBeforeCharacter == '\r' || chBeforeCharacter == '\n')))
|
||||
{
|
||||
S1++;
|
||||
(*pnPos)++;
|
||||
|
||||
BOOL bIsSectionFound = TRUE;
|
||||
|
||||
for (j = 0; *pnPos < nFileSize; (*pnPos)++)
|
||||
{
|
||||
if (*S1 == ']' && S2[j] == '\0')
|
||||
break;
|
||||
|
||||
if (*S1 != S2[j])
|
||||
{
|
||||
bIsSectionFound = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*S1 == ']' || *S1 == '\r' || *S1 == '\n')
|
||||
{
|
||||
bIsSectionFound = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
S1++;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (*pnPos >= nFileSize)
|
||||
return NULL;
|
||||
|
||||
if (bIsSectionFound == TRUE)
|
||||
return (char *)S1;
|
||||
}
|
||||
|
||||
chBeforeCharacter = *S1;
|
||||
S1++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char * __g_ini_file__search_key_ptr(const char * S1, const char * S2, int nFileSize, int * pnPos)
|
||||
{
|
||||
int j;
|
||||
char chBeforeCharacter = '\0';
|
||||
|
||||
if (S1 == NULL || S1[0] == '\0' || S2 == NULL || S2[0] == '\0')
|
||||
return NULL;
|
||||
|
||||
for (; *pnPos < nFileSize; (*pnPos)++)
|
||||
{
|
||||
if (*S1 == S2[0] && (chBeforeCharacter == '\r' || chBeforeCharacter == '\n'))
|
||||
{
|
||||
S1++;
|
||||
(*pnPos)++;
|
||||
|
||||
BOOL bIsKeyFound = TRUE;
|
||||
|
||||
for (j = 1; *pnPos < nFileSize; (*pnPos)++)
|
||||
{
|
||||
if (*S1 == '=' && S2[j] == '\0')
|
||||
break;
|
||||
|
||||
if (*S1 != S2[j])
|
||||
{
|
||||
bIsKeyFound = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*S1 == '\r' || *S1 == '\n')
|
||||
{
|
||||
bIsKeyFound = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
S1++;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (*pnPos >= nFileSize)
|
||||
return NULL;
|
||||
|
||||
if (bIsKeyFound == TRUE)
|
||||
return (char *)S1;
|
||||
else
|
||||
{
|
||||
for (; *pnPos < nFileSize; (*pnPos)++)
|
||||
{
|
||||
if (*S1 == '\r' || *S1 == '\n')
|
||||
break;
|
||||
|
||||
S1++;
|
||||
}
|
||||
|
||||
if (*pnPos >= nFileSize)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (*S1 == '[' && (chBeforeCharacter == '\r' || chBeforeCharacter == '\n'))
|
||||
{
|
||||
for (S1--; *pnPos > 0; (*pnPos)--)
|
||||
{
|
||||
if (*S1 != '\r' && *S1 != '\n')
|
||||
break;
|
||||
|
||||
S1--;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chBeforeCharacter = *S1;
|
||||
S1++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t __g_ini_file__value_len_without_rear_space(const char * STR)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (STR == NULL || STR[0] == '\0')
|
||||
return 0;
|
||||
|
||||
for (i = 0; STR[i] != '\0'; i++)
|
||||
{
|
||||
if (STR[i] == '\r' || STR[i] == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
for (i--; i >= 0; i--)
|
||||
{
|
||||
if (STR[i] != ' ')
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int GetPrivateProfileString_P(
|
||||
const char * lpAppName, // section name
|
||||
const char * lpKeyName, // key name
|
||||
const char * lpDefault, // default string
|
||||
char * lpReturnedString, // destination buffer
|
||||
unsigned int nSize, // size of destination buffer
|
||||
const char * lpFileName // initialization file name
|
||||
)
|
||||
{
|
||||
int fhINIFile;
|
||||
long nFileSize;
|
||||
char * pszBuffer;
|
||||
char * pszBufferPtr;
|
||||
char * pszSectionName;
|
||||
char * pszKeyName;
|
||||
size_t nCopySize;
|
||||
int nPos;
|
||||
|
||||
if (lpReturnedString == NULL)
|
||||
return 0;
|
||||
|
||||
if (lpAppName == NULL || lpAppName[0] == '\0' ||
|
||||
lpKeyName == NULL || lpKeyName[0] == '\0' ||
|
||||
lpDefault == NULL ||
|
||||
lpFileName == NULL || lpFileName[0] == '\0' ||
|
||||
nSize <= 0)
|
||||
{
|
||||
goto GetPrivateProfileString_P_Fail;
|
||||
}
|
||||
|
||||
if (strlen(lpAppName) > MAX_INI_SECTION_NAME_BUFFER_SIZE - 3)
|
||||
{
|
||||
printf("inifile\t[ERROR] Too large section name. over %d byte.\n", MAX_INI_SECTION_NAME_BUFFER_SIZE - 3);
|
||||
goto GetPrivateProfileString_P_Fail;
|
||||
}
|
||||
|
||||
lpReturnedString[0] = '\0';
|
||||
|
||||
MDF_lock();
|
||||
|
||||
fhINIFile = open(lpFileName, MD_FA_WOPEN);
|
||||
|
||||
if (fhINIFile == -1)
|
||||
{
|
||||
MDF_unlock();
|
||||
//printf("inifile\t[ERROR] Failed to open file. errno = %d\n", errno);
|
||||
|
||||
nCopySize = __g_ini_file__value_len_without_rear_space(lpDefault);
|
||||
if (nSize <= nCopySize)
|
||||
nCopySize = nSize - 1;
|
||||
|
||||
strncpy(lpReturnedString, lpDefault, nCopySize);
|
||||
lpReturnedString[nCopySize] = '\0';
|
||||
|
||||
return strlen(lpReturnedString);
|
||||
}
|
||||
|
||||
nFileSize = lseek(fhINIFile, 0L, SEEK_END);
|
||||
if (nFileSize > MAX_INI_FILE_SIZE)
|
||||
{
|
||||
printf("inifile\t[ERROR] Too large file. over %d byte.\n", MAX_INI_FILE_SIZE);
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
goto GetPrivateProfileString_P_Fail;
|
||||
}
|
||||
|
||||
lseek(fhINIFile, 0L, SEEK_SET);
|
||||
|
||||
pszBuffer = (char *)malloc(nFileSize + 1);
|
||||
if (read(fhINIFile, pszBuffer, nFileSize) == -1)
|
||||
{
|
||||
printf("inifile\t[ERROR] Failed to read file. errno = %d\n", errno);
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
free(pszBuffer);
|
||||
goto GetPrivateProfileString_P_Fail;
|
||||
}
|
||||
pszBuffer[nFileSize] = '\0';
|
||||
close(fhINIFile);
|
||||
|
||||
nCopySize = __g_ini_file__value_len_without_rear_space(lpAppName);
|
||||
pszSectionName = (char *)malloc(nCopySize + 1);
|
||||
strncpy(pszSectionName, lpAppName, nCopySize);
|
||||
pszSectionName[nCopySize] = '\0';
|
||||
|
||||
nCopySize = __g_ini_file__value_len_without_rear_space(lpKeyName);
|
||||
pszKeyName = (char *)malloc(nCopySize + 1);
|
||||
strncpy(pszKeyName, lpKeyName, nCopySize);
|
||||
pszKeyName[nCopySize] = '\0';
|
||||
|
||||
pszBufferPtr = __g_ini_file__search_section_ptr(pszBuffer, pszSectionName, nFileSize, &nPos);
|
||||
|
||||
if (pszBufferPtr != NULL)
|
||||
pszBufferPtr = __g_ini_file__search_key_ptr(pszBufferPtr, pszKeyName, nFileSize, &nPos);
|
||||
|
||||
if (pszBufferPtr != NULL && nPos < nFileSize)
|
||||
{
|
||||
pszBufferPtr++;
|
||||
nCopySize = __g_ini_file__value_len_without_rear_space(pszBufferPtr);
|
||||
|
||||
if (nSize <= nCopySize)
|
||||
nCopySize = nSize - 1;
|
||||
|
||||
strncpy(lpReturnedString, pszBufferPtr, nCopySize);
|
||||
lpReturnedString[nCopySize] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
nCopySize = __g_ini_file__value_len_without_rear_space(lpDefault);
|
||||
|
||||
if (nSize <= nCopySize)
|
||||
nCopySize = nSize - 1;
|
||||
|
||||
strncpy(lpReturnedString, lpDefault, nCopySize);
|
||||
lpReturnedString[nCopySize] = '\0';
|
||||
}
|
||||
|
||||
MDF_unlock();
|
||||
|
||||
free(pszSectionName);
|
||||
free(pszKeyName);
|
||||
free(pszBuffer);
|
||||
return strlen(lpReturnedString);
|
||||
|
||||
GetPrivateProfileString_P_Fail:
|
||||
lpReturnedString[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetPrivateProfileInt_P(
|
||||
const char* lpAppName, // section name
|
||||
const char* lpKeyName, // key name
|
||||
int nDefault, // return value if key name not found
|
||||
const char* lpFileName // initialization file name
|
||||
)
|
||||
{
|
||||
char szBuf[128];
|
||||
|
||||
GetPrivateProfileString_P(lpAppName, lpKeyName, "",
|
||||
szBuf, 128, lpFileName);
|
||||
|
||||
if (strlen(szBuf) <= 0)
|
||||
return nDefault;
|
||||
|
||||
return atoi(szBuf);
|
||||
}
|
||||
|
||||
BOOL WritePrivateProfileString_P(
|
||||
const char* lpAppName, // section name
|
||||
const char* lpKeyName, // key name
|
||||
const char* lpString, // string to add
|
||||
const char* lpFileName // initialization file
|
||||
)
|
||||
{
|
||||
#define FREE_BUFFERS() free(pszSectionName); free(pszKeyName); free(pszWriteString); free(pszBuffer)
|
||||
|
||||
int fhINIFile;
|
||||
long nFileSize;
|
||||
char * pszBuffer;
|
||||
char * pszBufferPtr;
|
||||
char * pszSectionName;
|
||||
char * pszKeyName;
|
||||
char * pszWriteString;
|
||||
size_t nWriteSize;
|
||||
int nPos;
|
||||
|
||||
if (lpAppName == NULL || lpAppName[0] == '\0' ||
|
||||
lpKeyName == NULL || lpKeyName[0] == '\0' ||
|
||||
lpFileName == NULL || lpFileName[0] == '\0')
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (strlen(lpAppName) > MAX_INI_SECTION_NAME_BUFFER_SIZE - 3)
|
||||
{
|
||||
printf("inifile\t[ERROR] Too large section name. over %d byte.\n", MAX_INI_SECTION_NAME_BUFFER_SIZE - 3);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nWriteSize = __g_ini_file__value_len_without_rear_space(lpAppName);
|
||||
pszSectionName = (char *)malloc(nWriteSize + 1);
|
||||
strncpy(pszSectionName, lpAppName, nWriteSize);
|
||||
pszSectionName[nWriteSize] = '\0';
|
||||
|
||||
nWriteSize = __g_ini_file__value_len_without_rear_space(lpKeyName);
|
||||
pszKeyName = (char *)malloc(nWriteSize + 1);
|
||||
strncpy(pszKeyName, lpKeyName, nWriteSize);
|
||||
pszKeyName[nWriteSize] = '\0';
|
||||
|
||||
nWriteSize = __g_ini_file__value_len_without_rear_space(lpString);
|
||||
pszWriteString = (char *)malloc(nWriteSize + 1);
|
||||
strncpy(pszWriteString, lpString, nWriteSize);
|
||||
pszWriteString[nWriteSize] = '\0';
|
||||
|
||||
MDF_lock();
|
||||
|
||||
fhINIFile = open(lpFileName, MD_FA_WOPEN);
|
||||
if (fhINIFile == -1)
|
||||
{
|
||||
//printf("inifile\t[ERROR] Failed to open file. errno = %d\n", errno);
|
||||
goto WritePrivateProfileString_P_New;
|
||||
}
|
||||
|
||||
nFileSize = lseek(fhINIFile, 0L, SEEK_END);
|
||||
if (nFileSize > MAX_INI_FILE_SIZE)
|
||||
{
|
||||
printf("inifile\t[ERROR] Too large file. over %d byte.\n", MAX_INI_FILE_SIZE);
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
free(pszSectionName);
|
||||
free(pszKeyName);
|
||||
free(pszWriteString);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nFileSize == 0)
|
||||
{
|
||||
close(fhINIFile);
|
||||
goto WritePrivateProfileString_P_New;
|
||||
}
|
||||
|
||||
lseek(fhINIFile, 0L, SEEK_SET);
|
||||
|
||||
pszBuffer = (char *)malloc(nFileSize + strlen(lpAppName) +
|
||||
strlen(lpKeyName) + strlen(lpString) + 10); // 10 : \r \n [ ] \r \n = \r \n \0
|
||||
|
||||
if (read(fhINIFile, pszBuffer, nFileSize) == -1)
|
||||
{
|
||||
printf("inifile\t[ERROR] Failed to read file. errno = %d\n", errno);
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
FREE_BUFFERS();
|
||||
return FALSE;
|
||||
}
|
||||
pszBuffer[nFileSize] = '\0';
|
||||
close(fhINIFile);
|
||||
|
||||
pszBufferPtr = __g_ini_file__search_section_ptr(pszBuffer, pszSectionName, nFileSize, &nPos);
|
||||
if (pszBufferPtr == NULL)
|
||||
{
|
||||
pszBufferPtr = pszBuffer + nFileSize;
|
||||
|
||||
#ifdef _WIN32
|
||||
sprintf(pszBufferPtr, "\r\n[%s]\r\n%s=%s\r\n", pszSectionName, pszKeyName, pszWriteString);
|
||||
#else
|
||||
sprintf(pszBufferPtr, "\n[%s]\n%s=%s\n", pszSectionName, pszKeyName, pszWriteString);
|
||||
#endif
|
||||
fhINIFile = open(lpFileName, MD_FA_WCREATE);
|
||||
if (fhINIFile == -1)
|
||||
{
|
||||
printf("inifile\t[ERROR] Failed to open file. errno = %d\n", errno);
|
||||
MDF_unlock();
|
||||
FREE_BUFFERS();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (write(fhINIFile, pszBuffer, strlen(pszBuffer)) == -1)
|
||||
{
|
||||
printf("inifile\t[ERROR] Failed to write file. errno = %d\n", errno);
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
FREE_BUFFERS();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
FREE_BUFFERS();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
pszBufferPtr = __g_ini_file__search_key_ptr(pszBufferPtr, pszKeyName, nFileSize, &nPos);
|
||||
if (pszBufferPtr == NULL)
|
||||
{
|
||||
char * pszTempBuffer;
|
||||
|
||||
fhINIFile = open(lpFileName, MD_FA_WCREATE);
|
||||
if (fhINIFile == -1)
|
||||
{
|
||||
printf("inifile\t[ERROR] Failed to open file. errno = %d\n", errno);
|
||||
MDF_unlock();
|
||||
FREE_BUFFERS();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pszBufferPtr = pszBuffer + nPos;
|
||||
|
||||
pszTempBuffer = (char *)malloc(strlen(pszKeyName) +
|
||||
strlen(pszWriteString) + 6); // 6 : \r \n = \r \n \0
|
||||
|
||||
#ifdef _WIN32
|
||||
if (*(pszBufferPtr - 1) != '\r' && *(pszBufferPtr - 1) != '\n')
|
||||
sprintf(pszTempBuffer, "\r\n%s=%s", pszKeyName, pszWriteString);
|
||||
else
|
||||
sprintf(pszTempBuffer, "%s=%s", pszKeyName, pszWriteString);
|
||||
#else
|
||||
if (*(pszBufferPtr - 1) != '\r' && *(pszBufferPtr - 1) != '\n')
|
||||
sprintf(pszTempBuffer, "\n%s=%s", pszKeyName, pszWriteString);
|
||||
else
|
||||
sprintf(pszTempBuffer, "%s=%s", pszKeyName, pszWriteString);
|
||||
#endif
|
||||
if (write(fhINIFile, pszBuffer, nPos) == -1 ||
|
||||
write(fhINIFile, pszTempBuffer, strlen(pszTempBuffer)) == -1 ||
|
||||
write(fhINIFile, pszBufferPtr, nFileSize - nPos) == -1)
|
||||
{
|
||||
printf("inifile\t[ERROR] Failed to write file. errno = %d\n", errno);
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
free(pszTempBuffer);
|
||||
FREE_BUFFERS();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
free(pszTempBuffer);
|
||||
FREE_BUFFERS();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
pszBufferPtr++;
|
||||
nPos++;
|
||||
|
||||
fhINIFile = open(lpFileName, MD_FA_WCREATE);
|
||||
if (fhINIFile == -1)
|
||||
{
|
||||
printf("inifile\t[ERROR] Failed to open file. errno = %d\n", errno);
|
||||
MDF_unlock();
|
||||
FREE_BUFFERS();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (write(fhINIFile, pszBuffer, nPos) != -1 &&
|
||||
write(fhINIFile, pszWriteString, strlen(pszWriteString)) != -1)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (*pszBufferPtr == '\0' || *pszBufferPtr == '\r' || *pszBufferPtr == '\n')
|
||||
break;
|
||||
|
||||
pszBufferPtr++;
|
||||
nPos++;
|
||||
}
|
||||
|
||||
if (*pszBufferPtr == '\0' || write(fhINIFile, pszBufferPtr, nFileSize - nPos) != -1)
|
||||
{
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
FREE_BUFFERS();
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
printf("inifile\t[ERROR] Failed to write file. errno = %d\n", errno);
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
FREE_BUFFERS();
|
||||
return FALSE;
|
||||
|
||||
WritePrivateProfileString_P_New:
|
||||
fhINIFile = open(lpFileName, MD_FA_WCREATE);
|
||||
if (fhINIFile == -1)
|
||||
{
|
||||
printf("inifile\t[ERROR] Failed to open file. errno = %d\n", errno);
|
||||
MDF_unlock();
|
||||
free(pszSectionName);
|
||||
free(pszKeyName);
|
||||
free(pszWriteString);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pszBuffer = (char *)malloc(strlen(pszSectionName) +
|
||||
strlen(pszKeyName) + strlen(pszWriteString) + 8); // 8 : [ ] \r \n = \r \n \0
|
||||
|
||||
#ifdef _WIN32
|
||||
sprintf(pszBuffer, "[%s]\r\n%s=%s\r\n", pszSectionName, pszKeyName, pszWriteString);
|
||||
#else
|
||||
sprintf(pszBuffer, "[%s]\n%s=%s\n", pszSectionName, pszKeyName, pszWriteString);
|
||||
#endif
|
||||
|
||||
if (write(fhINIFile, pszBuffer, strlen(pszBuffer)) == -1)
|
||||
{
|
||||
printf("inifile\t[ERROR] Failed to write file. errno = %d\n", errno);
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
FREE_BUFFERS();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
close(fhINIFile);
|
||||
MDF_unlock();
|
||||
FREE_BUFFERS();
|
||||
return TRUE;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
|
||||
|
||||
HIniFile::HIniFile()
|
||||
{
|
||||
m_szIniFileName[0] = '\0';
|
||||
m_pszBuffer = NULL;
|
||||
}
|
||||
|
||||
HIniFile::~HIniFile()
|
||||
{
|
||||
if (m_pszBuffer)
|
||||
free(m_pszBuffer);
|
||||
}
|
||||
|
||||
bool HIniFile::SetIniFile(const char * pszFileName)
|
||||
{
|
||||
if (pszFileName && pszFileName[0] != '\0')
|
||||
{
|
||||
strncpy(m_szIniFileName, pszFileName, IF_MAX_PATH);
|
||||
m_pszBuffer = (char *)malloc(IF_DEFAULT_BUFFER_SIZE);
|
||||
m_dwBufferLength = IF_DEFAULT_BUFFER_SIZE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char * HIniFile::ReadString(const char * pszSetionName, const char * pszKeyName,
|
||||
const char * pszDefault, unsigned long nMaxSize)
|
||||
{
|
||||
if (m_szIniFileName[0] == '\0')
|
||||
return "";
|
||||
|
||||
if (nMaxSize > IF_DEFAULT_BUFFER_SIZE)
|
||||
{
|
||||
free(m_pszBuffer);
|
||||
m_pszBuffer = (char *)malloc(nMaxSize);
|
||||
m_dwBufferLength = nMaxSize;
|
||||
}
|
||||
|
||||
GetPrivateProfileString(pszSetionName, pszKeyName, pszDefault, m_pszBuffer, nMaxSize, m_szIniFileName);
|
||||
|
||||
return m_pszBuffer;
|
||||
}
|
||||
|
||||
bool HIniFile::WriteString(const char * pszSetionName, const char * pszKeyName, const char * pszString)
|
||||
{
|
||||
if (m_szIniFileName[0] == '\0')
|
||||
return false;
|
||||
|
||||
return WritePrivateProfileString(pszSetionName, pszKeyName, pszString, m_szIniFileName) != FALSE;
|
||||
}
|
||||
|
||||
int HIniFile::ReadNumber(const char * pszSetionName, const char * pszKeyName, int nDefault)
|
||||
{
|
||||
if (m_szIniFileName[0] == '\0')
|
||||
return 0;
|
||||
|
||||
return GetPrivateProfileInt(pszSetionName, pszKeyName, nDefault, m_szIniFileName);
|
||||
}
|
||||
|
||||
bool HIniFile::WriteNumber(const char * pszSetionName, const char * pszKeyName, int nNumber)
|
||||
{
|
||||
if (m_szIniFileName[0] == '\0')
|
||||
return false;
|
||||
|
||||
snprintf(m_pszBuffer, m_dwBufferLength, "%d", nNumber);
|
||||
|
||||
return WritePrivateProfileString(pszSetionName, pszKeyName, m_pszBuffer, m_szIniFileName) != FALSE;
|
||||
}
|
||||
|
||||
bool HIniFile::ReadBoolean(const char * pszSetionName, const char * pszKeyName, bool bDefault)
|
||||
{
|
||||
if (m_szIniFileName[0] == '\0')
|
||||
return false;
|
||||
|
||||
GetPrivateProfileString(pszSetionName, pszKeyName, "FALSE", m_pszBuffer, m_dwBufferLength, m_szIniFileName);
|
||||
|
||||
if (strcasecmp(m_pszBuffer, "TRUE") == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HIniFile::WriteBoolean(const char * pszSetionName, const char * pszKeyName, bool bValue)
|
||||
{
|
||||
if (m_szIniFileName[0] == '\0')
|
||||
return false;
|
||||
|
||||
return WritePrivateProfileString(pszSetionName, pszKeyName, bValue ? "TRUE" : "FALSE", m_szIniFileName) != FALSE;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
#ifndef INI_FILE__H_
|
||||
#define INI_FILE__H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include <windows.h>
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
#else
|
||||
|
||||
#ifdef MULTI_THREAD_MODEL
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class HIniFile
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
IF_MAX_PATH = 512,
|
||||
IF_DEFAULT_BUFFER_SIZE = 1024,
|
||||
};
|
||||
|
||||
HIniFile();
|
||||
~HIniFile();
|
||||
|
||||
inline const char * GetIniFile() { return m_szIniFileName; }
|
||||
bool SetIniFile(const char * pszFileName);
|
||||
|
||||
const char * ReadString(const char * pszSetionName, const char * pszKeyName,
|
||||
const char * pszDefault, unsigned long nMaxSize = IF_DEFAULT_BUFFER_SIZE);
|
||||
bool WriteString(const char * pszSetionName, const char * pszKeyName, const char * pszString);
|
||||
|
||||
int ReadNumber(const char * pszSetionName, const char * pszKeyName, int nDefault);
|
||||
bool WriteNumber(const char * pszSetionName, const char * pszKeyName, int nNumber);
|
||||
|
||||
bool ReadBoolean(const char * pszSetionName, const char * pszKeyName, bool bDefault);
|
||||
bool WriteBoolean(const char * pszSetionName, const char * pszKeyName, bool bValue);
|
||||
|
||||
private:
|
||||
char m_szIniFileName[IF_MAX_PATH];
|
||||
char * m_pszBuffer;
|
||||
unsigned long m_dwBufferLength;
|
||||
};
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
// initialize file functions
|
||||
int GetPrivateProfileString_P(
|
||||
const char* lpAppName, // section name
|
||||
const char* lpKeyName, // key name
|
||||
const char* lpDefault, // default string
|
||||
char* lpReturnedString, // destination buffer
|
||||
unsigned int nSize, // size of destination buffer
|
||||
const char* lpFileName // initialization file name
|
||||
);
|
||||
|
||||
int GetPrivateProfileInt_P(
|
||||
const char* lpAppName, // section name
|
||||
const char* lpKeyName, // key name
|
||||
int nDefault, // return value if key name not found
|
||||
const char* lpFileName // initialization file name
|
||||
);
|
||||
|
||||
bool WritePrivateProfileString_P(
|
||||
const char* lpAppName, // section name
|
||||
const char* lpKeyName, // key name
|
||||
const char* lpString, // string to add
|
||||
const char* lpFileName // initialization file
|
||||
);
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
#endif // INI_FILE__H_
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,811 @@
|
||||
|
||||
#include "stringex.h"
|
||||
|
||||
#include "Common.h" // for debug
|
||||
#include "Logger.h" // for debug
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#else
|
||||
|
||||
//#ifndef __CYGWIN__
|
||||
int stricmp(const char * first, const char * last)
|
||||
{
|
||||
int f, l;
|
||||
|
||||
do
|
||||
{
|
||||
f = tolower(*first);
|
||||
l = tolower(*last);
|
||||
first++;
|
||||
last++;
|
||||
} while (f && l && f == l);
|
||||
|
||||
//return(f - l);
|
||||
return f == l ? 0 : f > l ? 1 : -1;
|
||||
}
|
||||
|
||||
int strnicmp(const char * first, const char * last, unsigned int count)
|
||||
{
|
||||
int f, l;
|
||||
|
||||
if (count)
|
||||
{
|
||||
do
|
||||
{
|
||||
f = tolower(*first);
|
||||
l = tolower(*last);
|
||||
first++;
|
||||
last++;
|
||||
} while (--count && f && l && f == l);
|
||||
|
||||
//return(f - l);
|
||||
return f == l ? 0 : f > l ? 1 : -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char * strlwr(char * str)
|
||||
{
|
||||
char * p = str;
|
||||
|
||||
do
|
||||
{
|
||||
*p = tolower(*p);
|
||||
p++;
|
||||
} while (*p);
|
||||
|
||||
return(str);
|
||||
}
|
||||
|
||||
char * strupr(char * str)
|
||||
{
|
||||
char * p = str;
|
||||
|
||||
do
|
||||
{
|
||||
*p = toupper(*p);
|
||||
p++;
|
||||
} while (*p);
|
||||
|
||||
return(str);
|
||||
}
|
||||
//#endif // __CYGWIN__
|
||||
|
||||
#endif
|
||||
|
||||
char * gets_hus(char * s, int n)
|
||||
{
|
||||
char * ch = s;
|
||||
int k;
|
||||
|
||||
while ((k = getchar ()) != '\n')
|
||||
{
|
||||
if (k == EOF)
|
||||
{
|
||||
if (ch == s || !feof(stdin))
|
||||
return NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
*ch++ = k;
|
||||
if (--n <= 1)
|
||||
break;
|
||||
}
|
||||
|
||||
*ch = '\0';
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
char * stristr(char * pszStr, char * pszSearch)
|
||||
{
|
||||
if (pszStr == NULL)
|
||||
{
|
||||
//HLOG(15, "[TRACE], stristr string is NULL\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *cp = pszStr;
|
||||
char *s1, *s2;
|
||||
int f, l;
|
||||
|
||||
if (!*pszSearch)
|
||||
return pszStr;
|
||||
|
||||
while (*cp)
|
||||
{
|
||||
s1 = cp;
|
||||
s2 = (char *)pszSearch;
|
||||
|
||||
f = tolower(*s1);
|
||||
l = tolower(*s2);
|
||||
|
||||
while (f && l && !(f-l))
|
||||
{
|
||||
s1++, s2++;
|
||||
f = tolower(*s1);
|
||||
l = tolower(*s2);
|
||||
}
|
||||
|
||||
if (!*s2)
|
||||
return cp;
|
||||
|
||||
cp++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char * StrIKeyword(char * string, char * strSearch)
|
||||
{
|
||||
char *cp = string;
|
||||
char *s1, *s2;
|
||||
int f, l;
|
||||
|
||||
if (!*strSearch)
|
||||
return string;
|
||||
|
||||
while (*cp)
|
||||
{
|
||||
s1 = cp;
|
||||
s2 = (char *)strSearch;
|
||||
|
||||
f = tolower(*s1);
|
||||
l = tolower(*s2);
|
||||
|
||||
while (f && l && !(f-l))
|
||||
{
|
||||
s1++, s2++;
|
||||
f = tolower(*s1);
|
||||
l = tolower(*s2);
|
||||
}
|
||||
|
||||
if (*s1 < 0)
|
||||
{
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
//if (!*s2) // stristr
|
||||
if (!*s2 && !isalnum(*s1) && *s1 != '.') // for com, com.cn
|
||||
return cp;
|
||||
|
||||
cp++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * StrNStr(const char * string, const char * strSearch, int nCount)
|
||||
{
|
||||
char *cp = (char *)string;
|
||||
char *s1, *s2;
|
||||
int f, l, nRemain = nCount, nr2 = nCount;
|
||||
|
||||
if (nCount == 0)
|
||||
return NULL;
|
||||
|
||||
if (!*strSearch)
|
||||
return((char *)string);
|
||||
|
||||
while (*cp)
|
||||
{
|
||||
s1 = cp;
|
||||
s2 = (char *)strSearch;
|
||||
|
||||
f = *s1;
|
||||
l = *s2;
|
||||
|
||||
if (nCount > 0)
|
||||
nr2 = nRemain;
|
||||
|
||||
while (f && l && !(f-l))
|
||||
{
|
||||
s1++, s2++;
|
||||
f = *s1;
|
||||
l = *s2;
|
||||
|
||||
if (nCount > 0 && --nr2 < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!*s2)
|
||||
return cp;
|
||||
|
||||
cp++;
|
||||
if (nCount > 0 && --nRemain <= 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * StrNIStr(const char * string, const char * strSearch, int nCount)
|
||||
{
|
||||
char *cp = (char *)string;
|
||||
char *s1, *s2;
|
||||
int f, l, nRemain = nCount, nr2 = nCount;
|
||||
|
||||
if (nCount == 0)
|
||||
return NULL;
|
||||
|
||||
if (!*strSearch)
|
||||
return((char *)string);
|
||||
|
||||
while (*cp)
|
||||
{
|
||||
s1 = cp;
|
||||
s2 = (char *)strSearch;
|
||||
|
||||
f = tolower(*s1);
|
||||
l = tolower(*s2);
|
||||
|
||||
if (nCount > 0)
|
||||
nr2 = nRemain;
|
||||
|
||||
while (f && l && !(f-l))
|
||||
{
|
||||
s1++, s2++;
|
||||
f = tolower(*s1);
|
||||
l = tolower(*s2);
|
||||
|
||||
if (nCount > 0 && --nr2 < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!*s2)
|
||||
return cp;
|
||||
|
||||
cp++;
|
||||
if (nCount > 0 && --nRemain <= 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * StrRChr(const char * string, const char * strStart, char ch)
|
||||
{
|
||||
const char * s = strStart;
|
||||
|
||||
if (strStart == NULL || string > s)
|
||||
return NULL;
|
||||
|
||||
while (s != string)
|
||||
{
|
||||
if (*s == ch)
|
||||
return s;
|
||||
|
||||
s--;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
const char * StrNIKeyword(const char * string, const char * strSearch, int nCount)
|
||||
{
|
||||
char *cp = (char *)string;
|
||||
char *s1, *s2;
|
||||
int f, l, nRemain = nCount, nr2 = nCount;
|
||||
|
||||
if (nCount == 0)
|
||||
return NULL;
|
||||
|
||||
if (!*strSearch)
|
||||
return((char *)string);
|
||||
|
||||
while (*cp)
|
||||
{
|
||||
s1 = cp;
|
||||
s2 = (char *)strSearch;
|
||||
|
||||
f = tolower(*s1);
|
||||
l = tolower(*s2);
|
||||
|
||||
if (nCount > 0)
|
||||
nr2 = nRemain;
|
||||
|
||||
while (f && l && !(f-l))
|
||||
{
|
||||
s1++, s2++;
|
||||
f = tolower(*s1);
|
||||
l = tolower(*s2);
|
||||
|
||||
if (nCount > 0 && --nr2 < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//if (!*s2) // StrNIStr
|
||||
if (!*s2 && !isalnum(*s1) && *s1 != '.')
|
||||
return cp;
|
||||
|
||||
cp++;
|
||||
if (nCount > 0 && --nRemain <= 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char * StrStrUntilChr(const char * string, const char * strSearch, char chUntil)
|
||||
{
|
||||
char *cp = (char *)string;
|
||||
char *s1, *s2;
|
||||
|
||||
if (!*strSearch)
|
||||
return ((char *)string);
|
||||
|
||||
while (*cp)
|
||||
{
|
||||
s1 = cp;
|
||||
s2 = (char *)strSearch;
|
||||
|
||||
if (*s1 == chUntil)
|
||||
return NULL;
|
||||
|
||||
while (*s1 && *s2 && !(*s1-*s2))
|
||||
{
|
||||
s1++, s2++;
|
||||
}
|
||||
|
||||
if (!*s2)
|
||||
return cp;
|
||||
|
||||
cp++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * StrStrUntilStr(const char * string, const char * strSearch, const char * strUntil)
|
||||
{
|
||||
char *cp = (char *)string;
|
||||
char *s1, *s2, *s3;
|
||||
|
||||
if (!*strSearch)
|
||||
return ((char *)string);
|
||||
|
||||
while (*cp)
|
||||
{
|
||||
s1 = cp;
|
||||
s2 = (char *)strSearch;
|
||||
s3 = (char *)strUntil;
|
||||
|
||||
while (*s1 && *s3 && !(*s1-*s3))
|
||||
{
|
||||
s1++, s3++;
|
||||
}
|
||||
|
||||
if (!*s3)
|
||||
return NULL;
|
||||
|
||||
while (*s1 && *s2 && !(*s1-*s2))
|
||||
{
|
||||
s1++, s2++;
|
||||
}
|
||||
|
||||
if (!*s2)
|
||||
return cp;
|
||||
|
||||
cp++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * StrBetweenCpy(const char * pSrc, const char * pszFront, const char * pszRear, char * pDst)
|
||||
{
|
||||
char * pszStart, * pszEnd;
|
||||
|
||||
if ((pszStart = (char *)strstr(pSrc, pszFront)) == NULL)
|
||||
return NULL;
|
||||
|
||||
pszStart += strlen(pszFront);
|
||||
|
||||
if ((pszEnd = strstr(pszStart, pszRear)) == NULL)
|
||||
return NULL;
|
||||
|
||||
strncpy(pDst, pszStart, pszEnd - pszStart);
|
||||
pDst[pszEnd - pszStart] = '\0';
|
||||
|
||||
return pszEnd + strlen(pszRear);
|
||||
}
|
||||
|
||||
size_t StrRemoveBetween(char * pszDst, const char * pszSrc, const char * pszFront, const char * pszRear)
|
||||
{
|
||||
char * pszStart, * pszEnd;
|
||||
|
||||
if ((pszStart = (char *)strstr(pszSrc, pszFront)) == NULL)
|
||||
return 0;
|
||||
|
||||
pszStart += strlen(pszFront);
|
||||
|
||||
if ((pszEnd = strstr(pszStart, pszRear)) == NULL)
|
||||
return 0;
|
||||
|
||||
size_t nFrontSize = pszStart - pszSrc;
|
||||
strncpy(pszDst, pszSrc, nFrontSize);
|
||||
strcpy(pszDst + nFrontSize, pszEnd);
|
||||
|
||||
return nFrontSize + strlen(pszEnd);
|
||||
}
|
||||
|
||||
int StrCountChar(const char * string, char ch)
|
||||
{
|
||||
int n = 0;
|
||||
while (*string)
|
||||
{
|
||||
if (*string++ == ch)
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int StrCountStr(const char * string, const char * strSearch)
|
||||
{
|
||||
int nCount = 0;
|
||||
size_t nSrcLength = strlen(string);
|
||||
size_t nFindLength = strlen(strSearch);
|
||||
|
||||
char * pszStart = (char *)string;
|
||||
char * pszEnd = (char *)string + nSrcLength;
|
||||
char * pszTarget;
|
||||
while (pszStart < pszEnd)
|
||||
{
|
||||
while ((pszTarget = strstr(pszStart, strSearch)) != NULL)
|
||||
{
|
||||
nCount++;
|
||||
pszStart = pszTarget + nFindLength;
|
||||
}
|
||||
pszStart += strlen(pszStart) + 1;
|
||||
}
|
||||
|
||||
return nCount;
|
||||
}
|
||||
|
||||
int StrCountRow(const char * string)
|
||||
{
|
||||
int nCount = 0;
|
||||
const char * p = string;
|
||||
while (*p)
|
||||
{
|
||||
if (*p++ == '\n')
|
||||
nCount++;
|
||||
}
|
||||
|
||||
if (nCount == 0)
|
||||
{
|
||||
p = string;
|
||||
while (*p)
|
||||
{
|
||||
if (*p++ == '\r')
|
||||
nCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nCount == 0 && *string != '\0')
|
||||
return 1;
|
||||
|
||||
return nCount;
|
||||
}
|
||||
|
||||
char * StrTok(const char * pszSrc, const char * pszDelimit, char * pszTokenBuff)
|
||||
{
|
||||
char * pNext, * pSrcOffset = (char *)pszSrc;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
pNext = strstr(pSrcOffset, pszDelimit);
|
||||
if (pNext == NULL)
|
||||
{
|
||||
strcpy(pszTokenBuff, pSrcOffset);
|
||||
return NULL;
|
||||
}
|
||||
else if (pNext != pSrcOffset)
|
||||
break;
|
||||
|
||||
pSrcOffset += strlen(pszDelimit);
|
||||
}
|
||||
|
||||
strncpy(pszTokenBuff, pSrcOffset, pNext - pSrcOffset);
|
||||
pszTokenBuff[pNext - pSrcOffset] = '\0';
|
||||
|
||||
return pNext + strlen(pszDelimit);
|
||||
}
|
||||
|
||||
// const char pszTest[] = " 123456 ";
|
||||
// char * psz = (char *)pszTest;
|
||||
// StrTrim(&psz, strlen(psz), true, true);
|
||||
// psz --> "123456"
|
||||
void StrTrim(char ** ppsz, size_t nLength, bool bRemoveFront, bool bRemoveRear)
|
||||
{
|
||||
if (bRemoveFront)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < nLength; i++)
|
||||
{
|
||||
if ((*ppsz)[i] == ' ' || (*ppsz)[i] == '\t')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
nLength -= i;
|
||||
*ppsz = *ppsz + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == nLength)
|
||||
{
|
||||
nLength = 0;
|
||||
(*ppsz)[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (bRemoveRear)
|
||||
{
|
||||
for (int i = int(nLength - 1); i >= 0; i--)
|
||||
{
|
||||
if ((*ppsz)[i] == ' ' || (*ppsz)[i] == '\t')
|
||||
{
|
||||
(*ppsz)[i] = '\0';
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char * StrNTrimPtr(const char * pszSrc, int nSrcCount)
|
||||
{
|
||||
int nRemain = nSrcCount;
|
||||
for (;;)
|
||||
{
|
||||
if (*pszSrc == '\0')
|
||||
break;
|
||||
else if (*pszSrc == ' ' || *pszSrc == '\t')
|
||||
pszSrc++;
|
||||
else
|
||||
break;
|
||||
|
||||
if (nSrcCount > 0 && --nRemain <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return pszSrc;
|
||||
}
|
||||
|
||||
void StrNTrimCpy(char * pszDst, const char * pszSrc, int nSrcCount)
|
||||
{
|
||||
if (nSrcCount == 0)
|
||||
return;
|
||||
|
||||
int nRemain = nSrcCount;
|
||||
for (;;)
|
||||
{
|
||||
if (*pszSrc == '\0')
|
||||
break;
|
||||
else if (*pszSrc == ' ' || *pszSrc == '\t')
|
||||
pszSrc++;
|
||||
else
|
||||
*pszDst++ = *pszSrc++;
|
||||
|
||||
if (nSrcCount > 0 && --nRemain <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
*pszDst = '\0';
|
||||
}
|
||||
|
||||
char * StrReadLine(char * pszDst, const char * pszSrc, int nCount)
|
||||
{
|
||||
int i = 0;
|
||||
for (; ; i++)
|
||||
{
|
||||
if (nCount > 0 && i >= nCount)
|
||||
break;
|
||||
|
||||
if (pszSrc[i] == '\r' ||
|
||||
pszSrc[i] == '\n')
|
||||
{
|
||||
pszDst[i] = '\0';
|
||||
break;
|
||||
}
|
||||
else if (pszSrc[i] == '\0')
|
||||
{
|
||||
pszDst[i] = '\0';
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
pszDst[i] = pszSrc[i];
|
||||
}
|
||||
|
||||
for (; ; i++)
|
||||
{
|
||||
if (nCount > 0 && i >= nCount)
|
||||
break;
|
||||
|
||||
if (pszSrc[i] != '\r' && pszSrc[i] != '\n' && pszSrc[i] != 0x09)
|
||||
break;
|
||||
}
|
||||
|
||||
return (char *)pszSrc + i;
|
||||
}
|
||||
|
||||
// return new memory
|
||||
const char * StrReplace(const char * pszText, const char * pszKeyword, const char * pszReplace, int nMode, int nCount)
|
||||
{
|
||||
if (nCount == 0)
|
||||
return NULL;
|
||||
|
||||
const char * (*fnStrStr)(const char *, const char *);
|
||||
if (nMode == 0)
|
||||
fnStrStr = (const char*(*)(const char*, const char*))strstr;
|
||||
else if (nMode == 1)
|
||||
fnStrStr = stristr;
|
||||
else
|
||||
fnStrStr = StrIKeyword;
|
||||
|
||||
int nRepeatCount = nCount;
|
||||
size_t nKeywordLength = strlen(pszKeyword);
|
||||
const char * pszNext = (const char *)pszText;
|
||||
int nKeywordCount = 0;
|
||||
for (;;)
|
||||
{
|
||||
if ((pszNext = fnStrStr(pszNext, pszKeyword)) == NULL)
|
||||
break;
|
||||
|
||||
nKeywordCount++;
|
||||
|
||||
if (nRepeatCount > -1 && --nRepeatCount == 0)
|
||||
break;
|
||||
|
||||
pszNext += nKeywordLength;
|
||||
}
|
||||
|
||||
if (nKeywordCount == 0)
|
||||
return NULL;
|
||||
|
||||
size_t nReplaceLength = strlen(pszReplace);
|
||||
size_t nTextLength = strlen(pszText);
|
||||
size_t nNewTextLength = nTextLength + (nReplaceLength - nKeywordLength) * nKeywordCount;
|
||||
char * pszNewText = (char *)malloc(nNewTextLength + 1);
|
||||
|
||||
size_t nCopySize;
|
||||
size_t nRemainSize = nTextLength;
|
||||
char * pszNewTextOffset = pszNewText;
|
||||
const char * pszTextOffset = pszText;
|
||||
|
||||
nRepeatCount = nCount;
|
||||
for (;;)
|
||||
{
|
||||
if ((pszNext = fnStrStr(pszTextOffset, pszKeyword)) == NULL)
|
||||
break;
|
||||
|
||||
nCopySize = pszNext - pszTextOffset;
|
||||
|
||||
memcpy(pszNewTextOffset, pszTextOffset, nCopySize);
|
||||
memcpy(pszNewTextOffset + nCopySize, pszReplace, nReplaceLength);
|
||||
|
||||
pszTextOffset += nCopySize + nKeywordLength;
|
||||
pszNewTextOffset += nCopySize + nReplaceLength;
|
||||
|
||||
nRemainSize -= nCopySize + nKeywordLength;
|
||||
|
||||
if (nRepeatCount > -1 && --nRepeatCount == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nRemainSize > 0)
|
||||
memcpy(pszNewTextOffset, pszTextOffset, nRemainSize);
|
||||
|
||||
pszNewText[nNewTextLength] = '\0';
|
||||
return pszNewText;
|
||||
}
|
||||
|
||||
size_t StrReplace2(char * pszDst, const char * pszText, const char * pszKeyword, const char * pszReplace, int nMode, int nCount)
|
||||
{
|
||||
if (nCount == 0)
|
||||
return 0;
|
||||
|
||||
const char * (*fnStrStr)(const char *, const char *);
|
||||
if (nMode == 0)
|
||||
fnStrStr = (const char*(*)(const char*, const char*))strstr;
|
||||
else if (nMode == 1)
|
||||
fnStrStr = stristr;
|
||||
else
|
||||
fnStrStr = StrIKeyword;
|
||||
|
||||
size_t nKeywordLength = strlen(pszKeyword);
|
||||
size_t nReplaceLength = strlen(pszReplace);
|
||||
size_t nRemainSize = strlen(pszText);
|
||||
char * pszNewTextOffset = pszDst;
|
||||
const char * pszTextOffset = pszText;
|
||||
|
||||
size_t nNewTextLength = 0;
|
||||
size_t nCopySize;
|
||||
const char * pszNext;
|
||||
|
||||
int nRepeatCount = nCount;
|
||||
for (;;)
|
||||
{
|
||||
if ((pszNext = fnStrStr(pszTextOffset, pszKeyword)) == NULL)
|
||||
break;
|
||||
|
||||
nCopySize = pszNext - pszTextOffset;
|
||||
|
||||
memcpy(pszNewTextOffset, pszTextOffset, nCopySize);
|
||||
memcpy(pszNewTextOffset + nCopySize, pszReplace, nReplaceLength);
|
||||
|
||||
pszTextOffset += nCopySize + nKeywordLength;
|
||||
pszNewTextOffset += nCopySize + nReplaceLength;
|
||||
|
||||
nNewTextLength += nCopySize + nReplaceLength;
|
||||
nRemainSize -= nCopySize + nKeywordLength;
|
||||
|
||||
if (nRepeatCount > -1 && --nRepeatCount == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nNewTextLength == 0)
|
||||
return 0;
|
||||
|
||||
if (nRemainSize > 0)
|
||||
{
|
||||
memcpy(pszNewTextOffset, pszTextOffset, nRemainSize);
|
||||
nNewTextLength += nRemainSize;
|
||||
}
|
||||
|
||||
pszDst[nNewTextLength] = '\0';
|
||||
return nNewTextLength;
|
||||
}
|
||||
|
||||
const void * memmem_hus(const void * pMem, size_t nMemSize, const void * pKeymem, size_t nKeymemSize)
|
||||
{
|
||||
const char * p1 = (const char *)pMem;
|
||||
const char * p2;
|
||||
const void * p3;
|
||||
size_t nP2;
|
||||
|
||||
do
|
||||
{
|
||||
p2 = (const char *)pKeymem;
|
||||
nP2 = nKeymemSize;
|
||||
|
||||
while (*p1 != *p2)
|
||||
{
|
||||
p1++;
|
||||
nMemSize--;
|
||||
|
||||
if (nMemSize <= 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p3 = p1;
|
||||
do
|
||||
{
|
||||
p1++;
|
||||
nMemSize--;
|
||||
|
||||
p2++;
|
||||
nP2--;
|
||||
|
||||
if (nP2 <= 0)
|
||||
return p3;
|
||||
else if (*p1 != *p2)
|
||||
break;
|
||||
} while (nMemSize);
|
||||
} while (nMemSize);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
#ifndef STRINGEX__H_
|
||||
#define STRINGEX__H_
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#pragma once
|
||||
|
||||
#else
|
||||
|
||||
//#ifndef __CYGWIN__
|
||||
int stricmp(const char * first, const char * last);
|
||||
int strnicmp(const char * first, const char * last, unsigned int count);
|
||||
char * strlwr(char * str);
|
||||
char * strupr(char * str);
|
||||
//#endif // __CYGWIN__
|
||||
|
||||
#endif
|
||||
|
||||
char * gets_hus(char * s, int n);
|
||||
|
||||
char * stristr(char * pszStr, char * pszSearch);
|
||||
extern inline const char * stristr(const char * pszStr, const char * pszSearch)
|
||||
{
|
||||
return (char *)stristr((char *)pszStr, (char *)pszSearch);
|
||||
}
|
||||
|
||||
extern inline char * strrstr(char * pszStr, char * pszSearch)
|
||||
{
|
||||
char * r = NULL;
|
||||
|
||||
if (!pszSearch[0])
|
||||
return (char *)pszStr + strlen(pszStr);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char * p = strstr(pszStr, pszSearch);
|
||||
if (!p)
|
||||
return r;
|
||||
r = p;
|
||||
pszStr = p + 1;
|
||||
}
|
||||
}
|
||||
|
||||
char * StrIKeyword(char * string, char * strSearch);
|
||||
extern inline const char * StrIKeyword(const char * string, const char * strSearch)
|
||||
{
|
||||
return (char *)StrIKeyword((char *)string, (char *)strSearch);
|
||||
}
|
||||
|
||||
extern inline char * StrNCpy(char * pszBuf, const char * pszStr, size_t nCount)
|
||||
{
|
||||
char * pszResult = strncpy(pszBuf, pszStr, nCount);
|
||||
pszBuf[nCount] = '\0';
|
||||
return pszResult;
|
||||
}
|
||||
|
||||
const char * StrNStr(const char * string, const char * strSearch, int nCount = -1);
|
||||
const char * StrNIStr(const char * string, const char * strSearch, int nCount = -1);
|
||||
const char * StrRChr(const char * string, const char * strStart, char chUntil);
|
||||
const char * StrStrUntilChr(const char * string, const char * strSearch, char chUntil);
|
||||
const char * StrStrUntilStr(const char * string, const char * strSearch, const char * strUntil);
|
||||
|
||||
const char * StrBetweenCpy(const char * pSrc, const char * pszFront, const char * pszRear, char * pDst);
|
||||
size_t StrRemoveBetween(char * pszDst, const char * pszSrc, const char * pszFront, const char * pszRear);
|
||||
|
||||
int StrCountChar(const char * string, char ch);
|
||||
int StrCountStr(const char * string, const char * strSearch);
|
||||
int StrCountRow(const char * string);
|
||||
|
||||
char * StrTok(const char * pszSrc, const char * pszDelimit, char * pszTokenBuff); // This function is similar to strtok(), thread safe
|
||||
|
||||
void StrTrim(char ** ppsz, size_t nLength, bool bRemoveFront, bool bRemoveRear);
|
||||
const char * StrNTrimPtr(const char * pszSrc, int nSrcCount = -1);
|
||||
void StrNTrimCpy(char * pszDst, const char * pszSrc, int nSrcCount = -1);
|
||||
char * StrReadLine(char * pszDst, const char * pszSrc, int nCount = -1);
|
||||
|
||||
const char * StrReplace(const char * pszText, const char * pszKeyword, const char * pszReplace, int nMode = 0, int nCount = -1); // nMode : 0 = case sensitive, 1 = no case, 2 = keyword
|
||||
size_t StrReplace2(char * pszDst, const char * pszText, const char * pszKeyword, const char * pszReplace, int nMode = 0, int nCount = -1); // nMode : 0 = case sensitive, 1 = no case, 2 = keyword
|
||||
|
||||
extern inline bool IsNumeric(const char * psz)
|
||||
{
|
||||
const char * p = psz;
|
||||
while (*p)
|
||||
{
|
||||
if (*p < 48 || *p > 57)
|
||||
return false;
|
||||
p++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern inline bool IsZeroString(const char * psz)
|
||||
{
|
||||
if (*psz == '\0')
|
||||
return false;
|
||||
|
||||
while (*psz)
|
||||
{
|
||||
if (*psz != '0')
|
||||
return false;
|
||||
|
||||
psz++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern inline int HexToI(char ch)
|
||||
{
|
||||
if ((ch >= '0') && (ch <= '9'))
|
||||
return ch-'0';
|
||||
else if ((ch >= 'a') && (ch <= 'f'))
|
||||
return ch-'a'+10;
|
||||
else if ((ch >= 'A') && (ch <= 'F'))
|
||||
return ch-'A'+10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern inline bool IsHex(char ch)
|
||||
{
|
||||
return (((ch>='0') && (ch <='9')) || ((ch>='a') && (ch <='f')) || ((ch >='A') && (ch <='F')));
|
||||
}
|
||||
|
||||
extern inline int AToH(char * psz)
|
||||
{
|
||||
int i = 0;
|
||||
while (*psz && IsHex(*psz))
|
||||
{
|
||||
i = i * 0x10 + HexToI(*psz);
|
||||
psz++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#if 0
|
||||
extern inline bool HexStrToVec(std::vector<uint8_t> * pVec, const char * pszHex)
|
||||
{
|
||||
uint8_t nValue;
|
||||
size_t nCount = strlen(pszHex);
|
||||
|
||||
for (size_t i = 0; i < nCount; i += 2)
|
||||
{
|
||||
nValue = HexToI(pszHex[i]) * 0x10;
|
||||
nValue += HexToI(pszHex[i + 1]);
|
||||
|
||||
pVec->push_back(nValue);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
extern inline void CharToHex(char * pszDst, const char ch, bool bUpperCase = false)
|
||||
{
|
||||
char chCase;
|
||||
if (bUpperCase)
|
||||
chCase = 'A';
|
||||
else
|
||||
chCase = 'a';
|
||||
|
||||
pszDst[0] = (ch >> 4) & 0x0f;
|
||||
pszDst[1] = ch & 0x0f;
|
||||
|
||||
if (pszDst[0] >= 10)
|
||||
pszDst[0] = pszDst[0] - 10 + chCase;
|
||||
else
|
||||
pszDst[0] = pszDst[0] + '0';
|
||||
|
||||
if (pszDst[1] >= 10)
|
||||
pszDst[1] = pszDst[1] - 10 + chCase;
|
||||
else
|
||||
pszDst[1] = pszDst[1] + '0';
|
||||
|
||||
pszDst[2] = '\0';
|
||||
}
|
||||
|
||||
//extern inline void ArrayToHexString(HString * pstrConverted, const unsigned char * pArray, size_t nSize, bool bUpperCase = false)
|
||||
//{
|
||||
// char szHex[4];
|
||||
// for (int i = 0; i < nSize; i++)
|
||||
// {
|
||||
// CharToHex(szHex, pArray[i]);
|
||||
// *pstrConverted += szHex;
|
||||
// }
|
||||
//}
|
||||
|
||||
// aaa\r\nbbb -> aaa\0bbb
|
||||
extern inline char * StrSlice(char * pszBuffer)
|
||||
{
|
||||
for (unsigned int i = 0; pszBuffer[i]; i++)
|
||||
{
|
||||
if (pszBuffer[i] == '\r' && pszBuffer[i + 1] == '\n')
|
||||
{
|
||||
pszBuffer[i] = '\0';
|
||||
return (pszBuffer + i + 2);
|
||||
}
|
||||
else if (pszBuffer[i] == '\n' || pszBuffer[i] == '\r')
|
||||
{
|
||||
pszBuffer[i] = '\0';
|
||||
return (pszBuffer + i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern inline char * StrTokenSlice(char * pszLine, char cDelimiter)
|
||||
{
|
||||
for (unsigned int i = 0; pszLine[i]; i++)
|
||||
{
|
||||
if (pszLine[i] == cDelimiter)
|
||||
{
|
||||
pszLine[i] = '\0';
|
||||
return (pszLine + i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const void * memmem_hus(const void * pMem, size_t nMemSize, const void * pKeymem, size_t nKeymemSize);
|
||||
|
||||
#endif // STRINGEX__H_
|
||||
@@ -0,0 +1,114 @@
|
||||
// DebugAssist.h: interface for the DebugAssist class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(_WIN32) && !defined(_DEBUG)
|
||||
#ifndef DEBUGASSIST_H__
|
||||
#define DEBUGASSIST_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <DbgHelp.h> // in Platform SDK
|
||||
//#include <c:\Program Files\Microsoft SDKs\Windows\v5.0\Include\DbgHelp.h>
|
||||
//or #include <c:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include\DbgHelp.h>
|
||||
//or #include <c:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Include\DbgHelp.h>
|
||||
//or #include <c:\Program Files (x86)\Microsoft Visual Studio 8\VC\PlatformSDK\Include\DbgHelp.h>
|
||||
#include <tchar.h>
|
||||
|
||||
|
||||
TCHAR g_szDbgModulePathName[2048] = {0,};
|
||||
TCHAR g_szDumpPathName[2048] = {0,};
|
||||
|
||||
LONG TopExceptionFilter(LPEXCEPTION_POINTERS pException)
|
||||
{
|
||||
HMODULE hDll = LoadLibrary(g_szDbgModulePathName);
|
||||
if (hDll == NULL)
|
||||
{
|
||||
OutputDebugString(TEXT("tps, ERROR, Can't found DbgHelp.dll file.\n"));
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
|
||||
exceptionInfo.ThreadId = GetCurrentThreadId();
|
||||
exceptionInfo.ExceptionPointers = pException;
|
||||
exceptionInfo.ClientPointers = NULL;
|
||||
|
||||
BOOL (WINAPI * fnWriteDump)(HANDLE, DWORD, ...);
|
||||
fnWriteDump = (BOOL (WINAPI *)(HANDLE, DWORD, ...))GetProcAddress(hDll, "MiniDumpWriteDump");
|
||||
if (fnWriteDump == NULL)
|
||||
{
|
||||
OutputDebugString(TEXT("tps, ERROR, Can't found MiniDumpWriteDump interface.\n"));
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
HANDLE hFile = CreateFile(g_szDumpPathName, GENERIC_WRITE, FILE_SHARE_WRITE,
|
||||
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
fnWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
|
||||
MiniDumpNormal, &exceptionInfo, NULL, NULL);
|
||||
|
||||
FreeLibrary(hDll);
|
||||
CloseHandle(hFile);
|
||||
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
void InitialDumpWriting(LPCTSTR pszDir = NULL, LPCTSTR pszPrefix = NULL)
|
||||
{
|
||||
TCHAR szPostFix[32];
|
||||
|
||||
SYSTEMTIME systemTime;
|
||||
GetLocalTime(&systemTime);
|
||||
|
||||
_stprintf(szPostFix, TEXT("_%.4d%.2d%.2d%.2d%.2d%.2d.dmp"), systemTime.wYear,
|
||||
systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
|
||||
|
||||
if (pszDir && pszPrefix)
|
||||
{
|
||||
// pszDir ex) "C:\\Temp\\"
|
||||
_tcscpy(g_szDbgModulePathName, pszDir);
|
||||
_tcscat(g_szDbgModulePathName, TEXT("dbghelp.dll"));
|
||||
|
||||
_tcscpy(g_szDumpPathName, pszDir);
|
||||
_tcscat(g_szDumpPathName, pszPrefix);
|
||||
_tcscat(g_szDumpPathName, szPostFix);
|
||||
}
|
||||
else
|
||||
{
|
||||
char szModuleFileName[2048];
|
||||
GetModuleFileName(NULL, szModuleFileName, sizeof(szModuleFileName));
|
||||
|
||||
char szDrive[_MAX_DRIVE], szDir[1024], szFileName[1024], szExt[1024];
|
||||
_splitpath_s(szModuleFileName, szDrive, _MAX_DRIVE, szDir, 1024, szFileName, 1024, szExt, 1024);
|
||||
|
||||
if (pszDir)
|
||||
{
|
||||
_tcscpy(g_szDbgModulePathName, pszDir);
|
||||
_tcscpy(g_szDumpPathName, pszDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tcscpy(g_szDbgModulePathName, szDrive);
|
||||
_tcscat(g_szDbgModulePathName, szDir);
|
||||
_tcscpy(g_szDumpPathName, g_szDbgModulePathName);
|
||||
}
|
||||
|
||||
_tcscat(g_szDbgModulePathName, TEXT("dbghelp.dll"));
|
||||
|
||||
if (pszPrefix)
|
||||
{
|
||||
_tcscat(g_szDumpPathName, pszPrefix);
|
||||
_tcscat(g_szDumpPathName, szPostFix);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tcscat(g_szDumpPathName, szFileName);
|
||||
_tcscat(g_szDumpPathName, szPostFix);
|
||||
}
|
||||
}
|
||||
|
||||
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)TopExceptionFilter);
|
||||
}
|
||||
|
||||
#endif // DEBUGASSIST_H__
|
||||
#endif // defined(_WIN32) && !defined(_DEBUG)
|
||||
@@ -0,0 +1,645 @@
|
||||
/*---------------------------------------------------------------------------
|
||||
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||
PARTICULAR PURPOSE.
|
||||
|
||||
Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved.
|
||||
|
||||
MODULE: service.c
|
||||
|
||||
PURPOSE: Implements functions required by all Windows NT services
|
||||
|
||||
FUNCTIONS:
|
||||
main(int argc, char **argv);
|
||||
service_ctrl(DWORD dwCtrlCode);
|
||||
service_main(DWORD dwArgc, LPTSTR *lpszArgv);
|
||||
CmdInstallService();
|
||||
CmdRemoveService();
|
||||
CmdDebugService(int argc, char **argv);
|
||||
ControlHandler ( DWORD dwCtrlType );
|
||||
GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <process.h>
|
||||
#include <tchar.h>
|
||||
#include "WinService.h"
|
||||
|
||||
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
|
||||
// internal variables
|
||||
SERVICE_STATUS g_ssStatus; // current status of the service
|
||||
SERVICE_STATUS_HANDLE g_sshStatusHandle;
|
||||
DWORD g_dwWinServiceErr = 0;
|
||||
TCHAR g_szWinServiceErr[256];
|
||||
BOOL g_bDebugExecuted = FALSE;
|
||||
|
||||
// internal function prototypes
|
||||
VOID WINAPI service_ctrl(DWORD dwCtrlCode);
|
||||
VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
|
||||
VOID CmdInstallService();
|
||||
VOID CmdRemoveService();
|
||||
VOID CmdDebugService(int argc, char **argv);
|
||||
BOOL WINAPI ControlHandler(DWORD dwCtrlType);
|
||||
LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize);
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: main
|
||||
//
|
||||
// PURPOSE: entrypoint for service
|
||||
//
|
||||
// PARAMETERS:
|
||||
// argc - number of command line arguments
|
||||
// argv - array of command line arguments
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
// main() either performs the command line task, or
|
||||
// call StartServiceCtrlDispatcher to register the
|
||||
// main service thread. When the this call returns,
|
||||
// the service has stopped, so exit.
|
||||
//
|
||||
#if 0 // original code
|
||||
void __cdecl main(int argc, char **argv)
|
||||
#else
|
||||
void WinServiceMain(int argc, char **argv)
|
||||
#endif
|
||||
{
|
||||
SERVICE_TABLE_ENTRY dispatchTable[] =
|
||||
{
|
||||
{ TEXT((char *)g_szServiceName), (LPSERVICE_MAIN_FUNCTION)service_main}, { NULL, NULL}
|
||||
};
|
||||
|
||||
if ((argc > 1) && ((*argv[1] == '-') || (*argv[1] == '/')))
|
||||
{
|
||||
if (_stricmp("install", argv[1] + 1) == 0)
|
||||
{
|
||||
CmdInstallService();
|
||||
}
|
||||
else if (_stricmp("remove", argv[1] + 1) == 0)
|
||||
{
|
||||
CmdRemoveService();
|
||||
}
|
||||
else if (_stricmp("debug", argv[1] + 1) == 0)
|
||||
{
|
||||
g_bDebugExecuted = TRUE;
|
||||
CmdDebugService(argc, argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto dispatch;
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// g_bDebugExecuted = TRUE;
|
||||
// CmdDebugService(argc, argv);
|
||||
//}
|
||||
|
||||
// if it doesn't match any of the above parameters
|
||||
// the service control manager may be starting the service
|
||||
// so we must call StartServiceCtrlDispatcher
|
||||
dispatch:
|
||||
const char * pszAppName = strrchr(argv[0], '\\');
|
||||
if (pszAppName)
|
||||
{
|
||||
pszAppName++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pszAppName = strrchr(argv[0], '/');
|
||||
if (pszAppName)
|
||||
pszAppName++;
|
||||
else
|
||||
pszAppName = argv[0];
|
||||
}
|
||||
|
||||
// this is just to be friendly
|
||||
printf("%s -install to install the service\n", pszAppName);
|
||||
printf("%s -remove to remove the service\n", pszAppName);
|
||||
//printf("%s -debug <params> to run as a console app for debugging\n", pszAppName);
|
||||
printf("\nStartServiceCtrlDispatcher being called.\n");
|
||||
printf("This may take several seconds. Please wait.\n");
|
||||
|
||||
#if 1 // original code
|
||||
if (!StartServiceCtrlDispatcher(dispatchTable))
|
||||
AddToMessageLog(TEXT("StartServiceCtrlDispatcher failed."));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: service_main
|
||||
//
|
||||
// PURPOSE: To perform actual initialization of the service
|
||||
//
|
||||
// PARAMETERS:
|
||||
// dwArgc - number of command line arguments
|
||||
// lpszArgv - array of command line arguments
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
// This routine performs the service initialization and then calls
|
||||
// the user defined ServiceStart() routine to perform majority
|
||||
// of the work.
|
||||
//
|
||||
void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
|
||||
{
|
||||
// register our service control handler:
|
||||
//
|
||||
g_sshStatusHandle = RegisterServiceCtrlHandler(TEXT(g_szServiceName), service_ctrl);
|
||||
|
||||
if (!g_sshStatusHandle)
|
||||
goto cleanup;
|
||||
|
||||
// SERVICE_STATUS members that don't change in example
|
||||
//
|
||||
g_ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
g_ssStatus.dwServiceSpecificExitCode = 0;
|
||||
|
||||
|
||||
// report the status to the service control manager.
|
||||
//
|
||||
if (!ReportStatusToSCMgr(
|
||||
SERVICE_START_PENDING, // service state
|
||||
NO_ERROR, // exit code
|
||||
3000)) // wait hint
|
||||
goto cleanup;
|
||||
|
||||
|
||||
ServiceStart(dwArgc, lpszArgv, FALSE);
|
||||
|
||||
cleanup:
|
||||
|
||||
// try to report the stopped status to the service control manager.
|
||||
//
|
||||
if (g_sshStatusHandle)
|
||||
ReportStatusToSCMgr(SERVICE_STOPPED, g_dwWinServiceErr, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: service_ctrl
|
||||
//
|
||||
// PURPOSE: This function is called by the SCM whenever
|
||||
// ControlService() is called on this service.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// dwCtrlCode - type of control requested
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
VOID WINAPI service_ctrl(DWORD dwCtrlCode)
|
||||
{
|
||||
// Handle the requested control code.
|
||||
//
|
||||
switch (dwCtrlCode)
|
||||
{
|
||||
// Stop the service.
|
||||
//
|
||||
// SERVICE_STOP_PENDING should be reported before
|
||||
// setting the Stop Event - hServerStopEvent - in
|
||||
// ServiceStop(). This avoids a race condition
|
||||
// which may result in a 1053 - The Service did not respond...
|
||||
// error.
|
||||
case SERVICE_CONTROL_STOP:
|
||||
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
|
||||
ServiceStop();
|
||||
return;
|
||||
|
||||
// Update the service status.
|
||||
//
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
break;
|
||||
|
||||
// invalid control code
|
||||
//
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
ReportStatusToSCMgr(g_ssStatus.dwCurrentState, NO_ERROR, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: ReportStatusToSCMgr()
|
||||
//
|
||||
// PURPOSE: Sets the current status of the service and
|
||||
// reports it to the Service Control Manager
|
||||
//
|
||||
// PARAMETERS:
|
||||
// dwCurrentState - the state of the service
|
||||
// dwWin32ExitCode - error code to report
|
||||
// dwWaitHint - worst case estimate to next checkpoint
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// TRUE - success
|
||||
// FALSE - failure
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
|
||||
{
|
||||
static DWORD dwCheckPoint = 1;
|
||||
BOOL fResult = TRUE;
|
||||
|
||||
if (!g_bDebugExecuted) // when debugging we don't report to the SCM
|
||||
{
|
||||
if (dwCurrentState == SERVICE_START_PENDING)
|
||||
g_ssStatus.dwControlsAccepted = 0;
|
||||
else
|
||||
g_ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||||
|
||||
g_ssStatus.dwCurrentState = dwCurrentState;
|
||||
g_ssStatus.dwWin32ExitCode = dwWin32ExitCode;
|
||||
g_ssStatus.dwWaitHint = dwWaitHint;
|
||||
|
||||
if ((dwCurrentState == SERVICE_RUNNING) ||
|
||||
(dwCurrentState == SERVICE_STOPPED))
|
||||
g_ssStatus.dwCheckPoint = 0;
|
||||
else
|
||||
g_ssStatus.dwCheckPoint = dwCheckPoint++;
|
||||
|
||||
|
||||
// Report the status of the service to the service control manager.
|
||||
//
|
||||
if (!(fResult = SetServiceStatus(g_sshStatusHandle, &g_ssStatus)))
|
||||
{
|
||||
AddToMessageLog(TEXT("SetServiceStatus"));
|
||||
}
|
||||
}
|
||||
return fResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
|
||||
//
|
||||
// PURPOSE: Allows any thread to log an error message
|
||||
//
|
||||
// PARAMETERS:
|
||||
// lpszMsg - text for message
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
VOID AddToMessageLog(LPTSTR lpszMsg)
|
||||
{
|
||||
//TCHAR szMsg [(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100 ];
|
||||
TCHAR * pszMsg = (TCHAR *)malloc(((strlen(g_szServiceName) / sizeof(TCHAR)) + 100) * sizeof(TCHAR));
|
||||
HANDLE hEventSource;
|
||||
LPTSTR lpszStrings[2];
|
||||
|
||||
if (!g_bDebugExecuted)
|
||||
{
|
||||
g_dwWinServiceErr = GetLastError();
|
||||
|
||||
// Use event logging to log the error.
|
||||
//
|
||||
hEventSource = RegisterEventSource(NULL, TEXT(g_szServiceName));
|
||||
|
||||
_stprintf(pszMsg, TEXT("%s error: %d"), TEXT(g_szServiceName), g_dwWinServiceErr);
|
||||
lpszStrings[0] = pszMsg;
|
||||
lpszStrings[1] = lpszMsg;
|
||||
|
||||
if (hEventSource != NULL)
|
||||
{
|
||||
ReportEvent(hEventSource, // handle of event source
|
||||
EVENTLOG_ERROR_TYPE, // event type
|
||||
0, // event category
|
||||
0, // event ID
|
||||
NULL, // current user's SID
|
||||
2, // strings in lpszStrings
|
||||
0, // no bytes of raw data
|
||||
(LPCTSTR *)lpszStrings, // array of error strings
|
||||
NULL); // no raw data
|
||||
DeregisterEventSource(hEventSource);
|
||||
}
|
||||
}
|
||||
|
||||
free(pszMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The following code handles service installation and removal
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CmdInstallService()
|
||||
//
|
||||
// PURPOSE: Installs the service
|
||||
//
|
||||
// PARAMETERS:
|
||||
// none
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
void CmdInstallService()
|
||||
{
|
||||
SC_HANDLE schService;
|
||||
SC_HANDLE schSCManager;
|
||||
|
||||
TCHAR szPath[2048];
|
||||
|
||||
if (GetModuleFileName(NULL, szPath, 2048) == 0)
|
||||
{
|
||||
_tprintf(TEXT("Unable to install %s - %s\n"), TEXT(g_szServiceDisplayName), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
return;
|
||||
}
|
||||
|
||||
schSCManager = OpenSCManager(
|
||||
NULL, // machine (NULL == local)
|
||||
NULL, // database (NULL == default)
|
||||
SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE // access required
|
||||
);
|
||||
if (schSCManager)
|
||||
{
|
||||
schService = CreateService(
|
||||
schSCManager, // SCManager database
|
||||
TEXT(g_szServiceName), // name of service
|
||||
TEXT(g_szServiceDisplayName), // name to display
|
||||
SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG | SERVICE_START, // desired access
|
||||
SERVICE_WIN32_OWN_PROCESS, // service type
|
||||
//SERVICE_DEMAND_START, // start type
|
||||
SERVICE_AUTO_START,
|
||||
SERVICE_ERROR_NORMAL, // error control type
|
||||
szPath, // service's binary
|
||||
NULL, // no load ordering group
|
||||
NULL, // no tag identifier
|
||||
TEXT(g_szDependencies), // dependencies
|
||||
NULL, // LocalSystem account
|
||||
NULL); // no password
|
||||
|
||||
if (g_szServiceDesc && g_szServiceDesc[0] != TEXT('\0'))
|
||||
{
|
||||
SERVICE_DESCRIPTION serviceDesc;
|
||||
serviceDesc.lpDescription = (LPSTR)g_szServiceDesc;
|
||||
|
||||
if (ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &serviceDesc) == 0)
|
||||
_tprintf(TEXT("ChangeServiceConfig2 failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
}
|
||||
|
||||
SC_ACTION scAction[1];
|
||||
scAction[0].Type = SC_ACTION_RESTART;
|
||||
scAction[0].Delay = 10000;
|
||||
|
||||
SERVICE_FAILURE_ACTIONS serviceFailAction;
|
||||
serviceFailAction.lpsaActions = (SC_ACTION *)scAction;
|
||||
serviceFailAction.cActions = 1;
|
||||
serviceFailAction.dwResetPeriod = 600;
|
||||
serviceFailAction.lpRebootMsg = TEXT("");
|
||||
serviceFailAction.lpCommand = TEXT("");
|
||||
|
||||
if (ChangeServiceConfig2(schService, SERVICE_CONFIG_FAILURE_ACTIONS, &serviceFailAction) == 0)
|
||||
_tprintf(TEXT("ChangeServiceConfig2 failed 2 - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
|
||||
if (schService)
|
||||
{
|
||||
_tprintf(TEXT("%s installed.\n"), TEXT(g_szServiceDisplayName));
|
||||
CloseServiceHandle(schService);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
}
|
||||
|
||||
CloseServiceHandle(schSCManager);
|
||||
}
|
||||
else
|
||||
_tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CmdRemoveService()
|
||||
//
|
||||
// PURPOSE: Stops and removes the service
|
||||
//
|
||||
// PARAMETERS:
|
||||
// none
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
void CmdRemoveService()
|
||||
{
|
||||
SC_HANDLE schService;
|
||||
SC_HANDLE schSCManager;
|
||||
|
||||
schSCManager = OpenSCManager(
|
||||
NULL, // machine (NULL == local)
|
||||
NULL, // database (NULL == default)
|
||||
SC_MANAGER_CONNECT // access required
|
||||
);
|
||||
if (schSCManager)
|
||||
{
|
||||
schService = OpenService(schSCManager, TEXT(g_szServiceName), DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
|
||||
|
||||
if (schService)
|
||||
{
|
||||
// try to stop the service
|
||||
if (ControlService(schService, SERVICE_CONTROL_STOP, &g_ssStatus))
|
||||
{
|
||||
_tprintf(TEXT("Stopping %s."), TEXT(g_szServiceDisplayName));
|
||||
Sleep(1000);
|
||||
|
||||
while (QueryServiceStatus(schService, &g_ssStatus))
|
||||
{
|
||||
if (g_ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
|
||||
{
|
||||
_tprintf(TEXT("."));
|
||||
Sleep(1000);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_ssStatus.dwCurrentState == SERVICE_STOPPED)
|
||||
_tprintf(TEXT("\n%s stopped.\n"), TEXT(g_szServiceDisplayName));
|
||||
else
|
||||
_tprintf(TEXT("\n%s failed to stop.\n"), TEXT(g_szServiceDisplayName));
|
||||
|
||||
}
|
||||
|
||||
// now remove the service
|
||||
if (DeleteService(schService))
|
||||
_tprintf(TEXT("%s removed.\n"), TEXT(g_szServiceDisplayName));
|
||||
else
|
||||
_tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
|
||||
|
||||
CloseServiceHandle(schService);
|
||||
}
|
||||
else
|
||||
_tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
|
||||
CloseServiceHandle(schSCManager);
|
||||
}
|
||||
else
|
||||
_tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(g_szWinServiceErr, 256));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The following code is for running the service as a console app
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CmdDebugService(int argc, char ** argv)
|
||||
//
|
||||
// PURPOSE: Runs the service as a console application
|
||||
//
|
||||
// PARAMETERS:
|
||||
// argc - number of command line arguments
|
||||
// argv - array of command line arguments
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
void CmdDebugService(int argc, char ** argv)
|
||||
{
|
||||
DWORD dwArgc;
|
||||
LPTSTR *lpszArgv;
|
||||
|
||||
#ifdef UNICODE
|
||||
lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc));
|
||||
if (NULL == lpszArgv)
|
||||
{
|
||||
// CommandLineToArvW failed!!
|
||||
_tprintf(TEXT("CmdDebugService CommandLineToArgvW returned NULL\n"));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
dwArgc = (DWORD) argc;
|
||||
lpszArgv = argv;
|
||||
#endif
|
||||
|
||||
_tprintf(TEXT("Debugging %s.\n"), TEXT(g_szServiceDisplayName));
|
||||
|
||||
SetConsoleCtrlHandler(ControlHandler, TRUE);
|
||||
|
||||
ServiceStart(dwArgc, lpszArgv, TRUE);
|
||||
|
||||
#ifdef UNICODE
|
||||
// Must free memory allocated for arguments
|
||||
GlobalFree(lpszArgv);
|
||||
#endif // UNICODE
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: ControlHandler ( DWORD dwCtrlType )
|
||||
//
|
||||
// PURPOSE: Handled console control events
|
||||
//
|
||||
// PARAMETERS:
|
||||
// dwCtrlType - type of control event
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// True - handled
|
||||
// False - unhandled
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
BOOL WINAPI ControlHandler(DWORD dwCtrlType)
|
||||
{
|
||||
switch (dwCtrlType)
|
||||
{
|
||||
case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
|
||||
case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
|
||||
_tprintf(TEXT("Stopping %s.\n"), TEXT(g_szServiceDisplayName));
|
||||
ServiceStop();
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// FUNCTION: GetLastErrorText
|
||||
//
|
||||
// PURPOSE: copies error message text to string
|
||||
//
|
||||
// PARAMETERS:
|
||||
// lpszBuf - destination buffer
|
||||
// dwSize - size of buffer
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// destination buffer
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize)
|
||||
{
|
||||
DWORD dwRet;
|
||||
LPTSTR lpszTemp = NULL;
|
||||
|
||||
dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
LANG_NEUTRAL,
|
||||
(LPTSTR)&lpszTemp,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
// supplied buffer is not long enough
|
||||
if (!dwRet || ((long)dwSize < (long)dwRet + 14))
|
||||
lpszBuf[0] = TEXT('\0');
|
||||
else
|
||||
{
|
||||
lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character
|
||||
_stprintf(lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError());
|
||||
}
|
||||
|
||||
if (lpszTemp)
|
||||
LocalFree((HLOCAL) lpszTemp);
|
||||
|
||||
return lpszBuf;
|
||||
}
|
||||
|
||||
|
||||
#endif _WIN32
|
||||
@@ -0,0 +1,120 @@
|
||||
/*---------------------------------------------------------------------------
|
||||
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||
PARTICULAR PURPOSE.
|
||||
|
||||
Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved.
|
||||
|
||||
MODULE: service.h
|
||||
|
||||
Comments: The use of this header file and the accompanying service.c
|
||||
file simplifies the process of writting a service. You as a developer
|
||||
simply need to follow the TODO's outlined in this header file, and
|
||||
implement the ServiceStart() and ServiceStop() functions.
|
||||
|
||||
There is no need to modify the code in service.c. Just add service.c
|
||||
to your project and link with the following libraries...
|
||||
|
||||
libcmt.lib kernel32.lib advapi.lib shell32.lib
|
||||
|
||||
This code also supports unicode. Be sure to compile both service.c and
|
||||
and code #include "service.h" with the same Unicode setting.
|
||||
|
||||
Upon completion, your code will have the following command line interface
|
||||
|
||||
<service exe> -? to display this list
|
||||
<service exe> -install to install the service
|
||||
<service exe> -remove to remove the service
|
||||
<service exe> -debug <params> to run as a console app for debugging
|
||||
|
||||
Note: This code also implements Ctrl+C and Ctrl+Break handlers
|
||||
when using the debug option. These console events cause
|
||||
your ServiceStop routine to be called
|
||||
|
||||
Also, this code only handles the OWN_SERVICE service type
|
||||
running in the LOCAL_SYSTEM security context.
|
||||
|
||||
To control your service ( start, stop, etc ) you may use the
|
||||
Services control panel applet or the NET.EXE program.
|
||||
|
||||
To aid in writing/debugging service, the
|
||||
SDK contains a utility (MSTOOLS\BIN\SC.EXE) that
|
||||
can be used to control, configure, or obtain service status.
|
||||
SC displays complete status for any service/driver
|
||||
in the service database, and allows any of the configuration
|
||||
parameters to be easily changed at the command line.
|
||||
For more information on SC.EXE, type SC at the command line.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN_SERVICE__H_
|
||||
#define WIN_SERVICE__H_
|
||||
|
||||
|
||||
extern const char * g_szServiceName; // internal name of the service
|
||||
extern const char * g_szServiceDisplayName; // displayed name of the service
|
||||
extern const char * g_szDependencies; // list of service dependencies - "dep1\0dep2\0\0"
|
||||
extern const char * g_szServiceDesc;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// todo: ServiceStart()must be defined by in your code.
|
||||
//// The service should use ReportStatusToSCMgr to indicate
|
||||
//// progress. This routine must also be used by StartService()
|
||||
//// to report to the SCM when the service is running.
|
||||
////
|
||||
//// If a ServiceStop procedure is going to take longer than
|
||||
//// 3 seconds to execute, it should spawn a thread to
|
||||
//// execute the stop code, and return. Otherwise, the
|
||||
//// ServiceControlManager will believe that the service has
|
||||
//// stopped responding
|
||||
////
|
||||
VOID ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv, BOOL bConsoleMode);
|
||||
VOID ServiceStop();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// The following are procedures which
|
||||
//// may be useful to call within the above procedures,
|
||||
//// but require no implementation by the user.
|
||||
//// They are implemented in service.c
|
||||
|
||||
//
|
||||
// FUNCTION: ReportStatusToSCMgr()
|
||||
//
|
||||
// PURPOSE: Sets the current status of the service and
|
||||
// reports it to the Service Control Manager
|
||||
//
|
||||
// PARAMETERS:
|
||||
// dwCurrentState - the state of the service
|
||||
// dwWin32ExitCode - error code to report
|
||||
// dwWaitHint - worst case estimate to next checkpoint
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// TRUE - success
|
||||
// FALSE - failure
|
||||
//
|
||||
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
|
||||
//
|
||||
// PURPOSE: Allows any thread to log an error message
|
||||
//
|
||||
// PARAMETERS:
|
||||
// lpszMsg - text for message
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
void AddToMessageLog(LPTSTR lpszMsg);
|
||||
|
||||
|
||||
void WinServiceMain(int argc, char **argv);
|
||||
|
||||
|
||||
#endif // WIN_SERVICE__H_
|
||||
#endif _WIN32
|
||||
Reference in New Issue
Block a user