refactor: centralize peer control routing
This commit is contained in:
parent
d443b82f1a
commit
a32cab645f
4 changed files with 218 additions and 126 deletions
|
|
@ -3,6 +3,7 @@ mod daemon;
|
|||
pub mod doctor;
|
||||
mod local_control;
|
||||
mod peer_client;
|
||||
mod peer_control;
|
||||
mod resource_contracts;
|
||||
mod runtime;
|
||||
pub mod service;
|
||||
|
|
@ -68,6 +69,10 @@ use iroh::protocol::ProtocolHandler;
|
|||
use iroh_docs::api::protocol::{AddrInfoOptions, ShareMode};
|
||||
pub use local_control::handle_request_async;
|
||||
use peer_client::{request_overlay_wire, request_peer_control, request_pipe_wire};
|
||||
use peer_control::{
|
||||
IrohAlpnRoute, PeerControlCaller, authenticate_peer_control_caller, classify_iroh_alpn,
|
||||
display_alpn, ensure_peer_card_matches_endpoint, iroh_node_addr_from_candidate,
|
||||
};
|
||||
use runtime::{
|
||||
NodeRuntime, OverlayTunCounters, OverlayTunRuntime, PipeRuntime, PubsubGossipTopicRuntime,
|
||||
PubsubRuntime,
|
||||
|
|
@ -223,12 +228,6 @@ struct PipeUnixConnectWire {
|
|||
bearer_proof: Option<BearerProof>,
|
||||
}
|
||||
|
||||
struct PeerControlCaller {
|
||||
peer_card: PeerCard,
|
||||
remote_endpoint_id: String,
|
||||
store: Store,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct InitOwnerOptions {
|
||||
pub admin_key_path: Option<PathBuf>,
|
||||
|
|
@ -4064,41 +4063,48 @@ async fn handle_iroh_control_connection(
|
|||
.await
|
||||
.map_err(|error| NodeError::IrohPeer(error.to_string()))?;
|
||||
let remote_endpoint_id = conn.remote_id().to_string();
|
||||
let route = classify_iroh_alpn(conn.alpn());
|
||||
let alpn = display_alpn(conn.alpn());
|
||||
let log_remote_endpoint_id = remote_endpoint_id.clone();
|
||||
let log_alpn = alpn.clone();
|
||||
tracing::debug!(remote_endpoint_id = %log_remote_endpoint_id, alpn = %log_alpn, "iroh connection established");
|
||||
if alpn == display_alpn(iroh_blobs::ALPN) {
|
||||
let blob_store = iroh_blob_store(&node)?.ok_or_else(|| {
|
||||
NodeError::IrohPeer("iroh-blobs ALPN accepted but blob store is unavailable".to_owned())
|
||||
})?;
|
||||
let protocol = iroh_blobs::BlobsProtocol::new(&blob_store, None);
|
||||
return protocol
|
||||
.accept(conn)
|
||||
.await
|
||||
.map_err(|error| NodeError::IrohPeer(format!("iroh-blobs accept failed: {error}")));
|
||||
}
|
||||
if alpn == display_alpn(iroh_docs::ALPN) {
|
||||
let docs = iroh_docs(&node)?.ok_or_else(|| {
|
||||
NodeError::IrohPeer(
|
||||
"iroh-docs ALPN accepted but docs runtime is unavailable".to_owned(),
|
||||
)
|
||||
})?;
|
||||
return docs
|
||||
.accept(conn)
|
||||
.await
|
||||
.map_err(|error| NodeError::IrohPeer(format!("iroh-docs accept failed: {error}")));
|
||||
}
|
||||
if alpn == display_alpn(iroh_gossip::ALPN) {
|
||||
let gossip = iroh_gossip(&node)?.ok_or_else(|| {
|
||||
NodeError::IrohPeer(
|
||||
"iroh-gossip ALPN accepted but gossip runtime is unavailable".to_owned(),
|
||||
)
|
||||
})?;
|
||||
return gossip
|
||||
.accept(conn)
|
||||
.await
|
||||
.map_err(|error| NodeError::IrohPeer(format!("iroh-gossip accept failed: {error}")));
|
||||
match route {
|
||||
IrohAlpnRoute::NativeBlobs => {
|
||||
let blob_store = iroh_blob_store(&node)?.ok_or_else(|| {
|
||||
NodeError::IrohPeer(
|
||||
"iroh-blobs ALPN accepted but blob store is unavailable".to_owned(),
|
||||
)
|
||||
})?;
|
||||
let protocol = iroh_blobs::BlobsProtocol::new(&blob_store, None);
|
||||
return protocol.accept(conn).await.map_err(|error| {
|
||||
NodeError::IrohPeer(format!("iroh-blobs accept failed: {error}"))
|
||||
});
|
||||
}
|
||||
IrohAlpnRoute::NativeDocs => {
|
||||
let docs = iroh_docs(&node)?.ok_or_else(|| {
|
||||
NodeError::IrohPeer(
|
||||
"iroh-docs ALPN accepted but docs runtime is unavailable".to_owned(),
|
||||
)
|
||||
})?;
|
||||
return docs
|
||||
.accept(conn)
|
||||
.await
|
||||
.map_err(|error| NodeError::IrohPeer(format!("iroh-docs accept failed: {error}")));
|
||||
}
|
||||
IrohAlpnRoute::NativeGossip => {
|
||||
let gossip = iroh_gossip(&node)?.ok_or_else(|| {
|
||||
NodeError::IrohPeer(
|
||||
"iroh-gossip ALPN accepted but gossip runtime is unavailable".to_owned(),
|
||||
)
|
||||
})?;
|
||||
return gossip.accept(conn).await.map_err(|error| {
|
||||
NodeError::IrohPeer(format!("iroh-gossip accept failed: {error}"))
|
||||
});
|
||||
}
|
||||
IrohAlpnRoute::SshProxy
|
||||
| IrohAlpnRoute::Pipe
|
||||
| IrohAlpnRoute::Overlay
|
||||
| IrohAlpnRoute::Control => {}
|
||||
}
|
||||
tracing::debug!(%remote_endpoint_id, %alpn, "waiting for iroh bidirectional stream");
|
||||
let (mut send, recv) = conn
|
||||
|
|
@ -4106,14 +4112,20 @@ async fn handle_iroh_control_connection(
|
|||
.await
|
||||
.map_err(|error| NodeError::IrohPeer(error.to_string()))?;
|
||||
tracing::debug!(%remote_endpoint_id, %alpn, "accepted iroh bidirectional stream");
|
||||
if alpn == display_alpn(geth_iroh::ALPN_SSH_PROXY) {
|
||||
return handle_ssh_proxy_wire_connection(node, remote_endpoint_id, send, recv).await;
|
||||
}
|
||||
if alpn == display_alpn(geth_iroh::ALPN_PIPE) {
|
||||
return handle_pipe_wire_connection(node, remote_endpoint_id, send, recv).await;
|
||||
}
|
||||
if alpn == display_alpn(geth_iroh::ALPN_OVERLAY) {
|
||||
return handle_overlay_wire_connection(node, remote_endpoint_id, send, recv).await;
|
||||
match route {
|
||||
IrohAlpnRoute::SshProxy => {
|
||||
return handle_ssh_proxy_wire_connection(node, remote_endpoint_id, send, recv).await;
|
||||
}
|
||||
IrohAlpnRoute::Pipe => {
|
||||
return handle_pipe_wire_connection(node, remote_endpoint_id, send, recv).await;
|
||||
}
|
||||
IrohAlpnRoute::Overlay => {
|
||||
return handle_overlay_wire_connection(node, remote_endpoint_id, send, recv).await;
|
||||
}
|
||||
IrohAlpnRoute::Control => {}
|
||||
IrohAlpnRoute::NativeBlobs | IrohAlpnRoute::NativeDocs | IrohAlpnRoute::NativeGossip => {
|
||||
unreachable!("native ALPN routes return before bidirectional stream handling")
|
||||
}
|
||||
}
|
||||
let mut recv = recv;
|
||||
let request_line = read_iroh_line(&mut recv, PEER_CONTROL_LINE_MAX).await?;
|
||||
|
|
@ -5470,75 +5482,6 @@ async fn handle_pipe_unix_wire_connection(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn iroh_node_addr_from_candidate(
|
||||
candidate: &EndpointCandidate,
|
||||
) -> Result<iroh::EndpointAddr, NodeError> {
|
||||
let endpoint_id = candidate
|
||||
.endpoint_id
|
||||
.parse::<iroh::EndpointId>()
|
||||
.map_err(|error| NodeError::IrohPeer(error.to_string()))?;
|
||||
let direct_addresses = candidate
|
||||
.direct_addresses
|
||||
.iter()
|
||||
.map(|addr| {
|
||||
addr.parse::<std::net::SocketAddr>()
|
||||
.map_err(|error| NodeError::IrohPeer(error.to_string()))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let mut node_addr = iroh::EndpointAddr::new(endpoint_id);
|
||||
for address in direct_addresses {
|
||||
node_addr = node_addr.with_ip_addr(address);
|
||||
}
|
||||
if let Some(relay_url) = &candidate.relay_url {
|
||||
node_addr = node_addr.with_relay_url(
|
||||
relay_url
|
||||
.parse::<iroh::RelayUrl>()
|
||||
.map_err(|error| NodeError::IrohPeer(error.to_string()))?,
|
||||
);
|
||||
}
|
||||
Ok(node_addr)
|
||||
}
|
||||
|
||||
fn ensure_peer_card_matches_endpoint(card: &PeerCard, endpoint_id: &str) -> Result<(), NodeError> {
|
||||
if card
|
||||
.endpoints
|
||||
.iter()
|
||||
.any(|candidate| candidate.endpoint_id == endpoint_id)
|
||||
{
|
||||
Ok(())
|
||||
} else {
|
||||
Err(NodeError::IrohPeer(format!(
|
||||
"signed peer card for {} does not bind Iroh endpoint {}",
|
||||
card.node_id, endpoint_id
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
fn authenticate_peer_control_caller(
|
||||
node: &LocalNode,
|
||||
peer_card: PeerCard,
|
||||
remote_endpoint_id: &str,
|
||||
) -> Result<PeerControlCaller, NodeError> {
|
||||
peer_card.validate_candidate()?;
|
||||
ensure_peer_card_matches_endpoint(&peer_card, remote_endpoint_id)?;
|
||||
let discovered = DiscoveredPeer::candidate(
|
||||
peer_card.clone(),
|
||||
UnixMillis(geth_store::now_ms()),
|
||||
DiscoverySource::PeerExchange,
|
||||
)?;
|
||||
let store = Store::open(&node.paths.metadata_db())?;
|
||||
store.upsert_peer_card(&StoredPeerCard {
|
||||
peer_id: peer_card.node_id.to_string(),
|
||||
card_json: serde_json::to_string(&peer_card)?,
|
||||
updated_at_ms: discovered.discovered_at.0,
|
||||
})?;
|
||||
Ok(PeerControlCaller {
|
||||
peer_card,
|
||||
remote_endpoint_id: remote_endpoint_id.to_owned(),
|
||||
store,
|
||||
})
|
||||
}
|
||||
|
||||
fn peer_gossip_endpoint_id(
|
||||
node: &LocalNode,
|
||||
peer_node: &str,
|
||||
|
|
@ -5581,10 +5524,6 @@ fn restricted_admin_shell_output(node: &LocalNode, command: &str) -> Result<Stri
|
|||
}
|
||||
}
|
||||
|
||||
fn display_alpn(alpn: &[u8]) -> String {
|
||||
String::from_utf8_lossy(alpn).into_owned()
|
||||
}
|
||||
|
||||
pub fn handle_request(
|
||||
node: &LocalNode,
|
||||
request: ControlRequest,
|
||||
|
|
|
|||
Loading…
Reference in a new issue