net/connect.lua
author Kim Alvefur <zash@zash.se>
Wed, 27 Mar 2024 19:33:11 +0100
changeset 13471 c2a476f4712a
parent 12978 ba409c67353b
permissions -rw-r--r--
util.startup: Fix exiting on pidfile trouble prosody.shutdown() relies on prosody.main_thread, which has not been set yet at this point. Doing a clean shutdown might actually be harmful in case it tears down things set up by the conflicting Prosody, such as the very pidfile we were looking at. Thanks again SigmaTel71 for noticing
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
12978
ba409c67353b net: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12643
diff changeset
     1
local server = require "prosody.net.server";
ba409c67353b net: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12643
diff changeset
     2
local log = require "prosody.util.logger".init("net.connect");
ba409c67353b net: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12643
diff changeset
     3
local new_id = require "prosody.util.id".short;
ba409c67353b net: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12643
diff changeset
     4
local timer = require "prosody.util.timer";
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     5
10489
913276ba0c47 net.connect: Mention RFC 6724 regression
Kim Alvefur <zash@zash.se>
parents: 10488
diff changeset
     6
-- FIXME RFC 6724
10456
fa11070c2cd7 net.connect: Add some TODO comments
Kim Alvefur <zash@zash.se>
parents: 10116
diff changeset
     7
-- FIXME Error propagation from resolvers doesn't work
10488
b13a31cea7d9 net.connect: Add some TODOs and FIXMEs
Kim Alvefur <zash@zash.se>
parents: 10456
diff changeset
     8
-- FIXME #1428 Reuse DNS resolver object between service and basic resolver
b13a31cea7d9 net.connect: Add some TODOs and FIXMEs
Kim Alvefur <zash@zash.se>
parents: 10456
diff changeset
     9
-- FIXME #1429 Close DNS resolver object when done
10456
fa11070c2cd7 net.connect: Add some TODO comments
Kim Alvefur <zash@zash.se>
parents: 10116
diff changeset
    10
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    11
local pending_connection_methods = {};
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    12
local pending_connection_mt = {
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    13
	__name = "pending_connection";
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    14
	__index = pending_connection_methods;
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    15
	__tostring = function (p)
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    16
		return "<pending connection "..p.id.." to "..tostring(p.target_resolver.hostname)..">";
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    17
	end;
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    18
};
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    19
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    20
function pending_connection_methods:log(level, message, ...)
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    21
	log(level, "[pending connection %s] "..message, self.id, ...);
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    22
end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    23
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    24
-- pending_connections_map[conn] = pending_connection
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    25
local pending_connections_map = {};
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    26
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    27
local pending_connection_listeners = {};
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    28
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    29
local function attempt_connection(p)
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    30
	p:log("debug", "Checking for targets...");
