mssql_browser/
error.rs

1use std::error::Error;
2use std::net::SocketAddr;
3
4/// An error that can be returned from the different browser operations
5pub enum BrowserError<
6    #[cfg(any(feature = "tokio", feature = "async-std"))]
7    SFError: Error = <super::socket::DefaultSocketFactory as super::socket::UdpSocketFactory>::Error,
8    #[cfg(any(feature = "tokio", feature = "async-std"))]
9    SError: Error = <<super::socket::DefaultSocketFactory as super::socket::UdpSocketFactory>::Socket as super::socket::UdpSocket>::Error,
10    #[cfg(all(not(feature = "tokio"), not(feature = "async-std")))]
11    SFError: Error,
12    #[cfg(all(not(feature = "tokio"), not(feature = "async-std")))]
13    SError: Error
14> {
15    /// The underlying `tokio::net::UdpSocket` failed to bind.
16    BindFailed(SFError),
17
18    /// Enabling the broadcast option on the `tokio::net::UdpSocket` failed.
19    SetBroadcastFailed(SError),
20
21    /// Sending the request datagram failed.
22    SendFailed(SocketAddr, SError),
23
24    /// Locking the `tokio::net::UdpSocket` to a specific endpoint via `tokio::net::UdpSocket::connect` failed.
25    ConnectFailed(SocketAddr, SError),
26
27    /// Receiving a datagram failed.
28    ReceiveFailed(SError),
29
30    /// The given instance name is too long.
31    InstanceNameTooLong,
32
33    /// The server send back an invalid response.
34    ProtocolError(BrowserProtocolError),
35}
36
37// Can't automatically derive Debug because it uses conditional type parameters
38impl<SFError: std::error::Error, SError: Error> std::fmt::Debug 
39    for BrowserError<SFError, SError> 
40{
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        use BrowserError::*;
43
44        match self {
45            BindFailed(e) => write!(f, "BindFailed({:?})", e),
46            SetBroadcastFailed(e) => write!(f, "SetBroadcastFailed({:?})", e),
47            SendFailed(addr, e) => write!(f, "SendFailed({:?}, {:?})", addr, e),
48            ConnectFailed(addr, e) => write!(f, "ConnectFailed({:?}, {:?})", addr, e),
49            ReceiveFailed(e) => write!(f, "ReceiveFailed({:?})", e),
50            InstanceNameTooLong => write!(f, "InstanceNameTooLong"),
51            ProtocolError(e) => write!(f, "ProtocolError({:?})", e),
52        }
53    }
54}
55
56impl<SFError: std::error::Error, SError: Error> std::fmt::Display
57    for BrowserError<SFError, SError>
58{
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        use BrowserError::*;
61
62        match self {
63            BindFailed(err) => write!(f, "bind failed: {}", err),
64            SetBroadcastFailed(err) => write!(f, "enabling broadcast option failed: {}", err),
65            SendFailed(addr, err) => write!(f, "sending of datagram to '{}' failed: {}", addr, err),
66            ConnectFailed(addr, err) => write!(f, "connect to '{}' failed: {}", addr, err),
67            ReceiveFailed(err) => write!(f, "receiving of datagram failed: {}", err),
68            InstanceNameTooLong => write!(
69                f,
70                "specified instance name is longer than {} bytes",
71                super::MAX_INSTANCE_NAME_LEN
72            ),
73            ProtocolError(e) => write!(f, "protocol error: {}", e),
74        }
75    }
76}
77
78impl<SFError: Error, SError: Error> Error for BrowserError<SFError, SError> {
79    fn cause(&self) -> Option<&dyn Error> {
80        use BrowserError::*;
81
82        match self {
83            BindFailed(err) => Some(err),
84            SetBroadcastFailed(err) => Some(err),
85            SendFailed(_, err) => Some(err),
86            ConnectFailed(_, err) => Some(err),
87            ReceiveFailed(err) => Some(err),
88            InstanceNameTooLong => None,
89            ProtocolError(err) => Some(err),
90        }
91    }
92}
93
94/// Received an unexpected response from the server
95#[derive(Debug)]
96pub enum BrowserProtocolError {
97    /// An unexpected token was received from the server
98    UnexpectedToken {
99        /// The token that was expected at this location
100        expected: BrowserProtocolToken,
101
102        /// The token that was found
103        found: BrowserProtocolToken,
104    },
105
106    /// The length of the datagram does not match the length
107    /// specified in the packet header.
108    LengthMismatch {
109        /// The size, in bytes, of the datagram
110        datagram: usize,
111
112        /// The size, in bytes, specified in the packet header
113        header: usize,
114    },
115
116    /// Unexpected MBCS string encoding found in the received message
117    InvalidUtf8(std::str::Utf8Error),
118
119    /// There was extraneous data after the parsed message
120    ExtraneousData(Vec<u8>),
121}
122
123impl std::fmt::Display for BrowserProtocolError {
124    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125        use BrowserProtocolError::*;
126
127        match self {
128            UnexpectedToken { expected, found } => {
129                write!(f, "expected {}, but found {}", expected, found)
130            }
131            LengthMismatch { datagram, header } => write!(
132                f,
133                "mismatch between datagram size {} bytes and size specified in header {} bytes",
134                datagram, header
135            ),
136            InvalidUtf8(err) => err.fmt(f),
137            ExtraneousData(data) => write!(f, "{} unexpected trailing bytes", data.len()),
138        }
139    }
140}
141
142impl Error for BrowserProtocolError {}
143
144/// The value that was expected.
145#[derive(Debug)]
146pub enum BrowserProtocolToken {
147    /// End of the datagram
148    EndOfMessage,
149
150    /// A literal string
151    Literal(String),
152
153    /// The message identifier specified in the header
154    MessageIdentifier(u8),
155
156    /// The message length specified in the header
157    MessageLength,
158
159    DacVersion(u8),
160    DacPort,
161    Identifier(BrowserProtocolField),
162    ValueOf(BrowserProtocolField),
163    TcpPort,
164    ViaParameters,
165    EndpointIdentifierOrSemicolon,
166}
167
168impl std::fmt::Display for BrowserProtocolToken {
169    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170        use BrowserProtocolToken::*;
171
172        match self {
173            EndOfMessage => write!(f, "end of message"),
174            Literal(s) => write!(f, "'{}'", s),
175            MessageIdentifier(v) => write!(f, "message identifier {:#X}", v),
176            MessageLength => write!(f, "message length"),
177            DacVersion(v) => write!(f, "dac version {}", v),
178            DacPort => write!(f, "dac port"),
179            Identifier(field) => write!(f, "identifier for field {:?}", field),
180            ValueOf(field) => write!(f, "value for field {:?}", field),
181            TcpPort => write!(f, "tcp port"),
182            ViaParameters => write!(f, "via parameters"),
183            EndpointIdentifierOrSemicolon => write!(f, "endpoint identifier or semicolon"),
184        }
185    }
186}
187
188/// Different fields found in a browser response
189#[derive(Debug, PartialEq, Eq, Copy, Clone)]
190pub enum BrowserProtocolField {
191    ServerName,
192    InstanceName,
193    IsClustered,
194    Version,
195
196    NamedPipeName,
197    TcpPort,
198    ViaMachineName,
199    RpcComputerName,
200    SpxServiceName,
201    AppleTalkObjectName,
202    BvItemName,
203    BvGroupName,
204    BvOrgName,
205}