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}