Files
wnmj/Servers/服务器组件/网站网关服务器/ServerSocketItem.cpp
2026-03-10 16:10:29 +08:00

470 lines
13 KiB
C++

#include "stdafx.h"
#include "IOCPServer.h"
#include "ServerSocketItem.h"
#include "WebServerDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define PACKET_SIZE 4096
#define BUFFER_OVERFLOW 8192
#define REQUEST_METHOD_POST 0
#define REQUEST_METHOD_GET 1
CServerSocketItem::CServerSocketItem(WORD id, WORD socket, DWORD dwClientAddr, CIOCPServer* pIOCPServer, IClientSocket* pClientSocket) : CTCPSocket(id, socket, dwClientAddr, pIOCPServer)
{
m_pClientSocket = pClientSocket;
}
CServerSocketItem::~CServerSocketItem()
{
}
bool CServerSocketItem::Close()
{
m_pIOCPServer->Disconnect(getID());
return true;
}
bool CServerSocketItem::processRecvData(void* data, DWORD len)
{
// [Trace] log raw incoming data
if (data != NULL && len > 0 && len != (DWORD)SOCKET_ERROR)
{
int nTraceLen = (len > 200) ? 200 : (int)len;
CString strRaw((LPCSTR)data, nTraceLen);
strRaw.Replace(_T("\r"), _T(""));
strRaw.Replace(_T("\n"), _T(" | "));
CString strLog;
strLog.Format(_T("[WebGate] Recv len=%d, head=[%s]"), len, strRaw);
CTraceService::TraceString(strLog, TraceLevel_Normal);
}
switch (len)
{
case 0:
SendResult(_T("{\"result\":%d}"), 1);
break;
case SOCKET_ERROR:
if (GetLastError() != WSAEWOULDBLOCK)
{
TCHAR szError[256];
_tprintf_s(szError, sizeof(szError), _T("ERROR in OnReceive(): %d"), GetLastError());
SaveLog(_T("%s"), szError, TraceLevel_Exception);
}
break;
default:
if (len != SOCKET_ERROR && len != 0)
{
try
{
// Filter non-HTTP data (TLS handshake / binary protocol)
BYTE cbFirstByte = ((LPBYTE)data)[0];
if (cbFirstByte == 0x16 || cbFirstByte == 0x15 || cbFirstByte == 0x00)
{
CString strLog;
strLog.Format(_T("[WebGate] Non-HTTP data (first=0x%02X, len=%d), rejected"), cbFirstByte, len);
CTraceService::TraceString(strLog, TraceLevel_Warning);
SendResult(_T("{\"result\":%d}"), 1);
break;
}
if ( false==m_ParseData.ParseRequests((LPBYTE)data, len) )
{
CString strLog;
strLog.Format(_T("[WebGate] ParseRequests failed, len=%d"), len);
CTraceService::TraceString(strLog, TraceLevel_Exception);
SendResult(_T("{\"result\":%d}"), 1);
break;
}
m_ParseData.ProcessRequests();
CString strUrl;
m_ParseData.GetServerVariable(_T("script_name"), strUrl);
// [Trace] log parsed request info
{
CString strLog;
strLog.Format(_T("[WebGate] Parsed: method=%d, url=[%s], query=[%s], form=[%s]"),
m_ParseData.GetRequestMethod(), strUrl,
m_ParseData.m_QueryParams, m_ParseData.m_FormVars);
CTraceService::TraceString(strLog, TraceLevel_Normal);
}
if ( strUrl.Compare(_T("/active.do"))==0 )
{
bool bRet = ExecuteRequest();
if ( bRet ) break;
// [Trace] ExecuteRequest returned false
{
CString strLog;
strLog.Format(_T("[WebGate] ExecuteRequest failed, url=[%s], query=[%s], form=[%s]"),
strUrl, m_ParseData.m_QueryParams, m_ParseData.m_FormVars);
CTraceService::TraceString(strLog, TraceLevel_Exception);
}
}
else
{
// [Trace] URL does not match /active.do
{
CString strLog;
strLog.Format(_T("[WebGate] URL mismatch: got=[%s] (len=%d), expected=[/active.do]"),
strUrl, strUrl.GetLength());
CTraceService::TraceString(strLog, TraceLevel_Exception);
}
SendResult(_T("{\"result\":%d}"), 1);
if ( strUrl == _T("/favicon.ico") ) break;
}
CTraceService::TraceString(_T("Request URL error: ") + strUrl, TraceLevel_Exception);
}
catch(...)
{
SendResult(_T("{\"result\":%d}"), 1);
throw ;
}
}
break;
}
return true;
}
bool CServerSocketItem::ExecuteRequest()
{
int nRequestMethod = m_ParseData.GetRequestMethod();
if (REQUEST_METHOD_POST == nRequestMethod)
{
m_ParseData.ParseQueryString(m_ParseData.m_FormVars);
SaveLog(_T("%s"), m_ParseData.m_FormVars);
}
else
{
m_ParseData.ParseQueryString(m_ParseData.m_QueryParams);
SaveLog(_T("%s"), m_ParseData.m_QueryParams);
}
CString strWay;
m_ParseData.GetQueryString(_T("way"), strWay);
int nWay = _ttoi(strWay.GetBuffer());
// [Trace] log way parameter
{
CString strLog;
strLog.Format(_T("[WebGate] ExecuteRequest: way=%d (raw=[%s]), method=%d"),
nWay, strWay, nRequestMethod);
CTraceService::TraceString(strLog, TraceLevel_Normal);
}
switch(nWay)
{
case eWebNull:
case eWebCardLib:
{
CTraceService::TraceString(_T("[WebGate] -> WebSetCardLibRequest"), TraceLevel_Normal);
WebSetCardLibRequest();
break;
}
case eWebCheatUser:
{
CTraceService::TraceString(_T("[WebGate] -> WebSetCheatUserRequest"), TraceLevel_Normal);
WebSetCheatUserRequest();
break;
}
case eWebCardLibGlobalCfg:
{
CTraceService::TraceString(_T("[WebGate] -> WebCardLibGlobalCfgRequest"), TraceLevel_Normal);
WebCardLibGlobalCfgRequest();
break;
}
default:
{
CString strLog;
strLog.Format(_T("[WebGate] Unknown way=%d, returning false"), nWay);
CTraceService::TraceString(strLog, TraceLevel_Exception);
return false;
}
}
return true;
}
// Set card library
bool CServerSocketItem::WebSetCardLibRequest()
{
CString strLibID, strSet, strLibKindID, strLibCustomID, strLibCardData, strSign;
m_ParseData.GetQueryString(_T("id"), strLibID);
m_ParseData.GetQueryString(_T("set"), strSet);
m_ParseData.GetQueryString(_T("kid"), strLibKindID);
m_ParseData.GetQueryString(_T("cid"), strLibCustomID);
m_ParseData.GetQueryString(_T("data"), strLibCardData);
m_ParseData.GetQueryString(_T("sign"), strSign);
CString strData;
strData.Format(_T("way=%d&id=%s&set=%s&kid=%s&cid=%s&data=%s&%s"), eWebCardLib, strLibID, strSet, strLibKindID, strLibCustomID, strLibCardData, CWebServerDlg::g_strVerifyKey);
TCHAR szMD5Result[33];
CWHEncrypt::MD5Encrypt(strData, szMD5Result);
// [Trace] log sign verification for CardLib
{
CString strLog;
strLog.Format(_T("[WebGate] CardLib sign check: recv=[%s], calc=[%s], id=[%s], set=[%s], kid=[%s], cid=[%s]"),
strSign, szMD5Result, strLibID, strSet, strLibKindID, strLibCustomID);
CTraceService::TraceString(strLog, TraceLevel_Normal);
}
if (strSign.CompareNoCase(szMD5Result) == 0)
{
CMD_CS_SetCardLib mCardLib;
ZeroMemory(&mCardLib, sizeof(CMD_CS_SetCardLib));
mCardLib.dwID = atoi(strLibID.GetBuffer());
mCardLib.dwCustomID = atoi(strLibCustomID.GetBuffer());
mCardLib.cbFlag = atoi(strSet.GetBuffer());
mCardLib.wKindID = atoi(strLibKindID.GetBuffer());
CString strSub;
int nCount = 0;
while (AfxExtractSubString(strSub, strLibCardData, nCount, ','))
{
ASSERT(nCount <= LEN_CARD_LIB);
if (nCount > LEN_CARD_LIB)
{
break;
}
TCHAR* lpStrEnd = NULL;
mCardLib.cbData[nCount] = (BYTE)_tcstol(strSub.GetBuffer(), &lpStrEnd, 16);
nCount++;
mCardLib.cbCount++;
}
m_pClientSocket->SendData(MDM_CS_WEB_SERVICE, SUB_CS_C_SET_CARD_LIB, &mCardLib, sizeof(CMD_CS_SetCardLib));
SendResult(_T("{\"result\":%d}"), OPER_SUCCESSED);
}
else
{
SendResult(_T("{\"result\":%d}"), OPER_VERIFY_ERROR);
SaveLog(_T("%s"), "Sign verify failed!");
}
return true;
}
// Set cheat user
bool CServerSocketItem::WebSetCheatUserRequest()
{
CString strUserID, strSet, strLibIndex, strLibStartTime, strLibStopTime, strSign;
m_ParseData.GetQueryString(_T("uid"), strUserID);
m_ParseData.GetQueryString(_T("set"), strSet);
m_ParseData.GetQueryString(_T("sign"), strSign);
m_ParseData.GetQueryString(_T("index"), strLibIndex);
m_ParseData.GetQueryString(_T("stime"), strLibStartTime);
m_ParseData.GetQueryString(_T("etime"), strLibStopTime);
CString strData;
strData.Format(_T("way=%d&uid=%s&set=%s&index=%s&stime=%s&etime=%s&%s"), eWebCheatUser, strUserID, strSet, strLibIndex, strLibStartTime, strLibStopTime, CWebServerDlg::g_strVerifyKey);
TCHAR szMD5Result[33];
CWHEncrypt::MD5Encrypt(strData, szMD5Result);
// [Trace] log sign verification for CheatUser
{
CString strLog;
strLog.Format(_T("[WebGate] CheatUser sign check: recv=[%s], calc=[%s], uid=[%s], set=[%s]"),
strSign, szMD5Result, strUserID, strSet);
CTraceService::TraceString(strLog, TraceLevel_Normal);
}
if ( strSign.CompareNoCase(szMD5Result) == 0 )
{
CMD_CS_SetCheatUser mCheatUser;
ZeroMemory(&mCheatUser, sizeof(CMD_CS_SetCheatUser));
mCheatUser.dwUserID = atoi(strUserID.GetBuffer());
mCheatUser.cbFlag = atoi(strSet.GetBuffer());
if (strLibStartTime.GetLength()>0 && strLibStopTime.GetLength()>0)
{
try
{
CTime cTime = CTime::GetCurrentTime();
CString strDateTime;
strDateTime.Format(_T("%s %s"), cTime.Format("%Y-%m-%d"), strLibStartTime);
mCheatUser.dwStartLibTime = CWHService::ConvertDateTimeToDWORD(strDateTime);
strDateTime.Format(_T("%s %s"), cTime.Format("%Y-%m-%d"), strLibStopTime);
mCheatUser.dwStopLibTime = CWHService::ConvertDateTimeToDWORD(strDateTime);
}
catch (...)
{
mCheatUser.dwStartLibTime = 0;
mCheatUser.dwStopLibTime = 0;
mCheatUser.cbFlag = 0;
}
}
else
{
mCheatUser.cbFlag = 0;
}
m_pClientSocket->SendData(MDM_CS_WEB_SERVICE, SUB_CS_C_SET_CHEAT_USER, &mCheatUser, sizeof(CMD_CS_SetCheatUser));
SendResult(_T("{\"result\":%d}"), OPER_SUCCESSED);
}
else
{
SendResult(_T("{\"result\":%d}"), OPER_VERIFY_ERROR);
SaveLog(_T("%s"), "Sign verify failed!");
}
return true;
}
// Card library global config
bool CServerSocketItem::WebCardLibGlobalCfgRequest()
{
CString strSet, strLibKindID, strCardLibCount, strLibStartTime, strLibStopTime, strSign;
m_ParseData.GetQueryString(_T("set"), strSet);
m_ParseData.GetQueryString(_T("kid"), strLibKindID);
m_ParseData.GetQueryString(_T("libcount"), strCardLibCount);
m_ParseData.GetQueryString(_T("stime"), strLibStartTime);
m_ParseData.GetQueryString(_T("etime"), strLibStopTime);
m_ParseData.GetQueryString(_T("sign"), strSign);
CString strData;
strData.Format(_T("way=%d&set=%s&kid=%s&libcount=%s&stime=%s&etime=%s&%s"), eWebCardLibGlobalCfg, strSet, strLibKindID, strCardLibCount, strLibStartTime, strLibStopTime, CWebServerDlg::g_strVerifyKey);
TCHAR szMD5Result[33];
CWHEncrypt::MD5Encrypt(strData, szMD5Result);
// [Trace] log sign verification for GlobalCfg
{
CString strLog;
strLog.Format(_T("[WebGate] GlobalCfg sign check: recv=[%s], calc=[%s], set=[%s], kid=[%s], libcount=[%s]"),
strSign, szMD5Result, strSet, strLibKindID, strCardLibCount);
CTraceService::TraceString(strLog, TraceLevel_Normal);
}
if (strSign.CompareNoCase(szMD5Result) == 0)
{
CMD_CS_CardLibGlobalCfg mGlobalCfg;
ZeroMemory(&mGlobalCfg, sizeof(CMD_CS_CardLibGlobalCfg));
mGlobalCfg.cbFlag = atoi(strSet.GetBuffer());
mGlobalCfg.wKindID = atoi(strLibKindID.GetBuffer());
mGlobalCfg.dwLibCount = atoi(strCardLibCount.GetBuffer());
if (strLibStartTime.GetLength() > 0 && strLibStopTime.GetLength() > 0)
{
try
{
mGlobalCfg.dwStartLibTime = CWHService::ConvertDateTimeToDWORD(strLibStartTime);
mGlobalCfg.dwStopLibTime = CWHService::ConvertDateTimeToDWORD(strLibStopTime);
}
catch (...)
{
mGlobalCfg.dwStartLibTime = 0;
mGlobalCfg.dwStopLibTime = 0;
mGlobalCfg.cbFlag = 0;
}
}
else
{
mGlobalCfg.cbFlag = 0;
}
m_pClientSocket->SendData(MDM_CS_WEB_SERVICE, SUB_CS_C_CARD_LIB_GLOBAL_CFG, &mGlobalCfg, sizeof(CMD_CS_CardLibGlobalCfg));
SendResult(_T("{\"result\":%d}"), OPER_SUCCESSED);
}
else
{
SendResult(_T("{\"result\":%d}"), OPER_VERIFY_ERROR);
SaveLog(_T("%s"), "Sign verify failed!");
}
return true;
}
bool CServerSocketItem::HttpResponse(LPCTSTR lpszMessage)
{
CString strHeader;
CString strResult = lpszMessage;
// HTTP version
strHeader = _T("HTTP/1.0 ");
// status
strHeader += _T("200 OK\r\n");
// servername
strHeader += _T("Server: Web Server\r\n");
// content type
strHeader += _T("Content-Type: text/html\r\n");
// file length
CString strLength;
strLength.Format(_T("Content-Length: %d\r\n"), strResult.GetLength());
strHeader += strLength;
SYSTEMTIME systemTime;
GetSystemTime(&systemTime);
// get internet time
TCHAR buff[INTERNET_RFC1123_BUFSIZE] = {0};
InternetTimeFromSystemTime(&systemTime, INTERNET_RFC1123_FORMAT, buff, INTERNET_RFC1123_BUFSIZE);
// modified
strHeader += _T("Last-Modified: ");
strHeader += CString(buff);
// In HTTP1.1, client and server support keep-alive by default.
// If client does not want keep-alive, set Connection: close in header.
// If server does not support keep-alive, response should also say Connection: close.
// connection
strHeader += _T("Connection: close");
strHeader += _T("\r\n\r\n");
strHeader += lpszMessage;
m_pIOCPServer->SendData(getID(), strHeader.GetBuffer(), strHeader.GetLength());
//Close();
return true;
}
// Send result
bool CServerSocketItem::SendResult(LPCTSTR pstrFormat, ...)
{
try
{
CString strResult;
// format and write the data we were given
va_list args;
va_start(args, pstrFormat);
strResult.FormatV(pstrFormat, args);
va_end(args);
HttpResponse(strResult);
}
catch(CMemoryException *e)
{
e->Delete();
return false;
}
catch(...)
{
return false;
}
return true;
}