Changeset

2879:94299e640ed0

Merge with 0.7 (and indirectly 0.6.2)
author Matthew Wild <mwild1@gmail.com>
date Mon, 15 Mar 2010 03:18:33 +0000
parents 2744:887d3a0e1e4e (current diff) 2878:9384ee36fc03 (diff)
children 2880:a3f6cc3417f2
files
diffstat 5 files changed, 114 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/core/s2smanager.lua	Fri Mar 05 18:35:23 2010 +0000
+++ b/core/s2smanager.lua	Mon Mar 15 03:18:33 2010 +0000
@@ -16,8 +16,10 @@
 local format = string.format;
 local t_insert, t_sort = table.insert, table.sort;
 local get_traceback = debug.traceback;
-local tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber
-    = tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber;
+local tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber,
+      setmetatable
+    = tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber,
+      setmetatable;
 
 local idna_to_ascii = require "util.encodings".idna.to_ascii;
 local connlisteners_get = require "net.connlisteners".get;
@@ -432,11 +434,8 @@
 end
 
 function streamclosed(session)
-	(session.log or log)("debug", "</stream:stream>");
-	if session.sends2s then
-		session.sends2s("</stream:stream>");
-	end
-	session.notopen = true;
+	(session.log or log)("debug", "Received </stream:stream>");
+	session:close();
 end
 
 function initiate_dialback(session)
@@ -510,9 +509,31 @@
 	end
 end
 
-local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed s2s session: %s", data); end
+local resting_session = { -- Resting, not dead
+		destroyed = true;
+		open_stream = function (session)
+			session.log("debug", "Attempt to open stream on resting session");
+		end;
+		close = function (session)
+			session.log("debug", "Attempt to close already-closed session");
+		end;
+	}; resting_session.__index = resting_session;
+
+function retire_session(session)
+	local log = session.log or log;
+	for k in pairs(session) do
+		if k ~= "trace" and k ~= "log" and k ~= "id" then
+			session[k] = nil;
+		end
+	end
+
+	function session.send(data) log("debug", "Discarding data sent to resting session: %s", tostring(data)); end
+	function session.data(data) log("debug", "Discarding data received from resting session: %s", tostring(data)); end
+	return setmetatable(session, resting_session);
+end
 
 function destroy_session(session, reason)
+	if session.destroyed then return; end
 	(session.log or log)("info", "Destroying "..tostring(session.direction).." session "..tostring(session.from_host).."->"..tostring(session.to_host));
 	
 	if session.direction == "outgoing" then
@@ -522,12 +543,7 @@
 		incoming_s2s[session] = nil;
 	end
 	
-	for k in pairs(session) do
-		if k ~= "trace" then
-			session[k] = nil;
-		end
-	end
-	session.data = null_data_handler;
+	retire_session(session); -- Clean session until it is GC'd
 end
 
 return _M;
--- a/core/sessionmanager.lua	Fri Mar 05 18:35:23 2010 +0000
+++ b/core/sessionmanager.lua	Mon Mar 15 03:18:33 2010 +0000
@@ -8,7 +8,7 @@
 
 
 
-local tonumber, tostring = tonumber, tostring;
+local tonumber, tostring, setmetatable = tonumber, tostring, setmetatable;
 local ipairs, pairs, print, next= ipairs, pairs, print, next;
 local format = import("string", "format");
 
@@ -66,10 +66,29 @@
 	return session;
 end
 
-local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed c2s session: %s", data); end
+local resting_session = { -- Resting, not dead
+		destroyed = true;
+		close = function (session)
+			session.log("debug", "Attempt to close already-closed session");
+		end;
+	}; resting_session.__index = resting_session;
+
+function retire_session(session)
+	local log = session.log or log;
+	for k in pairs(session) do
+		if k ~= "trace" and k ~= "log" and k ~= "id" then
+			session[k] = nil;
+		end
+	end
+
+	function session.send(data) log("debug", "Discarding data sent to resting session: %s", tostring(data)); end
+	function session.data(data) log("debug", "Discarding data received from resting session: %s", tostring(data)); end
+	return setmetatable(session, resting_session);
+end
 
 function destroy_session(session, err)
 	(session.log or log)("info", "Destroying session for %s (%s@%s)", session.full_jid or "(unknown)", session.username or "(unknown)", session.host or "(unknown)");
+	if session.destroyed then return; end
 	
 	-- Remove session/resource from user's session list
 	if session.full_jid then
@@ -85,12 +104,7 @@
 		hosts[session.host].events.fire_event("resource-unbind", {session=session, error=err});
 	end
 	
-	for k in pairs(session) do
-		if k ~= "trace" then
-			session[k] = nil;
-		end
-	end
-	session.data = null_data_handler;
+	retire_session(session);
 end
 
 function make_authenticated(session, username)
@@ -168,7 +182,12 @@
 
 function streamopened(session, attr)
 	local send = session.send;
-	session.host = attr.to or error("Client failed to specify destination hostname");
+	session.host = attr.to;
+	if not session.host then
+		session:close{ condition = "improper-addressing",
+			text = "A 'to' attribute is required on stream headers" };
+		return;
+	end
 	session.host = nameprep(session.host);
 	session.version = tonumber(attr.version) or 0;
 	session.streamid = uuid_generate();
