Comparison

mod_websocket/mod_websocket.lua @ 839:d297d76010d4

mod_websocket: Merge with current mod_c2s
author Florian Zeitz <florob@babelmonkeys.de>
date Thu, 04 Oct 2012 16:37:33 +0200
parent 694:02fcb102b9aa
child 840:f568661c9d39
comparison
equal deleted inserted replaced
838:c9e2beec4ef6 839:d297d76010d4
27 local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; 27 local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams";
28 28
29 local log = module._log; 29 local log = module._log;
30 30
31 local c2s_timeout = module:get_option_number("c2s_timeout"); 31 local c2s_timeout = module:get_option_number("c2s_timeout");
32 local stream_close_timeout = module:get_option_number("c2s_close_timeout", 5);
32 local opt_keepalives = module:get_option_boolean("tcp_keepalives", false); 33 local opt_keepalives = module:get_option_boolean("tcp_keepalives", false);
33 local self_closing_stream = module:get_option_boolean("websocket_self_closing_stream", true); 34 local self_closing_stream = module:get_option_boolean("websocket_self_closing_stream", true);
34 35
35 local sessions = module:shared("sessions"); 36 local sessions = module:shared("sessions");
37 local core_process_stanza = prosody.core_process_stanza;
36 38
37 local stream_callbacks = { default_ns = "jabber:client", handlestanza = core_process_stanza }; 39 local stream_callbacks = { default_ns = "jabber:client", handlestanza = core_process_stanza };
38 local listener = {}; 40 local listener = {};
39 41
40 -- Websocket helpers 42 -- Websocket helpers
160 send(features); 162 send(features);
161 end 163 end
162 164
163 function stream_callbacks.streamclosed(session) 165 function stream_callbacks.streamclosed(session)
164 session.log("debug", "Received </stream:stream>"); 166 session.log("debug", "Received </stream:stream>");
165 session:close(); 167 session:close(false);
166 end 168 end
167 169
168 function stream_callbacks.error(session, error, data) 170 function stream_callbacks.error(session, error, data)
169 if error == "no-stream" then 171 if error == "no-stream" then
170 session.log("debug", "Invalid opening stream header"); 172 session.log("debug", "Invalid opening stream header");
210 session.send("<?xml version='1.0'?>"..tostring(st.stanza("stream:stream", default_stream_attr))); 212 session.send("<?xml version='1.0'?>"..tostring(st.stanza("stream:stream", default_stream_attr)));
211 else 213 else
212 session.send("<?xml version='1.0'?>"..st.stanza("stream:stream", default_stream_attr):top_tag()); 214 session.send("<?xml version='1.0'?>"..st.stanza("stream:stream", default_stream_attr):top_tag());
213 end 215 end
214 end 216 end
215 if reason then 217 if reason then -- nil == no err, initiated by us, false == initiated by client
216 if type(reason) == "string" then -- assume stream error 218 if type(reason) == "string" then -- assume stream error
217 log("info", "Disconnecting client, <stream:error> is: %s", reason); 219 log("debug", "Disconnecting client, <stream:error> is: %s", reason);
218 session.send(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' })); 220 session.send(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' }));
219 elseif type(reason) == "table" then 221 elseif type(reason) == "table" then
220 if reason.condition then 222 if reason.condition then
221 local stanza = st.stanza("stream:error"):tag(reason.condition, stream_xmlns_attr):up(); 223 local stanza = st.stanza("stream:error"):tag(reason.condition, stream_xmlns_attr):up();
222 if reason.text then 224 if reason.text then
223 stanza:tag("text", stream_xmlns_attr):text(reason.text):up(); 225 stanza:tag("text", stream_xmlns_attr):text(reason.text):up();
224 end 226 end
225 if reason.extra then 227 if reason.extra then
226 stanza:add_child(reason.extra); 228 stanza:add_child(reason.extra);
227 end 229 end
228 log("info", "Disconnecting client, <stream:error> is: %s", tostring(stanza)); 230 log("debug", "Disconnecting client, <stream:error> is: %s", tostring(stanza));
229 session.send(stanza); 231 session.send(stanza);
230 elseif reason.name then -- a stanza 232 elseif reason.name then -- a stanza
231 log("info", "Disconnecting client, <stream:error> is: %s", tostring(reason)); 233 log("debug", "Disconnecting client, <stream:error> is: %s", tostring(reason));
232 session.send(reason); 234 session.send(reason);
233 end 235 end
234 end 236 end
235 end 237 end
236 session.send("</stream:stream>"); 238 session.send("</stream:stream>");
237 session.conn:close(); 239 function session.send() return false; end
238 listener.ondisconnect(session.conn, (reason and (reason.text or reason.condition)) or reason or "session closed"); 240
239 end 241 local reason = (reason and (reason.text or reason.condition)) or reason;
240 end 242 session.log("info", "c2s stream for %s closed: %s", session.full_jid or ("<"..session.ip..">"), reason or "session closed");
243
244 -- Authenticated incoming stream may still be sending us stanzas, so wait for </stream:stream> from remote
245 local conn = session.conn;
246 if reason == nil and not session.notopen and session.type == "c2s" then
247 -- Grace time to process data from authenticated cleanly-closed stream
248 add_task(stream_close_timeout, function ()
249 if not session.destroyed then
250 session.log("warn", "Failed to receive a stream close response, closing connection anyway...");
251 sm_destroy_session(session, reason);
252 conn:close();
253 end
254 end);
255 else
256 sm_destroy_session(session, reason);
257 conn:close();
258 end
259 end
260 end
261
262 module:hook_global("user-deleted", function(event)
263 local username, host = event.username, event.host;
264 local user = hosts[host].sessions[username];
265 if user and user.sessions then
266 for jid, session in pairs(user.sessions) do
267 session:close{ condition = "not-authorized", text = "Account deleted" };
268 end
269 end
270 end, 200);
241 271
242 --- Port listener 272 --- Port listener
243 function listener.onconnect(conn) 273 function listener.onconnect(conn)
244 local session = sm_new_session(conn); 274 local session = sm_new_session(conn);
245 sessions[conn] = session; 275 sessions[conn] = session;
329 end 359 end
330 360
331 function listener.ondisconnect(conn, err) 361 function listener.ondisconnect(conn, err)
332 local session = sessions[conn]; 362 local session = sessions[conn];
333 if session then 363 if session then
334 (session.log or log)("info", "Client disconnected: %s", err); 364 (session.log or log)("info", "Client disconnected: %s", err or "connection closed");
335 sm_destroy_session(session, err); 365 sm_destroy_session(session, err);
336 sessions[conn] = nil; 366 sessions[conn] = nil;
337 session = nil;
338 end 367 end
339 end 368 end
340 369
341 function listener.associate_session(conn, session) 370 function listener.associate_session(conn, session)
342 sessions[conn] = session; 371 sessions[conn] = session;