mumble_protocol/
control.rs

1//! Control channel messages and codecs
2
3use bytes::Buf;
4use bytes::BufMut;
5use bytes::Bytes;
6use bytes::BytesMut;
7use protobuf::error::ProtobufError;
8use protobuf::Message;
9use std::convert::TryFrom;
10use std::convert::TryInto;
11use std::io;
12use std::io::Cursor;
13use std::marker::PhantomData;
14use tokio_util::codec::Decoder;
15use tokio_util::codec::Encoder;
16
17use crate::voice::Clientbound;
18use crate::voice::Serverbound;
19use crate::voice::VoiceCodec;
20use crate::voice::VoicePacket;
21use crate::voice::VoicePacketDst;
22
23/// ProtoBuf message types for all Mumble messages.
24#[allow(renamed_and_removed_lints)] // protobuf is missing `clippy::` prefix
25#[allow(missing_docs)] // these would have to be auto-generated by protobuf
26pub mod msgs {
27    /// Mumble message type to packet ID mappings.
28    pub mod id {
29        pub use super::super::generated_id::*;
30    }
31
32    include!(concat!(env!("OUT_DIR"), "/proto/mod.rs"));
33}
34
35/// Raw/not-yet-parsed Mumble control packet.
36#[derive(Clone, Debug, PartialEq)]
37pub struct RawControlPacket {
38    /// Packet ID
39    ///
40    /// See [msgs::id].
41    pub id: u16,
42    /// Raw message bytes.
43    pub bytes: Bytes,
44}
45
46/// A `Codec` implementation that parses a stream of data into [RawControlPacket]s.
47#[derive(Debug)]
48pub struct RawControlCodec;
49
50impl RawControlCodec {
51    /// Creates a new RawControlCodec.
52    pub fn new() -> Self {
53        Default::default()
54    }
55}
56
57impl Default for RawControlCodec {
58    fn default() -> Self {
59        RawControlCodec
60    }
61}
62
63impl Decoder for RawControlCodec {
64    type Item = RawControlPacket;
65    type Error = io::Error;
66
67    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<RawControlPacket>, io::Error> {
68        let buf_len = buf.len();
69        if buf_len >= 6 {
70            let mut buf = Cursor::new(buf);
71            let id = buf.get_u16();
72            let len = buf.get_u32() as usize;
73            if len > 0x7f_ffff {
74                Err(io::Error::new(io::ErrorKind::Other, "packet too long"))
75            } else if buf_len >= 6 + len {
76                let mut bytes = buf.into_inner().split_to(6 + len);
77                bytes.advance(6);
78                let bytes = bytes.freeze();
79                Ok(Some(RawControlPacket { id, bytes }))
80            } else {
81                Ok(None)
82            }
83        } else {
84            Ok(None)
85        }
86    }
87}
88
89impl Encoder<RawControlPacket> for RawControlCodec {
90    type Error = io::Error;
91
92    fn encode(&mut self, item: RawControlPacket, dst: &mut BytesMut) -> Result<(), io::Error> {
93        let id = item.id;
94        let bytes = &item.bytes;
95        let len = bytes.len();
96        dst.reserve(6 + len);
97        dst.put_u16(id);
98        dst.put_u32(len as u32);
99        dst.put_slice(bytes);
100        Ok(())
101    }
102}
103
104/// A `Codec` implementation that parses a stream of data into [ControlPacket]s.
105///
106/// Since [VoicePacket]s can be tunneled over the control channel and their encoding and decoding
107/// depends on their destination, the control codec also needs to know the side it's on.
108/// See [ServerControlCodec] and [ClientControlCodec] for the two most reasonable configurations.
109#[derive(Debug)]
110pub struct ControlCodec<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> {
111    inner: RawControlCodec,
112    _encode_dst: PhantomData<EncodeDst>,
113    _decode_dst: PhantomData<DecodeDst>,
114}
115/// The [ControlCodec] used on the server side.
116pub type ServerControlCodec = ControlCodec<Clientbound, Serverbound>;
117/// The [ControlCodec] used on the client side.
118pub type ClientControlCodec = ControlCodec<Serverbound, Clientbound>;
119
120impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> ControlCodec<EncodeDst, DecodeDst> {
121    /// Creates a new control codec.
122    pub fn new() -> Self {
123        Default::default()
124    }
125}
126
127impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> Default
128    for ControlCodec<EncodeDst, DecodeDst>
129{
130    fn default() -> Self {
131        ControlCodec {
132            inner: RawControlCodec::default(),
133            _encode_dst: PhantomData,
134            _decode_dst: PhantomData,
135        }
136    }
137}
138
139impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> Decoder
140    for ControlCodec<EncodeDst, DecodeDst>
141{
142    type Item = ControlPacket<DecodeDst>;
143    type Error = io::Error;
144
145    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
146        Ok(if let Some(raw_packet) = self.inner.decode(buf)? {
147            Some(raw_packet.try_into()?)
148        } else {
149            None
150        })
151    }
152}
153
154impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> Encoder<ControlPacket<EncodeDst>>
155    for ControlCodec<EncodeDst, DecodeDst>
156{
157    type Error = io::Error;
158
159    fn encode(
160        &mut self,
161        item: ControlPacket<EncodeDst>,
162        dst: &mut BytesMut,
163    ) -> Result<(), Self::Error> {
164        self.inner.encode(item.into(), dst)
165    }
166}
167
168/// Generates packet to ID mappings which will end up in [msgs::ids].
169macro_rules! define_packet_mappings {
170    ( @def $id:expr, $name:ident) => {
171        #[allow(dead_code)]
172        #[allow(non_upper_case_globals)]
173        pub const $name: u16 = $id;
174    };
175    ( @rec $id:expr, $(#[$attr:meta])* $head:ident ) => {
176        $(#[$attr])*
177        define_packet_mappings!(@def $id, $head);
178    };
179    ( @rec $id:expr, $(#[$attr:meta])* $head:ident, $( $(#[$attr_tail:meta])* $tail:ident ),* ) => {
180        $(#[$attr])*
181        define_packet_mappings!(@def $id, $head);
182        define_packet_mappings!(@rec $id + 1, $($(#[$attr_tail])* $tail),*);
183    };
184    ( $( $(#[$attrs:meta])* $names:ident ),* ) => {
185        define_packet_mappings!(@rec 0, $($(#[$attrs])* $names),*);
186    };
187}
188
189/// Generates From impls for converting between RawCtrlPck <=> ProtoMsg => CtrlPck
190macro_rules! define_packet_from {
191    ( $Dst:ident UDPTunnel($type:ty) ) => {
192        impl<$Dst: VoicePacketDst> From<VoicePacket<Dst>> for RawControlPacket {
193            fn from(msg: VoicePacket<Dst>) -> Self {
194                let mut buf = BytesMut::new();
195                VoiceCodec::<Dst, Dst>::default()
196                    .encode(msg, &mut buf)
197                    .expect("VoiceEncoder is infallible");
198                Self {
199                    id: msgs::id::UDPTunnel,
200                    bytes: buf.freeze(),
201                }
202            }
203        }
204        impl<$Dst: VoicePacketDst> TryFrom<RawControlPacket> for VoicePacket<$Dst> {
205            type Error = io::Error;
206
207            fn try_from(packet: RawControlPacket) -> Result<Self, Self::Error> {
208                if packet.id == msgs::id::UDPTunnel {
209                    packet.bytes.try_into()
210                } else {
211                    Err(io::Error::new(
212                        io::ErrorKind::Other,
213                        concat!("expected packet of type ", stringify!(UDPTunnel)),
214                    ))
215                }
216            }
217        }
218        impl<$Dst: VoicePacketDst> TryFrom<Bytes> for VoicePacket<$Dst> {
219            type Error = io::Error;
220
221            fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
222                VoiceCodec::<$Dst, $Dst>::default()
223                    .decode(&mut BytesMut::from(bytes.as_ref()))
224                    .map(|it| it.expect("VoiceCodec is stateless"))
225            }
226        }
227        impl<$Dst: VoicePacketDst> From<$type> for ControlPacket<$Dst> {
228            fn from(inner: $type) -> Self {
229                ControlPacket::UDPTunnel(Box::new(inner))
230            }
231        }
232    };
233    ( $Dst:ident $name:ident($type:ty) ) => {
234        impl<$Dst: VoicePacketDst> From<$type> for ControlPacket<$Dst> {
235            fn from(inner: $type) -> Self {
236                ControlPacket::$name(Box::new(inner))
237            }
238        }
239        impl From<$type> for RawControlPacket {
240            fn from(msg: $type) -> Self {
241                Self {
242                    id: self::msgs::id::$name,
243                    bytes: msg.write_to_bytes().unwrap().into(),
244                }
245            }
246        }
247        impl TryFrom<RawControlPacket> for $type {
248            type Error = ProtobufError;
249
250            fn try_from(packet: RawControlPacket) -> Result<Self, Self::Error> {
251                if packet.id == msgs::id::$name {
252                    Self::try_from(packet.bytes)
253                } else {
254                    Err(ProtobufError::IoError(io::Error::new(
255                        io::ErrorKind::Other,
256                        concat!("expected packet of type ", stringify!($name)),
257                    )))
258                }
259            }
260        }
261        impl TryFrom<&[u8]> for $type {
262            type Error = ProtobufError;
263
264            fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
265                protobuf::parse_from_bytes(bytes)
266            }
267        }
268        impl TryFrom<Bytes> for $type {
269            type Error = ProtobufError;
270
271            fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
272                bytes.as_ref().try_into()
273            }
274        }
275    };
276}
277
278/// Generates the ControlPacket enum, From impls for RawCtrlPck <=> CtrlPck and CtrlPck::name()
279macro_rules! define_packet_enum {
280    ( $Dst:ident $( $(#[$attr:meta])* $name:ident($type:ty) ),* ) => {
281        /// A parsed Mumble control packet.
282        #[derive(Debug, Clone, PartialEq)]
283        #[allow(clippy::large_enum_variant)]
284        #[non_exhaustive]
285        pub enum ControlPacket<$Dst: VoicePacketDst> {
286            $(
287                #[allow(missing_docs)]
288                $(#[$attr])*
289                $name(Box<$type>),
290            )*
291            /// A packet of unknown type.
292            Other(RawControlPacket),
293        }
294        impl<Dst: VoicePacketDst> TryFrom<RawControlPacket> for ControlPacket<$Dst> {
295            type Error = ProtobufError;
296
297            fn try_from(packet: RawControlPacket) -> Result<Self, Self::Error> {
298                Ok(match packet.id {
299                    $(
300                        $(#[$attr])*
301                        msgs::id::$name => {
302                            ControlPacket::$name(Box::new(packet.bytes.try_into()?))
303                        }
304                    )*
305                        _ => ControlPacket::Other(packet),
306                })
307            }
308        }
309        impl<Dst: VoicePacketDst> From<ControlPacket<$Dst>> for RawControlPacket {
310            fn from(packet: ControlPacket<$Dst>) -> Self {
311                match packet {
312                    $(
313                        $(#[$attr])*
314                        ControlPacket::$name(inner) => (*inner).into(),
315                    )*
316                        ControlPacket::Other(inner) => inner,
317                }
318            }
319        }
320        impl<Dst: VoicePacketDst> ControlPacket<$Dst> {
321            /// Returns the internal name of a packet (for debugging purposes).
322            pub fn name(&self) -> &'static str {
323                match self {
324                    $(
325                        $(#[$attr])*
326                        ControlPacket::$name(_) => stringify!($name),
327                    )*
328                    ControlPacket::Other(_) => "unknown",
329                }
330            }
331        }
332    };
333}
334
335macro_rules! define_packets {
336    ( < $Dst:ident > $( $(#[$attr:meta])* $name:ident($type:ty), )* ) => {
337        #[allow(missing_docs)]
338        mod generated_id {
339            define_packet_mappings!($($(#[$attr])* $name),*);
340        }
341        define_packet_enum!($Dst $($(#[$attr])* $name($type)),*);
342        $(
343            $(#[$attr])*
344            define_packet_from!($Dst $name($type));
345        )*
346    };
347}
348
349define_packets![
350    <Dst>
351    Version(msgs::Version),
352    UDPTunnel(VoicePacket<Dst>),
353    Authenticate(msgs::Authenticate),
354    Ping(msgs::Ping),
355    Reject(msgs::Reject),
356    ServerSync(msgs::ServerSync),
357    ChannelRemove(msgs::ChannelRemove),
358    ChannelState(msgs::ChannelState),
359    UserRemove(msgs::UserRemove),
360    UserState(msgs::UserState),
361    BanList(msgs::BanList),
362    TextMessage(msgs::TextMessage),
363    PermissionDenied(msgs::PermissionDenied),
364    ACL(msgs::ACL),
365    QueryUsers(msgs::QueryUsers),
366    CryptSetup(msgs::CryptSetup),
367    ContextActionModify(msgs::ContextActionModify),
368    ContextAction(msgs::ContextAction),
369    UserList(msgs::UserList),
370    VoiceTarget(msgs::VoiceTarget),
371    PermissionQuery(msgs::PermissionQuery),
372    CodecVersion(msgs::CodecVersion),
373    UserStats(msgs::UserStats),
374    RequestBlob(msgs::RequestBlob),
375    ServerConfig(msgs::ServerConfig),
376    SuggestConfig(msgs::SuggestConfig),
377    #[cfg(feature = "webrtc-extensions")]
378    WebRTC(msgs::WebRTC),
379    #[cfg(feature = "webrtc-extensions")]
380    IceCandidate(msgs::IceCandidate),
381    #[cfg(feature = "webrtc-extensions")]
382    TalkingState(msgs::TalkingState),
383];