XEP-0410: implement server-side optimisation for self-pings

This prevents the ping from round-tripping through IRC and
possibly a random other client of the user. Please see XEP-0410
for the rationale.

Fixes #3385.
This commit is contained in:
Jonas Schäfer
2019-08-20 21:42:43 +02:00
parent a8cd241485
commit b68f36056d
5 changed files with 22 additions and 37 deletions
+3
View File
@@ -11,6 +11,9 @@ For users
- All commands sent to IRC servers are now throttled to avoid being - All commands sent to IRC servers are now throttled to avoid being
disconnected for excess flood. The limit value can be customized using the disconnected for excess flood. The limit value can be customized using the
ad-hoc configuration form on a server JID. ad-hoc configuration form on a server JID.
- Support for XEP-0410 Self-Ping Optimization. This will prevent clients
which use self-ping from dropping out of the MUC if another client with
bad connectivity is also joined from the same account.
For admins For admins
---------- ----------
+17
View File
@@ -747,6 +747,23 @@ void Bridge::send_irc_participant_ping_request(const Iid& iid, const std::string
"", true); "", true);
return; return;
} }
if (chan->get_self()->nick == nick)
{
// XEP-0410 self-ping optimisation: always reply without going the full
// round-trip through IRC and possibly another XMPP client. See the XEP
// for details.
Jid iq_from(from_jid);
iq_from.local = std::to_string(iid);
iq_from.resource = nick;
Stanza iq("iq");
iq["from"] = iq_from.full();
iq["to"] = to_jid;
iq["id"] = iq_id;
iq["type"] = "result";
this->xmpp.send_stanza(iq);
return;
}
if (chan->get_self()->nick != nick && !chan->find_user(nick)) if (chan->get_self()->nick != nick && !chan->find_user(nick))
{ {
this->xmpp.send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "item-not-found", this->xmpp.send_stanza_error("iq", to_jid, from_jid, iq_id, "cancel", "item-not-found",
+1 -1
View File
@@ -997,7 +997,7 @@ void BiboumiComponent::send_irc_channel_disco_info(const std::string& id, const
identity["category"] = "conference"; identity["category"] = "conference";
identity["type"] = "irc"; identity["type"] = "irc";
identity["name"] = ""s + iid.get_local() + " on " + iid.get_server(); identity["name"] = ""s + iid.get_local() + " on " + iid.get_server();
for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS, STABLE_MUC_ID_NS}) for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS, STABLE_MUC_ID_NS, SELF_PING_FLAG})
{ {
XmlSubNode feature(query, "feature"); XmlSubNode feature(query, "feature");
feature["var"] = ns; feature["var"] = ns;
+1
View File
@@ -38,6 +38,7 @@
#define MUC_TRAFFIC_NS "http://jabber.org/protocol/muc#traffic" #define MUC_TRAFFIC_NS "http://jabber.org/protocol/muc#traffic"
#define STABLE_ID_NS "urn:xmpp:sid:0" #define STABLE_ID_NS "urn:xmpp:sid:0"
#define STABLE_MUC_ID_NS "http://jabber.org/protocol/muc#stable_id" #define STABLE_MUC_ID_NS "http://jabber.org/protocol/muc#stable_id"
#define SELF_PING_FLAG MUC_NS"#self-ping-optimization"
/** /**
* An XMPP component, communicating with an XMPP server using the protocole * An XMPP component, communicating with an XMPP server using the protocole
-36
View File
@@ -1515,24 +1515,12 @@ if __name__ == '__main__':
# Send a ping to ourself # Send a ping to ourself
partial(send_stanza, partial(send_stanza,
"<iq type='get' from='{jid_one}/{resource_one}' id='first_ping' to='#foo%{irc_server_one}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"), "<iq type='get' from='{jid_one}/{resource_one}' id='first_ping' to='#foo%{irc_server_one}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"),
# We receive our own ping request,
partial(expect_stanza,
"/iq[@from='{lower_nick_one}%{irc_server_one}'][@type='get'][@to='{jid_one}/{resource_one}'][@id='gnip_tsrif']"),
# Respond to the request with an error
partial(send_stanza,
"<iq from='{jid_one}/{resource_one}' id='gnip_tsrif' to='{lower_nick_one}%{irc_server_one}' type='error'><error type='cancel'><feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>"),
partial(expect_stanza, partial(expect_stanza,
"/iq[@from='#foo%{irc_server_one}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_one}'][@id='first_ping']"), "/iq[@from='#foo%{irc_server_one}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_one}'][@id='first_ping']"),
# Send a ping to ourself # Send a ping to ourself
partial(send_stanza, partial(send_stanza,
"<iq type='get' from='{jid_one}/{resource_one}' id='first_ping' to='#foo%{irc_server_one}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"), "<iq type='get' from='{jid_one}/{resource_one}' id='first_ping' to='#foo%{irc_server_one}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"),
# We receive our own ping request,
partial(expect_stanza,
"/iq[@from='{lower_nick_one}%{irc_server_one}'][@type='get'][@to='{jid_one}/{resource_one}'][@id='gnip_tsrif']"),
# Respond to the request with an error
partial(send_stanza,
"<iq from='{jid_one}/{resource_one}' id='gnip_tsrif' to='{lower_nick_one}%{irc_server_one}' type='error'><error type='cancel'><service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>"),
partial(expect_stanza, partial(expect_stanza,
"/iq[@from='#foo%{irc_server_one}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_one}'][@id='first_ping']"), "/iq[@from='#foo%{irc_server_one}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_one}'][@id='first_ping']"),
]), ]),
@@ -1581,12 +1569,6 @@ if __name__ == '__main__':
# Send a ping to ourself # Send a ping to ourself
partial(send_stanza, partial(send_stanza,
"<iq type='get' from='{jid_one}/{resource_one}' id='first_ping' to='#foo%{irc_server_one}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"), "<iq type='get' from='{jid_one}/{resource_one}' id='first_ping' to='#foo%{irc_server_one}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"),
# We receive our own ping request,
partial(expect_stanza,
"/iq[@from='{lower_nick_one}%{irc_server_one}'][@type='get'][@to='{jid_one}/{resource_one}'][@id='gnip_tsrif']"),
# Respond to the request
partial(send_stanza,
"<iq type='result' to='{lower_nick_one}%{irc_server_one}' id='gnip_tsrif' from='{jid_one}/{resource_one}'/>"),
partial(expect_stanza, partial(expect_stanza,
"/iq[@from='#foo%{irc_server_one}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_one}'][@id='first_ping']"), "/iq[@from='#foo%{irc_server_one}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_one}'][@id='first_ping']"),
@@ -1602,23 +1584,11 @@ if __name__ == '__main__':
# And re-send a self ping # And re-send a self ping
partial(send_stanza, partial(send_stanza,
"<iq type='get' from='{jid_one}/{resource_one}' id='second_ping' to='#foo%{irc_server_one}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"), "<iq type='get' from='{jid_one}/{resource_one}' id='second_ping' to='#foo%{irc_server_one}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"),
# We receive our own ping request. Note that we don't know the to value, it could be one of our two resources.
partial(expect_stanza,
"/iq[@from='{lower_nick_one}%{irc_server_one}'][@type='get'][@to][@id='gnip_dnoces']",
after = partial(save_value, "to", partial(extract_attribute, "/iq", "to"))),
# Respond to the request, using the extracted 'to' value as our 'from'
partial(send_stanza,
"<iq type='result' to='{lower_nick_one}%{irc_server_one}' id='gnip_dnoces' from='{to}'/>"),
partial(expect_stanza, partial(expect_stanza,
"/iq[@from='#foo%{irc_server_one}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_one}'][@id='second_ping']"), "/iq[@from='#foo%{irc_server_one}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_one}'][@id='second_ping']"),
## And re-do exactly the same thing, just change the resource initiating the self ping ## And re-do exactly the same thing, just change the resource initiating the self ping
partial(send_stanza, partial(send_stanza,
"<iq type='get' from='{jid_one}/{resource_two}' id='third_ping' to='#foo%{irc_server_one}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"), "<iq type='get' from='{jid_one}/{resource_two}' id='third_ping' to='#foo%{irc_server_one}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"),
partial(expect_stanza,
"/iq[@from='{lower_nick_one}%{irc_server_one}'][@type='get'][@to][@id='gnip_driht']",
after = partial(save_value, "to", partial(extract_attribute, "/iq", "to"))),
partial(send_stanza,
"<iq type='result' to='{lower_nick_one}%{irc_server_one}' id='gnip_driht' from='{to}'/>"),
partial(expect_stanza, partial(expect_stanza,
"/iq[@from='#foo%{irc_server_one}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_two}'][@id='third_ping']"), "/iq[@from='#foo%{irc_server_one}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_two}'][@id='third_ping']"),
@@ -1639,12 +1609,6 @@ if __name__ == '__main__':
# Send a ping to ourself # Send a ping to ourself
partial(send_stanza, partial(send_stanza,
"<iq type='get' from='{jid_one}/{resource_one}' id='first_ping' to='#foo@{biboumi_host}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"), "<iq type='get' from='{jid_one}/{resource_one}' id='first_ping' to='#foo@{biboumi_host}/{nick_one}'><ping xmlns='urn:xmpp:ping' /></iq>"),
# We receive our own ping request,
partial(expect_stanza,
"/iq[@from='{lower_nick_one}@{biboumi_host}'][@type='get'][@to='{jid_one}/{resource_one}'][@id='gnip_tsrif']"),
# Respond to the request
partial(send_stanza,
"<iq type='result' to='{lower_nick_one}@{biboumi_host}' id='gnip_tsrif' from='{jid_one}/{resource_one}'/>"),
partial(expect_stanza, partial(expect_stanza,
"/iq[@from='#foo@{biboumi_host}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_one}'][@id='first_ping']"), "/iq[@from='#foo@{biboumi_host}/{nick_one}'][@type='result'][@to='{jid_one}/{resource_one}'][@id='first_ping']"),
], conf="fixed_server"), ], conf="fixed_server"),