mirror of
https://github.com/rustdesk/hbb_common.git
synced 2026-10-11 19:23:59 +00:00
socket_client: only the controller's NAT test takes the resolver's address
`new_direct_udp_for` is back on `test_target`. The punch reply the controlled side sends with it goes to the address it picks, and that reply lost is a device online and unreachable - so it keeps the handshake that proves the address, as the registration does. The controller's NAT test, once per connection, is what could not afford the proof, a round trip right before the connection it then opens to the same host; it alone takes the resolver's preferred address, as `new_direct_udp_for_unverified`, and a wrong one there costs that connection its UDP punch and nothing more. That lookup is the first on the controller's connection path and the one not under CONNECT_TIMEOUT, so it gets a second: a resolver that hangs would otherwise hold the connection for its whole retry schedule before `connect_tcp` even starts, and what a slower lookup loses is, again, only the NAT test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019aokqJuhjvB3kijXtAg5Ns
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
0bc83361d6
commit
7a5ad5252e
+17
-4
@@ -204,8 +204,8 @@ pub fn ipv4_to_ipv6(addr: String, ipv4: bool) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The resolver's preferred address for `target`: first in getaddrinfo's RFC 6724 order, so NAT64's
|
/// The resolver's preferred address for `target`: first in getaddrinfo's RFC 6724 order, so NAT64's
|
||||||
/// synthesized IPv6 leads on a v6-only host. Preferred, not proven reachable: the per-connection
|
/// synthesized IPv6 leads on a v6-only host. Preferred, not proven reachable: what `test_target`
|
||||||
/// UDP paths take it as is, and spare themselves the round trip that proving it costs.
|
/// falls back to, and what the controller's NAT test takes as is to spare itself the proof.
|
||||||
async fn resolve_target(target: &str) -> ResultType<SocketAddr> {
|
async fn resolve_target(target: &str) -> ResultType<SocketAddr> {
|
||||||
tokio::net::lookup_host(target)
|
tokio::net::lookup_host(target)
|
||||||
.await?
|
.await?
|
||||||
@@ -215,7 +215,7 @@ async fn resolve_target(target: &str) -> ResultType<SocketAddr> {
|
|||||||
|
|
||||||
/// The address of `target` a TCP connection reaches, the resolver's candidates tried in order until
|
/// The address of `target` a TCP connection reaches, the resolver's candidates tried in order until
|
||||||
/// one answers: an AAAA the server refuses is passed over for its A record, which the order alone
|
/// one answers: an AAAA the server refuses is passed over for its A record, which the order alone
|
||||||
/// would not do. For the rendezvous registration, which lives on what this picks.
|
/// would not do. For the rendezvous registration and the punch reply, which live on what it picks.
|
||||||
async fn test_target(target: &str) -> ResultType<SocketAddr> {
|
async fn test_target(target: &str) -> ResultType<SocketAddr> {
|
||||||
if let Ok(Ok(s)) = super::timeout(1000, tokio::net::TcpStream::connect(target)).await {
|
if let Ok(Ok(s)) = super::timeout(1000, tokio::net::TcpStream::connect(target)).await {
|
||||||
if let Ok(addr) = s.peer_addr() {
|
if let Ok(addr) = s.peer_addr() {
|
||||||
@@ -227,7 +227,20 @@ async fn test_target(target: &str) -> ResultType<SocketAddr> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn new_direct_udp_for(target: &str) -> ResultType<(Arc<UdpSocket>, SocketAddr)> {
|
pub async fn new_direct_udp_for(target: &str) -> ResultType<(Arc<UdpSocket>, SocketAddr)> {
|
||||||
let peer_addr = resolve_target(target).await?;
|
let peer_addr = test_target(target).await?;
|
||||||
|
let local_addr = Config::get_any_listen_addr(peer_addr.is_ipv4());
|
||||||
|
let socket = UdpSocket::bind(local_addr).await?;
|
||||||
|
Ok((Arc::new(socket), peer_addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `new_direct_udp_for` on the resolver's preferred address, with no handshake to prove it and a
|
||||||
|
/// second at most for the lookup: for the controller's NAT test, once per connection, where the
|
||||||
|
/// proof cost a round trip right before the connection it then opens to the same host.
|
||||||
|
#[inline]
|
||||||
|
pub async fn new_direct_udp_for_unverified(
|
||||||
|
target: &str,
|
||||||
|
) -> ResultType<(Arc<UdpSocket>, SocketAddr)> {
|
||||||
|
let peer_addr = super::timeout(1000, resolve_target(target)).await??;
|
||||||
let local_addr = Config::get_any_listen_addr(peer_addr.is_ipv4());
|
let local_addr = Config::get_any_listen_addr(peer_addr.is_ipv4());
|
||||||
let socket = UdpSocket::bind(local_addr).await?;
|
let socket = UdpSocket::bind(local_addr).await?;
|
||||||
Ok((Arc::new(socket), peer_addr))
|
Ok((Arc::new(socket), peer_addr))
|
||||||
|
|||||||
Reference in New Issue
Block a user