util.x509: Nameprep commonName once
[prosody.git] / net / connect.lua
blobd4de6fb452a30d53c6ce823b6b615c403f5b9233
1 local server = require "net.server";
2 local log = require "util.logger".init("net.connect");
3 local new_id = require "util.id".short;
5 local pending_connection_methods = {};
6 local pending_connection_mt = {
7 __name = "pending_connection";
8 __index = pending_connection_methods;
9 __tostring = function (p)
10 return "<pending connection "..p.id.." to "..tostring(p.target_resolver.hostname)..">";
11 end;
14 function pending_connection_methods:log(level, message, ...)
15 log(level, "[pending connection %s] "..message, self.id, ...);
16 end
18 -- pending_connections_map[conn] = pending_connection
19 local pending_connections_map = {};
21 local pending_connection_listeners = {};
23 local function attempt_connection(p)
24 p:log("debug", "Checking for targets...");
25 if p.conn then
26 pending_connections_map[p.conn] = nil;
27 p.conn = nil;
28 end
29 p.target_resolver:next(function (conn_type, ip, port, extra)
30 if not conn_type then
31 -- No more targets to try
32 p:log("debug", "No more connection targets to try");
33 if p.listeners.onfail then
34 p.listeners.onfail(p.data, p.last_error or "unable to resolve service");
35 end
36 return;
37 end
38 p:log("debug", "Next target to try is %s:%d", ip, port);
39 local conn, err = server.addclient(ip, port, pending_connection_listeners, p.options.pattern or "*a", p.options.sslctx, conn_type, extra);
40 if not conn then
41 log("debug", "Connection attempt failed immediately: %s", err);
42 p.last_error = err or "unknown reason";
43 return attempt_connection(p);
44 end
45 p.conn = conn;
46 pending_connections_map[conn] = p;
47 end);
48 end
50 function pending_connection_listeners.onconnect(conn)
51 local p = pending_connections_map[conn];
52 if not p then
53 log("warn", "Successful connection, but unexpected! Closing.");
54 conn:close();
55 return;
56 end
57 pending_connections_map[conn] = nil;
58 p:log("debug", "Successfully connected");
59 conn:setlistener(p.listeners, p.data);
60 return p.listeners.onconnect(conn);
61 end
63 function pending_connection_listeners.ondisconnect(conn, reason)
64 local p = pending_connections_map[conn];
65 if not p then
66 log("warn", "Failed connection, but unexpected!");
67 return;
68 end
69 p.last_error = reason or "unknown reason";
70 p:log("debug", "Connection attempt failed: %s", p.last_error);
71 attempt_connection(p);
72 end
74 local function connect(target_resolver, listeners, options, data)
75 local p = setmetatable({
76 id = new_id();
77 target_resolver = target_resolver;
78 listeners = assert(listeners);
79 options = options or {};
80 data = data;
81 }, pending_connection_mt);
83 p:log("debug", "Starting connection process");
84 attempt_connection(p);
85 end
87 return {
88 connect = connect;