Skip to main content

sccp_protocol/
lib.rs

1//! Typed Skinny Client Control Protocol messages and an asynchronous station server.
2//!
3//! The crate separates the phone-facing wire protocol from the call-control
4//! application. [`Server`] owns station connections and translates inbound
5//! packets into semantic [`Event`] values. Applications respond through a
6//! cloneable [`ServerHandle`] using typed [`Command`] values; no SIP or PBX
7//! policy is built into this crate.
8//!
9//! # Typical workflow
10//!
11//! 1. Build and validate one or more [`DeviceDefinition`] values.
12//! 2. Start [`Server::bind`], spawn [`Server::run`], and retain its
13//!    [`ServerHandle`] and event receiver.
14//! 3. Consume events in order. Registration, call input, media
15//!    acknowledgements, and disconnects all arrive through the same stream.
16//! 4. Send commands through the handle. Use [`ServerHandle::send_confirmed`]
17//!    when later work depends on the complete frame having reached the station
18//!    socket; [`ServerHandle::send`] confirms queue admission only.
19//! 5. Call [`ServerHandle::shutdown`] and await the server task during orderly
20//!    application shutdown.
21//!
22//! ```no_run
23//! use sccp_protocol::{
24//!     ButtonDefinition, DeviceDefinition, DeviceId, LineAppearance, LineDefinition,
25//!     Server, ServerConfig, SoftKeyProfile, StationTransportRequirement, StationUiPolicy,
26//! };
27//!
28//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
29//! let station = DeviceDefinition {
30//!     id: DeviceId::new("SEP001122334455")?,
31//!     description: "Front desk".into(),
32//!     transport: StationTransportRequirement::Either,
33//!     signaling_qos: None,
34//!     buttons: vec![ButtonDefinition::Line(LineAppearance::new(
35//!         1,
36//!         LineDefinition {
37//!             number: "1001".into(),
38//!             display_name: "Reception".into(),
39//!         },
40//!     ))],
41//!     soft_keys: SoftKeyProfile::default(),
42//!     ui: StationUiPolicy::default(),
43//! };
44//! station.validate()?;
45//!
46//! let (server, handle, mut events) = Server::bind(ServerConfig::default(), [station]).await?;
47//! let server_task = tokio::spawn(server.run());
48//!
49//! if let Some(event) = events.recv().await {
50//!     println!("{event:?}");
51//! }
52//!
53//! handle.shutdown().await?;
54//! server_task.await??;
55//! # Ok(())
56//! # }
57//! ```
58//!
59//! # Choosing an API layer
60//!
61//! Most applications use the crate-root re-exports plus [`server`] and
62//! [`types`]. [`message`] exposes framing, message IDs, codecs, and typed wire
63//! models for protocol tools or custom transports. [`phone`] contains bounded
64//! phone-hosted XML, authentication, service, and provisioning models.
65//! [`qos`] owns service-node reservation transitions without sharing handset
66//! session state. To supply an externally accepted transport—such as a TLS
67//! stream—construct the server with [`Server::with_ingress`] and feed streams through
68//! [`ServerIngress`].
69
70#![deny(missing_debug_implementations)]
71
72pub mod message;
73pub mod phone;
74pub mod qos;
75pub mod server;
76pub mod types;
77
78pub use message::capabilities::{
79    CapabilityUpdate, CapabilityUpdateVariant, ConferenceResource, ConferenceServiceResource,
80    CustomPictureFormat, DataCapability, StationMediaCapabilities, VideoCapability,
81    VideoLevelPreference,
82};
83pub use message::catalog::{MessageDirection, MessageId, MessageRoute};
84pub use message::values::{
85    AddParticipantResult, AlarmSeverity, AnnouncementPlayMode, AnnouncementPlayStatus,
86    AuditParticipantResult, BusyLampFieldState, ButtonType, CallForwardKind,
87    CallHistoryDisposition, CallInfoVisibility, CallPriority, CallSecurityState, CallState,
88    CallType, Codec, CodecKind, ConferenceResourceType, CreateConferenceResult,
89    DeleteConferenceResult, DeviceType, Digit, DtmfMode, DynamicCallInfoLayout, EchoCancellation,
90    EncryptionCapability, EncryptionMethod, EndOfAnnouncementAck, G723BitRate, IpAddressType,
91    KeyMode, LampMode, LayoutProfile, MediaPathCapability, MediaPathEvent, MediaPathId,
92    MediaStatus, MediaTransport, MediaType, MessageWaitingResult, MicrophoneMode, MiscCommandType,
93    ModifyConferenceResult, NotificationPriority, PartyInformationRestrictions, PhoneFeatures,
94    ProtocolVersion, QosDirection, QosErrorCode, QosReservationStyle,
95    RFC2833_TELEPHONE_EVENT_PAYLOAD, ReceiveTransmit, ResetType, RingDuration, RingerMode,
96    RsvpErrorCode, SilenceSuppression, SoftKey, SpeakerMode, StationSessionContext,
97    StatisticsProcessing, Stimulus, SubscriptionCause, Tone, ToneDirection, UnregisterStatus,
98    VideoFormat,
99};
100pub use message::wire::{CodecError, Frame, FrameDecoder, MAX_FRAME_SIZE};
101pub use message::{
102    AddParticipantRequest, AddParticipantResponse, AnnouncementEntry, AudioStreamControl,
103    AuditConferenceEntry, AuditConferenceResponse, AuditParticipantResponse, BoundedBytes,
104    BoundedBytesError, ButtonTemplateEntry, CONNECTION_QUALITY_MAX_BYTES, ChangeParticipantRequest,
105    ClientMessage, ConferenceParticipant, ConferenceParticipantChange, ConfigurationStatus,
106    ConnectionQualityStatistics, ConnectionStatistics, ControlMessage, CreateConferenceRequest,
107    CreateConferenceResponse, DtmfPayloadIdentity, DtmfPayloadRequest, DtmfToneControl,
108    ExtensionDeviceCapabilities, KnownOpaqueMessage, MAX_MULTIMEDIA_PICTURE_FORMATS,
109    MAX_SIGNALING_SERVERS, MEDIA_PORT_LIST_MAX_PORTS, MULTIMEDIA_CAPABILITY_BYTES, MediaCapability,
110    MediaEncryption, MediaEndpointAddress, MediaFailureDetection, MediaPortList,
111    MediaResourceNotification, MediaTransmissionAck, MessageWaitingCounts,
112    MessageWaitingNotification, MiscellaneousCommand, ModifyConferenceRequest,
113    ModifyConferenceResponse, MulticastMediaReception, MulticastMediaTransmission,
114    MultimediaCapabilityError, MultimediaPayload, MultimediaPayloadDescriptor,
115    MultimediaPictureFormat, MultimediaStreamControl, MultimediaVideoCapability,
116    MultimediaVideoCapabilityArm, OpenMultimediaChannel, OpenMultimediaReceiveChannelAck,
117    ParticipantChangeRouting, PortClose, PortEndpoint, PortRequest, QosApplicationIdentifier,
118    QosFlow, QosTrafficSpecification, RawMessage, RegisterTokenMessage, RegistrationMessage,
119    RegistrationWireDetails, RtpPayloadNumber, RtpPayloadNumberError, ServerMessage,
120    SessionTransmission, SignalingServerEndpoint, SpcpRegisterTokenMessage,
121    StartMultimediaTransmission, StartMultimediaTransmissionAck, SubscriptionRequest,
122    UserDataMessage, UserDataV1Message, VideoFlowControl, XML_ALARM_CANONICAL_DOCUMENT_BYTES,
123    XML_ALARM_CANONICAL_WIRE_BYTES, XML_ALARM_MAX_WIRE_BYTES, XmlAlarmMessage,
124};
125pub use phone::authentication::{
126    OpaquePhoneAuthenticationResponse, PHONE_AUTHENTICATION_MAX_PASSWORD_BYTES,
127    PHONE_AUTHENTICATION_MAX_QUERY_BYTES, PHONE_AUTHENTICATION_MAX_RESPONSE_BYTES,
128    PHONE_AUTHENTICATION_MAX_USER_ID_BYTES, PhoneAuthenticationError, PhoneAuthenticationPassword,
129    PhoneAuthenticationRequest, PhoneAuthenticationResponse, PhoneAuthenticationUserId,
130};
131pub use phone::service::{
132    CiscoIpPhoneError, CiscoIpPhoneResponse, CiscoIpPhoneResponseItem, PhoneExecuteStatus,
133    PhoneServiceError, PhoneServiceErrorCode, PhoneServiceEvent, PhoneServiceExtendedRouting,
134    PhoneServiceMessageKind, PhoneServicePayload, PhoneServiceRouting, PhoneServiceSubmission,
135    PhoneServiceSubmittedValue, parse_phone_service_payload,
136};
137pub use phone::xml::{
138    CiscoIpPhoneAlarm, CiscoIpPhoneAlarmEntry, CiscoIpPhoneAlarmEnum, CiscoIpPhoneAlarmParameter,
139    CiscoIpPhoneAlarmParameterList, CiscoIpPhoneAlarmString, CiscoIpPhoneBackground,
140    CiscoIpPhoneDirectory, CiscoIpPhoneDirectoryEntry, CiscoIpPhoneExecute,
141    CiscoIpPhoneExecuteItem, CiscoIpPhoneGraphicFileMenu, CiscoIpPhoneGraphicMenu,
142    CiscoIpPhoneIconFileItem, CiscoIpPhoneIconFileMenu, CiscoIpPhoneIconItem, CiscoIpPhoneIconMenu,
143    CiscoIpPhoneIconMenuItem, CiscoIpPhoneIconTitle, CiscoIpPhoneImage, CiscoIpPhoneImageFile,
144    CiscoIpPhoneImageList, CiscoIpPhoneImageListItem, CiscoIpPhoneInput, CiscoIpPhoneInputItem,
145    CiscoIpPhoneKeyItem, CiscoIpPhoneLocationInformation, CiscoIpPhoneMenu, CiscoIpPhoneMenuItem,
146    CiscoIpPhoneOffPremises, CiscoIpPhoneSetBackground, CiscoIpPhoneSetBackgroundPreview,
147    CiscoIpPhoneSetRingTone, CiscoIpPhoneSoftKeyItem, CiscoIpPhoneStatus, CiscoIpPhoneStatusFile,
148    CiscoIpPhoneText, CiscoIpPhoneTouchAreaMenuItem, CiscoIpPhoneWifiLocation,
149    ConferenceListAction, ConferenceListDocument, ConferenceListEntry, ConferenceMenuFamily,
150    ConferenceParticipantActionsDocument, OpaquePhoneAlarm, OpaquePhoneLocation,
151    PHONE_ALARM_MAX_BYTES, PHONE_BACKGROUND_APPLICATION_ID, PHONE_BACKGROUND_CONTROL_MAX_BYTES,
152    PHONE_BACKGROUND_LIST_MAX_BYTES, PHONE_BACKGROUND_LIST_MAX_ITEMS, PHONE_DIRECTORY_MAX_BYTES,
153    PHONE_DIRECTORY_MAX_ENTRIES, PHONE_EXECUTE_MAX_BYTES, PHONE_EXECUTE_MAX_ITEMS,
154    PHONE_GRAPHIC_FILE_MENU_MAX_ITEMS, PHONE_GRAPHIC_MENU_MAX_ITEMS, PHONE_ICON_MENU_MAX_ICONS,
155    PHONE_ICON_MENU_MAX_ITEMS, PHONE_IMAGE_BITMAP_MAX_BYTES, PHONE_IMAGE_MAX_BYTES,
156    PHONE_INPUT_MAX_BYTES, PHONE_INPUT_MAX_ITEMS, PHONE_LOCATION_MAX_BYTES, PHONE_MENU_MAX_BYTES,
157    PHONE_MENU_MAX_ITEMS, PHONE_RINGTONE_APPLICATION_ID, PHONE_RINGTONE_MAX_BYTES,
158    PHONE_STATUS_BITMAP_MAX_BYTES, PHONE_STATUS_MAX_BYTES, PHONE_TEXT_APPLICATION_ID,
159    PHONE_TEXT_LEGACY_MAX_CHARS, PHONE_TEXT_MAX_BYTES, PHONE_TEXT_MAX_CHARS,
160    PHONE_XML_MAX_NESTING_DEPTH, PhoneActionKind, PhoneAlarmKind, PhoneAlarmSummary,
161    PhoneAlarmTelemetry, PhoneBackgroundControlDocument, PhoneBackgroundHttpUrl,
162    PhoneBackgroundTftpUrl, PhoneBitmapData, PhoneBssid, PhoneExecutePriority, PhoneExecuteUrl,
163    PhoneImageDocument, PhoneImageUrl, PhoneInputFlags, PhoneInputParameterName, PhoneKeypadTarget,
164    PhoneLocationKind, PhoneLocationSummary, PhoneLocationTelemetry, PhoneRingtoneUrl,
165    PhoneServicePriority, PhoneSoftKeyPosition, PhoneStatusDocument, PhoneTouchArea, PhoneXmlError,
166    PhoneXmlKey, PhoneXmlRefresh, from_bytes as parse_phone_xml, parse_phone_alarm,
167    parse_phone_location, to_string as serialize_phone_xml,
168};
169pub use qos::{
170    QosReservationController, QosReservationError, QosReservationEvent, QosReservationFailure,
171    QosReservationId, QosReservationLimits, QosReservationPolicy, QosReservationRequest,
172    QosReservationSetup, QosReservationState, QosTransition,
173};
174pub use server::{
175    AnonymousHotlineDefinition, CallSelectionOrder, Command, CommandAction, DeviceEvent,
176    DeviceEventKind, DoNotDisturbButtonMode, DoNotDisturbMode, Event, HandsetAcknowledgement,
177    HandsetStatusMessage, IncomingRing, MAX_REGISTRATION_BACKOFF, MIN_REGISTRATION_BACKOFF,
178    MediaStatisticsSnapshot, MulticastMediaRoute, MultimediaReceiveDescriptor,
179    MultimediaTransmitControl, MultimediaTransmitDescriptor, PARKING_MENU_MAX_ITEMS,
180    ParkingMenuEntry, ReconfigureResult, RegistrationFallback, RegistrationTokenPolicy, Server,
181    ServerConfig, ServerError, ServerHandle, ServerIngress, SignalingServerRoute, SignalingSocket,
182    SocketQosFailure, SocketQosMark, SocketQosPolicy, SocketQosReport, StationIo, StationSocketQos,
183    VideoPictureReference, VideoPictureReferences, apply_socket_qos,
184};
185pub use types::{
186    AddonModuleDefinition, AppearanceId, AppearanceRingMode, ApplicationId, AudioProcessingPolicy,
187    BlfCallerInfo, BlfSpeedDialDefinition, BlfState, ButtonDefinition, CallDirection, CallId,
188    CallInfo, CallReference, CallerIdOverride, ConferenceId, DEFAULT_AUDIO_MAX_FRAMES_PER_PACKET,
189    DEFAULT_AUDIO_PACKET_MS, DateTemplate, DeviceDefinition, DeviceId, DeviceRegistration,
190    FeatureDefinition, LegacyCodePage, LineAppearance, LineDefinition, LineInstance, MediaEndpoint,
191    MediaTrafficClass, ParticipantId, PassthroughPartyId, ServiceDefinition, SessionGeneration,
192    SignalingQos, SoftKeyProfile, SpeedDialDefinition, StationTransport,
193    StationTransportRequirement, StationUiPolicy, TransactionId,
194};