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); |