summaryrefslogtreecommitdiff
path: root/protocols/WhatsAppWeb/src
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2022-10-01 15:44:39 +0300
committerGeorge Hazan <ghazan@miranda.im>2022-10-01 15:44:39 +0300
commit4599390ee98712d05550b9a49c4f02e5acebf31e (patch)
tree49345f93fa27124c27574a8d8e8b274b3ed9900b /protocols/WhatsAppWeb/src
parent87ff6ba67d4df0b4c0ae3db86220b816ec6a1e75 (diff)
WhatsApp: keep-alive packets
Diffstat (limited to 'protocols/WhatsAppWeb/src')
-rw-r--r--protocols/WhatsAppWeb/src/iq.cpp32
-rw-r--r--protocols/WhatsAppWeb/src/proto.h24
-rw-r--r--protocols/WhatsAppWeb/src/server.cpp30
-rw-r--r--protocols/WhatsAppWeb/src/utils.cpp22
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());