From 2de38661d64e9e0765eacab665100da6eb90ece9 Mon Sep 17 00:00:00 2001 From: John Livingston Date: Thu, 25 May 2023 17:30:53 +0200 Subject: [PATCH] Websocket S2S: ping every 55s to keep alive. --- CHANGELOG.md | 4 +++- .../mod_websocket_s2s_peertubelivechat.lua | 22 ++++++++++++++++++- server/lib/prosody/config/content.ts | 3 +++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d334bd4d..98a02c77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,9 +14,11 @@ TODO?: mod_s2s_peertubelivechat: dont allow to connect to remote server that are TODO: when sanitizing remote chat endpoint, check that the domain is the same as the video domain (or is room.videodomain.tld). TODO: only compatible with Prosody 0.12.x. So it should be documented for people using «system Prosody». And i should fix the ARM AppImage. TODO: it seems that in some case A->B can be Websocket, and B->A direct S2S. Check if this is fine. And maybe we can optimise some code, by allowing directS2S event if current server dont accept it. -TODO: check that the keepalive is working with websocket s2s. It seems the connection is often close and reopened. +TODO: add a specific websocket timeout option, and send keepalive. In production the connection is often close and reopened because of nginx 30s timeout. TODO: alpha.2 version force Websocket S2S when available, even if s2s is possible. Revert this before releasing. TODO?: always generate self-signed certificates. Could be used for outgoing s2s? +TODO: check in the diagnostic tool that Prosody is >=0.12 +TODO: ARM AppImage, and to say that needs Prosody >=0.12 ### Minor changes and fixes diff --git a/prosody-modules/mod_websocket_s2s_peertubelivechat/mod_websocket_s2s_peertubelivechat.lua b/prosody-modules/mod_websocket_s2s_peertubelivechat/mod_websocket_s2s_peertubelivechat.lua index b6f06f03..59cc3888 100644 --- a/prosody-modules/mod_websocket_s2s_peertubelivechat/mod_websocket_s2s_peertubelivechat.lua +++ b/prosody-modules/mod_websocket_s2s_peertubelivechat/mod_websocket_s2s_peertubelivechat.lua @@ -35,6 +35,7 @@ local frame_buffer_limit = module:get_option_number("websocket_frame_buffer_limi local frame_fragment_limit = module:get_option_number("websocket_frame_fragment_limit", 8); local stream_close_timeout = module:get_option_number("s2s_close_timeout", 5); local consider_websocket_secure = module:get_option_boolean("consider_websocket_secure"); +local websocket_s2s_ping_interval = module:get_option_number("websocket_s2s_ping_interval", 55); local xmlns_framing = "urn:ietf:params:xml:ns:xmpp-framing-server"; local xmlns_streams = "http://etherx.jabber.org/streams"; @@ -366,7 +367,7 @@ local function keepalive(event) local session = event.session; if session.open_stream == session_open_stream then local log = session.log or log - log("debug", "Sending a keepalive on outgoint websocket s2s"); + log("debug", "Sending a keepalive on outgoing websocket s2s"); return session.conn:write(build_frame({ opcode = 0x9, FIN = true })); end end @@ -594,6 +595,14 @@ function route_to_new_session(event) conn:setlistener(s2s_listener); s2s_listener.register_outgoing(conn, session); s2s_listener.onconnect(conn); + + -- many websocket server or proxy have timeouts when the connection is not active. + -- for example when nginx proxifies websocket, it has a default 60 seconds timeout. + -- so we will send keepalives on outgoing connections (in addition to keepalives sent by mod_s2s). + session.ws_s2s_keepalive_timer = module:add_timer(websocket_s2s_ping_interval, function () + log("debug", "Timer triggered, sending a keepalive on outgoing websocket s2s"); + return session.conn:write(build_frame({ opcode = 0x9, FIN = true })); + end); end local function onclose(s, code, message) @@ -657,6 +666,17 @@ function module.add_host(module) }); module:hook("s2s-read-timeout", keepalive, -0.9); + module:hook("s2s-destroyed", function (event) + local session = event.session; + if not session then + return; + end + local log = session.log or log; + if session.ws_s2s_keepalive_timer then + log("debug", "Stopping keepalive timer"); + session.ws_s2s_keepalive_timer:stop(); + end + end); end if require"core.modulemanager".get_modules_for_host("*"):contains(module.name) then diff --git a/server/lib/prosody/config/content.ts b/server/lib/prosody/config/content.ts index bf8fb0ae..15c7c102 100644 --- a/server/lib/prosody/config/content.ts +++ b/server/lib/prosody/config/content.ts @@ -296,6 +296,9 @@ class ProsodyConfigContent { this.global.set('peertubelivechat_instance_url', publicServerUrl) this.global.add('modules_enabled', 'websocket_s2s_peertubelivechat') + // Nginx closes the websockets connection after a timeout. Seems the default is 60s. + // So we will ping on outgoing websocket s2s connection every 55s. + this.global.set('websocket_s2s_ping_interval', 55) // FIXME: seems to be necessary to add the module on the muc host, so that dialback can trigger route/remote. this.muc.add('modules_enabled', 'websocket_s2s_peertubelivechat')