mumble_server_runtime_gateway/
handshake.rs1use mumble_server_runtime_protocol::ControlMessage;
19use mumble_server_runtime_protocol::messages::tcp;
20use mumble_server_runtime_shard::SessionId;
21
22use crate::config::GatewayConfig;
23
24pub use mumble_server_runtime_shard::perm;
30
31#[must_use]
34pub fn server_version(config: &GatewayConfig) -> ControlMessage {
35 let (major, minor, patch) = config.version;
36 ControlMessage::Version(tcp::Version {
37 version_v1: Some(
40 (u32::from(major) << 16) | (u32::from(minor) << 8) | u32::from(patch.min(0xFF)),
41 ),
42 version_v2: Some(config.version_v2()),
43 release: Some(format!("Mumble Server Runtime {major}.{minor}.{patch}")),
44 os: Some("Mumble Server Runtime".to_owned()),
45 os_version: None,
46 })
47}
48
49#[must_use]
51pub fn prelude(crypt_setup: tcp::CryptSetup) -> Vec<ControlMessage> {
52 vec![
53 ControlMessage::CryptSetup(crypt_setup),
54 ControlMessage::CodecVersion(tcp::CodecVersion {
57 alpha: 0,
58 beta: 0,
59 prefer_alpha: false,
60 opus: Some(true),
61 }),
62 ]
63}
64
65#[must_use]
67pub fn completion(config: &GatewayConfig, session: SessionId) -> Vec<ControlMessage> {
68 vec![
69 ControlMessage::ServerSync(tcp::ServerSync {
72 session: Some(session.0),
73 max_bandwidth: Some(config.max_bandwidth),
74 welcome_text: if config.welcome_text.is_empty() {
75 None
76 } else {
77 Some(config.welcome_text.clone())
78 },
79 permissions: Some(u64::from(perm::DEFAULT)),
80 }),
81 ControlMessage::ServerConfig(tcp::ServerConfig {
82 max_bandwidth: Some(config.max_bandwidth),
83 welcome_text: None,
84 allow_html: Some(config.allow_html),
85 message_length: Some(config.message_length),
86 image_message_length: None,
87 max_users: Some(config.max_users),
88 recording_allowed: Some(config.recording_allowed),
89 }),
90 ]
91}
92
93#[must_use]
97pub fn reject(reason: &str) -> ControlMessage {
98 ControlMessage::Reject(tcp::Reject {
99 r#type: Some(i32::from(tcp::reject::RejectType::None)),
100 reason: Some(reason.to_owned()),
101 })
102}
103
104#[cfg(test)]
105mod tests {
106 #![allow(clippy::expect_used)]
107
108 use super::*;
109
110 fn crypt() -> tcp::CryptSetup {
111 tcp::CryptSetup {
112 key: Some(vec![0u8; 16]),
113 client_nonce: Some(vec![0u8; 16]),
114 server_nonce: Some(vec![0u8; 16]),
115 }
116 }
117
118 #[test]
119 fn the_prelude_sets_up_crypto_then_the_codec() {
120 let messages = prelude(crypt());
121 assert!(matches!(
122 messages.first(),
123 Some(ControlMessage::CryptSetup(_))
124 ));
125 assert!(matches!(
126 messages.get(1),
127 Some(ControlMessage::CodecVersion(_))
128 ));
129 assert_eq!(messages.len(), 2);
130 }
131
132 #[test]
133 fn the_completion_syncs_before_it_configures() {
134 let messages = completion(&GatewayConfig::default(), SessionId(7));
135 match messages.first() {
136 Some(ControlMessage::ServerSync(sync)) => assert_eq!(sync.session, Some(7)),
137 other => panic!("expected ServerSync first, got {other:?}"),
138 }
139 assert!(matches!(
140 messages.get(1),
141 Some(ControlMessage::ServerConfig(_))
142 ));
143 }
144}