mod_smacks/mod_smacks.lua
changeset 3644 b2f32b3c6ec1
parent 3638 915e32d5a147
child 3650 58047d6f2b89
equal deleted inserted replaced
3643:562d3b219876 3644: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);