smpp_codec/pdus/session_pdus/unbind.rs
1use crate::common::{
2 get_status_code, get_status_description, PduError, CMD_UNBIND, CMD_UNBIND_RESP, HEADER_LEN,
3};
4use std::io::{Cursor, Read, Write};
5
6// --- Unbind Request ---
7/// Represents an Unbind Request PDU.
8///
9/// Used to request the termination of a session.
10#[derive(Debug, Clone, PartialEq)]
11pub struct UnbindRequest {
12 /// Sequence number of the PDU
13 pub sequence_number: u32,
14}
15
16impl UnbindRequest {
17 /// Create a new Unbind Request.
18 ///
19 /// # Examples
20 ///
21 /// ```
22 /// use smpp_codec::pdus::UnbindRequest;
23 ///
24 /// let sequence_number: u32 = 1;
25 /// let unbind_req = UnbindRequest::new(sequence_number);
26 /// ```
27 pub fn new(sequence_number: u32) -> Self {
28 Self { sequence_number }
29 }
30
31 /// Encode the struct into raw bytes for the network.
32 ///
33 /// # Errors
34 ///
35 /// Returns a [`PduError`] if an I/O error occurs while writing.
36 ///
37 /// # Examples
38 ///
39 /// ```
40 /// # use smpp_codec::pdus::UnbindRequest;
41 /// # let sequence_number: u32 = 1;
42 /// # let unbind_req = UnbindRequest::new(sequence_number);
43 /// let mut buffer = Vec::new();
44 /// unbind_req.encode(&mut buffer).expect("Encoding failed");
45 /// ```
46 pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
47 let command_len = HEADER_LEN as u32;
48 writer.write_all(&command_len.to_be_bytes())?;
49 writer.write_all(&CMD_UNBIND.to_be_bytes())?;
50 writer.write_all(&0u32.to_be_bytes())?; // Status always 0 for requests
51 writer.write_all(&self.sequence_number.to_be_bytes())?;
52 Ok(())
53 }
54
55 /// Decode raw bytes from the network into the struct.
56 ///
57 /// # Errors
58 ///
59 /// Returns a [`PduError`] if the buffer is too short.
60 ///
61 /// # Examples
62 ///
63 /// ```
64 /// # use smpp_codec::pdus::UnbindRequest;
65 /// # let sequence_number: u32 = 1;
66 /// # let unbind_req = UnbindRequest::new(sequence_number);
67 /// # let mut buffer = Vec::new();
68 /// # unbind_req.encode(&mut buffer).unwrap();
69 /// let decoded = UnbindRequest::decode(&buffer).expect("Decoding failed");
70 /// assert_eq!(decoded.sequence_number, 1);
71 /// ```
72 pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
73 if buffer.len() < HEADER_LEN {
74 return Err(PduError::BufferTooShort);
75 }
76 let mut cursor = Cursor::new(buffer);
77 cursor.set_position(12); // Skip len, id, status
78
79 let mut bytes = [0u8; 4];
80 cursor.read_exact(&mut bytes)?;
81 let sequence_number = u32::from_be_bytes(bytes);
82
83 Ok(Self { sequence_number })
84 }
85}
86
87// --- Unbind Response ---
88/// Represents an Unbind Response PDU.
89///
90/// Sent by the SMSC in response to an Unbind Request.
91#[derive(Debug, Clone, PartialEq)]
92pub struct UnbindResponse {
93 /// Sequence number of the PDU
94 pub sequence_number: u32,
95 /// Command Status (0 = OK, others = Error)
96 pub command_status: u32,
97 /// Human-readable description of status
98 pub status_description: String,
99}
100
101impl UnbindResponse {
102 /// Create a new Unbind Response.
103 ///
104 /// # Examples
105 ///
106 /// ```
107 /// use smpp_codec::pdus::UnbindResponse;
108 ///
109 /// let sequence_number: u32 = 1;
110 /// let unbind_resp = UnbindResponse::new(sequence_number, "ESME_ROK");
111 /// ```
112 pub fn new(sequence_number: u32, status_name: &str) -> Self {
113 let command_status = get_status_code(status_name);
114 Self {
115 sequence_number,
116 command_status,
117 status_description: status_name.to_string(),
118 }
119 }
120
121 /// Encode the struct into raw bytes for the network.
122 ///
123 /// # Errors
124 ///
125 /// Returns a [`PduError`] if an I/O error occurs while writing.
126 ///
127 /// # Examples
128 ///
129 /// ```
130 /// # use smpp_codec::pdus::UnbindResponse;
131 /// # let sequence_number: u32 = 1;
132 /// # let unbind_resp = UnbindResponse::new(sequence_number, "ESME_ROK");
133 /// let mut buffer = Vec::new();
134 /// unbind_resp.encode(&mut buffer).expect("Encoding failed");
135 /// ```
136 pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
137 let command_len = HEADER_LEN as u32;
138 writer.write_all(&command_len.to_be_bytes())?;
139 writer.write_all(&CMD_UNBIND_RESP.to_be_bytes())?;
140 writer.write_all(&self.command_status.to_be_bytes())?;
141 writer.write_all(&self.sequence_number.to_be_bytes())?;
142 Ok(())
143 }
144
145 /// Decode raw bytes from the network into the struct.
146 ///
147 /// # Errors
148 ///
149 /// Returns a [`PduError`] if the buffer is too short.
150 ///
151 /// # Examples
152 ///
153 /// ```
154 /// # use smpp_codec::pdus::UnbindResponse;
155 /// # let sequence_number: u32 = 1;
156 /// # let unbind_resp = UnbindResponse::new(sequence_number, "ESME_ROK");
157 /// # let mut buffer = Vec::new();
158 /// # unbind_resp.encode(&mut buffer).unwrap();
159 /// let decoded = UnbindResponse::decode(&buffer).expect("Decoding failed");
160 /// assert_eq!(decoded.sequence_number, 1);
161 /// ```
162 pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
163 if buffer.len() < HEADER_LEN {
164 return Err(PduError::BufferTooShort);
165 }
166 let mut cursor = Cursor::new(buffer);
167
168 // Skip Length (4) + ID (4)
169 cursor.set_position(8);
170
171 let mut bytes = [0u8; 4];
172
173 // Read Status
174 cursor.read_exact(&mut bytes)?;
175 let command_status = u32::from_be_bytes(bytes);
176
177 // Read Sequence
178 cursor.read_exact(&mut bytes)?;
179 let sequence_number = u32::from_be_bytes(bytes);
180
181 Ok(Self {
182 sequence_number,
183 command_status,
184 status_description: get_status_description(command_status),
185 })
186 }
187}