IMPORTANT: due to a drive failure, as of 13-Mar-2021, the Mercurial repository had to be re-mirrored, which changed every commit SHA. The old SHAs and trees are backed up in the vault branches. Please migrate to the new branches as soon as you can.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
prosody/core/sessionmanager.lua

120 lines
3.8 KiB

local tonumber, tostring = tonumber, tostring;
local ipairs, pairs, print= ipairs, pairs, print;
local collectgarbage = collectgarbage;
local m_random = import("math", "random");
local format = import("string", "format");
local hosts = hosts;
local sessions = sessions;
local modulemanager = require "core.modulemanager";
local log = require "util.logger".init("sessionmanager");
local error = error;
local uuid_generate = require "util.uuid".uuid_generate;
local newproxy = newproxy;
local getmetatable = getmetatable;
module "sessionmanager"
function new_session(conn)
local session = { conn = conn, notopen = true, priority = 0, type = "c2s_unauthed" };
if true then
session.trace = newproxy(true);
getmetatable(session.trace).__gc = function () print("Session got collected") end;
end
local w = conn.write;
session.send = function (t) w(tostring(t)); end
return session;
end
function destroy_session(session)
if not (session and session.disconnect) then return; end
log("debug", "Destroying session...");
session.disconnect();
if session.username then
if session.resource then
hosts[session.host].sessions[session.username].sessions[session.resource] = nil;
end
local nomore = true;
for res, ssn in pairs(hosts[session.host].sessions[session.username]) do
nomore = false;
end
if nomore then
hosts[session.host].sessions[session.username] = nil;
end
end
session.conn = nil;
session.disconnect = nil;
for k in pairs(session) do
if k ~= "trace" then
session[k] = nil;
end
end
collectgarbage("collect");
collectgarbage("collect");
collectgarbage("collect");
collectgarbage("collect");
collectgarbage("collect");
end
function send_to_session(session, data)
log("debug", "Sending: %s", tostring(data));
session.conn.write(tostring(data));
end
function make_authenticated(session, username)
session.username = username;
if session.type == "c2s_unauthed" then
session.type = "c2s";
end
return true;
end
function bind_resource(session, resource)
if not session.username then return false, "auth"; end
if session.resource then return false, "constraint"; end -- We don't support binding multiple resources
resource = resource or uuid_generate();
--FIXME: Randomly-generated resources must be unique per-user, and never conflict with existing
if not hosts[session.host].sessions[session.username] then
hosts[session.host].sessions[session.username] = { sessions = {} };
else
if hosts[session.host].sessions[session.username].sessions[resource] then
-- Resource conflict
return false, "conflict";
end
end
session.resource = resource;
session.full_jid = session.username .. '@' .. session.host .. '/' .. resource;
hosts[session.host].sessions[session.username].sessions[resource] = session;
return true;
end
function streamopened(session, attr)
local send = session.send;
session.host = attr.to or error("Client failed to specify destination hostname");
session.version = tonumber(attr.version) or 0;
session.streamid = m_random(1000000, 99999999);
print(session, session.host, "Client opened stream");
send("<?xml version='1.0'?>");
send(format("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='%s' from='%s' version='1.0'>", session.streamid, session.host));
local features = {};
modulemanager.fire_event("stream-features", session, features);
send("<stream:features>");
for _, feature in ipairs(features) do
send_to_session(session, tostring(feature));
end
send("</stream:features>");
log("info", "Stream opened successfully");
session.notopen = nil;
end
return _M;