diff options
author | Matthew Wild <mwild1@gmail.com> | 2018-02-23 15:53:45 +0000 |
---|---|---|
committer | Matthew Wild <mwild1@gmail.com> | 2018-02-23 15:53:45 +0000 |
commit | c27281a72055b599acab5272f17b869914ef936d (patch) | |
tree | 640cb0fdc674f685e2cea71aea16ed303c083935 /net/connect.lua | |
parent | 2727b7b72307c1f5e59f8b2e943074307010d262 (diff) | |
download | prosody-c27281a72055b599acab5272f17b869914ef936d.tar.gz prosody-c27281a72055b599acab5272f17b869914ef936d.zip |
net.connect: New API for outgoing connections, based on 'service resolvers'
Diffstat (limited to 'net/connect.lua')
-rw-r--r-- | net/connect.lua | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/net/connect.lua b/net/connect.lua new file mode 100644 index 00000000..dbd09694 --- /dev/null +++ b/net/connect.lua @@ -0,0 +1,78 @@ +local server = require "net.server"; +local log = require "util.logger".init("net.connect"); +local new_id = require "util.id".short; + +local pending_connection_methods = {}; +local pending_connection_mt = { + __name = "pending_connection"; + __index = pending_connection_methods; + __tostring = function (p) + return "<pending connection "..p.id.." to "..tostring(p.target_resolver.hostname)..">"; + end; +}; + +function pending_connection_methods:log(level, message, ...) + log(level, "[pending connection %s] "..message, self.id, ...); +end + +-- pending_connections_map[conn] = pending_connection +local pending_connections_map = {}; + +local pending_connection_listeners = {}; + +local function attempt_connection(p) + p:log("debug", "Checking for targets..."); + if p.conn then + pending_connections_map[p.conn] = nil; + p.conn = nil; + end + p.target_resolver:next(function (conn_type, ip, port, extra) + p:log("debug", "Next target to try is %s:%d", ip, port); + local conn = assert(server.addclient(ip, port, pending_connection_listeners, p.options.pattern, p.options.sslctx, conn_type, extra)); + p.conn = conn; + pending_connections_map[conn] = p; + end); +end + +function pending_connection_listeners.onconnect(conn) + local p = pending_connections_map[conn]; + if not p then + log("warn", "Successful connection, but unexpected! Closing."); + conn:close(); + return; + end + pending_connections_map[conn] = nil; + p:log("debug", "Successfully connected"); + if p.listeners.onattach then + p.listeners.onattach(conn, p.data); + end + conn:setlistener(p.listeners); + return p.listeners.onconnect(conn); +end + +function pending_connection_listeners.ondisconnect(conn, reason) + local p = pending_connections_map[conn]; + if not p then + log("warn", "Failed connection, but unexpected!"); + return; + end + p:log("debug", "Connection attempt failed"); + attempt_connection(p); +end + +local function connect(target_resolver, listeners, options, data) + local p = setmetatable({ + id = new_id(); + target_resolver = target_resolver; + listeners = assert(listeners); + options = options or {}; + cb = cb; + }, pending_connection_mt); + + p:log("debug", "Starting connection process"); + attempt_connection(p); +end + +return { + connect = connect; +}; |