1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! `SMPP` client error type.
use std::time::Duration;
use rusmpp::{
Command,
tokio_codec::{DecodeError, EncodeError},
values::InterfaceVersion,
};
/// Errors that can occur during `SMPP` operations.
#[non_exhaustive]
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Connection to `SMPP` server failed.
///
/// This error is returned by [`ConnectionBuilder::connect`](crate::builder::ConnectionBuilder::connect).
#[error("Failed to connect to the server: {0}")]
Connect(#[source] std::io::Error),
/// I/O error occurred.
///
/// This error can occur during reading from or writing to the network stream.
///
/// This error can be returned by various methods, such as sending commands or during background operations through the event stream as an [`Event::Error`](crate::event::Event::Error).
#[error("I/O error: {0}")]
Io(#[source] std::io::Error),
/// The connection to the `SMPP` server is closed.
///
/// This can happen when the client tries to send a command on a closed connection.
///
/// This error is returned by methods that send commands, such as [`bind_transceiver`](crate::client::Client::bind_transceiver) and [`submit_sm`](crate::client::Client::submit_sm).
///
/// # Note
///
/// [`Error::ConnectionClosed`] is different from [`Error::ConnectionClosedByPeer`].
///
/// - [`Error::ConnectionClosed`] means that the background connection managing the `SMPP` connection is closed (for example, the user called [`Client::close`](crate::client::Client::close) or the connection encountered a fatal error and closed itself).
/// - [`Error::ConnectionClosedByPeer`] means that the `SMPP` server closed the (TCP) connection unexpectedly.
#[error("Connection closed")]
ConnectionClosed,
/// The connection to the `SMPP` server was closed by the peer.
///
/// This can happen if the server closes the connection unexpectedly.
///
/// This error goes through the event stream as an [`Event::Error`](crate::event::Event::Error).
///
/// # Note
///
/// [`Error::ConnectionClosedByPeer`] is different from [`Error::ConnectionClosed`].
///
/// - [`Error::ConnectionClosedByPeer`] means that the `SMPP` server closed the (TCP) connection unexpectedly.
/// - [`Error::ConnectionClosed`] means that the background connection managing the `SMPP` connection is closed (for example, the user called [`Client::close`](crate::client::Client::close) or the connection encountered a fatal error and closed itself).
#[error("Connection closed by peer")]
ConnectionClosedByPeer,
/// Protocol encode error.
///
/// This error can be returned by various methods, such as sending commands or during background operations through the event stream as an [`Event::Error`](crate::event::Event::Error).
#[error("Protocol encode error: {0}")]
Encode(#[source] EncodeError),
/// Protocol decode error.
///
/// This error can be returned by various methods, such as sending commands or during background operations through the event stream as an [`Event::Error`](crate::event::Event::Error).
#[error("Protocol decode error: {0}")]
Decode(#[source] DecodeError),
/// The `SMPP` server did not respond to the [`EnquireLink`](rusmpp::Pdu::EnquireLink) request within the specified timeout.
///
/// This error goes through the event stream as an [`Event::Error`](crate::event::Event::Error).
#[error("Server did not respond to enquire link: timeout: {timeout:?}")]
EnquireLinkTimeout {
/// The timeout duration.
timeout: Duration,
},
/// The `SMPP` operation timed out.
///
/// The server did not respond to the request within the specified timeout.
///
/// This error is returned by methods that send commands and wait for a response, such as [`bind_transceiver`](crate::client::Client::bind_transceiver) and [`submit_sm`](crate::client::Client::submit_sm).
#[error("Response timed out: sequence number: {sequence_number}, timeout: {timeout:?}")]
ResponseTimeout {
/// The sequence number of the request that timed out.
sequence_number: u32,
/// The timeout duration.
timeout: Duration,
},
/// The `SMPP` operation failed with an error response from the server.
///
/// Error responses are responses with the status code other than [`EsmeRok`](rusmpp::CommandStatus::EsmeRok).
///
/// This error is returned by methods that send commands and wait for a response, such as [`bind_transceiver`](crate::client::Client::bind_transceiver) and [`submit_sm`](crate::client::Client::submit_sm).
#[error("Unexpected response from the server: response: {response:?}")]
UnexpectedResponse {
/// The response that was received from the server.
response: Box<Command>,
},
/// The client used an interface version that is not supported by the library.
///
/// The library supports only `SMPP v5.0`.
///
/// This error is returned by methods that send bind commands, such as [`bind_transceiver`](crate::client::Client::bind_transceiver), [`bind_receiver`](crate::client::Client::bind_receiver), and [`bind_transmitter`](crate::client::Client::bind_transmitter).
#[error("Unsupported interface version: {version:?}, supported version: {supported_version:?}")]
UnsupportedInterfaceVersion {
/// The requested interface version.
version: InterfaceVersion,
/// The version that is supported by the library.
supported_version: InterfaceVersion,
},
}
impl Error {
pub(crate) fn unexpected_response(response: impl Into<Box<Command>>) -> Self {
Self::UnexpectedResponse {
response: response.into(),
}
}
pub(crate) const fn unsupported_interface_version(version: InterfaceVersion) -> Self {
Self::UnsupportedInterfaceVersion {
version,
supported_version: InterfaceVersion::Smpp5_0,
}
}
pub(crate) const fn response_timeout(sequence_number: u32, timeout: Duration) -> Self {
Self::ResponseTimeout {
sequence_number,
timeout,
}
}
}
impl From<DecodeError> for Error {
fn from(value: DecodeError) -> Self {
match value {
DecodeError::Io(error) => Error::Io(error),
error => Error::Decode(error),
}
}
}
impl From<EncodeError> for Error {
fn from(value: EncodeError) -> Self {
match value {
EncodeError::Io(error) => Error::Io(error),
error => Error::Encode(error),
}
}
}