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
25 if os.getenv("HOME") then
26 CFG_DATADIR = CFG_DATADIR:gsub("^~", os.getenv("HOME"));
30 -- Required to be able to find packages installed with luarocks
31 pcall(require, "luarocks.require")
34 config = require "core.configmanager"
37 -- TODO: Check for other formats when we add support for them
38 -- Use lfs? Make a new conf/ dir?
39 local ok, level, err = config.load((CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
42 print("**************************");
43 if level == "parser" then
44 print("A problem occured while reading the config file "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
45 local err_line, err_message = tostring(err):match("%[string .-%]:(%d*): (.*)");
46 print("Error"..(err_line and (" on line "..err_line) or "")..": "..(err_message or tostring(err)));
48 elseif level == "file" then
49 print("Prosody was unable to find the configuration file.");
50 print("We looked for: "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
51 print("A sample config file is included in the Prosody download called prosody.cfg.lua.dist");
52 print("Copy or rename it to prosody.cfg.lua and edit as necessary.");
54 print("More help on configuring Prosody can be found at http://prosody.im/doc/configure");
56 print("**************************");
62 --- Initialize logging
63 require "core.loggingmanager"
65 --- Check runtime dependencies
66 require "util.dependencies"
68 --- Load socket framework
69 local server = require "net.server"
75 -- Global 'prosody' object
77 local prosody = prosody;
79 prosody.bare_sessions = bare_sessions;
80 prosody.full_sessions = full_sessions;
81 prosody.hosts = hosts;
83 prosody.paths = { source = CFG_SOURCEDIR, config = CFG_CONFIGDIR,
84 plugins = CFG_PLUGINDIR, data = CFG_DATADIR };
88 prosody.events = require "util.events".new();
90 -- Try to determine version
91 local version_file = io.open((CFG_SOURCEDIR or ".").."/prosody.version");
93 prosody.version = version_file:read("*a"):gsub("%s*$", "");
95 if #prosody.version == 12 and prosody.version:match("^[a-f0-9]+$") then
96 prosody.version = "hg:"..prosody.version;
99 prosody.version = "unknown";
102 log("info", "Hello and welcome to Prosody version %s", prosody.version);
104 --- Load and initialise core modules
105 require "util.import"
106 require "core.xmlhandlers"
107 require "core.rostermanager"
108 require "core.eventmanager"
109 require "core.hostmanager"
110 require "core.modulemanager"
111 require "core.usermanager"
112 require "core.sessionmanager"
113 require "core.stanza_router"
116 require "util.iterators"
119 -- Commented to protect us from
120 -- the second kind of people
122 pcall(require, "remdebug.engine");
123 if remdebug then remdebug.engine.start() end
126 local cl = require "net.connlisteners";
128 require "util.stanza"
131 ------------------------------------------------------------------------
134 ------------- Begin code without a home ---------------------
136 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";
137 require "util.datamanager".set_data_path(data_path);
138 require "util.datamanager".set_callback(function(username, host, datastore)
139 return config.get(host, "core", "anonymous_login");
142 ----------- End of out-of-place code --------------
144 -- Function to reload the config file
145 function prosody.reload_config()
146 log("info", "Reloading configuration file");
147 eventmanager.fire_event("reloading-config");
148 local ok, level, err = config.load((rawget(_G, "CFG_CONFIGDIR") or ".").."/prosody.cfg.lua");
150 if level == "parser" then
151 log("error", "There was an error parsing the configuration file: %s", tostring(err));
152 elseif level == "file" then
153 log("error", "Couldn't read the config file when trying to reload: %s", tostring(err));
158 -- Function to reopen logfiles
159 function prosody.reopen_logfiles()
160 log("info", "Re-opening log files");
161 eventmanager.fire_event("reopen-log-files"); -- Handled by appropriate log sinks
164 -- Function to initiate prosody shutdown
165 function prosody.shutdown(reason)
166 log("info", "Shutting down: %s", reason or "unknown reason");
167 eventmanager.fire_event("server-stopping", { reason = reason });
168 server.setquitting(true);
171 -- Signal to modules that we are ready to start
172 eventmanager.fire_event("server-starting");
174 -- Load SSL settings from config, and create a ctx table
175 local global_ssl_ctx = ssl and config.get("*", "core", "ssl");
176 if global_ssl_ctx then
177 local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
178 setmetatable(global_ssl_ctx, { __index = default_ssl_ctx });
181 -- start listening on sockets
182 function net_activate_ports(option, listener, default, conntype)
183 local ports = config.get("*", "core", option.."_ports") or default;
184 if type(ports) == "number" then ports = {ports} end;
186 if type(ports) ~= "table" then
187 log("error", "core."..option.." is not a table");
189 for _, port in ipairs(ports) do
190 if type(port) ~= "number" then
191 log("error", "Non-numeric "..option.."_ports: "..tostring(port));
194 ssl = conntype ~= "tcp" and global_ssl_ctx,
196 interface = config.get("*", "core", option.."_interface")
197 or cl.get(listener).default_interface
198 or config.get("*", "core", "interface"),
206 net_activate_ports("c2s", "xmppclient", {5222}, (global_ssl_ctx and "tls") or "tcp");
207 net_activate_ports("s2s", "xmppserver", {5269}, "tcp");
208 net_activate_ports("component", "xmppcomponent", {}, "tcp");
209 net_activate_ports("legacy_ssl", "xmppclient", {}, "ssl");
211 if cl.get("console") then
212 cl.start("console", { interface = config.get("*", "core", "console_interface") or "127.0.0.1" })
215 -- Catch global accesses --
216 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 }
218 function prosody.unlock_globals()
219 setmetatable(_G, nil);
222 function prosody.lock_globals()
223 setmetatable(_G, locked_globals_mt);
227 prosody.lock_globals();
229 eventmanager.fire_event("server-started");
231 -- Error handler for errors that make it this far
232 local function catch_uncaught_error(err)
233 if err:match("%d*: interrupted!$") then
237 log("error", "Top-level error, please report:\n%s", tostring(err));
238 local traceback = debug.traceback("", 2);
240 log("error", "%s", traceback);
243 eventmanager.fire_event("very-bad-error", "*", err, traceback);
246 while select(2, xpcall(server.loop, catch_uncaught_error)) ~= "quitting" do
250 log("info", "Shutdown status: Cleaning up");
251 eventmanager.fire_event("server-cleanup");
253 -- Ok, we're quitting I know, but we
254 -- need to do some tidying before we go :)
255 server.setquitting(false);
257 log("info", "Shutdown status: Closing all active sessions");
258 for hostname, host in pairs(hosts) do
259 log("debug", "Shutdown status: Closing client connections for %s", hostname)
260 if host.sessions then
261 for username, user in pairs(host.sessions) do
262 for resource, session in pairs(user.sessions) do
263 log("debug", "Closing connection for %s@%s/%s", username, hostname, resource);
264 session:close("system-shutdown");
269 log("debug", "Shutdown status: Closing outgoing s2s connections from %s", hostname);
271 for remotehost, session in pairs(host.s2sout) do
272 if session.close then
273 session:close("system-shutdown");
275 log("warn", "Unable to close outgoing s2s session to %s, no session:close()?!", remotehost);
281 log("info", "Shutdown status: Closing all server connections");
284 server.setquitting(true);
286 eventmanager.fire_event("server-stopped");
287 log("info", "Shutdown status: Complete!");