netconf/
error.rs

1use std::convert::Infallible;
2
3use bytes::Bytes;
4use iri_string::types::UriStr;
5use tokio::sync::mpsc;
6
7use crate::{
8    capabilities::Requirements,
9    message::{
10        self,
11        rpc::{self, operation::Datastore},
12    },
13};
14
15/// `netconf` library error variants
16#[derive(Debug, thiserror::Error)]
17pub enum Error {
18    // Transport //
19    #[cfg(feature = "ssh")]
20    /// The underlying SSH transport encountered an error.
21    #[error(transparent)]
22    SshTransport(#[from] russh::Error),
23
24    #[cfg(feature = "tls")]
25    /// The underlying TLS transport encountered an error.
26    #[error(transparent)]
27    TlsTransport(#[from] tokio_rustls::rustls::Error),
28
29    /// The underlying transport encountered an error.
30    #[error("a transport error occurred: {0}")]
31    Transport(#[from] std::io::Error),
32
33    /// Failure to enqueue an inter-task message.
34    #[error("failed to enqueue a message")]
35    EnqueueMessage(#[from] mpsc::error::SendError<Bytes>),
36
37    /// Failure to dequeue an inter-task message.
38    #[error("failed to dequeue a message: send side is closed")]
39    DequeueMessage,
40
41    #[cfg(feature = "tls")]
42    /// Invalid DNS name for certificate validation.
43    #[error(transparent)]
44    InvalidDnsName(#[from] rustls_pki_types::InvalidDnsNameError),
45
46    // Session establishment //
47    //
48    /// User authentication failed.
49    #[error("authentication failed for user {username}")]
50    Authentication {
51        /// User name provided during failed authentication attempt.
52        username: String,
53    },
54
55    /// Base protocol version negotiation failed.
56    #[error("failed to negotiate a common base protocol version")]
57    VersionNegotiation,
58
59    // Session management //
60    //
61    /// A `message-id` collision was detected.
62    #[error("encountered a 'message-id' collision. please file a bug report!")]
63    MessageIdCollision {
64        /// `message-id` for which a collision was detected.
65        message_id: rpc::MessageId,
66    },
67
68    /// Received a message with an unknown `message-id`.
69    #[error("request with message-id '{message_id:?}' not found")]
70    RequestNotFound {
71        /// `message-id` received in server message.
72        message_id: rpc::MessageId,
73    },
74
75    /// Attempted to process an already completed request.
76    #[error("attempted to poll for an already completed request")]
77    RequestComplete,
78
79    // Message encoding / serialization //
80    //
81    /// Message serialization failed.
82    #[error(transparent)]
83    WriteMessage(#[from] message::WriteError),
84
85    // Message decoding / de-serialization //
86    //
87    /// Message de-serialization failed
88    #[error(transparent)]
89    ReadMessage(#[from] message::ReadError),
90
91    // RPC request validation.
92    //
93    /// Attempted to perform `delete-config` operation targeting the `running` datastore.
94    #[error("deleting the <running/> datastore is not permitted")]
95    DeleteRunningConfig,
96
97    /// Invalid `session-id`.
98    #[error("invalid session-id: {session_id}")]
99    InvalidSessionId {
100        /// Invalid `session-id` value.
101        session_id: u32,
102    },
103
104    /// Attempted to perform `kill-session` operation targeting the current session.
105    #[error("kill-session operation targeting the current session is not permitted")]
106    KillCurrentSession,
107
108    /// Attempted to perform an unsupported operation.
109    #[error("unsupported rpc operation '{operation_name}' (requires {required_capabilities})")]
110    UnsupportedOperation {
111        /// RPC operation name.
112        operation_name: &'static str,
113        /// Required server capabilities.
114        required_capabilities: Requirements,
115    },
116
117    /// Attempted to set an unsupported operation parameter.
118    #[error("unsupported parameter '{param_name}' for rpc operation '{operation_name}' (requires {required_capabilities})")]
119    UnsupportedOperationParameter {
120        /// RPC operation name.
121        operation_name: &'static str,
122        /// Unsupported operation parameter.
123        param_name: &'static str,
124        /// Required server capabilities.
125        required_capabilities: Requirements,
126    },
127
128    /// Attempted to set an operation parameter to an unsupported value.
129    #[error("unsupported value '{param_value}' of parameter '{param_name}' for rpc operation '{operation_name}' (requires {required_capabilities})")]
130    UnsupportedOperParameterValue {
131        /// RPC operation name.
132        operation_name: &'static str,
133        /// Operation parameter.
134        param_name: &'static str,
135        /// Unsupported parameter value.
136        param_value: &'static str,
137        /// Required server capabilities.
138        required_capabilities: Requirements,
139    },
140
141    /// Attempted to perform an operation on an unsupported `source` datastore.
142    #[error("unsupported source datastore '{datastore:?}' (requires {required_capabilities})")]
143    UnsupportedSource {
144        /// Source datastore.
145        datastore: Datastore,
146        /// Required server capabilities.
147        required_capabilities: Requirements,
148    },
149
150    /// Attempted to perform an operation on an unsupported `target` datastore.
151    #[error("unsupported target datastore '{datastore:?}' (requires {required_capabilities})")]
152    UnsupportedTarget {
153        /// Target datastore.
154        datastore: Datastore,
155        /// Required server capabilities.
156        required_capabilities: Requirements,
157    },
158
159    /// Attempted to `lock` an unsupported datastore.
160    #[error(
161        "unsupported lock target datastore '{datastore:?}' (requires {required_capabilities})"
162    )]
163    UnsupportedLockTarget {
164        /// Target datastore.
165        datastore: Datastore,
166        /// Required server capabilities.
167        required_capabilities: Requirements,
168    },
169
170    /// Unsupported URL scheme.
171    #[error("unsupported scheme in url '{url}' (requires ':url:1.0' capability with corresponding 'scheme' parameter)")]
172    UnsupportedUrlScheme {
173        /// Unsupported URL.
174        url: Box<UriStr>,
175    },
176
177    /// Unsupported `filter` type.
178    #[error("unsupported filter type '{filter}' (requires {required_capabilities})")]
179    UnsupportedFilterType {
180        /// Unsupported filter type.
181        filter: &'static str,
182        /// Required server capabilities.
183        required_capabilities: Requirements,
184    },
185
186    /// Missing a required operation parameter.
187    #[error("missing required parameter {param_name} for rpc operation {operation_name}")]
188    MissingOperationParameter {
189        /// RPC operation name.
190        operation_name: &'static str,
191        /// Required parameter name.
192        param_name: &'static str,
193    },
194
195    /// Incompatible combination of operation parameters.
196    #[error("incompatible parameter combination for operation '{0}': {}", .parameters.join(", "))]
197    IncompatibleOperationParameters {
198        /// RPC operation name.
199        operation_name: &'static str,
200        /// Required server capabilities.
201        parameters: Vec<&'static str>,
202    },
203
204    /// Failed to parse a URL
205    #[error("failed to parse URI")]
206    UrlParse(#[from] iri_string::validate::Error),
207
208    // Protocol errors
209    //
210    /// RPC operation failure.
211    #[error("received rpc-error reply: {0}")]
212    RpcError(#[from] rpc::Errors),
213
214    /// Empty `rpc-reply` when data was expected.
215    #[error("unexpectedly empty rpc-reply")]
216    EmptyRpcReply,
217}
218
219impl Error {
220    pub(crate) const fn missing_operation_parameter(
221        operation_name: &'static str,
222        param_name: &'static str,
223    ) -> Self {
224        Self::MissingOperationParameter {
225            operation_name,
226            param_name,
227        }
228    }
229}
230
231impl From<Infallible> for Error {
232    fn from(_: Infallible) -> Self {
233        unreachable!()
234    }
235}