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 [`docs/state-machines.md`](../docs/state-machines.md)),
6//! CSeq correlation, missing/invalid `Session`, `Transport` header parsing
7//! (§12.39 — [`docs/transport-header.md`](../docs/transport-header.md)),
8//! interleaved framing (§10.12 — [`docs/interleaved-framing.md`](../docs/interleaved-framing.md)),
9//! and authentication (§14 — [`docs/auth.md`](../docs/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)]
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 carrying a `CSeq` that does not match any outstanding
41 /// request.
42 #[error("no pending request for CSeq {0}")]
43 UnknownCSeq(u32),
44
45 /// A response arrived with no parseable `CSeq` header.
46 #[error("response is missing a CSeq header")]
47 MissingCSeq,
48
49 /// An operation required an established session id but none was negotiated
50 /// (no SETUP response has been processed yet).
51 #[error("no session established (SETUP not completed)")]
52 MissingSession,
53
54 /// The `Transport` header value could not be parsed per RFC 2326 §12.39.
55 #[error("invalid Transport header: {0}")]
56 TransportParse(String),
57
58 /// A header value could not be serialized safely (control character in a value,
59 /// or a name that is not an RFC 2326 §15.1 token / session-id character).
60 #[error("cannot serialize header: {0}")]
61 HeaderSerialize(String),
62
63 /// The `Session` header value could not be parsed per RFC 2326 §12.37.
64 #[error("invalid Session header: {0}")]
65 SessionParse(String),
66
67 /// An interleaved `$` frame was malformed (RFC 2326 §10.12).
68 #[error("invalid interleaved frame: {0}")]
69 InterleavedFrame(String),
70
71 /// Authentication failed: no credentials were configured, the challenge
72 /// could not be parsed, or the digest computation failed (RFC 2326 §14).
73 #[error("authentication failure: {0}")]
74 Auth(String),
75
76 /// The request required a request URI but none was set.
77 #[error("request URI required but not set")]
78 MissingRequestUri,
79
80 /// A socket IO operation failed in the async adapter (feature `tokio`).
81 #[error("socket IO error: {0}")]
82 Io(String),
83
84 /// A bounded wait in the async adapter expired (feature `tokio`).
85 #[error("timed out waiting for {what}")]
86 Timeout {
87 /// Which bounded wait expired: `"connect"`, `"handshake"`, `"read"` or `"write"`.
88 what: &'static str,
89 },
90
91 /// A TLS operation failed in the async adapter (feature `tls`): bad server
92 /// name, handshake, or certificate configuration (`rtsps://`, RFC 2326 §19).
93 #[error("TLS error: {0}")]
94 Tls(String),
95
96 /// The server answered `454 Session Not Found` (RFC 2326 §11.3.2) to a
97 /// request on our session — the session is gone (timed out, or torn down
98 /// server-side), so the caller must re-`SETUP`. Surfaced by the send-only
99 /// push drain (a `GET_PARAMETER` keepalive is the usual trigger) instead
100 /// of being silently discarded.
101 #[error("RTSP session not found (454 {method:?}): the session is gone; re-SETUP")]
102 SessionNotFound {
103 /// The method whose request the server rejected with 454.
104 method: Method,
105 },
106}
107
108impl From<std::io::Error> for Error {
109 fn from(e: std::io::Error) -> Self {
110 Error::Io(e.to_string())
111 }
112}