mod_posix: Move everything to util.startup
This allows greater control over the order of events.
Notably, the internal ordering between daemonization, initialization of
libunbound and setup of signal handling is sensitive.
libunbound starts a separate thread for processing DNS requests.
If this thread is started before signal handling has been set up, it
will not inherit the signal handlers and instead behave as it would have
before signal handlers were set up, i.e. cause the whole process to
immediately exit.
libunbound is usually initialized on the first DNS request, usually
triggered by an outgoing s2s connection attempt.
If daemonization happens before signals have been set up, signals may
not be processed at all.
module:set_global();
local have_unix, unix = pcall(require, "socket.unix");
if have_unix and type(unix) == "function" then
-- COMPAT #1717
-- Before the introduction of datagram support, only the stream socket
-- constructor was exported instead of a module table. Due to the lack of a
-- proper release of LuaSocket, distros have settled on shipping either the
-- last RC tag or some commit since then.
-- Here we accommodate both variants.
unix = { stream = unix };
end
if not have_unix or type(unix) ~= "table" then
module:log_status("error", "LuaSocket unix socket support not available or incompatible, ensure it is up to date");
return;
end
local server = require "prosody.net.server";
local adminstream = require "prosody.util.adminstream";
local st = require "prosody.util.stanza";
local socket_path = module:get_option_path("admin_socket", "prosody.sock", "data");
local sessions = module:shared("sessions");
local function fire_admin_event(session, stanza)
local event_data = {
origin = session, stanza = stanza;
};
local event_name;
if stanza.attr.xmlns then
event_name = "admin/"..stanza.attr.xmlns..":"..stanza.name;
else
event_name = "admin/"..stanza.name;
end
module:log("debug", "Firing %s", event_name);
local ret = module:fire_event(event_name, event_data);
if ret == nil then
session.send(st.stanza("repl-result", { type = "error" }):text("No module handled this query. Is mod_admin_shell enabled?"));
end
return ret;
end
module:hook("server-stopping", function ()
for _, session in pairs(sessions) do
session:close("system-shutdown");
end
os.remove(socket_path);
end);
--- Unix domain socket management
local conn, sock;
local listeners = adminstream.server(sessions, fire_admin_event).listeners;
local function accept_connection()
module:log("debug", "accepting...");
local client = sock:accept();
if not client then return; end
server.wrapclient(client, "unix", 0, listeners, "*a");
end
function module.load()
sock = unix.stream();
sock:settimeout(0);
os.remove(socket_path);
local ok, err = sock:bind(socket_path);
if not ok then
module:log_status("error", "Unable to bind admin socket %s: %s", socket_path, err);
return;
end
local ok, err = sock:listen();
if not ok then
module:log_status("error", "Unable to listen on admin socket %s: %s", socket_path, err);
return;
end
if server.wrapserver then
conn = server.wrapserver(sock, socket_path, 0, listeners);
else
conn = server.watchfd(sock:getfd(), accept_connection);
end
end
function module.unload()
if conn then
conn:close();
end
if sock then
sock:close();
end
os.remove(socket_path);
end