From 5e65ecbf7c7e008ac23adc0f29bc000f7fd27019 Mon Sep 17 00:00:00 2001 From: Gluzskiy Alexandr Date: Wed, 28 Mar 2018 08:21:09 +0300 Subject: protocols: jabber: xep-0198 - moved implementation to separated units (refactoring) - first part (without resumption) should work now (still have some bugs), feel free to test --- protocols/JabberG/src/jabber_iqid.cpp | 6 +- protocols/JabberG/src/jabber_opt.cpp | 2 +- protocols/JabberG/src/jabber_proto.cpp | 13 +-- protocols/JabberG/src/jabber_proto.h | 8 +- protocols/JabberG/src/jabber_strm_mgmt.cpp | 175 +++++++++++++++++++++++++++++ protocols/JabberG/src/jabber_strm_mgmt.h | 55 +++++++++ protocols/JabberG/src/jabber_thread.cpp | 95 ++-------------- 7 files changed, 247 insertions(+), 107 deletions(-) create mode 100755 protocols/JabberG/src/jabber_strm_mgmt.cpp create mode 100755 protocols/JabberG/src/jabber_strm_mgmt.h diff --git a/protocols/JabberG/src/jabber_iqid.cpp b/protocols/JabberG/src/jabber_iqid.cpp index 83febdd7ed..c2d2d1313e 100755 --- a/protocols/JabberG/src/jabber_iqid.cpp +++ b/protocols/JabberG/src/jabber_iqid.cpp @@ -214,11 +214,7 @@ void CJabberProto::OnLoggedIn() setString("LastLoggedServer", m_ThreadInfo->conn.server); m_pepServices.ResetPublishAll(); if (m_bEnableStreamMgmt) - { - if (m_bStrmMgmtPendingEnable && !m_bStrmMgmtEnabled) - EnableStrmMgmt(); - } - + m_StrmMgmt.CheckState(); } void CJabberProto::OnIqResultGetAuth(HXML iqNode, CJabberIqInfo*) diff --git a/protocols/JabberG/src/jabber_opt.cpp b/protocols/JabberG/src/jabber_opt.cpp index 32a44d95f9..c63430d79a 100755 --- a/protocols/JabberG/src/jabber_opt.cpp +++ b/protocols/JabberG/src/jabber_opt.cpp @@ -795,7 +795,7 @@ public: m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Automatically save received notes"), m_proto->m_bAutosaveNotes); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Enable server-side history (XEP-0136)"), m_proto->m_bEnableMsgArchive); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Receive conversations from other devices (XEP-0280)"), m_proto->m_bEnableCarbons); - m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Use Stream Management (XEP-0198) if possible (PLACEHOLDER OPTION)"), m_proto->m_bEnableStreamMgmt); + m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Use Stream Management (XEP-0198) if possible (WIP! no resumption yet)"), m_proto->m_bEnableStreamMgmt); m_otvOptions.AddOption(LPGENW("Server options") L"/" LPGENW("Disable SASL authentication (for old servers)"), m_proto->m_bDisable3920auth); m_otvOptions.AddOption(LPGENW("Server options") L"/" LPGENW("Enable stream compression (if possible)"), m_proto->m_bEnableZlib); diff --git a/protocols/JabberG/src/jabber_proto.cpp b/protocols/JabberG/src/jabber_proto.cpp index 6a125f7ffc..84310548fe 100755 --- a/protocols/JabberG/src/jabber_proto.cpp +++ b/protocols/JabberG/src/jabber_proto.cpp @@ -71,10 +71,7 @@ CJabberProto::CJabberProto(const char *aProtoName, const wchar_t *aUserName) : m_hPrivacyMenuItems(10), m_lstJabberFeatCapPairsDynamic(2), m_uEnabledFeatCapsDynamic(0), - m_bStrmMgmtPendingEnable(false), - m_bStrmMgmtEnabled(false), - m_bStrmMgmtResumeSupported(false), - m_sStrmMgmtResumeId(nullptr), + m_StrmMgmt(this), m_bBsDirect(this, "BsDirect", TRUE), m_bAllowVersionRequests(this, "m_bAllowVersionRequests", TRUE), @@ -258,8 +255,6 @@ CJabberProto::~CJabberProto() delete it; } - if (m_sStrmMgmtResumeId) - mir_free(m_sStrmMgmtResumeId); } //////////////////////////////////////////////////////////////////////////////////////// @@ -1349,9 +1344,3 @@ int __cdecl CJabberProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARA } return 1; } - - -void CJabberProto::m_nStrmMgmtLocalSCount_incr() -{ - m_nStrmMgmtLocalSCount++; -} \ No newline at end of file diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h index 328192a811..729ca52efe 100755 --- a/protocols/JabberG/src/jabber_proto.h +++ b/protocols/JabberG/src/jabber_proto.h @@ -38,6 +38,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "jabber_presence_manager.h" #include "jabber_send_manager.h" #include "jabber_omemo.h" +#include "jabber_strm_mgmt.h" struct CJabberProto; @@ -285,9 +286,7 @@ struct CJabberProto : public PROTO, public IJabberInterface int m_nIqIdRegSetReg; //xep-0198 related vars - uint32_t m_nStrmMgmtSrvHCount, m_nStrmMgmtLocalHCount, m_nStrmMgmtLocalSCount, m_nStrmMgmtResumeMaxSeconds; - bool m_bStrmMgmtPendingEnable, m_bStrmMgmtEnabled, m_bStrmMgmtResumeSupported; - wchar_t *m_sStrmMgmtResumeId; + strm_mgmt m_StrmMgmt; int m_nSDBrowseMode; DWORD m_dwSDLastRefresh; @@ -805,7 +804,6 @@ struct CJabberProto : public PROTO, public IJabberInterface bool ProcessCaptcha(HXML node, HXML parentNode, ThreadData *info); void EnableCarbons(bool bEnable); - void EnableStrmMgmt(); //---- jabber_util.c ----------------------------------------------------------------- pResourceStatus ResourceInfoFromJID(const wchar_t *jid); @@ -931,8 +929,6 @@ public: HNETLIBUSER STDMETHODCALLTYPE GetHandle(); // Returns connection handle - void m_nStrmMgmtLocalSCount_incr(); - private: JabberFeatCapPairDynamic *FindFeature(const wchar_t *szFeature); }; diff --git a/protocols/JabberG/src/jabber_strm_mgmt.cpp b/protocols/JabberG/src/jabber_strm_mgmt.cpp new file mode 100755 index 0000000000..293e4783ad --- /dev/null +++ b/protocols/JabberG/src/jabber_strm_mgmt.cpp @@ -0,0 +1,175 @@ +/* + +Jabber Protocol Plugin for Miranda NG + +Copyright (c) 2018 Miranda NG team + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "stdafx.h" +#include "jabber_strm_mgmt.h" + +strm_mgmt::strm_mgmt(CJabberProto *_proto) : proto(_proto), m_bStrmMgmtPendingEnable(false), +m_bStrmMgmtEnabled(false), +m_bStrmMgmtResumeSupported(false) +{ + +} + +void strm_mgmt::OnProcessEnabled(HXML node, ThreadData * /*info*/) +{ + m_bStrmMgmtEnabled = true; + auto val = XmlGetAttrValue(node, L"max"); + m_nStrmMgmtResumeMaxSeconds = _wtoi(val); + val = XmlGetAttrValue(node, L"resume"); + if (mir_wstrcmp(val, L"true") || mir_wstrcmp(val, L"1")) + m_bStrmMgmtResumeSupported = true; + + m_sStrmMgmtResumeId = XmlGetAttrValue(node, L"id"); + m_nStrmMgmtLocalHCount = 0; + m_nStrmMgmtSrvHCount = 0; +} + +void strm_mgmt::OnProcessSMa(HXML node) +{ + if (!mir_wstrcmp(XmlGetAttrValue(node, L"xmlns"), L"urn:xmpp:sm:3")) + { + auto val = XmlGetAttrValue(node, L"h"); + uint32_t iVal = _wtoi(val); + m_nStrmMgmtSrvHCount = iVal; + int size = m_nStrmMgmtLocalSCount - m_nStrmMgmtSrvHCount; + if (size < 0) + { + //TODO: this should never happen, indicate server side bug + //TODO: once our side implementation good enough abort strem in this case, noop for now + } + else if (size > 0) + { + const size_t diff = NodeCache.size() - size; + if (diff) + { + size_t diff_tmp = diff; + for (auto i : NodeCache) + { + if (diff_tmp > 0) + { + xmlFree(i); + diff_tmp--; + } + } + diff_tmp = diff; + while (diff_tmp) + { + NodeCache.pop_front(); + diff_tmp--; + } + } + for (auto i : NodeCache) + proto->m_ThreadInfo->send(i); + } + NodeCache.clear(); + } +} + +void strm_mgmt::OnProcessSMr(HXML node) +{ + if (!mir_wstrcmp(XmlGetAttrValue(node, L"xmlns"), L"urn:xmpp:sm:3")) + { + XmlNode enable_sm(L"a"); + XmlAddAttr(enable_sm, L"xmlns", L"urn:xmpp:sm:3"); + xmlAddAttrInt(enable_sm, L"h", m_nStrmMgmtLocalHCount); + proto->m_ThreadInfo->send(enable_sm); + } +} + +void strm_mgmt::OnProcessFailed(HXML node, ThreadData * /*info*/) //used failed instead of failure, notes: https://xmpp.org/extensions/xep-0198.html#errors +{ + if (!mir_wstrcmp(XmlGetAttrValue(node, L"xmlns"), L"urn:xmpp:sm:3")) + { + //TODO: handle failure + } +} + +void strm_mgmt::CheckStreamFeatures(HXML node) +{ + if (!mir_wstrcmp(XmlGetName(node), L"sm")) + { + if (!mir_wstrcmp(XmlGetAttrValue(node, L"xmlns"), L"urn:xmpp:sm:3")) //we work only with version 3 or higher of sm + { + if (!(proto->m_bJabberOnline)) + m_bStrmMgmtPendingEnable = true; + else + EnableStrmMgmt(); + } + } +} + +void strm_mgmt::CheckState() +{ + if (m_bStrmMgmtPendingEnable) + EnableStrmMgmt(); + //TODO: resume stream from here ? +} + +void strm_mgmt::HandleOutgoingNode(HXML node) +{ + if (!m_bStrmMgmtEnabled) + return; + auto name = XmlGetName(node); + if (mir_wstrcmp(name, L"a") && mir_wstrcmp(name, L"r")) + { + m_nStrmMgmtLocalSCount++; + if ((m_nStrmMgmtLocalSCount - m_nStrmMgmtSrvHCount) >= m_nStrmMgmtCacheSize) + { + XmlNode enable_sm(L"r"); + XmlAddAttr(enable_sm, L"xmlns", L"urn:xmpp:sm:3"); + proto->m_ThreadInfo->send(enable_sm); + } + } +} + +void strm_mgmt::OnDisconnect() +{ + //TODO: following should be redone once resumption implemented + //reset state of stream management + m_bStrmMgmtEnabled = false; + m_bStrmMgmtPendingEnable = false; + //reset stream management h counters + m_nStrmMgmtLocalHCount = m_nStrmMgmtLocalSCount = m_nStrmMgmtSrvHCount = 0; +} + +void strm_mgmt::HandleIncommingNode(HXML node) +{ + if (m_bStrmMgmtEnabled && mir_wstrcmp(XmlGetName(node), L"r") && mir_wstrcmp(XmlGetName(node), L"a")) //TODO: something better + { + NodeCache.push_back(xmlCopyNode(node)); + m_nStrmMgmtLocalHCount++; + } + else if (!mir_wstrcmp(XmlGetName(node), L"r")) + OnProcessSMr(node); + else if (!mir_wstrcmp(XmlGetName(node), L"a")) + OnProcessSMa(node); +} + +void strm_mgmt::EnableStrmMgmt() +{ + XmlNode enable_sm(L"enable"); + XmlAddAttr(enable_sm, L"xmlns", L"urn:xmpp:sm:3"); + XmlAddAttr(enable_sm, L"resume", L"true"); //enable resumption (most useful part of this xep) + proto->m_ThreadInfo->send(enable_sm); + m_nStrmMgmtLocalSCount = 1; //TODO: this MUST be 0, i have bug somewhere. +} \ No newline at end of file diff --git a/protocols/JabberG/src/jabber_strm_mgmt.h b/protocols/JabberG/src/jabber_strm_mgmt.h new file mode 100755 index 0000000000..178727e2c0 --- /dev/null +++ b/protocols/JabberG/src/jabber_strm_mgmt.h @@ -0,0 +1,55 @@ +/* + +Jabber Protocol Plugin for Miranda NG + +Copyright (c) 2018 Miranda NG team + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef JABBER_STRM_MGMT_H +#define JABBER_STRM_MGMT_H + +#include + +struct CJabberProto; + +class strm_mgmt +{ + void OnProcessSMa(HXML node); + void OnProcessSMr(HXML node); + + + CJabberProto *proto; + uint32_t m_nStrmMgmtSrvHCount, m_nStrmMgmtLocalHCount, m_nStrmMgmtLocalSCount, m_nStrmMgmtResumeMaxSeconds; + const uint32_t m_nStrmMgmtCacheSize = 10; + bool m_bStrmMgmtPendingEnable, m_bStrmMgmtEnabled, m_bStrmMgmtResumeSupported; + std::wstring m_sStrmMgmtResumeId; + std::list NodeCache; + +public: + strm_mgmt(CJabberProto *proto); + void EnableStrmMgmt(); + void HandleOutgoingNode(HXML node); + void HandleIncommingNode(HXML node); + void OnProcessEnabled(HXML node, ThreadData *info); + void OnProcessFailed(HXML node, ThreadData * info); + void CheckStreamFeatures(HXML node); + void CheckState(); + void OnDisconnect(); +}; + +#endif //JABBER_STRM_MGMT_H \ No newline at end of file diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp index e75d3ec81f..aee0373064 100755 --- a/protocols/JabberG/src/jabber_thread.cpp +++ b/protocols/JabberG/src/jabber_thread.cpp @@ -519,12 +519,8 @@ recvRest: m_iDesiredStatus = m_iStatus = ID_STATUS_OFFLINE; ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus); - //TODO: following should be redone once resumption implemented - //reset state of stream management - m_bStrmMgmtEnabled = false; - m_bStrmMgmtPendingEnable = false; - //reset stream management h counters - m_nStrmMgmtLocalHCount = m_nStrmMgmtLocalSCount = m_nStrmMgmtSrvHCount = 0; + + m_StrmMgmt.OnDisconnect(); // Set all contacts to offline debugLogA("1"); @@ -744,15 +740,7 @@ void CJabberProto::OnProcessFeatures(HXML node, ThreadData *info) else if (!mir_wstrcmp(XmlGetName(n), L"auth")) m_AuthMechs.isAuthAvailable = true; else if (!mir_wstrcmp(XmlGetName(n), L"session")) m_AuthMechs.isSessionAvailable = true; else if (m_bEnableStreamMgmt && !mir_wstrcmp(XmlGetName(n), L"sm")) - { - if (!mir_wstrcmp(XmlGetAttrValue(n, L"xmlns"), L"urn:xmpp:sm:3")) //we work only with version 3 or higher of sm - { - if (!m_bJabberOnline) - m_bStrmMgmtPendingEnable = true; - else - EnableStrmMgmt(); - } - } + m_StrmMgmt.CheckStreamFeatures(n); } if (areMechanismsDefined) { @@ -790,58 +778,18 @@ void CJabberProto::OnProcessFailure(HXML node, ThreadData *info) } } -void CJabberProto::OnProcessFailed(HXML node, ThreadData * /*info*/) //used failed instead of failure, notes: https://xmpp.org/extensions/xep-0198.html#errors +void CJabberProto::OnProcessFailed(HXML node, ThreadData *info) //used failed instead of failure, notes: https://xmpp.org/extensions/xep-0198.html#errors { - if (m_bEnableStreamMgmt && !mir_wstrcmp(XmlGetAttrValue(node, L"xmlns"), L"urn:xmpp:sm:3")) - { - //TODO: handle failure - } + m_StrmMgmt.OnProcessFailed(node, info); } -void CJabberProto::OnProcessEnabled(HXML node, ThreadData * /*info*/) -{ - if (m_bEnableStreamMgmt && !mir_wstrcmp(XmlGetAttrValue(node, L"xmlns"), L"urn:xmpp:sm:3")) - { - m_bStrmMgmtEnabled = true; - auto val = XmlGetAttrValue(node, L"max"); - m_nStrmMgmtResumeMaxSeconds = _wtoi(val); - val = XmlGetAttrValue(node, L"resume"); - if (mir_wstrcmp(val, L"true") || mir_wstrcmp(val, L"1")) - m_bStrmMgmtResumeSupported = true; - - if (m_sStrmMgmtResumeId) - mir_free(m_sStrmMgmtResumeId); - m_sStrmMgmtResumeId = mir_wstrdup(XmlGetAttrValue(node, L"id")); - m_nStrmMgmtLocalHCount = 0; - m_nStrmMgmtSrvHCount = 0; //? - m_nStrmMgmtLocalSCount = 0; - } -} -void CJabberProto::OnProcessSMa(HXML node, ThreadData * /*info*/) +void CJabberProto::OnProcessEnabled(HXML node, ThreadData * info) { - if (!mir_wstrcmp(XmlGetAttrValue(node, L"xmlns"), L"urn:xmpp:sm:3")) - { - auto val = XmlGetAttrValue(node, L"h"); - uint32_t iVal = _wtoi(val); - m_nStrmMgmtSrvHCount = iVal; - if ((m_nStrmMgmtLocalSCount - m_nStrmMgmtSrvHCount) > 0) - { - //TODO: server have not handled some of sent nodes, handle situation - } - } + if (m_bEnableStreamMgmt && !mir_wstrcmp(XmlGetAttrValue(node, L"xmlns"), L"urn:xmpp:sm:3")) + m_StrmMgmt.OnProcessEnabled(node, info); } -void CJabberProto::OnProcessSMr(HXML node, ThreadData * /*info*/) -{ - if (!mir_wstrcmp(XmlGetAttrValue(node, L"xmlns"), L"urn:xmpp:sm:3")) - { - XmlNode enable_sm(L"a"); - XmlAddAttr(enable_sm, L"xmlns", L"urn:xmpp:sm:3"); - xmlAddAttrInt(enable_sm, L"h", m_nStrmMgmtLocalHCount); - m_ThreadInfo->send(enable_sm); - } -} void CJabberProto::OnProcessError(HXML node, ThreadData *info) { @@ -919,8 +867,8 @@ void CJabberProto::OnProcessProtocol(HXML node, ThreadData *info) { OnConsoleProcessXml(node, JCPF_IN); - if (m_bEnableStreamMgmt && m_bStrmMgmtEnabled && mir_wstrcmp(XmlGetName(node), L"r") && mir_wstrcmp(XmlGetName(node), L"a")) //TODO: something better - m_nStrmMgmtLocalHCount++; + if (m_bEnableStreamMgmt) + m_StrmMgmt.HandleIncommingNode(node); if (!mir_wstrcmp(XmlGetName(node), L"proceed")) OnProcessProceed(node, info); else if (!mir_wstrcmp(XmlGetName(node), L"compressed")) @@ -948,13 +896,6 @@ void CJabberProto::OnProcessProtocol(HXML node, ThreadData *info) OnProcessFailed(node, info); else if (!mir_wstrcmp(XmlGetName(node), L"enabled")) OnProcessEnabled(node, info); - else if (m_bEnableStreamMgmt) - { - if (!mir_wstrcmp(XmlGetName(node), L"r")) - OnProcessSMr(node, info); - else if (!mir_wstrcmp(XmlGetName(node), L"a")) - OnProcessSMa(node, info); - } else debugLogA("Invalid top-level tag (only and allowed)"); } @@ -2076,14 +2017,6 @@ void CJabberProto::EnableCarbons(bool bEnable) << XCHILDNS((bEnable) ? L"enable" : L"disable", JABBER_FEAT_CARBONS)); } -void CJabberProto::EnableStrmMgmt() -{ - XmlNode enable_sm(L"enable"); - XmlAddAttr(enable_sm, L"xmlns", L"urn:xmpp:sm:3"); - XmlAddAttr(enable_sm, L"resume", L"true"); //enable resumption (most useful part of this xep) - m_ThreadInfo->send(enable_sm); -} - ///////////////////////////////////////////////////////////////////////////////////////// // ThreadData constructor & destructor @@ -2204,11 +2137,7 @@ int ThreadData::send(HXML node) int result = send(utfStr, (int)mir_strlen(utfStr)); xmlFree(str); - if (proto->m_bEnableStreamMgmt && proto->m_bStrmMgmtEnabled) - { - auto name = XmlGetName(node); - if(mir_wstrcmp(name, L"a") && mir_wstrcmp(name, L"r")) - proto->m_nStrmMgmtLocalSCount_incr(); - } + if (proto->m_bEnableStreamMgmt) + proto->m_StrmMgmt.HandleOutgoingNode(node); //TODO: is this a correct place ? return result; } -- cgit v1.2.3