pb_mapper_client/diagnostics/port_mapping.rs
1//! What a tunnel's gateway port mapping is doing, as [`TunnelDiagnostics`]
2//! and [`TunnelEventKind::PortMappingChanged`] report it.
3//!
4//! [`TunnelDiagnostics`]: super::TunnelDiagnostics
5//! [`TunnelEventKind::PortMappingChanged`]: super::TunnelEventKind::PortMappingChanged
6
7use serde::Serialize;
8use std::net::{Ipv4Addr, SocketAddr};
9
10/// Where a gateway mapping stands. A lease outlives some stages: whether one
11/// is usable right now is [`PortMappingStatus::active`].
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
13#[serde(rename_all = "snake_case")]
14pub enum PortMappingStage {
15 /// Asked for when needed (`PortMapping::Auto`): starts if a direct
16 /// attempt fails to punch through, which none has.
17 Standby,
18 /// Requested; starts with the tunnel's first direct session, when its UDP
19 /// endpoint opens.
20 WaitingForDirect,
21 /// Looking for the default gateway and the protocols it speaks.
22 Discovering,
23 /// Found the gateway.
24 GatewayFound,
25 /// Learned which of PCP, NAT-PMP and UPnP the gateway speaks.
26 Discovered,
27 /// Asking the gateway for a mapping.
28 Requesting,
29 /// The gateway granted a lease.
30 Active,
31 /// Extending the lease, which stays usable meanwhile.
32 Renewing,
33 /// The lease ran out before it was renewed.
34 Expired,
35 /// No lease yet; asking again, 30 s after the first time and then less
36 /// often, up to every 10 min.
37 Retrying,
38 /// The local network changed; the gateway is looked for again.
39 NetworkChanged,
40 /// Asking the gateway to delete the lease.
41 Releasing,
42 /// The gateway confirmed the deletion (UPnP).
43 Released,
44 /// The deletion was sent; PCP and NAT-PMP do not acknowledge it.
45 ReleaseSent,
46 /// Discovery or a request failed; see [`PortMappingStatus::error`].
47 Failed,
48 /// The lease could not be deleted and may stay until it expires.
49 ReleaseFailed,
50 /// An operation was abandoned before it finished.
51 Cancelled,
52 /// The mapping stopped with its tunnel.
53 Stopped,
54}
55
56impl PortMappingStage {
57 /// Stable diagnostic label, matching the serialized representation.
58 pub fn as_str(self) -> &'static str {
59 match self {
60 Self::Standby => "standby",
61 Self::WaitingForDirect => "waiting_for_direct",
62 Self::Discovering => "discovering",
63 Self::GatewayFound => "gateway_found",
64 Self::Discovered => "discovered",
65 Self::Requesting => "requesting",
66 Self::Active => "active",
67 Self::Renewing => "renewing",
68 Self::Expired => "expired",
69 Self::Retrying => "retrying",
70 Self::NetworkChanged => "network_changed",
71 Self::Releasing => "releasing",
72 Self::Released => "released",
73 Self::ReleaseSent => "release_sent",
74 Self::Failed => "failed",
75 Self::ReleaseFailed => "release_failed",
76 Self::Cancelled => "cancelled",
77 Self::Stopped => "stopped",
78 }
79 }
80}
81
82/// How a gateway is asked for a mapping.
83#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
84#[serde(rename_all = "snake_case")]
85pub enum PortMappingProtocol {
86 Pcp,
87 NatPmp,
88 Upnp,
89}
90
91impl PortMappingProtocol {
92 /// Stable diagnostic label, matching the serialized representation.
93 pub fn as_str(self) -> &'static str {
94 match self {
95 Self::Pcp => "pcp",
96 Self::NatPmp => "nat_pmp",
97 Self::Upnp => "upnp",
98 }
99 }
100}
101
102/// A gateway mapping as it stands after its latest change. Credential-free;
103/// what the gateway said about a failure is cut to 256 characters.
104#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
105pub struct PortMappingStatus {
106 pub stage: PortMappingStage,
107 /// The local network this mapping belongs to; a change starts over.
108 pub network_generation: u64,
109 /// The direct endpoint's UDP port, once it is open.
110 pub local_port: Option<u16>,
111 pub gateway: Option<Ipv4Addr>,
112 /// The protocol of the latest request or lease.
113 pub protocol: Option<PortMappingProtocol>,
114 /// What the gateway speaks, once discovery finished.
115 pub available_protocols: Vec<PortMappingProtocol>,
116 /// The public address the latest lease mapped to.
117 pub external_addr: Option<SocketAddr>,
118 /// Whether a lease is usable now: still true while a renewal is pending
119 /// or has failed, until the lease expires or is released.
120 pub active: bool,
121 pub lease_lifetime_ms: Option<u64>,
122 pub error: Option<String>,
123}
124
125impl PortMappingStatus {
126 pub(crate) fn new(stage: PortMappingStage, network_generation: u64) -> Self {
127 Self {
128 stage,
129 network_generation,
130 local_port: None,
131 gateway: None,
132 protocol: None,
133 available_protocols: Vec::new(),
134 external_addr: None,
135 active: false,
136 lease_lifetime_ms: None,
137 error: None,
138 }
139 }
140}
141
142/// A tunnel's port mapping: where it stands, and what it took to get there.
143#[derive(Clone, Debug, Serialize)]
144pub struct PortMappingDiagnostics {
145 pub current: PortMappingStatus,
146 /// Requests for a new lease.
147 pub attempts: u64,
148 pub renewals: u64,
149 /// Failed discoveries, requests and releases.
150 pub failures: u64,
151}