view util/multitable.lua @ 11592:64cfa396bb84

net.server_epoll: Fix reporting of socket connect timeout If the underlying TCP connection times out before the write timeout kicks in, end up here with err="timeout", which the following code treats as a minor issue. Then, due to epoll apparently returning the EPOLLOUT (writable) event too, we go on and try to write to the socket (commonly stream headers). This fails because the socket is closed, which becomes the error returned up the stack to the rest of Prosody. This also trips the 'onconnect' signal, which has effects on various things, such as the net.connect state machine. Probably undesirable effects. With this, we instead return "connection timeout", like server_event, and destroy the connection handle properly. And then nothing else happens because the connection has been destroyed.
author Kim Alvefur <zash@zash.se>
date Mon, 07 Jun 2021 17:37:14 +0200
parents affcbccc1dff
children 39ae08180c81
line wrap: on
line source

-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--

local select = select;
local t_insert = table.insert;
local pairs, next, type = pairs, next, type;
local unpack = table.unpack or unpack; --luacheck: ignore 113

local _ENV = nil;
-- luacheck: std none

local function get(self, ...)
	local t = self.data;
	for n = 1,select('#', ...) do
		t = t[select(n, ...)];
		if not t then break; end
	end
	return t;
end

local function add(self, ...)
	local t = self.data;
	local count = select('#', ...);
	for n = 1,count-1 do
		local key = select(n, ...);
		local tab = t[key];
		if not tab then tab = {}; t[key] = tab; end
		t = tab;
	end
	t_insert(t, (select(count, ...)));
end

local function set(self, ...)
	local t = self.data;
	local count = select('#', ...);
	for n = 1,count-2 do
		local key = select(n, ...);
		local tab = t[key];
		if not tab then tab = {}; t[key] = tab; end
		t = tab;
	end
	t[(select(count-1, ...))] = (select(count, ...));
end

local function r(t, n, _end, ...)
	if t == nil then return; end
	local k = select(n, ...);
	if n == _end then
		t[k] = nil;
		return;
	end
	if k then
		local v = t[k];
		if v then
			r(v, n+1, _end, ...);
			if not next(v) then
				t[k] = nil;
			end
		end
	else
		for _,b in pairs(t) do
			r(b, n+1, _end, ...);
			if not next(b) then
				t[_] = nil;
			end
		end
	end
end

local function remove(self, ...)
	local _end = select('#', ...);
	for n = _end,1 do
		if select(n, ...) then _end = n; break; end
	end
	r(self.data, 1, _end, ...);
end


local function s(t, n, results, _end, ...)
	if t == nil then return; end
	local k = select(n, ...);
	if n == _end then
		if k == nil then
			for _, v in pairs(t) do
				t_insert(results, v);
			end
		else
			t_insert(results, t[k]);
		end
		return;
	end
	if k then
		local v = t[k];
		if v then
			s(v, n+1, results, _end, ...);
		end
	else
		for _,b in pairs(t) do
			s(b, n+1, results, _end, ...);
		end
	end
end

-- Search for keys, nil == wildcard
local function search(self, ...)
	local _end = select('#', ...);
	for n = _end,1 do
		if select(n, ...) then _end = n; break; end
	end
	local results = {};
	s(self.data, 1, results, _end, ...);
	return results;
end

-- Append results to an existing list
local function search_add(self, results, ...)
	if not results then results = {}; end
	local _end = select('#', ...);
	for n = _end,1 do
		if select(n, ...) then _end = n; break; end
	end
	s(self.data, 1, results, _end, ...);
	return results;
end

local function iter(self, ...)
	local query = { ... };
	local maxdepth = select("#", ...);
	local stack = { self.data };
	local keys = { };
	local function it(self) -- luacheck: ignore 432/self
		local depth = #stack;
		local key = next(stack[depth], keys[depth]);
		if key == nil then -- Go up the stack
			stack[depth], keys[depth] = nil, nil;
			if depth > 1 then
				return it(self);
			end
			return; -- The end
		else
			keys[depth] = key;
		end
		local value = stack[depth][key];
		if query[depth] == nil or key == query[depth] then
			if depth == maxdepth then -- Result
				local result = {}; -- Collect keys forming path to result
				for i = 1, depth do
					result[i] = keys[i];
				end
				result[depth+1] = value;
				return unpack(result, 1, depth+1);
			elseif type(value) == "table" then
				t_insert(stack, value); -- Descend
			end
		end
		return it(self);
	end;
	return it, self;
end

local function new()
	return {
		data = {};
		get = get;
		add = add;
		set = set;
		remove = remove;
		search = search;
		search_add = search_add;
		iter = iter;
	};
end

return {
	iter = iter;
	new = new;
};