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