# smpp34
[](https://crates.io/crates/smpp34)
[](https://docs.rs/smpp34)
[](https://github.com/Real-Time-Telecom-B-V/smpp34/actions/workflows/ci.yml)
[](LICENSE)
A pure-Rust implementation of the **SMPP 3.4** protocol (Short Message
Peer-to-Peer): a PDU codec plus an asynchronous ([tokio](https://tokio.rs))
**client** and **server** built on a listener-trait model.
- **Client** — bind to an SMSC as an ESME (transmitter, receiver or
transceiver), send `submit_sm` / `data_sm`, and receive `deliver_sm` and
session events through your own `SmppClientListener`.
- **Server** — accept ESME binds and dispatch `submit_sm`, `data_sm`,
`cancel_sm`, … to your `SmppServerListener`; push MT traffic back out with
`deliver_sm`.
- **Codec** — encode/decode every SMPP 3.4 PDU, including optional TLV
parameters.
Sessions handle the SMPP timers (`session_init`, `enquire_link`, `inactivity`,
`response`), sequence-number windowing, and optional TLS.
## Supported PDUs
`bind_transmitter` · `bind_receiver` · `bind_transceiver` (+ resps) · `outbind`
· `unbind` · `enquire_link` · `submit_sm` · `submit_sm_multi` · `deliver_sm` ·
`data_sm` · `query_sm` · `cancel_sm` · `replace_sm` · `alert_notification` ·
`generic_nack`, plus arbitrary **TLV** (optional parameter) encode/decode.
## Install
```sh
cargo add smpp34
```
## Quick start — server
Implement `SmppServerListener` and hand it to an `SmppServer`. (The trait has
one method per inbound PDU; the snippet below shows the common ones — see the
crate docs for the full set.)
```rust,no_run
use std::sync::Arc;
use std::net::{IpAddr, Ipv4Addr};
use async_trait::async_trait;
use smpp34::{
SmppServer, SmppServerListener, SmppConnectionInformation, SmppError,
bind_transceiver, bind_transceiver_resp, submit_sm, submit_sm_resp,
};
struct MyEsmeHandler;
#[async_trait]
impl SmppServerListener for MyEsmeHandler {
async fn on_bind_transceiver(
&self, req: bind_transceiver, _c: &SmppConnectionInformation, _s: &String,
) -> bind_transceiver_resp {
if req.system_id == "esme1" && req.password == "secret" {
req.accept("MySMSC".to_string(), Some(0x34)) // 0x34 = SMPP v3.4
} else {
req.reject(SmppError::ESME_RINVPASWD)
}
}
async fn on_submit_sm(
&self, req: submit_sm, _c: &SmppConnectionInformation, _s: &String,
) -> submit_sm_resp {
// ... route the message ...
req.accept("message-id-1".to_string())
}
// The trait also requires: on_bind_transmitter, on_bind_receiver, on_unbind,
// on_data_sm, on_cancel_sm, on_timeout, on_esme_bound, on_esme_unbound.
}
#[tokio::main]
async fn main() {
let listener = Arc::new(MyEsmeHandler);
let mut server = SmppServer::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 2775, listener);
server.start().await; // spawns the accept loop
tokio::signal::ctrl_c().await.unwrap();
server.stop().await;
}
```
## Quick start — client
Bind to an SMSC, then submit once the bind completes (the `on_smsc_bound`
callback hands you an `SMSC` you can submit through).
```rust,no_run
use std::sync::Arc;
use smpp34::client::{SmppClient, BIND_TYPE};
// `listener` implements SmppClientListener; its on_smsc_bound callback hands
// you the bound `SMSC` handle to submit through.
let listener = Arc::new(MyClientHandler::new());
let mut client = SmppClient::new(
"smsc.example.net".to_string(), 2775, /* tls = */ false,
BIND_TYPE::TRX,
"esme1".to_string(), "secret".to_string(), "GATEWAY".to_string(),
/* addr_ton */ 0, /* addr_npi */ 0, /* address_range */ String::new(),
listener.clone(),
/* window_size */ 20,
);
client.start().await;
// inside on_smsc_bound(smsc, _):
// smsc.send_submit_sm("", 1, 1, "12345".into(), 1, 1, "31600000000".into(),
// 0, 0, 0, "".into(), "".into(), 0, 0, 0, 0,
// b"hello".to_vec()).await?;
```
## TLS
Pass `tls = true` to `SmppClient::new` to bind over TLS. The TLS transport is
backed by [`tokio-native-tls`](https://crates.io/crates/tokio-native-tls)
(system OpenSSL).
## Timers & windowing
`SmppServer::new` / `SmppClient::new` use sensible default timers. Use the
`*_with_default_timers` constructors to set `session_init`, `enquire_link`,
`inactivity` and `response` timers (milliseconds) and the buffer / window size
explicitly.
## MSRV
Rust **1.80**.
## Stability
The SMPP 3.4 codec and the client/server session handling are used in
production. Until a `1.0` release the public API may still see ergonomic
refinement — pin a minor version if you need stability across `0.x` bumps. See
[`VERSIONING.md`](VERSIONING.md).
## License
[MIT](LICENSE) © Real Time Telecom B.V.
Maintained by [Real Time Telecom B.V.](https://realtime-telecom.nl) — carrier-grade
telecom infrastructure in Rust.