diff options
Diffstat (limited to 'net/server_epoll.lua')
-rw-r--r-- | net/server_epoll.lua | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/net/server_epoll.lua b/net/server_epoll.lua index fe60dc78..6c110241 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -29,11 +29,44 @@ local new_id = require "prosody.util.id".short; local xpcall = require "prosody.util.xpcall".xpcall; local sslconfig = require "prosody.util.sslconfig"; local tls_impl = require "prosody.net.tls_luasec"; +local have_signal, signal = pcall(require, "prosody.util.signal"); local poller = require "prosody.util.poll" local EEXIST = poller.EEXIST; local ENOENT = poller.ENOENT; +-- systemd socket activation +local SD_LISTEN_FDS_START = 3; +local SD_LISTEN_FDS = tonumber(os.getenv("LISTEN_FDS")) or 0; + +local inherited_sockets = setmetatable({}, { + __index = function(t, k) + local serv_mt = debug.getregistry()["tcp{server}"]; + for i = 1, SD_LISTEN_FDS do + local serv = socket.tcp(); + if serv:getfd() ~= _SOCKETINVALID then + -- If LuaSocket allocated a FD for then we can't really close it and it would leak. + log("error", "LuaSocket not compatible with socket activation. Upgrade LuaSocket or disable socket activation."); + setmetatable(t, nil); + break + end + serv:setfd(SD_LISTEN_FDS_START + i - 1); + debug.setmetatable(serv, serv_mt); + serv:settimeout(0); + local ip, port = serv:getsockname(); + t[ip .. ":" .. port] = serv; + if ip == "0.0.0.0" then + -- LuaSocket treats '*' as an alias for '0.0.0.0' + t["*:" .. port] = serv; + end + end + + -- Disable lazy-loading mechanism once performed + setmetatable(t, nil); + return t[k]; + end; +}); + local poll = assert(poller.new()); local _ENV = nil; @@ -630,30 +663,35 @@ end function interface:ssl_info() local sock = self.conn; + if not sock then return nil, "not-connected" end if not sock.info then return nil, "not-implemented"; end return sock:info(); end function interface:ssl_peercertificate() local sock = self.conn; + if not sock then return nil, "not-connected" end if not sock.getpeercertificate then return nil, "not-implemented"; end return sock:getpeercertificate(); end function interface:ssl_peerverification() local sock = self.conn; + if not sock then return nil, "not-connected" end if not sock.getpeerverification then return nil, { { "Chain verification not supported" } }; end return sock:getpeerverification(); end function interface:ssl_peerfinished() local sock = self.conn; + if not sock then return nil, "not-connected" end if not sock.getpeerfinished then return nil, "not-implemented"; end return sock:getpeerfinished(); end function interface:ssl_exportkeyingmaterial(label, len, context) local sock = self.conn; + if not sock then return nil, "not-connected" end if sock.exportkeyingmaterial then return sock:exportkeyingmaterial(label, len, context); end @@ -938,6 +976,14 @@ local function wrapserver(conn, addr, port, listeners, config) end local function listen(addr, port, listeners, config) + local inherited = inherited_sockets[addr .. ":" .. port]; + if inherited then + local conn = wrapserver(inherited, addr, port, listeners, config); + -- sockets created by systemd must not be :close() since we may not have + -- privileges to create them + conn.destroy = interface.del; + return conn; + end local conn, err = socket.bind(addr, port, cfg.tcp_backlog); if not conn then return conn, err; end conn:settimeout(0); @@ -1138,6 +1184,26 @@ local function loop(once) return quitting; end +local hook_signal; +if have_signal and signal.signalfd then + local function dispatch(self) + return self:on("signal", self.conn:read()); + end + + function hook_signal(signum, cb) + local sigfd = signal.signalfd(signum); + if not sigfd then + log("error", "Could not hook signal %d", signum); + return nil, "failed"; + end + local watch = watchfd(sigfd, dispatch); + watch.listeners = { onsignal = cb }; + watch.close = nil; -- revert to default + watch:noise("Signal handler %d ready", signum); + return watch; + end +end + return { get_backend = function () return "epoll"; end; addserver = addserver; @@ -1163,6 +1229,7 @@ return { set_config = function (newconfig) cfg = setmetatable(newconfig, default_config); end; + hook_signal = hook_signal; tls_builder = function(basedir) return sslconfig._new(tls_impl.new_context, basedir) |