aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/modulemanager.lua42
-rw-r--r--core/servermanager.lua14
-rw-r--r--core/sessionmanager.lua73
-rw-r--r--core/usermanager.lua2
-rw-r--r--core/xmlhandlers.lua32
5 files changed, 130 insertions, 33 deletions
diff --git a/core/modulemanager.lua b/core/modulemanager.lua
index ad92b41b..6d803a26 100644
--- a/core/modulemanager.lua
+++ b/core/modulemanager.lua
@@ -4,6 +4,7 @@ local log = require "util.logger".init("modulemanager")
local loadfile, pcall = loadfile, pcall;
local setmetatable, setfenv, getfenv = setmetatable, setfenv, getfenv;
local pairs, ipairs = pairs, ipairs;
+local t_insert = table.insert;
local type = type;
local tostring, print = tostring, print;
@@ -18,6 +19,7 @@ local handlers = {};
local modulehelpers = setmetatable({}, { __index = _G });
function modulehelpers.add_iq_handler(origin_type, xmlns, handler)
+ if not (origin_type and handler and xmlns) then return false; end
handlers[origin_type] = handlers[origin_type] or {};
handlers[origin_type].iq = handlers[origin_type].iq or {};
if not handlers[origin_type].iq[xmlns] then
@@ -29,17 +31,19 @@ function modulehelpers.add_iq_handler(origin_type, xmlns, handler)
end
end
-function modulehelpers.add_handler(origin_type, tag, handler)
+function modulehelpers.add_handler(origin_type, tag, xmlns, handler)
+ if not (origin_type and tag and xmlns and handler) then return false; end
handlers[origin_type] = handlers[origin_type] or {};
if not handlers[origin_type][tag] then
- handlers[origin_type][tag]= handler;
+ handlers[origin_type][tag] = handlers[origin_type][tag] or {};
+ handlers[origin_type][tag][xmlns]= handler;
handler_info[handler] = getfenv(2).module;
log("debug", "mod_%s now handles tag '%s'", getfenv(2).module.name, tag);
elseif handler_info[handlers[origin_type][tag]] then
log("warning", "mod_%s wants to handle tag '%s' but mod_%s already handles that", getfenv(2).module.name, tag, handler_info[handlers[origin_type][tag]].module.name);
end
end
-
+
function loadall()
load("saslauth");
load("legacyauth");
@@ -79,14 +83,38 @@ function handle_stanza(origin, stanza)
end
end
- --FIXME: All iq's must be replied to, here we should return service-unavailable I think
elseif handlers[origin_type] then
local handler = handlers[origin_type][name];
if handler then
- log("debug", "Passing stanza to mod_%s", handler_info[handler].name);
- return handler(origin, stanza) or true;
+ handler = handler[xmlns];
+ if handler then
+ log("debug", "Passing stanza to mod_%s", handler_info[handler].name);
+ return handler(origin, stanza) or true;
+ end
end
end
- log("debug", "Stanza unhandled by any modules");
+ log("debug", "Stanza unhandled by any modules, xmlns: %s", stanza.attr.xmlns);
return false; -- we didn't handle it
end
+
+do
+ local event_handlers = {};
+
+ function modulehelpers.add_event_hook(name, handler)
+ if not event_handlers[name] then
+ event_handlers[name] = {};
+ end
+ t_insert(event_handlers[name] , handler);
+ end
+
+ function fire_event(name, ...)
+ local event_handlers = event_handlers[name];
+ if event_handlers then
+ for name, handler in ipairs(event_handlers) do
+ handler(...);
+ end
+ end
+ end
+end
+
+return _M;
diff --git a/core/servermanager.lua b/core/servermanager.lua
index 02ccab53..c1e075db 100644
--- a/core/servermanager.lua
+++ b/core/servermanager.lua
@@ -1,8 +1,20 @@
+local st = require "util.stanza";
+local send = require "core.sessionmanager".send_to_session;
+local xmlns_stanzas ='urn:ietf:params:xml:ns:xmpp-stanzas';
+
require "modulemanager"
-- Handle stanzas that were addressed to the server (whether they came from c2s, s2s, etc.)
function handle_stanza(origin, stanza)
-- Use plugins
- return modulemanager.handle_stanza(origin, stanza);
+ if not modulemanager.handle_stanza(origin, stanza) then
+ if stanza.name == "iq" then
+ local reply = st.reply(stanza);
+ reply.attr.type = "error";
+ reply:tag("error", { type = "cancel" })
+ :tag("service-unavailable", { xmlns = xmlns_stanzas });
+ send(origin, reply);
+ end
+ end
end
diff --git a/core/sessionmanager.lua b/core/sessionmanager.lua
index e89de262..a7a9ff10 100644
--- a/core/sessionmanager.lua
+++ b/core/sessionmanager.lua
@@ -1,22 +1,62 @@
-local tostring = tostring;
-
-local print = print;
+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)
@@ -26,16 +66,16 @@ end
function make_authenticated(session, username)
session.username = username;
- session.resource = resource;
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 math.random(100000, 99999999); -- FIXME: Clearly we have issues :)
+ 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
@@ -54,4 +94,27 @@ function bind_resource(session, resource)
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; \ No newline at end of file
diff --git a/core/usermanager.lua b/core/usermanager.lua
index a67ad368..0f303b24 100644
--- a/core/usermanager.lua
+++ b/core/usermanager.lua
@@ -1,10 +1,12 @@
require "util.datamanager"
local datamanager = datamanager;
+local log = require "util.logger".init("usermanager");
module "usermanager"
function validate_credentials(host, username, password)
+ log("debug", "User '%s' is being validated", username);
local credentials = datamanager.load(username, host, "accounts") or {};
if password == credentials.password then return true; end
return false;
diff --git a/core/xmlhandlers.lua b/core/xmlhandlers.lua
index b6050c5a..ebc8f91d 100644
--- a/core/xmlhandlers.lua
+++ b/core/xmlhandlers.lua
@@ -1,4 +1,5 @@
+local sessionmanager_streamopened = require "core.sessionmanager".streamopened;
require "util.stanza"
local st = stanza;
@@ -9,6 +10,7 @@ local t_insert = table.insert;
local t_remove = table.remove;
local t_concat = table.concat;
local t_concatall = function (t, sep) local tt = {}; for _, s in ipairs(t) do t_insert(tt, tostring(s)); end return t_concat(tt, sep); end
+local sm_destroy_session = import("core.sessionmanager", "destroy_session");
local error = error;
@@ -27,7 +29,6 @@ function init_xmlhandlers(session)
local stanza
function xml_handlers:StartElement(name, attr)
- log("info", "xmlhandlers", "Start element: " .. name);
if stanza and #chardata > 0 then
-- We have some character data in the buffer
stanza:text(t_concat(chardata));
@@ -37,24 +38,7 @@ function init_xmlhandlers(session)
if not stanza then
if session.notopen then
if name == "stream" then
- session.host = attr.to or error("Client failed to specify destination hostname");
- session.version = 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));
- send("<stream:features>");
- if not session.username then
- send("<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>");
- send("<mechanism>PLAIN</mechanism>");
- send("</mechanisms>");
- else
- send("<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><required/></bind>");
- end
- --send [[<register xmlns="http://jabber.org/features/iq-register"/> ]]
- send("</stream:features>");
- log("info", "core", "Stream opened successfully");
- session.notopen = nil;
+ sessionmanager_streamopened(session, attr);
return;
end
error("Client failed to open stream successfully");
@@ -77,7 +61,15 @@ function init_xmlhandlers(session)
end
function xml_handlers:EndElement(name)
curr_ns,name = name:match("^(.+):(%w+)$");
- if (not stanza) or #stanza.last_add < 0 or (#stanza.last_add > 0 and name ~= stanza.last_add[#stanza.last_add].name) then error("XML parse error in client stream"); end
+ if (not stanza) or #stanza.last_add < 0 or (#stanza.last_add > 0 and name ~= stanza.last_add[#stanza.last_add].name) then
+ if name == "stream" then
+ log("debug", "Stream closed");
+ sm_destroy_session(session);
+ return;
+ else
+ error("XML parse error in client stream");
+ end
+ end
if stanza and #chardata > 0 then
-- We have some character data in the buffer
stanza:text(t_concat(chardata));