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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! Traversal methods — one module per NAT-traversal technique behind a common
//! [`TraversalMethod`] trait, plus the [`TraversalKind`] tag the strategy orders them by.
//!
//! Each method answers ONE question: "given this peer, can you produce a reachable socket address I
//! can dial (and, for the relayed method, an already-open transport)?" The [`crate::strategy`]
//! module owns the ORDER + the racing/sequencing; a method never decides it is "the one". This keeps
//! every technique small, single-purpose, and independently testable with a mock socket / fake IGD /
//! loopback relay.
//!
//! Attempt order (first success wins), from the crate `DESIGN.md`:
//! 1. [`direct`] — peer publicly reachable / already port-forwarded
//! 2. [`upnp`] — UPnP/IGD port mapping
//! 3. [`natpmp`] — NAT-PMP (RFC 6886)
//! 4. [`pcp`] — PCP (RFC 6887)
//! 5. [`hole_punch`] — relay-coordinated simultaneous-open hole punch: the relay is used ONLY as a
//! signaling/rendezvous channel to exchange candidates + coordinate timing; the DATA path is
//! peer-to-peer DIRECT (relay carries no data → minimal relay bandwidth).
//! 6. [`relayed`] — TURN-like relayed transport: the relay carries ALL data (highest relay
//! bandwidth). The genuine LAST resort, tried only after the hole punch (tier 5) fails.
//!
//! Tiers 5 and 6 are deliberately SEPARATE methods with separate abstractions
//! ([`hole_punch::HolePunchCoordinator`] = signaling-only vs [`relayed::RelayedTransport`] =
//! data-proxy) and separate [`TraversalKind`]s so observability reports exactly which succeeded and
//! the strategy prefers the bandwidth-cheap punch before the bandwidth-heavy TURN.
use SocketAddr;
use async_trait;
use crateMethodError;
use cratePeerTarget;
/// Which traversal technique produced a result — used to order methods, tag failures, and report
/// (observability) which method actually succeeded WITHOUT the caller caring.
///
/// Ordinal order == attempt order == relay-last: a smaller [`TraversalKind::rank`] is tried first,
/// and `Relayed` has the highest rank so it is always the last resort.
/// What a traversal method yields on success: the dialable candidate addresses for the peer
/// (ordered **IPv6-first**), plus which technique produced them. The [`crate::strategy`] then
/// performs the mTLS dial, trying the candidates IPv6-first with IPv4 fallback (happy-eyeballs, see
/// [`crate::dialer`]) — except the relayed method, which returns the already-open relay tunnel.
///
/// The direct/mapping methods carry the peer's whole IPv6-first candidate list so the dial can fall
/// back across families; the hole-punch/relayed methods yield a single coordinated/relay address
/// ([`MethodOutcome::single`]).
/// A single NAT-traversal technique. Implementors are small + single-purpose and MUST honour the
/// deadline the strategy hands them (they are additionally wrapped in a hard timeout by the
/// strategy, so a hung method can never block `connect`).