diff --git a/src/socket/tcp.rs b/src/socket/tcp.rs index 619f7c639..79caf8c83 100644 --- a/src/socket/tcp.rs +++ b/src/socket/tcp.rs @@ -744,7 +744,7 @@ impl<'a> Socket<'a> { /// Start listening on the given endpoint. /// - /// This function returns `Err(Error::Illegal)` if the socket was already open + /// This function returns `Err(Error::InvalidState)` if the socket was already open /// (see [is_open](#method.is_open)), and `Err(Error::Unaddressable)` /// if the port in the given endpoint is zero. pub fn listen(&mut self, local_endpoint: T) -> Result<(), ListenError> @@ -757,7 +757,19 @@ impl<'a> Socket<'a> { } if self.is_open() { - return Err(ListenError::InvalidState); + // If we were already listening to same endpoint there is nothing to do; exit early. + // + // In the past listening on an socket that was already listening was an error, + // however this makes writing an acceptor loop with multiple sockets impossible. + // Without this early exit, if you tried to listen on a socket that's already listening you'll + // immediately get an error. The only way around this is to abort the socket first + // before listening again, but this means that incoming connections can actually + // get aborted between the abort() and the next listen(). + if matches!(self.state, State::Listen) && self.listen_endpoint == local_endpoint { + return Ok(()); + } else { + return Err(ListenError::InvalidState); + } } self.reset(); @@ -2911,6 +2923,9 @@ mod test { fn test_listen_twice() { let mut s = socket(); assert_eq!(s.listen(80), Ok(())); + // multiple calls to listen are okay if its the same local endpoint and the state is still in listening + assert_eq!(s.listen(80), Ok(())); + s.set_state(State::SynReceived); // state change, simulate incoming connection assert_eq!(s.listen(80), Err(ListenError::InvalidState)); }