12416
18a3a6218100 net.connect: When more targets are immediately available, try them after a delay
Matthew Wild <mwild1@gmail.com>
parents: 12415
diff changeset
    31
	p.target_resolver:next(function (conn_type, ip, port, extra, more_targets_available)
8550
5e9c87376891 net.connect: Handle case when resolver runs out of targets
Matthew Wild <mwild1@gmail.com>
parents: 8549
diff changeset
    32
		if not conn_type then
5e9c87376891 net.connect: Handle case when resolver runs out of targets
Matthew Wild <mwild1@gmail.com>
parents: 8549
diff changeset
    33
			-- No more targets to try
11905
26406ce35e20 net.connect: Propagate last error message from resolvers
Kim Alvefur <zash@zash.se>
parents: 10949
diff changeset
    34
			p:log("debug", "No more connection targets to try", p.target_resolver.last_error);
12429
eabcc3ae22e9 net.connect: Improve handling of failure when attempts are still pending
Matthew Wild <mwild1@gmail.com>
parents: 12416
diff changeset
    35
			if next(p.conns) == nil then
eabcc3ae22e9 net.connect: Improve handling of failure when attempts are still pending
Matthew Wild <mwild1@gmail.com>
parents: 12416
diff changeset
    36
				p:log("debug", "No more targets, no pending connections. Connection failed.");
eabcc3ae22e9 net.connect: Improve handling of failure when attempts are still pending
Matthew Wild <mwild1@gmail.com>
parents: 12416
diff changeset
    37
				if p.listeners.onfail then
eabcc3ae22e9 net.connect: Improve handling of failure when attempts are still pending
Matthew Wild <mwild1@gmail.com>
parents: 12416
diff changeset
    38
					p.listeners.onfail(p.data, p.last_error or p.target_resolver.last_error or "unable to resolve service");
eabcc3ae22e9 net.connect: Improve handling of failure when attempts are still pending
Matthew Wild <mwild1@gmail.com>
parents: 12416
diff changeset
    39
				end
eabcc3ae22e9 net.connect: Improve handling of failure when attempts are still pending
Matthew Wild <mwild1@gmail.com>
parents: 12416
diff changeset
    40
			else
eabcc3ae22e9 net.connect: Improve handling of failure when attempts are still pending
Matthew Wild <mwild1@gmail.com>
parents: 12416
diff changeset
    41
				p:log("debug", "One or more connection attempts are still pending. Waiting for now.");
8550
5e9c87376891 net.connect: Handle case when resolver runs out of targets
Matthew Wild <mwild1@gmail.com>
parents: 8549
diff changeset
    42
			end
5e9c87376891 net.connect: Handle case when resolver runs out of targets
Matthew Wild <mwild1@gmail.com>
parents: 8549
diff changeset
    43
			return;
5e9c87376891 net.connect: Handle case when resolver runs out of targets
Matthew Wild <mwild1@gmail.com>
parents: 8549
diff changeset
    44
		end
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    45
		p:log("debug", "Next target to try is %s:%d", ip, port);
12209
a2e6605303fa net.connect: Allow passing TLS context from resolver
Kim Alvefur <zash@zash.se>
parents: 11907
diff changeset
    46
		local conn, err = server.addclient(ip, port, pending_connection_listeners, p.options.pattern or "*a",
a2e6605303fa net.connect: Allow passing TLS context from resolver
Kim Alvefur <zash@zash.se>
parents: 11907
diff changeset
    47
			extra and extra.sslctx or p.options.sslctx, conn_type, extra);
8551
162f75ac2693 net.connect: Handle immediate failures of server.addclient
Matthew Wild <mwild1@gmail.com>
parents: 8550
diff changeset
    48
		if not conn then
10116
b327f2870382 net.*: Remove tostring call from logging
Kim Alvefur <zash@zash.se>
parents: 9390
diff changeset
    49
			log("debug", "Connection attempt failed immediately: %s", err);
8551
162f75ac2693 net.connect: Handle immediate failures of server.addclient
Matthew Wild <mwild1@gmail.com>
parents: 8550
diff changeset
    50
			p.last_error = err or "unknown reason";
162f75ac2693 net.connect: Handle immediate failures of server.addclient
Matthew Wild <mwild1@gmail.com>
parents: 8550
diff changeset
    51
			return attempt_connection(p);
162f75ac2693 net.connect: Handle immediate failures of server.addclient
Matthew Wild <mwild1@gmail.com>
parents: 8550
diff changeset
    52
		end
12415
e132a4279914 net.connect: Support for multiple pending connection attempts
Matthew Wild <mwild1@gmail.com>
parents: 12209
diff changeset
    53
		p.conns[conn] = true;
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    54
		pending_connections_map[conn] = p;
12416
18a3a6218100 net.connect: When more targets are immediately available, try them after a delay
Matthew Wild <mwild1@gmail.com>
parents: 12415
diff changeset
    55
		if more_targets_available then
18a3a6218100 net.connect: When more targets are immediately available, try them after a delay
Matthew Wild <mwild1@gmail.com>
parents: 12415
diff changeset
    56
			timer.add_task(0.250, function ()
18a3a6218100 net.connect: When more targets are immediately available, try them after a delay
Matthew Wild <mwild1@gmail.com>
parents: 12415
diff changeset
    57
				if not p.connected then
18a3a6218100 net.connect: When more targets are immediately available, try them after a delay
Matthew Wild <mwild1@gmail.com>
parents: 12415
diff changeset
    58
					p:log("debug", "Still not connected, making parallel connection attempt...");
18a3a6218100 net.connect: When more targets are immediately available, try them after a delay
Matthew Wild <mwild1@gmail.com>
parents: 12415
diff changeset
    59
					attempt_connection(p);
18a3a6218100 net.connect: When more targets are immediately available, try them after a delay
Matthew Wild <mwild1@gmail.com>
parents: 12415
diff changeset
    60
				end
18a3a6218100 net.connect: When more targets are immediately available, try them after a delay
Matthew Wild <mwild1@gmail.com>
parents: 12415
diff changeset
    61
			end);
18a3a6218100 net.connect: When more targets are immediately available, try them after a delay
Matthew Wild <mwild1@gmail.com>
parents: 12415
diff changeset
    62
		end
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    63
	end);
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    64
end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    65
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    66
function pending_connection_listeners.onconnect(conn)
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    67
	local p = pending_connections_map[conn];
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    68
	if not p then
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    69
		log("warn", "Successful connection, but unexpected! Closing.");
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    70
		conn:close();
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    71
		return;
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    72
	end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    73
	pending_connections_map[conn] = nil;
