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")
35 require "util.require";
37 config = require "core.configmanager"
39 function read_config()
40 -- TODO: Check for other formats when we add support for them
41 -- Use lfs? Make a new conf/ dir?
42 local ok, level, err = config.load((CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
45 print("**************************");
46 if level == "parser" then
47 print("A problem occured while reading the config file "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
48 local err_line, err_message = tostring(err):match("%[string .-%]:(%d*): (.*)");
49 print("Error"..(err_line and (" on line "..err_line) or "")..": "..(err_message or tostring(err)));
51 elseif level == "file" then
52 print("Prosody was unable to find the configuration file.");
53 print("We looked for: "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
54 print("A sample config file is included in the Prosody download called prosody.cfg.lua.dist");
55 print("Copy or rename it to prosody.cfg.lua and edit as necessary.");
57 print("More help on configuring Prosody can be found at http://prosody.im/doc/configure");
59 print("**************************");
65 function load_libraries()
66 --- Initialize logging
67 require "core.loggingmanager"
69 --- Check runtime dependencies
70 require "util.dependencies"
72 --- Load socket framework
73 server = require "net.server"
76 function init_global_state()
81 -- Global 'prosody' object
83 local prosody = prosody;
85 prosody.bare_sessions = bare_sessions;
86 prosody.full_sessions = full_sessions;
87 prosody.hosts = hosts;
89 prosody.paths = { source = CFG_SOURCEDIR, config = CFG_CONFIGDIR,
90 plugins = CFG_PLUGINDIR, data = CFG_DATADIR };
94 prosody.events = require "util.events".new();
96 prosody.platform = "unknown";
97 if os.getenv("WINDIR") then
98 prosody.platform = "windows";
99 elseif package.config:sub(1,1) == "/" then
100 prosody.platform = "posix";
103 prosody.installed = nil;
104 if CFG_SOURCEDIR and (prosody.platform == "windows" or CFG_SOURCEDIR:match("^/")) then
105 prosody.installed = true;
108 -- Function to reload the config file
109 function prosody.reload_config()
110 log("info", "Reloading configuration file");
111 prosody.events.fire_event("reloading-config");
112 local ok, level, err = config.load((rawget(_G, "CFG_CONFIGDIR") or ".").."/prosody.cfg.lua");
114 if level == "parser" then
115 log("error", "There was an error parsing the configuration file: %s", tostring(err));
116 elseif level == "file" then
117 log("error", "Couldn't read the config file when trying to reload: %s", tostring(err));
120 return ok, (err and tostring(level)..": "..tostring(err)) or nil;
123 -- Function to reopen logfiles
124 function prosody.reopen_logfiles()
125 log("info", "Re-opening log files");
126 eventmanager.fire_event("reopen-log-files"); -- Handled by appropriate log sinks
127 prosody.events.fire_event("reopen-log-files");
130 -- Function to initiate prosody shutdown
131 function prosody.shutdown(reason)
132 log("info", "Shutting down: %s", reason or "unknown reason");
133 prosody.shutdown_reason = reason;
134 prosody.events.fire_event("server-stopping", {reason = reason});
135 server.setquitting(true);
139 function read_version()
140 -- Try to determine version
141 local version_file = io.open((CFG_SOURCEDIR or ".").."/prosody.version");
143 prosody.version = version_file:read("*a"):gsub("%s*$", "");
144 version_file:close();
145 if #prosody.version == 12 and prosody.version:match("^[a-f0-9]+$") then
146 prosody.version = "hg:"..prosody.version;
149 prosody.version = "unknown";
153 function load_secondary_libraries()
154 --- Load and initialise core modules
155 require "util.import"
156 require "core.xmlhandlers"
157 require "core.rostermanager"
158 require "core.eventmanager"
159 require "core.hostmanager"
160 require "core.modulemanager"
161 require "core.usermanager"
162 require "core.sessionmanager"
163 require "core.stanza_router"
168 require "util.datetime"
169 require "util.iterators"
171 require "util.helpers"
173 pcall(require, "util.signal") -- Not on Windows
175 -- Commented to protect us from
176 -- the second kind of people
178 pcall(require, "remdebug.engine");
179 if remdebug then remdebug.engine.start() end
182 require "net.connlisteners";
184 require "util.stanza"
188 function init_data_store()
189 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";
190 require "util.datamanager".set_data_path(data_path);
191 require "util.datamanager".add_callback(function(username, host, datastore, data)
192 if config.get(host, "core", "anonymous_login") then
195 return username, host, datastore, data;
199 function prepare_to_start()
200 -- Signal to modules that we are ready to start
201 eventmanager.fire_event("server-starting");
202 prosody.events.fire_event("server-starting");
204 -- Load SSL settings from config, and create a ctx table
205 local global_ssl_ctx = ssl and config.get("*", "core", "ssl");
206 if global_ssl_ctx then
207 local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
208 setmetatable(global_ssl_ctx, { __index = default_ssl_ctx });
211 local cl = require "net.connlisteners";
212 -- start listening on sockets
213 function prosody.net_activate_ports(option, listener, default, conntype)
214 if not cl.get(listener) then return; end
215 local ports = config.get("*", "core", option.."_ports") or default;
216 if type(ports) == "number" then ports = {ports} end;
218 if type(ports) ~= "table" then
219 log("error", "core."..option.." is not a table");
221 for _, port in ipairs(ports) do
222 if type(port) ~= "number" then
223 log("error", "Non-numeric "..option.."_ports: "..tostring(port));
226 ssl = conntype ~= "tcp" and global_ssl_ctx,
228 interface = config.get("*", "core", option.."_interface")
229 or cl.get(listener).default_interface
230 or config.get("*", "core", "interface"),
238 prosody.net_activate_ports("c2s", "xmppclient", {5222}, (global_ssl_ctx and "tls") or "tcp");
239 prosody.net_activate_ports("s2s", "xmppserver", {5269}, (global_ssl_ctx and "tls") or "tcp");
240 prosody.net_activate_ports("component", "xmppcomponent", {}, "tcp");
241 prosody.net_activate_ports("legacy_ssl", "xmppclient", {}, "ssl");
242 prosody.net_activate_ports("console", "console", {5582}, "tcp");
244 prosody.start_time = os.time();
247 function init_global_protection()
248 -- Catch global accesses --
249 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 }
251 function prosody.unlock_globals()
252 setmetatable(_G, nil);
255 function prosody.lock_globals()
256 setmetatable(_G, locked_globals_mt);
260 prosody.lock_globals();
264 -- Error handler for errors that make it this far
265 local function catch_uncaught_error(err)
266 if err:match("%d*: interrupted!$") then
270 log("error", "Top-level error, please report:\n%s", tostring(err));
271 local traceback = debug.traceback("", 2);
273 log("error", "%s", traceback);
276 prosody.events.fire_event("very-bad-error", {error = err, traceback = traceback});
279 while select(2, xpcall(server.loop, catch_uncaught_error)) ~= "quitting" do
285 log("info", "Shutdown status: Cleaning up");
286 prosody.events.fire_event("server-cleanup");
288 -- Ok, we're quitting I know, but we
289 -- need to do some tidying before we go :)
290 server.setquitting(false);
292 log("info", "Shutdown status: Closing all active sessions");
293 for hostname, host in pairs(hosts) do
294 log("debug", "Shutdown status: Closing client connections for %s", hostname)
295 if host.sessions then
296 local reason = { condition = "system-shutdown", text = "Server is shutting down" };
297 if prosody.shutdown_reason then
298 reason.text = reason.text..": "..prosody.shutdown_reason;
300 for username, user in pairs(host.sessions) do
301 for resource, session in pairs(user.sessions) do
302 log("debug", "Closing connection for %s@%s/%s", username, hostname, resource);
303 session:close(reason);
308 log("debug", "Shutdown status: Closing outgoing s2s connections from %s", hostname);
310 for remotehost, session in pairs(host.s2sout) do
311 if session.close then
312 session:close("system-shutdown");
314 log("warn", "Unable to close outgoing s2s session to %s, no session:close()?!", remotehost);
320 log("info", "Shutdown status: Closing all server connections");
323 server.setquitting(true);
330 log("info", "Hello and welcome to Prosody version %s", prosody.version);
331 load_secondary_libraries();
333 init_global_protection();
336 eventmanager.fire_event("server-started");
337 prosody.events.fire_event("server-started");
341 log("info", "Shutting down...");
343 eventmanager.fire_event("server-stopped");
344 prosody.events.fire_event("server-stopped");
345 log("info", "Shutdown complete");