--// lua libs //--
-local os = use "os"
local table = use "table"
local string = use "string"
local coroutine = use "coroutine"
local math_min = math.min
local math_huge = math.huge
local table_concat = table.concat
+local table_insert = table.insert
local string_sub = string.sub
local coroutine_wrap = coroutine.wrap
local coroutine_yield = coroutine.yield
local ssl_wrap = ( has_luasec and luasec.wrap )
local socket_bind = luasocket.bind
-local socket_sleep = luasocket.sleep
local socket_select = luasocket.select
--// functions //--
local _readtraffic
local _selecttimeout
-local _sleeptime
local _tcpbacklog
local _accepretry
local _sendtimeout
local _readtimeout
-local _timer
-
local _maxselectlen
local _maxfd
_readtraffic = 0
_selecttimeout = 1 -- timeout of socket.select
-_sleeptime = 0 -- time to wait at the end of every loop
_tcpbacklog = 128 -- some kind of hint to the OS
_accepretry = 10 -- seconds to wait until the next attempt of a full server to accept
local bufferqueuelen = 0 -- end of buffer array
local toclose
- local fatalerror
local needtls
local bufferlen = 0
return dispatch( handler, buffer, err )
else -- connections was closed or fatal error
out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " read error: ", tostring(err) )
- fatalerror = true
_ = handler and handler:force_close( err )
return false
end
return true
else -- connection was closed during sending or fatal error
out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " write error: ", tostring(err) )
- fatalerror = true
_ = handler and handler:force_close( err )
return false
end
getsettings = function( )
return {
select_timeout = _selecttimeout;
- select_sleep_time = _sleeptime;
tcp_backlog = _tcpbacklog;
max_send_buffer_size = _maxsendlen;
max_receive_buffer_size = _maxreadlen;
return nil, "invalid settings table"
end
_selecttimeout = tonumber( new.select_timeout ) or _selecttimeout
- _sleeptime = tonumber( new.select_sleep_time ) or _sleeptime
_maxsendlen = tonumber( new.max_send_buffer_size ) or _maxsendlen
_maxreadlen = tonumber( new.max_receive_buffer_size ) or _maxreadlen
_checkinterval = tonumber( new.select_idle_check_interval ) or _checkinterval
return true
end
+local add_task do
+ local data = {};
+ local new_data = {};
+
+ function add_task(delay, callback)
+ local current_time = luasocket_gettime();
+ delay = delay + current_time;
+ if delay >= current_time then
+ table_insert(new_data, {delay, callback});
+ else
+ local r = callback(current_time);
+ if r and type(r) == "number" then
+ return add_task(r, callback);
+ end
+ end
+ end
+
+ addtimer(function(current_time)
+ if #new_data > 0 then
+ for _, d in pairs(new_data) do
+ table_insert(data, d);
+ end
+ new_data = {};
+ end
+
+ local next_time = math_huge;
+ for i, d in pairs(data) do
+ local t, callback = d[1], d[2];
+ if t <= current_time then
+ data[i] = nil;
+ local r = callback(current_time);
+ if type(r) == "number" then
+ add_task(r, callback);
+ next_time = math_min(next_time, r);
+ end
+ else
+ next_time = math_min(next_time, t - current_time);
+ end
+ end
+ return next_time;
+ end);
+end
+
stats = function( )
return _readtraffic, _sendtraffic, _readlistlen, _sendlistlen, _timerlistlen
end
loop = function(once) -- this is the main loop of the program
if quitting then return "quitting"; end
if once then quitting = "once"; end
- local next_timer_time = math_huge;
+ _currenttime = luasocket_gettime( )
repeat
+ -- Fire timers
+ local next_timer_time = math_huge;
+ for i = 1, _timerlistlen do
+ local t = _timerlist[ i ]( _currenttime ) -- fire timers
+ if t then next_timer_time = math_min(next_timer_time, t); end
+ end
+
local read, write, err = socket_select( _readlist, _sendlist, math_min(_selecttimeout, next_timer_time) )
- for i, socket in ipairs( write ) do -- send data waiting in writequeues
+ for _, socket in ipairs( write ) do -- send data waiting in writequeues
local handler = _socketlist[ socket ]
if handler then
handler.sendbuffer( )
out_put "server.lua: found no handler and closed socket (writelist)" -- this should not happen
end
end
- for i, socket in ipairs( read ) do -- receive data
+ for _, socket in ipairs( read ) do -- receive data
local handler = _socketlist[ socket ]
if handler then
handler.readbuffer( )
end
end
- -- Fire timers
- if _currenttime - _timer >= math_min(next_timer_time, 1) then
- next_timer_time = math_huge;
- for i = 1, _timerlistlen do
- local t = _timerlist[ i ]( _currenttime ) -- fire timers
- if t then next_timer_time = math_min(next_timer_time, t); end
- end
- _timer = _currenttime
- else
- next_timer_time = next_timer_time - (_currenttime - _timer);
- end
-
for server, paused_time in pairs( _fullservers ) do
if _currenttime - paused_time > _accepretry then
_fullservers[ server ] = nil;
server.resume();
end
end
-
- -- wait some time (0 by default)
- socket_sleep( _sleeptime )
until quitting;
if once and quitting == "once" then quitting = nil; return; end
closeall();
elseif sslctx and not has_luasec then
err = "luasec not found"
end
- if not typ then
+ if getaddrinfo and not typ then
local addrinfo, err = getaddrinfo(address)
if not addrinfo then return nil, err end
if addrinfo[1] and addrinfo[1].family == "inet6" then
typ = "tcp6"
- else
- typ = "tcp"
end
end
- local create = luasocket[typ]
+ local create = luasocket[typ or "tcp"]
if type( create ) ~= "function" then
err = "invalid socket type"
end
end
client:settimeout( 0 )
local ok, err = client:connect( address, port )
- if ok or err == "timeout" then
+ if ok or err == "timeout" or err == "Operation already in progress" then
return wrapclient( client, address, port, listeners, pattern, sslctx )
else
return nil, err
end
end
---// EXPERIMENTAL //--
-
----------------------------------// BEGIN //--
use "setmetatable" ( _socketlist, { __mode = "k" } )
use "setmetatable" ( _readtimes, { __mode = "k" } )
use "setmetatable" ( _writetimes, { __mode = "k" } )
-_timer = luasocket_gettime( )
_starttime = luasocket_gettime( )
local function setlogger(new_logger)
return {
_addtimer = addtimer,
+ add_task = add_task;
addclient = addclient,
wrapclient = wrapclient,
return true, "OK";
end
+def_env.timer = {};
+
+function def_env.timer:info()
+ local socket = require "socket";
+ local print = self.session.print;
+ local add_task = require"util.timer".add_task;
+ local h, params = add_task.h, add_task.params;
+ if h then
+ print("-- util.timer");
+ for i, id in ipairs(h.ids) do
+ if not params[id] then
+ print(os.date("%F %T", h.priorities[i]), h.items[id]);
+ elseif not params[id].callback then
+ print(os.date("%F %T", h.priorities[i]), h.items[id], unpack(params[id]));
+ else
+ print(os.date("%F %T", h.priorities[i]), params[id].callback, unpack(params[id]));
+ end
+ end
+ end
+ if server.event_base then
+ local count = 0;
+ for k, v in pairs(debug.getregistry()) do
+ if type(v) == "function" and v.callback and v.callback == add_task._on_timer then
+ count = count + 1;
+ end
+ end
+ print(count .. " libevent callbacks");
+ end
+ if h then
+ local next_time = h:peek();
+ if next_time then
+ return true, os.date("Next event at %F %T (in %%.6fs)", next_time):format(next_time - socket.gettime());
+ end
+ end
+ return true;
+end
+
def_env.module = {};
local function get_hosts_set(hosts, module)
end
function def_env.s2s:showcert(domain)
- local ser = require "util.serialization".serialize;
local print = self.session.print;
local s2s_sessions = module:shared"/*/s2s/sessions";
local domain_sessions = set.new(array.collect(values(s2s_sessions)))
end
function def_env.muc:create(room_jid)
- local room, host = check_muc(room_jid);
+ local room_name, host = check_muc(room_jid);
if not room_name then
return room_name, host;
end
- if not room then return nil, host end
+ if not room_name then return nil, host end
if hosts[host].modules.muc.rooms[room_jid] then return nil, "Room exists already" end
return hosts[host].modules.muc.create_room(room_jid);
end
if not room_name then
return room_name, host;
end
- local room_obj = hosts[host].modules.muc.rooms[room_jid];
+ local room_obj = hosts[host].modules.muc.get_room_from_jid(room_jid);
if not room_obj then
return nil, "No such room: "..room_jid;
end
end
local print = self.session.print;
local c = 0;
- for name in keys(host_session.modules.muc.rooms) do
- print(name);
+ for room in host_session.modules.muc.each_room() do
+ print(room.jid);
c = c + 1;
end
return true, c.." rooms";
if option == "short" or option == "full" then
session.print("Welcome to the Prosody administration console. For a list of commands, type: help");
session.print("You may find more help on using this console in our online documentation at ");
- session.print("http://prosody.im/doc/console\n");
+ session.print("https://prosody.im/doc/console\n");
end
if option ~= "short" and option ~= "full" and option ~= "graphic" then
session.print(option);