Skip to content

Commit

Permalink
misc/multistream-select: Always interpret EOF as negotiation failure
Browse files Browse the repository at this point in the history
  • Loading branch information
mxinden committed Nov 5, 2020
1 parent d74b242 commit 01b54b8
Showing 1 changed file with 17 additions and 34 deletions.
51 changes: 17 additions & 34 deletions misc/multistream-select/src/listener_select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,15 @@ where
{
RecvHeader { io: MessageIO<R> },
SendHeader { io: MessageIO<R>, version: Version },
RecvMessage {
io: MessageIO<R>,
/// Whether the last sent message was a [`Message::NotAvailable`].
prev_sent_na: bool,
},
RecvMessage { io: MessageIO<R> },
SendMessage {
io: MessageIO<R>,
message: Message,
protocol: Option<N>
},
Flush {
io: MessageIO<R>,
protocol: Option<N>,
/// Whether the last sent message was a [`Message::NotAvailable`].
prev_sent_na: bool
protocol: Option<N>
},
Done
}
Expand Down Expand Up @@ -150,32 +144,23 @@ where
}

*this.state = match version {
Version::V1 => State::Flush { io, protocol: None, prev_sent_na: false },
Version::V1Lazy => State::RecvMessage { io, prev_sent_na: false },
Version::V1 => State::Flush { io, protocol: None },
Version::V1Lazy => State::RecvMessage { io },
}
}

State::RecvMessage { mut io, prev_sent_na } => {
State::RecvMessage { mut io } => {
let msg = match Pin::new(&mut io).poll_next(cx) {
Poll::Ready(Some(Ok(msg))) => msg,
Poll::Ready(None) => {
// When a listener rejects a protocol with [`Message::NotAvailable`] and
// the dialer does not have alternative protocols to propose then the
// dialer will stop the negotiation and drop the corresponding stream.
// As a listener interpret an EOF after sending a
// [`Message::NotAvailable`] as a failed negotiation. Interpret an EOF
// as an io error in all other cases.
let err = if prev_sent_na {
NegotiationError::Failed
} else {
NegotiationError::from(ProtocolError::IoError(
io::ErrorKind::UnexpectedEof.into(),
))
};
return Poll::Ready(Err(err));
}
// Treat EOF error as [`NegotiationError::Failed`], not as
// [`NegotiationError::ProtocolError`]. This is e.g. important when a
// listener rejects a protocol with [`Message::NotAvailable`] and the dialer
// does not have alternative protocols to propose. Then the dialer will stop
// the negotiation and drop the corresponding stream. As a listener this EOF
// should be interpreted as a failed negotiation.
Poll::Ready(None) => return Poll::Ready(Err(NegotiationError::Failed)),
Poll::Pending => {
*this.state = State::RecvMessage { io, prev_sent_na };
*this.state = State::RecvMessage { io };
return Poll::Pending;
}
Poll::Ready(Some(Err(err))) => return Poll::Ready(Err(From::from(err))),
Expand Down Expand Up @@ -221,19 +206,17 @@ where
Poll::Ready(Err(err)) => return Poll::Ready(Err(From::from(err))),
}

let is_na_msg = matches!(message, Message::NotAvailable);

if let Err(err) = Pin::new(&mut io).start_send(message) {
return Poll::Ready(Err(From::from(err)));
}

*this.state = State::Flush { io, protocol, prev_sent_na: is_na_msg };
*this.state = State::Flush { io, protocol };
}

State::Flush { mut io, protocol, prev_sent_na } => {
State::Flush { mut io, protocol } => {
match Pin::new(&mut io).poll_flush(cx) {
Poll::Pending => {
*this.state = State::Flush { io, protocol, prev_sent_na };
*this.state = State::Flush { io, protocol };
return Poll::Pending
},
Poll::Ready(Ok(())) => {
Expand All @@ -246,7 +229,7 @@ where
let io = Negotiated::completed(io.into_inner());
return Poll::Ready(Ok((protocol, io)))
}
None => *this.state = State::RecvMessage { io, prev_sent_na }
None => *this.state = State::RecvMessage { io }
}
}
Poll::Ready(Err(err)) => return Poll::Ready(Err(From::from(err))),
Expand Down

0 comments on commit 01b54b8

Please sign in to comment.