sccp-protocol 0.3.6

Cisco SCCP (Skinny Client Control Protocol) codec/server
Documentation

Typed Skinny Client Control Protocol messages and an asynchronous station server.

The crate separates the phone-facing wire protocol from the call-control application. [Server] owns station connections and translates inbound packets into semantic [Event] values. Applications respond through a cloneable [ServerHandle] using typed [Command] values; no SIP or PBX policy is built into this crate.

Typical workflow

  1. Build and validate one or more [DeviceDefinition] values.
  2. Start [Server::bind], spawn [Server::run], and retain its [ServerHandle] and event receiver.
  3. Consume events in order. Registration, call input, media acknowledgements, and disconnects all arrive through the same stream.
  4. Send commands through the handle. Use [ServerHandle::send_confirmed] when later work depends on the complete frame having reached the station socket; [ServerHandle::send] confirms queue admission only.
  5. Call [ServerHandle::shutdown] and await the server task during orderly application shutdown.
use sccp_protocol::{
    ButtonDefinition, DeviceDefinition, DeviceId, LineAppearance, LineDefinition,
    Server, ServerConfig, SoftKeyProfile, StationTransportRequirement, StationUiPolicy,
};

# async fn example() -> Result<(), Box<dyn std::error::Error>> {
let station = DeviceDefinition {
    id: DeviceId::new("SEP001122334455")?,
    description: "Front desk".into(),
    transport: StationTransportRequirement::Either,
    signaling_qos: None,
    buttons: vec![ButtonDefinition::Line(LineAppearance::new(
        1,
        LineDefinition {
            number: "1001".into(),
            display_name: "Reception".into(),
        },
    ))],
    soft_keys: SoftKeyProfile::default(),
    ui: StationUiPolicy::default(),
};
station.validate()?;

let (server, handle, mut events) = Server::bind(ServerConfig::default(), [station]).await?;
let server_task = tokio::spawn(server.run());

if let Some(event) = events.recv().await {
    println!("{event:?}");
}

handle.shutdown().await?;
server_task.await??;
# Ok(())
# }

Choosing an API layer

Most applications use the crate-root re-exports plus [server] and [types]. [message] exposes framing, message IDs, codecs, and typed wire models for protocol tools or custom transports. [phone] contains bounded phone-hosted XML, authentication, service, and provisioning models. [qos] owns service-node reservation transitions without sharing handset session state. To supply an externally accepted transport—such as a TLS stream—construct the server with [Server::with_ingress] and feed streams through [ServerIngress].