#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 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; }