mumble_server_runtime_gateway/connection.rs
1//! One task per TCP connection: terminate TLS, route, attach, serve, detach.
2//!
3//! The task owns the socket and nothing else. A migration never moves it: only
4//! the shard it sends its events to changes, which is exactly why a connection
5//! can cross shards without its client noticing anything but a new tree.
6//!
7//! ```text
8//! TLS -> Version -> [Authenticate] -> router.route()
9//! -> attach -> prelude -> the shard's first transition -> ServerSync
10//! -> service loop
11//! -> detach
12//! ```
13
14use std::net::SocketAddr;
15use std::sync::Arc;
16use std::time::{Duration, Instant};
17
18use anyhow::{Context, Result};
19use mumble_server_runtime_protocol::messages::tcp;
20use mumble_server_runtime_protocol::{
21 ControlMessage, UdpMessage, decode_frame, decode_udp, encode_frame, parse_frame,
22};
23use mumble_server_runtime_shard::{ChannelId, OutboundQueue, ShardCommand, TextTarget};
24use ring::rand::SystemRandom;
25use tokio::io::{AsyncReadExt, AsyncWriteExt, ReadHalf, WriteHalf};
26use tokio::net::{TcpStream, UdpSocket};
27use tokio::sync::mpsc;
28use tokio_rustls::TlsAcceptor;
29use tokio_rustls::server::TlsStream;
30
31use crate::config::GatewayConfig;
32use crate::handshake;
33use crate::limits;
34use crate::peer::{ClientReport, Peer, ShardPlane};
35use crate::router::{ConnectionIdentity, ConnectionRouter, RouteDecision};
36use crate::runtime::RuntimeHandle;
37use crate::voice::{VoicePlane, generate_crypt_setup};
38
39/// How long the handshake waits for the shard to publish this connection's
40/// first view.
41///
42/// Generous, because the wait is only ever one shard turn plus scheduling. It
43/// exists so a shard wedged by a flavor's own bug refuses the arrival instead of
44/// leaving a client staring at a handshake that never completes.
45const FIRST_VIEW_TIMEOUT: Duration = Duration::from_secs(5);
46
47/// Serve one accepted TCP connection to completion.
48///
49/// # Errors
50///
51/// A TLS failure, a malformed frame or a dropped socket. Any of them ends the
52/// connection cleanly: it is detached and its peer record removed.
53pub async fn serve<R: ConnectionRouter>(
54 tcp: TcpStream,
55 acceptor: TlsAcceptor,
56 runtime: RuntimeHandle,
57 router: Arc<R>,
58 voice: Arc<VoicePlane>,
59 udp: Arc<UdpSocket>,
60 config: Arc<GatewayConfig>,
61) -> Result<()> {
62 // A fresh randomness handle per connection; `SystemRandom` is a cheap ZST.
63 let rng = SystemRandom::new();
64 // Nagle off: control latency matters more than coalescing small frames.
65 let _ignored = tcp.set_nodelay(true);
66 let host = tcp.peer_addr().context("TCP peer address")?.ip();
67
68 let tls = acceptor.accept(tcp).await.context("TLS handshake")?;
69 let certificate_hash = crate::tls::client_certificate_hash(&tls);
70 let (read_half, write_half) = tokio::io::split(tls);
71 let mut reader = FrameReader::new(read_half);
72 let mut writer = write_half;
73
74 // The server announces its version as soon as TLS completes, before the
75 // client authenticates (REF Server.cpp::encrypted).
76 write_message(&mut writer, &handshake::server_version(&config)).await?;
77
78 let Some(authenticate) = wait_for_authenticate(&mut reader).await? else {
79 return Ok(()); // it left before authenticating
80 };
81
82 let identity = ConnectionIdentity {
83 // The client's proposal, bounded before it is ever stored or rendered.
84 name: authenticate
85 .username
86 .as_deref()
87 .unwrap_or("Guest")
88 .chars()
89 .take(64)
90 .collect(),
91 certificate_hash,
92 credential: authenticate.password,
93 };
94
95 if runtime.peers().len() >= config.max_users as usize {
96 write_message(&mut writer, &handshake::reject("the server is full")).await?;
97 return Ok(());
98 }
99
100 // Both identifiers are reserved before the routing decision, so the router
101 // can bind this connection's claimed identity to the id every later event
102 // will carry. Neither is ever reused, so reserving one for a connection that
103 // is then rejected costs a number and nothing else.
104 let connection = runtime.next_connection();
105 let session = runtime
106 .session_for(connection)
107 .context("allocating a session")?;
108
109 let shard = match router.route(connection, &identity).await {
110 RouteDecision::Attach(shard) => shard,
111 RouteDecision::Reject(reason) => {
112 write_message(&mut writer, &handshake::reject(&reason)).await?;
113 return Ok(());
114 }
115 };
116
117 let (crypt_setup, crypt_state) = generate_crypt_setup(&rng)?;
118 let (queue, mut outbound) = OutboundQueue::new();
119
120 // The plane is a placeholder until `attach` points it at the real shard.
121 // Registering first is what lets the shard's very first render already find
122 // the connection in the peer table.
123 let placeholder = ShardPlane {
124 shard,
125 routing: tokio::sync::watch::channel(Arc::new(
126 mumble_server_runtime_shard::AudioRouting::default(),
127 ))
128 .1,
129 };
130 let peer = Arc::new(Peer::new(
131 connection,
132 session,
133 host,
134 crypt_state,
135 Arc::new(queue),
136 placeholder,
137 Instant::now(),
138 ));
139 runtime.peers().insert(Arc::clone(&peer));
140
141 // Everything past registration is wrapped so a failure during the handshake
142 // gets exactly the same cleanup as a steady-state disconnect.
143 let result = async {
144 for message in handshake::prelude(crypt_setup) {
145 write_message(&mut writer, &message).await?;
146 }
147
148 let ready = runtime
149 .attach(&peer, shard)
150 .context("attaching to the routed shard")?;
151
152 // The first transition is the ordinary one: the shard plans it, the
153 // queue carries it, and the handshake merely writes it out before
154 // `ServerSync`. That is what keeps invariants 1 and 6 satisfied with a
155 // single rendering path in the runtime.
156 tokio::time::timeout(FIRST_VIEW_TIMEOUT, ready)
157 .await
158 .context("the shard did not publish a first view in time")?
159 .context("the shard dropped the connection during its first render")?;
160 drain(&mut writer, &mut outbound).await?;
161
162 for message in handshake::completion(&config, session) {
163 write_message(&mut writer, &message).await?;
164 }
165
166 service(
167 &mut reader,
168 &mut writer,
169 &mut outbound,
170 &Serving {
171 peer: &peer,
172 runtime: &runtime,
173 voice: &voice,
174 udp: &udp,
175 config: &config,
176 },
177 )
178 .await
179 }
180 .await;
181
182 runtime.peers().remove(connection);
183 runtime.detach(connection, peer.shard(), "connection closed");
184
185 result
186}
187
188/// Everything the service loop needs from the gateway around one connection.
189///
190/// Grouped rather than passed one by one: they share a lifetime, none of them
191/// changes while a connection lives, and a handler that needs three of them
192/// should not have to say so in its signature.
193struct Serving<'a> {
194 peer: &'a Arc<Peer>,
195 runtime: &'a RuntimeHandle,
196 voice: &'a Arc<VoicePlane>,
197 udp: &'a UdpSocket,
198 config: &'a GatewayConfig,
199}
200
201/// The steady state: read client frames, write what the shard pushed.
202async fn service(
203 reader: &mut FrameReader,
204 writer: &mut WriteHalf<TlsStream<TcpStream>>,
205 outbound: &mut mpsc::Receiver<ControlMessage>,
206 serving: &Serving<'_>,
207) -> Result<()> {
208 let Serving {
209 peer,
210 runtime,
211 voice,
212 udp,
213 config,
214 } = *serving;
215 loop {
216 // A refused control message means this client is too far behind to hold
217 // a correct view, so the connection ends and reconnecting rebuilds one.
218 //
219 // Polling rather than being woken is sound: the flag is only set when
220 // the queue is full, which means there are messages waiting, so the
221 // branch below fires immediately and comes straight back here.
222 if peer.queue().must_close() {
223 anyhow::bail!(
224 "session {:?}: output queue overflowed, closing rather than diverging",
225 peer.session()
226 );
227 }
228
229 tokio::select! {
230 // Cancellation-safe: `next` reads into an owned buffer and never
231 // leaves a half-consumed frame across an await, so dropping it on
232 // the other branch loses nothing.
233 incoming = reader.next() => {
234 match incoming? {
235 None => return Ok(()), // clean close
236 Some(ControlMessage::UdpTunnel(raw)) => {
237 for (sealed, to) in tunnelled(voice, peer, &raw) {
238 if let Err(error) = udp.send_to(&sealed, to).await {
239 eprintln!("mumble-server-runtime-gateway: UDP send to {to} failed: {error}");
240 }
241 }
242 }
243 Some(message) => {
244 for reply in inbound(message, peer, runtime, config) {
245 write_message(writer, &reply).await?;
246 }
247 }
248 }
249 }
250 // Cancellation-safe: a message leaves the channel only when this
251 // branch is selected.
252 queued = outbound.recv() => {
253 match queued {
254 Some(message) => {
255 let was_voice = matches!(message, ControlMessage::UdpTunnel(_));
256 write_message(writer, &message).await?;
257 // Draining control capacity is what a congested shard is
258 // waiting for, so tell it - for this connection alone,
259 // in O(1). Draining a tunnelled voice packet frees
260 // nothing worth re-rendering for, and it happens fifty
261 // times a second per speaker.
262 if !was_voice {
263 let _delivered = runtime.send(
264 peer.shard(),
265 ShardCommand::Drained(peer.connection()),
266 );
267 }
268 }
269 // The queue's sending half lives in the shard; losing it
270 // means the shard is gone.
271 None => return Ok(()),
272 }
273 }
274 }
275 }
276}
277
278/// Read frames until `Authenticate` arrives, or the client leaves.
279async fn wait_for_authenticate(reader: &mut FrameReader) -> Result<Option<tcp::Authenticate>> {
280 loop {
281 match reader.next().await? {
282 None => return Ok(None),
283 Some(ControlMessage::Authenticate(authenticate)) => return Ok(Some(authenticate)),
284 // The client's own Version, and any other pre-auth chatter, is
285 // accepted and ignored.
286 Some(_) => continue,
287 }
288 }
289}
290
291/// Handle one control message from the client.
292///
293/// Every branch ends in an explicit outcome (R6): a reply, a request forwarded
294/// to the shard, or a logged refusal.
295fn inbound(
296 message: ControlMessage,
297 peer: &Arc<Peer>,
298 runtime: &RuntimeHandle,
299 config: &GatewayConfig,
300) -> Vec<ControlMessage> {
301 if unidles(&message) {
302 peer.record_activity(Instant::now());
303 }
304
305 match message {
306 // REF: references/mumble/src/murmur/Messages.cpp : `Server::msgPing`
307 // stores what the client reports about its own side, then answers with
308 // the timestamp and the server's OCB2 counters.
309 ControlMessage::Ping(ping) => {
310 peer.record_report(reported(&ping));
311 vec![ControlMessage::Ping(ping_reply(&ping, peer))]
312 }
313
314 ControlMessage::UserState(state) => user_state(&state, peer, runtime),
315
316 // Both are questions rather than intents, so the flavor never sees them:
317 // the shard answers from the render it already published, for the asking
318 // connection alone.
319 //
320 // REF: references/mumble/src/mumble/MainWindow.cpp : the client asks
321 // these of its own accord, on channel selection and on opening a
322 // user's information window.
323 ControlMessage::PermissionQuery(query) => match query.channel_id {
324 Some(channel) => {
325 let _delivered = runtime.send(
326 peer.shard(),
327 ShardCommand::QueriedPermissions {
328 connection: peer.connection(),
329 channel: ChannelId(channel),
330 },
331 );
332 Vec::new()
333 }
334 // `flush` is the server's word to the client, and a query about no
335 // channel at all has no answer.
336 None => {
337 refused("PermissionQuery naming no channel", peer);
338 vec![permission_denied(peer)]
339 }
340 },
341
342 ControlMessage::UserStats(request) => user_stats(&request, peer, runtime),
343
344 ControlMessage::TextMessage(text) => text_message(&text, peer, runtime, config),
345
346 // An intent, so it goes to the shard, which alone knows what this
347 // connection was offered and what it can see. Nothing is validated here:
348 // the gateway holds no view, and guessing would only mean refusing a
349 // legitimate button.
350 //
351 // REF: references/mumble/src/murmur/Messages.cpp : `msgContextAction`
352 // uses `MSG_SETUP`, so it counts as activity like any other intent.
353 ControlMessage::ContextAction(action) => {
354 let _delivered = runtime.send(
355 peer.shard(),
356 ShardCommand::InvokedAction {
357 connection: peer.connection(),
358 action: action.action,
359 session: action.session.map(mumble_server_runtime_shard::SessionId),
360 channel: action.channel_id.map(ChannelId),
361 },
362 );
363 Vec::new()
364 }
365
366 other => {
367 refused(kind_of(&other), peer);
368 vec![permission_denied(peer)]
369 }
370 }
371}
372
373/// Handle a `UserState` a client sent about itself.
374///
375/// Both intents this build understands are forwarded as *requests*: the flavor
376/// decides, and until it renders something new nothing about the view changes.
377/// Anything aimed at another session is moderation, which no flavor here
378/// exposes, so it is refused.
379///
380/// A `UserState` carrying **no** session at all is about its own sender. That is
381/// not a leniency, it is how the official client mutes itself.
382///
383/// REF: references/mumble/src/murmur/Messages.cpp : `VICTIM_SETUP` starts from
384/// `uSource` and only looks a session up when the message carries one.
385/// REF: references/mumble/src/mumble/ServerHandler.cpp : `setSelfMuteDeafState`
386/// sends a `UserState` with both flags and no session.
387fn user_state(
388 state: &tcp::UserState,
389 peer: &Arc<Peer>,
390 runtime: &RuntimeHandle,
391) -> Vec<ControlMessage> {
392 let mine = state
393 .session
394 .is_none_or(|session| session == peer.session().0);
395 if !mine {
396 refused("UserState aimed at another session", peer);
397 return vec![permission_denied(peer)];
398 }
399
400 let mut forwarded = false;
401
402 // "Put me in that channel", the double-click. A channel the connection
403 // cannot see is refused by the shard, which is what keeps a guessed id from
404 // working as an existence oracle.
405 //
406 // REF: references/vendored/Mumble.proto : a client moves itself with a
407 // `UserState` naming its own session and a `channel_id`.
408 if let Some(channel) = state.channel_id {
409 let _delivered = runtime.send(
410 peer.shard(),
411 ShardCommand::Requested {
412 connection: peer.connection(),
413 channel: ChannelId(channel),
414 },
415 );
416 forwarded = true;
417 }
418
419 let (self_mute, self_deaf) = self_state(state);
420 if self_mute.is_some() || self_deaf.is_some() {
421 let _delivered = runtime.send(
422 peer.shard(),
423 ShardCommand::RequestedSelfState {
424 connection: peer.connection(),
425 self_mute,
426 self_deaf,
427 },
428 );
429 forwarded = true;
430 }
431
432 if forwarded {
433 return Vec::new();
434 }
435
436 // Recording announcements, plugin context, listener registrations and
437 // temporary access tokens all land here. None of them is mirrored into a
438 // view, and acknowledging them silently would be a lie (R6).
439 refused("UserState", peer);
440 vec![permission_denied(peer)]
441}
442
443/// Handle a `TextMessage` a client typed.
444///
445/// Everything decided here is a property of the message itself - how fast they
446/// arrive, how long it is, what shape its targets have - and nothing is a
447/// property of the view, which this side does not hold. Whether the connection
448/// may name that target at all is the shard's question, and it is asked there.
449///
450/// The four refusals are not interchangeable:
451///
452/// - A flood is dropped with **no answer**, like the reference server's, because
453/// answering a flood is participating in it.
454/// - An empty message is dropped silently: there is nothing to deliver.
455/// - Too long gets `TextTooLong`, which the client has a message for.
456/// - Anything else gets the generic refusal.
457///
458/// REF: references/mumble/src/murmur/Messages.cpp : `msgTextMessage` runs
459/// `RATELIMIT`, then `isTextAllowed` with `PERM_DENIED_TYPE(TextTooLong)`,
460/// then returns on an empty message, before looking at a single target.
461fn text_message(
462 text: &tcp::TextMessage,
463 peer: &Arc<Peer>,
464 runtime: &RuntimeHandle,
465 config: &GatewayConfig,
466) -> Vec<ControlMessage> {
467 if !peer.allow_text(Instant::now()) {
468 refused("TextMessage over the rate limit", peer);
469 return Vec::new();
470 }
471
472 if text.message.trim().is_empty() {
473 return Vec::new();
474 }
475
476 // Counted in characters where the reference server counts UTF-16 code
477 // units. The two agree on everything below the astral planes, and erring
478 // towards accepting one emoji-heavy message the reference would have cut is
479 // the safer side of a limit that exists to bound a text box.
480 let length = u32::try_from(text.message.chars().count()).unwrap_or(u32::MAX);
481 if config.message_length > 0 && length > config.message_length {
482 refused("TextMessage over the advertised length", peer);
483 return vec![ControlMessage::PermissionDenied(tcp::PermissionDenied {
484 r#type: Some(i32::from(tcp::permission_denied::DenyType::TextTooLong)),
485 ..Default::default()
486 })];
487 }
488
489 // The reference server strips HTML when it does not allow it. Stripping it
490 // correctly is a parser, and a parser fed by clients is the last thing this
491 // crate should grow, so a server that turned HTML off refuses markup instead
492 // of quietly rewriting it (R6).
493 //
494 // REF: references/mumble/src/murmur/Server.cpp : `isTextAllowed` runs
495 // `HTMLFilter::filter` when `bAllowHTML` is false.
496 if !config.allow_html && text.message.contains('<') {
497 refused(
498 "TextMessage carrying markup on a server that forbids it",
499 peer,
500 );
501 return vec![ControlMessage::PermissionDenied(tcp::PermissionDenied {
502 session: Some(peer.session().0),
503 reason: Some("This server does not accept formatted text".to_owned()),
504 r#type: Some(i32::from(tcp::permission_denied::DenyType::Text)),
505 ..Default::default()
506 })];
507 }
508
509 let Some(to) = single_target(text) else {
510 refused("TextMessage naming no single target", peer);
511 return vec![permission_denied(peer)];
512 };
513
514 let _delivered = runtime.send(
515 peer.shard(),
516 ShardCommand::Said {
517 connection: peer.connection(),
518 to,
519 message: text.message.clone(),
520 },
521 );
522 Vec::new()
523}
524
525/// The one target a `TextMessage` names, or nothing.
526///
527/// The official client fills exactly one of the three lists with exactly one
528/// identifier, so anything else is either a different client with a fan-out this
529/// server has not agreed to, or a probe. Both are refused.
530///
531/// REF: references/mumble/src/mumble/ServerHandler.cpp :
532/// `sendUserTextMessage` adds one session; `sendChannelTextMessage` adds one
533/// `channel_id`, or one `tree_id` for the tree variant.
534fn single_target(text: &tcp::TextMessage) -> Option<TextTarget> {
535 match (
536 text.session.as_slice(),
537 text.channel_id.as_slice(),
538 text.tree_id.as_slice(),
539 ) {
540 ([session], [], []) => Some(TextTarget::Session(mumble_server_runtime_shard::SessionId(
541 *session,
542 ))),
543 ([], [channel], []) => Some(TextTarget::Channel(ChannelId(*channel))),
544 ([], [], [tree]) => Some(TextTarget::Tree(ChannelId(*tree))),
545 _ => None,
546 }
547}
548
549/// Handle a client's `UserStats` question.
550///
551/// Split in two because the two halves know different things. What the runtime
552/// publishes about *another* user is a view question, so the shard answers it
553/// and only for a user this connection can see. What it knows about the asker
554/// itself is a transport question - the OCB2 counters live here, in the peer -
555/// and it is the same triplet every `Ping` reply already carries, so answering
556/// discloses nothing new.
557///
558/// A `UserStats` with no session at all is about its sender, like every other
559/// message that omits it.
560///
561/// REF: references/mumble/src/murmur/Messages.cpp : `msgUserStats` answers the
562/// full detail only for `extend` - self, or Ban at the root - and the packet
563/// counters only for `local`.
564fn user_stats(
565 request: &tcp::UserStats,
566 peer: &Arc<Peer>,
567 runtime: &RuntimeHandle,
568) -> Vec<ControlMessage> {
569 let target = request.session.unwrap_or(peer.session().0);
570 if target == peer.session().0 {
571 return vec![own_stats(peer, Instant::now())];
572 }
573
574 let _delivered = runtime.send(
575 peer.shard(),
576 ShardCommand::QueriedUserStats {
577 connection: peer.connection(),
578 target: mumble_server_runtime_shard::SessionId(target),
579 },
580 );
581 Vec::new()
582}
583
584/// Whether a message means somebody is still there.
585///
586/// A keepalive and the two questions a client asks on its own do not: a window
587/// left open polling for statistics would otherwise keep an idle user looking
588/// active forever.
589///
590/// REF: references/mumble/src/murmur/Messages.cpp : `MSG_SETUP` calls
591/// `resetIdleSeconds()` while `MSG_SETUP_NO_UNIDLE` does not, and the second
592/// is used by `msgPing`, `msgCryptSetup`, `msgVoiceTarget`,
593/// `msgPermissionQuery`, `msgCodecVersion`, `msgUserStats` and
594/// `msgRequestBlob`.
595fn unidles(message: &ControlMessage) -> bool {
596 !matches!(
597 message,
598 ControlMessage::Ping(_)
599 | ControlMessage::CryptSetup(_)
600 | ControlMessage::VoiceTarget(_)
601 | ControlMessage::PermissionQuery(_)
602 | ControlMessage::CodecVersion(_)
603 | ControlMessage::UserStats(_)
604 | ControlMessage::RequestBlob(_)
605 )
606}
607
608/// What a client reports about its own side of the link, in every `Ping`.
609///
610/// Kept verbatim, exactly as the reference server keeps it, because none of it
611/// is measurable from here: the loss the client sees, its own ping to us, the
612/// packets it counted. It only ever travels back to the client that sent it.
613///
614/// REF: references/mumble/src/murmur/Messages.cpp : `msgPing` assigns each of
615/// these straight from the message, then answers with the server's own
616/// counters.
617fn reported(ping: &tcp::Ping) -> ClientReport {
618 ClientReport {
619 good: ping.good.unwrap_or_default(),
620 late: ping.late.unwrap_or_default(),
621 lost: ping.lost.unwrap_or_default(),
622 resync: ping.resync.unwrap_or_default(),
623 udp_packets: ping.udp_packets.unwrap_or_default(),
624 tcp_packets: ping.tcp_packets.unwrap_or_default(),
625 udp_ping_avg: ping.udp_ping_avg.unwrap_or_default(),
626 udp_ping_var: ping.udp_ping_var.unwrap_or_default(),
627 tcp_ping_avg: ping.tcp_ping_avg.unwrap_or_default(),
628 tcp_ping_var: ping.tcp_ping_var.unwrap_or_default(),
629 }
630}
631
632/// What this connection may be told about itself.
633///
634/// Three kinds of number, and they are not worth the same:
635///
636/// - `from_client` is the **server's** decryption tally for this peer, the one
637/// thing here the client cannot know. It is the same triplet its `Ping`
638/// replies already carry.
639/// - `bandwidth` and the two times are measured here too.
640/// - everything else is the client's own report, handed straight back. It tells
641/// the client nothing new, but the information window hides the whole UDP
642/// block unless **both** halves are present, so the mirror is what makes the
643/// half that matters visible at all.
644///
645/// The certificate chain, the client version and the IP address are left out on
646/// purpose: a connection already knows all three about itself, and holding a DER
647/// chain per peer to fill a dialog is memory spent on nothing.
648///
649/// REF: references/mumble/src/mumble/UserInformation.cpp : the dialog calls
650/// `qgbUDP->setVisible(false)` unless `has_from_client() && has_from_server()`,
651/// and prints `bandwidth / 125.0` as kbit/s.
652fn own_stats(peer: &Peer, now: Instant) -> ControlMessage {
653 let (good, late, lost) = peer.crypt_counters();
654 let reported = peer.reported();
655 let (bandwidth, idle) = peer.traffic(now);
656 let seconds =
657 |duration: std::time::Duration| u32::try_from(duration.as_secs()).unwrap_or(u32::MAX);
658
659 ControlMessage::UserStats(tcp::UserStats {
660 session: Some(peer.session().0),
661 from_client: Some(tcp::user_stats::Stats {
662 good: Some(good),
663 late: Some(late),
664 lost: Some(lost),
665 // Nonce resync is refused, so zero is the count rather than a
666 // placeholder, exactly as in the `Ping` reply.
667 resync: Some(0),
668 }),
669 from_server: Some(tcp::user_stats::Stats {
670 good: Some(reported.good),
671 late: Some(reported.late),
672 lost: Some(reported.lost),
673 resync: Some(reported.resync),
674 }),
675 udp_packets: Some(reported.udp_packets),
676 tcp_packets: Some(reported.tcp_packets),
677 udp_ping_avg: Some(reported.udp_ping_avg),
678 udp_ping_var: Some(reported.udp_ping_var),
679 tcp_ping_avg: Some(reported.tcp_ping_avg),
680 tcp_ping_var: Some(reported.tcp_ping_var),
681 bandwidth: Some(bandwidth),
682 onlinesecs: Some(seconds(now.saturating_duration_since(peer.online_since()))),
683 idlesecs: Some(seconds(idle)),
684 ..Default::default()
685 })
686}
687
688/// The self-mute and self-deafen a `UserState` asks for, with the two
689/// implications that need no memory of the current state.
690///
691/// Deafened implies muted, and unmuting undeafens. Both are what the reference
692/// server does, and applying them at the protocol boundary keeps the flavor from
693/// having to know a Mumble rule. The order matters: a message asking to be
694/// deafened while unmuted resolves to "both", exactly as Murmur resolves it,
695/// because the deafen rewrite runs first and the unmute test then sees the
696/// rewritten value.
697///
698/// A flag the client did not mention stays `None`, because only the flavor knows
699/// what it currently renders.
700///
701/// REF: references/mumble/src/murmur/Messages.cpp : `msgUserState` sets
702/// `self_mute` when `self_deaf` is true, then clears `self_deaf` when
703/// `self_mute` is false.
704fn self_state(state: &tcp::UserState) -> (Option<bool>, Option<bool>) {
705 let mut self_mute = state.self_mute;
706 let mut self_deaf = state.self_deaf;
707
708 if self_deaf == Some(true) {
709 self_mute = Some(true);
710 }
711 if self_mute == Some(false) {
712 self_deaf = Some(false);
713 }
714
715 (self_mute, self_deaf)
716}
717
718/// Route a TCP-tunnelled voice packet (the UDP fallback of spec 15.6).
719///
720/// The payload is a plaintext UDP packet, so once decoded it goes through the
721/// very same routing as a datagram. Recipients on UDP are returned as datagrams;
722/// recipients on the tunnel are served inside the voice plane.
723fn tunnelled(voice: &Arc<VoicePlane>, peer: &Arc<Peer>, raw: &[u8]) -> Vec<(Vec<u8>, SocketAddr)> {
724 // The client is telling us its UDP does not work, so its own audio goes back
725 // over the tunnel until a datagram from it reaches us again.
726 // REF: references/mumble/src/murmur/Server.cpp : the `UDPTunnel` branch sets
727 // `u->aiUdpFlag = 0`.
728 peer.set_udp_mode(false);
729
730 if !limits::is_acceptable_size(raw.len()) {
731 eprintln!(
732 "mumble-server-runtime-gateway: session {:?}: dropping a {}-byte tunnelled packet",
733 peer.session(),
734 raw.len()
735 );
736 return Vec::new();
737 }
738
739 match decode_udp(raw) {
740 Ok(UdpMessage::Audio(audio)) => voice.route(peer, &audio, Instant::now(), raw.len()),
741 Ok(UdpMessage::Ping(_)) => {
742 // Connectivity pings belong on the UDP socket; one arriving here
743 // measures nothing, so it is refused rather than answered.
744 eprintln!(
745 "mumble-server-runtime-gateway: session {:?}: refusing a ping through the tunnel",
746 peer.session()
747 );
748 Vec::new()
749 }
750 Err(error) => {
751 eprintln!(
752 "mumble-server-runtime-gateway: session {:?}: bad tunnelled envelope: {error}",
753 peer.session()
754 );
755 Vec::new()
756 }
757 }
758}
759
760/// Build the reply to a TCP `Ping`.
761///
762/// Reporting `good` is not bookkeeping. The client reads it as `uiRemoteGood`
763/// and, if it is still zero twenty seconds into the session, decides its UDP
764/// never reaches us and falls back to the TCP tunnel permanently - while the UDP
765/// plane is working in both directions.
766///
767/// REF: references/mumble/src/mumble/ServerHandler.cpp : `TCPMessageType::Ping`
768/// disables UDP on `(uiRemoteGood == 0 || uiGood == 0) && bUdp && elapsed >
769/// 20000000`.
770fn ping_reply(request: &tcp::Ping, peer: &Peer) -> tcp::Ping {
771 let (good, late, lost) = peer.crypt_counters();
772 tcp::Ping {
773 timestamp: request.timestamp,
774 good: Some(good),
775 late: Some(late),
776 lost: Some(lost),
777 // Nonce resync is refused, so zero is the true count rather than a
778 // placeholder.
779 resync: Some(0),
780 ..Default::default()
781 }
782}
783
784/// REF: references/vendored/Mumble.proto : `PermissionDenied`.
785fn permission_denied(peer: &Peer) -> ControlMessage {
786 ControlMessage::PermissionDenied(tcp::PermissionDenied {
787 session: Some(peer.session().0),
788 reason: Some("This action is not available in the current view".to_owned()),
789 r#type: Some(i32::from(tcp::permission_denied::DenyType::Text)),
790 ..Default::default()
791 })
792}
793
794/// Name the drop so it is auditable rather than silent (R6).
795fn refused(kind: &str, peer: &Peer) {
796 eprintln!(
797 "mumble-server-runtime-gateway: session {:?}: refusing {kind}",
798 peer.session()
799 );
800}
801
802fn kind_of(message: &ControlMessage) -> &'static str {
803 match message {
804 ControlMessage::ChannelState(_) => "ChannelState",
805 ControlMessage::ChannelRemove(_) => "ChannelRemove",
806 ControlMessage::UserRemove(_) => "UserRemove",
807 ControlMessage::Acl(_) => "ACL",
808 ControlMessage::VoiceTarget(_) => "VoiceTarget",
809 ControlMessage::CryptSetup(_) => "CryptSetup(resync)",
810 ControlMessage::RequestBlob(_) => "RequestBlob",
811 _ => "an unsupported message",
812 }
813}
814
815/// Write everything already queued, then return.
816///
817/// `try_recv` is deliberate: the queue holds exactly what the shard's first
818/// transition put there, and waiting for more would wait forever.
819async fn drain(
820 writer: &mut WriteHalf<TlsStream<TcpStream>>,
821 outbound: &mut mpsc::Receiver<ControlMessage>,
822) -> Result<()> {
823 while let Ok(message) = outbound.try_recv() {
824 write_message(writer, &message).await?;
825 }
826 Ok(())
827}
828
829async fn write_message(
830 writer: &mut WriteHalf<TlsStream<TcpStream>>,
831 message: &ControlMessage,
832) -> Result<()> {
833 let mut framed = Vec::new();
834 encode_frame(message, &mut framed).context("encoding a control frame")?;
835 writer.write_all(&framed).await.context("TCP write")?;
836 writer.flush().await.context("TCP flush")?;
837 Ok(())
838}
839
840/// Incremental frame reader over the TLS read half.
841struct FrameReader {
842 read: ReadHalf<TlsStream<TcpStream>>,
843 buffer: Vec<u8>,
844}
845
846impl FrameReader {
847 fn new(read: ReadHalf<TlsStream<TcpStream>>) -> FrameReader {
848 FrameReader {
849 read,
850 buffer: Vec::with_capacity(4096),
851 }
852 }
853
854 /// The next complete control message, or `None` at a clean EOF on a frame
855 /// boundary. Reassembles across TLS records.
856 async fn next(&mut self) -> Result<Option<ControlMessage>> {
857 loop {
858 if let Some((message, consumed)) = self.try_parse()? {
859 self.buffer.drain(..consumed);
860 return Ok(Some(message));
861 }
862
863 let mut chunk = [0u8; 4096];
864 let read = self.read.read(&mut chunk).await.context("TCP read")?;
865 if read == 0 {
866 if self.buffer.is_empty() {
867 return Ok(None);
868 }
869 anyhow::bail!(
870 "connection closed mid-frame ({} bytes buffered)",
871 self.buffer.len()
872 );
873 }
874 self.buffer
875 .extend_from_slice(chunk.get(..read).unwrap_or_default());
876 }
877 }
878
879 fn try_parse(&self) -> Result<Option<(ControlMessage, usize)>> {
880 match parse_frame(&self.buffer).context("framing")? {
881 Some(frame) => {
882 let consumed = frame.total_len();
883 let message = decode_frame(&frame).context("decoding a control message")?;
884 Ok(Some((message, consumed)))
885 }
886 None => Ok(None),
887 }
888 }
889}
890
891#[cfg(test)]
892mod tests {
893 use super::*;
894
895 fn asked(self_mute: Option<bool>, self_deaf: Option<bool>) -> (Option<bool>, Option<bool>) {
896 self_state(&tcp::UserState {
897 self_mute,
898 self_deaf,
899 ..Default::default()
900 })
901 }
902
903 /// The whole table, because the two implications interact and the
904 /// interesting cases are the contradictory ones.
905 ///
906 /// REF: references/mumble/src/murmur/Messages.cpp : `msgUserState`. Each row
907 /// is what that code leaves in the broadcast message for the same input.
908 #[test]
909 fn the_self_state_resolves_the_way_the_reference_server_resolves_it() {
910 // What the official client always sends: both flags, no contradiction.
911 assert_eq!(asked(Some(true), Some(false)), (Some(true), Some(false)));
912 assert_eq!(asked(Some(false), Some(false)), (Some(false), Some(false)));
913 assert_eq!(asked(Some(true), Some(true)), (Some(true), Some(true)));
914
915 // Deafened wins over unmuted: Murmur overwrites `self_mute` before it
916 // ever reads it, so "deafen me but leave me unmuted" means both.
917 assert_eq!(asked(Some(false), Some(true)), (Some(true), Some(true)));
918
919 // One flag alone. Deafening still implies muting; unmuting still
920 // undeafens; the two that imply nothing leave the other untouched.
921 assert_eq!(asked(None, Some(true)), (Some(true), Some(true)));
922 assert_eq!(asked(Some(false), None), (Some(false), Some(false)));
923 assert_eq!(asked(Some(true), None), (Some(true), None));
924 assert_eq!(asked(None, Some(false)), (None, Some(false)));
925 }
926
927 #[test]
928 fn a_user_state_about_nothing_asks_for_nothing() {
929 // The guard that keeps `user_state` from forwarding an empty request,
930 // and therefore from acknowledging one.
931 assert_eq!(asked(None, None), (None, None));
932 }
933}