code_app/sdk/webservice/SockIoUser.cpp

650 lines
14 KiB
C++
Raw 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 "WebServer.h"
#include "MsgLoop.h"
#include "Manager.h"
#include "../../base/HGInfo.h"
#include "../../base/HGUtility.h"
#include "sha1.h"
#include "base64.h"
#include "cJSON.h"
#if defined(HG_CMP_MSC)
SockIoUser::SockIoUser(class WebServer* server, HGUInt id, const char* ip, uint16_t port, SOCKET sockConn)
#else
SockIoUser::SockIoUser(class WebServer* server, HGUInt id, const char* ip, uint16_t port, int sockConn)
#endif
: WebUser(server, id, ip, port, sockConn)
{
GetManager()->SetScanEvent(ScanCallback, this);
}
SockIoUser::~SockIoUser()
{
GetManager()->ResetScanEvent();
}
void SockIoUser::HandleCmd(const SockIoCmdParam* param)
{
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::HandleRet(const SockIoRetParam* param)
{
SendResponse(param->data, param->size, HGTRUE);
}
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或者网络断开
WebMsg msg;
msg.msgId = WEB_MSGID_DISCONNET;
msg.svrId = m_server->GetId();
msg.usrId = m_id;
msg.param = NULL;
GetLoop()->Send(&msg);
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)
{
WebMsg msg;
msg.msgId = WEB_MSGID_DISCONNET;
msg.svrId = m_server->GetId();
msg.usrId = m_id;
msg.param = NULL;
GetLoop()->Send(&msg);
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]) // 断开连接
{
WebMsg msg;
msg.msgId = WEB_MSGID_DISCONNET;
msg.svrId = m_server->GetId();
msg.usrId = m_id;
msg.param = NULL;
GetLoop()->Send(&msg);
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 // 帧错误,断开连接
{
WebMsg msg;
msg.msgId = WEB_MSGID_DISCONNET;
msg.svrId = m_server->GetId();
msg.usrId = m_id;
msg.param = NULL;
GetLoop()->Send(&msg);
break;
}
}
else if (2 == nHeadDataLen)
{
if (0 == (headData[1] & 0x80)) // 必须经过掩码处理
{
WebMsg msg;
msg.msgId = WEB_MSGID_DISCONNET;
msg.svrId = m_server->GetId();
msg.usrId = m_id;
msg.param = NULL;
GetLoop()->Send(&msg);
break;
}
if ((0x80 | 0x09) == headData[0]) // PING帧
{
if (0x80 != headData[1])
{
WebMsg msg;
msg.msgId = WEB_MSGID_DISCONNET;
msg.svrId = m_server->GetId();
msg.usrId = m_id;
msg.param = NULL;
GetLoop()->Send(&msg);
break;
}
}
else if ((0x80 | 0x0A) == headData[0]) // PONG帧
{
if (0x80 != headData[1])
{
WebMsg msg;
msg.msgId = WEB_MSGID_DISCONNET;
msg.svrId = m_server->GetId();
msg.usrId = m_id;
msg.param = NULL;
GetLoop()->Send(&msg);
break;
}
}
else
{
if ((headData[1] & 0x7F) <= 125)
{
uint32_t nCmdSize = (headData[1] & 0x7F);
nHeadDataLen = 0;
if (0 == nCmdSize)
{
WebMsg msg;
msg.msgId = WEB_MSGID_DISCONNET;
msg.svrId = m_server->GetId();
msg.usrId = m_id;
msg.param = NULL;
GetLoop()->Send(&msg);
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)
{
WebMsg msg;
msg.msgId = WEB_MSGID_DISCONNET;
msg.svrId = m_server->GetId();
msg.usrId = m_id;
msg.param = NULL;
GetLoop()->Send(&msg);
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))
{
WebMsg msg;
msg.msgId = WEB_MSGID_DISCONNET;
msg.svrId = m_server->GetId();
msg.usrId = m_id;
msg.param = NULL;
GetLoop()->Send(&msg);
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
{
SockIoCmdParam* param = new SockIoCmdParam;
param->data = new HGByte[vAllData.size()];
param->size = (HGUInt)vAllData.size();
memcpy(param->data, &vAllData[0], vAllData.size());
WebMsg msg;
msg.msgId = WEB_MSGID_SOCKIOCMD;
msg.svrId = m_server->GetId();
msg.usrId = m_id;
msg.param = param;
bool b = GetLoop()->Send(&msg);
if (!b)
{
delete[] param->data;
param->size = 0;
delete param;
}
}
bHandle = false;
vAllData.clear();
}
}
}
}
}
}
if (NULL != pData)
{
delete[] pData;
pData = NULL;
nDataSize = 0;
nMaskCount = 0;
}
}
void SockIoUser::ScanCallback(HGUInt event, void* value1, void* value2, void* param)
{
SockIoUser* p = (SockIoUser*)param;
char *resp = NULL;
if (SCANEVENT_ARRIVE == event)
{
resp = new char[256];
sprintf(resp, "42[\"success\", \"%s\"]", (const char*)value1);
}
else if (SCANEVENT_REMOVE == event)
{
}
else if (SCANEVENT_WORKING == event)
{
resp = new char[256];
sprintf(resp, "42[\"event\", \"%s\"]", "......");
}
else if (SCANEVENT_FINISH == event)
{
resp = new char[256];
sprintf(resp, "42[\"result\", {\"code\":204, \"msg\":\"%s\"}]", (const char *)value1);
}
else if (SCANEVENT_ERROR == event)
{
resp = new char[256];
sprintf(resp, "42[\"error\", \"%s\"]", (const char*)value1);
}
else if (SCANEVENT_IMAGE == event)
{
const char* imgName = (const char*)value1;
const char* imgBase64 = (const char*)value2;
resp = new char[256 + strlen(imgName) + strlen(imgBase64)];
sprintf(resp, "42[\"image\", {\"code\":201, \"imageName\":\"%s\", \"image\":\"%s\"}]", imgName, imgBase64);
}
if (NULL != resp)
{
SockIoRetParam* param = new SockIoRetParam;
param->data = new HGByte[strlen(resp)];
param->size = (HGUInt)strlen(resp);
memcpy(param->data, resp, strlen(resp));
WebMsg msg;
msg.msgId = WEB_MSGID_SOCKIORET;
msg.svrId = p->m_server->GetId();
msg.usrId = p->m_id;
msg.param = param;
bool b = p->GetLoop()->Send(&msg);
if (!b)
{
delete[] param->data;
param->size = 0;
delete param;
}
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;
}