Reset peer's endpoint when NAT traversal fails to connect to any endpoint candidates (#262)

* Add a missing call to reset a peer's endpoint when NAT traversal fails to connect to any endpoint candidates

* Simplify the process of resetting a peer to its server-reported endpoint
pull/263/head
Brian Schwind 2023-05-31 11:48:52 +09:00 committed by GitHub
parent ebeac3db76
commit bd4aabe787
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 23 additions and 18 deletions

View File

@ -33,17 +33,28 @@ impl<'a> NatTraverse<'a> {
// Limit reported alternative candidates to 10. // Limit reported alternative candidates to 10.
peer.candidates.truncate(10); peer.candidates.truncate(10);
// remove server-reported endpoint from elsewhere in the list if it existed. // Remove server-reported endpoint from elsewhere in the list if it existed.
let endpoint = peer.endpoint.clone(); let endpoint = peer.endpoint.clone();
peer.candidates peer.candidates
.retain(|addr| Some(addr) != endpoint.as_ref()); .retain(|addr| Some(addr) != endpoint.as_ref());
// Add the server-reported endpoint to the beginning of the list. In the event
// no other endpoints worked, the remaining endpoint in the list will be the one
// assigned to the peer so it should default to the server-reported endpoint.
// This is inserted at the beginning of the Vec as candidates are popped from
// the end as the algorithm progresses.
if let Some(endpoint) = endpoint {
peer.candidates.insert(0, endpoint);
}
} }
let mut nat_traverse = Self { let mut nat_traverse = Self {
interface, interface,
backend, backend,
remaining, remaining,
}; };
nat_traverse.refresh_remaining()?; nat_traverse.refresh_remaining()?;
Ok(nat_traverse) Ok(nat_traverse)
} }
@ -55,10 +66,9 @@ impl<'a> NatTraverse<'a> {
self.remaining.len() self.remaining.len()
} }
/// Refreshes the current state of candidate traversal attempts, returning /// Refreshes the current state of candidate traversal attempts, filtering out
/// the peers that have been exhausted of all options (not included are /// the peers that have been exhausted of all endpoint options.
/// peers that have successfully connected, or peers removed from the interface). fn refresh_remaining(&mut self) -> Result<(), Error> {
fn refresh_remaining(&mut self) -> Result<Vec<Peer>, Error> {
let device = Device::get(self.interface, self.backend)?; let device = Device::get(self.interface, self.backend)?;
// Remove connected and missing peers // Remove connected and missing peers
self.remaining.retain(|peer| { self.remaining.retain(|peer| {
@ -79,21 +89,14 @@ impl<'a> NatTraverse<'a> {
false false
} }
}); });
let (exhausted, remaining): (Vec<_>, Vec<_>) = self
.remaining self.remaining.retain(|peer| !peer.candidates.is_empty());
.drain(..)
.partition(|peer| peer.candidates.is_empty()); Ok(())
self.remaining = remaining;
Ok(exhausted)
} }
pub fn step(&mut self) -> Result<(), Error> { pub fn step(&mut self) -> Result<(), Error> {
let exhausted = self.refresh_remaining()?; self.refresh_remaining()?;
// Reset peer endpoints that had no viable candidates back to the server-reported one, if it exists.
let reset_updates = exhausted
.into_iter()
.filter_map(|peer| set_endpoint(&peer.public_key, peer.endpoint.as_ref()));
// Set all peers' endpoints to their next available candidate. // Set all peers' endpoints to their next available candidate.
let candidate_updates = self.remaining.iter_mut().filter_map(|peer| { let candidate_updates = self.remaining.iter_mut().filter_map(|peer| {
@ -104,7 +107,7 @@ impl<'a> NatTraverse<'a> {
set_endpoint(&peer.public_key, endpoint.as_ref()) set_endpoint(&peer.public_key, endpoint.as_ref())
}); });
let updates: Vec<_> = reset_updates.chain(candidate_updates).collect(); let updates: Vec<_> = candidate_updates.collect();
DeviceUpdate::new() DeviceUpdate::new()
.add_peers(&updates) .add_peers(&updates)
@ -113,12 +116,14 @@ impl<'a> NatTraverse<'a> {
let start = Instant::now(); let start = Instant::now();
while start.elapsed() < STEP_INTERVAL { while start.elapsed() < STEP_INTERVAL {
self.refresh_remaining()?; self.refresh_remaining()?;
if self.is_finished() { if self.is_finished() {
log::debug!("NAT traverser is finished!"); log::debug!("NAT traverser is finished!");
break; break;
} }
std::thread::sleep(Duration::from_millis(100)); std::thread::sleep(Duration::from_millis(100));
} }
Ok(()) Ok(())
} }
} }