rusmpp_core/pdus/owned/pdu.rs
1use crate::{
2 CommandId,
3 decode::{
4 DecodeError, DecodeResultExt,
5 owned::{Decode, DecodeWithKeyOptional, DecodeWithLength},
6 },
7 encode::{Encode, Length},
8 types::owned::AnyOctetString,
9};
10
11use super::*;
12
13/// `SMPP` PDU.
14#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
15#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
16#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
17#[cfg_attr(feature = "serde-deserialize-unchecked", derive(::serde::Deserialize))]
18pub enum Pdu {
19 /// Authentication PDU used by a transmitter ESME to bind to
20 /// the Message Centre. The PDU contains identification
21 /// information and an access password for the ESME.
22 BindTransmitter(BindTransmitter),
23 /// Message Centre response to a bind_transmitter PDU. This
24 /// PDU indicates the success or failure of the ESME’s attempt
25 /// to bind as a transmitter.
26 BindTransmitterResp(BindTransmitterResp),
27 /// Authentication PDU used by a receiver ESME to bind to the
28 /// Message Centre. The PDU contains identification information,
29 /// an access password for the ESME and may also contain
30 /// routing information specifying the range of addresses
31 /// serviced by the ESME.
32 BindReceiver(BindReceiver),
33 /// Message Centre response to a bind_receiver PDU. This PDU
34 /// indicates the success or failure of the ESME’s attempt to bind
35 /// as a receiver.
36 BindReceiverResp(BindReceiverResp),
37 /// Authentication PDU used by a transceiver ESME to bind to
38 /// the Message Centre. The PDU contains identification
39 /// information, an access password for the ESME and may also
40 /// contain routing information specifying the range of addresses
41 /// serviced by the ESME.
42 BindTransceiver(BindTransceiver),
43 /// Message Centre response to a bind_transceiver PDU. This
44 /// PDU indicates the success or failure of the ESME’s attempt
45 /// to bind as a transceiver.
46 BindTransceiverResp(BindTransceiverResp),
47 /// Authentication PDU used by a Message Centre to Outbind to
48 /// an ESME to inform it that messages are present in the MC.
49 /// The PDU contains identification, and access password for the
50 /// ESME. If the ESME authenticates the request, it will respond
51 /// with a bind_receiver or bind_transceiver to begin the process
52 /// of binding into the MC.
53 Outbind(Outbind),
54 /// The alert_notification PDU is sent by the MC to the ESME across a Receiver or Transceiver
55 /// session. It is sent when the MC has detected that a particular mobile subscriber has become
56 /// available and a delivery pending flag had been previously set for that subscriber by means of
57 /// the set_dpf TLV.
58 ///
59 /// A typical use of this operation is to trigger a data content ‘Push’ to the subscriber from a WAP
60 /// Proxy Server.
61 ///
62 /// Note: There is no associated alert_notification_resp PDU.
63 AlertNotification(AlertNotification),
64 /// This operation is used by an ESME to submit a short message to the MC for onward
65 /// transmission to a specified short message entity (SME).
66 SubmitSm(SubmitSm),
67 SubmitSmResp(SubmitSmResp),
68 /// This command is issued by the ESME to query the status of a previously submitted short
69 /// message.
70 /// The matching mechanism is based on the MC assigned message_id and source address.
71 /// Where the original submit_sm, data_sm or submit_multi ‘source address’ was defaulted to
72 /// NULL, then the source address in the query_sm command should also be set to NULL.
73 QuerySm(QuerySm),
74 QuerySmResp(QuerySmResp),
75 /// The deliver_sm is issued by the MC to send a message to an ESME. Using this command,
76 /// the MC may route a short message to the ESME for delivery.
77 DeliverSm(DeliverSm),
78 DeliverSmResp(DeliverSmResp),
79 /// The data_sm operation is similar to the submit_sm in that it provides a means to submit a
80 /// mobile-terminated message. However, data_sm is intended for packet-based applications
81 /// such as WAP in that it features a reduced PDU body containing fields relevant to WAP or
82 /// packet-based applications.
83 DataSm(DataSm),
84 DataSmResp(DataSmResp),
85 /// This command is issued by the ESME to cancel one or more previously submitted short
86 /// messages that are pending delivery. The command may specify a particular message to
87 /// cancel, or all messages matching a particular source, destination and service_type.
88 ///
89 /// If the message_id is set to the ID of a previously submitted message, then provided the
90 /// source address supplied by the ESME matches that of the stored message, that message
91 /// will be cancelled.
92 ///
93 /// If the message_id is NULL, all outstanding undelivered messages with matching source and
94 /// destination addresses (and service_type if specified) are cancelled.
95 /// Where the original submit_sm, data_sm or submit_multi ‘source address’ is defaulted to
96 /// NULL, then the source address in the cancel_sm command should also be NULL.
97 CancelSm(CancelSm),
98 /// This command is issued by the ESME to replace a previously submitted short message that
99 /// is pending delivery. The matching mechanism is based on the message_id and source
100 /// address of the original message.
101 ///
102 /// Where the original submit_sm ‘source address’ was defaulted to NULL, then the source
103 /// address in the replace_sm command should also be NULL.
104 ReplaceSm(ReplaceSm),
105 /// The submit_multi operation is an enhanced variation of submit_sm designed to support up to
106 /// 255 different destinations instead of the default single destination. It provides an efficient
107 /// means of sending the same message to several different subscribers at the same time.
108 SubmitMulti(SubmitMulti),
109 SubmitMultiResp(SubmitMultiResp),
110 /// This operation is issued by the ESME to submit a message to the Message Centre for
111 /// broadcast to a specified geographical area or set of geographical areas.
112 BroadcastSm(BroadcastSm),
113 BroadcastSmResp(BroadcastSmResp),
114 /// This command is issued by the ESME to query the status of a previously submitted
115 /// broadcast message. The message can be queried either on the basis of the Message Center
116 /// assigned reference message_id returned in the broadcast_sm_resp or by the ESME
117 /// assigned message reference number user_message_reference as indicated in the
118 /// broadcast_sm operation associated with that message.
119 ///
120 /// Note: Where the broadcast is queried on the basis of the ESME assigned message
121 /// reference user_message_reference this should be qualified within the service by the
122 /// system_id and/or the system_type associated with the query_broadcast_sm operation
123 /// (specified in the bind operation). If more than one message with the same
124 /// user_message_reference value is present in the Message Center, the details of the most
125 /// recently submitted message with the specified user_message_reference value will be
126 /// returned in the query_broadcast_sm_resp.
127 QueryBroadcastSm(QueryBroadcastSm),
128 QueryBroadcastSmResp(QueryBroadcastSmResp),
129 /// This command is issued by the ESME to cancel a broadcast message which has been
130 /// previously submitted to the Message Centre for broadcast via broadcast_sm and which is still
131 /// pending delivery.
132 ///
133 /// If the message_id is set to the ID of a previously submitted message, then provided the
134 /// source address supplied by the ESME matches that of the stored message, that message
135 /// will be cancelled.
136 ///
137 /// If the message_id is NULL, all outstanding undelivered messages with matching source and
138 /// destination addresses (and service_type if specified) are cancelled.
139 ///
140 /// If the user_message_reference is set to the ESME-assigned reference of a previously
141 /// submitted message, then provided the source address supplied by the ESME matches that of
142 /// the stored message, that message will be cancelled.
143 ///
144 /// Where the original broadcast_sm ‘source address’ was defaulted to NULL, then the source
145 /// address in the cancel_broadcast_sm command should also be NULL.
146 CancelBroadcastSm(CancelBroadcastSm),
147 /// This PDU can be sent by the ESME or MC as a means of
148 /// initiating the termination of a `SMPP` session.
149 Unbind,
150 /// This PDU can be sent by the ESME or MC as a means of
151 /// acknowledging the receipt of an unbind request. After
152 /// sending this PDU the MC typically closes the network
153 /// connection.
154 UnbindResp,
155 /// This PDU can be sent by the ESME or MC to test the network
156 /// connection. The receiving peer is expected to acknowledge
157 /// the PDU as a means of verifying the test.
158 EnquireLink,
159 /// This PDU is used to acknowledge an enquire_link request
160 /// sent by an ESME or MC.
161 EnquireLinkResp,
162 /// This PDU can be sent by an ESME or MC as a means of
163 /// indicating the receipt of an invalid PDU. The receipt of a
164 /// generic_nack usually indicates that the remote peer either
165 /// cannot identify the PDU or has deemed it an invalid PDU due
166 /// to its size or content.
167 GenericNack,
168 /// The MC returns this PDU to indicate the success or failure of
169 /// a cancel_sm PDU.
170 CancelSmResp,
171 /// The replace_sm_resp PDU indicates the success or failure of
172 /// a replace_sm PDU.
173 ReplaceSmResp,
174 /// The MC returns a query_broadcast_sm_resp PDU as a
175 /// means of indicating the result of a broadcast query
176 /// attempt. The PDU will indicate the success or failure of the
177 /// attempt and for successful attempts will also include the
178 /// current state of the message.
179 CancelBroadcastSmResp,
180 Other {
181 command_id: CommandId,
182 body: AnyOctetString,
183 },
184}
185
186impl Pdu {
187 pub const fn command_id(&self) -> CommandId {
188 match self {
189 Pdu::BindTransmitter(_) => CommandId::BindTransmitter,
190 Pdu::BindTransmitterResp(_) => CommandId::BindTransmitterResp,
191 Pdu::BindReceiver(_) => CommandId::BindReceiver,
192 Pdu::BindReceiverResp(_) => CommandId::BindReceiverResp,
193 Pdu::BindTransceiver(_) => CommandId::BindTransceiver,
194 Pdu::BindTransceiverResp(_) => CommandId::BindTransceiverResp,
195 Pdu::Outbind(_) => CommandId::Outbind,
196 Pdu::AlertNotification(_) => CommandId::AlertNotification,
197 Pdu::SubmitSm(_) => CommandId::SubmitSm,
198 Pdu::SubmitSmResp(_) => CommandId::SubmitSmResp,
199 Pdu::QuerySm(_) => CommandId::QuerySm,
200 Pdu::QuerySmResp(_) => CommandId::QuerySmResp,
201 Pdu::DeliverSm(_) => CommandId::DeliverSm,
202 Pdu::DeliverSmResp(_) => CommandId::DeliverSmResp,
203 Pdu::DataSm(_) => CommandId::DataSm,
204 Pdu::DataSmResp(_) => CommandId::DataSmResp,
205 Pdu::CancelSm(_) => CommandId::CancelSm,
206 Pdu::ReplaceSm(_) => CommandId::ReplaceSm,
207 Pdu::SubmitMulti(_) => CommandId::SubmitMulti,
208 Pdu::SubmitMultiResp(_) => CommandId::SubmitMultiResp,
209 Pdu::BroadcastSm(_) => CommandId::BroadcastSm,
210 Pdu::BroadcastSmResp(_) => CommandId::BroadcastSmResp,
211 Pdu::QueryBroadcastSm(_) => CommandId::QueryBroadcastSm,
212 Pdu::QueryBroadcastSmResp(_) => CommandId::QueryBroadcastSmResp,
213 Pdu::CancelBroadcastSm(_) => CommandId::CancelBroadcastSm,
214 Pdu::Other { command_id, .. } => *command_id,
215 // These are empty pdus.
216 // The reason they exist is to force the creation of a command with the correct command_id using a pdu.
217 Pdu::Unbind => CommandId::Unbind,
218 Pdu::UnbindResp => CommandId::UnbindResp,
219 Pdu::EnquireLink => CommandId::EnquireLink,
220 Pdu::EnquireLinkResp => CommandId::EnquireLinkResp,
221 Pdu::GenericNack => CommandId::GenericNack,
222 Pdu::CancelSmResp => CommandId::CancelSmResp,
223 Pdu::ReplaceSmResp => CommandId::ReplaceSmResp,
224 Pdu::CancelBroadcastSmResp => CommandId::CancelBroadcastSmResp,
225 }
226 }
227}
228
229impl Length for Pdu {
230 fn length(&self) -> usize {
231 match self {
232 Pdu::BindTransmitter(body) => body.length(),
233 Pdu::BindTransmitterResp(body) => body.length(),
234 Pdu::BindReceiver(body) => body.length(),
235 Pdu::BindReceiverResp(body) => body.length(),
236 Pdu::BindTransceiver(body) => body.length(),
237 Pdu::BindTransceiverResp(body) => body.length(),
238 Pdu::Outbind(body) => body.length(),
239 Pdu::AlertNotification(body) => body.length(),
240 Pdu::SubmitSm(body) => body.length(),
241 Pdu::SubmitSmResp(body) => body.length(),
242 Pdu::QuerySm(body) => body.length(),
243 Pdu::QuerySmResp(body) => body.length(),
244 Pdu::DeliverSm(body) => body.length(),
245 Pdu::DeliverSmResp(body) => body.length(),
246 Pdu::DataSm(body) => body.length(),
247 Pdu::DataSmResp(body) => body.length(),
248 Pdu::CancelSm(body) => body.length(),
249 Pdu::ReplaceSm(body) => body.length(),
250 Pdu::SubmitMulti(body) => body.length(),
251 Pdu::SubmitMultiResp(body) => body.length(),
252 Pdu::BroadcastSm(body) => body.length(),
253 Pdu::BroadcastSmResp(body) => body.length(),
254 Pdu::QueryBroadcastSm(body) => body.length(),
255 Pdu::QueryBroadcastSmResp(body) => body.length(),
256 Pdu::CancelBroadcastSm(body) => body.length(),
257 Pdu::Unbind => 0,
258 Pdu::UnbindResp => 0,
259 Pdu::EnquireLink => 0,
260 Pdu::EnquireLinkResp => 0,
261 Pdu::GenericNack => 0,
262 Pdu::CancelSmResp => 0,
263 Pdu::ReplaceSmResp => 0,
264 Pdu::CancelBroadcastSmResp => 0,
265 Pdu::Other { body, .. } => body.length(),
266 }
267 }
268}
269
270impl Encode for Pdu {
271 fn encode(&self, dst: &mut [u8]) -> usize {
272 match self {
273 Pdu::BindTransmitter(body) => body.encode(dst),
274 Pdu::BindTransmitterResp(body) => body.encode(dst),
275 Pdu::BindReceiver(body) => body.encode(dst),
276 Pdu::BindReceiverResp(body) => body.encode(dst),
277 Pdu::BindTransceiver(body) => body.encode(dst),
278 Pdu::BindTransceiverResp(body) => body.encode(dst),
279 Pdu::Outbind(body) => body.encode(dst),
280 Pdu::AlertNotification(body) => body.encode(dst),
281 Pdu::SubmitSm(body) => body.encode(dst),
282 Pdu::SubmitSmResp(body) => body.encode(dst),
283 Pdu::QuerySm(body) => body.encode(dst),
284 Pdu::QuerySmResp(body) => body.encode(dst),
285 Pdu::DeliverSm(body) => body.encode(dst),
286 Pdu::DeliverSmResp(body) => body.encode(dst),
287 Pdu::DataSm(body) => body.encode(dst),
288 Pdu::DataSmResp(body) => body.encode(dst),
289 Pdu::CancelSm(body) => body.encode(dst),
290 Pdu::ReplaceSm(body) => body.encode(dst),
291 Pdu::SubmitMulti(body) => body.encode(dst),
292 Pdu::SubmitMultiResp(body) => body.encode(dst),
293 Pdu::BroadcastSm(body) => body.encode(dst),
294 Pdu::BroadcastSmResp(body) => body.encode(dst),
295 Pdu::QueryBroadcastSm(body) => body.encode(dst),
296 Pdu::QueryBroadcastSmResp(body) => body.encode(dst),
297 Pdu::CancelBroadcastSm(body) => body.encode(dst),
298 Pdu::Unbind
299 | Pdu::UnbindResp
300 | Pdu::EnquireLink
301 | Pdu::EnquireLinkResp
302 | Pdu::GenericNack
303 | Pdu::CancelSmResp
304 | Pdu::ReplaceSmResp
305 | Pdu::CancelBroadcastSmResp => 0,
306 Pdu::Other { body, .. } => body.encode(dst),
307 }
308 }
309}
310
311impl DecodeWithKeyOptional for Pdu {
312 type Key = CommandId;
313
314 fn decode(
315 key: Self::Key,
316 src: &[u8],
317 length: usize,
318 ) -> Result<Option<(Self, usize)>, DecodeError> {
319 if length == 0 {
320 let body = match key {
321 CommandId::Unbind => Pdu::Unbind,
322 CommandId::UnbindResp => Pdu::UnbindResp,
323 CommandId::EnquireLink => Pdu::EnquireLink,
324 CommandId::EnquireLinkResp => Pdu::EnquireLinkResp,
325 CommandId::GenericNack => Pdu::GenericNack,
326 CommandId::CancelSmResp => Pdu::CancelSmResp,
327 CommandId::ReplaceSmResp => Pdu::ReplaceSmResp,
328 CommandId::CancelBroadcastSmResp => Pdu::CancelBroadcastSmResp,
329 _ => return Ok(None),
330 };
331
332 return Ok(Some((body, 0)));
333 }
334
335 let (body, size) = match key {
336 CommandId::BindTransmitter => Decode::decode(src).map_decoded(Self::BindTransmitter)?,
337 CommandId::BindTransmitterResp => {
338 DecodeWithLength::decode(src, length).map_decoded(Self::BindTransmitterResp)?
339 }
340 CommandId::BindReceiver => Decode::decode(src).map_decoded(Self::BindReceiver)?,
341 CommandId::BindReceiverResp => {
342 DecodeWithLength::decode(src, length).map_decoded(Self::BindReceiverResp)?
343 }
344 CommandId::BindTransceiver => Decode::decode(src).map_decoded(Self::BindTransceiver)?,
345 CommandId::BindTransceiverResp => {
346 DecodeWithLength::decode(src, length).map_decoded(Self::BindTransceiverResp)?
347 }
348 CommandId::Outbind => Decode::decode(src).map_decoded(Self::Outbind)?,
349 CommandId::AlertNotification => {
350 DecodeWithLength::decode(src, length).map_decoded(Self::AlertNotification)?
351 }
352 CommandId::SubmitSm => SubmitSm::decode(src, length).map_decoded(Self::SubmitSm)?,
353 CommandId::SubmitSmResp => {
354 DecodeWithLength::decode(src, length).map_decoded(Self::SubmitSmResp)?
355 }
356 CommandId::QuerySm => Decode::decode(src).map_decoded(Self::QuerySm)?,
357 CommandId::QuerySmResp => Decode::decode(src).map_decoded(Self::QuerySmResp)?,
358 CommandId::DeliverSm => {
359 DecodeWithLength::decode(src, length).map_decoded(Self::DeliverSm)?
360 }
361 CommandId::DeliverSmResp => {
362 DecodeWithLength::decode(src, length).map_decoded(Self::DeliverSmResp)?
363 }
364 CommandId::DataSm => DecodeWithLength::decode(src, length).map_decoded(Self::DataSm)?,
365 CommandId::DataSmResp => {
366 DecodeWithLength::decode(src, length).map_decoded(Self::DataSmResp)?
367 }
368 CommandId::CancelSm => Decode::decode(src).map_decoded(Self::CancelSm)?,
369 CommandId::ReplaceSm => {
370 DecodeWithLength::decode(src, length).map_decoded(Self::ReplaceSm)?
371 }
372 CommandId::SubmitMulti => {
373 DecodeWithLength::decode(src, length).map_decoded(Self::SubmitMulti)?
374 }
375 CommandId::SubmitMultiResp => {
376 DecodeWithLength::decode(src, length).map_decoded(Self::SubmitMultiResp)?
377 }
378 CommandId::BroadcastSm => {
379 DecodeWithLength::decode(src, length).map_decoded(Self::BroadcastSm)?
380 }
381 CommandId::BroadcastSmResp => {
382 DecodeWithLength::decode(src, length).map_decoded(Self::BroadcastSmResp)?
383 }
384 CommandId::QueryBroadcastSm => {
385 DecodeWithLength::decode(src, length).map_decoded(Self::QueryBroadcastSm)?
386 }
387 CommandId::QueryBroadcastSmResp => {
388 DecodeWithLength::decode(src, length).map_decoded(Self::QueryBroadcastSmResp)?
389 }
390 CommandId::CancelBroadcastSm => {
391 DecodeWithLength::decode(src, length).map_decoded(Self::CancelBroadcastSm)?
392 }
393 CommandId::Other(_) => {
394 DecodeWithLength::decode(src, length).map_decoded(|body| Pdu::Other {
395 command_id: key,
396 body,
397 })?
398 }
399 // Length is not 0 and still have to decode the body. This is an invalid PDU.
400 CommandId::Unbind
401 | CommandId::UnbindResp
402 | CommandId::EnquireLink
403 | CommandId::EnquireLinkResp
404 | CommandId::GenericNack
405 | CommandId::CancelSmResp
406 | CommandId::ReplaceSmResp
407 | CommandId::CancelBroadcastSmResp => return Ok(None),
408 };
409
410 Ok(Some((body, size)))
411 }
412}