bump hbb_common: name the punch by every transport it carries

`get_local_endpoint_trickle` became `local_endpoint() -> &str`, which
cannot fail, so both call sites lose an unreachable error arm — the
mediator's closed a pc against a failure that no longer exists.

`punch_type` named one transport, and picked it off `allow_tcp_punch`.
A round carries several at once — a NAT port and a v6 address and an
offer — and since the TCP punch became a switch it can carry none, so
one name had to misreport both: the logs of the round that broke WebRTC
read "#1 UDP punch attempt" while the request also carried the v6
address and the offer that was actually failing, and a round with
nothing to punch with was labelled "WebRTC". List them instead —
"UDP+IPv6+WebRTC" — and call the empty round "Relay", which is what it
can still end as and what `typ` prints for it.

The offer is moved into the request rather than cloned into it; that
was its last use.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019UzcMTdYTEv2QbMHcTSUy3
This commit is contained in:
rustdesk
2026-08-25 08:38:56 +08:00
parent 39a266cfd5
commit d6a670e764
3 changed files with 29 additions and 28 deletions

View File

@@ -855,25 +855,33 @@ impl Client {
.map(|(socket, addr)| (Some(socket), Some(addr))) .map(|(socket, addr)| (Some(socket), Some(addr)))
.unwrap_or((None, None)); .unwrap_or((None, None));
let udp_nat_port = udp.1.map(|x| *x.lock().unwrap()).unwrap_or(0); let udp_nat_port = udp.1.map(|x| *x.lock().unwrap()).unwrap_or(0);
let webrtc_sdp_offer = let webrtc_sdp_offer = webrtc_offerer
if let Some(stream) = webrtc_offerer.as_ref().and_then(|g| g.stream()) { .as_ref()
match stream.get_local_endpoint_trickle().await { .and_then(|g| g.stream())
Ok(endpoint) => endpoint, .map(|stream| stream.local_endpoint().to_owned())
Err(err) => { .unwrap_or_default();
log::warn!("failed to read local WebRTC offer: {}", err);
String::new()
}
}
} else {
String::new()
};
let allow_tcp_punch = tcp_punch_allowed() && request_allows_tcp_punch(&webrtc_sdp_offer); let allow_tcp_punch = tcp_punch_allowed() && request_allows_tcp_punch(&webrtc_sdp_offer);
let punch_type = if udp_nat_port > 0 { // Every direct transport this round carries, not one of them: a round can carry several
"UDP" // at once (a NAT port and an offer and a v6 address), and since the TCP punch became a
} else if allow_tcp_punch { // switch it can carry none — a single name had to misreport both. `relay` is not a punch,
"TCP" // it is what a round with nothing to punch with can still end as.
let mut transports = Vec::new();
if udp_nat_port > 0 {
transports.push("UDP");
}
if allow_tcp_punch {
transports.push("TCP");
}
if ipv6.1.is_some() {
transports.push("IPv6");
}
if !webrtc_sdp_offer.is_empty() {
transports.push("WebRTC");
}
let punch_type = if transports.is_empty() {
"Relay".to_owned()
} else { } else {
"WebRTC" transports.join("+")
}; };
msg_out.set_punch_hole_request(PunchHoleRequest { msg_out.set_punch_hole_request(PunchHoleRequest {
id: peer.to_owned(), id: peer.to_owned(),
@@ -889,7 +897,7 @@ impl Client {
// The offer's envelope itself declares its ICE policy (`ice_policy: "all"` under // The offer's envelope itself declares its ICE policy (`ice_policy: "all"` under
// pure ws), telling the controlled side its answer may gather every candidate // pure ws), telling the controlled side its answer may gather every candidate
// type despite force_relay instead of requiring TURN. // type despite force_relay instead of requiring TURN.
webrtc_sdp_offer: webrtc_sdp_offer.clone(), webrtc_sdp_offer,
..Default::default() ..Default::default()
}); });
let webrtc_session_key = webrtc_offerer let webrtc_session_key = webrtc_offerer
@@ -1310,7 +1318,7 @@ impl Client {
webrtc_for_connect, webrtc_for_connect,
webrtc_bridge_stop, webrtc_bridge_stop,
allow_tcp_punch, allow_tcp_punch,
punch_type, &punch_type,
) )
.await?, .await?,
(feedback, rendezvous_server), (feedback, rendezvous_server),

View File

@@ -700,14 +700,7 @@ impl RendezvousMediator {
) -> ResultType<String> { ) -> ResultType<String> {
let mut stream = let mut stream =
WebRTCStream::new(&ph.webrtc_sdp_offer, relay_only_ice, CONNECT_TIMEOUT).await?; WebRTCStream::new(&ph.webrtc_sdp_offer, relay_only_ice, CONNECT_TIMEOUT).await?;
let answer = match stream.get_local_endpoint_trickle().await { let answer = stream.local_endpoint().to_owned();
Ok(answer) => answer,
Err(e) => {
// Close the freshly-created pc so a failure here doesn't leak it in SESSIONS.
stream.close().await;
return Err(e);
}
};
let session_key = stream.session_key().to_owned(); let session_key = stream.session_key().to_owned();
let return_route = ph.socket_addr.clone(); let return_route = ph.socket_addr.clone();