prosody

changeset 1529
b5e4215f797d
parent 1523
841d61be198f
child 1530
0494f5e3be23
equal deleted inserted replaced
1528:87c71e882437 1529:b5e4215f797d
34 pcall(require, "luarocks.require") 34 pcall(require, "luarocks.require")
35 35
36 36
37 config = require "core.configmanager" 37 config = require "core.configmanager"
38 38
39 do 39 function read_config()
40 -- TODO: Check for other formats when we add support for them 40 -- TODO: Check for other formats when we add support for them
41 -- Use lfs? Make a new conf/ dir? 41 -- Use lfs? Make a new conf/ dir?
42 local ok, level, err = config.load((CFG_CONFIGDIR or ".").."/prosody.cfg.lua"); 42 local ok, level, err = config.load((CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
43 if not ok then 43 if not ok then
44 print("\n"); 44 print("\n");
60 print(""); 60 print("");
61 os.exit(1); 61 os.exit(1);
62 end 62 end
63 end 63 end
64 64
65 --- Initialize logging 65 read_config();
66 require "core.loggingmanager" 66
67 67 function load_libraries()
68 --- Check runtime dependencies 68 --- Initialize logging
69 require "util.dependencies" 69 require "core.loggingmanager"
70 70
71 --- Load socket framework 71 --- Check runtime dependencies
72 local server = require "net.server" 72 require "util.dependencies"
73 73
74 bare_sessions = {}; 74 --- Load socket framework
75 full_sessions = {}; 75 server = require "net.server"
76 hosts = {}; 76 end
77 77 load_libraries();
78 -- Global 'prosody' object 78
79 prosody = {}; 79 function init_global_state()
80 local prosody = prosody; 80 bare_sessions = {};
81 81 full_sessions = {};
82 prosody.bare_sessions = bare_sessions; 82 hosts = {};
83 prosody.full_sessions = full_sessions; 83
84 prosody.hosts = hosts; 84 -- Global 'prosody' object
85 85 prosody = {};
86 prosody.paths = { source = CFG_SOURCEDIR, config = CFG_CONFIGDIR, 86 local prosody = prosody;
87 plugins = CFG_PLUGINDIR, data = CFG_DATADIR }; 87
88 88 prosody.bare_sessions = bare_sessions;
89 prosody.arg = arg; 89 prosody.full_sessions = full_sessions;
90 90 prosody.hosts = hosts;
91 prosody.events = require "util.events".new(); 91
92 92 prosody.paths = { source = CFG_SOURCEDIR, config = CFG_CONFIGDIR,
93 -- Try to determine version 93 plugins = CFG_PLUGINDIR, data = CFG_DATADIR };
94 local version_file = io.open((CFG_SOURCEDIR or ".").."/prosody.version"); 94
95 if version_file then 95 prosody.arg = _G.arg;
96 prosody.version = version_file:read("*a"):gsub("%s*$", ""); 96
97 version_file:close(); 97 prosody.events = require "util.events".new();
98 if #prosody.version == 12 and prosody.version:match("^[a-f0-9]+$") then 98 end
99 prosody.version = "hg:"..prosody.version; 99 init_global_state();
100 end 100
101 else 101
102 prosody.version = "unknown"; 102 function read_version()
103 end 103 -- Try to determine version
104 104 local version_file = io.open((CFG_SOURCEDIR or ".").."/prosody.version");
105 if version_file then
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;
110 end
111 else
112 prosody.version = "unknown";
113 end
114 end
115 read_version();
105 log("info", "Hello and welcome to Prosody version %s", prosody.version); 116 log("info", "Hello and welcome to Prosody version %s", prosody.version);
106 117
107 --- Load and initialise core modules 118 function load_secondary_libraries()
108 require "util.import" 119 --- Load and initialise core modules
109 require "core.xmlhandlers" 120 require "util.import"
110 require "core.rostermanager" 121 require "core.xmlhandlers"
111 require "core.eventmanager" 122 require "core.rostermanager"
112 require "core.hostmanager" 123 require "core.eventmanager"
113 require "core.modulemanager" 124 require "core.hostmanager"
114 require "core.usermanager" 125 require "core.modulemanager"
115 require "core.sessionmanager" 126 require "core.usermanager"
116 require "core.stanza_router" 127 require "core.sessionmanager"
117 128 require "core.stanza_router"
118 require "util.array" 129
119 require "util.iterators" 130 require "util.array"
120 require "util.timer" 131 require "util.iterators"
121 132 require "util.timer"
122 -- Commented to protect us from 133
123 -- the second kind of people 134 -- Commented to protect us from
124 --[[ 135 -- the second kind of people
125 pcall(require, "remdebug.engine"); 136 --[[
126 if remdebug then remdebug.engine.start() end 137 pcall(require, "remdebug.engine");
127 ]] 138 if remdebug then remdebug.engine.start() end
128 139 ]]
129 local cl = require "net.connlisteners"; 140
130 141 require "net.connlisteners";
131 require "util.stanza" 142
132 require "util.jid" 143 require "util.stanza"
133 144 require "util.jid"
134 ------------------------------------------------------------------------ 145 end
135 146 load_secondary_libraries();
136 147
137 ------------- Begin code without a home --------------------- 148
138 149 function init_data_store()
139 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data"; 150 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";
140 require "util.datamanager".set_data_path(data_path); 151 require "util.datamanager".set_data_path(data_path);
141 require "util.datamanager".add_callback(function(username, host, datastore, data) 152 require "util.datamanager".add_callback(function(username, host, datastore, data)
142 if config.get(host, "core", "anonymous_login") then 153 if config.get(host, "core", "anonymous_login") then
143 return false; 154 return false;
144 end 155 end
145 return username, host, datastore, data; 156 return username, host, datastore, data;
146 end); 157 end);
147 158 end
148 ----------- End of out-of-place code -------------- 159 init_data_store();
149 160
150 -- Function to reload the config file 161 -- Function to reload the config file
151 function prosody.reload_config() 162 function prosody.reload_config()
152 log("info", "Reloading configuration file"); 163 log("info", "Reloading configuration file");
153 prosody.events.fire_event("reloading-config"); 164 prosody.events.fire_event("reloading-config");
173 log("info", "Shutting down: %s", reason or "unknown reason"); 184 log("info", "Shutting down: %s", reason or "unknown reason");
174 prosody.events.fire_event("server-stopping", {reason = reason}); 185 prosody.events.fire_event("server-stopping", {reason = reason});
175 server.setquitting(true); 186 server.setquitting(true);
176 end 187 end
177 188
178 -- Signal to modules that we are ready to start 189 function prosody.prepare_to_start()
179 eventmanager.fire_event("server-starting"); 190 -- Signal to modules that we are ready to start
180 prosody.events.fire_event("server-starting"); 191 eventmanager.fire_event("server-starting");
181 192 prosody.events.fire_event("server-starting");
182 -- Load SSL settings from config, and create a ctx table 193
183 local global_ssl_ctx = ssl and config.get("*", "core", "ssl"); 194 -- Load SSL settings from config, and create a ctx table
184 if global_ssl_ctx then 195 local global_ssl_ctx = ssl and config.get("*", "core", "ssl");
185 local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; }; 196 if global_ssl_ctx then
186 setmetatable(global_ssl_ctx, { __index = default_ssl_ctx }); 197 local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
187 end 198 setmetatable(global_ssl_ctx, { __index = default_ssl_ctx });
188 199 end
189 -- start listening on sockets 200
190 function net_activate_ports(option, listener, default, conntype) 201 local cl = require "net.connlisteners";
191 local ports = config.get("*", "core", option.."_ports") or default; 202 -- start listening on sockets
192 if type(ports) == "number" then ports = {ports} end; 203 function net_activate_ports(option, listener, default, conntype)
193 204 local ports = config.get("*", "core", option.."_ports") or default;
194 if type(ports) ~= "table" then 205 if type(ports) == "number" then ports = {ports} end;
195 log("error", "core."..option.." is not a table"); 206
196 else 207 if type(ports) ~= "table" then
197 for _, port in ipairs(ports) do 208 log("error", "core."..option.." is not a table");
198 if type(port) ~= "number" then 209 else
199 log("error", "Non-numeric "..option.."_ports: "..tostring(port)); 210 for _, port in ipairs(ports) do
200 else 211 if type(port) ~= "number" then
201 cl.start(listener, { 212 log("error", "Non-numeric "..option.."_ports: "..tostring(port));
202 ssl = conntype ~= "tcp" and global_ssl_ctx, 213 else
203 port = port, 214 cl.start(listener, {
204 interface = config.get("*", "core", option.."_interface") 215 ssl = conntype ~= "tcp" and global_ssl_ctx,
205 or cl.get(listener).default_interface 216 port = port,
206 or config.get("*", "core", "interface"), 217 interface = config.get("*", "core", option.."_interface")
207 type = conntype 218 or cl.get(listener).default_interface
208 }); 219 or config.get("*", "core", "interface"),
220 type = conntype
221 });
222 end
209 end 223 end
210 end 224 end
211 end 225 end
212 end 226
213 227 net_activate_ports("c2s", "xmppclient", {5222}, (global_ssl_ctx and "tls") or "tcp");
214 net_activate_ports("c2s", "xmppclient", {5222}, (global_ssl_ctx and "tls") or "tcp"); 228 net_activate_ports("s2s", "xmppserver", {5269}, "tcp");
215 net_activate_ports("s2s", "xmppserver", {5269}, "tcp"); 229 net_activate_ports("component", "xmppcomponent", {}, "tcp");
216 net_activate_ports("component", "xmppcomponent", {}, "tcp"); 230 net_activate_ports("legacy_ssl", "xmppclient", {}, "ssl");
217 net_activate_ports("legacy_ssl", "xmppclient", {}, "ssl"); 231
218 232 if cl.get("console") then
219 if cl.get("console") then 233 cl.start("console", { interface = config.get("*", "core", "console_interface") or "127.0.0.1" })
220 cl.start("console", { interface = config.get("*", "core", "console_interface") or "127.0.0.1" }) 234 end
221 end 235
222 236 prosody.start_time = os.time();
223 -- Catch global accesses -- 237 end
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 } 238 prosody.prepare_to_start();
225 239
226 function prosody.unlock_globals() 240 function prosody.init_global_protection()
227 setmetatable(_G, nil); 241 -- Catch global accesses --
228 end 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 }
229 243
230 function prosody.lock_globals() 244 function prosody.unlock_globals()
231 setmetatable(_G, locked_globals_mt); 245 setmetatable(_G, nil);
232 end 246 end
233 247
234 -- And lock now... 248 function prosody.lock_globals()
235 prosody.lock_globals(); 249 setmetatable(_G, locked_globals_mt);
236 250 end
237 prosody.start_time = os.time(); 251
252 -- And lock now...
253 prosody.lock_globals();
254 end
255 prosody.init_global_protection();
256
238 257
239 eventmanager.fire_event("server-started"); 258 eventmanager.fire_event("server-started");
240 prosody.events.fire_event("server-started"); 259 prosody.events.fire_event("server-started");
241 260
242 -- Error handler for errors that make it this far 261 function prosody.loop()
243 local function catch_uncaught_error(err) 262 -- Error handler for errors that make it this far
244 if err:match("%d*: interrupted!$") then 263 local function catch_uncaught_error(err)
245 return "quitting"; 264 if err:match("%d*: interrupted!$") then
246 end 265 return "quitting";
247 266 end
248 log("error", "Top-level error, please report:\n%s", tostring(err)); 267
249 local traceback = debug.traceback("", 2); 268 log("error", "Top-level error, please report:\n%s", tostring(err));
250 if traceback then 269 local traceback = debug.traceback("", 2);
251 log("error", "%s", traceback); 270 if traceback then
252 end 271 log("error", "%s", traceback);
253 272 end
254 prosody.events.fire_event("very-bad-error", {error = err, traceback = traceback}); 273
255 end 274 prosody.events.fire_event("very-bad-error", {error = err, traceback = traceback});
256 275 end
257 while select(2, xpcall(server.loop, catch_uncaught_error)) ~= "quitting" do 276
258 socket.sleep(0.2); 277 while select(2, xpcall(server.loop, catch_uncaught_error)) ~= "quitting" do
259 end 278 socket.sleep(0.2);
260 279 end
261 log("info", "Shutdown status: Cleaning up"); 280 end
262 prosody.events.fire_event("server-cleanup"); 281 prosody.loop();
263 282
264 -- Ok, we're quitting I know, but we 283 function prosody.cleanup()
265 -- need to do some tidying before we go :) 284 log("info", "Shutdown status: Cleaning up");
266 server.setquitting(false); 285 prosody.events.fire_event("server-cleanup");
267 286
268 log("info", "Shutdown status: Closing all active sessions"); 287 -- Ok, we're quitting I know, but we
269 for hostname, host in pairs(hosts) do 288 -- need to do some tidying before we go :)
270 log("debug", "Shutdown status: Closing client connections for %s", hostname) 289 server.setquitting(false);
271 if host.sessions then 290
272 for username, user in pairs(host.sessions) do 291 log("info", "Shutdown status: Closing all active sessions");
273 for resource, session in pairs(user.sessions) do 292 for hostname, host in pairs(hosts) do
274 log("debug", "Closing connection for %s@%s/%s", username, hostname, resource); 293 log("debug", "Shutdown status: Closing client connections for %s", hostname)
275 session:close("system-shutdown"); 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");
299 end
276 end 300 end
277 end 301 end
278 end 302
279 303 log("debug", "Shutdown status: Closing outgoing s2s connections from %s", hostname);
280 log("debug", "Shutdown status: Closing outgoing s2s connections from %s", hostname); 304 if host.s2sout then
281 if host.s2sout then 305 for remotehost, session in pairs(host.s2sout) do
282 for remotehost, session in pairs(host.s2sout) do 306 if session.close then
283 if session.close then 307 session:close("system-shutdown");
284 session:close("system-shutdown"); 308 else
285 else 309 log("warn", "Unable to close outgoing s2s session to %s, no session:close()?!", remotehost);
286 log("warn", "Unable to close outgoing s2s session to %s, no session:close()?!", remotehost); 310 end
287 end 311 end
288 end 312 end
289 end 313 end
290 end 314
291 315 log("info", "Shutdown status: Closing all server connections");
292 log("info", "Shutdown status: Closing all server connections"); 316 server.closeall();
293 server.closeall(); 317
294 318 server.setquitting(true);
295 server.setquitting(true); 319 end
320 prosody.cleanup();
296 321
297 eventmanager.fire_event("server-stopped"); 322 eventmanager.fire_event("server-stopped");
298 prosody.events.fire_event("server-stopped"); 323 prosody.events.fire_event("server-stopped");
299 log("info", "Shutdown status: Complete!"); 324 log("info", "Shutdown status: Complete!");

mercurial