-
Notifications
You must be signed in to change notification settings - Fork 293
feat(iroh): add initial scaffolding for WebRTC support #3440
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat(iroh): add initial scaffolding for WebRTC support #3440
Conversation
We're discussing this in the iroh discord: https://discord.com/channels/1161119546170687619/1406897550140772393 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've had a quick scroll through and noticed a bunch of println
s and commented out code still. Could you add a note on what the stated of completion of the PR is, what the first round of review should pay attention to?
This PR is still in progress - I’ll clean up the println! statements and remove the commented-out code before finalizing. For the first round of review, I’d like you to mainly focus on whether I am correctly sending the WebRTC offer/ICE candidate from one node to another. Current flow Node A is spawned. Node B connects. Node B uses discovery to send a ping . I refactored the message-sending logic so that send_ping now also carries WebRTC ICE candidate information. Points where I need guidance
For now you can ignore webrtc actor (peer connection state ) as it needs to be changed |
/// Socket addresses where the peer might be reached directly. | ||
pub direct_addresses: BTreeSet<SocketAddr>, | ||
/// Static Webrtc connection information for the node | ||
pub webrtc_info: Option<WebRtcInfo>, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding:
NodeAddr is used by the discovery system to locate nodes in the network. For discovery purposes, we only need the node_id to find a node. Once found, WebRTC connections are established through the standard offer/answer exchange process.
My concern:
Since WebRTC connections require dynamic offer/answer negotiation anyway, is it necessary to store static WebRTC information like channel_id and webrtc_info (certificate fingerprints) here?
iroh-base/src/webrtc_port.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this file to uniquely identify the webrtc connection on the node locally. We need to decide if this correct.
iroh-base/Cargo.toml
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file can be ignored for now
@@ -224,7 +224,7 @@ impl From<NodeAddr> for NodeData { | |||
/// `UserData` implements [`FromStr`] and [`TryFrom<String>`], so you can | |||
/// convert `&str` and `String` into `UserData` easily. | |||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] | |||
pub struct UserData(String); | |||
pub struct UserData(pub String); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs to revert it back. It was a quick fix for compilation erros. #3250
@@ -587,6 +620,7 @@ impl NodeState { | |||
// direct address paths to contact but no RelayUrl, we still need to send a DISCO | |||
// ping to the direct address paths so that the other node will learn about us and | |||
// accepts the connection. | |||
println!("----------- 625"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs to revert it back. #3250
@@ -115,6 +117,7 @@ pub(super) struct NodeState { | |||
/// | |||
/// The fallback/bootstrap path, if non-zero (non-zero for well-behaved clients). | |||
relay_url: Option<(RelayUrl, PathState)>, | |||
webrtc_channel: Option<(ChannelId, PathState)>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is incorrect. I need more intuition on what node state , what to put it here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can ignore this file for now
@@ -55,6 +56,7 @@ pub(super) struct NodeMap { | |||
pub(super) struct NodeMapInner { | |||
by_node_key: HashMap<NodeId, usize>, | |||
by_ip_port: HashMap<IpPort, usize>, | |||
by_webrtc_port: HashMap<WebRtcPort, usize>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also need guidance on this part. If this is correct or needs changes
iroh/src/endpoint.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can ignore this file for now
} | ||
} | ||
} | ||
disco::Message::WebRtcIceCandidate(ice) => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we use this file, we can see the offer being received at this point.
iroh/src/magicsock.rs
Outdated
// the packet if grease_quic_bit is set to false. | ||
endpoint_config.grease_quic_bit(false); | ||
|
||
let sender = transports.create_sender(msock.clone()); | ||
let local_addrs_watch = transports.local_addrs_watch(); | ||
let network_change_sender = transports.create_network_change_sender(); | ||
|
||
let endpoint = quinn::Endpoint::new_with_abstract_socket( | ||
endpoint_config, | ||
Some(server_config), | ||
Box::new(MagicUdpSocket { | ||
socket: msock.clone(), | ||
transports, | ||
}), | ||
#[cfg(not(wasm_browser))] | ||
Arc::new(quinn::TokioRuntime), | ||
#[cfg(wasm_browser)] | ||
Arc::new(crate::web_runtime::WebRuntime), | ||
) | ||
.context(CreateQuinnEndpointSnafu)?; | ||
|
||
let network_monitor = netmon::Monitor::new() | ||
.await | ||
.context(CreateNetmonMonitorSnafu)?; | ||
|
||
let qad_endpoint = endpoint.clone(); | ||
|
||
#[cfg(any(test, feature = "test-utils"))] | ||
let client_config = if insecure_skip_relay_cert_verify { | ||
iroh_relay::client::make_dangerous_client_config() | ||
} else { | ||
default_quic_client_config() | ||
}; | ||
#[cfg(not(any(test, feature = "test-utils")))] | ||
let client_config = default_quic_client_config(); | ||
|
||
let net_report_config = net_report::Options::default(); | ||
#[cfg(not(wasm_browser))] | ||
let net_report_config = net_report_config.quic_config(Some(QuicConfig { | ||
ep: qad_endpoint, | ||
client_config, | ||
ipv4: true, | ||
ipv6, | ||
})); | ||
|
||
#[cfg(any(test, feature = "test-utils"))] | ||
let net_report_config = | ||
net_report_config.insecure_skip_relay_cert_verify(insecure_skip_relay_cert_verify); | ||
|
||
let net_reporter = net_report::Client::new( | ||
#[cfg(not(wasm_browser))] | ||
dns_resolver, | ||
#[cfg(not(wasm_browser))] | ||
Some(ip_mapped_addrs), | ||
relay_map.clone(), | ||
net_report_config, | ||
metrics.net_report.clone(), | ||
); | ||
|
||
let (direct_addr_done_tx, direct_addr_done_rx) = mpsc::channel(8); | ||
let direct_addr_update_state = DirectAddrUpdateState::new( | ||
msock.clone(), | ||
#[cfg(not(wasm_browser))] | ||
port_mapper, | ||
Arc::new(AsyncMutex::new(net_reporter)), | ||
relay_map, | ||
direct_addr_done_tx, | ||
); | ||
|
||
let netmon_watcher = network_monitor.interface_state(); | ||
let actor = Actor { | ||
msg_receiver: actor_receiver, | ||
msock: msock.clone(), | ||
periodic_re_stun_timer: new_re_stun_timer(false), | ||
network_monitor, | ||
netmon_watcher, | ||
direct_addr_update_state, | ||
network_change_sender, | ||
direct_addr_done_rx, | ||
pending_call_me_maybes: Default::default(), | ||
disco_receiver, | ||
}; | ||
|
||
let actor_token = CancellationToken::new(); | ||
let token = actor_token.clone(); | ||
let actor_task = task::spawn( | ||
actor | ||
.run(token, local_addrs_watch, sender) | ||
.instrument(info_span!("actor")), | ||
); | ||
|
||
let actor_task = Arc::new(Mutex::new(Some(AbortOnDropHandle::new(actor_task)))); | ||
|
||
Ok(Handle { | ||
msock, | ||
actor_task, | ||
endpoint, | ||
actor_token, | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can ignore this part for now
iroh/src/magicsock.rs
Outdated
let network_change_sender = transports.create_network_change_sender(); | ||
|
||
let endpoint = quinn::Endpoint::new_with_abstract_socket( | ||
endpoint_config, | ||
Some(server_config), | ||
Box::new(MagicUdpSocket { | ||
socket: msock.clone(), | ||
transports, | ||
}), | ||
#[cfg(not(wasm_browser))] | ||
Arc::new(quinn::TokioRuntime), | ||
#[cfg(wasm_browser)] | ||
Arc::new(crate::web_runtime::WebRuntime), | ||
) | ||
.context(CreateQuinnEndpointSnafu)?; | ||
|
||
let network_monitor = netmon::Monitor::new() | ||
.await | ||
.context(CreateNetmonMonitorSnafu)?; | ||
|
||
let qad_endpoint = endpoint.clone(); | ||
|
||
#[cfg(any(test, feature = "test-utils"))] | ||
let client_config = if insecure_skip_relay_cert_verify { | ||
iroh_relay::client::make_dangerous_client_config() | ||
} else { | ||
default_quic_client_config() | ||
}; | ||
#[cfg(not(any(test, feature = "test-utils")))] | ||
let client_config = default_quic_client_config(); | ||
|
||
let net_report_config = net_report::Options::default(); | ||
#[cfg(not(wasm_browser))] | ||
let net_report_config = net_report_config.quic_config(Some(QuicConfig { | ||
ep: qad_endpoint, | ||
client_config, | ||
ipv4: true, | ||
ipv6, | ||
})); | ||
|
||
#[cfg(any(test, feature = "test-utils"))] | ||
let net_report_config = | ||
net_report_config.insecure_skip_relay_cert_verify(insecure_skip_relay_cert_verify); | ||
|
||
let net_reporter = net_report::Client::new( | ||
#[cfg(not(wasm_browser))] | ||
dns_resolver, | ||
#[cfg(not(wasm_browser))] | ||
Some(ip_mapped_addrs), | ||
relay_map.clone(), | ||
net_report_config, | ||
metrics.net_report.clone(), | ||
); | ||
|
||
let (direct_addr_done_tx, direct_addr_done_rx) = mpsc::channel(8); | ||
let direct_addr_update_state = DirectAddrUpdateState::new( | ||
msock.clone(), | ||
#[cfg(not(wasm_browser))] | ||
port_mapper, | ||
Arc::new(AsyncMutex::new(net_reporter)), | ||
relay_map, | ||
direct_addr_done_tx, | ||
); | ||
|
||
let netmon_watcher = network_monitor.interface_state(); | ||
let actor = Actor { | ||
msg_receiver: actor_receiver, | ||
msock: msock.clone(), | ||
periodic_re_stun_timer: new_re_stun_timer(false), | ||
network_monitor, | ||
netmon_watcher, | ||
direct_addr_update_state, | ||
network_change_sender, | ||
direct_addr_done_rx, | ||
pending_call_me_maybes: Default::default(), | ||
disco_receiver, | ||
}; | ||
|
||
let actor_token = CancellationToken::new(); | ||
let token = actor_token.clone(); | ||
let actor_task = task::spawn( | ||
actor | ||
.run(token, local_addrs_watch, sender) | ||
.instrument(info_span!("actor")), | ||
); | ||
|
||
let actor_task = Arc::new(Mutex::new(Some(AbortOnDropHandle::new(actor_task)))); | ||
|
||
Ok(Handle { | ||
msock, | ||
actor_task, | ||
endpoint, | ||
actor_token, | ||
}) | ||
} | ||
|
||
/// The underlying [`quinn::Endpoint`] | ||
pub fn endpoint(&self) -> &quinn::Endpoint { | ||
&self.endpoint | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also ignore this part
iroh/src/disco.rs
Outdated
@@ -57,8 +56,11 @@ pub enum MessageType { | |||
Ping = 0x01, | |||
Pong = 0x02, | |||
CallMeMaybe = 0x03, | |||
WebRtcIceCandidate = 0x06 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will also need some refactoring
iroh/Cargo.toml
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since I was running the complete stack locally, I had to modify the Cargo.toml. I think we should consider adding Cargo.toml to .gitignore, unless you suggest a better approach.
Hi team,
I’ve added the basic struct for WebRTC support to get things started.
Kindly guide me if this is a good direction or if there’s anything I should take care of early on.
Also, what signaling server setup would you recommend for Iroh’s WebRTC integration?
Thanks!