Skip to main content

smpp_codec/pdus/delivery_pdus/
data_sm_request.rs

1use crate::common::{read_c_string, write_c_string, Npi, PduError, Ton, CMD_DATA_SM, HEADER_LEN};
2use crate::tlv::{tags, Tlv};
3use std::io::{Cursor, Read, Write};
4
5/// Represents a Data SM Request PDU.
6///
7/// Used to transfer data between the SMSC and the ESME.
8/// It is an alternative to `SubmitSm` and `DeliverSm`.
9#[derive(Debug, Clone, PartialEq)]
10pub struct DataSm {
11    /// Sequence number of the PDU
12    pub sequence_number: u32,
13    /// Service Type
14    pub service_type: String,
15    /// Source Address Type of Number
16    pub source_addr_ton: Ton,
17    /// Source Address Numbering Plan Indicator
18    pub source_addr_npi: Npi,
19    /// Source Address
20    pub source_addr: String,
21    /// Destination Address Type of Number
22    pub dest_addr_ton: Ton,
23    /// Destination Address Numbering Plan Indicator
24    pub dest_addr_npi: Npi,
25    /// Destination Address
26    pub dest_addr: String,
27    /// ESM Class
28    pub esm_class: u8,
29    /// Registered Delivery
30    pub registered_delivery: u8,
31    /// Data Coding Scheme
32    pub data_coding: u8,
33    /// Optional Parameters (Payload goes here via 'message_payload')
34    pub optional_params: Vec<Tlv>, // Payload goes here via 'message_payload'
35}
36
37impl DataSm {
38    /// Create a new Data SM Request.
39    ///
40    /// # Examples
41    ///
42    /// ```
43    /// use smpp_codec::pdus::DataSm;
44    ///
45    /// let pdu = DataSm::new(
46    ///     1,
47    ///     "Source".to_string(),
48    ///     "Dest".to_string(),
49    ///     b"Payload".to_vec(),
50    /// );
51    /// ```
52    pub fn new(
53        sequence_number: u32,
54        source_addr: String,
55        dest_addr: String,
56        payload: Vec<u8>,
57    ) -> Self {
58        let mut pdu = Self {
59            sequence_number,
60            service_type: String::new(),
61            source_addr_ton: Ton::Unknown,
62            source_addr_npi: Npi::Unknown,
63            source_addr,
64            dest_addr_ton: Ton::Unknown,
65            dest_addr_npi: Npi::Unknown,
66            dest_addr,
67            esm_class: 0,
68            registered_delivery: 0,
69            data_coding: 0,
70            optional_params: Vec::new(),
71        };
72
73        // DataSm relies on TLV for the body
74        pdu.add_tlv(Tlv::new(tags::MESSAGE_PAYLOAD, payload));
75        pdu
76    }
77
78    /// Add a TLV to the optional parameters.
79    pub fn add_tlv(&mut self, tlv: Tlv) {
80        self.optional_params.push(tlv);
81    }
82
83    /// Encode the PDU into the writer.
84    ///
85    /// # Errors
86    ///
87    /// Returns a [`PduError`] if the write fails.
88    pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
89        // Calculate Body Length
90        // ServiceType(N+1)
91        // Src(1+1+N+1)
92        // Dest(1+1+N+1)
93        // Flags(1+1+1)
94        // TLVs
95        let tlvs_len: usize = self
96            .optional_params
97            .iter()
98            .map(|tlv| 4 + tlv.length as usize)
99            .sum();
100
101        let body_len = self.service_type.len() + 1 +
102                       1 + 1 + self.source_addr.len() + 1 +
103                       1 + 1 + self.dest_addr.len() + 1 +
104                       1 + 1 + 1 + // esm_class, reg_del, data_coding
105                       tlvs_len;
106
107        let command_len = (HEADER_LEN + body_len) as u32;
108
109        writer.write_all(&command_len.to_be_bytes())?;
110        writer.write_all(&CMD_DATA_SM.to_be_bytes())?;
111        writer.write_all(&0u32.to_be_bytes())?;
112        writer.write_all(&self.sequence_number.to_be_bytes())?;
113
114        write_c_string(writer, &self.service_type)?;
115
116        writer.write_all(&[self.source_addr_ton as u8, self.source_addr_npi as u8])?;
117        write_c_string(writer, &self.source_addr)?;
118
119        writer.write_all(&[self.dest_addr_ton as u8, self.dest_addr_npi as u8])?;
120        write_c_string(writer, &self.dest_addr)?;
121
122        writer.write_all(&[self.esm_class, self.registered_delivery, self.data_coding])?;
123
124        for tlv in &self.optional_params {
125            tlv.encode(writer)?;
126        }
127        Ok(())
128    }
129
130    /// Decode the PDU from the buffer.
131    ///
132    /// # Errors
133    ///
134    /// Returns a [`PduError`] if the buffer is too short or malformed.
135    pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
136        if buffer.len() < HEADER_LEN {
137            return Err(PduError::BufferTooShort);
138        }
139        let mut cursor = Cursor::new(buffer);
140        cursor.set_position(12);
141
142        let mut bytes = [0u8; 4];
143        cursor.read_exact(&mut bytes)?;
144        let sequence_number = u32::from_be_bytes(bytes);
145
146        let service_type = read_c_string(&mut cursor)?;
147
148        let mut u8_buf = [0u8; 1];
149
150        // Source
151        cursor.read_exact(&mut u8_buf)?;
152        let source_addr_ton = Ton::from(u8_buf[0]);
153        cursor.read_exact(&mut u8_buf)?;
154        let source_addr_npi = Npi::from(u8_buf[0]);
155        let source_addr = read_c_string(&mut cursor)?;
156
157        // Destination
158        cursor.read_exact(&mut u8_buf)?;
159        let dest_addr_ton = Ton::from(u8_buf[0]);
160        cursor.read_exact(&mut u8_buf)?;
161        let dest_addr_npi = Npi::from(u8_buf[0]);
162        let dest_addr = read_c_string(&mut cursor)?;
163
164        // Flags
165        cursor.read_exact(&mut u8_buf)?;
166        let esm_class = u8_buf[0];
167        cursor.read_exact(&mut u8_buf)?;
168        let registered_delivery = u8_buf[0];
169        cursor.read_exact(&mut u8_buf)?;
170        let data_coding = u8_buf[0];
171
172        let mut optional_params = Vec::new();
173        while let Some(tlv) = Tlv::decode(&mut cursor)? {
174            optional_params.push(tlv);
175        }
176
177        Ok(Self {
178            sequence_number,
179            service_type,
180            source_addr_ton,
181            source_addr_npi,
182            source_addr,
183            dest_addr_ton,
184            dest_addr_npi,
185            dest_addr,
186            esm_class,
187            registered_delivery,
188            data_coding,
189            optional_params,
190        })
191    }
192}