12415
e132a4279914 net.connect: Support for multiple pending connection attempts
Matthew Wild <mwild1@gmail.com>
parents: 12209
diff changeset
    74
	if p.connected then
e132a4279914 net.connect: Support for multiple pending connection attempts
Matthew Wild <mwild1@gmail.com>
parents: 12209
diff changeset
    75
		-- We already succeeded in connecting
e132a4279914 net.connect: Support for multiple pending connection attempts
Matthew Wild <mwild1@gmail.com>
parents: 12209
diff changeset
    76
		p.conns[conn] = nil;
e132a4279914 net.connect: Support for multiple pending connection attempts
Matthew Wild <mwild1@gmail.com>
parents: 12209
diff changeset
    77
		conn:close();
e132a4279914 net.connect: Support for multiple pending connection attempts
Matthew Wild <mwild1@gmail.com>
parents: 12209
diff changeset
    78
		return;
e132a4279914 net.connect: Support for multiple pending connection attempts
Matthew Wild <mwild1@gmail.com>
parents: 12209
diff changeset
    79
	end
e132a4279914 net.connect: Support for multiple pending connection attempts
Matthew Wild <mwild1@gmail.com>
parents: 12209
diff changeset
    80
	p.connected = true;
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    81
	p:log("debug", "Successfully connected");
9390
33e52f727f0f net.connect: Fix passing request table to new listener
Kim Alvefur <zash@zash.se>
parents: 9389
diff changeset
    82
	conn:setlistener(p.listeners, p.data);
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    83
	return p.listeners.onconnect(conn);
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    84
end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    85
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    86
function pending_connection_listeners.ondisconnect(conn, reason)
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    87
	local p = pending_connections_map[conn];
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    88
	if not p then
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    89
		log("warn", "Failed connection, but unexpected!");
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    90
		return;
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    91
	end
12415
e132a4279914 net.connect: Support for multiple pending connection attempts
Matthew Wild <mwild1@gmail.com>
parents: 12209
diff changeset
    92
	p.conns[conn] = nil;
12472
353836684009 net.connect: Fix accumulation of connection attempt references
Kim Alvefur <zash@zash.se>
parents: 12430
diff changeset
    93
	pending_connections_map[conn] = nil;
8549
d66916dc318a net.connect: Track last connection error
Matthew Wild <mwild1@gmail.com>
parents: 8539
diff changeset
    94
	p.last_error = reason or "unknown reason";
d66916dc318a net.connect: Track last connection error
Matthew Wild <mwild1@gmail.com>
parents: 8539
diff changeset
    95
	p:log("debug", "Connection attempt failed: %s", p.last_error);
12430
7a3da1acace1 net.connect: Improve logging on connection attempt failure
Matthew Wild <mwild1@gmail.com>
parents: 12429
diff changeset
    96
	if p.connected then
