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, MULTIMEDIA_CAPABILITY_BYTES, MediaCapability, MediaEncryption,
110    MediaEndpointAddress, MediaFailureDetection, MediaResourceNotification, MediaTransmissionAck,
111    MessageWaitingCounts, MessageWaitingNotification, MiscellaneousCommand,
112    ModifyConferenceRequest, ModifyConferenceResponse, MulticastMediaReception,
113    MulticastMediaTransmission, MultimediaCapabilityError, MultimediaPayload,
114    MultimediaPayloadDescriptor, MultimediaPictureFormat, MultimediaStreamControl,
115    MultimediaVideoCapability, MultimediaVideoCapabilityArm, OpenMultimediaChannel,
116    OpenMultimediaReceiveChannelAck, ParticipantChangeRouting, PortClose, PortEndpoint,
117    PortRequest, QosApplicationIdentifier, QosFlow, QosTrafficSpecification, RawMessage,
118    RegisterTokenMessage, RegistrationMessage, RegistrationWireDetails, RtpPayloadNumber,
119    RtpPayloadNumberError, ServerMessage, SessionTransmission, SignalingServerEndpoint,
120    StartMultimediaTransmission, StartMultimediaTransmissionAck, SubscriptionRequest,
121    UserDataMessage, UserDataV1Message, VideoFlowControl, XML_ALARM_CANONICAL_DOCUMENT_BYTES,
122    XML_ALARM_CANONICAL_WIRE_BYTES, XML_ALARM_MAX_WIRE_BYTES, XmlAlarmMessage,
123};
124pub use phone::authentication::{
125    OpaquePhoneAuthenticationResponse, PHONE_AUTHENTICATION_MAX_PASSWORD_BYTES,
126    PHONE_AUTHENTICATION_MAX_QUERY_BYTES, PHONE_AUTHENTICATION_MAX_RESPONSE_BYTES,
127    PHONE_AUTHENTICATION_MAX_USER_ID_BYTES, PhoneAuthenticationError, PhoneAuthenticationPassword,
128    PhoneAuthenticationRequest, PhoneAuthenticationResponse, PhoneAuthenticationUserId,
129};
130pub use phone::service::{
131    CiscoIpPhoneError, CiscoIpPhoneResponse, CiscoIpPhoneResponseItem, PhoneExecuteStatus,
132    PhoneServiceError, PhoneServiceErrorCode, PhoneServiceEvent, PhoneServiceExtendedRouting,
133    PhoneServiceMessageKind, PhoneServicePayload, PhoneServiceRouting, PhoneServiceSubmission,
134    PhoneServiceSubmittedValue, parse_phone_service_payload,
135};
136pub use phone::xml::{
137    CiscoIpPhoneAlarm, CiscoIpPhoneAlarmEntry, CiscoIpPhoneAlarmEnum, CiscoIpPhoneAlarmParameter,
138    CiscoIpPhoneAlarmParameterList, CiscoIpPhoneAlarmString, CiscoIpPhoneBackground,
139    CiscoIpPhoneDirectory, CiscoIpPhoneDirectoryEntry, CiscoIpPhoneExecute,
140    CiscoIpPhoneExecuteItem, CiscoIpPhoneGraphicFileMenu, CiscoIpPhoneGraphicMenu,
141    CiscoIpPhoneIconFileItem, CiscoIpPhoneIconFileMenu, CiscoIpPhoneIconItem, CiscoIpPhoneIconMenu,
142    CiscoIpPhoneIconMenuItem, CiscoIpPhoneIconTitle, CiscoIpPhoneImage, CiscoIpPhoneImageFile,
143    CiscoIpPhoneImageList, CiscoIpPhoneImageListItem, CiscoIpPhoneInput, CiscoIpPhoneInputItem,
144    CiscoIpPhoneKeyItem, CiscoIpPhoneLocationInformation, CiscoIpPhoneMenu, CiscoIpPhoneMenuItem,
145    CiscoIpPhoneOffPremises, CiscoIpPhoneSetBackground, CiscoIpPhoneSetBackgroundPreview,
146    CiscoIpPhoneSetRingTone, CiscoIpPhoneSoftKeyItem, CiscoIpPhoneStatus, CiscoIpPhoneStatusFile,
147    CiscoIpPhoneText, CiscoIpPhoneTouchAreaMenuItem, CiscoIpPhoneWifiLocation,
148    ConferenceListAction, ConferenceListDocument, ConferenceListEntry, ConferenceMenuFamily,
149    ConferenceParticipantActionsDocument, OpaquePhoneAlarm, OpaquePhoneLocation,
150    PHONE_ALARM_MAX_BYTES, PHONE_BACKGROUND_APPLICATION_ID, PHONE_BACKGROUND_CONTROL_MAX_BYTES,
151    PHONE_BACKGROUND_LIST_MAX_BYTES, PHONE_BACKGROUND_LIST_MAX_ITEMS, PHONE_DIRECTORY_MAX_BYTES,
152    PHONE_DIRECTORY_MAX_ENTRIES, PHONE_EXECUTE_MAX_BYTES, PHONE_EXECUTE_MAX_ITEMS,
153    PHONE_GRAPHIC_FILE_MENU_MAX_ITEMS, PHONE_GRAPHIC_MENU_MAX_ITEMS, PHONE_ICON_MENU_MAX_ICONS,
154    PHONE_ICON_MENU_MAX_ITEMS, PHONE_IMAGE_BITMAP_MAX_BYTES, PHONE_IMAGE_MAX_BYTES,
155    PHONE_INPUT_MAX_BYTES, PHONE_INPUT_MAX_ITEMS, PHONE_LOCATION_MAX_BYTES, PHONE_MENU_MAX_BYTES,
156    PHONE_MENU_MAX_ITEMS, PHONE_RINGTONE_APPLICATION_ID, PHONE_RINGTONE_MAX_BYTES,
157    PHONE_STATUS_BITMAP_MAX_BYTES, PHONE_STATUS_MAX_BYTES, PHONE_TEXT_APPLICATION_ID,
158    PHONE_TEXT_LEGACY_MAX_CHARS, PHONE_TEXT_MAX_BYTES, PHONE_TEXT_MAX_CHARS,
159    PHONE_XML_MAX_NESTING_DEPTH, PhoneActionKind, PhoneAlarmKind, PhoneAlarmSummary,
160    PhoneAlarmTelemetry, PhoneBackgroundControlDocument, PhoneBackgroundHttpUrl,
161    PhoneBackgroundTftpUrl, PhoneBitmapData, PhoneBssid, PhoneExecutePriority, PhoneExecuteUrl,
162    PhoneImageDocument, PhoneImageUrl, PhoneInputFlags, PhoneInputParameterName, PhoneKeypadTarget,
163    PhoneLocationKind, PhoneLocationSummary, PhoneLocationTelemetry, PhoneRingtoneUrl,
164    PhoneServicePriority, PhoneSoftKeyPosition, PhoneStatusDocument, PhoneTouchArea, PhoneXmlError,
165    PhoneXmlKey, PhoneXmlRefresh, from_bytes as parse_phone_xml, parse_phone_alarm,
166    parse_phone_location, to_string as serialize_phone_xml,
167};
168pub use qos::{
169    QosReservationController, QosReservationError, QosReservationEvent, QosReservationFailure,
170    QosReservationId, QosReservationLimits, QosReservationPolicy, QosReservationRequest,
171    QosReservationSetup, QosReservationState, QosTransition,
172};
173pub use server::{
174    AnonymousHotlineDefinition, CallSelectionOrder, Command, CommandAction, DeviceEvent,
175    DeviceEventKind, DoNotDisturbButtonMode, DoNotDisturbMode, Event, HandsetAcknowledgement,
176    HandsetStatusMessage, IncomingRing, MAX_REGISTRATION_BACKOFF, MIN_REGISTRATION_BACKOFF,
177    MediaStatisticsSnapshot, MulticastMediaRoute, MultimediaReceiveDescriptor,
178    MultimediaTransmitControl, MultimediaTransmitDescriptor, PARKING_MENU_MAX_ITEMS,
179    ParkingMenuEntry, ReconfigureResult, RegistrationFallback, RegistrationTokenPolicy, Server,
180    ServerConfig, ServerError, ServerHandle, ServerIngress, SignalingServerRoute, SignalingSocket,
181    SocketQosFailure, SocketQosMark, SocketQosPolicy, SocketQosReport, StationIo, StationSocketQos,
182    VideoPictureReference, VideoPictureReferences, apply_socket_qos,
183};
184pub use types::{
185    AddonModuleDefinition, AppearanceId, AppearanceRingMode, ApplicationId, AudioProcessingPolicy,
186    BlfCallerInfo, BlfSpeedDialDefinition, BlfState, ButtonDefinition, CallDirection, CallId,
187    CallInfo, CallReference, CallerIdOverride, ConferenceId, DEFAULT_AUDIO_MAX_FRAMES_PER_PACKET,
188    DEFAULT_AUDIO_PACKET_MS, DateTemplate, DeviceDefinition, DeviceId, DeviceRegistration,
189    FeatureDefinition, LegacyCodePage, LineAppearance, LineDefinition, LineInstance, MediaEndpoint,
190    MediaTrafficClass, ParticipantId, PassthroughPartyId, ServiceDefinition, SessionGeneration,
191    SignalingQos, SoftKeyProfile, SpeedDialDefinition, StationTransport,
192    StationTransportRequirement, StationUiPolicy, TransactionId,
193};