3 -- Copyright (C) 2008-2009 Matthew Wild
4 -- Copyright (C) 2008-2009 Waqas Hussain
6 -- This project is MIT/X11 licensed. Please see the
7 -- COPYING file in the source package for more information.
10 -- Will be modified by configure script if run --
12 CFG_SOURCEDIR=os.getenv("PROSODY_SRCDIR");
13 CFG_CONFIGDIR=os.getenv("PROSODY_CFGDIR");
14 CFG_PLUGINDIR=os.getenv("PROSODY_PLUGINDIR");
15 CFG_DATADIR=os.getenv("PROSODY_DATADIR");
17 -- -- -- -- -- -- -- ---- -- -- -- -- -- -- -- --
20 package.path = CFG_SOURCEDIR.."/?.lua;"..package.path;
21 package.cpath = CFG_SOURCEDIR.."/?.so;"..package.cpath;
24 package.path = package.path..";"..(CFG_SOURCEDIR or ".").."/fallbacks/?.lua";
25 package.cpath = package.cpath..";"..(CFG_SOURCEDIR or ".").."/fallbacks/?.so";
28 if os.getenv("HOME") then
29 CFG_DATADIR = CFG_DATADIR:gsub("^~", os.getenv("HOME"));
33 -- Required to be able to find packages installed with luarocks
34 pcall(require, "luarocks.require")
36 -- Replace require with one that doesn't pollute _G
39 local _real_require = require;
41 local curr_env = getfenv(2);
42 local curr_env_mt = getmetatable(getfenv(2));
43 local _realG_mt = getmetatable(_realG);
44 if curr_env_mt and curr_env_mt.__index and not curr_env_mt.__newindex and _realG_mt then
46 old_newindex, _realG_mt.__newindex = _realG_mt.__newindex, curr_env;
47 local ret = _real_require(...);
48 _realG_mt.__newindex = old_newindex;
51 return _real_require(...);
56 config = require "core.configmanager"
58 function read_config()
59 -- TODO: Check for other formats when we add support for them
60 -- Use lfs? Make a new conf/ dir?
61 local ok, level, err = config.load((CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
64 print("**************************");
65 if level == "parser" then
66 print("A problem occured while reading the config file "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
67 local err_line, err_message = tostring(err):match("%[string .-%]:(%d*): (.*)");
68 print("Error"..(err_line and (" on line "..err_line) or "")..": "..(err_message or tostring(err)));
70 elseif level == "file" then
71 print("Prosody was unable to find the configuration file.");
72 print("We looked for: "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
73 print("A sample config file is included in the Prosody download called prosody.cfg.lua.dist");
74 print("Copy or rename it to prosody.cfg.lua and edit as necessary.");
76 print("More help on configuring Prosody can be found at http://prosody.im/doc/configure");
78 print("**************************");
84 function load_libraries()
85 --- Initialize logging
86 require "core.loggingmanager"
88 --- Check runtime dependencies
89 require "util.dependencies"
91 --- Load socket framework
92 server = require "net.server"
95 function init_global_state()
100 -- Global 'prosody' object
102 local prosody = prosody;
104 prosody.bare_sessions = bare_sessions;
105 prosody.full_sessions = full_sessions;
106 prosody.hosts = hosts;
108 prosody.paths = { source = CFG_SOURCEDIR, config = CFG_CONFIGDIR,
109 plugins = CFG_PLUGINDIR, data = CFG_DATADIR };
111 prosody.arg = _G.arg;
113 prosody.events = require "util.events".new();
115 prosody.platform = "unknown";
116 if os.getenv("WINDIR") then
117 prosody.platform = "windows";
118 elseif package.config:sub(1,1) == "/" then
119 prosody.platform = "posix";
122 prosody.installed = nil;
123 if CFG_SOURCEDIR and (prosody.platform == "windows" or CFG_SOURCEDIR:match("^/")) then
124 prosody.installed = true;
127 -- Function to reload the config file
128 function prosody.reload_config()
129 log("info", "Reloading configuration file");
130 prosody.events.fire_event("reloading-config");
131 local ok, level, err = config.load((rawget(_G, "CFG_CONFIGDIR") or ".").."/prosody.cfg.lua");
133 if level == "parser" then
134 log("error", "There was an error parsing the configuration file: %s", tostring(err));
135 elseif level == "file" then
136 log("error", "Couldn't read the config file when trying to reload: %s", tostring(err));
139 return ok, (err and tostring(level)..": "..tostring(err)) or nil;
142 -- Function to reopen logfiles
143 function prosody.reopen_logfiles()
144 log("info", "Re-opening log files");
145 eventmanager.fire_event("reopen-log-files"); -- Handled by appropriate log sinks
146 prosody.events.fire_event("reopen-log-files");
149 -- Function to initiate prosody shutdown
150 function prosody.shutdown(reason)
151 log("info", "Shutting down: %s", reason or "unknown reason");
152 prosody.shutdown_reason = reason;
153 prosody.events.fire_event("server-stopping", {reason = reason});
154 server.setquitting(true);
158 function read_version()
159 -- Try to determine version
160 local version_file = io.open((CFG_SOURCEDIR or ".").."/prosody.version");
162 prosody.version = version_file:read("*a"):gsub("%s*$", "");
163 version_file:close();
164 if #prosody.version == 12 and prosody.version:match("^[a-f0-9]+$") then
165 prosody.version = "hg:"..prosody.version;
168 prosody.version = "unknown";
172 function load_secondary_libraries()
173 --- Load and initialise core modules
174 require "util.import"
175 require "core.xmlhandlers"
176 require "core.rostermanager"
177 require "core.eventmanager"
178 require "core.hostmanager"
179 require "core.modulemanager"
180 require "core.usermanager"
181 require "core.sessionmanager"
182 require "core.stanza_router"
187 require "util.datetime"
188 require "util.iterators"
190 require "util.helpers"
192 pcall(require, "util.signal") -- Not on Windows
194 -- Commented to protect us from
195 -- the second kind of people
197 pcall(require, "remdebug.engine");
198 if remdebug then remdebug.engine.start() end
201 require "net.connlisteners";
203 require "util.stanza"
207 function init_data_store()
208 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";
209 require "util.datamanager".set_data_path(data_path);
210 require "util.datamanager".add_callback(function(username, host, datastore, data)
211 if config.get(host, "core", "anonymous_login") then
214 return username, host, datastore, data;
218 function prepare_to_start()
219 -- Signal to modules that we are ready to start
220 eventmanager.fire_event("server-starting");
221 prosody.events.fire_event("server-starting");
223 -- Load SSL settings from config, and create a ctx table
224 local global_ssl_ctx = rawget(_G, "ssl") and config.get("*", "core", "ssl");
225 if global_ssl_ctx then
226 local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
227 setmetatable(global_ssl_ctx, { __index = default_ssl_ctx });
230 local cl = require "net.connlisteners";
231 -- start listening on sockets
232 function prosody.net_activate_ports(option, listener, default, conntype)
233 if not cl.get(listener) then return; end
234 local ports = config.get("*", "core", option.."_ports") or default;
235 if type(ports) == "number" then ports = {ports} end;
237 if type(ports) ~= "table" then
238 log("error", "core."..option.." is not a table");
240 for _, port in ipairs(ports) do
241 if type(port) ~= "number" then
242 log("error", "Non-numeric "..option.."_ports: "..tostring(port));
245 ssl = conntype ~= "tcp" and global_ssl_ctx,
247 interface = config.get("*", "core", option.."_interface")
248 or cl.get(listener).default_interface
249 or config.get("*", "core", "interface"),
257 prosody.net_activate_ports("c2s", "xmppclient", {5222}, (global_ssl_ctx and "tls") or "tcp");
258 prosody.net_activate_ports("s2s", "xmppserver", {5269}, (global_ssl_ctx and "tls") or "tcp");
259 prosody.net_activate_ports("component", "xmppcomponent", {}, "tcp");
260 prosody.net_activate_ports("legacy_ssl", "xmppclient", {}, "ssl");
261 prosody.net_activate_ports("console", "console", {5582}, "tcp");
263 prosody.start_time = os.time();
266 function init_global_protection()
267 -- Catch global accesses --
268 local locked_globals_mt = { __index = function (t, k) error("Attempt to read a non-existent global '"..k.."'", 2); end, __newindex = function (t, k, v) error("Attempt to set a global: "..tostring(k).." = "..tostring(v), 2); end }
270 function prosody.unlock_globals()
271 setmetatable(_G, nil);
274 function prosody.lock_globals()
275 setmetatable(_G, locked_globals_mt);
279 prosody.lock_globals();
283 -- Error handler for errors that make it this far
284 local function catch_uncaught_error(err)
285 if type(err) == "string" and err:match("%d*: interrupted!$") then
289 log("error", "Top-level error, please report:\n%s", tostring(err));
290 local traceback = debug.traceback("", 2);
292 log("error", "%s", traceback);
295 prosody.events.fire_event("very-bad-error", {error = err, traceback = traceback});
298 while select(2, xpcall(server.loop, catch_uncaught_error)) ~= "quitting" do
304 log("info", "Shutdown status: Cleaning up");
305 prosody.events.fire_event("server-cleanup");
307 -- Ok, we're quitting I know, but we
308 -- need to do some tidying before we go :)
309 server.setquitting(false);
311 log("info", "Shutdown status: Closing all active sessions");
312 for hostname, host in pairs(hosts) do
313 log("debug", "Shutdown status: Closing client connections for %s", hostname)
314 if host.sessions then
315 local reason = { condition = "system-shutdown", text = "Server is shutting down" };
316 if prosody.shutdown_reason then
317 reason.text = reason.text..": "..prosody.shutdown_reason;
319 for username, user in pairs(host.sessions) do
320 for resource, session in pairs(user.sessions) do
321 log("debug", "Closing connection for %s@%s/%s", username, hostname, resource);
322 session:close(reason);
327 log("debug", "Shutdown status: Closing outgoing s2s connections from %s", hostname);
329 for remotehost, session in pairs(host.s2sout) do
330 if session.close then
331 session:close("system-shutdown");
333 log("warn", "Unable to close outgoing s2s session to %s, no session:close()?!", remotehost);
339 log("info", "Shutdown status: Closing all server connections");
342 server.setquitting(true);
349 log("info", "Hello and welcome to Prosody version %s", prosody.version);
350 load_secondary_libraries();
352 init_global_protection();
355 eventmanager.fire_event("server-started");
356 prosody.events.fire_event("server-started");
360 log("info", "Shutting down...");
362 eventmanager.fire_event("server-stopped");
363 prosody.events.fire_event("server-stopped");
364 log("info", "Shutdown complete");