aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/mod_smacks.lua
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/mod_smacks.lua')
-rw-r--r--plugins/mod_smacks.lua86
1 files changed, 46 insertions, 40 deletions
diff --git a/plugins/mod_smacks.lua b/plugins/mod_smacks.lua
index 3a4c7b84..e2bbff9c 100644
--- a/plugins/mod_smacks.lua
+++ b/plugins/mod_smacks.lua
@@ -2,7 +2,7 @@
--
-- Copyright (C) 2010-2015 Matthew Wild
-- Copyright (C) 2010 Waqas Hussain
--- Copyright (C) 2012-2021 Kim Alvefur
+-- Copyright (C) 2012-2022 Kim Alvefur
-- Copyright (C) 2012 Thijs Alkemade
-- Copyright (C) 2014 Florian Zeitz
-- Copyright (C) 2016-2020 Thilo Molitor
@@ -10,6 +10,7 @@
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
+-- TODO unify sendq and smqueue
local tonumber = tonumber;
local tostring = tostring;
@@ -83,6 +84,22 @@ local all_old_sessions = module:open_store("smacks_h");
local old_session_registry = module:open_store("smacks_h", "map");
local session_registry = module:shared "/*/smacks/resumption-tokens"; -- > user@host/resumption-token --> resource
+local function track_session(session, id)
+ session_registry[jid.join(session.username, session.host, id or session.resumption_token)] = session;
+ session.resumption_token = id;
+end
+
+local function save_old_session(session)
+ session_registry[jid.join(session.username, session.host, session.resumption_token)] = nil;
+ return old_session_registry:set(session.username, session.resumption_token,
+ { h = session.handled_stanza_count; t = os.time() })
+end
+
+local function clear_old_session(session, id)
+ session_registry[jid.join(session.username, session.host, id or session.resumption_token)] = nil;
+ return old_session_registry:set(session.username, id or session.resumption_token, nil)
+end
+
local ack_errors = require"util.error".init("mod_smacks", xmlns_sm3, {
head = { condition = "undefined-condition"; text = "Client acknowledged more stanzas than sent by server" };
tail = { condition = "undefined-condition"; text = "Client acknowledged less stanzas than already acknowledged" };
@@ -155,13 +172,12 @@ end
local function request_ack(session, reason)
local queue = session.outgoing_stanza_queue;
- session.log("debug", "Sending <r> (inside timer, before send) from %s - #queue=%d", reason, queue:count_unacked());
+ session.log("debug", "Sending <r> from %s - #queue=%d", reason, queue:count_unacked());
session.awaiting_ack = true;
(session.sends2s or session.send)(st.stanza("r", { xmlns = session.smacks }))
if session.destroyed then return end -- sending something can trigger destruction
-- expected_h could be lower than this expression e.g. more stanzas added to the queue meanwhile)
session.last_requested_h = queue:count_acked() + queue:count_unacked();
- session.log("debug", "Sending <r> (inside timer, after send) from %s - #queue=%d", reason, queue:count_unacked());
if not session.delayed_ack_timer then
session.delayed_ack_timer = timer.add_task(delayed_ack_timeout, function()
ack_delayed(session, nil); -- we don't know if this is the only new stanza in the queue
@@ -234,8 +250,7 @@ module:hook("pre-session-close", function(event)
if session.smacks == nil then return end
if session.resumption_token then
session.log("debug", "Revoking resumption token");
- session_registry[jid.join(session.username, session.host, session.resumption_token)] = nil;
- old_session_registry:set(session.username, session.resumption_token, nil);
+ clear_old_session(session);
session.resumption_token = nil;
else
session.log("debug", "Session not resumable");
@@ -284,7 +299,7 @@ function handle_enable(session, stanza, xmlns_sm)
if session.username then
local old_sessions, err = all_old_sessions:get(session.username);
- module:log("debug", "Old sessions: %q", old_sessions)
+ session.log("debug", "Old sessions: %q", old_sessions)
if old_sessions then
local keep, count = {}, 0;
for token, info in it.sorted_pairs(old_sessions, function(a, b)
@@ -296,11 +311,11 @@ function handle_enable(session, stanza, xmlns_sm)
end
all_old_sessions:set(session.username, keep);
elseif err then
- module:log("error", "Unable to retrieve old resumption counters: %s", err);
+ session.log("error", "Unable to retrieve old resumption counters: %s", err);
end
end
- module:log("debug", "Enabling stream management");
+ session.log("debug", "Enabling stream management");
session.smacks = xmlns_sm;
wrap_session(session, false);
@@ -310,8 +325,7 @@ function handle_enable(session, stanza, xmlns_sm)
local resume = stanza.attr.resume;
if resume == "true" or resume == "1" then
resume_token = new_id();
- session_registry[jid.join(session.username, session.host, resume_token)] = session;
- session.resumption_token = resume_token;
+ track_session(session, resume_token);
resume_max = tostring(resume_timeout);
end
(session.sends2s or session.send)(st.stanza("enabled", { xmlns = xmlns_sm, id = resume_token, resume = resume, max = resume_max }));
@@ -320,29 +334,23 @@ end
module:hook_tag(xmlns_sm2, "enable", function (session, stanza) return handle_enable(session, stanza, xmlns_sm2); end, 100);
module:hook_tag(xmlns_sm3, "enable", function (session, stanza) return handle_enable(session, stanza, xmlns_sm3); end, 100);
-module:hook_tag("http://etherx.jabber.org/streams", "features",
- function (session, stanza)
- -- Needs to be done after flushing sendq since those aren't stored as
- -- stanzas and counting them is weird.
- -- TODO unify sendq and smqueue
- timer.add_task(1e-6, function ()
- if can_do_smacks(session) then
- if stanza:get_child("sm", xmlns_sm3) then
- session.sends2s(st.stanza("enable", sm3_attr));
- session.smacks = xmlns_sm3;
- elseif stanza:get_child("sm", xmlns_sm2) then
- session.sends2s(st.stanza("enable", sm2_attr));
- session.smacks = xmlns_sm2;
- else
- return;
- end
- wrap_session_out(session, false);
- end
- end);
- end);
+module:hook_tag("http://etherx.jabber.org/streams", "features", function(session, stanza)
+ if can_do_smacks(session) then
+ session.smacks_feature = stanza:get_child("sm", xmlns_sm3) or stanza:get_child("sm", xmlns_sm2);
+ end
+end);
+
+module:hook("s2sout-established", function (event)
+ local session = event.session;
+ if not session.smacks_feature then return end
+
+ session.smacks = session.smacks_feature.attr.xmlns;
+ wrap_session_out(session, false);
+ session.sends2s(st.stanza("enable", { xmlns = session.smacks }));
+end);
function handle_enabled(session, stanza, xmlns_sm) -- luacheck: ignore 212/stanza
- module:log("debug", "Enabling stream management");
+ session.log("debug", "Enabling stream management");
session.smacks = xmlns_sm;
wrap_session_in(session, false);
@@ -356,10 +364,10 @@ module:hook_tag(xmlns_sm3, "enabled", function (session, stanza) return handle_e
function handle_r(origin, stanza, xmlns_sm) -- luacheck: ignore 212/stanza
if not origin.smacks then
- module:log("debug", "Received ack request from non-smack-enabled session");
+ origin.log("debug", "Received ack request from non-smack-enabled session");
return;
end
- module:log("debug", "Received ack request, acking for %d", origin.handled_stanza_count);
+ origin.log("debug", "Received ack request, acking for %d", origin.handled_stanza_count);
-- Reply with <a>
(origin.sends2s or origin.send)(st.stanza("a", { xmlns = xmlns_sm, h = format_h(origin.handled_stanza_count) }));
-- piggyback our own ack request if needed (see request_ack_if_needed() for explanation of last_requested_h)
@@ -412,13 +420,14 @@ local function handle_unacked_stanzas(session)
local queue = session.outgoing_stanza_queue;
local unacked = queue:count_unacked()
if unacked > 0 then
+ local error_from = jid.join(session.username, session.host or module.host);
tx_dropped_stanzas:sample(unacked);
session.smacks = false; -- Disable queueing
session.outgoing_stanza_queue = nil;
for stanza in queue._queue:consume() do
if not module:fire_event("delivery/failure", { session = session, stanza = stanza }) then
if stanza.attr.type ~= "error" and stanza.attr.from ~= session.full_jid then
- local reply = st.error_reply(stanza, "cancel", "recipient-unavailable");
+ local reply = st.error_reply(stanza, "cancel", "recipient-unavailable", nil, error_from);
module:send(reply);
end
end
@@ -485,9 +494,7 @@ module:hook("pre-resource-unbind", function (event)
end
session.log("debug", "Destroying session for hibernating too long");
- session_registry[jid.join(session.username, session.host, session.resumption_token)] = nil;
- old_session_registry:set(session.username, session.resumption_token,
- { h = session.handled_stanza_count; t = os.time() });
+ save_old_session(session);
session.resumption_token = nil;
session.resending_unacked = true; -- stop outgoing_stanza_filter from re-queueing anything anymore
sessionmanager.destroy_session(session, "Hibernating too long");
@@ -544,7 +551,7 @@ function handle_resume(session, stanza, xmlns_sm)
session.send(st.stanza("failed", { xmlns = xmlns_sm, h = format_h(old_session.h) })
:tag("item-not-found", { xmlns = xmlns_errors })
);
- old_session_registry:set(session.username, id, nil);
+ clear_old_session(session, id);
resumption_expired(1);
else
session.log("debug", "Tried to resume non-existent session with id %s", id);
@@ -701,8 +708,7 @@ module:hook_global("server-stopping", function(event)
for _, user in pairs(local_sessions) do
for _, session in pairs(user.sessions) do
if session.resumption_token then
- if old_session_registry:set(session.username, session.resumption_token,
- { h = session.handled_stanza_count; t = os.time() }) then
+ if save_old_session(session) then
session.resumption_token = nil;
-- Deal with unacked stanzas