Skip to content

Commit

Permalink
refactor, remove some magicsock apis and add
Browse files Browse the repository at this point in the history
this method handles the logic of getting a mapped quic addr and launching discovery if it is needed
  • Loading branch information
ramfox committed Apr 25, 2024
1 parent 209789e commit a674622
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 48 deletions.
94 changes: 63 additions & 31 deletions iroh-net/src/magic_endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,39 +442,14 @@ impl MagicEndpoint {
self.add_node_addr(node_addr.clone())?;
}

let NodeAddr { node_id, info } = node_addr;
let NodeAddr { node_id, info } = node_addr.clone();

// Get the mapped IPv6 address from the magic socket. Quinn will connect to this address.
let (addr, discovery) = match self.msock.get_mapping_addr_if_send_addr_available(&node_id) {
Some(addr) => {
// We got a mapped address, which means we either spoke to this endpoint before, or
// the user provided addressing info with the [`NodeAddr`].
// This does not mean that we can actually connect to any of these addresses.
// Therefore, we will invoke the discovery service if we haven't received from the
// endpoint on any of the existing paths recently.
// If the user provided addresses in this connect call, we will add a delay
// followed by a recheck before starting the discovery, to give the magicsocket a
// chance to test the newly provided addresses.
let delay = (!info.is_empty()).then_some(DISCOVERY_WAIT_PERIOD);
let discovery = DiscoveryTask::maybe_start_after_delay(self, node_id, delay)
.ok()
.flatten();
(addr, discovery)
}

None => {
// We have not spoken to this endpoint before, and the user provided no direct
// addresses or relay URLs. Thus, we start a discovery task and wait for the first
// result to arrive, and only then continue, because otherwise we wouldn't have any
// path to the remote endpoint.
let mut discovery = DiscoveryTask::start(self.clone(), node_id)?;
discovery.first_arrived().await?;
let addr = self.msock.get_mapping_addr_if_send_addr_available(&node_id).ok_or_else(|| {
anyhow!("Failed to retrieve the mapped address from the magic socket. Unable to dial node {node_id:?}")
})?;
(addr, Some(discovery))
}
};
// Start discovery for this node if it's enabled and we have no valid or verified
// address information for this node.
let (addr, discovery) = self
.get_mapping_addr_and_maybe_start_discovery(node_addr)
.await?;

debug!(
"connecting to {}: (via {} - {:?})",
Expand Down Expand Up @@ -522,6 +497,63 @@ impl MagicEndpoint {
connect.await.context("failed connecting to provider")
}

/// Return the quic mapped address for this `node_id` and possibly start discovery
/// services if discovery is enabled on this magic endpoint.
///
/// This will launch discovery in all cases except if:
/// 1) we do not have discovery enabled
/// 2) we have discovery enabled, but already have at least one verified, unexpired
/// addresses for this `node_id`
///
/// # Errors
///
/// This method may fail if we have no way of dialing the node. This can occur if
/// because we were given no dialing information in the [`NodeAddr`] and no discovery
/// services configured or discovery failed to fetch any dialing information.
async fn get_mapping_addr_and_maybe_start_discovery(
&self,
node_addr: NodeAddr,
) -> Result<(SocketAddr, Option<DiscoveryTask>)> {
let node_id = node_addr.node_id;
let addr = if self.msock.has_send_address(node_id) {
self.msock.get_mapping_addr(&node_id)
} else {
None
};
match addr {
Some(addr) => {
// We got a mapped address, which means we either spoke to this endpoint before, or
// the user provided addressing info with the [`NodeAddr`].
// This does not mean that we can actually connect to any of these addresses.
// Therefore, we will invoke the discovery service if we haven't received from the
// endpoint on any of the existing paths recently.
// If the user provided addresses in this connect call, we will add a delay
// followed by a recheck before starting the discovery, to give the magicsocket a
// chance to test the newly provided addresses.
let delay = (!node_addr.info.is_empty()).then_some(DISCOVERY_WAIT_PERIOD);
let discovery = DiscoveryTask::maybe_start_after_delay(self, node_id, delay)
.ok()
.flatten();
Ok((addr, discovery))
}

None => {
// We have not spoken to this endpoint before, and the user provided no direct
// addresses or relay URLs. Thus, we start a discovery task and wait for the first
// result to arrive, and only then continue, because otherwise we wouldn't have any
// path to the remote endpoint.
let mut discovery = DiscoveryTask::start(self.clone(), node_id)?;
discovery.first_arrived().await?;
if self.msock.has_send_address(node_id) {
let addr = self.msock.get_mapping_addr(&node_id).expect("checked");
Ok((addr, Some(discovery)))
} else {
bail!("Failed to retrieve the mapped address from the magic socket. Unable to dial node {node_id:?}");
}
}
}
}

/// Inform the magic socket about addresses of the peer.
///
/// This updates the magic socket's *netmap* with these addresses, which are used as candidates
Expand Down
17 changes: 0 additions & 17 deletions iroh-net/src/magicsock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1397,23 +1397,6 @@ impl MagicSock {
.map(|a| a.0)
}

/// Returns the [`SocketAddr`] which can be used by the QUIC layer to dial this node.
///
/// Returns `None` if no send address is available.
pub fn get_mapping_addr_if_send_addr_available(
&self,
node_key: &PublicKey,
) -> Option<SocketAddr> {
if self.has_send_address(*node_key) {
self.inner
.node_map
.get_quic_mapped_addr_for_node_key(node_key)
.map(|a| a.0)
} else {
None
}
}

/// Returns the relay node with the best latency.
///
/// If `None`, then we currently have no verified connection to a relay node.
Expand Down

0 comments on commit a674622

Please sign in to comment.