Conversation
Missing: the watcher rube goldberg types!
|
Documentation for this PR has been generated and is available at: https://n0-computer.github.io/iroh/pr/3845/docs/iroh/ Last updated: 2026-03-04T16:00:35Z |
Plus some refactoring to make the types a bit less frightening. Also reduce the amount of code behind the wasm_browser config so you can work on it without having to compile to wasm.
fc0b076 to
a6d5dad
Compare
a6d5dad to
aabdc93
Compare
The examples for user transports that I can come up with are a WebRTC transport, a WifiAware transport, and a BLE transport. So that would mean they should basically be regarded as similar to the IP transports?
Relays are still too special. Even if we don't have any transports, we can still open relay connections (the relay connection management isn't self-contained in the relay transport). We also use relays for QAD. |
Fully agree. I just had to mention it, since you got a lot of places where relays are being treated in a very similar way to user addrs. But it is perfectly fine to keep them separate for now (or maybe forever... ) |
| Some((transports::Addr::User(_), _)) => { | ||
| // todo: when should we select an user path? | ||
| None | ||
| } |
There was a problem hiding this comment.
This currently just says we never switch away from user transports, even if "better" ones are available.
We need to figure this out before merging. To reason about this, I'm thinking about example user transports:
- WifiAware
- WebRTC
- In-process simulated networks
- Bluetooth
I'd say that we should prefer IP paths if the work and have lower RTT.
So that'd mean that here we're checking if current_rtt >= new_rtt + RTT_SWITCHING_MIN_IP similar to above. And if that is true, we resolve to best_ip_path, if not, we keep the user path.
Additionally, we should check if we have a user transport available, and switch away from None, Relay or Ip to a user path in the match cases above, if the user transport ends up having a lower RTT.
Tbh, this could become quite complicated quickly. E.g. maybe some user transports actually want to stay in the background (with PATH_BACKUP), and only be used if (once we have an API for that) a stream is specifically attached to that path.
We should probably think about how much wiggle-room we have if we'd set the API in stone for 1.0.
There was a problem hiding this comment.
See the new API. Basically this is solved by #3870. For each transport (=address type) you can have a rtt bias (positive or negative), and you can configure for each address type if it is a normal transport or a transport of last resort.
Then within each group transports compete according to their biased rtt, and there is stickiness. For switching the group there is no stickiness.
71b17c9 to
98edf8f
Compare
| /// Only the client closes paths, just like only the client opens paths. This is to | ||
| /// avoid the client and server selecting different paths and accidentally closing all | ||
| /// paths. | ||
| fn close_redundant_paths(&mut self, selected_path: &transports::Addr) { |
There was a problem hiding this comment.
should this account for custom transports in some form?
There was a problem hiding this comment.
Not sure. A custom path is just another path, so I guess this does not have to be special cased for custom paths.
There was a problem hiding this comment.
we special case IP paths in here, that's why I am wondering
There was a problem hiding this comment.
Oh god. I guess you are right.
We are using is_ip as a "this is a good path" stand-in for now. Not just here, but in a lot of places.
I guess we would have to change is_ip with checking if the path is a "primary". But you can't see that from an addr - custom transports can be either. So it would have to be a lookup in bias_map.
Something like this:
+ let is_primary = |addr: &transports::Addr| {
+ self.transport_bias
+ .get(addr)
+ .transport_type == transports::TransportType::Primary
+ };
+
for (conn_id, conn_state) in self.connections.iter() {
for (path_id, path_remote) in conn_state
.open_paths
.iter()
- .filter(|(_, addr)| addr.is_ip())
+ .filter(|(_, addr)| is_primary(addr))
.filter(|(_, addr)| *addr != selected_path)
{
- if conn_state.open_paths.values().filter(|a| a.is_ip()).count() <= 1 {
+ if conn_state.open_paths.values().filter(|a| is_primary(a)).count() <= 1 {
continue; // Do not close the last direct path.
}
if let Some(path) = conn_state
There was a problem hiding this comment.
Without custom transports is_primary returns true only for ip, so the behaviour would be unchanged.
There was a problem hiding this comment.
There are only a few non-test places other than this where is_ip is used. BUT... I think custom transports as implemented now introduce the concept of a backup transport, that gets sorted together with the relay transports, but is not a relay.
I wonder if we should just drop this and say that all custom transports are direct. They would have to compete with Ip transports on the basis of their (biased) rtt. That would probably simplify not mixing up all the relay special cases with custom transports.
There was a problem hiding this comment.
You could flip is_ip to just !is_relay and call it a day...
There was a problem hiding this comment.
I am honestly not sure what to do here yet, lets make a todo/note in the comment and open an issue about it, so we don't forget about it
Instead use TransportType as a transport category
b0d5ad8 to
397d0ed
Compare
For now, backup is reserved for relay.
We treat all non-relay paths as direct paths. Custom transports compete with Ip paths based on biased rtt.
# Conflicts: # iroh/src/endpoint.rs # iroh/src/socket.rs # iroh/src/socket/remote_map/remote_state.rs
Description
Adds user defined transports.
Transports have to impl a dynable trait, currently named CustomTransport. Implementing this requires implementing another dynable trait CustomSender. Creating a transport requires implementing yet another dynable trait CustomTransportFactory.
A custom addr is just an opaque blob with an u64 tranport id. Small blobs will be inlined, but that is an implementation detail.
Formatting currently is "-"
Replaces #3707
Breaking Changes
Notes & open questions
Question: encoding of custom addrs in DNS records.
Question: Feature gate or not? User transports require exposing a bit more of the guts, e.g. transmit fields, so we might want to put this behind a feature flag that is documented to be not part of the stable API.Question: Path selection.Currently in select_best_path we never select an user path. For some reason it still works, but we probably should put in some logic there.DRY the different mapped addrs?
We could DRY the 2 differnet mapped addrs a bit more. But once you start with this you get into a rabbit hole. Should relay transports just be a special kind of custom transport? If we could abstract the logic when to choose the relay, this might work. Maybe this is best left for later.Update: path selection is now taken care of. Basically each path gets a 2-tuple consisting of primary/secondary and biased rtt, then sort and take the best. There is an API to add a bias for each addr type and also to configure for each transport if it is a transport of last resort.
Here is how to bias a transport:
I also added some tests to make sure custom transports work if the ip transport is enabled.