-
Notifications
You must be signed in to change notification settings - Fork 0
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
*: Remove ListenerId
#4
Conversation
Remove ListenerClosed. It was used for the following cases: - listen_on failed -> Added new event ListenFailure to cover this case - remove_listener -> Now just report AddressExpired - fatal error on active listener (not used in any of our transports) -> Transports should report AddressExpired for associated addresses -> Transports can report Transport::Error for debugging purposed
Don't inform the behaviour of non-fatal listener/ transport errors. They are only for debug purposes and being `dyn Error` they can not be handled by the Behaviour anyway. Rename SwarmEvent::ListenerError to SwarmEvent::TransportError
Here is an idea but we may need a bit more refinement: We can define a generic function on multiaddress like: impl Multiaddress {
pub fn matches_wildcard_mask(&self, other: Multiaddress) -> bool {}
}
Perhaps we could use this so we don't have to tear apart the address completely in |
transports/websocket/src/framed.rs
Outdated
listener_protos: HashMap<ListenerId, Protocol<'static>>, | ||
/// Ws / Wss protocols extension for inner listening addresses, mapped to | ||
/// the port of the listening address. | ||
listener_protos: HashMap<u16, Protocol<'static>>, |
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 could collide on IPv6 and IPv4, right? E.g. say I am listening via wss
on /ip6/xxx/tcp/42
and ws
on /ip4/xxx/tcp/42
.
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.
Good catch!
if self.tls_config.server.is_some() { | ||
p | ||
} else { | ||
if self.tls_config.server.is_none() { | ||
debug!("/wss address but TLS server support is not configured"); |
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.
Isn't this already checked within self.is_tcp_addr
?
transports/websocket/src/framed.rs
Outdated
|
||
fn insert_proto(&mut self, inner_addr: Multiaddr, proto: Protocol<'static>) { | ||
let mut addr_iter = inner_addr.iter(); | ||
let ip_proto = addr_iter.next().expect("Address is valid."); |
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.
These expect
calls are safe due to the previous call to is_tcp_addr
, correct? Given that the two methods are called in sequence, how about combining them into one method, e.g. validate_addr_and_insert_proto
? That would remove the need for an expect
call, right?
I would like to be a bit careful, given that a remote could potentially give us a malformed address and thus panic the main event loop in case miss an edge case here.
Bummer that
@thomaseizinger this looks worth exploring.
Note that |
Will take another look at the remaining changes. Thanks for looking into this @elenaf9! |
Works too. As long as the limitations are properly documented, we could also introduce it on I am a bit worried that a private, standalone function will bitrot and not actually be expanded. But at the same time, it may be premature optimisation. |
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.
Couple of comments. Overall, apart from the libp2p-websocket
changes, this looks good to me. Thanks for splitting it into the many commits. Made reviewing very easy.
👍 I like the idea.
@thomaseizinger @mxinden we already have a couple of methods for trait MultiaddrExt {
fn address_translation(&self, observed: &Multiaddr) -> Option<Multiaddr>;
fn is_global_ip(&self) -> bool;
fn get_ip_addr(addr: &Multiaddr) -> Option<IpAddr>;
fn matches_wildcard_mask(&self, other: &Multiaddr) -> bool;
}
impl MultiaddrExt for Multiaddr { .. } The only maybe unwanted implication of this would be that the trait would have to be public. But I don't see a downside of this, as long as we document the maturity of the methods appropriately. |
I am a bit hesitant to create an extension trait that is meant to be used by other crates. That gives me "public utility methods" vibes 😅 If they are generally useful, I think they should be upstreamed and otherwise, they should stay private. |
No opinion in regards to where this logic should live. Gut feeling is that it should be private as long as there is no second user. Though again, fine either way. |
I refactored the address mapping in
This results in the same logic as before, but implemented a bit simpler. Also now it considers if an wildcard address is ipv4 or ipv6. |
Another idea that came to my mind: What if a Websocket transport instance either supports That would resolve the whole need for |
Yes that would work! I think this should be done in a separate PR on master, but that makes only sense if we all agree that |
Taking this further, we could have two separate transport implementations and thus completely get rid of the conditional logic. |
Am I correct that doing this would allow us to unambiguously do the mapping without the "taking apart" etc? If yes, then I am in favor of this change on the |
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.
A few minor comments :)
NewAddress(Multiaddr), | ||
/// An address is no longer being listened on. | ||
AddressExpired { | ||
/// The listener that is no longer listening on the address. | ||
listener_id: ListenerId, | ||
/// The new address that is being listened on. | ||
listen_addr: Multiaddr, | ||
}, | ||
/// A connection is incoming on one of the listeners. | ||
AddressExpired(Multiaddr), | ||
/// A connection is incomings. |
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.
StartedListening
and StoppedListening
would be closer aligned with the names of the trait functions.
@@ -115,15 +114,15 @@ pub trait Transport { | |||
/// | |||
/// Returning an error from the stream is considered fatal. The listener can also report | |||
/// non-fatal errors by producing a [`TransportEvent::Error`]. | |||
fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<Self::Error>> | |||
fn listen_on(&mut self, addr: Multiaddr) -> Result<(), TransportError<Self::Error>> |
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.
Maybe this should be start_listen_on
then?
/// The new address that is being listened on. | ||
listen_addr: Multiaddr, | ||
}, | ||
NewAddress(Multiaddr), |
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.
Not moving from a struct to a tuple variant would reduce the diff a bit I think.
transport::TransportEvent::NewAddress(addr) => { | ||
addr_sender.take().unwrap().send(addr).unwrap(); |
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 diff for example could entirely be avoided :)
let ws_proto1 = Protocol::Ws(std::borrow::Cow::Borrowed("1")); | ||
let addr1 = Multiaddr::from(Ipv4Addr::UNSPECIFIED) | ||
.with(Protocol::Tcp(0)) | ||
.with(ws_proto1.clone()); |
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 these would be more readable if parsed from a string.
I thought about this for a while and decided to stick with |
Description
As discussed in libp2p#2652 (review), this PR removes any notion of listeners from the
Transport API
, in particular theListenerId
. As a result now the only way to identify an internal listener is via Multiaddresss. (cc @mxinden @thomaseizinger).For almost all transports this does not change much, the only exception is
WsConfig
, which should be reviewed carefully.For
WsConfig
we have to map back events from the inner transport to a previously calledlisten_on
. Because we have to handle the case of wildcard addresses, this is a bit more complicated. My current solution relies on the multiaddress being a tcp one (even though ourWsConfig
is generic, websockets are always based on tcp, so I think its an acceptable assumption to make), which is not ideal. If there would be a similar use-case that is completely generic over the inner transport, this could be even more difficult.I am still in favor of this change, but I wonder if there is a way we can make this mapping easier for the user.
The PR is split into separate commits for each layer in which the
ListenerId
is removed, so it is best reviewed commit-by-commit.Open Questions
Should we include in
TransportEvent::NewAddress
the address that the user initially provided inlisten_on
to allow mapping the addresses?Change checklist