aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES1
-rw-r--r--GNUmakefile43
-rw-r--r--core/certmanager.lua2
-rw-r--r--core/portmanager.lua4
-rw-r--r--makefile47
-rw-r--r--plugins/mod_c2s.lua4
-rw-r--r--plugins/mod_carbons.lua10
-rw-r--r--plugins/mod_mam/mod_mam.lua19
-rw-r--r--plugins/mod_s2s.lua4
-rw-r--r--teal-src/util/poll.d.tl9
-rw-r--r--util-src/poll.c172
-rw-r--r--util/async.lua4
-rw-r--r--util/prosodyctl/check.lua84
13 files changed, 351 insertions, 52 deletions
diff --git a/CHANGES b/CHANGES
index 8e3a556c..69dad49b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -58,6 +58,7 @@ TRUNK
- MUC: support for XEP-0421 occupant identifiers
- `prosodyctl check connectivity` via observe.jabber.network
- libunbound for DNS queries
+- The POSIX poll() API used by server_epoll on \*nix other than Linux
## Changes
diff --git a/GNUmakefile b/GNUmakefile
index 829a1c3e..e9ec78c4 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -31,23 +31,36 @@ ifeq ($(EXCERTS),yes)
-$(MAKE) -C certs localhost.crt example.com.crt
endif
-CMODULES=util/encodings.so util/encodings.so util/pposix.so util/signal.so util/struct.so
-
-install: prosody.install prosodyctl.install prosody.cfg.lua.install $(CMODULES)
- $(MKDIR) $(BIN) $(CONFIG) $(MODULES) $(SOURCE)
- $(MKDIR_PRIVATE) $(DATA)
- $(MKDIR) $(MAN)/man1
+install-etc: prosody.cfg.lua.install
+ $(MKDIR) $(CONFIG)
$(MKDIR) $(CONFIG)/certs
- $(MKDIR) $(SOURCE)/core $(SOURCE)/net $(SOURCE)/util
+ $(INSTALL_DATA) certs/* $(CONFIG)/certs
+ test -f $(CONFIG)/prosody.cfg.lua || $(INSTALL_DATA) prosody.cfg.lua.install $(CONFIG)/prosody.cfg.lua
+
+install-bin: prosody.install prosodyctl.install
+ $(MKDIR) $(BIN)
$(INSTALL_EXEC) ./prosody.install $(BIN)/prosody
$(INSTALL_EXEC) ./prosodyctl.install $(BIN)/prosodyctl
+
+install-core:
+ $(MKDIR) $(SOURCE)
+ $(MKDIR) $(SOURCE)/core
$(INSTALL_DATA) core/*.lua $(SOURCE)/core
+
+install-net:
+ $(MKDIR) $(SOURCE)
+ $(MKDIR) $(SOURCE)/net
$(INSTALL_DATA) net/*.lua $(SOURCE)/net
$(MKDIR) $(SOURCE)/net/http $(SOURCE)/net/resolvers $(SOURCE)/net/websocket
$(INSTALL_DATA) net/http/*.lua $(SOURCE)/net/http
$(INSTALL_DATA) net/resolvers/*.lua $(SOURCE)/net/resolvers
$(INSTALL_DATA) net/websocket/*.lua $(SOURCE)/net/websocket
+
+install-util: util/encodings.so util/encodings.so util/pposix.so util/signal.so util/struct.so
+ $(MKDIR) $(SOURCE)
+ $(MKDIR) $(SOURCE)/util
$(INSTALL_DATA) util/*.lua $(SOURCE)/util
+ $(MAKE) install -C util-src
$(INSTALL_DATA) util/*.so $(SOURCE)/util
$(MKDIR) $(SOURCE)/util/sasl
$(INSTALL_DATA) util/sasl/*.lua $(SOURCE)/util/sasl
@@ -55,17 +68,27 @@ install: prosody.install prosodyctl.install prosody.cfg.lua.install $(CMODULES)
$(INSTALL_DATA) util/human/*.lua $(SOURCE)/util/human
$(MKDIR) $(SOURCE)/util/prosodyctl
$(INSTALL_DATA) util/prosodyctl/*.lua $(SOURCE)/util/prosodyctl
+
+install-plugins:
+ $(MKDIR) $(MODULES)
$(MKDIR) $(MODULES)/mod_pubsub $(MODULES)/adhoc $(MODULES)/muc $(MODULES)/mod_mam
$(INSTALL_DATA) plugins/*.lua $(MODULES)
$(INSTALL_DATA) plugins/mod_pubsub/*.lua $(MODULES)/mod_pubsub
$(INSTALL_DATA) plugins/adhoc/*.lua $(MODULES)/adhoc
$(INSTALL_DATA) plugins/muc/*.lua $(MODULES)/muc
$(INSTALL_DATA) plugins/mod_mam/*.lua $(MODULES)/mod_mam
- $(INSTALL_DATA) certs/* $(CONFIG)/certs
+
+install-man:
+ $(MKDIR) $(MAN)/man1
$(INSTALL_DATA) man/prosodyctl.man $(MAN)/man1/prosodyctl.1
- test -f $(CONFIG)/prosody.cfg.lua || $(INSTALL_DATA) prosody.cfg.lua.install $(CONFIG)/prosody.cfg.lua
+
+install-meta:
-test -f prosody.version && $(INSTALL_DATA) prosody.version $(SOURCE)/prosody.version
- $(MAKE) install -C util-src
+
+install-data:
+ $(MKDIR_PRIVATE) $(DATA)
+
+install: install-util install-net install-core install-plugins install-bin install-etc install-man install-meta install-data
clean:
rm -f prosody.install
diff --git a/core/certmanager.lua b/core/certmanager.lua
index 2585716f..c193e824 100644
--- a/core/certmanager.lua
+++ b/core/certmanager.lua
@@ -120,7 +120,7 @@ local function index_certs(dir, files_by_name, depth_limit)
if f then
-- TODO look for chained certificates
local firstline = f:read();
- if firstline == "-----BEGIN CERTIFICATE-----" then
+ if firstline == "-----BEGIN CERTIFICATE-----" and lfs.attributes(find_matching_key(full), "mode") == "file" then
f:seek("set")
local cert = ssl.loadcertificate(f:read("*a"))
-- TODO if more than one cert is found for a name, the most recently
diff --git a/core/portmanager.lua b/core/portmanager.lua
index 95d42b77..38c74b66 100644
--- a/core/portmanager.lua
+++ b/core/portmanager.lua
@@ -216,7 +216,9 @@ function close(interface, port)
end
function get_service_at(interface, port)
- local data = active_services:search(nil, interface, port)[1][1];
+ local data = active_services:search(nil, interface, port);
+ if not data or not data[1] or not data[1][1] then return nil, "not-found"; end
+ data = data[1][1];
return data.service, data.server;
end
diff --git a/makefile b/makefile
index a1dd1579..cd6340b7 100644
--- a/makefile
+++ b/makefile
@@ -30,21 +30,39 @@ all: prosody.install prosodyctl.install prosody.cfg.lua.install prosody.version
$(MAKE) -C certs localhost.crt example.com.crt
.endif
-install: prosody.install prosodyctl.install prosody.cfg.lua.install util/encodings.so util/encodings.so util/pposix.so util/signal.so
- $(MKDIR) $(BIN) $(CONFIG) $(MODULES) $(SOURCE)
- $(MKDIR_PRIVATE) $(DATA)
- $(MKDIR) $(MAN)/man1
+install-etc: prosody.cfg.lua.install
+ $(MKDIR) $(CONFIG)
$(MKDIR) $(CONFIG)/certs
- $(MKDIR) $(SOURCE)/core $(SOURCE)/net $(SOURCE)/util
+ test -f $(CONFIG)/prosody.cfg.lua || $(INSTALL_DATA) prosody.cfg.lua.install $(CONFIG)/prosody.cfg.lua
+.if $(EXCERTS) == "yes"
+ $(INSTALL_DATA) certs/localhost.crt certs/localhost.key $(CONFIG)/certs
+ $(INSTALL_DATA) certs/example.com.crt certs/example.com.key $(CONFIG)/certs
+.endif
+
+install-bin: prosody.install prosodyctl.install
+ $(MKDIR) $(BIN)
$(INSTALL_EXEC) ./prosody.install $(BIN)/prosody
$(INSTALL_EXEC) ./prosodyctl.install $(BIN)/prosodyctl
+
+install-core:
+ $(MKDIR) $(SOURCE)
+ $(MKDIR) $(SOURCE)/core
$(INSTALL_DATA) core/*.lua $(SOURCE)/core
+
+install-net:
+ $(MKDIR) $(SOURCE)
+ $(MKDIR) $(SOURCE)/net
$(INSTALL_DATA) net/*.lua $(SOURCE)/net
$(MKDIR) $(SOURCE)/net/http $(SOURCE)/net/resolvers $(SOURCE)/net/websocket
$(INSTALL_DATA) net/http/*.lua $(SOURCE)/net/http
$(INSTALL_DATA) net/resolvers/*.lua $(SOURCE)/net/resolvers
$(INSTALL_DATA) net/websocket/*.lua $(SOURCE)/net/websocket
+
+install-util: util/encodings.so util/encodings.so util/pposix.so util/signal.so
+ $(MKDIR) $(SOURCE)
+ $(MKDIR) $(SOURCE)/util
$(INSTALL_DATA) util/*.lua $(SOURCE)/util
+ $(MAKE) install -C util-src
$(INSTALL_DATA) util/*.so $(SOURCE)/util
$(MKDIR) $(SOURCE)/util/sasl
$(INSTALL_DATA) util/sasl/*.lua $(SOURCE)/util/sasl
@@ -52,20 +70,27 @@ install: prosody.install prosodyctl.install prosody.cfg.lua.install util/encodin
$(INSTALL_DATA) util/human/*.lua $(SOURCE)/util/human
$(MKDIR) $(SOURCE)/util/prosodyctl
$(INSTALL_DATA) util/prosodyctl/*.lua $(SOURCE)/util/prosodyctl
+
+install-plugins:
+ $(MKDIR) $(MODULES)
$(MKDIR) $(MODULES)/mod_pubsub $(MODULES)/adhoc $(MODULES)/muc $(MODULES)/mod_mam
$(INSTALL_DATA) plugins/*.lua $(MODULES)
$(INSTALL_DATA) plugins/mod_pubsub/*.lua $(MODULES)/mod_pubsub
$(INSTALL_DATA) plugins/adhoc/*.lua $(MODULES)/adhoc
$(INSTALL_DATA) plugins/muc/*.lua $(MODULES)/muc
$(INSTALL_DATA) plugins/mod_mam/*.lua $(MODULES)/mod_mam
-.if $(EXCERTS) == "yes"
- $(INSTALL_DATA) certs/localhost.crt certs/localhost.key $(CONFIG)/certs
- $(INSTALL_DATA) certs/example.com.crt certs/example.com.key $(CONFIG)/certs
-.endif
+
+install-man:
+ $(MKDIR) $(MAN)/man1
$(INSTALL_DATA) man/prosodyctl.man $(MAN)/man1/prosodyctl.1
- test -f $(CONFIG)/prosody.cfg.lua || $(INSTALL_DATA) prosody.cfg.lua.install $(CONFIG)/prosody.cfg.lua
+
+install-meta:
-test -f prosody.version && $(INSTALL_DATA) prosody.version $(SOURCE)/prosody.version
- $(MAKE) install -C util-src
+
+install-data:
+ $(MKDIR_PRIVATE) $(DATA)
+
+install: install-util install-net install-core install-plugins install-bin install-etc install-man install-meta install-data
clean:
rm -f prosody.install
diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua
index 33fd7a0a..c8f54fa7 100644
--- a/plugins/mod_c2s.lua
+++ b/plugins/mod_c2s.lua
@@ -433,7 +433,7 @@ module:hook("server-stopping", function(event) -- luacheck: ignore 212/event
end, -80);
module:hook("server-stopping", function(event)
- local wait, done = async.waiter();
+ local wait, done = async.waiter(1, true);
module:hook("c2s-closed", function ()
if next(sessions) == nil then done(); end
end)
@@ -446,7 +446,7 @@ module:hook("server-stopping", function(event)
-- Wait for them to close properly if they haven't already
if next(sessions) ~= nil then
- add_task(stream_close_timeout+1, done);
+ add_task(stream_close_timeout+1, function () done() end);
module:log("info", "Waiting for sessions to close");
wait();
end
diff --git a/plugins/mod_carbons.lua b/plugins/mod_carbons.lua
index 5b0bdeb7..7a5b757c 100644
--- a/plugins/mod_carbons.lua
+++ b/plugins/mod_carbons.lua
@@ -69,6 +69,12 @@ local function should_copy(stanza, c2s, user_bare) --> boolean, reason: string
return false, "default";
end
+module:hook("carbons-should-copy", function (event)
+ local should, why = should_copy(event.stanza);
+ event.reason = why;
+ return should;
+end, -1)
+
local function message_handler(event, c2s)
local origin, stanza = event.origin, event.stanza;
local orig_type = stanza.attr.type or "normal";
@@ -101,7 +107,9 @@ local function message_handler(event, c2s)
return -- No use in sending carbons to an offline user
end
- local should, why = should_copy(stanza, c2s, bare_jid);
+ local event_payload = { stanza = stanza; session = origin };
+ local should = module:fire_event("carbons-should-copy", event_payload);
+ local why = event_payload.reason;
if not should then
module:log("debug", "Not copying stanza: %s (%s)", stanza:top_tag(), why);
diff --git a/plugins/mod_mam/mod_mam.lua b/plugins/mod_mam/mod_mam.lua
index d4b2b060..50095e2f 100644
--- a/plugins/mod_mam/mod_mam.lua
+++ b/plugins/mod_mam/mod_mam.lua
@@ -54,7 +54,7 @@ end
local use_total = module:get_option_boolean("mam_include_total", true);
function schedule_cleanup()
- -- replaced by non-noop later if cleanup is enabled
+ -- replaced later if cleanup is enabled
end
-- Handle prefs.
@@ -311,7 +311,7 @@ local function strip_stanza_id(stanza, user)
return stanza;
end
-local function should_store(stanza, c2s) --> boolean, reason: string
+local function should_store(stanza) --> boolean, reason: string
local st_type = stanza.attr.type or "normal";
-- FIXME pass direction of stanza and use that along with bare/full JID addressing
-- for more accurate MUC / type=groupchat check
@@ -320,7 +320,7 @@ local function should_store(stanza, c2s) --> boolean, reason: string
-- Headline messages are ephemeral by definition
return false, "headline";
end
- if st_type == "error" and not c2s then
+ if st_type == "error" then
-- Errors not sent sent from a local client
-- Why would a client send an error anyway?
if jid_resource(stanza.attr.to) then
@@ -380,6 +380,12 @@ local function should_store(stanza, c2s) --> boolean, reason: string
return false, "default";
end
+module:hook("archive-should-store", function (event)
+ local should, why = should_store(event.stanza);
+ event.reason = why;
+ return should;
+end, -1)
+
-- Handle messages
local function message_handler(event, c2s)
local origin, stanza = event.origin, event.stanza;
@@ -396,9 +402,12 @@ local function message_handler(event, c2s)
-- Filter out <stanza-id> that claim to be from us
event.stanza = strip_stanza_id(stanza, store_user);
- local should, why = should_store(stanza, c2s);
+ local event_payload = { stanza = stanza; session = origin };
+ local should = module:fire_event("archive-should-store", event_payload);
+ local why = event_payload.reason;
+
if not should then
- log("debug", "Not archiving stanza: %s (%s)", stanza:top_tag(), why);
+ log("debug", "Not archiving stanza: %s (%s)", stanza:top_tag(), event_payload.reason);
return;
end
diff --git a/plugins/mod_s2s.lua b/plugins/mod_s2s.lua
index 655cb599..3ad0f521 100644
--- a/plugins/mod_s2s.lua
+++ b/plugins/mod_s2s.lua
@@ -973,7 +973,7 @@ module:hook("server-stopping", function(event)
end
end
- local wait, done = async.waiter();
+ local wait, done = async.waiter(1, true);
module:hook("s2s-closed", function ()
if next(sessions) == nil then done(); end
end, 1)
@@ -987,7 +987,7 @@ module:hook("server-stopping", function(event)
-- Wait for them to close properly if they haven't already
if next(sessions) ~= nil then
module:log("info", "Waiting for sessions to close");
- add_task(stream_close_timeout + 1, done);
+ add_task(stream_close_timeout + 1, function () done() end);
wait();
end
diff --git a/teal-src/util/poll.d.tl b/teal-src/util/poll.d.tl
index 7e346161..8df56d57 100644
--- a/teal-src/util/poll.d.tl
+++ b/teal-src/util/poll.d.tl
@@ -17,8 +17,15 @@ end
local record lib
new : function () : state
- ENOENT : integer
EEXIST : integer
+ EMFILE : integer
+ ENOENT : integer
+ enum api_backend
+ "epoll"
+ "poll"
+ "select"
+ end
+ api : api_backend
end
return lib
diff --git a/util-src/poll.c b/util-src/poll.c
index 6c6a4e63..81caa953 100644
--- a/util-src/poll.c
+++ b/util-src/poll.c
@@ -1,7 +1,7 @@
/*
* Lua polling library
- * Copyright (C) 2017-2018 Kim Alvefur
+ * Copyright (C) 2017-2022 Kim Alvefur
*
* This project is MIT licensed. Please see the
* COPYING file in the source package for more information.
@@ -12,8 +12,15 @@
#include <string.h>
#include <errno.h>
-#ifdef __linux__
+#if defined(__linux__)
#define USE_EPOLL
+#define POLL_BACKEND "epoll"
+#elif defined(__unix__)
+#define USE_POLL
+#define POLL_BACKEND "poll"
+#else
+#define USE_SELECT
+#define POLL_BACKEND "select"
#endif
#ifdef USE_EPOLL
@@ -21,18 +28,21 @@
#ifndef MAX_EVENTS
#define MAX_EVENTS 64
#endif
-#else
+#endif
+#ifdef USE_POLL
+#include <poll.h>
+#ifndef MAX_EVENTS
+#define MAX_EVENTS 10000
+#endif
+#endif
+#ifdef USE_SELECT
#include <sys/select.h>
#endif
#include <lualib.h>
#include <lauxlib.h>
-#ifdef USE_EPOLL
-#define STATE_MT "util.poll<epoll>"
-#else
-#define STATE_MT "util.poll<select>"
-#endif
+#define STATE_MT "util.poll<" POLL_BACKEND ">"
#if (LUA_VERSION_NUM == 501)
#define luaL_setmetatable(L, tname) luaL_getmetatable(L, tname); lua_setmetatable(L, -2)
@@ -49,7 +59,12 @@ typedef struct Lpoll_state {
#ifdef USE_EPOLL
int epoll_fd;
struct epoll_event events[MAX_EVENTS];
-#else
+#endif
+#ifdef USE_POLL
+ nfds_t count;
+ struct pollfd events[MAX_EVENTS];
+#endif
+#ifdef USE_SELECT
fd_set wantread;
fd_set wantwrite;
fd_set readable;
@@ -96,7 +111,34 @@ static int Ladd(lua_State *L) {
lua_pushboolean(L, 1);
return 1;
-#else
+#endif
+#ifdef USE_POLL
+
+ for(nfds_t i = 0; i < state->count; i++) {
+ if(state->events[i].fd == fd) {
+ luaL_pushfail(L);
+ lua_pushstring(L, strerror(EEXIST));
+ lua_pushinteger(L, EEXIST);
+ return 3;
+ }
+ }
+
+ if(state->count >= MAX_EVENTS) {
+ luaL_pushfail(L);
+ lua_pushstring(L, strerror(EMFILE));
+ lua_pushinteger(L, EMFILE);
+ return 3;
+ }
+
+ state->events[state->count].fd = fd;
+ state->events[state->count].events = (wantread ? POLLIN : 0) | (wantwrite ? POLLOUT : 0);
+ state->events[state->count].revents = 0;
+ state->count++;
+
+ lua_pushboolean(L, 1);
+ return 1;
+#endif
+#ifdef USE_SELECT
if(fd > FD_SETSIZE) {
luaL_pushfail(L);
@@ -169,7 +211,29 @@ static int Lset(lua_State *L) {
return 3;
}
-#else
+#endif
+#ifdef USE_POLL
+ int wantread = lua_toboolean(L, 3);
+ int wantwrite = lua_toboolean(L, 4);
+
+ for(nfds_t i = 0; i < state->count; i++) {
+ struct pollfd *event = &state->events[i];
+
+ if(event->fd == fd) {
+ event->events = (wantread ? POLLIN : 0) | (wantwrite ? POLLOUT : 0);
+ lua_pushboolean(L, 1);
+ return 1;
+ } else if(event->fd == -1) {
+ break;
+ }
+ }
+
+ luaL_pushfail(L);
+ lua_pushstring(L, strerror(ENOENT));
+ lua_pushinteger(L, ENOENT);
+ return 3;
+#endif
+#ifdef USE_SELECT
if(!FD_ISSET(fd, &state->all)) {
luaL_pushfail(L);
@@ -227,7 +291,42 @@ static int Ldel(lua_State *L) {
return 3;
}
-#else
+#endif
+#ifdef USE_POLL
+
+ if(state->count == 0) {
+ luaL_pushfail(L);
+ lua_pushstring(L, strerror(ENOENT));
+ lua_pushinteger(L, ENOENT);
+ return 3;
+ }
+
+ /*
+ * Move the last item on top of the removed one
+ */
+ struct pollfd *last = &state->events[state->count - 1];
+
+ for(nfds_t i = 0; i < state->count; i++) {
+ struct pollfd *event = &state->events[i];
+
+ if(event->fd == fd) {
+ event->fd = last->fd;
+ event->events = last->events;
+ event->revents = last->revents;
+ last->fd = -1;
+ state->count--;
+
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ }
+
+ luaL_pushfail(L);
+ lua_pushstring(L, strerror(ENOENT));
+ lua_pushinteger(L, ENOENT);
+ return 3;
+#endif
+#ifdef USE_SELECT
if(!FD_ISSET(fd, &state->all)) {
luaL_pushfail(L);
@@ -264,7 +363,24 @@ static int Lpushevent(lua_State *L, struct Lpoll_state *state) {
return 3;
}
-#else
+#endif
+#ifdef USE_POLL
+
+ for(int i = state->processed - 1; i >= 0; i--) {
+ struct pollfd *event = &state->events[i];
+
+ if(event->fd != -1 && event->revents != 0) {
+ lua_pushinteger(L, event->fd);
+ lua_pushboolean(L, event->revents & (POLLIN | POLLHUP | POLLERR));
+ lua_pushboolean(L, event->revents & POLLOUT);
+ event->revents = 0;
+ state->processed = i;
+ return 3;
+ }
+ }
+
+#endif
+#ifdef USE_SELECT
for(int fd = state->processed + 1; fd < FD_SETSIZE; fd++) {
if(FD_ISSET(fd, &state->readable) || FD_ISSET(fd, &state->writable) || FD_ISSET(fd, &state->err)) {
@@ -300,7 +416,11 @@ static int Lwait(lua_State *L) {
#ifdef USE_EPOLL
ret = epoll_wait(state->epoll_fd, state->events, MAX_EVENTS, timeout * 1000);
-#else
+#endif
+#ifdef USE_POLL
+ ret = poll(state->events, state->count, timeout * 1000);
+#endif
+#ifdef USE_SELECT
/*
* select(2) mutates the fd_sets passed to it so in order to not
* have to recreate it manually every time a copy is made.
@@ -341,7 +461,11 @@ static int Lwait(lua_State *L) {
*/
#ifdef USE_EPOLL
state->processed = ret;
-#else
+#endif
+#ifdef USE_POLL
+ state->processed = state->count;
+#endif
+#ifdef USE_SELECT
state->processed = -1;
#endif
return Lpushevent(L, state);
@@ -411,7 +535,19 @@ static int Lnew(lua_State *L) {
}
state->epoll_fd = epoll_fd;
-#else
+#endif
+#ifdef USE_POLL
+ state->processed = -1;
+ state->count = 0;
+
+ for(nfds_t i = 0; i < MAX_EVENTS; i++) {
+ state->events[i].fd = -1;
+ state->events[i].events = 0;
+ state->events[i].revents = 0;
+ }
+
+#endif
+#ifdef USE_SELECT
FD_ZERO(&state->wantread);
FD_ZERO(&state->wantwrite);
FD_ZERO(&state->readable);
@@ -473,8 +609,12 @@ int luaopen_util_poll(lua_State *L) {
lua_setfield(L, -2, #named_error);
push_errno(EEXIST);
+ push_errno(EMFILE);
push_errno(ENOENT);
+ lua_pushliteral(L, POLL_BACKEND);
+ lua_setfield(L, -2, "api");
+
}
return 1;
}
diff --git a/util/async.lua b/util/async.lua
index ece589cb..2830238f 100644
--- a/util/async.lua
+++ b/util/async.lua
@@ -73,7 +73,7 @@ local function runner_continue(thread)
return true;
end
-local function waiter(num)
+local function waiter(num, allow_many)
local thread = checkthread();
num = num or 1;
local waiting;
@@ -85,7 +85,7 @@ local function waiter(num)
num = num - 1;
if num == 0 and waiting then
runner_continue(thread);
- elseif num < 0 then
+ elseif not allow_many and num < 0 then
error("done() called too many times");
end
end;
diff --git a/util/prosodyctl/check.lua b/util/prosodyctl/check.lua
index f2b84c7a..2ef3bbcb 100644
--- a/util/prosodyctl/check.lua
+++ b/util/prosodyctl/check.lua
@@ -505,6 +505,69 @@ local function check(arg)
ok = false;
end
+ do
+ local global_modules = set.new(config["*"].modules_enabled);
+ local registration_enabled_hosts = {};
+ for host in enabled_hosts() do
+ local host_modules = set.new(config[host].modules_enabled) + global_modules;
+ local allow_registration = config[host].allow_registration;
+ local mod_register = host_modules:contains("register");
+ local mod_register_ibr = host_modules:contains("register_ibr");
+ local mod_invites_register = host_modules:contains("invites_register");
+ local registration_invite_only = config[host].registration_invite_only;
+ local is_vhost = not config[host].component_module;
+ if is_vhost and (mod_register_ibr or (mod_register and allow_registration))
+ and not (mod_invites_register and registration_invite_only) then
+ table.insert(registration_enabled_hosts, host);
+ end
+ end
+ if #registration_enabled_hosts > 0 then
+ table.sort(registration_enabled_hosts);
+ print("");
+ print(" Public registration is enabled on:");
+ print(" "..table.concat(registration_enabled_hosts, ", "));
+ print("");
+ print(" If this is intentional, review our guidelines on running a public server");
+ print(" at https://prosody.im/doc/public_servers - otherwise, consider switching to");
+ print(" invite-based registration, which is more secure.");
+ end
+ end
+
+ do
+ local orphan_components = {};
+ local referenced_components = set.new();
+ local enabled_hosts_set = set.new();
+ for host, host_options in it.filter("*", pairs(configmanager.getconfig())) do
+ if host_options.enabled ~= false then
+ enabled_hosts_set:add(host);
+ for _, disco_item in ipairs(host_options.disco_items or {}) do
+ referenced_components:add(disco_item[1]);
+ end
+ end
+ end
+ for host, host_config in enabled_hosts() do
+ local is_component = not not host_config.component_module;
+ if is_component then
+ local parent_domain = host:match("^[^.]+%.(.+)$");
+ local is_orphan = not (enabled_hosts_set:contains(parent_domain) or referenced_components:contains(host));
+ if is_orphan then
+ table.insert(orphan_components, host);
+ end
+ end
+ end
+ if #orphan_components > 0 then
+ table.sort(orphan_components);
+ print("");
+ print(" Your configuration contains the following unreferenced components:\n");
+ print(" "..table.concat(orphan_components, "\n "));
+ print("");
+ print(" Clients may not be able to discover these services because they are not linked to");
+ print(" any VirtualHost. They are automatically linked if they are direct subdomains of a");
+ print(" VirtualHost. Alternatively, you can explicitly link them using the disco_items option.");
+ print(" For more information see https://prosody.im/doc/modules/mod_disco#items");
+ end
+ end
+
print("Done.\n");
end
if not what or what == "dns" then
@@ -585,6 +648,11 @@ local function check(arg)
end
end
+ -- Allow admin to specify additional (e.g. undiscoverable) IP addresses in the config
+ for _, address in ipairs(configmanager.get("*", "external_addresses") or {}) do
+ external_addresses:add(address);
+ end
+
if external_addresses:empty() then
print("");
print(" Failed to determine the external addresses of this server. Checks may be inaccurate.");
@@ -599,6 +667,8 @@ local function check(arg)
return (n:gsub("%.$", ""));
end
+ local unknown_addresses = set.new();
+
for jid, host_options in enabled_hosts() do
local all_targets_ok, some_targets_ok = true, false;
local node, host = jid_split(jid);
@@ -781,6 +851,7 @@ local function check(arg)
print(" "..target_host.." A record points to internal address, external connections might fail");
else
print(" "..target_host.." A record points to unknown address "..record.a);
+ unknown_addresses:add(record.a);
all_targets_ok = false;
end
end
@@ -799,6 +870,7 @@ local function check(arg)
print(" "..target_host.." AAAA record points to internal address, external connections might fail");
else
print(" "..target_host.." AAAA record points to unknown address "..record.aaaa);
+ unknown_addresses:add(record.aaaa);
all_targets_ok = false;
end
end
@@ -844,6 +916,18 @@ local function check(arg)
print("");
end
if not problem_hosts:empty() then
+ if not unknown_addresses:empty() then
+ print("");
+ print("Some of your DNS records point to unknown IP addresses. This may be expected if your server");
+ print("is behind a NAT or proxy. The unrecognized addresses were:");
+ print("");
+ print(" Unrecognized: "..tostring(unknown_addresses));
+ print("");
+ print("The addresses we found on this system are:");
+ print("");
+ print(" Internal: "..tostring(internal_addresses));
+ print(" External: "..tostring(external_addresses));
+ end
print("");
print("For more information about DNS configuration please see https://prosody.im/doc/dns");
print("");