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 --
13 CFG_CONFIGDIR=os.getenv("PROSODY_CFGDIR");
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("**************************");
67 function load_libraries()
68 --- Initialize logging
69 require "core.loggingmanager"
71 --- Check runtime dependencies
72 require "util.dependencies"
74 --- Load socket framework
75 server = require "net.server"
79 function init_global_state()
84 -- Global 'prosody' object
86 local prosody = prosody;
88 prosody.bare_sessions = bare_sessions;
89 prosody.full_sessions = full_sessions;
90 prosody.hosts = hosts;
92 prosody.paths = { source = CFG_SOURCEDIR, config = CFG_CONFIGDIR,
93 plugins = CFG_PLUGINDIR, data = CFG_DATADIR };
97 prosody.events = require "util.events".new();
102 function read_version()
103 -- Try to determine version
104 local version_file = io.open((CFG_SOURCEDIR or ".").."/prosody.version");
106 prosody.version = version_file:read("*a"):gsub("%s*$", "");
107 version_file:close();
108 if #prosody.version == 12 and prosody.version:match("^[a-f0-9]+$") then
109 prosody.version = "hg:"..prosody.version;
112 prosody.version = "unknown";
116 log("info", "Hello and welcome to Prosody version %s", prosody.version);
118 function load_secondary_libraries()
119 --- Load and initialise core modules
120 require "util.import"
121 require "core.xmlhandlers"
122 require "core.rostermanager"
123 require "core.eventmanager"
124 require "core.hostmanager"
125 require "core.modulemanager"
126 require "core.usermanager"
127 require "core.sessionmanager"
128 require "core.stanza_router"
131 require "util.iterators"
134 -- Commented to protect us from
135 -- the second kind of people
137 pcall(require, "remdebug.engine");
138 if remdebug then remdebug.engine.start() end
141 require "net.connlisteners";
143 require "util.stanza"
146 load_secondary_libraries();
149 function init_data_store()
150 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";
151 require "util.datamanager".set_data_path(data_path);
152 require "util.datamanager".add_callback(function(username, host, datastore, data)
153 if config.get(host, "core", "anonymous_login") then
156 return username, host, datastore, data;
161 -- Function to reload the config file
162 function prosody.reload_config()
163 log("info", "Reloading configuration file");
164 prosody.events.fire_event("reloading-config");
165 local ok, level, err = config.load((rawget(_G, "CFG_CONFIGDIR") or ".").."/prosody.cfg.lua");
167 if level == "parser" then
168 log("error", "There was an error parsing the configuration file: %s", tostring(err));
169 elseif level == "file" then
170 log("error", "Couldn't read the config file when trying to reload: %s", tostring(err));
175 -- Function to reopen logfiles
176 function prosody.reopen_logfiles()
177 log("info", "Re-opening log files");
178 eventmanager.fire_event("reopen-log-files"); -- Handled by appropriate log sinks
179 prosody.events.fire_event("reopen-log-files");
182 -- Function to initiate prosody shutdown
183 function prosody.shutdown(reason)
184 log("info", "Shutting down: %s", reason or "unknown reason");
185 prosody.events.fire_event("server-stopping", {reason = reason});
186 server.setquitting(true);
189 function prosody.prepare_to_start()
190 -- Signal to modules that we are ready to start
191 eventmanager.fire_event("server-starting");
192 prosody.events.fire_event("server-starting");
194 -- Load SSL settings from config, and create a ctx table
195 local global_ssl_ctx = ssl and config.get("*", "core", "ssl");
196 if global_ssl_ctx then
197 local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
198 setmetatable(global_ssl_ctx, { __index = default_ssl_ctx });
201 local cl = require "net.connlisteners";
202 -- start listening on sockets
203 function net_activate_ports(option, listener, default, conntype)
204 local ports = config.get("*", "core", option.."_ports") or default;
205 if type(ports) == "number" then ports = {ports} end;
207 if type(ports) ~= "table" then
208 log("error", "core."..option.." is not a table");
210 for _, port in ipairs(ports) do
211 if type(port) ~= "number" then
212 log("error", "Non-numeric "..option.."_ports: "..tostring(port));
215 ssl = conntype ~= "tcp" and global_ssl_ctx,
217 interface = config.get("*", "core", option.."_interface")
218 or cl.get(listener).default_interface
219 or config.get("*", "core", "interface"),
227 net_activate_ports("c2s", "xmppclient", {5222}, (global_ssl_ctx and "tls") or "tcp");
228 net_activate_ports("s2s", "xmppserver", {5269}, "tcp");
229 net_activate_ports("component", "xmppcomponent", {}, "tcp");
230 net_activate_ports("legacy_ssl", "xmppclient", {}, "ssl");
232 if cl.get("console") then
233 cl.start("console", { interface = config.get("*", "core", "console_interface") or "127.0.0.1" })
236 prosody.start_time = os.time();
238 prosody.prepare_to_start();
240 function prosody.init_global_protection()
241 -- Catch global accesses --
242 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 }
244 function prosody.unlock_globals()
245 setmetatable(_G, nil);
248 function prosody.lock_globals()
249 setmetatable(_G, locked_globals_mt);
253 prosody.lock_globals();
255 prosody.init_global_protection();
258 eventmanager.fire_event("server-started");
259 prosody.events.fire_event("server-started");
261 function prosody.loop()
262 -- Error handler for errors that make it this far
263 local function catch_uncaught_error(err)
264 if err:match("%d*: interrupted!$") then
268 log("error", "Top-level error, please report:\n%s", tostring(err));
269 local traceback = debug.traceback("", 2);
271 log("error", "%s", traceback);
274 prosody.events.fire_event("very-bad-error", {error = err, traceback = traceback});
277 while select(2, xpcall(server.loop, catch_uncaught_error)) ~= "quitting" do
283 function prosody.cleanup()
284 log("info", "Shutdown status: Cleaning up");
285 prosody.events.fire_event("server-cleanup");
287 -- Ok, we're quitting I know, but we
288 -- need to do some tidying before we go :)
289 server.setquitting(false);
291 log("info", "Shutdown status: Closing all active sessions");
292 for hostname, host in pairs(hosts) do
293 log("debug", "Shutdown status: Closing client connections for %s", hostname)
294 if host.sessions then
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("system-shutdown");
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);
322 eventmanager.fire_event("server-stopped");
323 prosody.events.fire_event("server-stopped");
324 log("info", "Shutdown status: Complete!");