Skip to content

Commit 17ef4e3

Browse files
fix(netwatch): improve UDP rebind (#95)
We already handle this in the drop implementation, but when doing rebind we did not properly wait for the socket to close, which caused issues on slower systems, especially wine.
1 parent 35ab4fa commit 17ef4e3

1 file changed

Lines changed: 28 additions & 16 deletions

File tree

netwatch/src/udp.rs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,8 @@ enum SocketState {
688688
addr: SocketAddr,
689689
},
690690
Closed {
691+
/// The addr to rebind to when recovering.
692+
addr: SocketAddr,
691693
last_max_gso_segments: NonZeroUsize,
692694
last_gro_segments: NonZeroUsize,
693695
last_may_fragment: bool,
@@ -768,25 +770,34 @@ impl SocketState {
768770
}
769771

770772
fn rebind(&mut self) -> io::Result<()> {
771-
let (addr, closed_state) = match self {
772-
Self::Connected { state, addr, .. } => {
773-
let s = SocketState::Closed {
774-
last_max_gso_segments: state.max_gso_segments(),
775-
last_gro_segments: state.gro_segments(),
776-
last_may_fragment: state.may_fragment(),
777-
};
778-
(*addr, s)
779-
}
780-
Self::Closed { .. } => {
781-
return Err(io::Error::other("socket is closed and cannot be rebound"));
782-
}
773+
let addr = match self {
774+
Self::Connected { addr, .. } => *addr,
775+
Self::Closed { addr, .. } => *addr,
783776
};
784777
debug!("rebinding {}", addr);
785778

786-
*self = closed_state;
787-
*self = Self::bind(addr)?;
779+
// Transition to Closed first to drop the old socket.
780+
// This is needed so the port is released before we try to bind again.
781+
if let Self::Connected { state, .. } = self {
782+
*self = SocketState::Closed {
783+
addr,
784+
last_max_gso_segments: state.max_gso_segments(),
785+
last_gro_segments: state.gro_segments(),
786+
last_may_fragment: state.may_fragment(),
787+
};
788+
}
788789

789-
Ok(())
790+
match Self::bind(addr) {
791+
Ok(new_state) => {
792+
*self = new_state;
793+
Ok(())
794+
}
795+
Err(err) => {
796+
// Stay in Closed state but allow future rebind attempts
797+
debug!("rebind failed, will retry on next attempt: {}", err);
798+
Err(err)
799+
}
800+
}
790801
}
791802

792803
fn is_closed(&self) -> bool {
@@ -795,8 +806,9 @@ impl SocketState {
795806

796807
fn close(&mut self) -> Option<(tokio::net::UdpSocket, quinn_udp::UdpSocketState)> {
797808
match self {
798-
Self::Connected { state, .. } => {
809+
Self::Connected { state, addr, .. } => {
799810
let s = SocketState::Closed {
811+
addr: *addr,
800812
last_max_gso_segments: state.max_gso_segments(),
801813
last_gro_segments: state.gro_segments(),
802814
last_may_fragment: state.may_fragment(),

0 commit comments

Comments
 (0)