@@ -201,8 +220,8 @@
 end
 
 function streamclosed(session)
-	session.send("</stream:stream>");
-	session.notopen = true;
+	session.log("debug", "Received </stream:stream>");
+	session:close();
 end
 
 function send_to_available_resources(user, host, stanza)
--- a/net/xmppclient_listener.lua	Fri Mar 05 18:35:23 2010 +0000
+++ b/net/xmppclient_listener.lua	Mon Mar 15 03:18:33 2010 +0000
@@ -33,13 +33,32 @@
 local stream_callbacks = { default_ns = "jabber:client",
 		streamopened = sm_streamopened, streamclosed = sm_streamclosed, handlestanza = core_process_stanza };
 
+local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams";
+
 function stream_callbacks.error(session, error, data)
 	if error == "no-stream" then
 		session.log("debug", "Invalid opening stream header");
 		session:close("invalid-namespace");
-	elseif session.close then
-		(session.log or log)("debug", "Client XML parse error: %s", tostring(error));
+	elseif error == "parse-error" then
+		(session.log or log)("debug", "Client XML parse error: %s", tostring(data));
 		session:close("xml-not-well-formed");
+	elseif error == "stream-error" then
+		local condition, text = "undefined-condition";
+		for child in data:children() do
+			if child.attr.xmlns == xmlns_xmpp_streams then
+				if child.name ~= "text" then
+					condition = child.name;
+				else
+					text = child:get_text();
+				end
+				if condition ~= "undefined-condition" and text then
+					break;
+				end
+			end
+		end
+		text = condition .. (text and (" ("..text..")") or "");
+		session.log("info", "Session closed by remote with error: %s", text);
+		session:close(nil, text);
 	end
 end
 
--- a/net/xmppcomponent_listener.lua	Fri Mar 05 18:35:23 2010 +0000
+++ b/net/xmppcomponent_listener.lua	Mon Mar 15 03:18:33 2010 +0000
@@ -34,16 +34,33 @@
 
 local stream_callbacks = { default_ns = xmlns_component };
 
+local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams";
+
 function stream_callbacks.error(session, error, data, data2)
+	if session.destroyed then return; end
 	log("warn", "Error processing component stream: "..tostring(error));
 	if error == "no-stream" then
 		session:close("invalid-namespace");
-	elseif error == "xml-parse-error" and data == "unexpected-element-close" then
-		session.log("warn", "Unexpected close of '%s' tag", data2);
+	elseif error == "parse-error" then
+		session.log("warn", "External component %s XML parse error: %s", tostring(session.host), tostring(data));
 		session:close("xml-not-well-formed");
-	else
-		session.log("warn", "External component %s XML parse error: %s", tostring(session.host), tostring(error));
-		session:close("xml-not-well-formed");
+	elseif error == "stream-error" then
+		local condition, text = "undefined-condition";
+		for child in data:children() do
+			if child.attr.xmlns == xmlns_xmpp_streams then
+				if child.name ~= "text" then
+					condition = child.name;
+				else
+					text = child:get_text();
+				end
+				if condition ~= "undefined-condition" and text then
+					break;
+				end
+			end
+		end
+		text = condition .. (text and (" ("..text..")") or "");
+		session.log("info", "Session closed by remote with error: %s", text);
+		session:close(nil, text);
 	end
 end
 
@@ -71,8 +88,8 @@
 end
 
 function stream_callbacks.streamclosed(session)
-	session.send("</stream:stream>");
-	session.notopen = true;
+	session.log("Received </stream:stream>");
+	session:close();
 end
 
 local core_process_stanza = core_process_stanza;
@@ -89,6 +106,7 @@
 local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'};
 local default_stream_attr = { ["xmlns:stream"] = "http://etherx.jabber.org/streams", xmlns = stream_callbacks.default_ns, version = "1.0", id = "" };
 local function session_close(session, reason)
+	if session.destroyed then return; end
 	local log = session.log or log;
 	if session.conn then
 		if session.notopen then
@@ -146,6 +164,7 @@
 		function session.data(conn, data)
 			local ok, err = parser:parse(data);
 			if ok then return; end
+			log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_"));
 			session:close("xml-not-well-formed");
 		end
 		
@@ -167,7 +186,12 @@
 			hosts[session.host].connected = nil;
 		end
 		sessions[conn]  = nil;
-		for k in pairs(session) do session[k] = nil; end
+		for k in pairs(session) do
+			if k ~= "log" and k ~= "close" then
+				session[k] = nil;
+			end
+		end
+		session.destroyed = true;
 		session = nil;
 	end
 end
--- a/net/xmppserver_listener.lua	Fri Mar 05 18:35:23 2010 +0000
+++ b/net/xmppserver_listener.lua	Mon Mar 15 03:18:33 2010 +0000
@@ -176,7 +176,7 @@
 				return; -- 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));
+		(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);
 		sessions[conn]  = nil;
 		session = nil;