Skip to main content

rtsp_runtime/
error.rs

1//! Error types for the RTSP session engine.
2//!
3//! Structured [`thiserror`] errors covering the failure surface of the sans-IO
4//! engine: RTSP message parse/serialize, state-machine violations (RFC 2326
5//! Appendix A — see `private/specs-verified/rtp/rtsp-runtime/state-machines.md`),
6//! CSeq correlation, missing/invalid `Session`, `Transport` header parsing
7//! (§12.39 — `private/specs-verified/rtp/rtsp-runtime/transport-header.md`),
8//! interleaved framing (§10.12 — `private/specs-verified/rtp/rtsp-runtime/interleaved-framing.md`),
9//! and authentication (§14 — `private/specs-verified/rtp/rtsp-runtime/auth.md`).
10
11use crate::Method;
12use crate::state::SessionState;
13
14/// Result alias for the engine's fallible operations.
15pub type Result<T> = core::result::Result<T, Error>;
16
17/// Errors produced by the RTSP session engine.
18#[non_exhaustive]
19#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
20pub enum Error {
21    /// The RTSP message could not be parsed by the underlying `rtsp-types` codec.
22    #[error("failed to parse RTSP message: {0}")]
23    MessageParse(String),
24
25    /// The RTSP message could not be serialized by the underlying codec.
26    #[error("failed to serialize RTSP message: {0}")]
27    MessageWrite(String),
28
29    /// A method was invoked (client) or received (server) that is not permitted
30    /// in the current session state. The server maps this to `455 Method Not
31    /// Valid In This State` (RFC 2326 §11.3.6, Appendix A).
32    #[error("method {method:?} not valid in state {state:?}")]
33    MethodNotValidInState {
34        /// The offending method.
35        method: Method,
36        /// The state the object was in when the method was attempted.
37        state: SessionState,
38    },
39
40    /// A response arrived with no parseable `CSeq` header.
41    #[error("response is missing a CSeq header")]
42    MissingCSeq,
43
44    /// The `Transport` header value could not be parsed per RFC 2326 §12.39.
45    #[error("invalid Transport header: {0}")]
46    TransportParse(String),
47
48    /// A header value could not be serialized safely (control character in a value,
49    /// or a name that is not an RFC 2326 §15.1 token / session-id character).
50    #[error("cannot serialize header: {0}")]
51    HeaderSerialize(String),
52
53    /// The `Session` header value could not be parsed per RFC 2326 §12.37.
54    #[error("invalid Session header: {0}")]
55    SessionParse(String),
56
57    /// An interleaved `$` frame was malformed (RFC 2326 §10.12).
58    #[error("invalid interleaved frame: {0}")]
59    InterleavedFrame(String),
60
61    /// Authentication failed: no credentials were configured, the challenge
62    /// could not be parsed, or the digest computation failed (RFC 2326 §14).
63    #[error("authentication failure: {0}")]
64    Auth(#[from] broadcast_auth::Error),
65
66    /// The server answered `401 Unauthorized` without a `WWW-Authenticate`
67    /// challenge, so there is nothing to answer (RFC 2326 §14).
68    #[error("authentication failure: 401 without WWW-Authenticate")]
69    MissingAuthChallenge,
70
71    /// A socket IO operation failed in the async adapter (feature `tokio`).
72    #[error("socket IO error: {0}")]
73    Io(String),
74
75    /// A bounded wait in the async adapter expired (feature `tokio`).
76    #[error("timed out waiting for {what}")]
77    Timeout {
78        /// Which bounded wait expired: `"connect"`, `"handshake"`, `"read"` or `"write"`.
79        what: &'static str,
80    },
81
82    /// A TLS operation failed in the async adapter (feature `tls`): bad server
83    /// name, handshake, or certificate configuration (`rtsps://`).
84    #[error("TLS error: {0}")]
85    Tls(String),
86
87    /// The server answered `454 Session Not Found` (RFC 2326 §11.3.5) to a
88    /// request on our session — the session is gone (timed out, or torn down
89    /// server-side), so the caller must re-`SETUP`. Surfaced by the send-only
90    /// push drain (a `GET_PARAMETER` keepalive is the usual trigger) instead
91    /// of being silently discarded.
92    #[error("RTSP session not found (454 {method:?}): the session is gone; re-SETUP")]
93    SessionNotFound {
94        /// The method whose request the server rejected with 454.
95        method: Method,
96    },
97}
98
99impl From<std::io::Error> for Error {
100    fn from(e: std::io::Error) -> Self {
101        Error::Io(e.to_string())
102    }
103}