X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=prosody;h=ade85f80af1126c8697c5fd1d8a6eb66dc64de2a;hb=be7359164d5a2386006ac3e41a2558446edb6378;hp=7bc075d746a0de6890f12507a8aaa76fb9ea1b3c;hpb=13eb49c333d7ce8a3425d2c33997ab8b16414158;p=prosody.git diff --git a/prosody b/prosody index 7bc075d7..ade85f80 100755 --- a/prosody +++ b/prosody @@ -7,19 +7,33 @@ -- COPYING file in the source package for more information. -- +-- prosody - main executable for Prosody XMPP server + -- Will be modified by configure script if run -- -CFG_SOURCEDIR=os.getenv("PROSODY_SRCDIR"); -CFG_CONFIGDIR=os.getenv("PROSODY_CFGDIR"); -CFG_PLUGINDIR=os.getenv("PROSODY_PLUGINDIR"); -CFG_DATADIR=os.getenv("PROSODY_DATADIR"); +CFG_SOURCEDIR=CFG_SOURCEDIR or os.getenv("PROSODY_SRCDIR"); +CFG_CONFIGDIR=CFG_CONFIGDIR or os.getenv("PROSODY_CFGDIR"); +CFG_PLUGINDIR=CFG_PLUGINDIR or os.getenv("PROSODY_PLUGINDIR"); +CFG_DATADIR=CFG_DATADIR or os.getenv("PROSODY_DATADIR"); -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +local function is_relative(path) + local path_sep = package.config:sub(1,1); + return ((path_sep == "/" and path:sub(1,1) ~= "/") + or (path_sep == "\\" and (path:sub(1,1) ~= "/" and path:sub(2,3) ~= ":\\"))) +end + -- Tell Lua where to find our libraries if CFG_SOURCEDIR then - package.path = CFG_SOURCEDIR.."/?.lua;"..package.path; - package.cpath = CFG_SOURCEDIR.."/?.so;"..package.cpath; + local function filter_relative_paths(path) + if is_relative(path) then return ""; end + end + local function sanitise_paths(paths) + return (paths:gsub("[^;]+;?", filter_relative_paths):gsub(";;+", ";")); + end + package.path = sanitise_paths(CFG_SOURCEDIR.."/?.lua;"..package.path); + package.cpath = sanitise_paths(CFG_SOURCEDIR.."/?.so;"..package.cpath); end -- Substitute ~ with path to home directory in data path @@ -29,9 +43,18 @@ if CFG_DATADIR then end end +if #arg > 0 and arg[1] ~= "--config" then + print("Unknown command-line option: "..tostring(arg[1])); + print("Perhaps you meant to use prosodyctl instead?"); + return 1; +end + -- Global 'prosody' object -prosody = { events = require "util.events".new(); }; -local prosody = prosody; +local prosody = { events = require "util.events".new(); }; +_G.prosody = prosody; + +-- Check dependencies +local dependencies = require "util.dependencies"; -- Load the config-parsing module config = require "core.configmanager" @@ -50,6 +73,8 @@ function read_config() if CFG_CONFIGDIR then table.insert(filenames, CFG_CONFIGDIR.."/"..arg[2]); end + elseif os.getenv("PROSODY_CONFIG") then -- Passed by prosodyctl + table.insert(filenames, os.getenv("PROSODY_CONFIG")); else for _, format in ipairs(config.parsers()) do table.insert(filenames, (CFG_CONFIGDIR or ".").."/prosody.cfg."..format); @@ -64,14 +89,21 @@ function read_config() break; end end + prosody.config_file = filename local ok, level, err = config.load(filename); if not ok then print("\n"); print("**************************"); if level == "parser" then - print("A problem occured while reading the config file "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua"); + print("A problem occured while reading the config file "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua"..":"); + print(""); local err_line, err_message = tostring(err):match("%[string .-%]:(%d*): (.*)"); - print("Error"..(err_line and (" on line "..err_line) or "")..": "..(err_message or tostring(err))); + if err:match("chunk has too many syntax levels$") then + print("An Include statement in a config file is including an already-included"); + print("file and causing an infinite loop. An Include statement in a config file is..."); + else + print("Error"..(err_line and (" on line "..err_line) or "")..": "..(err_message or tostring(err))); + end print(""); elseif level == "file" then print("Prosody was unable to find the configuration file."); @@ -79,7 +111,7 @@ function read_config() print("A sample config file is included in the Prosody download called prosody.cfg.lua.dist"); print("Copy or rename it to prosody.cfg.lua and edit as necessary."); end - print("More help on configuring Prosody can be found at http://prosody.im/doc/configure"); + print("More help on configuring Prosody can be found at https://prosody.im/doc/configure"); print("Good luck!"); print("**************************"); print(""); @@ -87,8 +119,15 @@ function read_config() end end +function check_dependencies() + if not dependencies.check_dependencies() then + os.exit(1); + end +end + function load_libraries() -- Load socket framework + socket = require "socket"; server = require "net.server" end @@ -97,11 +136,21 @@ function init_logging() require "core.loggingmanager" end -function check_dependencies() - -- Check runtime dependencies - if not require "util.dependencies".check_dependencies() then - os.exit(1); +function log_dependency_warnings() + dependencies.log_warnings(); +end + +function sanity_check() + for host, host_config in pairs(config.getconfig()) do + if host ~= "*" + and host_config.enabled ~= false + and not host_config.component_module then + return; + end end + log("error", "No enabled VirtualHost entries found in the config file."); + log("error", "At least one active host is required for Prosody to function. Exiting..."); + os.exit(1); end function sandbox_require() @@ -109,15 +158,26 @@ function sandbox_require() -- for neat sandboxing of modules local _realG = _G; local _real_require = require; + local getfenv = getfenv or function (f) + -- FIXME: This is a hack to replace getfenv() in Lua 5.2 + local name, env = debug.getupvalue(debug.getinfo(f or 1).func, 1); + if name == "_ENV" then + return env; + end + end function require(...) local curr_env = getfenv(2); - local curr_env_mt = getmetatable(getfenv(2)); + local curr_env_mt = getmetatable(curr_env); local _realG_mt = getmetatable(_realG); if curr_env_mt and curr_env_mt.__index and not curr_env_mt.__newindex and _realG_mt then - local old_newindex + local old_newindex, old_index; old_newindex, _realG_mt.__newindex = _realG_mt.__newindex, curr_env; + old_index, _realG_mt.__index = _realG_mt.__index, function (_G, k) + return rawget(curr_env, k); + end; local ret = _real_require(...); _realG_mt.__newindex = old_newindex; + _realG_mt.__index = old_index; return ret; end return _real_require(...); @@ -152,6 +212,7 @@ function set_function_metatable() end function init_global_state() + -- COMPAT: These globals are deprecated bare_sessions = {}; full_sessions = {}; hosts = {}; @@ -160,9 +221,16 @@ function init_global_state() prosody.full_sessions = full_sessions; prosody.hosts = hosts; - prosody.paths = { source = CFG_SOURCEDIR, config = CFG_CONFIGDIR, - plugins = CFG_PLUGINDIR, data = CFG_DATADIR }; - + local data_path = config.get("*", "data_path") or CFG_DATADIR or "data"; + local custom_plugin_paths = config.get("*", "plugin_paths"); + if custom_plugin_paths then + local path_sep = package.config:sub(3,3); + -- path1;path2;path3;defaultpath... + CFG_PLUGINDIR = table.concat(custom_plugin_paths, path_sep)..path_sep..(CFG_PLUGINDIR or "plugins"); + end + prosody.paths = { source = CFG_SOURCEDIR, config = CFG_CONFIGDIR or ".", + plugins = CFG_PLUGINDIR or "plugins", data = data_path }; + prosody.arg = _G.arg; prosody.platform = "unknown"; @@ -177,11 +245,16 @@ function init_global_state() prosody.installed = true; end + if prosody.installed then + -- Change working directory to data path. + require "lfs".chdir(data_path); + end + -- Function to reload the config file function prosody.reload_config() log("info", "Reloading configuration file"); prosody.events.fire_event("reloading-config"); - local ok, level, err = config.load((rawget(_G, "CFG_CONFIGDIR") or ".").."/prosody.cfg.lua"); + local ok, level, err = config.load(prosody.config_file); if not ok then if level == "parser" then log("error", "There was an error parsing the configuration file: %s", tostring(err)); @@ -199,73 +272,16 @@ function init_global_state() end -- Function to initiate prosody shutdown - function prosody.shutdown(reason) + function prosody.shutdown(reason, code) log("info", "Shutting down: %s", reason or "unknown reason"); prosody.shutdown_reason = reason; - prosody.events.fire_event("server-stopping", {reason = reason}); + prosody.shutdown_code = code; + prosody.events.fire_event("server-stopping", { + reason = reason; + code = code; + }); server.setquitting(true); end - - -- Load SSL settings from config, and create a ctx table - local certmanager = require "core.certmanager"; - local global_ssl_ctx = certmanager.create_context("*", "server"); - prosody.global_ssl_ctx = global_ssl_ctx; - - local cl = require "net.connlisteners"; - function prosody.net_activate_ports(option, listener, default, conntype) - conntype = conntype or (global_ssl_ctx and "tls") or "tcp"; - local ports_option = option and option.."_ports" or "ports"; - if not cl.get(listener) then return; end - local ports = config.get("*", "core", ports_option) or default; - if type(ports) == "number" then ports = {ports} end; - - if type(ports) ~= "table" then - log("error", "core."..ports_option.." is not a table"); - else - for _, port in ipairs(ports) do - port = tonumber(port); - if type(port) ~= "number" then - log("error", "Non-numeric "..ports_option..": "..tostring(port)); - else - local ok, err = cl.start(listener, { - ssl = conntype == "ssl" and global_ssl_ctx, - port = port, - interface = (option and config.get("*", "core", option.."_interface")) - or cl.get(listener).default_interface - or config.get("*", "core", "interface"), - type = conntype - }); - if not ok then - local friendly_message = err; - if err:match(" in use") then - if port == 5222 or port == 5223 or port == 5269 then - friendly_message = "check that Prosody or another XMPP server is " - .."not already running and using this port"; - elseif port == 80 or port == 81 then - friendly_message = "check that a HTTP server is not already using " - .."this port"; - elseif port == 5280 then - friendly_message = "check that Prosody or a BOSH connection manager " - .."is not already running"; - else - friendly_message = "this port is in use by another application"; - end - elseif err:match("permission") then - friendly_message = "Prosody does not have sufficient privileges to use this port"; - elseif err == "no ssl context" then - if not config.get("*", "core", "ssl") then - friendly_message = "there is no 'ssl' config under Host \"*\" which is " - .."require for legacy SSL ports"; - else - friendly_message = "initializing SSL support failed, see previous log entries"; - end - end - log("error", "Failed to open server port %d, %s", port, friendly_message); - end - end - end - end - end end function read_version() @@ -286,15 +302,16 @@ function load_secondary_libraries() --- Load and initialise core modules require "util.import" require "util.xmppstream" - require "core.xmlhandlers" - require "core.rostermanager" + require "core.stanza_router" + require "core.statsmanager" require "core.hostmanager" + require "core.portmanager" require "core.modulemanager" require "core.usermanager" + require "core.rostermanager" require "core.sessionmanager" - require "core.stanza_router" package.loaded['core.componentmanager'] = setmetatable({},{__index=function() - log("warn", "componentmanager is deprecated: %s", debug.traceback():match("\n[^\n]*\n[\s\t]*([^\n]*)")); + log("warn", "componentmanager is deprecated: %s", debug.traceback():match("\n[^\n]*\n[ \t]*([^\n]*)")); return function() end end}); @@ -315,21 +332,11 @@ function load_secondary_libraries() if remdebug then remdebug.engine.start() end ]] - require "net.connlisteners"; - require "util.stanza" require "util.jid" end function init_data_store() - local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data"; - require "util.datamanager".set_data_path(data_path); - require "util.datamanager".add_callback(function(username, host, datastore, data) - if config.get(host, "core", "anonymous_login") then - return false; - end - return username, host, datastore, data; - end); require "core.storagemanager"; end @@ -337,20 +344,6 @@ function prepare_to_start() log("info", "Prosody is using the %s backend for connection handling", server.get_backend()); -- Signal to modules that we are ready to start prosody.events.fire_event("server-starting"); - - -- start listening on sockets - if config.get("*", "core", "ports") then - prosody.net_activate_ports(nil, "multiplex", {5222, 5269}); - if config.get("*", "core", "ssl_ports") then - prosody.net_activate_ports("ssl", "multiplex", {5223}, "ssl"); - end - else - prosody.net_activate_ports("c2s", "xmppclient", {5222}); - prosody.net_activate_ports("s2s", "xmppserver", {5269}); - prosody.net_activate_ports("component", "xmppcomponent", {5347}, "tcp"); - prosody.net_activate_ports("legacy_ssl", "xmppclient", {}, "ssl"); - end - prosody.start_time = os.time(); end @@ -389,51 +382,16 @@ function loop() prosody.events.fire_event("very-bad-error", {error = err, traceback = traceback}); end + local sleep = require"socket".sleep; + while select(2, xpcall(server.loop, catch_uncaught_error)) ~= "quitting" do - socket.sleep(0.2); + sleep(0.2); end end function cleanup() log("info", "Shutdown status: Cleaning up"); prosody.events.fire_event("server-cleanup"); - - -- Ok, we're quitting I know, but we - -- need to do some tidying before we go :) - server.setquitting(false); - - log("info", "Shutdown status: Closing all active sessions"); - for hostname, host in pairs(hosts) do - log("debug", "Shutdown status: Closing client connections for %s", hostname) - if host.sessions then - local reason = { condition = "system-shutdown", text = "Server is shutting down" }; - if prosody.shutdown_reason then - reason.text = reason.text..": "..prosody.shutdown_reason; - end - for username, user in pairs(host.sessions) do - for resource, session in pairs(user.sessions) do - log("debug", "Closing connection for %s@%s/%s", username, hostname, resource); - session:close(reason); - end - end - end - - log("debug", "Shutdown status: Closing outgoing s2s connections from %s", hostname); - if host.s2sout then - for remotehost, session in pairs(host.s2sout) do - if session.close then - session:close("system-shutdown"); - else - log("warn", "Unable to close outgoing s2s session to %s, no session:close()?!", remotehost); - end - end - end - end - - log("info", "Shutdown status: Closing all server connections"); - server.closeall(); - - server.setquitting(true); end -- Are you ready? :) @@ -441,13 +399,15 @@ end -- previous steps to have already been performed read_config(); init_logging(); -check_dependencies(); +sanity_check(); sandbox_require(); set_function_metatable(); +check_dependencies(); load_libraries(); init_global_state(); read_version(); log("info", "Hello and welcome to Prosody version %s", prosody.version); +log_dependency_warnings(); load_secondary_libraries(); init_data_store(); init_global_protection(); @@ -462,3 +422,4 @@ cleanup(); prosody.events.fire_event("server-stopped"); log("info", "Shutdown complete"); +os.exit(prosody.shutdown_code)