aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--HACKERS8
-rw-r--r--README2
-rw-r--r--TODO17
-rw-r--r--core/componentmanager.lua17
-rw-r--r--core/hostmanager.lua4
-rw-r--r--core/s2smanager.lua35
-rw-r--r--net/dns.lua17
-rw-r--r--net/http.lua29
-rw-r--r--net/httpclient_listener.lua2
-rw-r--r--net/httpserver.lua2
-rw-r--r--net/server.lua4
-rw-r--r--net/xmppserver_listener.lua6
-rw-r--r--plugins/mod_httpserver.lua24
-rw-r--r--plugins/mod_posix.lua37
-rw-r--r--plugins/mod_saslauth.lua3
-rw-r--r--plugins/mod_tls.lua2
-rwxr-xr-xprosody13
-rwxr-xr-xprosodyctl30
-rw-r--r--util-src/lsignal.c73
-rw-r--r--util/prosodyctl.lua11
20 files changed, 237 insertions, 99 deletions
diff --git a/HACKERS b/HACKERS
index a8585af0..40cbd8aa 100644
--- a/HACKERS
+++ b/HACKERS
@@ -5,6 +5,8 @@ involved you can join us on our mailing list and discussion rooms. More
information on these at http://prosody.im/discuss
Patches are welcome, though before sending we would appreciate if you read
-docs/coding_style.txt for guidelines on how to format your code, and are
-comfortable with copyright of contributions being assigned to the core
-developers.
+docs/coding_style.txt for guidelines on how to format your code, and other tips.
+
+Documentation for developers can be found at http://prosody.im/doc/developers
+
+Have fun :)
diff --git a/README b/README
index a28f135d..3cffea49 100644
--- a/README
+++ b/README
@@ -32,6 +32,6 @@ Mailing lists:
## Installation
See the accompanying INSTALL file for help on building Prosody from source. Alternatively
-see our guide at http://prosody.im/install
+see our guide at http://prosody.im/doc/install
diff --git a/TODO b/TODO
index a3266d82..17cf4e67 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,18 @@
-- Ad-hoc commands
-- Clustering
+== 0.7 ==
+DONE: http://blog.prosody.im/prosody-0-7-0rc1-available-for-testing/
+== 0.8 ==
+- Ad-hoc commands:
+ http://code.google.com/p/prosody-modules/wiki/mod_adhoc
+ http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_admin
+ http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_ping
+ http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_uptime
+
- Pubsub
+- Data storage backend abstraction
+== 0.9 ==
+- Clustering
+== 1.0 ==
+- Web interface?
+- World domination
diff --git a/core/componentmanager.lua b/core/componentmanager.lua
index a16c01d2..c701c4d7 100644
--- a/core/componentmanager.lua
+++ b/core/componentmanager.lua
@@ -14,9 +14,10 @@ local jid_split = require "util.jid".split;
local fire_event = require "core.eventmanager".fire_event;
local events_new = require "util.events".new;
local st = require "util.stanza";
-local hosts = hosts;
+local prosody, hosts = prosody, prosody.hosts;
+local ssl = ssl;
-local pairs, type, tostring = pairs, type, tostring;
+local pairs, setmetatable, type, tostring = pairs, setmetatable, type, tostring;
local components = {};
@@ -73,18 +74,24 @@ end
function create_component(host, component, events)
-- TODO check for host well-formedness
- local ssl_ctx;
- if host then
+ local ssl_ctx, ssl_ctx_in;
+ if host and ssl then
-- We need to find SSL context to use...
-- Discussion in prosody@ concluded that
-- 1 level back is usually enough by default
local base_host = host:gsub("^[^%.]+%.", "");
if hosts[base_host] then
ssl_ctx = hosts[base_host].ssl_ctx;
+ ssl_ctx_in = hosts[base_host].ssl_ctx_in;
+ elseif prosody.global_ssl_ctx then
+ -- We have no cert, and no parent host to borrow a cert from
+ -- Use global/default cert if there is one
+ ssl_ctx = ssl.newcontext(prosody.global_ssl_ctx);
+ ssl_ctx_in = ssl.newcontext(setmetatable({ mode = "server" }, { __index = prosody.global_ssl_ctx }));
end
end
return { type = "component", host = host, connected = true, s2sout = {},
- ssl_ctx = ssl_ctx, events = events or events_new() };
+ ssl_ctx = ssl_ctx, ssl_ctx_in = ssl_ctx_in, events = events or events_new() };
end
function register_component(host, component, session)
diff --git a/core/hostmanager.lua b/core/hostmanager.lua
index 8010b3de..125e71ba 100644
--- a/core/hostmanager.lua
+++ b/core/hostmanager.lua
@@ -20,8 +20,8 @@ end
local incoming_s2s = _G.prosody.incoming_s2s;
-- These are the defaults if not overridden in the config
-local default_ssl_ctx = { mode = "client", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
-local default_ssl_ctx_in = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
+local default_ssl_ctx = { mode = "client", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none", options = "no_sslv2"; };
+local default_ssl_ctx_in = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none", options = "no_sslv2"; };
local log = require "util.logger".init("hostmanager");
diff --git a/core/s2smanager.lua b/core/s2smanager.lua
index e8d8e723..92f07354 100644
--- a/core/s2smanager.lua
+++ b/core/s2smanager.lua
@@ -54,7 +54,7 @@ function compare_srv_priorities(a,b)
return a.priority < b.priority or (a.priority == b.priority and a.weight > b.weight);
end
-local function bounce_sendq(session)
+local function bounce_sendq(session, reason)
local sendq = session.sendq;
if sendq then
session.log("info", "sending error replies for "..#sendq.." queued stanzas because of failed outgoing connection to "..tostring(session.to_host));
@@ -72,6 +72,9 @@ local function bounce_sendq(session)
reply.attr.type = "error";
reply:tag("error", {type = "cancel"})
:tag("remote-server-not-found", {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}):up();
+ if reason then
+ reply:tag("text", {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}):text("Connection failed: "..reason):up();
+ end
core_process_stanza(dummy, reply);
end
sendq[i] = nil;
@@ -224,7 +227,7 @@ function attempt_connection(host_session, err)
if not ok then
if not attempt_connection(host_session, err) then
-- No more attempts will be made
- destroy_session(host_session);
+ destroy_session(host_session, err);
end
end
end, "_xmpp-server._tcp."..connect_host..".", "SRV");
@@ -284,7 +287,7 @@ function try_connect(host_session, connect_host, connect_port)
log("debug", "DNS lookup failed to get a response for %s", connect_host);
if not attempt_connection(host_session, "name resolution failed") then -- Retry if we can
log("debug", "No other records to try for %s - destroying", host_session.to_host);
- destroy_session(host_session); -- End of the line, we can't
+ destroy_session(host_session, "DNS resolution failed"); -- End of the line, we can't
end
end
end, connect_host, "A", "IN");
@@ -300,7 +303,7 @@ function try_connect(host_session, connect_host, connect_port)
end
function make_connect(host_session, connect_host, connect_port)
- host_session.log("info", "Beginning new connection attempt to %s (%s:%d)", host_session.to_host, connect_host, connect_port);
+ (host_session.log or log)("info", "Beginning new connection attempt to %s (%s:%d)", host_session.to_host, connect_host, connect_port);
-- Ok, we're going to try to connect
local from_host, to_host = host_session.from_host, host_session.to_host;
@@ -369,17 +372,17 @@ function streamopened(session, attr)
session.streamid = uuid_gen();
(session.log or log)("debug", "incoming s2s received <stream:stream>");
- send("<?xml version='1.0'?>");
- send(stanza("stream:stream", { xmlns='jabber:server', ["xmlns:db"]='jabber:server:dialback',
- ["xmlns:stream"]='http://etherx.jabber.org/streams', id=session.streamid, from=session.to_host, version=(session.version > 0 and "1.0" or nil) }):top_tag());
if session.to_host and not hosts[session.to_host] then
-- Attempting to connect to a host we don't serve
session:close({ condition = "host-unknown"; text = "This host does not serve "..session.to_host });
return;
end
+ send("<?xml version='1.0'?>");
+ send(stanza("stream:stream", { xmlns='jabber:server', ["xmlns:db"]='jabber:server:dialback',
+ ["xmlns:stream"]='http://etherx.jabber.org/streams', id=session.streamid, from=session.to_host, to=session.from_host, version=(session.version > 0 and "1.0" or nil) }):top_tag());
if session.version >= 1.0 then
local features = st.stanza("stream:features");
-
+
if session.to_host then
hosts[session.to_host].events.fire_event("s2s-stream-features", { session = session, features = features });
else
@@ -402,7 +405,7 @@ function streamopened(session, attr)
if send_buffer and #send_buffer > 0 then
log("debug", "Sending s2s send_buffer now...");
for i, data in ipairs(send_buffer) do
- session.sends2s(tostring(data));
+ session.sends2s(data);
send_buffer[i] = nil;
end
end
@@ -446,6 +449,16 @@ function verify_dialback(id, to, from, key)
end
function make_authenticated(session, host)
+ if not session.secure then
+ local local_host = session.direction == "incoming" and session.to_host or session.from_host;
+ if config.get(local_host, "core", "s2s_require_encryption") then
+ session:close({
+ condition = "policy-violation",
+ text = "Encrypted server-to-server communication is required but was not "
+ ..((session.direction == "outgoing" and "offered") or "used")
+ });
+ end
+ end
if session.type == "s2sout_unauthed" then
session.type = "s2sout";
elseif session.type == "s2sin_unauthed" then
@@ -493,12 +506,12 @@ end
local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed s2s session: %s", data); end
-function destroy_session(session)
+function destroy_session(session, reason)
(session.log or log)("info", "Destroying "..tostring(session.direction).." session "..tostring(session.from_host).."->"..tostring(session.to_host));
if session.direction == "outgoing" then
hosts[session.from_host].s2sout[session.to_host] = nil;
- bounce_sendq(session);
+ bounce_sendq(session, reason);
elseif session.direction == "incoming" then
incoming_s2s[session] = nil;
end
diff --git a/net/dns.lua b/net/dns.lua
index 25941015..1b5321af 100644
--- a/net/dns.lua
+++ b/net/dns.lua
@@ -183,7 +183,7 @@ end
function dns.random(...) -- - - - - - - - - - - - - - - - - - - dns.random
- math.randomseed(10000*socket.gettime());
+ math.randomseed(math.floor(10000*socket.gettime()));
dns.random = math.random;
return dns.random(...);
end
@@ -746,7 +746,7 @@ function resolver:receive(rset) -- - - - - - - - - - - - - - - - - receive
if not next(self.active) then self:closeall(); end
-- was the query on the wanted list?
- local q = response.question;
+ local q = response.question[1];
local cos = get(self.wanted, q.class, q.type, q.name);
if cos then
for co in pairs(cos) do
@@ -769,21 +769,18 @@ function resolver:feed(sock, packet)
self.time = socket.gettime();
local response = self:decode(packet);
- if response then
+ if response and self.active[response.header.id]
+ and self.active[response.header.id][response.question.raw] then
--print('received response');
--self.print(response);
- for i,section in pairs({ 'answer', 'authority', 'additional' }) do
- for j,rr in pairs(response[section]) do
- self:remember(rr, response.question[1].type);
- end
+ for j,rr in pairs(response.answer) do
+ self:remember(rr, response.question[1].type);
end
-- retire the query
local queries = self.active[response.header.id];
- if queries[response.question.raw] then
- queries[response.question.raw] = nil;
- end
+ queries[response.question.raw] = nil;
if not next(queries) then self.active[response.header.id] = nil; end
if not next(self.active) then self:closeall(); end
diff --git a/net/http.lua b/net/http.lua
index 9d2f9b96..09b04e61 100644
--- a/net/http.lua
+++ b/net/http.lua
@@ -30,7 +30,7 @@ function urldecode(s) return s and (s:gsub("%%(%x%x)", function (c) return char(
local function expectbody(reqt, code)
if reqt.method == "HEAD" then return nil end
- if code == 204 or code == 304 then return nil end
+ if code == 204 or code == 304 or code == 301 then return nil end
if code >= 100 and code < 200 then return nil end
return 1
end
@@ -43,6 +43,7 @@ local function request_reader(request, data, startpos)
elseif request.state ~= "completed" then
-- Error.. connection was closed prematurely
request.callback("connection-closed", 0, request);
+ return;
end
destroy_request(request);
request.body = nil;
@@ -73,22 +74,31 @@ local function request_reader(request, data, startpos)
elseif request.state == "headers" then
print("Reading headers...")
local pos = startpos;
- local headers = request.responseheaders or {};
+ local headers, headers_complete = request.responseheaders;
+ if not headers then
+ headers = {};
+ request.responseheaders = headers;
+ end
for line in data:sub(startpos, -1):gmatch("(.-)\r\n") do
startpos = startpos + #line + 2;
local k, v = line:match("(%S+): (.+)");
if k and v then
headers[k:lower()] = v;
- print("Header: "..k:lower().." = "..v);
+ --print("Header: "..k:lower().." = "..v);
elseif #line == 0 then
- request.responseheaders = headers;
+ headers_complete = true;
break;
else
print("Unhandled header line: "..line);
end
end
+ if not headers_complete then return; end
-- Reached the end of the headers
- request.state = "body";
+ if not expectbody(request, request.code) then
+ request.callback(nil, request.code, request);
+ return;
+ end
+ request.state = "body";
if #data > startpos then
return request_reader(request, data, startpos);
end
@@ -97,12 +107,15 @@ local function request_reader(request, data, startpos)
local http, code, text, linelen = data:match("^HTTP/(%S+) (%d+) (.-)\r\n()", startpos);
code = tonumber(code);
if not code then
- return request.callback("invalid-status-line", 0, request);
+ log("warn", "Invalid HTTP status line, telling callback then closing");
+ local ret = request.callback("invalid-status-line", 0, request);
+ destroy_request(request);
+ return ret;
end
request.code, request.responseversion = code, http;
- if request.onlystatus or not expectbody(request, code) then
+ if request.onlystatus then
if request.callback then
request.callback(nil, code, request);
end
@@ -200,7 +213,7 @@ end
function destroy_request(request)
if request.conn then
request.handler.close()
- listener.disconnect(request.conn, "closed");
+ listener.disconnect(request.handler, "closed");
end
end
diff --git a/net/httpclient_listener.lua b/net/httpclient_listener.lua
index 69b7946b..a688a3e0 100644
--- a/net/httpclient_listener.lua
+++ b/net/httpclient_listener.lua
@@ -30,7 +30,7 @@ end
function httpclient.disconnect(conn, err)
local request = requests[conn];
- if request then
+ if request and err ~= "closed" then
request:reader(nil);
end
requests[conn] = nil;
diff --git a/net/httpserver.lua b/net/httpserver.lua
index c4be59bf..6bd641f9 100644
--- a/net/httpserver.lua
+++ b/net/httpserver.lua
@@ -65,6 +65,7 @@ local function send_response(request, response)
resp = { "HTTP/1.0 200 OK\r\n" };
t_insert(resp, "Connection: close\r\n");
+ t_insert(resp, "Content-Type: text/html\r\n");
t_insert(resp, "Content-Length: ");
t_insert(resp, #response);
t_insert(resp, "\r\n\r\n");
@@ -286,6 +287,7 @@ function new_from_config(ports, handle_request, default_options)
if ssl then
ssl.mode = "server";
ssl.protocol = "sslv23";
+ ssl.options = "no_sslv2";
end
new{ port = port, interface = interface,
diff --git a/net/server.lua b/net/server.lua
index 6ab8ce91..ad46071b 100644
--- a/net/server.lua
+++ b/net/server.lua
@@ -434,7 +434,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
handler.bufferlen = function( readlen, sendlen )
maxsendlen = sendlen or maxsendlen
maxreadlen = readlen or maxreadlen
- return maxreadlen, maxsendlen
+ return bufferlen, maxreadlen, maxsendlen
end
handler.lock = function( switch )
if switch == true then
@@ -467,7 +467,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport
end
local _readbuffer = function( ) -- this function reads data
local buffer, err, part = receive( socket, pattern ) -- receive buffer with "pattern"
- if not err or ( err == "timeout" or err == "wantread" ) then -- received something
+ if not err or (err == "wantread" or err == "timeout") or string_len(part) > 0 then -- received something
local buffer = buffer or part or ""
local len = string_len( buffer )
if len > maxreadlen then
diff --git a/net/xmppserver_listener.lua b/net/xmppserver_listener.lua
index 2ab51992..86a3d735 100644
--- a/net/xmppserver_listener.lua
+++ b/net/xmppserver_listener.lua
@@ -152,14 +152,14 @@ function xmppserver.disconnect(conn, err)
local session = sessions[conn];
if session then
if err and err ~= "closed" and session.srv_hosts then
- (session.log or log)("debug", "s2s connection closed unexpectedly");
+ (session.log or log)("debug", "s2s connection attempt failed: %s", err);
if s2s_attempt_connect(session, err) then
- (session.log or log)("debug", "...so we're going to try again");
+ (session.log or log)("debug", "...so we're going to try another target");
return; -- Session lives for now
end
end
(session.log or log)("info", "s2s disconnected: %s->%s (%s)", tostring(session.from_host), tostring(session.to_host), tostring(err));
- s2s_destroy_session(session);
+ s2s_destroy_session(session, err);
sessions[conn] = nil;
session = nil;
end
diff --git a/plugins/mod_httpserver.lua b/plugins/mod_httpserver.lua
index 545d4faf..c12f1c05 100644
--- a/plugins/mod_httpserver.lua
+++ b/plugins/mod_httpserver.lua
@@ -15,8 +15,20 @@ local t_concat = table.concat;
local http_base = config.get("*", "core", "http_path") or "www_files";
local response_400 = { status = "400 Bad Request", body = "<h1>Bad Request</h1>Sorry, we didn't understand your request :(" };
+local response_403 = { status = "403 Forbidden", body = "<h1>Forbidden</h1>You don't have permission to view the contents of this directory :(" };
local response_404 = { status = "404 Not Found", body = "<h1>Page Not Found</h1>Sorry, we couldn't find what you were looking for :(" };
+-- TODO: Should we read this from /etc/mime.types if it exists? (startup time...?)
+local mime_map = {
+ html = "text/html";
+ htm = "text/html";
+ xml = "text/xml";
+ xsl = "text/xml";
+ txt = "text/plain; charset=utf-8";
+ js = "text/javascript";
+ css = "text/css";
+};
+
local function preprocess_path(path)
if path:sub(1,1) ~= "/" then
path = "/"..path;
@@ -36,11 +48,19 @@ local function preprocess_path(path)
end
function serve_file(path)
- local f, err = open(http_base..path, "r");
+ local f, err = open(http_base..path, "rb");
if not f then return response_404; end
local data = f:read("*a");
f:close();
- return data;
+ if not data then
+ return response_403;
+ end
+ local ext = path:match("%.([^.]*)$");
+ local mime = mime_map[ext]; -- Content-Type should be nil when not known
+ return {
+ headers = { ["Content-Type"] = mime; };
+ body = data;
+ };
end
local function handle_file_request(method, body, request)
diff --git a/plugins/mod_posix.lua b/plugins/mod_posix.lua
index b75b9610..ed0dbd87 100644
--- a/plugins/mod_posix.lua
+++ b/plugins/mod_posix.lua
@@ -19,6 +19,9 @@ end
local logger_set = require "util.logger".setwriter;
+local lfs = require "lfs";
+local stat = lfs.attributes;
+
local prosody = _G.prosody;
module.host = "*"; -- we're a global module
@@ -59,28 +62,38 @@ module:add_event_hook("server-starting", function ()
end
end);
-local pidfile_written;
+local pidfile;
+local pidfile_handle;
local function remove_pidfile()
- if pidfile_written then
- os.remove(pidfile_written);
- pidfile_written = nil;
+ if pidfile_handle then
+ pidfile_handle:close();
+ os.remove(pidfile);
+ pidfile, pidfile_handle = nil, nil;
end
end
local function write_pidfile()
- if pidfile_written then
+ if pidfile_handle then
remove_pidfile();
end
- local pidfile = module:get_option("pidfile");
+ pidfile = module:get_option("pidfile");
if pidfile then
- local pf, err = io.open(pidfile, "w+");
- if not pf then
- module:log("error", "Couldn't write pidfile; %s", err);
+ local mode = stat(pidfile) and "r+" or "w+";
+ pidfile_handle, err = io.open(pidfile, mode);
+ if not pidfile_handle then
+ module:log("error", "Couldn't write pidfile at %s; %s", pidfile, err);
+ prosody.shutdown("Couldn't write pidfile");
else
- pf:write(tostring(pposix.getpid()));
- pf:close();
- pidfile_written = pidfile;
+ if not lfs.lock(pidfile_handle, "w") then -- Exclusive lock
+ local other_pid = pidfile_handle:read("*a");
+ module:log("error", "Another Prosody instance seems to be running with PID %s, quitting", other_pid);
+ pidfile_handle = nil;
+ prosody.shutdown("Prosody already running");
+ else
+ pidfile_handle:write(tostring(pposix.getpid()));
+ pidfile_handle:flush();
+ end
end
end
end
diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua
index 9fd719c9..2aee2be0 100644
--- a/plugins/mod_saslauth.lua
+++ b/plugins/mod_saslauth.lua
@@ -115,6 +115,9 @@ local function sasl_handler(session, stanza)
if not session.sasl_handler then
return session.send(build_reply("failure", "invalid-mechanism"));
end
+ if secure_auth_only and not session.secure then
+ return session.send(build_reply("failure", "encryption-required"));
+ end
elseif not session.sasl_handler then
return; -- FIXME ignoring out of order stanzas because ejabberd does
end
diff --git a/plugins/mod_tls.lua b/plugins/mod_tls.lua
index 54b48161..67555b15 100644
--- a/plugins/mod_tls.lua
+++ b/plugins/mod_tls.lua
@@ -94,6 +94,8 @@ module:hook_stanza(xmlns_starttls, "proceed",
function (session, stanza)
module:log("debug", "Proceeding with TLS on s2sout...");
local format, to_host, from_host = string.format, session.to_host, session.from_host;
+ local ssl_ctx = session.from_host and hosts[session.from_host].ssl_ctx or global_ssl_ctx;
+ session.conn.set_sslctx(ssl_ctx);
session:reset_stream();
session.conn.starttls(true);
session.secure = false;
diff --git a/prosody b/prosody
index 55198c2f..7f4a2cec 100755
--- a/prosody
+++ b/prosody
@@ -31,7 +31,9 @@ if CFG_DATADIR then
end
-- Required to be able to find packages installed with luarocks
-pcall(require, "luarocks.require")
+if not pcall(require, "luarocks.loader") then -- Try LuaRocks 2.x
+ pcall(require, "luarocks.require") -- Try LuaRocks 1.x
+end
-- Replace require with one that doesn't pollute _G
do
@@ -177,7 +179,7 @@ function init_global_state()
-- Load SSL settings from config, and create a ctx table
local global_ssl_ctx = rawget(_G, "ssl") and config.get("*", "core", "ssl");
if global_ssl_ctx then
- local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
+ local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none", options = "no_sslv2"; };
setmetatable(global_ssl_ctx, { __index = default_ssl_ctx });
end
@@ -192,14 +194,15 @@ function init_global_state()
log("error", "core."..option.." is not a table");
else
for _, port in ipairs(ports) do
+ port = tonumber(port);
if type(port) ~= "number" then
log("error", "Non-numeric "..option.."_ports: "..tostring(port));
else
local ok, err = cl.start(listener, {
ssl = conntype ~= "tcp" and global_ssl_ctx,
port = port,
- interface = config.get("*", "core", option.."_interface")
- or cl.get(listener).default_interface
+ interface = (option and config.get("*", "core", option.."_interface"))
+ or cl.get(listener).default_interface
or config.get("*", "core", "interface"),
type = conntype
});
@@ -332,7 +335,7 @@ end
function loop()
-- Error handler for errors that make it this far
local function catch_uncaught_error(err)
- if type(err) == "string" and err:match("%d*: interrupted!$") then
+ if type(err) == "string" and err:match("interrupted!$") then
return "quitting";
end
diff --git a/prosodyctl b/prosodyctl
index 522ebde9..89368a78 100755
--- a/prosodyctl
+++ b/prosodyctl
@@ -30,7 +30,10 @@ if CFG_DATADIR then
end
-- Required to be able to find packages installed with luarocks
-pcall(require, "luarocks.require")
+if not pcall(require, "luarocks.loader") then -- Try LuaRocks 2.x
+ pcall(require, "luarocks.require") -- Try LuaRocks 1.x
+end
+
config = require "core.configmanager"
@@ -137,18 +140,33 @@ function show_usage(usage, desc)
end
local function getchar(n)
- os.execute("stty raw -echo");
- local ok, char = pcall(io.read, n or 1);
- os.execute("stty sane");
+ local stty_ret = os.execute("stty raw -echo 2>/dev/null");
+ local ok, char;
+ if stty_ret == 0 then
+ ok, char = pcall(io.read, n or 1);
+ os.execute("stty sane");
+ else
+ ok, char = pcall(io.read, "*l");
+ if ok then
+ char = char:sub(1, n or 1);
+ end
+ end
if ok then
return char;
end
end
local function getpass()
- os.execute("stty -echo");
+ local stty_ret = os.execute("stty -echo 2>/dev/null");
+ if stty_ret ~= 0 then
+ io.write("\027[08m"); -- ANSI 'hidden' text attribute
+ end
local ok, pass = pcall(io.read, "*l");
- os.execute("stty sane");
+ if stty_ret == 0 then
+ os.execute("stty sane");
+ else
+ io.write("\027[00m");
+ end
io.write("\n");
if ok then
return pass;
diff --git a/util-src/lsignal.c b/util-src/lsignal.c
index 80799e4a..fe35e8b7 100644
--- a/util-src/lsignal.c
+++ b/util-src/lsignal.c
@@ -1,9 +1,9 @@
/*
* lsignal.h -- Signal Handler Library for Lua
*
- * Version: 1.000
+ * Version: 1.000+changes
*
- * Copyright (C) 2007 Patrick J. Donnelly (batrick@unm.edu)
+ * Copyright (C) 2007 Patrick J. Donnelly (batrick@batbytes.com)
*
* This software is distributed under the same license as Lua 5.0:
*
@@ -27,6 +27,7 @@
*/
#include <signal.h>
+#include <stdlib.h>
#include "lua.h"
#include "lauxlib.h"
@@ -149,43 +150,67 @@ static const struct lua_signal lua_signals[] = {
{NULL, 0}
};
-static int Nsig = 0;
static lua_State *Lsig = NULL;
static lua_Hook Hsig = NULL;
static int Hmask = 0;
static int Hcount = 0;
+static struct signal_event
+{
+ int Nsig;
+ struct signal_event *next_event;
+} *signal_queue = NULL;
+
+static struct signal_event *last_event = NULL;
+
static void sighook(lua_State *L, lua_Debug *ar)
{
+ /* restore the old hook */
+ lua_sethook(L, Hsig, Hmask, Hcount);
+
lua_pushstring(L, LUA_SIGNAL);
lua_gettable(L, LUA_REGISTRYINDEX);
- lua_pushnumber(L, Nsig);
- lua_gettable(L, -2);
- lua_call(L, 0, 0);
+ struct signal_event *event;
+ while((event = signal_queue))
+ {
+ lua_pushnumber(L, event->Nsig);
+ lua_gettable(L, -2);
+ lua_call(L, 0, 0);
+ signal_queue = event->next_event;
+ free(event);
+ };
+
+ lua_pop(L, 1); /* pop lua_signal table */
- /* set the old hook */
- lua_sethook(L, Hsig, Hmask, Hcount);
}
static void handle(int sig)
{
- Hsig = lua_gethook(Lsig);
- Hmask = lua_gethookmask(Lsig);
- Hcount = lua_gethookcount(Lsig);
- Nsig = sig;
-
- lua_sethook(Lsig, sighook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
- /*
- switch (sig)
+ if(!signal_queue)
+ {
+ /* Store the existing debug hook (if any) and its parameters */
+ Hsig = lua_gethook(Lsig);
+ Hmask = lua_gethookmask(Lsig);
+ Hcount = lua_gethookcount(Lsig);
+
+ signal_queue = malloc(sizeof(struct signal_event));
+ signal_queue->Nsig = sig;
+ signal_queue->next_event = NULL;
+
+ last_event = signal_queue;
+
+ /* Set our new debug hook */
+ lua_sethook(Lsig, sighook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
+ }
+ else
{
- case SIGABRT: ;
- case SIGFPE: ;
- case SIGILL: ;
- case SIGINT: ;
- case SIGSEGV: ;
- case SIGTERM: ;
- } */
+ last_event->next_event = malloc(sizeof(struct signal_event));
+ last_event->next_event->Nsig = sig;
+ last_event->next_event->next_event = NULL;
+
+ last_event = last_event->next_event;
+ }
}
/*
@@ -348,7 +373,7 @@ static int l_kill(lua_State *L)
static const struct luaL_Reg lsignal_lib[] = {
{"signal", l_signal},
{"raise", l_raise},
-#ifdef _POSIX_SOURCE
+#if defined _POSIX_SOURCE || (defined(sun) || defined(__sun))
{"kill", l_kill},
#endif
{NULL, NULL}
diff --git a/util/prosodyctl.lua b/util/prosodyctl.lua
index b24e194d..7ce6c513 100644
--- a/util/prosodyctl.lua
+++ b/util/prosodyctl.lua
@@ -12,6 +12,7 @@ local encodings = require "util.encodings";
local stringprep = encodings.stringprep;
local usermanager = require "core.usermanager";
local signal = require "util.signal";
+local lfs = require "lfs";
local nodeprep, nameprep = stringprep.nodeprep, stringprep.nameprep;
@@ -64,11 +65,17 @@ function getpid()
return false, "no-pidfile";
end
- local file, err = io.open(pidfile);
+ local file, err = io.open(pidfile, "r+");
if not file then
return false, "pidfile-read-failed", err;
end
+ local locked, err = lfs.lock(file, "w");
+ if locked then
+ file:close();
+ return false, "pidfile-not-locked";
+ end
+
local pid = tonumber(file:read("*a"));
file:close();
@@ -82,7 +89,7 @@ end
function isrunning()
local ok, pid, err = _M.getpid();
if not ok then
- if pid == "pidfile-read-failed" then
+ if pid == "pidfile-read-failed" or pid == "pidfile-not-locked" then
-- Report as not running, since we can't open the pidfile
-- (it probably doesn't exist)
return true, false;