mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-09 08:14:42 +00:00
Apply rustfmt to master-only code
This commit is contained in:
@@ -1,12 +1,10 @@
|
||||
//! Handshake handlers and connection promotion.
|
||||
|
||||
use crate::node::{Node, NodeError};
|
||||
use crate::peer::{
|
||||
cross_connection_winner, ActivePeer, PeerConnection, PromotionResult,
|
||||
};
|
||||
use crate::transport::{Link, LinkDirection, LinkId, ReceivedPacket};
|
||||
use crate::node::wire::{build_msg2, Msg1Header, Msg2Header};
|
||||
use crate::PeerIdentity;
|
||||
use crate::node::wire::{Msg1Header, Msg2Header, build_msg2};
|
||||
use crate::node::{Node, NodeError};
|
||||
use crate::peer::{ActivePeer, PeerConnection, PromotionResult, cross_connection_winner};
|
||||
use crate::transport::{Link, LinkDirection, LinkId, ReceivedPacket};
|
||||
use std::time::Duration;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
@@ -63,8 +61,7 @@ impl Node {
|
||||
{
|
||||
if link.direction() == LinkDirection::Inbound {
|
||||
// Check if this link belongs to an already-promoted active peer
|
||||
let is_active_peer = self.peers.values()
|
||||
.any(|p| p.link_id() == existing_link_id);
|
||||
let is_active_peer = self.peers.values().any(|p| p.link_id() == existing_link_id);
|
||||
|
||||
if is_active_peer {
|
||||
// Possible restart — fall through to decrypt and check epoch
|
||||
@@ -100,8 +97,7 @@ impl Node {
|
||||
// peer, this may be a rekey msg1 (same epoch) or a
|
||||
// restart (different epoch). Set possible_restart to enable
|
||||
// the epoch/rekey check below.
|
||||
let is_active_peer = self.peers.values()
|
||||
.any(|p| p.link_id() == existing_link_id);
|
||||
let is_active_peer = self.peers.values().any(|p| p.link_id() == existing_link_id);
|
||||
if is_active_peer {
|
||||
possible_restart = true;
|
||||
} else {
|
||||
@@ -126,7 +122,12 @@ impl Node {
|
||||
|
||||
let our_keypair = self.identity.keypair();
|
||||
let noise_msg1 = &packet.data[header.noise_msg1_offset..];
|
||||
let msg2_response = match conn.receive_handshake_init(our_keypair, self.startup_epoch, noise_msg1, packet.timestamp_ms) {
|
||||
let msg2_response = match conn.receive_handshake_init(
|
||||
our_keypair,
|
||||
self.startup_epoch,
|
||||
noise_msg1,
|
||||
packet.timestamp_ms,
|
||||
) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
self.msg1_rate_limiter.complete_handshake();
|
||||
@@ -162,9 +163,7 @@ impl Node {
|
||||
// If we fell through from the addr_to_link check above with
|
||||
// possible_restart=true, we now have the decrypted epoch from msg1.
|
||||
// Compare it against the stored epoch for this peer.
|
||||
if possible_restart
|
||||
&& let Some(existing_peer) = self.peers.get(&peer_node_addr)
|
||||
{
|
||||
if possible_restart && let Some(existing_peer) = self.peers.get(&peer_node_addr) {
|
||||
let new_epoch = conn.remote_epoch();
|
||||
let existing_epoch = existing_peer.remote_epoch();
|
||||
|
||||
@@ -192,10 +191,8 @@ impl Node {
|
||||
// During simultaneous connection, both sides promote
|
||||
// within the same tick and the peer's msg1 arrives
|
||||
// immediately — a genuine rekey can't fire that fast.
|
||||
let session_age_secs = existing_peer
|
||||
.session_established_at()
|
||||
.elapsed()
|
||||
.as_secs();
|
||||
let session_age_secs =
|
||||
existing_peer.session_established_at().elapsed().as_secs();
|
||||
if self.config.node.rekey.enabled
|
||||
&& existing_peer.has_session()
|
||||
&& existing_peer.is_healthy()
|
||||
@@ -272,7 +269,8 @@ impl Node {
|
||||
};
|
||||
|
||||
// Send msg2 response using the new handshake
|
||||
let wire_msg2 = build_msg2(our_new_index, header.sender_idx, &msg2_response);
|
||||
let wire_msg2 =
|
||||
build_msg2(our_new_index, header.sender_idx, &msg2_response);
|
||||
if let Some(transport) = self.transports.get(&packet.transport_id) {
|
||||
match transport.send(&packet.remote_addr, &wire_msg2).await {
|
||||
Ok(_) => {
|
||||
@@ -401,7 +399,8 @@ impl Node {
|
||||
// Clean up on failure
|
||||
self.connections.remove(&link_id);
|
||||
self.links.remove(&link_id);
|
||||
self.addr_to_link.remove(&(packet.transport_id, packet.remote_addr));
|
||||
self.addr_to_link
|
||||
.remove(&(packet.transport_id, packet.remote_addr));
|
||||
let _ = self.index_allocator.free(our_index);
|
||||
self.msg1_rate_limiter.complete_handshake();
|
||||
return;
|
||||
@@ -434,7 +433,10 @@ impl Node {
|
||||
self.bloom_state.mark_update_needed(node_addr);
|
||||
self.reset_discovery_backoff();
|
||||
}
|
||||
PromotionResult::CrossConnectionWon { loser_link_id, node_addr } => {
|
||||
PromotionResult::CrossConnectionWon {
|
||||
loser_link_id,
|
||||
node_addr,
|
||||
} => {
|
||||
// Store msg2 on peer for resend on duplicate msg1
|
||||
if let Some(peer) = self.peers.get_mut(&node_addr) {
|
||||
peer.set_handshake_msg2(wire_msg2.clone());
|
||||
@@ -552,9 +554,7 @@ impl Node {
|
||||
|
||||
// Find peer with rekey in progress for this index
|
||||
let peer_addr = self.peers.iter().find_map(|(addr, peer)| {
|
||||
if peer.rekey_in_progress()
|
||||
&& peer.rekey_our_index() == Some(header.receiver_idx)
|
||||
{
|
||||
if peer.rekey_in_progress() && peer.rekey_our_index() == Some(header.receiver_idx) {
|
||||
Some(*addr)
|
||||
} else {
|
||||
None
|
||||
@@ -568,15 +568,12 @@ impl Node {
|
||||
if let Some(peer) = self.peers.get_mut(&peer_node_addr) {
|
||||
match peer.complete_rekey_msg2(noise_msg2) {
|
||||
Ok(session) => {
|
||||
let our_index = peer.rekey_our_index()
|
||||
.unwrap_or(header.receiver_idx);
|
||||
let our_index = peer.rekey_our_index().unwrap_or(header.receiver_idx);
|
||||
peer.set_pending_session(session, our_index, header.sender_idx);
|
||||
|
||||
if let Some(transport_id) = peer.transport_id() {
|
||||
self.peers_by_index.insert(
|
||||
(transport_id, our_index.as_u32()),
|
||||
peer_node_addr,
|
||||
);
|
||||
self.peers_by_index
|
||||
.insert((transport_id, our_index.as_u32()), peer_node_addr);
|
||||
}
|
||||
|
||||
debug!(
|
||||
@@ -679,15 +676,17 @@ impl Node {
|
||||
let outbound_our_index = conn.our_index();
|
||||
let outbound_session = conn.take_session();
|
||||
|
||||
let (outbound_session, outbound_our_index) =
|
||||
match (outbound_session, outbound_our_index) {
|
||||
(Some(s), Some(idx)) => (s, idx),
|
||||
_ => {
|
||||
warn!(peer = %self.peer_display_name(&peer_node_addr), "Incomplete outbound connection");
|
||||
self.pending_outbound.remove(&key);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let (outbound_session, outbound_our_index) = match (
|
||||
outbound_session,
|
||||
outbound_our_index,
|
||||
) {
|
||||
(Some(s), Some(idx)) => (s, idx),
|
||||
_ => {
|
||||
warn!(peer = %self.peer_display_name(&peer_node_addr), "Incomplete outbound connection");
|
||||
self.pending_outbound.remove(&key);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(peer) = self.peers.get_mut(&peer_node_addr) {
|
||||
let suppressed = peer.replay_suppressed_count();
|
||||
@@ -700,13 +699,12 @@ impl Node {
|
||||
// Update peers_by_index: remove old inbound index, add outbound
|
||||
let transport_id = peer.transport_id().unwrap();
|
||||
if let Some(old_idx) = old_our_index {
|
||||
self.peers_by_index.remove(&(transport_id, old_idx.as_u32()));
|
||||
self.peers_by_index
|
||||
.remove(&(transport_id, old_idx.as_u32()));
|
||||
let _ = self.index_allocator.free(old_idx);
|
||||
}
|
||||
self.peers_by_index.insert(
|
||||
(transport_id, outbound_our_index.as_u32()),
|
||||
peer_node_addr,
|
||||
);
|
||||
self.peers_by_index
|
||||
.insert((transport_id, outbound_our_index.as_u32()), peer_node_addr);
|
||||
|
||||
if suppressed > 0 {
|
||||
debug!(
|
||||
@@ -791,7 +789,10 @@ impl Node {
|
||||
self.bloom_state.mark_update_needed(node_addr);
|
||||
self.reset_discovery_backoff();
|
||||
}
|
||||
PromotionResult::CrossConnectionWon { loser_link_id, node_addr } => {
|
||||
PromotionResult::CrossConnectionWon {
|
||||
loser_link_id,
|
||||
node_addr,
|
||||
} => {
|
||||
// Close the losing TCP connection (no-op for connectionless)
|
||||
if let Some(loser_link) = self.links.get(&loser_link_id) {
|
||||
let loser_tid = loser_link.transport_id();
|
||||
@@ -803,10 +804,8 @@ impl Node {
|
||||
// Clean up the losing connection's link
|
||||
self.remove_link(&loser_link_id);
|
||||
// Ensure addr_to_link points to the winning link
|
||||
self.addr_to_link.insert(
|
||||
(packet.transport_id, packet.remote_addr.clone()),
|
||||
link_id,
|
||||
);
|
||||
self.addr_to_link
|
||||
.insert((packet.transport_id, packet.remote_addr.clone()), link_id);
|
||||
debug!(
|
||||
peer = %self.peer_display_name(&node_addr),
|
||||
loser_link_id = %loser_link_id,
|
||||
@@ -873,30 +872,31 @@ impl Node {
|
||||
.take_session()
|
||||
.ok_or(NodeError::NoSession(link_id))?;
|
||||
|
||||
let our_index = connection.our_index().ok_or_else(|| {
|
||||
NodeError::PromotionFailed {
|
||||
let our_index = connection
|
||||
.our_index()
|
||||
.ok_or_else(|| NodeError::PromotionFailed {
|
||||
link_id,
|
||||
reason: "missing our_index".into(),
|
||||
}
|
||||
})?;
|
||||
let their_index = connection.their_index().ok_or_else(|| {
|
||||
NodeError::PromotionFailed {
|
||||
})?;
|
||||
let their_index = connection
|
||||
.their_index()
|
||||
.ok_or_else(|| NodeError::PromotionFailed {
|
||||
link_id,
|
||||
reason: "missing their_index".into(),
|
||||
}
|
||||
})?;
|
||||
let transport_id = connection.transport_id().ok_or_else(|| {
|
||||
NodeError::PromotionFailed {
|
||||
})?;
|
||||
let transport_id = connection
|
||||
.transport_id()
|
||||
.ok_or_else(|| NodeError::PromotionFailed {
|
||||
link_id,
|
||||
reason: "missing transport_id".into(),
|
||||
}
|
||||
})?;
|
||||
let current_addr = connection.source_addr().ok_or_else(|| {
|
||||
NodeError::PromotionFailed {
|
||||
})?;
|
||||
let current_addr = connection
|
||||
.source_addr()
|
||||
.ok_or_else(|| NodeError::PromotionFailed {
|
||||
link_id,
|
||||
reason: "missing source_addr".into(),
|
||||
}
|
||||
})?.clone();
|
||||
})?
|
||||
.clone();
|
||||
let link_stats = connection.link_stats().clone();
|
||||
let remote_epoch = connection.remote_epoch();
|
||||
|
||||
@@ -908,11 +908,8 @@ impl Node {
|
||||
let existing_link_id = existing_peer.link_id();
|
||||
|
||||
// Determine which connection wins
|
||||
let this_wins = cross_connection_winner(
|
||||
self.identity.node_addr(),
|
||||
&peer_node_addr,
|
||||
is_outbound,
|
||||
);
|
||||
let this_wins =
|
||||
cross_connection_winner(self.identity.node_addr(), &peer_node_addr, is_outbound);
|
||||
|
||||
if this_wins {
|
||||
// This connection wins, replace the existing peer
|
||||
@@ -923,8 +920,7 @@ impl Node {
|
||||
if let (Some(old_tid), Some(old_idx)) =
|
||||
(old_peer.transport_id(), old_peer.our_index())
|
||||
{
|
||||
self.peers_by_index
|
||||
.remove(&(old_tid, old_idx.as_u32()));
|
||||
self.peers_by_index.remove(&(old_tid, old_idx.as_u32()));
|
||||
let _ = self.index_allocator.free(old_idx);
|
||||
}
|
||||
|
||||
@@ -942,7 +938,9 @@ impl Node {
|
||||
&self.config.node.mmp,
|
||||
remote_epoch,
|
||||
);
|
||||
new_peer.set_tree_announce_min_interval_ms(self.config.node.tree.announce_min_interval_ms);
|
||||
new_peer.set_tree_announce_min_interval_ms(
|
||||
self.config.node.tree.announce_min_interval_ms,
|
||||
);
|
||||
|
||||
self.peers.insert(peer_node_addr, new_peer);
|
||||
self.peers_by_index
|
||||
@@ -1008,13 +1006,17 @@ impl Node {
|
||||
// Normal promotion
|
||||
if self.max_peers > 0 && self.peers.len() >= self.max_peers {
|
||||
let _ = self.index_allocator.free(our_index);
|
||||
return Err(NodeError::MaxPeersExceeded { max: self.max_peers });
|
||||
return Err(NodeError::MaxPeersExceeded {
|
||||
max: self.max_peers,
|
||||
});
|
||||
}
|
||||
|
||||
// Preserve tree announce rate-limit state from old peer (if reconnecting).
|
||||
// Without this, reconnection resets the rate limit window to zero,
|
||||
// allowing an immediate announce that can feed an announce loop.
|
||||
let old_announce_ts = self.peers.get(&peer_node_addr)
|
||||
let old_announce_ts = self
|
||||
.peers
|
||||
.get(&peer_node_addr)
|
||||
.map(|p| p.last_tree_announce_sent_ms());
|
||||
|
||||
let mut new_peer = ActivePeer::with_session(
|
||||
@@ -1031,7 +1033,8 @@ impl Node {
|
||||
&self.config.node.mmp,
|
||||
remote_epoch,
|
||||
);
|
||||
new_peer.set_tree_announce_min_interval_ms(self.config.node.tree.announce_min_interval_ms);
|
||||
new_peer
|
||||
.set_tree_announce_min_interval_ms(self.config.node.tree.announce_min_interval_ms);
|
||||
if let Some(ts) = old_announce_ts {
|
||||
new_peer.set_last_tree_announce_sent_ms(ts);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
//! 2. Drain window expiry (clean up previous session after cutover)
|
||||
//! 3. Initiator-side cutover (first send after handshake completion)
|
||||
|
||||
use crate::NodeAddr;
|
||||
use crate::node::Node;
|
||||
use crate::node::wire::build_msg1;
|
||||
use crate::noise::HandshakeState;
|
||||
use crate::protocol::{SessionDatagram, SessionSetup};
|
||||
use crate::NodeAddr;
|
||||
use tracing::{debug, trace, warn};
|
||||
|
||||
/// Keep previous session alive for this long after cutover.
|
||||
@@ -69,7 +69,8 @@ impl Node {
|
||||
}
|
||||
|
||||
let elapsed = peer.session_established_at().elapsed().as_secs();
|
||||
let counter = peer.noise_session()
|
||||
let counter = peer
|
||||
.noise_session()
|
||||
.map(|s| s.current_send_counter())
|
||||
.unwrap_or(0);
|
||||
|
||||
@@ -88,9 +89,10 @@ impl Node {
|
||||
debug_assert!(
|
||||
peer.transport_id().is_some()
|
||||
&& peer.our_index().is_some()
|
||||
&& self.peers_by_index.contains_key(
|
||||
&(peer.transport_id().unwrap(), peer.our_index().unwrap().as_u32())
|
||||
),
|
||||
&& self.peers_by_index.contains_key(&(
|
||||
peer.transport_id().unwrap(),
|
||||
peer.our_index().unwrap().as_u32()
|
||||
)),
|
||||
"peers_by_index should contain pre-registered new index after cutover"
|
||||
);
|
||||
debug!(
|
||||
@@ -106,7 +108,8 @@ impl Node {
|
||||
&& let Some(old_our_index) = peer.complete_drain()
|
||||
{
|
||||
if let Some(transport_id) = peer.transport_id() {
|
||||
self.peers_by_index.remove(&(transport_id, old_our_index.as_u32()));
|
||||
self.peers_by_index
|
||||
.remove(&(transport_id, old_our_index.as_u32()));
|
||||
}
|
||||
let _ = self.index_allocator.free(old_our_index);
|
||||
trace!(
|
||||
@@ -208,7 +211,8 @@ impl Node {
|
||||
}
|
||||
|
||||
// Register in pending_outbound for msg2 dispatch (maps to existing link)
|
||||
self.pending_outbound.insert((transport_id, our_index.as_u32()), link_id);
|
||||
self.pending_outbound
|
||||
.insert((transport_id, our_index.as_u32()), link_id);
|
||||
}
|
||||
|
||||
/// Resend pending rekey msg1s and abandon timed-out rekeys.
|
||||
|
||||
+96
-48
@@ -1,11 +1,11 @@
|
||||
//! Node lifecycle management: start, stop, and peer connection initiation.
|
||||
|
||||
use super::{Node, NodeError, NodeState};
|
||||
use crate::node::wire::build_msg1;
|
||||
use crate::peer::PeerConnection;
|
||||
use crate::protocol::{Disconnect, DisconnectReason};
|
||||
use crate::transport::{packet_channel, Link, LinkDirection, LinkId, TransportAddr, TransportId};
|
||||
use crate::upper::tun::{run_tun_reader, shutdown_tun_interface, TunDevice, TunState};
|
||||
use crate::node::wire::build_msg1;
|
||||
use crate::transport::{Link, LinkDirection, LinkId, TransportAddr, TransportId, packet_channel};
|
||||
use crate::upper::tun::{TunDevice, TunState, run_tun_reader, shutdown_tun_interface};
|
||||
use crate::{NodeAddr, PeerIdentity};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
@@ -50,7 +50,10 @@ impl Node {
|
||||
return;
|
||||
}
|
||||
|
||||
debug!(count = peer_configs.len(), "Initiating static peer connections");
|
||||
debug!(
|
||||
count = peer_configs.len(),
|
||||
"Initiating static peer connections"
|
||||
);
|
||||
|
||||
for peer_config in peer_configs {
|
||||
if let Err(e) = self.initiate_peer_connection(&peer_config).await {
|
||||
@@ -67,14 +70,16 @@ impl Node {
|
||||
/// Initiate a connection to a single peer.
|
||||
///
|
||||
/// Creates a link, starts the Noise handshake, and sends the first message.
|
||||
pub(super) async fn initiate_peer_connection(&mut self, peer_config: &crate::config::PeerConfig) -> Result<(), NodeError> {
|
||||
pub(super) async fn initiate_peer_connection(
|
||||
&mut self,
|
||||
peer_config: &crate::config::PeerConfig,
|
||||
) -> Result<(), NodeError> {
|
||||
// Parse the peer's npub to get their identity
|
||||
let peer_identity = PeerIdentity::from_npub(&peer_config.npub).map_err(|e| {
|
||||
NodeError::InvalidPeerNpub {
|
||||
let peer_identity =
|
||||
PeerIdentity::from_npub(&peer_config.npub).map_err(|e| NodeError::InvalidPeerNpub {
|
||||
npub: peer_config.npub.clone(),
|
||||
reason: e.to_string(),
|
||||
}
|
||||
})?;
|
||||
})?;
|
||||
|
||||
let peer_node_addr = *peer_identity.node_addr();
|
||||
|
||||
@@ -158,7 +163,10 @@ impl Node {
|
||||
(tid, TransportAddr::from_string(&addr.addr))
|
||||
};
|
||||
|
||||
match self.initiate_connection(transport_id, remote_addr, peer_identity).await {
|
||||
match self
|
||||
.initiate_connection(transport_id, remote_addr, peer_identity)
|
||||
.await
|
||||
{
|
||||
Ok(()) => return Ok(()),
|
||||
Err(e) => {
|
||||
debug!(
|
||||
@@ -197,7 +205,9 @@ impl Node {
|
||||
) -> Result<(), NodeError> {
|
||||
let peer_node_addr = *peer_identity.node_addr();
|
||||
|
||||
let is_connection_oriented = self.transports.get(&transport_id)
|
||||
let is_connection_oriented = self
|
||||
.transports
|
||||
.get(&transport_id)
|
||||
.map(|t| t.transport_type().connection_oriented)
|
||||
.unwrap_or(false);
|
||||
|
||||
@@ -258,7 +268,8 @@ impl Node {
|
||||
Ok(())
|
||||
} else {
|
||||
// Connectionless: proceed with immediate handshake
|
||||
self.start_handshake(link_id, transport_id, remote_addr, peer_identity).await
|
||||
self.start_handshake(link_id, transport_id, remote_addr, peer_identity)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,16 +306,17 @@ impl Node {
|
||||
|
||||
// Start the Noise handshake and get message 1
|
||||
let our_keypair = self.identity.keypair();
|
||||
let noise_msg1 = match connection.start_handshake(our_keypair, self.startup_epoch, current_time_ms) {
|
||||
Ok(msg) => msg,
|
||||
Err(e) => {
|
||||
// Clean up the index and link
|
||||
let _ = self.index_allocator.free(our_index);
|
||||
self.links.remove(&link_id);
|
||||
self.addr_to_link.remove(&(transport_id, remote_addr));
|
||||
return Err(NodeError::HandshakeFailed(e.to_string()));
|
||||
}
|
||||
};
|
||||
let noise_msg1 =
|
||||
match connection.start_handshake(our_keypair, self.startup_epoch, current_time_ms) {
|
||||
Ok(msg) => msg,
|
||||
Err(e) => {
|
||||
// Clean up the index and link
|
||||
let _ = self.index_allocator.free(our_index);
|
||||
self.links.remove(&link_id);
|
||||
self.addr_to_link.remove(&(transport_id, remote_addr));
|
||||
return Err(NodeError::HandshakeFailed(e.to_string()));
|
||||
}
|
||||
};
|
||||
|
||||
// Set index and transport info on the connection
|
||||
connection.set_our_index(our_index);
|
||||
@@ -328,7 +340,8 @@ impl Node {
|
||||
connection.set_handshake_msg1(wire_msg1.clone(), current_time_ms + resend_interval);
|
||||
|
||||
// Track in pending_outbound for msg2 dispatch
|
||||
self.pending_outbound.insert((transport_id, our_index.as_u32()), link_id);
|
||||
self.pending_outbound
|
||||
.insert((transport_id, our_index.as_u32()), link_id);
|
||||
self.connections.insert(link_id, connection);
|
||||
|
||||
// Send the wire format handshake message
|
||||
@@ -419,7 +432,10 @@ impl Node {
|
||||
remote_addr = %remote_addr,
|
||||
"Auto-connecting to discovered peer"
|
||||
);
|
||||
if let Err(e) = self.initiate_connection(transport_id, remote_addr, identity).await {
|
||||
if let Err(e) = self
|
||||
.initiate_connection(transport_id, remote_addr, identity)
|
||||
.await
|
||||
{
|
||||
warn!(error = %e, "Failed to auto-connect to discovered peer");
|
||||
}
|
||||
}
|
||||
@@ -481,12 +497,15 @@ impl Node {
|
||||
);
|
||||
|
||||
// Start the handshake now that the transport is connected
|
||||
if let Err(e) = self.start_handshake(
|
||||
pending.link_id,
|
||||
pending.transport_id,
|
||||
pending.remote_addr.clone(),
|
||||
pending.peer_identity,
|
||||
).await {
|
||||
if let Err(e) = self
|
||||
.start_handshake(
|
||||
pending.link_id,
|
||||
pending.transport_id,
|
||||
pending.remote_addr.clone(),
|
||||
pending.peer_identity,
|
||||
)
|
||||
.await
|
||||
{
|
||||
warn!(
|
||||
link_id = %pending.link_id,
|
||||
error = %e,
|
||||
@@ -583,7 +602,7 @@ impl Node {
|
||||
// Calculate max MSS for TCP clamping
|
||||
let effective_mtu = self.effective_ipv6_mtu();
|
||||
let max_mss = effective_mtu.saturating_sub(40).saturating_sub(20); // IPv6 + TCP headers
|
||||
|
||||
|
||||
info!("effective MTU: {} bytes", effective_mtu);
|
||||
debug!(" max TCP MSS: {} bytes", max_mss);
|
||||
|
||||
@@ -594,11 +613,9 @@ impl Node {
|
||||
let (shutdown_read_fd, shutdown_write_fd) = {
|
||||
let mut fds = [0i32; 2];
|
||||
if unsafe { libc::pipe(fds.as_mut_ptr()) } < 0 {
|
||||
return Err(NodeError::Tun(
|
||||
crate::upper::tun::TunError::Configure(
|
||||
"failed to create shutdown pipe".into(),
|
||||
),
|
||||
));
|
||||
return Err(NodeError::Tun(crate::upper::tun::TunError::Configure(
|
||||
"failed to create shutdown pipe".into(),
|
||||
)));
|
||||
}
|
||||
(fds[0], fds[1])
|
||||
};
|
||||
@@ -622,11 +639,26 @@ impl Node {
|
||||
let transport_mtu = self.transport_mtu();
|
||||
#[cfg(target_os = "macos")]
|
||||
let reader_handle = thread::spawn(move || {
|
||||
run_tun_reader(device, mtu, our_addr, reader_tun_tx, outbound_tx, transport_mtu, shutdown_read_fd);
|
||||
run_tun_reader(
|
||||
device,
|
||||
mtu,
|
||||
our_addr,
|
||||
reader_tun_tx,
|
||||
outbound_tx,
|
||||
transport_mtu,
|
||||
shutdown_read_fd,
|
||||
);
|
||||
});
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let reader_handle = thread::spawn(move || {
|
||||
run_tun_reader(device, mtu, our_addr, reader_tun_tx, outbound_tx, transport_mtu);
|
||||
run_tun_reader(
|
||||
device,
|
||||
mtu,
|
||||
our_addr,
|
||||
reader_tun_tx,
|
||||
outbound_tx,
|
||||
transport_mtu,
|
||||
);
|
||||
});
|
||||
|
||||
self.tun_state = TunState::Active;
|
||||
@@ -636,7 +668,9 @@ impl Node {
|
||||
self.tun_reader_handle = Some(reader_handle);
|
||||
self.tun_writer_handle = Some(writer_handle);
|
||||
#[cfg(target_os = "macos")]
|
||||
{ self.tun_shutdown_fd = Some(shutdown_write_fd); }
|
||||
{
|
||||
self.tun_shutdown_fd = Some(shutdown_write_fd);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
self.tun_state = TunState::Failed;
|
||||
@@ -653,11 +687,19 @@ impl Node {
|
||||
let dns_channel_size = self.config.node.buffers.dns_channel;
|
||||
let (identity_tx, identity_rx) = tokio::sync::mpsc::channel(dns_channel_size);
|
||||
let dns_ttl = self.config.dns.ttl();
|
||||
let base_hosts = crate::upper::hosts::HostMap::from_peer_configs(self.config.peers());
|
||||
let hosts_path = std::path::PathBuf::from(crate::upper::hosts::DEFAULT_HOSTS_PATH);
|
||||
let reloader = crate::upper::hosts::HostMapReloader::new(base_hosts, hosts_path);
|
||||
let base_hosts =
|
||||
crate::upper::hosts::HostMap::from_peer_configs(self.config.peers());
|
||||
let hosts_path =
|
||||
std::path::PathBuf::from(crate::upper::hosts::DEFAULT_HOSTS_PATH);
|
||||
let reloader =
|
||||
crate::upper::hosts::HostMapReloader::new(base_hosts, hosts_path);
|
||||
info!(bind = %bind, hosts = reloader.hosts().len(), "DNS responder started for .fips domain (auto-reload enabled)");
|
||||
let handle = tokio::spawn(crate::upper::dns::run_dns_responder(socket, identity_tx, dns_ttl, reloader));
|
||||
let handle = tokio::spawn(crate::upper::dns::run_dns_responder(
|
||||
socket,
|
||||
identity_tx,
|
||||
dns_ttl,
|
||||
reloader,
|
||||
));
|
||||
self.dns_identity_rx = Some(identity_rx);
|
||||
self.dns_task = Some(handle);
|
||||
}
|
||||
@@ -693,7 +735,8 @@ impl Node {
|
||||
}
|
||||
|
||||
// Send disconnect notifications to all active peers before closing transports
|
||||
self.send_disconnect_to_all_peers(DisconnectReason::Shutdown).await;
|
||||
self.send_disconnect_to_all_peers(DisconnectReason::Shutdown)
|
||||
.await;
|
||||
|
||||
// Shutdown transports (they're packet producers)
|
||||
let transport_ids: Vec<_> = self.transports.keys().cloned().collect();
|
||||
@@ -767,7 +810,9 @@ impl Node {
|
||||
let plaintext = disconnect.encode();
|
||||
|
||||
// Collect node_addrs to avoid borrow conflict with send helper
|
||||
let peer_addrs: Vec<NodeAddr> = self.peers.iter()
|
||||
let peer_addrs: Vec<NodeAddr> = self
|
||||
.peers
|
||||
.iter()
|
||||
.filter(|(_, peer)| peer.can_send() && peer.has_session())
|
||||
.map(|(addr, _)| *addr)
|
||||
.collect();
|
||||
@@ -782,7 +827,10 @@ impl Node {
|
||||
|
||||
let mut sent = 0usize;
|
||||
for node_addr in &peer_addrs {
|
||||
match self.send_encrypted_link_message(node_addr, &plaintext).await {
|
||||
match self
|
||||
.send_encrypted_link_message(node_addr, &plaintext)
|
||||
.await
|
||||
{
|
||||
Ok(()) => sent += 1,
|
||||
Err(e) => {
|
||||
debug!(
|
||||
@@ -847,8 +895,8 @@ impl Node {
|
||||
///
|
||||
/// Removes the peer and suppresses auto-reconnect.
|
||||
pub(crate) fn api_disconnect(&mut self, npub: &str) -> Result<serde_json::Value, String> {
|
||||
let peer_identity = PeerIdentity::from_npub(npub)
|
||||
.map_err(|e| format!("invalid npub '{npub}': {e}"))?;
|
||||
let peer_identity =
|
||||
PeerIdentity::from_npub(npub).map_err(|e| format!("invalid npub '{npub}': {e}"))?;
|
||||
let node_addr = *peer_identity.node_addr();
|
||||
|
||||
if !self.peers.contains_key(&node_addr) {
|
||||
|
||||
+91
-63
@@ -5,40 +5,43 @@
|
||||
//! Bloom filters, coordinate caches, transports, links, and peers.
|
||||
|
||||
mod bloom;
|
||||
mod discovery_rate_limit;
|
||||
mod handlers;
|
||||
mod lifecycle;
|
||||
mod retry;
|
||||
mod discovery_rate_limit;
|
||||
mod rate_limit;
|
||||
mod retry;
|
||||
mod routing_error_rate_limit;
|
||||
pub(crate) mod session;
|
||||
pub(crate) mod session_wire;
|
||||
pub(crate) mod wire;
|
||||
pub(crate) mod stats;
|
||||
mod tree;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod tree;
|
||||
pub(crate) mod wire;
|
||||
|
||||
use crate::bloom::BloomState;
|
||||
use crate::cache::CoordCache;
|
||||
use crate::utils::index::IndexAllocator;
|
||||
use crate::node::session::SessionEntry;
|
||||
use crate::peer::{ActivePeer, PeerConnection};
|
||||
use self::discovery_rate_limit::{DiscoveryBackoff, DiscoveryForwardRateLimiter};
|
||||
use self::rate_limit::HandshakeRateLimiter;
|
||||
use self::routing_error_rate_limit::RoutingErrorRateLimiter;
|
||||
use self::wire::{
|
||||
FLAG_CE, FLAG_KEY_EPOCH, FLAG_SP, build_encrypted, build_established_header,
|
||||
prepend_inner_header,
|
||||
};
|
||||
use crate::bloom::BloomState;
|
||||
use crate::cache::CoordCache;
|
||||
use crate::node::session::SessionEntry;
|
||||
use crate::peer::{ActivePeer, PeerConnection};
|
||||
use crate::transport::ethernet::EthernetTransport;
|
||||
use crate::transport::tcp::TcpTransport;
|
||||
use crate::transport::tor::TorTransport;
|
||||
use crate::transport::udp::UdpTransport;
|
||||
use crate::transport::{
|
||||
Link, LinkId, PacketRx, PacketTx, TransportAddr, TransportError, TransportHandle, TransportId,
|
||||
};
|
||||
use crate::transport::udp::UdpTransport;
|
||||
use crate::transport::tcp::TcpTransport;
|
||||
use crate::transport::tor::TorTransport;
|
||||
use crate::transport::ethernet::EthernetTransport;
|
||||
use crate::tree::TreeState;
|
||||
use crate::upper::hosts::HostMap;
|
||||
use crate::upper::icmp_rate_limit::IcmpRateLimiter;
|
||||
use crate::upper::tun::{TunError, TunOutboundRx, TunState, TunTx};
|
||||
use self::wire::{build_encrypted, build_established_header, prepend_inner_header, FLAG_CE, FLAG_KEY_EPOCH, FLAG_SP};
|
||||
use crate::utils::index::IndexAllocator;
|
||||
use crate::{Config, ConfigError, Identity, IdentityError, NodeAddr, PeerIdentity};
|
||||
use rand::Rng;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
@@ -105,7 +108,11 @@ pub enum NodeError {
|
||||
SendFailed { node_addr: NodeAddr, reason: String },
|
||||
|
||||
#[error("mtu exceeded forwarding to {node_addr}: packet {packet_size} > mtu {mtu}")]
|
||||
MtuExceeded { node_addr: NodeAddr, packet_size: usize, mtu: u16 },
|
||||
MtuExceeded {
|
||||
node_addr: NodeAddr,
|
||||
packet_size: usize,
|
||||
mtu: u16,
|
||||
},
|
||||
|
||||
#[error("config error: {0}")]
|
||||
Config(#[from] ConfigError),
|
||||
@@ -546,10 +553,7 @@ impl Node {
|
||||
coords_response_rate_limiter: RoutingErrorRateLimiter::with_interval(
|
||||
std::time::Duration::from_millis(coords_response_interval_ms),
|
||||
),
|
||||
discovery_backoff: DiscoveryBackoff::with_params(
|
||||
backoff_base_secs,
|
||||
backoff_max_secs,
|
||||
),
|
||||
discovery_backoff: DiscoveryBackoff::with_params(backoff_base_secs, backoff_max_secs),
|
||||
discovery_forward_limiter: DiscoveryForwardRateLimiter::with_interval(
|
||||
std::time::Duration::from_secs(forward_min_interval_secs),
|
||||
),
|
||||
@@ -784,7 +788,9 @@ impl Node {
|
||||
#[cfg(any(not(feature = "ble"), test))]
|
||||
if !ble_instances.is_empty() {
|
||||
#[cfg(not(test))]
|
||||
tracing::warn!("BLE transport configured but 'ble' feature not enabled at compile time");
|
||||
tracing::warn!(
|
||||
"BLE transport configured but 'ble' feature not enabled at compile time"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -845,13 +851,9 @@ impl Node {
|
||||
/// (TransportId, TransportAddr) pair by finding the BLE transport
|
||||
/// instance matching the adapter name.
|
||||
#[cfg(target_os = "linux")]
|
||||
fn resolve_ble_addr(
|
||||
&self,
|
||||
addr_str: &str,
|
||||
) -> Result<(TransportId, TransportAddr), NodeError> {
|
||||
fn resolve_ble_addr(&self, addr_str: &str) -> Result<(TransportId, TransportAddr), NodeError> {
|
||||
let ta = TransportAddr::from_string(addr_str);
|
||||
let adapter = crate::transport::ble::addr::adapter_from_addr(&ta)
|
||||
.ok_or_else(|| {
|
||||
let adapter = crate::transport::ble::addr::adapter_from_addr(&ta).ok_or_else(|| {
|
||||
NodeError::NoTransportForType(format!(
|
||||
"invalid BLE address format '{}': expected 'adapter/mac'",
|
||||
addr_str
|
||||
@@ -862,9 +864,7 @@ impl Node {
|
||||
let transport_id = self
|
||||
.transports
|
||||
.iter()
|
||||
.find(|(_, handle)| {
|
||||
handle.transport_type().name == "ble" && handle.is_operational()
|
||||
})
|
||||
.find(|(_, handle)| handle.transport_type().name == "ble" && handle.is_operational())
|
||||
.map(|(id, _)| *id)
|
||||
.ok_or_else(|| {
|
||||
NodeError::NoTransportForType(format!(
|
||||
@@ -1060,9 +1060,10 @@ impl Node {
|
||||
let now = std::time::Instant::now();
|
||||
let should_log = match self.last_mesh_size_log {
|
||||
None => true,
|
||||
Some(last) => now.duration_since(last) >= std::time::Duration::from_secs(
|
||||
self.config.node.mmp.log_interval_secs,
|
||||
),
|
||||
Some(last) => {
|
||||
now.duration_since(last)
|
||||
>= std::time::Duration::from_secs(self.config.node.mmp.log_interval_secs)
|
||||
}
|
||||
};
|
||||
if should_log {
|
||||
tracing::debug!(
|
||||
@@ -1111,7 +1112,6 @@ impl Node {
|
||||
self.tun_name.as_deref()
|
||||
}
|
||||
|
||||
|
||||
// === Resource Limits ===
|
||||
|
||||
/// Set the maximum number of connections (handshake phase).
|
||||
@@ -1192,14 +1192,17 @@ impl Node {
|
||||
/// Add a link.
|
||||
pub fn add_link(&mut self, link: Link) -> Result<(), NodeError> {
|
||||
if self.max_links > 0 && self.links.len() >= self.max_links {
|
||||
return Err(NodeError::MaxLinksExceeded { max: self.max_links });
|
||||
return Err(NodeError::MaxLinksExceeded {
|
||||
max: self.max_links,
|
||||
});
|
||||
}
|
||||
let link_id = link.link_id();
|
||||
let transport_id = link.transport_id();
|
||||
let remote_addr = link.remote_addr().clone();
|
||||
|
||||
self.links.insert(link_id, link);
|
||||
self.addr_to_link.insert((transport_id, remote_addr), link_id);
|
||||
self.addr_to_link
|
||||
.insert((transport_id, remote_addr), link_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1214,8 +1217,14 @@ impl Node {
|
||||
}
|
||||
|
||||
/// Find link ID by transport address.
|
||||
pub fn find_link_by_addr(&self, transport_id: TransportId, addr: &TransportAddr) -> Option<LinkId> {
|
||||
self.addr_to_link.get(&(transport_id, addr.clone())).copied()
|
||||
pub fn find_link_by_addr(
|
||||
&self,
|
||||
transport_id: TransportId,
|
||||
addr: &TransportAddr,
|
||||
) -> Option<LinkId> {
|
||||
self.addr_to_link
|
||||
.get(&(transport_id, addr.clone()))
|
||||
.copied()
|
||||
}
|
||||
|
||||
/// Remove a link.
|
||||
@@ -1361,11 +1370,14 @@ impl Node {
|
||||
pub(crate) fn register_identity(&mut self, node_addr: NodeAddr, pubkey: secp256k1::PublicKey) {
|
||||
let mut prefix = [0u8; 15];
|
||||
prefix.copy_from_slice(&node_addr.as_bytes()[0..15]);
|
||||
self.identity_cache.insert(prefix, (node_addr, pubkey, Self::now_ms()));
|
||||
self.identity_cache
|
||||
.insert(prefix, (node_addr, pubkey, Self::now_ms()));
|
||||
// LRU eviction
|
||||
let max = self.config.node.cache.identity_size;
|
||||
if self.identity_cache.len() > max
|
||||
&& let Some(oldest_key) = self.identity_cache.iter()
|
||||
&& let Some(oldest_key) = self
|
||||
.identity_cache
|
||||
.iter()
|
||||
.min_by_key(|(_, (_, _, ts))| *ts)
|
||||
.map(|(k, _)| *k)
|
||||
{
|
||||
@@ -1374,7 +1386,10 @@ impl Node {
|
||||
}
|
||||
|
||||
/// Look up a destination by FipsAddress prefix (bytes 1-15 of the IPv6 address).
|
||||
pub(crate) fn lookup_by_fips_prefix(&mut self, prefix: &[u8; 15]) -> Option<(NodeAddr, secp256k1::PublicKey)> {
|
||||
pub(crate) fn lookup_by_fips_prefix(
|
||||
&mut self,
|
||||
prefix: &[u8; 15],
|
||||
) -> Option<(NodeAddr, secp256k1::PublicKey)> {
|
||||
if let Some(entry) = self.identity_cache.get_mut(prefix) {
|
||||
entry.2 = Self::now_ms(); // LRU touch
|
||||
Some((entry.0, entry.1))
|
||||
@@ -1413,9 +1428,7 @@ impl Node {
|
||||
/// has declared us as their parent (making them our child).
|
||||
pub(crate) fn is_tree_peer(&self, peer_addr: &NodeAddr) -> bool {
|
||||
// Peer is our parent
|
||||
if !self.tree_state.is_root()
|
||||
&& self.tree_state.my_declaration().parent_id() == peer_addr
|
||||
{
|
||||
if !self.tree_state.is_root() && self.tree_state.my_declaration().parent_id() == peer_addr {
|
||||
return true;
|
||||
}
|
||||
// Peer is our child (their declaration names us as parent)
|
||||
@@ -1464,7 +1477,10 @@ impl Node {
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|d| d.as_millis() as u64)
|
||||
.unwrap_or(0);
|
||||
let dest_coords = self.coord_cache.get_and_touch(dest_node_addr, now_ms)?.clone();
|
||||
let dest_coords = self
|
||||
.coord_cache
|
||||
.get_and_touch(dest_node_addr, now_ms)?
|
||||
.clone();
|
||||
|
||||
// 3. Bloom filter candidates — requires dest_coords for loop-free selection.
|
||||
// If no candidate is strictly closer, fall through to tree routing.
|
||||
@@ -1566,7 +1582,8 @@ impl Node {
|
||||
node_addr: &NodeAddr,
|
||||
plaintext: &[u8],
|
||||
) -> Result<(), NodeError> {
|
||||
self.send_encrypted_link_message_with_ce(node_addr, plaintext, false).await
|
||||
self.send_encrypted_link_message_with_ce(node_addr, plaintext, false)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Like `send_encrypted_link_message` but allows setting the FMP CE flag.
|
||||
@@ -1578,7 +1595,9 @@ impl Node {
|
||||
plaintext: &[u8],
|
||||
ce_flag: bool,
|
||||
) -> Result<(), NodeError> {
|
||||
let peer = self.peers.get_mut(node_addr)
|
||||
let peer = self
|
||||
.peers
|
||||
.get_mut(node_addr)
|
||||
.ok_or(NodeError::PeerNotFound(*node_addr))?;
|
||||
|
||||
let their_index = peer.their_index().ok_or_else(|| NodeError::SendFailed {
|
||||
@@ -1589,18 +1608,19 @@ impl Node {
|
||||
node_addr: *node_addr,
|
||||
reason: "no transport_id".into(),
|
||||
})?;
|
||||
let remote_addr = peer.current_addr().cloned().ok_or_else(|| NodeError::SendFailed {
|
||||
node_addr: *node_addr,
|
||||
reason: "no current_addr".into(),
|
||||
})?;
|
||||
let remote_addr = peer
|
||||
.current_addr()
|
||||
.cloned()
|
||||
.ok_or_else(|| NodeError::SendFailed {
|
||||
node_addr: *node_addr,
|
||||
reason: "no current_addr".into(),
|
||||
})?;
|
||||
|
||||
// Prepend 4-byte session-relative timestamp (inner header)
|
||||
let timestamp_ms = peer.session_elapsed_ms();
|
||||
|
||||
// MMP: read spin bit value before entering session borrow
|
||||
let sp_flag = peer.mmp()
|
||||
.map(|mmp| mmp.spin_bit.tx_bit())
|
||||
.unwrap_or(false);
|
||||
let sp_flag = peer.mmp().map(|mmp| mmp.spin_bit.tx_bit()).unwrap_or(false);
|
||||
let mut flags = if sp_flag { FLAG_SP } else { 0 };
|
||||
if ce_flag {
|
||||
flags |= FLAG_CE;
|
||||
@@ -1609,10 +1629,12 @@ impl Node {
|
||||
flags |= FLAG_KEY_EPOCH;
|
||||
}
|
||||
|
||||
let session = peer.noise_session_mut().ok_or_else(|| NodeError::SendFailed {
|
||||
node_addr: *node_addr,
|
||||
reason: "no noise session".into(),
|
||||
})?;
|
||||
let session = peer
|
||||
.noise_session_mut()
|
||||
.ok_or_else(|| NodeError::SendFailed {
|
||||
node_addr: *node_addr,
|
||||
reason: "no noise session".into(),
|
||||
})?;
|
||||
|
||||
// Inner plaintext: [timestamp:4 LE][msg_type][payload...]
|
||||
let inner_plaintext = prepend_inner_header(timestamp_ms, plaintext);
|
||||
@@ -1623,18 +1645,24 @@ impl Node {
|
||||
let header = build_established_header(their_index, counter, flags, payload_len);
|
||||
|
||||
// Encrypt with AAD binding to the outer header
|
||||
let ciphertext = session.encrypt_with_aad(&inner_plaintext, &header).map_err(|e| NodeError::SendFailed {
|
||||
node_addr: *node_addr,
|
||||
reason: format!("encryption failed: {}", e),
|
||||
})?;
|
||||
let ciphertext = session
|
||||
.encrypt_with_aad(&inner_plaintext, &header)
|
||||
.map_err(|e| NodeError::SendFailed {
|
||||
node_addr: *node_addr,
|
||||
reason: format!("encryption failed: {}", e),
|
||||
})?;
|
||||
|
||||
let wire_packet = build_encrypted(&header, &ciphertext);
|
||||
|
||||
// Re-borrow peer for stats update after sending
|
||||
let transport = self.transports.get(&transport_id)
|
||||
let transport = self
|
||||
.transports
|
||||
.get(&transport_id)
|
||||
.ok_or(NodeError::TransportNotFound(transport_id))?;
|
||||
|
||||
let bytes_sent = transport.send(&remote_addr, &wire_packet).await
|
||||
let bytes_sent = transport
|
||||
.send(&remote_addr, &wire_packet)
|
||||
.await
|
||||
.map_err(|e| match e {
|
||||
TransportError::MtuExceeded { packet_size, mtu } => NodeError::MtuExceeded {
|
||||
node_addr: *node_addr,
|
||||
|
||||
@@ -284,7 +284,14 @@ mod tests {
|
||||
let hi = (expected * 1.2).max(expected + 0.5).min(10.0);
|
||||
|
||||
let tokens = bucket.tokens();
|
||||
assert!((lo..=hi).contains(&tokens), "tokens: {}, expected ~{:.2} (range {:.2}..={:.2})", tokens, expected, lo, hi);
|
||||
assert!(
|
||||
(lo..=hi).contains(&tokens),
|
||||
"tokens: {}, expected ~{:.2} (range {:.2}..={:.2})",
|
||||
tokens,
|
||||
expected,
|
||||
lo,
|
||||
hi
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+26
-9
@@ -6,12 +6,12 @@
|
||||
|
||||
use super::*;
|
||||
use crate::config::BleConfig;
|
||||
use crate::transport::ble::BleTransport;
|
||||
use crate::transport::ble::addr::BleAddr;
|
||||
use crate::transport::ble::io::{MockBleIo, MockBleStream};
|
||||
use crate::transport::ble::BleTransport;
|
||||
use crate::transport::{packet_channel, Transport, TransportHandle, TransportId};
|
||||
use crate::transport::{Transport, TransportHandle, TransportId, packet_channel};
|
||||
use spanning_tree::{
|
||||
cleanup_nodes, drain_all_packets, initiate_handshake, verify_tree_convergence, TestNode,
|
||||
TestNode, cleanup_nodes, drain_all_packets, initiate_handshake, verify_tree_convergence,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex as StdMutex};
|
||||
@@ -44,8 +44,8 @@ async fn make_test_node_ble(node_num: u8) -> TestNode {
|
||||
adapter: Some("hci0".to_string()),
|
||||
mtu: Some(2048),
|
||||
accept_connections: Some(true),
|
||||
scan: Some(false), // no auto-scan in tests
|
||||
advertise: Some(false), // no advertising in tests
|
||||
scan: Some(false), // no auto-scan in tests
|
||||
advertise: Some(false), // no advertising in tests
|
||||
auto_connect: Some(false),
|
||||
..Default::default()
|
||||
};
|
||||
@@ -91,7 +91,11 @@ async fn wire_ble_connection(nodes: &[TestNode], i: usize, j: usize, bank: &Stre
|
||||
bank.lock().unwrap().insert(key, stream_i);
|
||||
|
||||
// Inject stream_j into node j's accept loop so it sees the inbound.
|
||||
let transport_j = nodes[j].node.transports.get(&nodes[j].transport_id).unwrap();
|
||||
let transport_j = nodes[j]
|
||||
.node
|
||||
.transports
|
||||
.get(&nodes[j].transport_id)
|
||||
.unwrap();
|
||||
match transport_j {
|
||||
TransportHandle::Ble(t) => {
|
||||
t.io().inject_inbound(stream_j).await;
|
||||
@@ -103,7 +107,11 @@ async fn wire_ble_connection(nodes: &[TestNode], i: usize, j: usize, bank: &Stre
|
||||
/// Install a connect handler on node `i` that draws from the stream bank.
|
||||
fn install_connect_handler(nodes: &[TestNode], i: usize, bank: &StreamBank) {
|
||||
let bank = Arc::clone(bank);
|
||||
let transport_i = nodes[i].node.transports.get(&nodes[i].transport_id).unwrap();
|
||||
let transport_i = nodes[i]
|
||||
.node
|
||||
.transports
|
||||
.get(&nodes[i].transport_id)
|
||||
.unwrap();
|
||||
match transport_i {
|
||||
TransportHandle::Ble(t) => {
|
||||
t.io().set_connect_handler(move |addr, _psm| {
|
||||
@@ -125,7 +133,11 @@ fn install_connect_handler(nodes: &[TestNode], i: usize, bank: &StreamBank) {
|
||||
/// BLE send_async fails fast if no connection exists, so connections must
|
||||
/// be pre-established before initiating handshakes.
|
||||
async fn establish_ble_connection(nodes: &[TestNode], i: usize, j: usize) {
|
||||
let transport = nodes[i].node.transports.get(&nodes[i].transport_id).unwrap();
|
||||
let transport = nodes[i]
|
||||
.node
|
||||
.transports
|
||||
.get(&nodes[i].transport_id)
|
||||
.unwrap();
|
||||
transport.connect(&nodes[j].addr).await.unwrap();
|
||||
// Let the background connect task complete
|
||||
tokio::task::yield_now().await;
|
||||
@@ -288,6 +300,11 @@ async fn test_ble_discovery() {
|
||||
node.transports
|
||||
.insert(transport_id, TransportHandle::Ble(transport));
|
||||
|
||||
let mut nodes = vec![TestNode { node, transport_id, packet_rx, addr: ta }];
|
||||
let mut nodes = vec![TestNode {
|
||||
node,
|
||||
transport_id,
|
||||
packet_rx,
|
||||
addr: ta,
|
||||
}];
|
||||
cleanup_nodes(&mut nodes).await;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ use crate::transport::{LinkDirection, TransportAddr, packet_channel};
|
||||
use crate::utils::index::SessionIndex;
|
||||
use std::time::Duration;
|
||||
|
||||
mod bloom;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod ble;
|
||||
mod bloom;
|
||||
mod disconnect;
|
||||
mod discovery;
|
||||
mod ethernet;
|
||||
|
||||
Reference in New Issue
Block a user