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"
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 --- Initialize logging
66 require "core.loggingmanager"
68 --- Check runtime dependencies
69 require "util.dependencies"
71 --- Load socket framework
72 local server = require "net.server"
78 -- Global 'prosody' object
80 local prosody = prosody;
82 prosody.bare_sessions = bare_sessions;
83 prosody.full_sessions = full_sessions;
84 prosody.hosts = hosts;
86 prosody.paths = { source = CFG_SOURCEDIR, config = CFG_CONFIGDIR,
87 plugins = CFG_PLUGINDIR, data = CFG_DATADIR };
91 prosody.events = require "util.events".new();
93 -- Try to determine version
94 local version_file = io.open((CFG_SOURCEDIR or ".").."/prosody.version");
96 prosody.version = version_file:read("*a"):gsub("%s*$", "");
98 if #prosody.version == 12 and prosody.version:match("^[a-f0-9]+$") then
99 prosody.version = "hg:"..prosody.version;
102 prosody.version = "unknown";
105 log("info", "Hello and welcome to Prosody version %s", prosody.version);
107 --- Load and initialise core modules
108 require "util.import"
109 require "core.xmlhandlers"
110 require "core.rostermanager"
111 require "core.eventmanager"
112 require "core.hostmanager"
113 require "core.modulemanager"
114 require "core.usermanager"
115 require "core.sessionmanager"
116 require "core.stanza_router"
119 require "util.iterators"
122 -- Commented to protect us from
123 -- the second kind of people
125 pcall(require, "remdebug.engine");
126 if remdebug then remdebug.engine.start() end
129 local cl = require "net.connlisteners";
131 require "util.stanza"
134 ------------------------------------------------------------------------
137 ------------- Begin code without a home ---------------------
139 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";
140 require "util.datamanager".set_data_path(data_path);
141 require "util.datamanager".add_callback(function(username, host, datastore, data)
142 if config.get(host, "core", "anonymous_login") then
145 return username, host, datastore, data;
148 ----------- End of out-of-place code --------------
150 -- Function to reload the config file
151 function prosody.reload_config()
152 log("info", "Reloading configuration file");
153 prosody.events.fire_event("reloading-config");
154 local ok, level, err = config.load((rawget(_G, "CFG_CONFIGDIR") or ".").."/prosody.cfg.lua");
156 if level == "parser" then
157 log("error", "There was an error parsing the configuration file: %s", tostring(err));
158 elseif level == "file" then
159 log("error", "Couldn't read the config file when trying to reload: %s", tostring(err));
164 -- Function to reopen logfiles
165 function prosody.reopen_logfiles()
166 log("info", "Re-opening log files");
167 eventmanager.fire_event("reopen-log-files"); -- Handled by appropriate log sinks
168 prosody.events.fire_event("reopen-log-files");
171 -- Function to initiate prosody shutdown
172 function prosody.shutdown(reason)
173 log("info", "Shutting down: %s", reason or "unknown reason");
174 prosody.events.fire_event("server-stopping", {reason = reason});
175 server.setquitting(true);
178 -- Signal to modules that we are ready to start
179 eventmanager.fire_event("server-starting");
180 prosody.events.fire_event("server-starting");
182 -- Load SSL settings from config, and create a ctx table
183 local global_ssl_ctx = ssl and config.get("*", "core", "ssl");
184 if global_ssl_ctx then
185 local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
186 setmetatable(global_ssl_ctx, { __index = default_ssl_ctx });
189 -- start listening on sockets
190 function net_activate_ports(option, listener, default, conntype)
191 local ports = config.get("*", "core", option.."_ports") or default;
192 if type(ports) == "number" then ports = {ports} end;
194 if type(ports) ~= "table" then
195 log("error", "core."..option.." is not a table");
197 for _, port in ipairs(ports) do
198 if type(port) ~= "number" then
199 log("error", "Non-numeric "..option.."_ports: "..tostring(port));
202 ssl = conntype ~= "tcp" and global_ssl_ctx,
204 interface = config.get("*", "core", option.."_interface")
205 or cl.get(listener).default_interface
206 or config.get("*", "core", "interface"),
214 net_activate_ports("c2s", "xmppclient", {5222}, (global_ssl_ctx and "tls") or "tcp");
215 net_activate_ports("s2s", "xmppserver", {5269}, "tcp");
216 net_activate_ports("component", "xmppcomponent", {}, "tcp");
217 net_activate_ports("legacy_ssl", "xmppclient", {}, "ssl");
219 if cl.get("console") then
220 cl.start("console", { interface = config.get("*", "core", "console_interface") or "127.0.0.1" })
223 -- Catch global accesses --
224 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 }
226 function prosody.unlock_globals()
227 setmetatable(_G, nil);
230 function prosody.lock_globals()
231 setmetatable(_G, locked_globals_mt);
235 prosody.lock_globals();
237 prosody.start_time = os.time();
239 eventmanager.fire_event("server-started");
240 prosody.events.fire_event("server-started");
242 -- Error handler for errors that make it this far
243 local function catch_uncaught_error(err)
244 if err:match("%d*: interrupted!$") then
248 log("error", "Top-level error, please report:\n%s", tostring(err));
249 local traceback = debug.traceback("", 2);
251 log("error", "%s", traceback);
254 prosody.events.fire_event("very-bad-error", {error = err, traceback = traceback});
257 while select(2, xpcall(server.loop, catch_uncaught_error)) ~= "quitting" do
261 log("info", "Shutdown status: Cleaning up");
262 prosody.events.fire_event("server-cleanup");
264 -- Ok, we're quitting I know, but we
265 -- need to do some tidying before we go :)
266 server.setquitting(false);
268 log("info", "Shutdown status: Closing all active sessions");
269 for hostname, host in pairs(hosts) do
270 log("debug", "Shutdown status: Closing client connections for %s", hostname)
271 if host.sessions then
272 for username, user in pairs(host.sessions) do
273 for resource, session in pairs(user.sessions) do
274 log("debug", "Closing connection for %s@%s/%s", username, hostname, resource);
275 session:close("system-shutdown");
280 log("debug", "Shutdown status: Closing outgoing s2s connections from %s", hostname);
282 for remotehost, session in pairs(host.s2sout) do
283 if session.close then
284 session:close("system-shutdown");
286 log("warn", "Unable to close outgoing s2s session to %s, no session:close()?!", remotehost);
292 log("info", "Shutdown status: Closing all server connections");
295 server.setquitting(true);
297 eventmanager.fire_event("server-stopped");
298 prosody.events.fire_event("server-stopped");
299 log("info", "Shutdown status: Complete!");