diff --git a/conf/mod_carbons.lua b/conf/mod_carbons.lua index 6d70826..1cb8ae2 100644 --- a/conf/mod_carbons.lua +++ b/conf/mod_carbons.lua @@ -1,5 +1,5 @@ --- XEP-0280: Message Carbons implementation for Prosody --- Copyright (C) 2011 Kim Alvefur +-- XEP-0280: Message Carbons implementation for metronome +-- Copyright (C) 2011-2016 Kim Alvefur -- -- This file is MIT/X11 licensed. @@ -9,14 +9,15 @@ local xmlns_carbons = "urn:xmpp:carbons:2"; local xmlns_carbons_old = "urn:xmpp:carbons:1"; local xmlns_carbons_really_old = "urn:xmpp:carbons:0"; local xmlns_forward = "urn:xmpp:forward:0"; -local full_sessions, bare_sessions = full_sessions, bare_sessions; +local full_sessions, bare_sessions = metronome.full_sessions, metronome.bare_sessions; local function toggle_carbons(event) local origin, stanza = event.origin, event.stanza; local state = stanza.tags[1].attr.mode or stanza.tags[1].name; module:log("debug", "%s %sd carbons", origin.full_jid, state); origin.want_carbons = state == "enable" and stanza.tags[1].attr.xmlns; - return origin.send(st.reply(stanza)); + origin.send(st.reply(stanza)); + return true; end module:hook("iq-set/self/"..xmlns_carbons..":disable", toggle_carbons); module:hook("iq-set/self/"..xmlns_carbons..":enable", toggle_carbons); @@ -28,14 +29,12 @@ module:hook("iq-set/self/"..xmlns_carbons_really_old..":carbons", toggle_carbons local function message_handler(event, c2s) local origin, stanza = event.origin, event.stanza; - local orig_type = stanza.attr.type; + local orig_type = stanza.attr.type or "normal"; local orig_from = stanza.attr.from; local orig_to = stanza.attr.to; - if not (orig_type == nil - or orig_type == "normal" - or orig_type == "chat") then - return -- No carbons for messages of type error or headline + if not(orig_type == "chat" or (orig_type == "normal" and stanza:get_child("body"))) then + return -- Only chat type messages end -- Stanza sent by a local client @@ -75,7 +74,7 @@ local function message_handler(event, c2s) elseif stanza:get_child("no-copy", "urn:xmpp:hints") then module:log("debug", "Message has no-copy hint, ignoring"); return - elseif stanza:get_child("x", "http://jabber.org/protocol/muc#user") then + elseif not c2s and bare_jid == orig_from and stanza:get_child("x", "http://jabber.org/protocol/muc#user") then module:log("debug", "MUC PM, ignoring"); return end @@ -123,12 +122,12 @@ local function c2s_message_handler(event) end -- Stanzas sent by local clients -module:hook("pre-message/host", c2s_message_handler, 1); -module:hook("pre-message/bare", c2s_message_handler, 1); -module:hook("pre-message/full", c2s_message_handler, 1); +module:hook("pre-message/host", c2s_message_handler, 0.05); -- priority between mod_message (0 in 0.9) and mod_firewall (0.1) +module:hook("pre-message/bare", c2s_message_handler, 0.05); +module:hook("pre-message/full", c2s_message_handler, 0.05); -- Stanzas to local clients -module:hook("message/bare", message_handler, 1); -module:hook("message/full", message_handler, 1); +module:hook("message/bare", message_handler, 0.05); +module:hook("message/full", message_handler, 0.05); module:add_feature(xmlns_carbons); module:add_feature(xmlns_carbons_old); diff --git a/conf/mod_smacks.lua b/conf/mod_smacks.lua index 1ef6a50..48c5cc8 100644 --- a/conf/mod_smacks.lua +++ b/conf/mod_smacks.lua @@ -5,7 +5,7 @@ -- Copyright (C) 2012-2015 Kim Alvefur -- Copyright (C) 2012 Thijs Alkemade -- Copyright (C) 2014 Florian Zeitz --- Copyright (C) 2016-2017 Thilo Molitor +-- Copyright (C) 2016-2019 Thilo Molitor -- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. @@ -116,7 +116,7 @@ local function stoppable_timer(delay, callback) end local function delayed_ack_function(session) - -- fire event only if configured to do so and our session is not hibernated or destroyed + -- fire event only if configured to do so and our session is not already hibernated or destroyed if delayed_ack_timeout > 0 and session.awaiting_ack and not session.hibernating and not session.destroyed then session.log("debug", "Firing event 'smacks-ack-delayed', queue = %d", @@ -159,16 +159,26 @@ module:hook("s2s-stream-features", local function request_ack_if_needed(session, force, reason) local queue = session.outgoing_stanza_queue; + local expected_h = session.last_acknowledged_stanza + #queue; + -- session.log("debug", "*** SMACKS(1) ***: awaiting_ack=%s, hibernating=%s", tostring(session.awaiting_ack), tostring(session.hibernating)); if session.awaiting_ack == nil and not session.hibernating then - if (#queue > max_unacked_stanzas and session.last_queue_count ~= #queue) or force then + -- this check of last_requested_h prevents ack-loops if missbehaving clients report wrong + -- stanza counts. it is set when an is really sent (e.g. inside timer), preventing any + -- further requests until a higher h-value would be expected. + -- session.log("debug", "*** SMACKS(2) ***: #queue=%s, max_unacked_stanzas=%s, expected_h=%s, last_requested_h=%s", tostring(#queue), tostring(max_unacked_stanzas), tostring(expected_h), tostring(session.last_requested_h)); + if (#queue > max_unacked_stanzas and expected_h ~= session.last_requested_h) or force then session.log("debug", "Queuing (in a moment) from %s - #queue=%d", reason, #queue); session.awaiting_ack = false; session.awaiting_ack_timer = stoppable_timer(1e-06, function () - if not session.awaiting_ack and not session.hibernating then - session.log("debug", "Sending (inside timer, before send)"); + -- session.log("debug", "*** SMACKS(3) ***: awaiting_ack=%s, hibernating=%s", tostring(session.awaiting_ack), tostring(session.hibernating)); + -- only request ack if needed and our session is not already hibernated or destroyed + if not session.awaiting_ack and not session.hibernating and not session.destroyed then + session.log("debug", "Sending (inside timer, before send) from %s - #queue=%d", reason, #queue); (session.sends2s or session.send)(st.stanza("r", { xmlns = session.smacks })) - session.log("debug", "Sending (inside timer, after send)"); session.awaiting_ack = true; + -- expected_h could be lower than this expression e.g. more stanzas added to the queue meanwhile) + session.last_requested_h = session.last_acknowledged_stanza + #queue; + session.log("debug", "Sending (inside timer, after send) from %s - #queue=%d", reason, #queue); if not session.delayed_ack_timer then session.delayed_ack_timer = stoppable_timer(delayed_ack_timeout, function() delayed_ack_function(session); @@ -187,8 +197,6 @@ local function request_ack_if_needed(session, force, reason) session.log("debug", "Calling delayed_ack_function directly (still waiting for ack)"); delayed_ack_function(session); end - - session.last_queue_count = #queue; end local function outgoing_stanza_filter(stanza, session) @@ -329,8 +337,9 @@ function handle_r(origin, stanza, xmlns_sm) module:log("debug", "Received ack request, acking for %d", origin.handled_stanza_count); -- Reply with (origin.sends2s or origin.send)(st.stanza("a", { xmlns = xmlns_sm, h = string.format("%d", origin.handled_stanza_count) })); - -- piggyback our own ack request - if #origin.outgoing_stanza_queue > 0 and origin.last_queue_count ~= #origin.outgoing_stanza_queue then + -- piggyback our own ack request if needed (see request_ack_if_needed() for explanation of last_requested_h) + local expected_h = origin.last_acknowledged_stanza + #origin.outgoing_stanza_queue; + if #origin.outgoing_stanza_queue > 0 and expected_h ~= origin.last_requested_h then request_ack_if_needed(origin, true, "piggybacked by handle_r"); end return true; @@ -587,7 +596,6 @@ local function handle_read_timeout(event) return false; -- Kick the session end session.log("debug", "Sending (read timeout)"); - session.awaiting_ack = false; (session.sends2s or session.send)(st.stanza("r", { xmlns = session.smacks })); session.awaiting_ack = true; if not session.delayed_ack_timer then