X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=plugins%2Fmod_c2s.lua;h=89d678caedc62ef446ab0163f353a7cd5345c42e;hb=d6d7dbbadf00ff9cc6d203309b128bccd4e47d86;hp=743fe3d2a9334914866ea0e9854d4e2cd58549f0;hpb=42fd790bd338f256e4b4ca2c8ce3cc9c328bf361;p=prosody.git diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 743fe3d2..89d678ca 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -11,14 +11,12 @@ module:set_global(); local add_task = require "util.timer".add_task; local new_xmpp_stream = require "util.xmppstream".new; local nameprep = require "util.encodings".stringprep.nameprep; -local portmanager = require "core.portmanager"; local sessionmanager = require "core.sessionmanager"; local st = require "util.stanza"; local sm_new_session, sm_destroy_session = sessionmanager.new_session, sessionmanager.destroy_session; local uuid_generate = require "util.uuid".generate; local xpcall, tostring, type = xpcall, tostring, type; -local format = string.format; local traceback = debug.traceback; local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; @@ -26,9 +24,11 @@ local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; local log = module._log; local c2s_timeout = module:get_option_number("c2s_timeout"); +local stream_close_timeout = module:get_option_number("c2s_close_timeout", 5); local opt_keepalives = module:get_option_boolean("tcp_keepalives", false); local sessions = module:shared("sessions"); +local core_process_stanza = prosody.core_process_stanza; local stream_callbacks = { default_ns = "jabber:client", handlestanza = core_process_stanza }; local listener = {}; @@ -55,8 +55,9 @@ function stream_callbacks.streamopened(session, attr) return; end - send(""); - send(format("", session.streamid, session.host)); + send(""..st.stanza("stream:stream", { + xmlns = 'jabber:client', ["xmlns:stream"] = 'http://etherx.jabber.org/streams'; + id = session.streamid, from = session.host, version = '1.0', ["xml:lang"] = 'en' }):top_tag()); (session.log or log)("debug", "Sent reply to client"); session.notopen = nil; @@ -65,6 +66,14 @@ function stream_callbacks.streamopened(session, attr) -- since we now have a new stream header, session is secured if session.secure == false then session.secure = true; + + -- Check if TLS compression is used + local sock = session.conn:socket(); + if sock.info then + session.compressed = sock:info"compression"; + elseif sock.compression then + session.compressed = sock:compression(); --COMPAT mw/luasec-hg + end end local features = st.stanza("stream:features"); @@ -76,7 +85,7 @@ end function stream_callbacks.streamclosed(session) session.log("debug", "Received "); - session:close(); + session:close(false); end function stream_callbacks.error(session, error, data) @@ -122,9 +131,9 @@ local function session_close(session, reason) session.send(""); session.send(st.stanza("stream:stream", default_stream_attr):top_tag()); end - if reason then + if reason then -- nil == no err, initiated by us, false == initiated by client if type(reason) == "string" then -- assume stream error - log("info", "Disconnecting client, is: %s", reason); + log("debug", "Disconnecting client, is: %s", reason); session.send(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' })); elseif type(reason) == "table" then if reason.condition then @@ -135,20 +144,49 @@ local function session_close(session, reason) if reason.extra then stanza:add_child(reason.extra); end - log("info", "Disconnecting client, is: %s", tostring(stanza)); + log("debug", "Disconnecting client, is: %s", tostring(stanza)); session.send(stanza); elseif reason.name then -- a stanza - log("info", "Disconnecting client, is: %s", tostring(reason)); + log("debug", "Disconnecting client, is: %s", tostring(reason)); session.send(reason); end end end + session.send(""); - session.conn:close(); - listener.ondisconnect(session.conn, (reason and (reason.text or reason.condition)) or reason or "session closed"); + function session.send() return false; end + + local reason = (reason and (reason.text or reason.condition)) or reason; + session.log("info", "c2s stream for %s closed: %s", session.full_jid or ("<"..session.ip..">"), reason or "session closed"); + + -- Authenticated incoming stream may still be sending us stanzas, so wait for from remote + local conn = session.conn; + if reason == nil and not session.notopen and session.type == "c2s" then + -- Grace time to process data from authenticated cleanly-closed stream + add_task(stream_close_timeout, function () + if not session.destroyed then + session.log("warn", "Failed to receive a stream close response, closing connection anyway..."); + sm_destroy_session(session, reason); + conn:close(); + end + end); + else + sm_destroy_session(session, reason); + conn:close(); + end end end +module:hook_global("user-deleted", function(event) + local username, host = event.username, event.host; + local user = hosts[host].sessions[username]; + if user and user.sessions then + for jid, session in pairs(user.sessions) do + session:close{ condition = "not-authorized", text = "Account deleted" }; + end + end +end, 200); + --- Port listener function listener.onconnect(conn) local session = sm_new_session(conn); @@ -159,6 +197,14 @@ function listener.onconnect(conn) -- Client is using legacy SSL (otherwise mod_tls sets this flag) if conn:ssl() then session.secure = true; + + -- Check if TLS compression is used + local sock = conn:socket(); + if sock.info then + session.compressed = sock:info"compression"; + elseif sock.compression then + session.compressed = sock:compression(); --COMPAT mw/luasec-hg + end end if opt_keepalives then @@ -209,10 +255,9 @@ end function listener.ondisconnect(conn, err) local session = sessions[conn]; if session then - (session.log or log)("info", "Client disconnected: %s", err); + (session.log or log)("info", "Client disconnected: %s", err or "connection closed"); sm_destroy_session(session, err); sessions[conn] = nil; - session = nil; end end @@ -220,7 +265,16 @@ function listener.associate_session(conn, session) sessions[conn] = session; end -module:add_item("net-provider", { +module:hook("server-stopping", function(event) + local reason = event.reason; + for _, session in pairs(sessions) do + session:close{ condition = "system-shutdown", text = reason }; + end +end, 1000); + + + +module:provides("net", { name = "c2s"; listener = listener; default_port = 5222; @@ -230,7 +284,7 @@ module:add_item("net-provider", { }; }); -module:add_item("net-provider", { +module:provides("net", { name = "legacy_ssl"; listener = listener; encryption = "ssl";