From 1bb28a6635aa77540d10d01624a10367b02bce0a Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Sun, 22 Jul 2012 16:29:52 +0100
Subject: mod_s2s/s2sout.lib: Fix indentation

---
 plugins/mod_s2s/s2sout.lib.lua | 120 ++++++++++++++++++++---------------------
 1 file changed, 60 insertions(+), 60 deletions(-)

(limited to 'plugins')

diff --git a/plugins/mod_s2s/s2sout.lib.lua b/plugins/mod_s2s/s2sout.lib.lua
index 6e1eb3d7..d2c6023e 100644
--- a/plugins/mod_s2s/s2sout.lib.lua
+++ b/plugins/mod_s2s/s2sout.lib.lua
@@ -173,85 +173,85 @@ function s2sout.try_connect(host_session, connect_host, connect_port, err)
 		local have_other_result = not(has_ipv4) or not(has_ipv6) or false;
 
 		if has_ipv4 then
-		handle4 = adns.lookup(function (reply, err)
-			handle4 = nil;
+			handle4 = adns.lookup(function (reply, err)
+				handle4 = nil;
 
-			-- COMPAT: This is a compromise for all you CNAME-(ab)users :)
-			if not (reply and reply[#reply] and reply[#reply].a) then
-				local count = max_dns_depth;
-				reply = dns.peek(connect_host, "CNAME", "IN");
-				while count > 0 and reply and reply[#reply] and not reply[#reply].a and reply[#reply].cname do
-					log("debug", "Looking up %s (DNS depth is %d)", tostring(reply[#reply].cname), count);
-					reply = dns.peek(reply[#reply].cname, "A", "IN") or dns.peek(reply[#reply].cname, "CNAME", "IN");
-					count = count - 1;
+				-- COMPAT: This is a compromise for all you CNAME-(ab)users :)
+				if not (reply and reply[#reply] and reply[#reply].a) then
+					local count = max_dns_depth;
+					reply = dns.peek(connect_host, "CNAME", "IN");
+					while count > 0 and reply and reply[#reply] and not reply[#reply].a and reply[#reply].cname do
+						log("debug", "Looking up %s (DNS depth is %d)", tostring(reply[#reply].cname), count);
+						reply = dns.peek(reply[#reply].cname, "A", "IN") or dns.peek(reply[#reply].cname, "CNAME", "IN");
+						count = count - 1;
+					end
 				end
-			end
-			-- end of CNAME resolving
+				-- end of CNAME resolving
 
-			if reply and reply[#reply] and reply[#reply].a then
-				for _, ip in ipairs(reply) do
-					log("debug", "DNS reply for %s gives us %s", connect_host, ip.a);
-					IPs[#IPs+1] = new_ip(ip.a, "IPv4");
+				if reply and reply[#reply] and reply[#reply].a then
+					for _, ip in ipairs(reply) do
+						log("debug", "DNS reply for %s gives us %s", connect_host, ip.a);
+						IPs[#IPs+1] = new_ip(ip.a, "IPv4");
+					end
 				end
-			end
 
-			if have_other_result then
-				if #IPs > 0 then
-					rfc3484_dest(host_session.ip_hosts, sources);
-					for i = 1, #IPs do
-						IPs[i] = {ip = IPs[i], port = connect_port};
+				if have_other_result then
+					if #IPs > 0 then
+						rfc3484_dest(host_session.ip_hosts, sources);
+						for i = 1, #IPs do
+							IPs[i] = {ip = IPs[i], port = connect_port};
+						end
+						host_session.ip_choice = 0;
+						s2sout.try_next_ip(host_session);
+					else
+						log("debug", "DNS lookup failed to get a response for %s", connect_host);
+						host_session.ip_hosts = nil;
+						if not s2sout.attempt_connection(host_session, "name resolution failed") then -- Retry if we can
+							log("debug", "No other records to try for %s - destroying", host_session.to_host);
+							err = err and (": "..err) or "";
+							s2s_destroy_session(host_session, "DNS resolution failed"..err); -- End of the line, we can't
+						end
 					end
-					host_session.ip_choice = 0;
-					s2sout.try_next_ip(host_session);
 				else
-					log("debug", "DNS lookup failed to get a response for %s", connect_host);
-					host_session.ip_hosts = nil;
-					if not s2sout.attempt_connection(host_session, "name resolution failed") then -- Retry if we can
-						log("debug", "No other records to try for %s - destroying", host_session.to_host);
-						err = err and (": "..err) or "";
-						s2s_destroy_session(host_session, "DNS resolution failed"..err); -- End of the line, we can't
-					end
+					have_other_result = true;
 				end
-			else
-				have_other_result = true;
-			end
-		end, connect_host, "A", "IN");
+			end, connect_host, "A", "IN");
 		else
 			have_other_result = true;
 		end
 
 		if has_ipv6 then
-		handle6 = adns.lookup(function (reply, err)
-			handle6 = nil;
+			handle6 = adns.lookup(function (reply, err)
+				handle6 = nil;
 
-			if reply and reply[#reply] and reply[#reply].aaaa then
-				for _, ip in ipairs(reply) do
-					log("debug", "DNS reply for %s gives us %s", connect_host, ip.aaaa);
-					IPs[#IPs+1] = new_ip(ip.aaaa, "IPv6");
+				if reply and reply[#reply] and reply[#reply].aaaa then
+					for _, ip in ipairs(reply) do
+						log("debug", "DNS reply for %s gives us %s", connect_host, ip.aaaa);
+						IPs[#IPs+1] = new_ip(ip.aaaa, "IPv6");
+					end
 				end
-			end
 
-			if have_other_result then
-				if #IPs > 0 then
-					rfc3484_dest(host_session.ip_hosts, sources);
-					for i = 1, #IPs do
-						IPs[i] = {ip = IPs[i], port = connect_port};
+				if have_other_result then
+					if #IPs > 0 then
+						rfc3484_dest(host_session.ip_hosts, sources);
+						for i = 1, #IPs do
+							IPs[i] = {ip = IPs[i], port = connect_port};
+						end
+						host_session.ip_choice = 0;
+						s2sout.try_next_ip(host_session);
+					else
+						log("debug", "DNS lookup failed to get a response for %s", connect_host);
+						host_session.ip_hosts = nil;
+						if not s2sout.attempt_connection(host_session, "name resolution failed") then -- Retry if we can
+							log("debug", "No other records to try for %s - destroying", host_session.to_host);
+							err = err and (": "..err) or "";
+							s2s_destroy_session(host_session, "DNS resolution failed"..err); -- End of the line, we can't
+						end
 					end
-					host_session.ip_choice = 0;
-					s2sout.try_next_ip(host_session);
 				else
-					log("debug", "DNS lookup failed to get a response for %s", connect_host);
-					host_session.ip_hosts = nil;
-					if not s2sout.attempt_connection(host_session, "name resolution failed") then -- Retry if we can
-						log("debug", "No other records to try for %s - destroying", host_session.to_host);
-						err = err and (": "..err) or "";
-						s2s_destroy_session(host_session, "DNS resolution failed"..err); -- End of the line, we can't
-					end
+					have_other_result = true;
 				end
-			else
-				have_other_result = true;
-			end
-		end, connect_host, "AAAA", "IN");
+			end, connect_host, "AAAA", "IN");
 		else
 			have_other_result = true;
 		end
-- 
cgit v1.2.3


From 7c1372811acef73a712f6182c5a268b500b40ee8 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Sun, 22 Jul 2012 16:45:27 +0100
Subject: mod_s2s: Make unauthed session timeout a little more aggressive...
 otherwise it's possible for sessions to slip under the net and never get
 killed off

---
 plugins/mod_s2s/mod_s2s.lua | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

(limited to 'plugins')

diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua
index f6c20606..1dbdc6ee 100644
--- a/plugins/mod_s2s/mod_s2s.lua
+++ b/plugins/mod_s2s/mod_s2s.lua
@@ -413,11 +413,9 @@ local function initialize_session(session)
 		return handlestanza(session, stanza);
 	end
 
-	local conn = session.conn;
 	add_task(connect_timeout, function ()
-		if session.conn ~= conn or session.connecting
-		or session.type == "s2sin" or session.type == "s2sout" then
-			return; -- Ok, we're connect[ed|ing]
+		if session.type == "s2sin" or session.type == "s2sout" then
+			return; -- Ok, we're connected
 		end
 		-- Not connected, need to close session and clean up
 		(session.log or log)("debug", "Destroying incomplete session %s->%s due to inactivity",
-- 
cgit v1.2.3


From efc4ec5efea1a4160a2651973e5cf5f5a2c3b6c3 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Sun, 22 Jul 2012 16:59:12 +0100
Subject: mod_c2s: Don't call ondisconnect manually on close, it is now called
 by net.server. Replace with inline code for destroying the session, and also
 waiting for a reply </stream:stream> if there is a chance of further data
 sent by the client. session.send() on a half-closed stream returns false (and
 does not deliver the data).

---
 plugins/mod_c2s.lua | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

(limited to 'plugins')

diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua
index 55c53e2d..75a6f689 100644
--- a/plugins/mod_c2s.lua
+++ b/plugins/mod_c2s.lua
@@ -24,6 +24,7 @@ local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams";
 local log = module._log;
 
 local c2s_timeout = module:get_option_number("c2s_timeout");
+local stream_close_timeout = module:get_option_number("c2s_close_timeout", 5);
 local opt_keepalives = module:get_option_boolean("tcp_keepalives", false);
 
 local sessions = module:shared("sessions");
@@ -143,8 +144,27 @@ local function session_close(session, reason)
 			end
 		end
 		session.send("</stream:stream>");
-		session.conn:close();
-		listener.ondisconnect(session.conn, (reason and (reason.text or reason.condition)) or reason or "session closed");
+		
+		function session.send() return false; end
+		
+		local reason = (reason and (reason.text or reason.condition)) or reason or "session closed";
+		session.log("info", "c2s stream for %s closed: %s", session.full_jid or ("<"..session.ip..">"), reason);
+
+		-- Authenticated incoming stream may still be sending us stanzas, so wait for </stream:stream> from remote
+		local conn = session.conn;
+		if reason == "session closed" and not session.notopen and session.type == "c2s" then
+			-- Grace time to process data from authenticated cleanly-closed stream
+			add_task(stream_close_timeout, function ()
+				if not session.destroyed then
+					session.log("warn", "Failed to receive a stream close response, closing connection anyway...");
+					sm_destroy_session(session, reason);
+					conn:close();
+				end
+			end);
+		else
+			sm_destroy_session(session, reason);
+			conn:close();
+		end
 	end
 end
 
@@ -208,10 +228,9 @@ end
 function listener.ondisconnect(conn, err)
 	local session = sessions[conn];
 	if session then
-		(session.log or log)("info", "Client disconnected: %s", err);
+		(session.log or log)("info", "Client disconnected: %s", err or "connection closed");
 		sm_destroy_session(session, err);
 		sessions[conn]  = nil;
-		session = nil;
 	end
 end
 
-- 
cgit v1.2.3


From 5efb7f0824efc81a06c0d9f9d139bc41637d9fd7 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Sun, 22 Jul 2012 16:59:55 +0100
Subject: mod_message: Don't treat a message as delivered ok if session.send()
 returns false

---
 plugins/mod_message.lua | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

(limited to 'plugins')

diff --git a/plugins/mod_message.lua b/plugins/mod_message.lua
index ebff2fe7..0b0ad8e4 100644
--- a/plugins/mod_message.lua
+++ b/plugins/mod_message.lua
@@ -35,10 +35,13 @@ local function process_to_bare(bare, origin, stanza)
 		if user then -- some resources are connected
 			local recipients = user.top_resources;
 			if recipients then
+				local sent;
 				for i=1,#recipients do
-					recipients[i].send(stanza);
+					sent = recipients[i].send(stanza) or sent;
+				end
+				if sent then
+					return true;
 				end
-				return true;
 			end
 		end
 		-- no resources are online
@@ -65,9 +68,7 @@ module:hook("message/full", function(data)
 	local origin, stanza = data.origin, data.stanza;
 	
 	local session = full_sessions[stanza.attr.to];
-	if session then
-		-- TODO fire post processing event
-		session.send(stanza);
+	if session and session.send(stanza) then
 		return true;
 	else -- resource not online
 		return process_to_bare(jid_bare(stanza.attr.to), origin, stanza);
-- 
cgit v1.2.3


From 94c9ed4e158fe9b24de77cde5da3a9124f7ffc38 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Sun, 22 Jul 2012 17:01:52 +0100
Subject: mod_iq: Don't treat an iq as handled if session.send() returns false

---
 plugins/mod_iq.lua | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

(limited to 'plugins')

diff --git a/plugins/mod_iq.lua b/plugins/mod_iq.lua
index 6412ad11..8044a533 100644
--- a/plugins/mod_iq.lua
+++ b/plugins/mod_iq.lua
@@ -17,10 +17,7 @@ if module:get_host_type() == "local" then
 		local origin, stanza = data.origin, data.stanza;
 
 		local session = full_sessions[stanza.attr.to];
-		if session then
-			-- TODO fire post processing event
-			session.send(stanza);
-		else -- resource not online
+		if not (session and session.send(stanza)) then
 			if stanza.attr.type == "get" or stanza.attr.type == "set" then
 				origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
 			end
-- 
cgit v1.2.3


From 41bab931e0143e408f83e3013e661a055a0d8150 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Sun, 22 Jul 2012 17:02:18 +0100
Subject: mod_presence: Handle nil disconnection error

---
 plugins/mod_presence.lua | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

(limited to 'plugins')

diff --git a/plugins/mod_presence.lua b/plugins/mod_presence.lua
index 6d039d83..09a6f9f2 100644
--- a/plugins/mod_presence.lua
+++ b/plugins/mod_presence.lua
@@ -352,13 +352,15 @@ module:hook("resource-unbind", function(event)
 	-- Send unavailable presence
 	if session.presence then
 		local pres = st.presence{ type = "unavailable" };
-		if not(err) or err == "closed" then err = "connection closed"; end
-		pres:tag("status"):text("Disconnected: "..err):up();
+		if err then
+			pres:tag("status"):text("Disconnected: "..err):up();
+		end
 		session:dispatch_stanza(pres);
 	elseif session.directed then
 		local pres = st.presence{ type = "unavailable", from = session.full_jid };
-		if not(err) or err == "closed" then err = "connection closed"; end
-		pres:tag("status"):text("Disconnected: "..err):up();
+		if err then
+			pres:tag("status"):text("Disconnected: "..err):up();
+		end
 		for jid in pairs(session.directed) do
 			pres.attr.to = jid;
 			core_post_stanza(session, pres, true);
-- 
cgit v1.2.3


From ef597cb9a9a2793fe9b071f887848ca1c4d73d4d Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Sun, 22 Jul 2012 17:04:02 +0100
Subject: mod_s2s: Don't treat a stanza as delivered if session.sends2s()
 returns false

---
 plugins/mod_s2s/mod_s2s.lua | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

(limited to 'plugins')

diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua
index 1dbdc6ee..8b1c7dab 100644
--- a/plugins/mod_s2s/mod_s2s.lua
+++ b/plugins/mod_s2s/mod_s2s.lua
@@ -97,9 +97,10 @@ function route_to_existing_session(event)
 				log("error", "WARNING! This might, possibly, be a bug, but it might not...");
 				log("error", "We are going to send from %s instead of %s", tostring(host.from_host), tostring(from_host));
 			end
-			host.sends2s(stanza);
-			host.log("debug", "stanza sent over "..host.type);
-			return true;
+			if host.sends2s(stanza) then
+				host.log("debug", "stanza sent over "..host.type);
+				return true;
+			end
 		end
 	end
 end
-- 
cgit v1.2.3


From 193ea4ef3030ab24da31f86031f6ea8386331099 Mon Sep 17 00:00:00 2001
From: Matthew Wild <mwild1@gmail.com>
Date: Sun, 22 Jul 2012 17:07:21 +0100
Subject: mod_s2s: Don't call ondisconnect manually, don't call conn:close() 3
 times (!) and merge its logic and streamdisconnected into session_close -
 including now waiting for a reply </stream:stream> if there is the chance of
 further stanzas requiring delivery arriving. session.sends2s() on a
 half-closed stream returns false.

---
 plugins/mod_s2s/mod_s2s.lua | 48 +++++++++++++++++++++++++++------------------
 1 file changed, 29 insertions(+), 19 deletions(-)

(limited to 'plugins')

diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua
index 8b1c7dab..f686fcfb 100644
--- a/plugins/mod_s2s/mod_s2s.lua
+++ b/plugins/mod_s2s/mod_s2s.lua
@@ -31,6 +31,7 @@ local cert_verify_identity = require "util.x509".verify_identity;
 local s2sout = module:require("s2sout");
 
 local connect_timeout = module:get_option_number("s2s_timeout", 60);
+local stream_close_timeout = module:get_option_number("s2s_close_timeout", 5);
 
 local sessions = module:shared("sessions");
 
@@ -292,18 +293,6 @@ function stream_callbacks.streamclosed(session)
 	session:close();
 end
 
-function stream_callbacks.streamdisconnected(session, err)
-	if err and err ~= "closed" and session.direction == "outgoing" and session.notopen then
-		(session.log or log)("debug", "s2s connection attempt failed: %s", err);
-		if s2sout.attempt_connection(session, err) then
-			(session.log or log)("debug", "...so we're going to try another target");
-			return true; -- Session lives for now
-		end
-	end
-	(session.log or log)("info", "s2s disconnected: %s->%s (%s)", tostring(session.from_host), tostring(session.to_host), tostring(err or "closed"));
-	s2s_destroy_session(session, err);
-end
-
 function stream_callbacks.error(session, error, data)
 	if error == "no-stream" then
 		session:close("invalid-namespace");
@@ -375,11 +364,26 @@ local function session_close(session, reason, remote_reason)
 			end
 		end
 		session.sends2s("</stream:stream>");
-		if session.notopen or not session.conn:close() then
-			session.conn:close(true); -- Force FIXME: timer?
+
+		function session.sends2s() return false; end
+		
+		local reason = remote_reason or (reason and (reason.text or reason.condition)) or reason or "stream closed";
+		session.log("info", "%s s2s stream %s->%s closed: %s", session.direction, session.from_host or "(unknown host)", session.to_host or "(unknown host)", reason);
+		
+		-- Authenticated incoming stream may still be sending us stanzas, so wait for </stream:stream> from remote
+		local conn = session.conn;
+		if not session.notopen and session.type == "s2sin" then
+			add_task(stream_close_timeout, function ()
+				if not session.destroyed then
+					session.log("warn", "Failed to receive a stream close response, closing connection anyway...");
+					s2s_destroy_session(session, reason);
+					conn:close();
+				end
+			end);
+		else
+			s2s_destroy_session(session, reason);
+			conn:close(); -- Close immediately, as this is an outgoing connection or is not authed
 		end
-		session.conn:close();
-		listener.ondisconnect(session.conn, remote_reason or (reason and (reason.text or reason.condition)) or reason or "stream closed");
 	end
 end
 
@@ -473,11 +477,17 @@ end
 function listener.ondisconnect(conn, err)
 	local session = sessions[conn];
 	if session then
-		if stream_callbacks.streamdisconnected(session, err) then
-			return; -- Connection lives, for now
+		if err and session.direction == "outgoing" and session.notopen then
+			(session.log or log)("debug", "s2s connection attempt failed: %s", err);
+			if s2sout.attempt_connection(session, err) then
+				(session.log or log)("debug", "...so we're going to try another target");
+				return; -- Session lives for now
+			end
 		end
+		(session.log or log)("debug", "s2s disconnected: %s->%s (%s)", tostring(session.from_host), tostring(session.to_host), tostring(err or "connection closed"));
+		s2s_destroy_session(session, err);
+		sessions[conn] = nil;
 	end
-	sessions[conn] = nil;
 end
 
 function listener.register_outgoing(conn, session)
-- 
cgit v1.2.3