549 lines
11 KiB
C++
549 lines
11 KiB
C++
#include "WSUser.h"
|
||
#include "WSServer.h"
|
||
#include "ManagerV2.h"
|
||
#include "base/HGInfo.h"
|
||
#include "cJSON.h"
|
||
#include "sha1.h"
|
||
#include "base64.h"
|
||
|
||
namespace ver_2
|
||
{
|
||
static int GetJsonIntValue(cJSON* json, const std::string& key)
|
||
{
|
||
int ret = 0;
|
||
|
||
cJSON* p = json->child;
|
||
while (NULL != p)
|
||
{
|
||
if (0 == strcmp(p->string, key.c_str()))
|
||
{
|
||
if (p->type == cJSON_Number)
|
||
ret = p->valueint;
|
||
break;
|
||
}
|
||
|
||
p = p->next;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
static bool GetJsonBoolValue(cJSON* json, const std::string& key)
|
||
{
|
||
bool ret = false;
|
||
|
||
cJSON* p = json->child;
|
||
while (NULL != p)
|
||
{
|
||
if (0 == strcmp(p->string, key.c_str()))
|
||
{
|
||
if (p->type == cJSON_True)
|
||
ret = true;
|
||
break;
|
||
}
|
||
|
||
p = p->next;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
static std::string GetJsonStringValue(cJSON* json, const std::string& key)
|
||
{
|
||
std::string ret;
|
||
|
||
cJSON* p = json->child;
|
||
while (NULL != p)
|
||
{
|
||
if (0 == strcmp(p->string, key.c_str()))
|
||
{
|
||
if (p->type == cJSON_String)
|
||
ret = p->valuestring;
|
||
break;
|
||
}
|
||
|
||
p = p->next;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
#if defined(HG_CMP_MSC)
|
||
WSUser::WSUser(WebServer* server, HGUInt id, const std::string& ip, uint16_t port, SOCKET sockConn)
|
||
#else
|
||
WSUser::WSUser(WebServer* server, HGUInt id, const std::string& ip, uint16_t port, int sockConn)
|
||
#endif
|
||
: WebUser(server, id, ip, port, sockConn)
|
||
{
|
||
|
||
}
|
||
|
||
WSUser::~WSUser()
|
||
{
|
||
|
||
}
|
||
|
||
ManagerV2* WSUser::GetManager()
|
||
{
|
||
return ((WSServer*)m_server)->GetManger();
|
||
}
|
||
|
||
void WSUser::HandleCmd(const WSCmdParam* param)
|
||
{
|
||
assert(NULL != param && m_id == param->usrId);
|
||
|
||
std::string cmdData((const char*)param->data, param->size);
|
||
cJSON* json = cJSON_Parse(cmdData.c_str());
|
||
if (NULL != json)
|
||
{
|
||
std::string func = GetJsonStringValue(json, "func");
|
||
if ("set_global_config" == func)
|
||
{
|
||
|
||
}
|
||
else if ("get_global_config" == func)
|
||
{
|
||
|
||
}
|
||
else if ("load_local_image" == func)
|
||
{
|
||
|
||
}
|
||
|
||
cJSON_Delete(json);
|
||
}
|
||
}
|
||
|
||
void WSUser::HandleEvent(const WSEvtParam* param)
|
||
{
|
||
assert(NULL != param && m_id == param->usrId);
|
||
|
||
SendResponse(param->data, param->size, HGTRUE);
|
||
}
|
||
|
||
void WSUser::PostCmdMsg(const HGByte* data, HGUInt dataSize)
|
||
{
|
||
WSCmdParam* param = new WSCmdParam;
|
||
param->svr = (WSServer*)m_server;
|
||
param->usrId = m_id;
|
||
param->data = new HGByte[dataSize];
|
||
param->size = dataSize;
|
||
memcpy(param->data, data, dataSize);
|
||
|
||
HGMsg msg;
|
||
msg.id = MSGID_WS_COMMAND;
|
||
msg.data = param;
|
||
if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_server->GetMsgPump(), &msg))
|
||
{
|
||
delete[] param->data;
|
||
param->size = 0;
|
||
delete param;
|
||
}
|
||
}
|
||
|
||
void WSUser::PostEventMsg(const HGByte* data, HGUInt dataSize)
|
||
{
|
||
WSEvtParam* param = new WSEvtParam;
|
||
param->svr = (WSServer*)m_server;
|
||
param->usrId = m_id;
|
||
param->data = new HGByte[dataSize];
|
||
param->size = dataSize;
|
||
memcpy(param->data, data, dataSize);
|
||
|
||
HGMsg msg;
|
||
msg.id = MSGID_WS_EVENT;
|
||
msg.data = param;
|
||
if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_server->GetMsgPump(), &msg))
|
||
{
|
||
delete[] param->data;
|
||
param->size = 0;
|
||
delete param;
|
||
}
|
||
}
|
||
|
||
void WSUser::ThreadFunc()
|
||
{
|
||
HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "WSUser::ThreadFunc");
|
||
|
||
char chBuffer[2048];
|
||
const char* pBuffer = chBuffer;
|
||
int nBufferSize = 0;
|
||
bool bConnect = false;
|
||
|
||
unsigned char connectDataTail[4] = { '\r', '\n', '\r', '\n' };
|
||
unsigned int connectDataTailLen = 0;
|
||
std::string connectData;
|
||
|
||
uint8_t* pData = NULL;
|
||
int nDataSize = 0;
|
||
uint8_t* pDataEx = NULL;
|
||
int nRemainSize = 0;
|
||
uint8_t headData[20];
|
||
uint32_t nHeadDataLen = 0;
|
||
uint8_t vMask[4];
|
||
uint32_t nMaskCount = 0;
|
||
bool bHandle = false;
|
||
std::vector<uint8_t> vAllData;
|
||
|
||
while (1)
|
||
{
|
||
if (0 == nBufferSize)
|
||
{
|
||
int len = recv(m_sockConn, chBuffer, 2048, 0);
|
||
if (len <= 0)
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD>socketConn<6E><6E><EFBFBD><EFBFBD><EFBFBD>߿ͻ<DFBF><CDBB>˹ر<CBB9><D8B1><EFBFBD>socket<65><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD>
|
||
PostDisConnectMsg();
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
pBuffer = chBuffer;
|
||
nBufferSize = len;
|
||
}
|
||
}
|
||
|
||
assert(nBufferSize > 0);
|
||
|
||
if (!bConnect)
|
||
{
|
||
unsigned char b = *pBuffer;
|
||
++pBuffer;
|
||
--nBufferSize;
|
||
|
||
connectData.push_back(b);
|
||
if (b == connectDataTail[connectDataTailLen])
|
||
{
|
||
++connectDataTailLen;
|
||
}
|
||
else
|
||
{
|
||
connectDataTailLen = 0;
|
||
if (b == connectDataTail[connectDataTailLen])
|
||
{
|
||
++connectDataTailLen;
|
||
}
|
||
}
|
||
|
||
if (4 == connectDataTailLen)
|
||
{
|
||
connectDataTailLen = 0;
|
||
bool shakeRet = ShakeHand(connectData);
|
||
connectData.clear();
|
||
|
||
if (!shakeRet)
|
||
{
|
||
PostDisConnectMsg();
|
||
break;
|
||
}
|
||
|
||
bConnect = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (NULL == pData)
|
||
{
|
||
assert(0 == nDataSize);
|
||
|
||
uint8_t b = *pBuffer;
|
||
++pBuffer;
|
||
--nBufferSize;
|
||
headData[nHeadDataLen] = b;
|
||
++nHeadDataLen;
|
||
|
||
if (1 == nHeadDataLen)
|
||
{
|
||
if ((0x80 | 0x08) == headData[0]) // <20>Ͽ<EFBFBD><CFBF><EFBFBD><EFBFBD><EFBFBD>
|
||
{
|
||
PostDisConnectMsg();
|
||
break;
|
||
}
|
||
else if ((0x80 | 0x09) == headData[0]) // PING֡
|
||
{
|
||
//
|
||
}
|
||
else if ((0x80 | 0x0A) == headData[0]) // PONG֡
|
||
{
|
||
//
|
||
}
|
||
else if ((0x00 | 0x01) == headData[0] || (0x00 | 0x02) == headData[0] || (0x00 | 0x00) == headData[0] || (0x80 | 0x00) == headData[0]
|
||
|| (0x80 | 0x01) == headData[0] || (0x80 | 0x02) == headData[0]) // <20><><EFBFBD><EFBFBD>֡
|
||
{
|
||
if ((0x80 | 0x00) == headData[0] || (0x80 | 0x01) == headData[0] || (0x80 | 0x02) == headData[0])
|
||
{
|
||
// <20><>Ƭ<EFBFBD><C6AC><EFBFBD><EFBFBD>
|
||
bHandle = true;
|
||
}
|
||
else
|
||
{
|
||
// <20><>Ƭ֡
|
||
bHandle = false;
|
||
}
|
||
}
|
||
else // ֡<><D6A1><EFBFBD>Ͽ<F3A3ACB6><CFBF><EFBFBD><EFBFBD><EFBFBD>
|
||
{
|
||
PostDisConnectMsg();
|
||
break;
|
||
}
|
||
}
|
||
else if (2 == nHeadDataLen)
|
||
{
|
||
if (0 == (headData[1] & 0x80)) // <20><><EFBFBD>뾭<EFBFBD><EBBEAD><EFBFBD><EFBFBD><EFBFBD>봦<EFBFBD><EBB4A6>
|
||
{
|
||
PostDisConnectMsg();
|
||
break;
|
||
}
|
||
|
||
if ((0x80 | 0x09) == headData[0]) // PING֡
|
||
{
|
||
if (0x80 != headData[1])
|
||
{
|
||
PostDisConnectMsg();
|
||
break;
|
||
}
|
||
}
|
||
else if ((0x80 | 0x0A) == headData[0]) // PONG֡
|
||
{
|
||
if (0x80 != headData[1])
|
||
{
|
||
PostDisConnectMsg();
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ((headData[1] & 0x7F) <= 125)
|
||
{
|
||
uint32_t nCmdSize = (headData[1] & 0x7F);
|
||
nHeadDataLen = 0;
|
||
|
||
if (0 == nCmdSize)
|
||
{
|
||
PostDisConnectMsg();
|
||
break;
|
||
}
|
||
|
||
nDataSize = nCmdSize;
|
||
nRemainSize = nCmdSize;
|
||
pData = new uint8_t[nDataSize];
|
||
pDataEx = pData;
|
||
}
|
||
}
|
||
}
|
||
else if (4 == nHeadDataLen)
|
||
{
|
||
if ((0x80 | 0x09) == headData[0]) // PING֡
|
||
{
|
||
//
|
||
}
|
||
else if ((0x80 | 0x0A) == headData[0]) // PONG֡
|
||
{
|
||
//
|
||
}
|
||
else
|
||
{
|
||
if ((headData[1] & 0x7F) == 126)
|
||
{
|
||
uint32_t nCmdSize = ntohs(*(uint16_t*)&headData[2]);
|
||
nHeadDataLen = 0;
|
||
|
||
if (0 == nCmdSize)
|
||
{
|
||
PostDisConnectMsg();
|
||
break;
|
||
}
|
||
|
||
nDataSize = nCmdSize;
|
||
nRemainSize = nCmdSize;
|
||
pData = new uint8_t[nDataSize];
|
||
pDataEx = pData;
|
||
}
|
||
}
|
||
}
|
||
else if (6 == nHeadDataLen)
|
||
{
|
||
if ((0x80 | 0x09) == headData[0]) // PING֡
|
||
{
|
||
nHeadDataLen = 0;
|
||
|
||
Pong();
|
||
}
|
||
else if ((0x80 | 0x0A) == headData[0]) // PONG֡
|
||
{
|
||
nHeadDataLen = 0;
|
||
}
|
||
}
|
||
else if (10 == nHeadDataLen)
|
||
{
|
||
if ((headData[1] & 0x7F) == 127) // <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>127
|
||
{
|
||
uint32_t nCmdSizeHigh = ntohl(*(uint32_t*)&headData[2]);
|
||
uint32_t nCmdSize = ntohl(*(uint32_t*)&headData[6]);
|
||
nHeadDataLen = 0;
|
||
|
||
if ((0 != nCmdSizeHigh) || (0 == nCmdSize))
|
||
{
|
||
PostDisConnectMsg();
|
||
break;
|
||
}
|
||
|
||
nDataSize = nCmdSize;
|
||
nRemainSize = nCmdSize;
|
||
pData = new uint8_t[nDataSize];
|
||
pDataEx = pData;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (4 != nMaskCount)
|
||
{
|
||
uint8_t b = *pBuffer;
|
||
++pBuffer;
|
||
--nBufferSize;
|
||
vMask[nMaskCount] = b;
|
||
++nMaskCount;
|
||
}
|
||
else
|
||
{
|
||
int nWriteSize = HGMIN(nBufferSize, nRemainSize);
|
||
memcpy(pDataEx, pBuffer, nWriteSize);
|
||
pBuffer += nWriteSize;
|
||
nBufferSize -= nWriteSize;
|
||
pDataEx += nWriteSize;
|
||
nRemainSize -= nWriteSize;
|
||
|
||
if (0 == nRemainSize)
|
||
{
|
||
assert(pDataEx == pData + nDataSize);
|
||
|
||
for (int i = 0; i < nDataSize; ++i)
|
||
{
|
||
int j = i % 4;
|
||
pData[i] = pData[i] ^ vMask[j];
|
||
vAllData.push_back(pData[i]);
|
||
}
|
||
|
||
delete[] pData;
|
||
pData = NULL;
|
||
nDataSize = 0;
|
||
nMaskCount = 0;
|
||
|
||
if (bHandle)
|
||
{
|
||
PostCmdMsg(&vAllData[0], vAllData.size());
|
||
|
||
bHandle = false;
|
||
vAllData.clear();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (NULL != pData)
|
||
{
|
||
delete[] pData;
|
||
pData = NULL;
|
||
nDataSize = 0;
|
||
nMaskCount = 0;
|
||
}
|
||
}
|
||
|
||
bool WSUser::ShakeHand(const std::string& head)
|
||
{
|
||
std::string requestMethod;
|
||
std::string requestURIPath;
|
||
HttpPairs requestURIQueryInfos;
|
||
std::string requestURIFragment;
|
||
std::string httpVersion;
|
||
HttpPairs headInfos;
|
||
HttpHead::AnalysisHead(head, requestMethod, requestURIPath, requestURIQueryInfos,
|
||
requestURIFragment, httpVersion, headInfos);
|
||
|
||
if ("Upgrade" != HttpHead::GetValue(headInfos, "Connection"))
|
||
return false;
|
||
if ("websocket" != HttpHead::GetValue(headInfos, "Upgrade"))
|
||
return false;
|
||
|
||
std::string key = HttpHead::GetValue(headInfos, "Sec-WebSocket-Key");
|
||
if (key.empty())
|
||
return false;
|
||
|
||
key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||
|
||
unsigned int message_digest[5];
|
||
SHA1 sha;
|
||
sha.Reset();
|
||
sha << key.c_str();
|
||
sha.Result(message_digest);
|
||
|
||
for (int i = 0; i < 5; ++i)
|
||
message_digest[i] = htonl(message_digest[i]);
|
||
std::string serverKey = base64_encode((const unsigned char*)message_digest, 20);
|
||
|
||
std::string handShakeResp = "HTTP/1.1 101 Switching Protocols\r\n";
|
||
handShakeResp += "Upgrade: websocket\r\n";
|
||
handShakeResp += "Connection: Upgrade\r\n";
|
||
handShakeResp += "Sec-WebSocket-Accept:";
|
||
handShakeResp += serverKey;
|
||
handShakeResp += "\r\n\r\n";
|
||
send(m_sockConn, handShakeResp.c_str(), (int)handShakeResp.length(), 0);
|
||
return true;
|
||
}
|
||
|
||
void WSUser::Pong()
|
||
{
|
||
uint8_t vHead[2];
|
||
vHead[0] = 0x80 | 0x0A;
|
||
vHead[1] = 0;
|
||
|
||
HGBase_EnterLock(m_cs);
|
||
send(m_sockConn, (const char*)vHead, 2, 0);
|
||
HGBase_LeaveLock(m_cs);
|
||
}
|
||
|
||
bool WSUser::SendResponse(const HGByte* data, HGUInt size, HGBool text)
|
||
{
|
||
if (NULL == data || 0 == size)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
uint32_t nHeadLen = 0;
|
||
|
||
uint8_t vHead[20] = { 0 };
|
||
vHead[0] = text ? (0x80 | 0x01) : (0x80 | 0x02);
|
||
if (size <= 125)
|
||
{
|
||
vHead[1] = (uint8_t)size;
|
||
nHeadLen = 2;
|
||
}
|
||
else if (size <= 0xFFFF)
|
||
{
|
||
vHead[1] = 126;
|
||
uint16_t payloadLength16b = htons((uint16_t)size);
|
||
memcpy(&vHead[2], &payloadLength16b, 2);
|
||
nHeadLen = 4;
|
||
}
|
||
else
|
||
{
|
||
vHead[1] = 127;
|
||
vHead[2] = 0;
|
||
vHead[3] = 0;
|
||
vHead[4] = 0;
|
||
vHead[5] = 0;
|
||
uint32_t payloadLength32b = htonl(size);
|
||
memcpy(&vHead[6], &payloadLength32b, 4);
|
||
nHeadLen = 10;
|
||
}
|
||
|
||
HGBase_EnterLock(m_cs);
|
||
send(m_sockConn, (const char*)vHead, nHeadLen, 0);
|
||
send(m_sockConn, (const char*)data, size, 0);
|
||
HGBase_LeaveLock(m_cs);
|
||
return true;
|
||
}
|
||
} |