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")
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();
97 -- Function to reload the config file
98 function prosody.reload_config()
99 log("info", "Reloading configuration file");
100 prosody.events.fire_event("reloading-config");
101 local ok, level, err = config.load((rawget(_G, "CFG_CONFIGDIR") or ".").."/prosody.cfg.lua");
103 if level == "parser" then
104 log("error", "There was an error parsing the configuration file: %s", tostring(err));
105 elseif level == "file" then
106 log("error", "Couldn't read the config file when trying to reload: %s", tostring(err));
109 return ok, (err and tostring(level)..": "..tostring(err)) or nil;
112 -- Function to reopen logfiles
113 function prosody.reopen_logfiles()
114 log("info", "Re-opening log files");
115 eventmanager.fire_event("reopen-log-files"); -- Handled by appropriate log sinks
116 prosody.events.fire_event("reopen-log-files");
119 -- Function to initiate prosody shutdown
120 function prosody.shutdown(reason)
121 log("info", "Shutting down: %s", reason or "unknown reason");
122 prosody.shutdown_reason = reason;
123 prosody.events.fire_event("server-stopping", {reason = reason});
124 server.setquitting(true);
128 function read_version()
129 -- Try to determine version
130 local version_file = io.open((CFG_SOURCEDIR or ".").."/prosody.version");
132 prosody.version = version_file:read("*a"):gsub("%s*$", "");
133 version_file:close();
134 if #prosody.version == 12 and prosody.version:match("^[a-f0-9]+$") then
135 prosody.version = "hg:"..prosody.version;
138 prosody.version = "unknown";
142 function load_secondary_libraries()
143 --- Load and initialise core modules
144 require "util.import"
145 require "core.xmlhandlers"
146 require "core.rostermanager"
147 require "core.eventmanager"
148 require "core.hostmanager"
149 require "core.modulemanager"
150 require "core.usermanager"
151 require "core.sessionmanager"
152 require "core.stanza_router"
155 require "util.iterators"
157 require "util.helpers"
159 -- Commented to protect us from
160 -- the second kind of people
162 pcall(require, "remdebug.engine");
163 if remdebug then remdebug.engine.start() end
166 require "net.connlisteners";
168 require "util.stanza"
172 function init_data_store()
173 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";
174 require "util.datamanager".set_data_path(data_path);
175 require "util.datamanager".add_callback(function(username, host, datastore, data)
176 if config.get(host, "core", "anonymous_login") then
179 return username, host, datastore, data;
183 function prepare_to_start()
184 -- Signal to modules that we are ready to start
185 eventmanager.fire_event("server-starting");
186 prosody.events.fire_event("server-starting");
188 -- Load SSL settings from config, and create a ctx table
189 local global_ssl_ctx = ssl and config.get("*", "core", "ssl");
190 if global_ssl_ctx then
191 local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
192 setmetatable(global_ssl_ctx, { __index = default_ssl_ctx });
195 local cl = require "net.connlisteners";
196 -- start listening on sockets
197 function net_activate_ports(option, listener, default, conntype)
198 if not cl.get(listener) then return; end
199 local ports = config.get("*", "core", option.."_ports") or default;
200 if type(ports) == "number" then ports = {ports} end;
202 if type(ports) ~= "table" then
203 log("error", "core."..option.." is not a table");
205 for _, port in ipairs(ports) do
206 if type(port) ~= "number" then
207 log("error", "Non-numeric "..option.."_ports: "..tostring(port));
210 ssl = conntype ~= "tcp" and global_ssl_ctx,
212 interface = config.get("*", "core", option.."_interface")
213 or cl.get(listener).default_interface
214 or config.get("*", "core", "interface"),
222 net_activate_ports("c2s", "xmppclient", {5222}, (global_ssl_ctx and "tls") or "tcp");
223 net_activate_ports("s2s", "xmppserver", {5269}, "tcp");
224 net_activate_ports("component", "xmppcomponent", {}, "tcp");
225 net_activate_ports("legacy_ssl", "xmppclient", {}, "ssl");
226 net_activate_ports("console", "console", {5582}, "tcp");
228 prosody.start_time = os.time();
231 function init_global_protection()
232 -- Catch global accesses --
233 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 }
235 function prosody.unlock_globals()
236 setmetatable(_G, nil);
239 function prosody.lock_globals()
240 setmetatable(_G, locked_globals_mt);
244 prosody.lock_globals();
248 -- Error handler for errors that make it this far
249 local function catch_uncaught_error(err)
250 if err:match("%d*: interrupted!$") then
254 log("error", "Top-level error, please report:\n%s", tostring(err));
255 local traceback = debug.traceback("", 2);
257 log("error", "%s", traceback);
260 prosody.events.fire_event("very-bad-error", {error = err, traceback = traceback});
263 while select(2, xpcall(server.loop, catch_uncaught_error)) ~= "quitting" do
269 log("info", "Shutdown status: Cleaning up");
270 prosody.events.fire_event("server-cleanup");
272 -- Ok, we're quitting I know, but we
273 -- need to do some tidying before we go :)
274 server.setquitting(false);
276 log("info", "Shutdown status: Closing all active sessions");
277 for hostname, host in pairs(hosts) do
278 log("debug", "Shutdown status: Closing client connections for %s", hostname)
279 if host.sessions then
280 local reason = { condition = "system-shutdown", text = "Server is shutting down" };
281 if prosody.shutdown_reason then
282 reason.text = reason.text..": "..prosody.shutdown_reason;
284 for username, user in pairs(host.sessions) do
285 for resource, session in pairs(user.sessions) do
286 log("debug", "Closing connection for %s@%s/%s", username, hostname, resource);
287 session:close(reason);
292 log("debug", "Shutdown status: Closing outgoing s2s connections from %s", hostname);
294 for remotehost, session in pairs(host.s2sout) do
295 if session.close then
296 session:close("system-shutdown");
298 log("warn", "Unable to close outgoing s2s session to %s, no session:close()?!", remotehost);
304 log("info", "Shutdown status: Closing all server connections");
307 server.setquitting(true);
314 log("info", "Hello and welcome to Prosody version %s", prosody.version);
315 load_secondary_libraries();
318 init_global_protection();
320 eventmanager.fire_event("server-started");
321 prosody.events.fire_event("server-started");
325 log("info", "Shutting down...");
327 eventmanager.fire_event("server-stopped");
328 prosody.events.fire_event("server-stopped");
329 log("info", "Shutdown complete");