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();
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"
166 require "util.iterators"
168 require "util.helpers"
170 -- Commented to protect us from
171 -- the second kind of people
173 pcall(require, "remdebug.engine");
174 if remdebug then remdebug.engine.start() end
177 require "net.connlisteners";
179 require "util.stanza"
183 function init_data_store()
184 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";
185 require "util.datamanager".set_data_path(data_path);
186 require "util.datamanager".add_callback(function(username, host, datastore, data)
187 if config.get(host, "core", "anonymous_login") then
190 return username, host, datastore, data;
194 function prepare_to_start()
195 -- Signal to modules that we are ready to start
196 eventmanager.fire_event("server-starting");
197 prosody.events.fire_event("server-starting");
199 -- Load SSL settings from config, and create a ctx table
200 local global_ssl_ctx = ssl and config.get("*", "core", "ssl");
201 if global_ssl_ctx then
202 local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
203 setmetatable(global_ssl_ctx, { __index = default_ssl_ctx });
206 local cl = require "net.connlisteners";
207 -- start listening on sockets
208 function net_activate_ports(option, listener, default, conntype)
209 if not cl.get(listener) then return; end
210 local ports = config.get("*", "core", option.."_ports") or default;
211 if type(ports) == "number" then ports = {ports} end;
213 if type(ports) ~= "table" then
214 log("error", "core."..option.." is not a table");
216 for _, port in ipairs(ports) do
217 if type(port) ~= "number" then
218 log("error", "Non-numeric "..option.."_ports: "..tostring(port));
221 ssl = conntype ~= "tcp" and global_ssl_ctx,
223 interface = config.get("*", "core", option.."_interface")
224 or cl.get(listener).default_interface
225 or config.get("*", "core", "interface"),
233 net_activate_ports("c2s", "xmppclient", {5222}, (global_ssl_ctx and "tls") or "tcp");
234 net_activate_ports("s2s", "xmppserver", {5269}, "tcp");
235 net_activate_ports("component", "xmppcomponent", {}, "tcp");
236 net_activate_ports("legacy_ssl", "xmppclient", {}, "ssl");
237 net_activate_ports("console", "console", {5582}, "tcp");
239 prosody.start_time = os.time();
242 function init_global_protection()
243 -- Catch global accesses --
244 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 }
246 function prosody.unlock_globals()
247 setmetatable(_G, nil);
250 function prosody.lock_globals()
251 setmetatable(_G, locked_globals_mt);
255 prosody.lock_globals();
259 -- Error handler for errors that make it this far
260 local function catch_uncaught_error(err)
261 if err:match("%d*: interrupted!$") then
265 log("error", "Top-level error, please report:\n%s", tostring(err));
266 local traceback = debug.traceback("", 2);
268 log("error", "%s", traceback);
271 prosody.events.fire_event("very-bad-error", {error = err, traceback = traceback});
274 while select(2, xpcall(server.loop, catch_uncaught_error)) ~= "quitting" do
280 log("info", "Shutdown status: Cleaning up");
281 prosody.events.fire_event("server-cleanup");
283 -- Ok, we're quitting I know, but we
284 -- need to do some tidying before we go :)
285 server.setquitting(false);
287 log("info", "Shutdown status: Closing all active sessions");
288 for hostname, host in pairs(hosts) do
289 log("debug", "Shutdown status: Closing client connections for %s", hostname)
290 if host.sessions then
291 local reason = { condition = "system-shutdown", text = "Server is shutting down" };
292 if prosody.shutdown_reason then
293 reason.text = reason.text..": "..prosody.shutdown_reason;
295 for username, user in pairs(host.sessions) do
296 for resource, session in pairs(user.sessions) do
297 log("debug", "Closing connection for %s@%s/%s", username, hostname, resource);
298 session:close(reason);
303 log("debug", "Shutdown status: Closing outgoing s2s connections from %s", hostname);
305 for remotehost, session in pairs(host.s2sout) do
306 if session.close then
307 session:close("system-shutdown");
309 log("warn", "Unable to close outgoing s2s session to %s, no session:close()?!", remotehost);
315 log("info", "Shutdown status: Closing all server connections");
318 server.setquitting(true);
325 log("info", "Hello and welcome to Prosody version %s", prosody.version);
326 load_secondary_libraries();
329 init_global_protection();
331 eventmanager.fire_event("server-started");
332 prosody.events.fire_event("server-started");
336 log("info", "Shutting down...");
338 eventmanager.fire_event("server-stopped");
339 prosody.events.fire_event("server-stopped");
340 log("info", "Shutdown complete");