diff options
Diffstat (limited to 'core/sessionmanager.lua')
-rw-r--r-- | core/sessionmanager.lua | 72 |
1 files changed, 54 insertions, 18 deletions
diff --git a/core/sessionmanager.lua b/core/sessionmanager.lua index ad4ad0c9..e1f1a802 100644 --- a/core/sessionmanager.lua +++ b/core/sessionmanager.lua @@ -8,7 +8,7 @@ -local tonumber, tostring = tonumber, tostring; +local tonumber, tostring, setmetatable = tonumber, tostring, setmetatable; local ipairs, pairs, print, next= ipairs, pairs, print, next; local format = import("string", "format"); @@ -25,6 +25,7 @@ local rm_load_roster = require "core.rostermanager".load_roster; local config_get = require "core.configmanager".get; local nameprep = require "util.encodings".stringprep.nameprep; local resourceprep = require "util.encodings".stringprep.resourceprep; +local nodeprep = require "util.encodings".stringprep.nodeprep; local fire_event = require "core.eventmanager".fire_event; local add_task = require "util.timer".add_task; @@ -50,8 +51,8 @@ function new_session(conn) open_sessions = open_sessions + 1; log("debug", "open sessions now: ".. open_sessions); local w = conn.write; - session.send = function (t) w(tostring(t)); end - session.ip = conn.ip(); + session.send = function (t) w(conn, tostring(t)); end + session.ip = conn:ip(); local conn_name = "c2s"..tostring(conn):match("[a-f0-9]+$"); session.log = logger.init(conn_name); @@ -66,34 +67,51 @@ function new_session(conn) return session; end -local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed c2s session: %s", data); end +local resting_session = { -- Resting, not dead + destroyed = true; + type = "c2s_destroyed"; + close = function (session) + session.log("debug", "Attempt to close already-closed session"); + end; + }; resting_session.__index = resting_session; + +function retire_session(session) + local log = session.log or log; + for k in pairs(session) do + if k ~= "trace" and k ~= "log" and k ~= "id" then + session[k] = nil; + end + end + + function session.send(data) log("debug", "Discarding data sent to resting session: %s", tostring(data)); end + function session.data(data) log("debug", "Discarding data received from resting session: %s", tostring(data)); end + return setmetatable(session, resting_session); +end function destroy_session(session, err) (session.log or log)("info", "Destroying session for %s (%s@%s)", session.full_jid or "(unknown)", session.username or "(unknown)", session.host or "(unknown)"); + if session.destroyed then return; end -- Remove session/resource from user's session list if session.full_jid then - hosts[session.host].events.fire_event("resource-unbind", {session=session, error=err}); - hosts[session.host].sessions[session.username].sessions[session.resource] = nil; full_sessions[session.full_jid] = nil; - + if not next(hosts[session.host].sessions[session.username].sessions) then log("debug", "All resources of %s are now offline", session.username); hosts[session.host].sessions[session.username] = nil; bare_sessions[session.username..'@'..session.host] = nil; end + + hosts[session.host].events.fire_event("resource-unbind", {session=session, error=err}); end - for k in pairs(session) do - if k ~= "trace" then - session[k] = nil; - end - end - session.data = null_data_handler; + retire_session(session); end function make_authenticated(session, username) + username = nodeprep(username); + if not username or #username == 0 then return nil, "Invalid username"; end session.username = username; if session.type == "c2s_unauthed" then session.type = "c2s"; @@ -121,7 +139,7 @@ function bind_resource(session, resource) local sessions = hosts[session.host].sessions[session.username].sessions; local limit = config_get(session.host, "core", "max_resources") or 10; if #sessions >= limit then - return nil, "cancel", "conflict", "Resource limit reached; only "..limit.." resources allowed"; + return nil, "cancel", "resource-constraint", "Resource limit reached; only "..limit.." resources allowed"; end if sessions[resource] then -- Resource conflict @@ -159,7 +177,19 @@ function bind_resource(session, resource) hosts[session.host].sessions[session.username].sessions[resource] = session; full_sessions[session.full_jid] = session; - session.roster = rm_load_roster(session.username, session.host); + local err; + session.roster, err = rm_load_roster(session.username, session.host); + if err then + full_sessions[session.full_jid] = nil; + hosts[session.host].sessions[session.username].sessions[resource] = nil; + session.full_jid = nil; + session.resource = nil; + if next(bare_sessions[session.username..'@'..session.host].sessions) == nil then + bare_sessions[session.username..'@'..session.host] = nil; + hosts[session.host].sessions[session.username] = nil; + end + return nil, "cancel", "internal-server-error", "Error loading roster"; + end hosts[session.host].events.fire_event("resource-bind", {session=session}); @@ -168,7 +198,12 @@ end function streamopened(session, attr) local send = session.send; - session.host = attr.to or error("Client failed to specify destination hostname"); + session.host = attr.to; + if not session.host then + session:close{ condition = "improper-addressing", + text = "A 'to' attribute is required on stream headers" }; + return; + end session.host = nameprep(session.host); session.version = tonumber(attr.version) or 0; session.streamid = uuid_generate(); @@ -193,6 +228,7 @@ function streamopened(session, attr) end local features = st.stanza("stream:features"); + hosts[session.host].events.fire_event("stream-features", { origin = session, features = features }); fire_event("stream-features", session, features); send(features); @@ -200,8 +236,8 @@ function streamopened(session, attr) end function streamclosed(session) - session.send("</stream:stream>"); - session.notopen = true; + session.log("debug", "Received </stream:stream>"); + session:close(); end function send_to_available_resources(user, host, stanza) |