7a3da1acace1 net.connect: Improve logging on connection attempt failure
Matthew Wild <mwild1@gmail.com>
parents: 12429
diff changeset
    97
		p:log("debug", "Connection already established, ignoring failure");
7a3da1acace1 net.connect: Improve logging on connection attempt failure
Matthew Wild <mwild1@gmail.com>
parents: 12429
diff changeset
    98
	elseif next(p.conns) == nil then
12429
eabcc3ae22e9 net.connect: Improve handling of failure when attempts are still pending
Matthew Wild <mwild1@gmail.com>
parents: 12416
diff changeset
    99
		p:log("debug", "No pending connection attempts, and not yet connected");
eabcc3ae22e9 net.connect: Improve handling of failure when attempts are still pending
Matthew Wild <mwild1@gmail.com>
parents: 12416
diff changeset
   100
		attempt_connection(p);
12430
7a3da1acace1 net.connect: Improve logging on connection attempt failure
Matthew Wild <mwild1@gmail.com>
parents: 12429
diff changeset
   101
	else
7a3da1acace1 net.connect: Improve logging on connection attempt failure
Matthew Wild <mwild1@gmail.com>
parents: 12429
diff changeset
   102
		p:log("debug", "Other attempts are still pending, ignoring failure");
12429
eabcc3ae22e9 net.connect: Improve handling of failure when attempts are still pending
Matthew Wild <mwild1@gmail.com>
parents: 12416
diff changeset
   103
	end
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   104
end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   105
10627
f51c88baeb8a Backed out changeset 44ef46e1a951 (not optimal API)
Matthew Wild <mwild1@gmail.com>
parents: 10616
diff changeset
   106
local function connect(target_resolver, listeners, options, data)
f51c88baeb8a Backed out changeset 44ef46e1a951 (not optimal API)
Matthew Wild <mwild1@gmail.com>
parents: 10616
diff changeset
   107
	local p = setmetatable({
f51c88baeb8a Backed out changeset 44ef46e1a951 (not optimal API)
Matthew Wild <mwild1@gmail.com>
parents: 10616
diff changeset
   108
		id = new_id();
f51c88baeb8a Backed out changeset 44ef46e1a951 (not optimal API)
Matthew Wild <mwild1@gmail.com>
parents: 10616
diff changeset
   109
		target_resolver = target_resolver;
f51c88baeb8a Backed out changeset 44ef46e1a951 (not optimal API)
Matthew Wild <mwild1@gmail.com>
parents: 10616
diff changeset
   110
		listeners = assert(listeners);
f51c88baeb8a Backed out changeset 44ef46e1a951 (not optimal API)
Matthew Wild <mwild1@gmail.com>
parents: 10616
diff changeset
   111
		options = options or {};
f51c88baeb8a Backed out changeset 44ef46e1a951 (not optimal API)
Matthew Wild <mwild1@gmail.com>
parents: 10616
diff changeset
   112
		data = data;
12415
e132a4279914 net.connect: Support for multiple pending connection attempts
Matthew Wild <mwild1@gmail.com>
parents: 12209
diff changeset
   113
		conns = {};
10627
f51c88baeb8a Backed out changeset 44ef46e1a951 (not optimal API)
Matthew Wild <mwild1@gmail.com>
parents: 10616
diff changeset
   114
	}, pending_connection_mt);
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   115
10627
f51c88baeb8a Backed out changeset 44ef46e1a951 (not optimal API)
Matthew Wild <mwild1@gmail.com>
parents: 10616
diff changeset
   116
	p:log("debug", "Starting connection process");
f51c88baeb8a Backed out changeset 44ef46e1a951 (not optimal API)
Matthew Wild <mwild1@gmail.com>
parents: 10616
diff changeset
   117
	attempt_connection(p);
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   118
end
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   119
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   120
return {
10627
f51c88baeb8a Backed out changeset 44ef46e1a951 (not optimal API)
Matthew Wild <mwild1@gmail.com>
parents: 10616
diff changeset
   121
	connect = connect;
8534
601681acea73 net.connect: New API for outgoing connections, based on 'service resolvers'
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   122
};