diff options
author | George Hazan <ghazan@miranda.im> | 2022-10-01 15:44:39 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2022-10-01 15:44:39 +0300 |
commit | 4599390ee98712d05550b9a49c4f02e5acebf31e (patch) | |
tree | 49345f93fa27124c27574a8d8e8b274b3ed9900b /protocols/WhatsAppWeb/src | |
parent | 87ff6ba67d4df0b4c0ae3db86220b816ec6a1e75 (diff) |
WhatsApp: keep-alive packets
Diffstat (limited to 'protocols/WhatsAppWeb/src')
-rw-r--r-- | protocols/WhatsAppWeb/src/iq.cpp | 32 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/proto.h | 24 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/server.cpp | 30 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/utils.cpp | 22 |
4 files changed, 74 insertions, 34 deletions
diff --git a/protocols/WhatsAppWeb/src/iq.cpp b/protocols/WhatsAppWeb/src/iq.cpp index 1442e5c02f..287fbe54e5 100644 --- a/protocols/WhatsAppWeb/src/iq.cpp +++ b/protocols/WhatsAppWeb/src/iq.cpp @@ -45,6 +45,28 @@ void WhatsAppProto::OnStreamError(const WANode &node) ///////////////////////////////////////////////////////////////////////////////////////// +void WhatsAppProto::OnSuccess(const WANode &) +{ + OnLoggedIn(); + + WANode iq("iq"); + iq << CHAR_PARAM("to", S_WHATSAPP_NET) << CHAR_PARAM("xmlns", "passive") << CHAR_PARAM("type", "set"); + iq.addChild("active"); + WSSendNode(iq); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void WhatsAppProto::OnIqResult(const WANode &node) +{ + if (auto *pszId = node.getAttr("id")) + for (auto &it: m_arPacketQueue) + if (it->szPacketId == pszId) + (this->*it->pHandler)(node); +} + +///////////////////////////////////////////////////////////////////////////////////////// + void WhatsAppProto::OnIqPairDevice(const WANode &node) { WANode reply("iq"); @@ -301,8 +323,10 @@ LBL_Error: void WhatsAppProto::InitPersistentHandlers() { - m_arPersistent.insert(new WAPersistentHandler("iq", "md", "pair-device", &WhatsAppProto::OnIqPairDevice)); - m_arPersistent.insert(new WAPersistentHandler("iq", "md", "pair-success", &WhatsAppProto::OnIqPairSuccess)); - - m_arPersistent.insert(new WAPersistentHandler("stream:error", nullptr, nullptr, &WhatsAppProto::OnStreamError)); + m_arPersistent.insert(new WAPersistentHandler("iq", "set", "md", "pair-device", &WhatsAppProto::OnIqPairDevice)); + m_arPersistent.insert(new WAPersistentHandler("iq", "set", "md", "pair-success", &WhatsAppProto::OnIqPairSuccess)); + m_arPersistent.insert(new WAPersistentHandler(0, "result", 0, 0, &WhatsAppProto::OnIqResult)); + + m_arPersistent.insert(new WAPersistentHandler("stream:error", 0, 0, 0, &WhatsAppProto::OnStreamError)); + m_arPersistent.insert(new WAPersistentHandler("success", 0, 0, 0, &WhatsAppProto::OnSuccess)); } diff --git a/protocols/WhatsAppWeb/src/proto.h b/protocols/WhatsAppWeb/src/proto.h index b2e0bc6301..80ce03dba7 100644 --- a/protocols/WhatsAppWeb/src/proto.h +++ b/protocols/WhatsAppWeb/src/proto.h @@ -17,24 +17,24 @@ typedef void (WhatsAppProto:: *WA_PKT_HANDLER)(const WANode &node); struct WARequest { - WARequest(WA_PKT_HANDLER _1, void *_2 = nullptr) : - pHandler(_1), - pUserInfo(_2) + WARequest(const CMStringA &_1, WA_PKT_HANDLER _2, void *_3 = nullptr) : + szPacketId(_1), + pHandler(_2), + pUserInfo(_3) {} + CMStringA szPacketId; WA_PKT_HANDLER pHandler; void *pUserInfo; }; struct WAPersistentHandler { - WAPersistentHandler(const char *_1, const char *_2, const char *_3, WA_PKT_HANDLER _4) : - pszType(_1), pszXmlns(_2), pszNode(_3), pHandler(_4) + WAPersistentHandler(const char *_1, const char *_2, const char *_3, const char *_4, WA_PKT_HANDLER _5) : + pszTitle(_1), pszType(_2), pszXmlns(_3), pszChild(_4), pHandler(_5) {} - const char *pszType; - const char *pszXmlns; - const char *pszNode; + const char *pszTitle, *pszType, *pszXmlns, *pszChild; WA_PKT_HANDLER pHandler; }; @@ -172,7 +172,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto> /// Network //////////////////////////////////////////////////////////////////////////// - time_t m_iLoginTime; + time_t m_lastRecvTime; HNETLIBCONN m_hServerConn; mir_cs m_csPacketQueue; @@ -181,6 +181,10 @@ class WhatsAppProto : public PROTO<WhatsAppProto> LIST<WAPersistentHandler> m_arPersistent; WA_PKT_HANDLER FindPersistentHandler(const WANode &node); + int m_iPacketId; + uint16_t m_wMsgPrefix[2]; + CMStringA generateMessageId(); + bool WSReadPacket(const WSHeader &hdr, MBinBuffer &buf); int WSSend(const MessageLite &msg); int WSSendNode(WANode &node, WA_PKT_HANDLER = nullptr); @@ -203,7 +207,9 @@ class WhatsAppProto : public PROTO<WhatsAppProto> void InitPersistentHandlers(); void OnIqPairDevice(const WANode &node); void OnIqPairSuccess(const WANode &node); + void OnIqResult(const WANode &node); void OnStreamError(const WANode &node); + void OnSuccess(const WANode &node); // binary packets void ProcessBinaryPacket(const void *pData, size_t cbLen); diff --git a/protocols/WhatsAppWeb/src/server.cpp b/protocols/WhatsAppWeb/src/server.cpp index 126d73e956..7be1f40713 100644 --- a/protocols/WhatsAppWeb/src/server.cpp +++ b/protocols/WhatsAppWeb/src/server.cpp @@ -45,7 +45,10 @@ void WhatsAppProto::ServerThreadWorker() debugLogA("Server connection succeeded"); m_hServerConn = pReply->nlc; - m_iLoginTime = time(0); + m_lastRecvTime = time(0); + m_iPacketId = 1; + + Utils_GetRandom(m_wMsgPrefix, sizeof(m_wMsgPrefix)); auto &pubKey = m_noise->ephemeral.pub; auto *client = new proto::HandshakeMessage::ClientHello(); client->set_ephemeral(pubKey.data(), pubKey.length()); @@ -81,6 +84,8 @@ void WhatsAppProto::ServerThreadWorker() netbuf.length(), hdr.opCode, hdr.headerSize, hdr.payloadSize, hdr.bIsFinal, hdr.bIsMasked); // Netlib_Dump(m_hServerConn, netbuf.data(), netbuf.length(), false, 0); + m_lastRecvTime = time(0); + // read all payloads from the current buffer, one by one while (true) { MBinBuffer currPacket; @@ -241,12 +246,13 @@ void WhatsAppProto::OnLoggedIn() ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iDesiredStatus); m_iStatus = m_iDesiredStatus; - SendKeepAlive(); - m_impl.m_keepAlive.Start(60000); + m_impl.m_keepAlive.Start(1000); } void WhatsAppProto::OnLoggedOut(void) { + m_impl.m_keepAlive.Stop(); + debugLogA("WhatsAppProto::OnLoggedOut"); m_bTerminated = true; @@ -258,20 +264,14 @@ void WhatsAppProto::OnLoggedOut(void) void WhatsAppProto::SendKeepAlive() { - WebSocket_SendText(m_hServerConn, "?,,"); - time_t now = time(0); + if (now - m_lastRecvTime > 20) { + WANode iq("iq"); + iq << CHAR_PARAM("id", generateMessageId()) << CHAR_PARAM("to", S_WHATSAPP_NET) << CHAR_PARAM("type", "get") << CHAR_PARAM("xmlns", "w:p"); + iq.addChild("ping"); + WSSendNode(iq); - for (auto &it : m_arUsers) { - if (it->m_time1 && now - it->m_time1 >= 1200) { // 20 minutes - setWord(it->hContact, "Status", ID_STATUS_NA); - it->m_time1 = 0; - it->m_time2 = now; - } - else if (it->m_time2 && now - it->m_time2 >= 1200) { // 20 minutes - setWord(it->hContact, "Status", ID_STATUS_OFFLINE); - it->m_time2 = 0; - } + m_lastRecvTime = now; } } diff --git a/protocols/WhatsAppWeb/src/utils.cpp b/protocols/WhatsAppWeb/src/utils.cpp index 7e45d65ea2..885393a354 100644 --- a/protocols/WhatsAppWeb/src/utils.cpp +++ b/protocols/WhatsAppWeb/src/utils.cpp @@ -87,16 +87,19 @@ WAUser* WhatsAppProto::AddUser(const char *szId, bool bTemporary) WA_PKT_HANDLER WhatsAppProto::FindPersistentHandler(const WANode &pNode) { auto *pChild = pNode.getFirstChild(); - CMStringA szTitle = (pChild) ? pChild->title : ""; - CMStringA szType = pNode.title; + CMStringA szChild = (pChild) ? pChild->title : ""; + CMStringA szTitle = pNode.title; + CMStringA szType = pNode.getAttr("type"); CMStringA szXmlns = pNode.getAttr("xmlns"); for (auto &it : m_arPersistent) { + if (it->pszTitle && szTitle != it->pszTitle) + continue; if (it->pszType && szType != it->pszType) continue; if (it->pszXmlns && szXmlns != it->pszXmlns) continue; - if (it->pszNode && szTitle != it->pszNode) + if (it->pszChild && szChild != it->pszChild) continue; return it->pHandler; } @@ -106,6 +109,13 @@ WA_PKT_HANDLER WhatsAppProto::FindPersistentHandler(const WANode &pNode) ///////////////////////////////////////////////////////////////////////////////////////// +CMStringA WhatsAppProto::generateMessageId() +{ + return CMStringA(FORMAT, "%d.%d-%d", m_wMsgPrefix[0], m_wMsgPrefix[1], m_iPacketId++); +} + +///////////////////////////////////////////////////////////////////////////////////////// + MBinBuffer WhatsAppProto::getBlob(const char *szSetting) { MBinBuffer buf; @@ -125,12 +135,12 @@ int WhatsAppProto::WSSend(const MessageLite &msg) if (m_hServerConn == nullptr) return -1; - // debugLogA("Sending packet: %s", msg..DebugString().c_str()); - int cbLen = msg.ByteSize(); ptrA protoBuf((char *)mir_alloc(cbLen)); msg.SerializeToArray(protoBuf, cbLen); + Netlib_Dump(m_hServerConn, protoBuf, cbLen, true, 0); + MBinBuffer payload = m_noise->encodeFrame(protoBuf, cbLen); WebSocket_SendBinary(m_hServerConn, payload.data(), payload.length()); return 0; @@ -154,7 +164,7 @@ int WhatsAppProto::WSSendNode(WANode &node, WA_PKT_HANDLER pHandler) if (pHandler != nullptr) { mir_cslock lck(m_csPacketQueue); - m_arPacketQueue.insert(new WARequest(pHandler)); + m_arPacketQueue.insert(new WARequest(node.getAttr("id"), pHandler)); } MBinBuffer encData = m_noise->encrypt(writer.body.data(), writer.body.length()); |