Mercurial > prosody-hg
comparison core/s2smanager.lua @ 434:0d7ba3742f7a
(Basic) IDNA and SRV fallback support
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Wed, 26 Nov 2008 23:44:30 +0000 |
| parents | e918c979ad1a |
| children | 4087aa611de2 |
comparison
equal
deleted
inserted
replaced
| 433:afbf29498123 | 434:0d7ba3742f7a |
|---|---|
| 6 local t_insert, t_sort = table.insert, table.sort; | 6 local t_insert, t_sort = table.insert, table.sort; |
| 7 local get_traceback = debug.traceback; | 7 local get_traceback = debug.traceback; |
| 8 local tostring, pairs, ipairs, getmetatable, print, newproxy, error, tonumber | 8 local tostring, pairs, ipairs, getmetatable, print, newproxy, error, tonumber |
| 9 = tostring, pairs, ipairs, getmetatable, print, newproxy, error, tonumber; | 9 = tostring, pairs, ipairs, getmetatable, print, newproxy, error, tonumber; |
| 10 | 10 |
| 11 local idna_to_ascii = require "util.encodings".idna.to_ascii; | |
| 11 local connlisteners_get = require "net.connlisteners".get; | 12 local connlisteners_get = require "net.connlisteners".get; |
| 12 local wraptlsclient = require "net.server".wraptlsclient; | 13 local wraptlsclient = require "net.server".wraptlsclient; |
| 13 local modulemanager = require "core.modulemanager"; | 14 local modulemanager = require "core.modulemanager"; |
| 14 local st = require "stanza"; | 15 local st = require "stanza"; |
| 15 local stanza = st.stanza; | 16 local stanza = st.stanza; |
| 82 end | 83 end |
| 83 | 84 |
| 84 function new_outgoing(from_host, to_host) | 85 function new_outgoing(from_host, to_host) |
| 85 local host_session = { to_host = to_host, from_host = from_host, notopen = true, type = "s2sout_unauthed", direction = "outgoing" }; | 86 local host_session = { to_host = to_host, from_host = from_host, notopen = true, type = "s2sout_unauthed", direction = "outgoing" }; |
| 86 hosts[from_host].s2sout[to_host] = host_session; | 87 hosts[from_host].s2sout[to_host] = host_session; |
| 87 local cl = connlisteners_get("xmppserver"); | 88 |
| 88 | 89 local log; |
| 89 local conn, handler = socket.tcp() | 90 do |
| 90 | 91 local conn_name = "s2sout"..tostring(conn):match("[a-f0-9]*$"); |
| 91 local connect_host, connect_port = to_host, 5269; | 92 log = logger_init(conn_name); |
| 92 | 93 host_session.log = log; |
| 93 local answer = dns.lookup("_xmpp-server._tcp."..to_host..".", "SRV"); | 94 end |
| 95 | |
| 96 attempt_connection(host_session); | |
| 97 | |
| 98 return host_session; | |
| 99 end | |
| 100 | |
| 101 | |
| 102 function attempt_connection(host_session, err) | |
| 103 local from_host, to_host = host_session.from_host, host_session.to_host; | |
| 104 local conn, handler = socket.tcp() | |
| 105 | |
| 106 local connect_host, connect_port = idna_to_ascii(to_host), 5269; | |
| 107 | |
| 108 if not err then -- This is our first attempt | |
| 109 local answer = dns.lookup("_xmpp-server._tcp."..connect_host..".", "SRV"); | |
| 94 | 110 |
| 95 if answer then | 111 if answer then |
| 96 log("debug", to_host.." has SRV records, handling..."); | 112 log("debug", to_host.." has SRV records, handling..."); |
| 97 local srv_hosts = {}; | 113 local srv_hosts = {}; |
| 98 host_session.srv_hosts = srv_hosts; | 114 host_session.srv_hosts = srv_hosts; |
| 100 t_insert(srv_hosts, record.srv); | 116 t_insert(srv_hosts, record.srv); |
| 101 end | 117 end |
| 102 t_sort(srv_hosts, compare_srv_priorities); | 118 t_sort(srv_hosts, compare_srv_priorities); |
| 103 | 119 |
| 104 local srv_choice = srv_hosts[1]; | 120 local srv_choice = srv_hosts[1]; |
| 121 host_session.srv_choice = 1; | |
| 105 if srv_choice then | 122 if srv_choice then |
| 106 connect_host, connect_port = srv_choice.target or to_host, srv_choice.port or connect_port; | 123 connect_host, connect_port = srv_choice.target or to_host, srv_choice.port or connect_port; |
| 107 log("debug", "Best record found, will connect to %s:%d", connect_host, connect_port); | 124 log("debug", "Best record found, will connect to %s:%d", connect_host, connect_port); |
| 108 end | 125 end |
| 109 end | 126 end |
| 110 | 127 elseif host_session.srv_hosts and #host_session.srv_hosts > host_session.srv_choice then -- Not our first attempt, and we also have SRV |
| 111 conn:settimeout(0); | 128 host_session.srv_choice = host_session.srv_choice + 1; |
| 112 local success, err = conn:connect(connect_host, connect_port); | 129 local srv_choice = host_session.srv_hosts[host_session.srv_choice]; |
| 113 if not success and err ~= "timeout" then | 130 connect_host, connect_port = srv_choice.target or to_host, srv_choice.port or connect_port; |
| 114 log("warn", "s2s connect() failed: %s", err); | 131 host_session.log("debug", "Attempt #%d: This time to %s:%d", host_session.srv_choice, connect_host, connect_port); |
| 115 end | 132 else |
| 116 | 133 host_session.log("debug", "Out of connection options, can't connect to %s", tostring(host_session.to_host)); |
| 117 conn = wraptlsclient(cl, conn, connect_host, connect_port, 0, 1, hosts[from_host].ssl_ctx ); | 134 -- We're out of options |
| 118 host_session.conn = conn; | 135 return false; |
| 119 | 136 end |
| 120 -- Register this outgoing connection so that xmppserver_listener knows about it | 137 |
| 121 -- otherwise it will assume it is a new incoming connection | 138 -- Ok, we're going to try to connect |
| 122 cl.register_outgoing(conn, host_session); | 139 conn:settimeout(0); |
| 123 | 140 local success, err = conn:connect(connect_host, connect_port); |
| 124 local log; | 141 if not success and err ~= "timeout" then |
| 125 do | 142 log("warn", "s2s connect() failed: %s", err); |
| 126 local conn_name = "s2sout"..tostring(conn):match("[a-f0-9]*$"); | 143 end |
| 127 log = logger_init(conn_name); | 144 |
| 128 host_session.log = log; | 145 local cl = connlisteners_get("xmppserver"); |
| 129 end | 146 conn = wraptlsclient(cl, conn, connect_host, connect_port, 0, 1, hosts[from_host].ssl_ctx ); |
| 130 | 147 host_session.conn = conn; |
| 131 local w = conn.write; | 148 |
| 132 host_session.sends2s = function (t) log("debug", "sending: %s", tostring(t)); w(tostring(t)); end | 149 -- Register this outgoing connection so that xmppserver_listener knows about it |
| 133 | 150 -- otherwise it will assume it is a new incoming connection |
| 134 conn.write(format([[<stream:stream xmlns='jabber:server' xmlns:db='jabber:server:dialback' xmlns:stream='http://etherx.jabber.org/streams' from='%s' to='%s' version='1.0'>]], from_host, to_host)); | 151 cl.register_outgoing(conn, host_session); |
| 135 | 152 |
| 136 return host_session; | 153 local w = conn.write; |
| 154 host_session.sends2s = function (t) log("debug", "sending: %s", tostring(t)); w(tostring(t)); end | |
| 155 | |
| 156 conn.write(format([[<stream:stream xmlns='jabber:server' xmlns:db='jabber:server:dialback' xmlns:stream='http://etherx.jabber.org/streams' from='%s' to='%s' version='1.0'>]], from_host, to_host)); | |
| 157 return true; | |
| 137 end | 158 end |
| 138 | 159 |
| 139 function streamopened(session, attr) | 160 function streamopened(session, attr) |
| 140 local send = session.sends2s; | 161 local send = session.sends2s; |
| 141 | 162 |
| 157 (session.log or log)("debug", "incoming s2s received <stream:stream>"); | 178 (session.log or log)("debug", "incoming s2s received <stream:stream>"); |
| 158 send("<?xml version='1.0'?>"); | 179 send("<?xml version='1.0'?>"); |
| 159 send(stanza("stream:stream", { xmlns='jabber:server', ["xmlns:db"]='jabber:server:dialback', ["xmlns:stream"]='http://etherx.jabber.org/streams', id=session.streamid, from=session.to_host }):top_tag()); | 180 send(stanza("stream:stream", { xmlns='jabber:server', ["xmlns:db"]='jabber:server:dialback', ["xmlns:stream"]='http://etherx.jabber.org/streams', id=session.streamid, from=session.to_host }):top_tag()); |
| 160 if session.to_host and not hosts[session.to_host] then | 181 if session.to_host and not hosts[session.to_host] then |
| 161 -- Attempting to connect to a host we don't serve | 182 -- Attempting to connect to a host we don't serve |
| 162 session:close("host-unknown"); | 183 session:close({ condition = "host-unknown"; text = "This host does not serve "..session.to_host }); |
| 163 return; | 184 return; |
| 164 end | 185 end |
| 165 if session.version >= 1.0 then | 186 if session.version >= 1.0 then |
| 166 send(st.stanza("stream:features") | 187 send(st.stanza("stream:features") |
| 167 :tag("dialback", { xmlns='urn:xmpp:features:dialback' }):tag("optional"):up():up()); | 188 :tag("dialback", { xmlns='urn:xmpp:features:dialback' }):tag("optional"):up():up()); |
