code_app/sdk/webservice/SockIoUser.cpp

629 lines
14 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "SockIoUser.h"
#include "SockIoServer.h"
#include "ManagerV1.h"
#include "base/HGInfo.h"
#include "base/HGUtility.h"
#include "cJSON.h"
#include "sha1.h"
#include "base64.h"
namespace ver_1
{
#if defined(HG_CMP_MSC)
SockIoUser::SockIoUser(WebServer* server, HGUInt id, const std::string& ip, uint16_t port, SOCKET sockConn)
#else
SockIoUser::SockIoUser(WebServer* server, HGUInt id, const std::string& ip, uint16_t port, int sockConn)
#endif
: WebUser(server, id, ip, port, sockConn)
{
GetManager()->AddUser(this);
}
SockIoUser::~SockIoUser()
{
GetManager()->RemoveUser(this);
}
ManagerV1* SockIoUser::GetManager()
{
return ((SockIoServer*)m_server)->GetManger();
}
void SockIoUser::HandleCmd(const SockIoCmdParam* param)
{
assert(NULL != param && m_id == param->usrId);
std::string user;
std::string data;
GetMsgInfo(param, user, data);
if (user.empty())
{
return;
}
if ("scan" == user)
{
std::string imgName;
bool insert = false;
cJSON* json = cJSON_Parse(data.c_str());
if (NULL != json)
{
if (NULL != json->child && 0 == strcmp("imageName", json->child->string)
&& cJSON_String == json->child->type)
{
imgName = json->child->valuestring;
if (NULL != json->child->next && 0 == strcmp("isInsert", json->child->next->string)
&& cJSON_True == json->child->next->type)
insert = true;
}
cJSON_Delete(json);
}
bool ret = GetManager()->Scan(imgName, insert);
if (!ret)
{
std::string resp = "42[\"error\", \"scan error\"]";
SendResponse((const HGByte*)resp.c_str(), (HGUInt)resp.size(), HGTRUE);
}
}
else if ("stop" == user)
{
bool ret = GetManager()->StopScan();
assert(ret);
std::string resp = "42[\"success\", \"stop scan success!\"]";
SendResponse((const HGByte*)resp.c_str(), (HGUInt)resp.size(), HGTRUE);
}
}
void SockIoUser::HandleEvent(const SockIoEvtParam* param)
{
assert(NULL != param && m_id == param->usrId);
SendResponse(param->data, param->size, HGTRUE);
}
void SockIoUser::PostCmdMsg(const HGByte* data, HGUInt dataSize)
{
SockIoCmdParam* param = new SockIoCmdParam;
param->svr = (SockIoServer*)m_server;
param->usrId = m_id;
param->data = new HGByte[dataSize];
param->size = dataSize;
memcpy(param->data, data, dataSize);
HGMsg msg;
msg.id = MSGID_SOCKIO_COMMAND;
msg.data = param;
if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_server->GetMsgPump(), &msg))
{
delete[] param->data;
param->size = 0;
delete param;
}
}
void SockIoUser::PostEventMsg(const HGByte* data, HGUInt dataSize)
{
SockIoEvtParam* param = new SockIoEvtParam;
param->svr = (SockIoServer*)m_server;
param->usrId = m_id;
param->data = new HGByte[dataSize];
param->size = dataSize;
memcpy(param->data, data, dataSize);
HGMsg msg;
msg.id = MSGID_SOCKIO_EVENT;
msg.data = param;
if (HGBASE_ERR_OK != HGBase_PostPumpMessage(m_server->GetMsgPump(), &msg))
{
delete[] param->data;
param->size = 0;
delete param;
}
}
void SockIoUser::ThreadFunc()
{
HGBase_WriteInfo(HGBASE_INFOTYPE_DESC, "SockIoUser::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)
{
// 这里跳出可能是服务器关闭了socketConn或者客户端关闭了socket或者网络断开
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]) // 断开连接
{
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]) // 数据帧
{
if ((0x80 | 0x00) == headData[0] || (0x80 | 0x01) == headData[0] || (0x80 | 0x02) == headData[0])
{
// 分片结束
bHandle = true;
}
else
{
// 分片帧
bHandle = false;
}
}
else // 帧错误,断开连接
{
PostDisConnectMsg();
break;
}
}
else if (2 == nHeadDataLen)
{
if (0 == (headData[1] & 0x80)) // 必须经过掩码处理
{
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) // 这里一定会等于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)
{
if (1 == vAllData.size() && '2' == vAllData[0])
{
// socket.io pong
char data = '3';
SendResponse((const HGByte*)&data, 1, HGTRUE);
}
else
{
PostCmdMsg(&vAllData[0], (HGUInt)vAllData.size());
}
bHandle = false;
vAllData.clear();
}
}
}
}
}
}
if (NULL != pData)
{
delete[] pData;
pData = NULL;
nDataSize = 0;
nMaskCount = 0;
}
}
void SockIoUser::SaneEvent(int code, const char* str, bool err, void* param)
{
SockIoUser* p = (SockIoUser*)param;
char* resp = NULL;
if (SANEEVENT_ARRIVE == code)
{
resp = new char[256];
sprintf(resp, "42[\"success\", \"%s\"]", str);
}
else if (SANEEVENT_REMOVE == code)
{
}
else if (SANEEVENT_WORKING == code)
{
resp = new char[256];
sprintf(resp, "42[\"event\", \"%s\"]", "......");
}
else if (SANEEVENT_FINISH == code)
{
resp = new char[256];
sprintf(resp, "42[\"result\", {\"code\":204, \"msg\":\"%s\"}]", str);
}
else if (SANEEVENT_ERROR == code)
{
resp = new char[256];
sprintf(resp, "42[\"error\", \"%s\"]", str);
}
if (NULL != resp)
{
p->PostEventMsg((const HGByte*)resp, (HGUInt)strlen(resp));
delete[] resp;
}
}
void SockIoUser::SaneImageCallback(const char* name, const char* base64, void* param)
{
SockIoUser* p = (SockIoUser*)param;
char* resp = NULL;
const char* imgName = (const char*)name;
const char* imgBase64 = (const char*)base64;
resp = new char[256 + strlen(imgName) + strlen(imgBase64)];
sprintf(resp, "42[\"image\", {\"code\":201, \"imageName\":\"%s\", \"image\":\"%s\"}]", imgName, imgBase64);
if (NULL != resp)
{
p->PostEventMsg((const HGByte*)resp, (HGUInt)strlen(resp));
delete[] resp;
}
}
void SockIoUser::GetMsgInfo(const SockIoCmdParam* param, std::string& user, std::string& data)
{
user.clear();
data.clear();
std::string paramStr((const char*)param->data, param->size);
size_t pos = paramStr.find('[');
if (std::string::npos == pos)
{
return;
}
std::string msgType = paramStr.substr(0, pos);
if ("42" != msgType)
{
return;
}
std::string msgInfo = paramStr.substr(pos);
cJSON* json = cJSON_Parse(msgInfo.c_str());
if (NULL != json)
{
if (NULL != json->child)
{
user = json->child->valuestring;
if (NULL != json->child->next)
data = json->child->next->valuestring;
}
cJSON_Delete(json);
}
}
bool SockIoUser::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 ("websocket" != HttpHead::GetValue(requestURIQueryInfos, "transport"))
return false;
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);
char uuid[256] = { 0 };
HGBase_GetUuid(uuid, 256);
std::string resp = "0{";
resp += "\"sid\":\"";
resp += uuid;
resp += "\",";
resp += "\"upgrades\":[\"websocket\"],";
resp += "\"pingInterval\":25000,";
resp += "\"pingTimeout\":60000";
resp += "}";
SendResponse((const HGByte*)resp.c_str(), (int)resp.size(), HGTRUE);
resp = "40";
SendResponse((const HGByte*)resp.c_str(), (int)resp.size(), HGTRUE);
return true;
}
void SockIoUser::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 SockIoUser::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;
}
}