Software / code / prosody-modules
Comparison
mod_tcpproxy/mod_tcpproxy.lua @ 147:4db80a46b064
mod_tcpproxy: Initial commit. The moment you didn't know you've been waiting for is here... the dawn of TCP over XMPP.
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Tue, 13 Apr 2010 04:38:07 +0100 |
| child | 153:31e24026e4fd |
comparison
equal
deleted
inserted
replaced
| 146:2620bc59cca3 | 147:4db80a46b064 |
|---|---|
| 1 local st = require "util.stanza"; | |
| 2 | |
| 3 local xmlns_ibb = "http://jabber.org/protocol/ibb"; | |
| 4 local xmlns_tcp = "http://prosody.im/protocol/tcpproxy"; | |
| 5 | |
| 6 local host_attr, port_attr = xmlns_tcp.."\1host", xmlns_tcp.."\1port"; | |
| 7 | |
| 8 local base64 = require "util.encodings".base64; | |
| 9 local b64, unb64 = base64.encode, base64.decode; | |
| 10 | |
| 11 local host = module.host; | |
| 12 | |
| 13 local open_connections = {}; | |
| 14 | |
| 15 local function new_session(jid, sid, conn) | |
| 16 if not open_connections[jid] then | |
| 17 open_connections[jid] = {}; | |
| 18 end | |
| 19 open_connections[jid][sid] = conn; | |
| 20 end | |
| 21 local function close_session(jid, sid) | |
| 22 if open_connections[jid] then | |
| 23 open_connections[jid][sid] = nil; | |
| 24 if next(open_connections[jid]) == nil then | |
| 25 open_connections[jid] = nil; | |
| 26 end | |
| 27 return true; | |
| 28 end | |
| 29 end | |
| 30 | |
| 31 function proxy_component(origin, stanza) | |
| 32 local ibb_tag = stanza.tags[1]; | |
| 33 if (not (stanza.name == "iq" and stanza.attr.type == "set") | |
| 34 and stanza.name ~= "message") | |
| 35 or | |
| 36 (not (ibb_tag) | |
| 37 or ibb_tag.attr.xmlns ~= xmlns_ibb) then | |
| 38 if stanza.attr.type ~= "error" then | |
| 39 origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); | |
| 40 end | |
| 41 return; | |
| 42 end | |
| 43 | |
| 44 if ibb_tag.name == "open" then | |
| 45 -- Starting a new stream | |
| 46 local to_host, to_port = ibb_tag.attr[host_attr], ibb_tag.attr[port_attr]; | |
| 47 local jid, sid = stanza.attr.from, ibb_tag.attr.sid; | |
| 48 if not (to_host and to_port) then | |
| 49 return origin.send(st.error_reply(stanza, "modify", "bad-request", "No host/port specified")); | |
| 50 elseif not sid or sid == "" then | |
| 51 return origin.send(st.error_reply(stanza, "modify", "bad-request", "No sid specified")); | |
| 52 elseif ibb_tag.attr.stanza ~= "message" then | |
| 53 return origin.send(st.error_reply(stanza, "modify", "bad-request", "Only 'message' stanza transport is supported")); | |
| 54 end | |
| 55 local conn, err = socket.tcp(); | |
| 56 if not conn then | |
| 57 return origin.send(st.error_reply(stanza, "wait", "resource-constraint", err)); | |
| 58 end | |
| 59 conn:settimeout(0); | |
| 60 | |
| 61 local success, err = conn:connect(to_host, to_port); | |
| 62 if not success and err ~= "timeout" then | |
| 63 return origin.send(st.error_reply(stanza, "wait", "remote-server-not-found", err)); | |
| 64 end | |
| 65 | |
| 66 local listener,seq = {}, 0; | |
| 67 function listener.onconnect(conn) | |
| 68 origin.send(st.reply(stanza)); | |
| 69 end | |
| 70 function listener.onincoming(conn, data) | |
| 71 origin.send(st.message({to=jid,from=host}) | |
| 72 :tag("data", {xmlns=xmlns_ibb,seq=seq,sid=sid}) | |
| 73 :text(b64(data))); | |
| 74 seq = seq + 1; | |
| 75 end | |
| 76 function listener.ondisconnect(conn, err) | |
| 77 origin.send(st.message({to=jid,from=host}) | |
| 78 :tag("close", {xmlns=xmlns_ibb,sid=sid})); | |
| 79 close_session(jid, sid); | |
| 80 end | |
| 81 | |
| 82 conn = server.wrapclient(conn, to_host, to_port, listener, "*a" ); | |
| 83 new_session(jid, sid, conn); | |
| 84 elseif ibb_tag.name == "data" then | |
| 85 local conn = open_connections[stanza.attr.from][ibb_tag.attr.sid]; | |
| 86 if conn then | |
| 87 conn:write(unb64(ibb_tag:get_text())); | |
| 88 else | |
| 89 return origin.send(st.error_reply(stanza, "cancel", "item-not-found")); | |
| 90 end | |
| 91 elseif ibb_tag.name == "close" then | |
| 92 if close_session(stanza.attr.from, ibb_tag.attr.sid) then | |
| 93 origin.send(st.reply(stanza)); | |
| 94 else | |
| 95 return origin.send(st.error_reply(stanza, "cancel", "item-not-found")); | |
| 96 end | |
| 97 end | |
| 98 end | |
| 99 | |
| 100 require "core.componentmanager".register_component(host, proxy_component); |