Skip to content

Should Error::HandshakePending be documented as an exception to fatal error handling? #158

Description

@HMBSbige

Hi, I may be misunderstanding the intended error contract.

The README says every Error returned by handle_packet, handle_timeout, send_application_data, or close is fatal and that the Dtls instance should always be dropped:

https://github.com/algesten/dimpl/blob/37f950984af1d0c2f86ef21b940c672fb27cd7c7/README.md#error-handling

However, Error::HandshakePending says callers should buffer the data and retry once the handshake advances:

dimpl/src/error.rs

Lines 46 to 51 in 37f9509

/// Application data cannot be sent because the handshake is not yet complete.
///
/// For auto-sense instances this means the version has not yet been
/// resolved. Callers should buffer the data and retry once the
/// handshake advances.
HandshakePending,

send_application_data repeats that guidance, and both it and close return HandshakePending from the pending branch before invoking the protocol-specific send or close logic:

dimpl/src/lib.rs

Lines 816 to 867 in 37f9509

/// Send application data over the established DTLS session.
///
/// Returns [`Error::HandshakePending`] if the DTLS version has not
/// yet been resolved (auto-sense pending). Callers should buffer
/// the data externally and retry after the handshake progresses.
pub fn send_application_data(&mut self, data: &[u8]) -> Result<(), Error> {
// unwrap is ok, we only have an Option to deal with pending auto.
let inner = self.inner.as_mut().unwrap();
if inner.is_pending() {
return Err(Error::HandshakePending);
}
match inner {
Inner::Client12(client) => client.send_application_data(data),
Inner::Server12(server) => server.send_application_data(data),
Inner::Client13(client) => client.send_application_data(data),
Inner::Server13(server) => server.send_application_data(data),
Inner::ClientPending(_) => Err(Error::HandshakePending),
}
}
/// Initiate graceful shutdown by sending a `close_notify` alert.
///
/// **Connected** (`AwaitApplicationData`): queues a `close_notify` alert;
/// the next [`poll_output`](Self::poll_output) cycle yields it as
/// [`Output::Packet`].
///
/// **Handshake in progress**: aborts immediately without sending an
/// alert (no authenticated channel exists). Subsequent calls to
/// [`send_application_data`](Self::send_application_data) will return
/// an error.
///
/// **Pending** (version not yet resolved): returns
/// [`Error::HandshakePending`]. Callers who want to discard a pending
/// connection can simply drop the [`Dtls`] value.
///
/// The alert is not retransmitted (per RFC 6347 §4.2.7 / RFC 9147 §5.10).
pub fn close(&mut self) -> Result<(), Error> {
let inner = self.inner.as_mut().unwrap();
if inner.is_pending() {
return Err(Error::HandshakePending);
}
match inner {
Inner::Client12(client) => client.close(),
Inner::Server12(server) => server.close(),
Inner::Client13(client) => client.close(),
Inner::Server13(server) => server.close(),
Inner::ClientPending(_) => Err(Error::HandshakePending),
}

Does this mean HandshakePending is recoverable and should be documented as an exception to the README’s fatal-error rule?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions