module "s2smanager"
-local function compare_srv_priorities(a,b) return a.priority < b.priority or a.weight < b.weight; end
+function compare_srv_priorities(a,b)
+ return a.priority < b.priority or (a.priority == b.priority and a.weight > b.weight);
+end
-local function bounce_sendq(session)
+local function bounce_sendq(session, reason)
local sendq = session.sendq;
if sendq then
session.log("info", "sending error replies for "..#sendq.." queued stanzas because of failed outgoing connection to "..tostring(session.to_host));
reply.attr.type = "error";
reply:tag("error", {type = "cancel"})
:tag("remote-server-not-found", {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}):up();
+ if reason then
+ reply:tag("text", {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}):text("Connection failed: "..reason):up();
+ end
core_process_stanza(dummy, reply);
end
sendq[i] = nil;
end
function send_to_host(from_host, to_host, data)
+ if not hosts[from_host] then
+ log("warn", "Attempt to send stanza from %s - a host we don't serve", from_host);
+ return false;
+ end
local host = hosts[from_host].s2sout[to_host];
if host then
-- We have a connection to this host already
- if host.type == "s2sout_unauthed" and data.name ~= "db:verify" and ((not data.xmlns) or data.xmlns == "jabber:client" or data.xmlns == "jabber:server") then
+ if host.type == "s2sout_unauthed" and (data.name ~= "db:verify" or not host.dialback_key) and ((not data.xmlns) or data.xmlns == "jabber:client" or data.xmlns == "jabber:server") then
(host.log or log)("debug", "trying to send over unauthed s2sout to "..to_host);
- if not host.notopen and not host.dialback_key and host.sends2s then
- host.log("debug", "dialback had not been initiated");
- initiate_dialback(host);
- end
-- Queue stanza until we are able to send it
if host.sendq then t_insert(host.sendq, {tostring(data), st.reply(data)});
else
log("debug", "opening a new outgoing connection for this stanza");
local host_session = new_outgoing(from_host, to_host);
+
-- Store in buffer
host_session.sendq = { {tostring(data), st.reply(data)} };
log("debug", "stanza [%s] queued until connection complete", tostring(data.name));
host_session.log = log;
end
- -- This is the first call, can't fail (the first step is DNS lookup)
+ -- Kick the connection attempting machine
attempt_connection(host_session);
if not host_session.sends2s then
local from_host, to_host = host_session.from_host, host_session.to_host;
local connect_host, connect_port = idna_to_ascii(to_host), 5269;
+ if not connect_host then
+ return false;
+ end
+
if not err then -- This is our first attempt
log("debug", "First attempt to connect to %s, starting with SRV lookup...", to_host);
host_session.connecting = true;
if not ok then
if not attempt_connection(host_session, err) then
-- No more attempts will be made
- destroy_session(host_session);
+ destroy_session(host_session, err);
end
end
end, "_xmpp-server._tcp."..connect_host..".", "SRV");
log("debug", "DNS lookup failed to get a response for %s", connect_host);
if not 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);
- destroy_session(host_session); -- End of the line, we can't
+ destroy_session(host_session, "DNS resolution failed"); -- End of the line, we can't
end
end
end, connect_host, "A", "IN");
local from_host, to_host = host_session.from_host, host_session.to_host;
local conn, handler = socket.tcp()
+
+ if not conn then
+ log("warn", "Failed to create outgoing connection, system error: %s", handler);
+ return false, handler;
+ end
conn:settimeout(0);
local success, err = conn:connect(connect_host, connect_port);
session.streamid = uuid_gen();
(session.log or log)("debug", "incoming s2s received <stream:stream>");
- send("<?xml version='1.0'?>");
- 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, version=(session.version > 0 and "1.0" or nil) }):top_tag());
if session.to_host and not hosts[session.to_host] then
-- Attempting to connect to a host we don't serve
session:close({ condition = "host-unknown"; text = "This host does not serve "..session.to_host });
return;
end
+ send("<?xml version='1.0'?>");
+ 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, version=(session.version > 0 and "1.0" or nil) }):top_tag());
if session.version >= 1.0 then
local features = st.stanza("stream:features");
-
+
if session.to_host then
hosts[session.to_host].events.fire_event("s2s-stream-features", { session = session, features = features });
else
if send_buffer and #send_buffer > 0 then
log("debug", "Sending s2s send_buffer now...");
for i, data in ipairs(send_buffer) do
- session.sends2s(tostring(data));
+ session.sends2s(data);
send_buffer[i] = nil;
end
end
end
end
-function destroy_session(session)
+function destroy_session(session, reason)
(session.log or log)("info", "Destroying "..tostring(session.direction).." session "..tostring(session.from_host).."->"..tostring(session.to_host));
if session.direction == "outgoing" then
hosts[session.from_host].s2sout[session.to_host] = nil;
- bounce_sendq(session);
+ bounce_sendq(session, reason);
elseif session.direction == "incoming" then
incoming_s2s[session] = nil;
end