Mercurial > prosody-modules
comparison mod_smacks/mod_smacks.lua @ 3640:b2f32b3c6ec1
mod_smacks: fix bug in bad client handling introduced by last commit
Use absolute h-values instead of queue-count to determine if a new
request should be sent out or if we are looping instead.
| author | tmolitor <thilo@eightysoft.de> |
|---|---|
| date | Fri, 02 Aug 2019 18:26:06 +0200 |
| parents | 915e32d5a147 |
| children | 58047d6f2b89 |
comparison
equal
deleted
inserted
replaced
| 3639:562d3b219876 | 3640:b2f32b3c6ec1 |
|---|---|
| 157 end | 157 end |
| 158 end); | 158 end); |
| 159 | 159 |
| 160 local function request_ack_if_needed(session, force, reason) | 160 local function request_ack_if_needed(session, force, reason) |
| 161 local queue = session.outgoing_stanza_queue; | 161 local queue = session.outgoing_stanza_queue; |
| 162 local expected_h = session.last_acknowledged_stanza + #queue; | |
| 163 -- session.log("debug", "*** SMACKS(1) ***: awaiting_ack=%s, hibernating=%s", tostring(session.awaiting_ack), tostring(session.hibernating)); | |
| 162 if session.awaiting_ack == nil and not session.hibernating then | 164 if session.awaiting_ack == nil and not session.hibernating then |
| 163 -- this check of last_queue_count prevents ack-loops if missbehaving clients report wrong | 165 -- this check of last_requested_h prevents ack-loops if missbehaving clients report wrong |
| 164 -- stanza counts. it is set when an <r> is really sent (e.g. inside timer), preventing any | 166 -- stanza counts. it is set when an <r> is really sent (e.g. inside timer), preventing any |
| 165 -- further requests until the queue count changes (either by incoming acks or by adding | 167 -- further requests until a higher h-value would be expected. |
| 166 -- more stanzas) | 168 -- 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)); |
| 167 if (#queue > max_unacked_stanzas and session.last_queue_count ~= #queue) or force then | 169 if (#queue > max_unacked_stanzas and expected_h ~= session.last_requested_h) or force then |
| 168 session.log("debug", "Queuing <r> (in a moment) from %s - #queue=%d", reason, #queue); | 170 session.log("debug", "Queuing <r> (in a moment) from %s - #queue=%d", reason, #queue); |
| 169 session.awaiting_ack = false; | 171 session.awaiting_ack = false; |
| 170 session.awaiting_ack_timer = stoppable_timer(1e-06, function () | 172 session.awaiting_ack_timer = stoppable_timer(1e-06, function () |
| 173 -- session.log("debug", "*** SMACKS(3) ***: awaiting_ack=%s, hibernating=%s", tostring(session.awaiting_ack), tostring(session.hibernating)); | |
| 171 if not session.awaiting_ack and not session.hibernating then | 174 if not session.awaiting_ack and not session.hibernating then |
| 172 session.log("debug", "Sending <r> (inside timer, before send)"); | 175 session.log("debug", "Sending <r> (inside timer, before send) from %s - #queue=%d", reason, #queue); |
| 173 (session.sends2s or session.send)(st.stanza("r", { xmlns = session.smacks })) | 176 (session.sends2s or session.send)(st.stanza("r", { xmlns = session.smacks })) |
| 174 session.awaiting_ack = true; | 177 session.awaiting_ack = true; |
| 175 session.last_queue_count = #queue; | 178 -- expected_h could be lower than this expression e.g. more stanzas added to the queue meanwhile) |
| 176 session.log("debug", "Sending <r> (inside timer, after send)"); | 179 session.last_requested_h = session.last_acknowledged_stanza + #queue; |
| 180 session.log("debug", "Sending <r> (inside timer, after send) from %s - #queue=%d", reason, #queue); | |
| 177 if not session.delayed_ack_timer then | 181 if not session.delayed_ack_timer then |
| 178 session.delayed_ack_timer = stoppable_timer(delayed_ack_timeout, function() | 182 session.delayed_ack_timer = stoppable_timer(delayed_ack_timeout, function() |
| 179 delayed_ack_function(session); | 183 delayed_ack_function(session); |
| 180 end); | 184 end); |
| 181 end | 185 end |
| 330 return; | 334 return; |
| 331 end | 335 end |
| 332 module:log("debug", "Received ack request, acking for %d", origin.handled_stanza_count); | 336 module:log("debug", "Received ack request, acking for %d", origin.handled_stanza_count); |
| 333 -- Reply with <a> | 337 -- Reply with <a> |
| 334 (origin.sends2s or origin.send)(st.stanza("a", { xmlns = xmlns_sm, h = string.format("%d", origin.handled_stanza_count) })); | 338 (origin.sends2s or origin.send)(st.stanza("a", { xmlns = xmlns_sm, h = string.format("%d", origin.handled_stanza_count) })); |
| 335 -- piggyback our own ack request | 339 -- piggyback our own ack request if needed (see request_ack_if_needed() for explanation of last_requested_h) |
| 336 if #origin.outgoing_stanza_queue > 0 and origin.last_queue_count ~= #origin.outgoing_stanza_queue then | 340 local expected_h = origin.last_acknowledged_stanza + #origin.outgoing_stanza_queue; |
| 341 if #origin.outgoing_stanza_queue > 0 and expected_h ~= origin.last_requested_h then | |
| 337 request_ack_if_needed(origin, true, "piggybacked by handle_r"); | 342 request_ack_if_needed(origin, true, "piggybacked by handle_r"); |
| 338 end | 343 end |
| 339 return true; | 344 return true; |
| 340 end | 345 end |
| 341 module:hook_stanza(xmlns_sm2, "r", function (origin, stanza) return handle_r(origin, stanza, xmlns_sm2); end); | 346 module:hook_stanza(xmlns_sm2, "r", function (origin, stanza) return handle_r(origin, stanza, xmlns_sm2); end); |
