mod_bidi/mod_bidi.lua
changeset 1121 c714ed7de4ee
parent 932 4e235e565693
child 1122 6094d57c5387
equal deleted inserted replaced
1120:fc26a33fc2f3 1121:c714ed7de4ee
     2 -- http://xmpp.org/extensions/xep-0288.html
     2 -- http://xmpp.org/extensions/xep-0288.html
     3 -- Copyright (C) 2013 Kim Alvefur
     3 -- Copyright (C) 2013 Kim Alvefur
     4 --
     4 --
     5 -- This file is MIT/X11 licensed.
     5 -- This file is MIT/X11 licensed.
     6 --
     6 --
     7 local s2smanager = require"core.s2smanager";
       
     8 local add_filter = require "util.filters".add_filter;
     7 local add_filter = require "util.filters".add_filter;
     9 local st = require "util.stanza";
     8 local st = require "util.stanza";
    10 local jid_split = require"util.jid".prepped_split;
     9 local jid_split = require"util.jid".prepped_split;
    11 
    10 local core_process_stanza = prosody.core_process_stanza;
       
    11 local traceback = debug.traceback;
       
    12 local hosts = hosts;
    12 local xmlns_bidi_feature = "urn:xmpp:features:bidi"
    13 local xmlns_bidi_feature = "urn:xmpp:features:bidi"
    13 local xmlns_bidi = "urn:xmpp:bidi";
    14 local xmlns_bidi = "urn:xmpp:bidi";
    14 local noop = function () end
    15 local bidi_sessions = module:shared"sessions";
    15 local core_process_stanza = prosody.core_process_stanza or core_process_stanza;
       
    16 local traceback = debug.traceback;
       
    17 
    16 
    18 local function handleerr(err) log("error", "Traceback[s2s]: %s: %s", tostring(err), traceback()); end
    17 local function handleerr(err) log("error", "Traceback[s2s]: %s: %s", tostring(err), traceback()); end
    19 local function handlestanza(session, stanza)
    18 local function handlestanza(session, stanza)
    20 	if stanza.attr.xmlns == "jabber:client" then --COMPAT: Prosody pre-0.6.2 may send jabber:client
    19 	if stanza.attr.xmlns == "jabber:client" then --COMPAT: Prosody pre-0.6.2 may send jabber:client
    21 		stanza.attr.xmlns = nil;
    20 		stanza.attr.xmlns = nil;
    25 		return xpcall(function () return core_process_stanza(session, stanza) end, handleerr);
    24 		return xpcall(function () return core_process_stanza(session, stanza) end, handleerr);
    26 	end
    25 	end
    27 end
    26 end
    28 
    27 
    29 local function new_bidi(origin)
    28 local function new_bidi(origin)
    30 	local bidi_session, remote_host;
    29 	if origin.type == "s2sin" then -- then we create an "outgoing" bidirectional session
    31 	origin.log("debug", "Creating bidirectional session wrapper");
       
    32 	if origin.direction == "incoming" then -- then we create an "outgoing" bidirectional session
       
    33 		local conflicting_session = hosts[origin.to_host].s2sout[origin.from_host]
    30 		local conflicting_session = hosts[origin.to_host].s2sout[origin.from_host]
    34 		if conflicting_session then
    31 		if conflicting_session then
    35 			conflicting_session.log("info", "We already have an outgoing connection to %s, closing it...", origin.from_host);
    32 			conflicting_session.log("info", "We already have an outgoing connection to %s, closing it...", origin.from_host);
    36 			conflicting_session:close{ condition = "conflict", text = "Replaced by bidirectional stream" }
    33 			conflicting_session:close{ condition = "conflict", text = "Replaced by bidirectional stream" }
    37 			s2smanager.destroy_session(conflicting_session);
    34 			s2smanager.destroy_session(conflicting_session);
    38 		end
    35 		end
    39 		remote_host = origin.from_host;
    36 		bidi_sessions[origin.from_host] = origin;
    40 		bidi_session = s2smanager.new_outgoing(origin.to_host, origin.from_host)
    37 	elseif origin.type == "s2sout" then -- handle incoming stanzas correctly
    41 	else -- outgoing -- then we create an "incoming" bidirectional session
    38 		local bidi_session = {
       
    39 			type = "s2sin";
       
    40 			is_bidi = true; orig_session = origin;
       
    41 			to_host = origin.from_host;
       
    42 			from_host = origin.to_host;
       
    43 			hosts = {};
       
    44 		}
       
    45 		origin.bidi_session = bidi_session;
       
    46 		setmetatable(bidi_session, { __index = origin });
       
    47 		module:fire_event("s2s-authenticated", { session = bidi_session, host = origin.to_host });
    42 		remote_host = origin.to_host;
    48 		remote_host = origin.to_host;
    43 		bidi_session = s2smanager.new_incoming(origin.conn)
       
    44 		bidi_session.to_host = origin.from_host;
       
    45 		bidi_session.from_host = origin.to_host;
       
    46 		add_filter(origin, "stanzas/in", function(stanza)
    49 		add_filter(origin, "stanzas/in", function(stanza)
    47 			if stanza.attr.xmlns ~= nil then return stanza end
    50 			if stanza.attr.xmlns ~= nil then return stanza end
    48 			local _, host = jid_split(stanza.attr.from);
    51 			local _, host = jid_split(stanza.attr.from);
    49 			if host ~= remote_host then return stanza end
    52 			if host ~= remote_host then return stanza end
    50 			handlestanza(bidi_session, stanza);
    53 			handlestanza(bidi_session, stanza);
    51 		end, 1);
    54 		end, 1);
    52 	end
    55 	end
    53 	origin.bidi_session = bidi_session;
    56 end
    54 	bidi_session.sends2s = origin.sends2s;
       
    55 	bidi_session.bounce_sendq = noop;
       
    56 	bidi_session.notopen = nil;
       
    57 	bidi_session.is_bidi = true;
       
    58 	bidi_session.bidi_session = false;
       
    59 	bidi_session.orig_session = origin;
       
    60 	bidi_session.secure = origin.secure;
       
    61 	bidi_session.cert_identity_status = origin.cert_identity_status;
       
    62 	bidi_session.cert_chain_status = origin.cert_chain_status;
       
    63 	bidi_session.close = function(...)
       
    64 		return origin.close(...);
       
    65 	end
       
    66 
    57 
    67 	bidi_session.log("info", "Bidirectional session established");
    58 module:hook("route/remote", function(event)
    68 	module:fire_event("s2s-authenticated", { session = bidi_session, host = remote_host });
    59 	local from_host, to_host, stanza = event.from_host, event.to_host, event.stanza;
    69 	return bidi_session;
    60 	if from_host ~= module.host then return end
    70 end
    61 	local to_session = bidi_sessions[to_host]
       
    62 	if not to_session then return end
       
    63 	return to_session.sends2s(stanza);
       
    64 end, -2);
    71 
    65 
    72 -- Incoming s2s
    66 -- Incoming s2s
    73 module:hook("s2s-stream-features", function(event)
    67 module:hook("s2s-stream-features", function(event)
    74 	local origin, features = event.origin, event.features;
    68 	local origin, features = event.origin, event.features;
    75 	if not origin.is_bidi and not hosts[module.host].s2sout[origin.from_host] then
    69 	if not origin.is_bidi and not hosts[module.host].s2sout[origin.from_host] then
   109 module:hook("s2sin-established", enable_bidi);
   103 module:hook("s2sin-established", enable_bidi);
   110 module:hook("s2sout-established", enable_bidi);
   104 module:hook("s2sout-established", enable_bidi);
   111 
   105 
   112 function disable_bidi(event)
   106 function disable_bidi(event)
   113 	local session = event.session;
   107 	local session = event.session;
   114 	if session.bidi_session then
   108 	if session.type == "s2sin" then -- then we create an "outgoing" bidirectional session
   115 		local bidi_session = session.bidi_session;
   109 		bidi_sessions[session.from_host] = nil;
   116 		session.bidi_session, bidi_session.orig_session = nil, nil;
       
   117 		session.log("debug", "Tearing down bidirectional stream");
       
   118 		s2smanager.destroy_session(bidi_session, event.reason);
       
   119 	elseif session.orig_session then
       
   120 		local orig_session = session.orig_session;
       
   121 		orig_session.bidi_session, session.orig_session = nil, nil;
       
   122 		orig_session.log("debug", "Tearing down bidirectional stream");
       
   123 		s2smanager.destroy_session(orig_session, event.reason);
       
   124 	end
   110 	end
   125 end
   111 end
   126 
   112 
   127 module:hook("s2sin-destroyed", disable_bidi);
   113 module:hook("s2sin-destroyed", disable_bidi);
   128 module:hook("s2sout-destroyed", disable_bidi);
   114 module:hook("s2sout-destroyed", disable_bidi);