smpp_codec/pdus/session_pdus/bind_response.rs
1// bind_response.rs (Handles both Encoder and Decoder)
2use crate::common::{get_status_code, get_status_description, PduError, HEADER_LEN};
3use std::io::{Cursor, Read, Write};
4
5/// Represents a Bind Response PDU.
6///
7/// Sent by the SMSC in response to a Bind Request.
8#[derive(Debug, Clone)]
9pub struct BindResponse {
10 pub sequence_number: u32,
11 pub command_status: u32, // 0 = OK, others = Error
12 pub status_description: String, // Human-readable description of status
13 pub command_id: u32, // e.g., 0x80000009 (bind_transceiver_resp)
14 pub system_id: String, // SMSC ID
15 pub optional_params: Vec<u8>, // Rarely used in Bind Resp, but allowed
16}
17
18impl BindResponse {
19 /// Create a new Bind Response.
20 ///
21 /// # Examples
22 ///
23 /// ```
24 /// use smpp_codec::pdus::BindResponse;
25 /// use smpp_codec::common::{CMD_BIND_TRANSCEIVER_RESP, BindMode};
26 ///
27 /// let sequence_number: u32 = 1;
28 /// let resp = BindResponse::new(
29 /// sequence_number,
30 /// CMD_BIND_TRANSCEIVER_RESP,
31 /// "ESME_ROK",
32 /// "system_id".to_string()
33 /// );
34 /// ```
35 pub fn new(
36 sequence_number: u32,
37 command_id: u32,
38 status_name: &str,
39 system_id: String,
40 ) -> Self {
41 let command_status = get_status_code(status_name);
42 Self {
43 sequence_number,
44 command_id,
45 command_status,
46 status_description: status_name.to_string(),
47 system_id,
48 optional_params: Vec::new(),
49 }
50 }
51
52 /// Encode the struct into raw bytes for the network.
53 ///
54 /// # Errors
55 ///
56 /// Returns a [`PduError`] if:
57 /// * An I/O error occurs while writing.
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// # use smpp_codec::pdus::BindResponse;
63 /// # use smpp_codec::common::CMD_BIND_TRANSMITTER_RESP;
64 /// # let sequence_number: u32 = 1;
65 /// # let bind_resp = BindResponse::new(sequence_number, CMD_BIND_TRANSMITTER_RESP, "ESME_ROK", "id".into());
66 /// let mut buffer = Vec::new();
67 /// bind_resp.encode(&mut buffer).expect("Encoding failed");
68 /// ```
69 pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
70 let mut body = Vec::new();
71
72 // If status is OK, we must include system_id.
73 // On error, body can be empty (or just header).
74 if self.command_status == 0 {
75 body.write_all(self.system_id.as_bytes())?;
76 body.write_all(&[0])?; // Null terminator
77
78 // Add optional params if any
79 body.write_all(&self.optional_params)?;
80 }
81
82 let command_len = (HEADER_LEN + body.len()) as u32;
83
84 // Write Header
85 writer.write_all(&command_len.to_be_bytes())?;
86 writer.write_all(&self.command_id.to_be_bytes())?;
87 writer.write_all(&self.command_status.to_be_bytes())?;
88 writer.write_all(&self.sequence_number.to_be_bytes())?;
89
90 // Write Body
91 writer.write_all(&body)?;
92
93 Ok(())
94 }
95
96 /// Decode raw bytes from the network into the struct.
97 ///
98 /// # Errors
99 ///
100 /// Returns a [`PduError`] if:
101 /// * The buffer is too short.
102 /// * The buffer data is malformed.
103 ///
104 /// # Examples
105 ///
106 /// ```
107 /// # use smpp_codec::pdus::BindResponse;
108 /// # use smpp_codec::common::CMD_BIND_TRANSCEIVER_RESP;
109 /// # let sequence_number: u32 = 1;
110 /// # let resp = BindResponse::new(sequence_number, CMD_BIND_TRANSCEIVER_RESP, "ESME_ROK", "id".into());
111 /// # let mut buffer = Vec::new();
112 /// # resp.encode(&mut buffer).unwrap();
113 /// let decoded = BindResponse::decode(&buffer).expect("Decoding failed");
114 /// assert_eq!(decoded.sequence_number, 1);
115 /// ```
116 pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
117 if buffer.len() < HEADER_LEN {
118 return Err(PduError::BufferTooShort);
119 }
120
121 let mut cursor = Cursor::new(buffer);
122
123 // 1. Read Header
124 let mut bytes = [0u8; 4];
125
126 cursor.read_exact(&mut bytes)?;
127 let command_len = u32::from_be_bytes(bytes) as usize;
128
129 cursor.read_exact(&mut bytes)?;
130 let command_id = u32::from_be_bytes(bytes);
131
132 cursor.read_exact(&mut bytes)?;
133 let command_status = u32::from_be_bytes(bytes);
134
135 cursor.read_exact(&mut bytes)?;
136 let sequence_number = u32::from_be_bytes(bytes);
137
138 // 2. Read Body
139 let system_id: String;
140 let mut optional_params = Vec::new();
141
142 // Only try to read body if length > header
143 if command_len > HEADER_LEN {
144 // The cursor is currently at pos 16 (end of header).
145 // Read system_id (C-String)
146 if command_status == 0 {
147 system_id = crate::common::read_c_string(&mut cursor)?;
148 } else {
149 system_id = String::new();
150 }
151 } else {
152 system_id = String::new();
153 }
154
155 // Optional Params
156 // optional_params reused from above
157 let current_pos = cursor.position() as usize;
158 if current_pos < command_len {
159 let remaining_len = command_len - current_pos;
160 let mut temp_buf = vec![0u8; remaining_len];
161 cursor.read_exact(&mut temp_buf)?;
162 optional_params = temp_buf;
163 }
164
165 let status_description = get_status_description(command_status);
166
167 Ok(Self {
168 sequence_number,
169 command_status,
170 status_description,
171 command_id,
172 system_id,
173 optional_params,
174 })
175 }
176}