Software /
code /
prosody-modules
File
mod_tcpproxy/mod_tcpproxy.lua @ 4203:c4002aae4ad3
mod_s2s_keepalive: Use timestamp as iq @id
RFC 6120 implies that the id attribute must be unique within a stream.
This should fix problems with remote servers that enforce uniqueness and
don't answer duplicated ids.
If it doesn't do that, then at least you can get a guesstimate at
round-trip time from the difference between the result iq stanza and the
timestamp it was logged without having to go look for when it was sent,
or needing to keep state.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Wed, 14 Oct 2020 18:02:10 +0200 |
parent | 1865:db8b256f51ff |
child | 4853:3804332c204e |
line wrap: on
line source
local st = require "util.stanza"; local xmlns_ibb = "http://jabber.org/protocol/ibb"; local xmlns_tcp = "http://prosody.im/protocol/tcpproxy"; local host_attr, port_attr = xmlns_tcp.."\1host", xmlns_tcp.."\1port"; local base64 = require "util.encodings".base64; local b64, unb64 = base64.encode, base64.decode; local host = module.host; local open_connections = {}; local function new_session(jid, sid, conn) if not open_connections[jid] then open_connections[jid] = {}; end open_connections[jid][sid] = conn; end local function close_session(jid, sid) if open_connections[jid] then open_connections[jid][sid] = nil; if next(open_connections[jid]) == nil then open_connections[jid] = nil; end return true; end end function proxy_component(origin, stanza) local ibb_tag = stanza.tags[1]; if (not (stanza.name == "iq" and stanza.attr.type == "set") and stanza.name ~= "message") or (not (ibb_tag) or ibb_tag.attr.xmlns ~= xmlns_ibb) then if stanza.attr.type ~= "error" then origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); end return; end if ibb_tag.name == "open" then -- Starting a new stream local to_host, to_port = ibb_tag.attr[host_attr], ibb_tag.attr[port_attr]; local jid, sid = stanza.attr.from, ibb_tag.attr.sid; if not (to_host and to_port) then origin.send(st.error_reply(stanza, "modify", "bad-request", "No host/port specified")); return true; elseif not sid or sid == "" then origin.send(st.error_reply(stanza, "modify", "bad-request", "No sid specified")); return true; elseif ibb_tag.attr.stanza ~= "message" then origin.send(st.error_reply(stanza, "modify", "bad-request", "Only 'message' stanza transport is supported")); return true; end local conn, err = socket.tcp(); if not conn then origin.send(st.error_reply(stanza, "wait", "resource-constraint", err)); return true; end conn:settimeout(0); local success, err = conn:connect(to_host, to_port); if not success and err ~= "timeout" then origin.send(st.error_reply(stanza, "wait", "remote-server-not-found", err)); return true; end local listener,seq = {}, 0; function listener.onconnect(conn) origin.send(st.reply(stanza)); end function listener.onincoming(conn, data) origin.send(st.message({to=jid,from=host}) :tag("data", {xmlns=xmlns_ibb,seq=seq,sid=sid}) :text(b64(data))); seq = seq + 1; end function listener.ondisconnect(conn, err) origin.send(st.message({to=jid,from=host}) :tag("close", {xmlns=xmlns_ibb,sid=sid})); close_session(jid, sid); end conn = server.wrapclient(conn, to_host, to_port, listener, "*a" ); new_session(jid, sid, conn); elseif ibb_tag.name == "data" then local conn = open_connections[stanza.attr.from][ibb_tag.attr.sid]; if conn then local data = unb64(ibb_tag:get_text()); if data then conn:write(data); else origin.send( st.error_reply(stanza, "modify", "bad-request", "Invalid data (base64?)") ); return true; end else origin.send(st.error_reply(stanza, "cancel", "item-not-found")); return true; end elseif ibb_tag.name == "close" then if close_session(stanza.attr.from, ibb_tag.attr.sid) then origin.send(st.reply(stanza)); else origin.send(st.error_reply(stanza, "cancel", "item-not-found")); return true; end end end local function stanza_handler(event) proxy_component(event.origin, event.stanza); return true; end module:hook("iq/bare", stanza_handler, -1); module:hook("message/bare", stanza_handler, -1); module:hook("presence/bare", stanza_handler, -1); module:hook("iq/full", stanza_handler, -1); module:hook("message/full", stanza_handler, -1); module:hook("presence/full", stanza_handler, -1); module:hook("iq/host", stanza_handler, -1); module:hook("message/host", stanza_handler, -1); module:hook("presence/host", stanza_handler, -1); require "core.componentmanager".register_component(host, function() end); -- COMPAT Prosody 0.7