diff --git a/tokio-xmpp/src/client/async_client.rs b/tokio-xmpp/src/client/async_client.rs index ff057df8..cb0f17f2 100644 --- a/tokio-xmpp/src/client/async_client.rs +++ b/tokio-xmpp/src/client/async_client.rs @@ -243,42 +243,50 @@ impl Stream for Client { }; // Poll stream - match Pin::new(&mut stream).poll_next(cx) { - Poll::Ready(None) => { - // EOF - self.state = ClientState::Disconnected; - Poll::Ready(Some(Event::Disconnected(Error::Disconnected))) - } - Poll::Ready(Some(Ok(Packet::Stanza(stanza)))) => { - // Receive stanza - self.state = ClientState::Connected(stream); - Poll::Ready(Some(Event::Stanza(stanza))) - } - Poll::Ready(Some(Ok(Packet::Text(_)))) => { - // Ignore text between stanzas - self.state = ClientState::Connected(stream); - Poll::Pending - } - Poll::Ready(Some(Ok(Packet::StreamStart(_)))) => { - // - self.state = ClientState::Disconnected; - Poll::Ready(Some(Event::Disconnected( - ProtocolError::InvalidStreamStart.into(), - ))) - } - Poll::Ready(Some(Ok(Packet::StreamEnd))) => { - // End of stream: - self.state = ClientState::Disconnected; - Poll::Ready(Some(Event::Disconnected(Error::Disconnected))) - } - Poll::Pending => { - // Try again later - self.state = ClientState::Connected(stream); - Poll::Pending - } - Poll::Ready(Some(Err(e))) => { - self.state = ClientState::Disconnected; - Poll::Ready(Some(Event::Disconnected(e.into()))) + // + // This needs to be a loop in order to ignore packets we don’t care about, or those + // we want to handle elsewhere. Returning something isn’t correct in those two + // cases because it would signal to tokio that the XMPPStream is also done, while + // there could be additional packets waiting for us. + // + // The proper solution is thus a loop which we exit once we have something to + // return. + loop { + match Pin::new(&mut stream).poll_next(cx) { + Poll::Ready(None) => { + // EOF + self.state = ClientState::Disconnected; + return Poll::Ready(Some(Event::Disconnected(Error::Disconnected))); + } + Poll::Ready(Some(Ok(Packet::Stanza(stanza)))) => { + // Receive stanza + self.state = ClientState::Connected(stream); + return Poll::Ready(Some(Event::Stanza(stanza))); + } + Poll::Ready(Some(Ok(Packet::Text(_)))) => { + // Ignore text between stanzas + } + Poll::Ready(Some(Ok(Packet::StreamStart(_)))) => { + // + self.state = ClientState::Disconnected; + return Poll::Ready(Some(Event::Disconnected( + ProtocolError::InvalidStreamStart.into(), + ))); + } + Poll::Ready(Some(Ok(Packet::StreamEnd))) => { + // End of stream: + self.state = ClientState::Disconnected; + return Poll::Ready(Some(Event::Disconnected(Error::Disconnected))); + } + Poll::Pending => { + // Try again later + self.state = ClientState::Connected(stream); + return Poll::Pending; + } + Poll::Ready(Some(Err(e))) => { + self.state = ClientState::Disconnected; + return Poll::Ready(Some(Event::Disconnected(e.into()))); + } } } }