1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! Dial hand-off (SPEC §5.8, §11): turning a *ranked identity* into something a caller can actually
//! connect to.
//!
//! The selector still opens no socket. What it removes is the last piece of hand-assembly a consumer
//! had to do between `select` and `dig_peer::DigPeer::connect`: mapping a chosen `peer_id` back to
//! its dial addresses and building a [`PeerTarget`]. Every consumer doing that itself is a second
//! implementation of one shared behavior, which is exactly how the addressing of two crates drifts
//! apart (#1283).
//!
//! For the same reason this module **inherits** the candidate ordering rather than expressing one:
//! [`dig_dht::dial_candidates`] is the ONE place the DHT states it, and it carries three properties
//! that are easy to omit when re-derived — the dialable-kind filter, dedup by `host:port`, and the
//! reserved fallback slot that stops a cap-`MAX_DIAL_CANDIDATES` truncation from excluding every
//! non-IPv6 candidate (the #836 read-leg failure: a v6 attempt must never mask a working v4 one).
//!
//! The [`PeerTarget`] carries the `peer_id`, and `DigPeer::connect` PINS the mTLS handshake to it —
//! so a caller that means to reach peer X cannot be answered by a different CA-valid peer. That
//! pinning is the reason the hand-off is a target and not a bare address list (NC-12: a dialed peer
//! is untrusted, and the addresses it advertised are a hint, never evidence about who it is).
use CandidateAddr;
use PeerTarget;
use ;
use cratePeerId;
/// Build the dial target for `peer_id` from its learned candidate addresses.
///
/// Candidates whose host is not an IP literal are dropped FIRST, then the survivors go through
/// [`dig_dht::dial_candidates`] — that order matters: `dial_candidates` bounds the list at
/// [`MAX_DIAL_CANDIDATES`](dig_dht::MAX_DIAL_CANDIDATES), so filtering afterwards would let unusable
/// hostnames occupy cap slots and push a working IP literal out of the result entirely.
///
/// Dropping hostnames at all is this layer's one addition, and it is forced by the output type: a
/// [`PeerTarget`] carries resolved [`SocketAddr`]s, and this crate resolves no DNS on the dial path.
/// DHT candidates are *observed* socket addresses, so a hostname denotes a malformed record.
///
/// Address FAMILY order is applied by `dial_candidates` (IPv6-first, IPv4-fallback) and again by
/// `dig-ip` at dial time against the local host's own families; this layer adds no ordering of its
/// own. When nothing dialable survives, the result is a relay-only target: the peer stays reachable
/// by identity alone rather than becoming unconnectable.
/// Resolve one candidate to a dialable socket, or `None` when its host is not an IP literal.
///
/// Parsing the host into an [`IpAddr`] before attaching the port is what makes this correct for IPv6
/// and v4-mapped hosts alike — formatting `host:port` as text would produce `::1:9000`, which is a
/// different (and unparseable) address.