1#![allow(clippy::new_ret_no_self)]
2use std::convert::TryInto;
3use std::io::prelude::*;
4use std::{fmt, io, str};
5
6use bitflags::bitflags;
7use num_derive::{FromPrimitive, ToPrimitive};
8use num_traits::{FromPrimitive as _, ToPrimitive as _};
9use omnom::{ReadExt, WriteExt};
10use serde::{Deserialize, Serialize};
11
12use crate::{Error, HexSlice, Result};
13
14#[derive(
15 Clone, Copy, Debug, Deserialize, Eq, FromPrimitive, Hash, PartialEq, ToPrimitive, Serialize,
16)]
17#[repr(u8)]
18pub enum PacketType {
19 Voice,
20 VoiceWhisper,
21 Command,
22 CommandLow,
23 Ping,
24 Pong,
25 Ack,
26 AckLow,
27 Init,
28}
29
30#[derive(Clone, Copy, Deserialize, Debug, Eq, PartialEq, Hash, Serialize)]
31pub enum Direction {
32 S2C,
34 C2S,
36}
37
38bitflags! {
39 pub struct Flags: u8 {
40 const UNENCRYPTED = 0x80;
41 const COMPRESSED = 0x40;
42 const NEWPROTOCOL = 0x20;
43 const FRAGMENTED = 0x10;
44 }
45}
46
47impl PacketType {
48 pub fn is_command(self) -> bool {
49 self == PacketType::Command || self == PacketType::CommandLow
50 }
51 pub fn is_ack(self) -> bool {
52 self == PacketType::Ack || self == PacketType::AckLow || self == PacketType::Pong
53 }
54 pub fn is_voice(self) -> bool { self == PacketType::Voice || self == PacketType::VoiceWhisper }
55}
56
57#[repr(u8)]
58#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive, ToPrimitive)]
59pub enum CodecType {
60 SpeexNarrowband,
62 SpeexWideband,
64 SpeexUltrawideband,
66 CeltMono,
68 OpusVoice,
70 OpusMusic,
72}
73
74macro_rules! create_buf {
75 ($($name:ident, $borrow_name:ident, $convert:ident);*) => {
76 rental! {
77 pub mod rentals {
78 $(
79 #[rental(covariant, debug)]
80 pub struct $name {
81 data: Vec<u8>,
82 content: super::$borrow_name<'data>,
83 }
84 )*
85 }
86 }
87
88 $(
89 #[derive(Debug)]
90 pub struct $name(pub rentals::$name);
91 impl $name {
92 #[inline]
95 pub fn try_new(direction: Direction, data: Vec<u8>) -> Result<Self> {
96 Ok(Self(rentals::$name::try_new(data, |d| {
97 InPacket::new(direction, d).$convert()
98 }).map_err(|e| e.0)?))
99 }
100 #[inline]
101 pub fn raw_data(&self) -> &[u8] { self.0.head() }
102 #[inline]
103 pub fn data(&self) -> &$borrow_name { self.0.suffix() }
104 #[inline]
105 pub fn into_buffer(self) -> Vec<u8> { self.0.into_head() }
106 }
107 )*
108 }
109}
110
111create_buf!(InAudioBuf, InAudio, into_audio;
112 InCommandBuf, InCommand, into_command;
113 InC2SInitBuf, InC2SInit, into_c2sinit;
114 InS2CInitBuf, InS2CInit, into_s2cinit);
115
116#[derive(Clone)]
118pub struct InUdpPacket<'a>(pub InPacket<'a>);
119
120impl<'a> InUdpPacket<'a> {
121 pub fn new(packet: InPacket<'a>) -> Self { Self(packet) }
122}
123
124#[derive(Clone)]
125pub struct InHeader<'a> {
126 direction: Direction,
127 data: &'a [u8],
128}
129
130#[derive(Clone)]
131pub struct InPacket<'a> {
132 header: InHeader<'a>,
133 content: &'a [u8],
134}
135
136#[derive(Clone, Debug)]
137pub struct InCommand<'a> {
138 packet: InPacket<'a>,
139}
140
141#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize)]
142pub struct OutUdpPacket {
143 generation_id: u32,
144 data: OutPacket,
145}
146
147#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize)]
148pub struct OutPacket {
149 dir: Direction,
150 data: Vec<u8>,
151}
152
153#[derive(Clone)]
159pub enum C2SInitData<'a> {
160 Init0 {
161 version: u32,
162 timestamp: u32,
163 random0: &'a [u8; 4],
164 },
165 Init2 {
166 version: u32,
167 random1: &'a [u8; 16],
168 random0_r: &'a [u8; 4],
169 },
170 Init4 {
171 version: u32,
172 x: &'a [u8; 64],
173 n: &'a [u8; 64],
174 level: u32,
175 random2: &'a [u8; 100],
176 y: &'a [u8; 64],
178 command: &'a [u8],
180 },
181}
182
183#[derive(Clone)]
184pub enum S2CInitData<'a> {
185 Init1 { random1: &'a [u8; 16], random0_r: &'a [u8; 4] },
186 Init3 { x: &'a [u8; 64], n: &'a [u8; 64], level: u32, random2: &'a [u8; 100] },
187 Init127 {},
188}
189
190#[derive(Clone, Debug)]
191pub struct InS2CInit<'a> {
192 packet: InPacket<'a>,
193 data: S2CInitData<'a>,
194}
195
196#[derive(Clone, Debug)]
197pub struct InC2SInit<'a> {
198 packet: InPacket<'a>,
199 data: C2SInitData<'a>,
200}
201
202#[derive(Clone, Debug, Eq, PartialEq)]
203pub enum AudioData<'a> {
204 C2S {
205 id: u16,
206 codec: CodecType,
207 data: &'a [u8],
208 },
209 C2SWhisper {
210 id: u16,
211 codec: CodecType,
212 channels: Vec<u64>,
213 clients: Vec<u16>,
214 data: &'a [u8],
215 },
216 C2SWhisperNew {
218 id: u16,
219 codec: CodecType,
220 whisper_type: u8,
221 target: u8,
222 target_id: u64,
223 data: &'a [u8],
224 },
225
226 S2C {
227 id: u16,
228 from: u16,
229 codec: CodecType,
230 data: &'a [u8],
231 },
232 S2CWhisper {
233 id: u16,
234 from: u16,
235 codec: CodecType,
236 data: &'a [u8],
237 },
238}
239
240#[derive(Clone)]
241pub struct InAudio<'a> {
242 packet: InPacket<'a>,
243 data: AudioData<'a>,
244}
245
246#[must_use]
247pub struct OutCommand(pub OutPacket);
248pub struct OutC2SInit0;
249pub struct OutC2SInit2;
250pub struct OutC2SInit4;
251pub struct OutS2CInit1;
252pub struct OutS2CInit3;
253pub struct OutAck;
254pub struct OutAudio;
255
256struct EscapedWriter<'a>(&'a mut Vec<u8>);
258
259impl Direction {
260 #[inline]
261 pub fn reverse(self) -> Self {
262 match self {
263 Direction::S2C => Direction::C2S,
264 Direction::C2S => Direction::S2C,
265 }
266 }
267}
268
269impl<'a> InPacket<'a> {
270 #[inline]
272 pub fn try_new(direction: Direction, data: &'a [u8]) -> Result<Self> {
273 let header_len =
274 if direction == Direction::S2C { crate::S2C_HEADER_LEN } else { crate::C2S_HEADER_LEN };
275 if data.len() < header_len {
276 return Err(Error::PacketTooShort(data.len()));
277 }
278
279 let p_type = data[header_len - 1] & 0xf;
281 if p_type > 8 {
282 return Err(Error::UnknownPacketType(p_type));
283 }
284
285 Ok(Self::new(direction, data))
286 }
287
288 #[inline]
292 pub fn new(direction: Direction, data: &'a [u8]) -> Self {
293 let header = InHeader::new(direction, data);
294 let header_len = header.data.len();
295
296 Self { header, content: &data[header_len..] }
297 }
298
299 #[inline]
300 pub fn header(&self) -> &InHeader<'a> { &self.header }
301 #[inline]
302 pub fn content(&self) -> &[u8] { self.content }
303
304 #[inline]
306 pub fn ack_packet(&self) -> Result<Option<u16>> {
307 let p_type = self.header().packet_type();
308 if p_type.is_ack() {
309 Ok(Some(
310 self.content()
311 .read_be()
312 .map_err(|_| Error::PacketContentTooShort(self.content().len()))?,
313 ))
314 } else if p_type == PacketType::Init {
315 if self.header.direction == Direction::S2C {
316 Ok(Some(
317 self.content
318 .get(0)
319 .ok_or_else(|| Error::PacketContentTooShort(self.content().len()))
320 .and_then(|i| match u16::from(*i) {
321 1 => Ok(0),
322 3 => Ok(2),
323 127 => Ok(2), _ => Err(Error::InvalidInitStep(*i)),
325 })?,
326 ))
327 } else {
328 Ok(self
329 .content
330 .get(4)
331 .ok_or_else(|| Error::PacketContentTooShort(self.content().len()))
332 .and_then(|i| match u16::from(*i) {
333 0 => Ok(None),
334 2 => Ok(Some(1)),
335 4 => Ok(Some(3)),
336 _ => Err(Error::InvalidInitStep(*i)),
337 })?)
338 }
339 } else {
340 Ok(None)
341 }
342 }
343
344 pub fn into_audio(self) -> Result<InAudio<'a>> {
346 let p_type = self.header().packet_type();
347 let newprotocol = self.header().flags().contains(Flags::NEWPROTOCOL);
348 let data = AudioData::parse(p_type, newprotocol, self.header.direction, self.content)?;
349
350 Ok(InAudio { packet: self, data })
351 }
352
353 pub fn into_command(self) -> Result<InCommand<'a>> { Ok(InCommand { packet: self }) }
355
356 pub fn into_s2cinit(self) -> Result<InS2CInit<'a>> {
357 if self.header.direction != Direction::S2C {
358 return Err(Error::WrongDirection);
359 }
360 let p_type = self.header().packet_type();
361 if p_type != PacketType::Init {
362 return Err(Error::WrongPacketType(p_type));
363 }
364 let mac = self.header().mac();
365 if mac != b"TS3INIT1" {
366 return Err(Error::WrongInitMac(mac.to_vec()));
367 }
368
369 if self.content.is_empty() {
370 return Err(Error::PacketContentTooShort(self.content.len()));
371 }
372
373 let data;
374 if self.content[0] == 1 {
375 if self.content.len() < 21 {
376 return Err(Error::PacketContentTooShort(self.content.len()));
377 }
378 data = S2CInitData::Init1 {
379 random1: (&self.content[1..17]).try_into().unwrap(),
380 random0_r: (&self.content[17..21]).try_into().unwrap(),
381 };
382 } else if self.content[0] == 3 {
383 if self.content.len() < 233 {
384 return Err(Error::PacketContentTooShort(self.content.len()));
385 }
386 data = S2CInitData::Init3 {
387 x: (&self.content[1..65]).try_into().unwrap(),
388 n: (&self.content[65..129]).try_into().unwrap(),
389 level: (&self.content[129..]).read_be()?,
390 random2: (&self.content[133..233]).try_into().unwrap(),
391 };
392 } else if self.content[0] == 127 {
393 data = S2CInitData::Init127 {};
394 } else {
395 return Err(Error::InvalidInitStep(self.content[0]));
396 }
397
398 Ok(InS2CInit { packet: self, data })
399 }
400
401 pub fn into_c2sinit(self) -> Result<InC2SInit<'a>> {
402 if self.header.direction != Direction::C2S {
403 return Err(Error::WrongDirection);
404 }
405 let p_type = self.header().packet_type();
406 if p_type != PacketType::Init {
407 return Err(Error::WrongPacketType(p_type));
408 }
409 let mac = self.header().mac();
410 if mac != b"TS3INIT1" {
411 return Err(Error::WrongInitMac(mac.to_vec()));
412 }
413
414 if self.content.len() < 5 {
415 return Err(Error::PacketContentTooShort(self.content.len()));
416 }
417
418 let data;
419 let version = (&self.content[0..]).read_be()?;
420 if self.content[4] == 0 {
421 if self.content.len() < 13 {
422 return Err(Error::PacketContentTooShort(self.content.len()));
423 }
424 data = C2SInitData::Init0 {
425 version,
426 timestamp: (&self.content[5..]).read_be()?,
427 random0: (&self.content[9..13]).try_into().unwrap(),
428 };
429 } else if self.content[4] == 2 {
430 if self.content.len() < 25 {
431 return Err(Error::PacketContentTooShort(self.content.len()));
432 }
433 data = C2SInitData::Init2 {
434 version,
435 random1: (&self.content[5..21]).try_into().unwrap(),
436 random0_r: (&self.content[21..25]).try_into().unwrap(),
437 };
438 } else if self.content[4] == 4 {
439 let len = 5 + 128 + 4 + 100 + 64;
440 if self.content.len() < len + 20 {
441 return Err(Error::PacketContentTooShort(self.content.len()));
442 }
443 data = C2SInitData::Init4 {
444 version,
445 x: (&self.content[5..69]).try_into().unwrap(),
446 n: (&self.content[69..133]).try_into().unwrap(),
447 level: (&self.content[133..]).read_be()?,
448 random2: (&self.content[137..237]).try_into().unwrap(),
449 y: (&self.content[237..301]).try_into().unwrap(),
450 command: &self.content[len..],
451 };
452 } else {
453 return Err(Error::InvalidInitStep(self.content[0]));
454 }
455
456 Ok(InC2SInit { packet: self, data })
457 }
458}
459
460impl fmt::Debug for InPacket<'_> {
461 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
462 write!(f, "Packet({:?}", self.header())?;
463 let mut success = false;
464 match self.header.packet_type() {
465 PacketType::Voice | PacketType::VoiceWhisper => {
466 if let Ok(packet) = self.clone().into_audio() {
467 success = true;
468 write!(f, ", {:?}", packet)?;
469 }
470 }
471 PacketType::Command | PacketType::CommandLow => {
472 if let Ok(packet) = str::from_utf8(self.content()) {
473 success = true;
474 write!(f, ", {:?}", packet)?;
475 }
476 }
477 PacketType::Ping | PacketType::Pong | PacketType::Ack | PacketType::AckLow => {
478 success = true;
479 if !self.content().is_empty() {
480 write!(f, ", 0x")?;
481 }
482 for b in self.content() {
483 write!(f, "{:02x}", b)?;
484 }
485 }
486 PacketType::Init => {
487 if self.header.direction == Direction::C2S {
488 if let Ok(packet) = self.clone().into_c2sinit() {
489 success = true;
490 write!(f, ", {:?}", packet.data)?;
491 }
492 } else if let Ok(packet) = self.clone().into_s2cinit() {
493 success = true;
494 write!(f, ", {:?}", packet.data)?;
495 }
496 }
497 }
498
499 if !success {
500 write!(f, ", failed to parse, content: {})", HexSlice(self.content()))?;
501 }
502
503 write!(f, ")")?;
504 Ok(())
505 }
506}
507
508impl fmt::Debug for InUdpPacket<'_> {
509 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
510 write!(f, "Packet({:?}, content: {})", self.0.header(), HexSlice(self.0.content()))?;
511 Ok(())
512 }
513}
514
515impl fmt::Debug for InHeader<'_> {
516 #[rustfmt::skip]
517 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
518 write!(f, "Header(")?;
519 if self.mac() != &[0; 8] {
520 write!(f, "mac: {}, ", HexSlice(self.mac()))?;
521 }
522 write!(f, "id: {:#x}, ", self.packet_id())?;
523 if let Some(c_id) = self.client_id() {
524 write!(f, "c_id: {:#x}, ", c_id)?;
525 }
526 write!(f, "{:?}, ", self.packet_type())?;
527 write!(f, "")?;
528 let flags = self.flags();
529 write!(f, "{}", if flags.contains(Flags::UNENCRYPTED) { "u" } else { "-" })?;
530 write!(f, "{}", if flags.contains(Flags::COMPRESSED) { "c" } else { "-" })?;
531 write!(f, "{}", if flags.contains(Flags::NEWPROTOCOL) { "n" } else { "-" })?;
532 write!(f, "{}", if flags.contains(Flags::FRAGMENTED) { "f" } else { "-" })?;
533
534 write!(f, ")")?;
535 Ok(())
536 }
537}
538
539impl<'a> InHeader<'a> {
540 #[inline]
541 pub fn new(direction: Direction, data: &'a [u8]) -> Self {
542 let header_len =
543 if direction == Direction::S2C { crate::S2C_HEADER_LEN } else { crate::C2S_HEADER_LEN };
544
545 Self { direction, data: &data[..header_len] }
546 }
547
548 #[inline]
550 fn get_off(&self) -> usize { if self.direction == Direction::S2C { 10 } else { 12 } }
551
552 #[inline]
553 pub fn direction(&self) -> Direction { self.direction }
554 #[inline]
555 pub fn data(&self) -> &'a [u8] { self.data }
556 #[inline]
557 pub fn mac(&self) -> &'a [u8; 8] { (&self.data[..8]).try_into().unwrap() }
558 #[inline]
559 pub fn packet_id(&self) -> u16 { (&self.data[8..10]).read_be().unwrap() }
560
561 #[inline]
562 pub fn client_id(&self) -> Option<u16> {
563 if self.direction == Direction::S2C {
564 None
565 } else {
566 Some((&self.data[10..12]).read_be().unwrap())
567 }
568 }
569
570 #[inline]
571 pub fn flags(&self) -> Flags { Flags::from_bits(self.data[self.get_off()] & 0xf0).unwrap() }
572
573 #[inline]
574 pub fn packet_type(&self) -> PacketType {
575 PacketType::from_u8(self.data[self.get_off()] & 0xf).unwrap()
576 }
577
578 pub fn get_meta(&self) -> &'a [u8] { &self.data[8..] }
579}
580
581impl C2SInitData<'_> {
582 pub fn get_step(&self) -> u8 {
583 match self {
584 C2SInitData::Init0 { .. } => 0,
585 C2SInitData::Init2 { .. } => 2,
586 C2SInitData::Init4 { .. } => 4,
587 }
588 }
589}
590
591impl<'a> fmt::Debug for C2SInitData<'a> {
592 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
593 match self {
594 C2SInitData::Init0 { .. } => write!(f, "Init0"),
595 C2SInitData::Init2 { .. } => write!(f, "Init2"),
596 C2SInitData::Init4 { level, command, .. } => {
597 write!(f, "Init4(level: {}, ", level)?;
598 if let Ok(s) = str::from_utf8(command) {
599 write!(f, "{:?}", s)?;
600 } else {
601 write!(f, "{}", HexSlice(command))?;
602 }
603 write!(f, ")")?;
604 Ok(())
605 }
606 }
607 }
608}
609
610impl S2CInitData<'_> {
611 pub fn get_step(&self) -> u8 {
612 match self {
613 S2CInitData::Init1 { .. } => 1,
614 S2CInitData::Init3 { .. } => 3,
615 S2CInitData::Init127 { .. } => 127,
616 }
617 }
618}
619
620impl<'a> fmt::Debug for S2CInitData<'a> {
621 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
622 match self {
623 S2CInitData::Init1 { .. } => write!(f, "Init1"),
624 S2CInitData::Init3 { level, .. } => write!(f, "Init3(level: {})", level),
625 S2CInitData::Init127 { .. } => write!(f, "Init127"),
626 }
627 }
628}
629
630impl<'a> InCommand<'a> {
631 #[inline]
632 pub fn packet(&self) -> &InPacket<'a> { &self.packet }
633}
634
635impl<'a> AudioData<'a> {
636 pub fn parse(
637 p_type: PacketType, newprotocol: bool, dir: Direction, content: &'a [u8],
638 ) -> Result<Self> {
639 let id = (&content[..]).read_be()?;
640 if p_type == PacketType::Voice {
641 if dir == Direction::S2C {
642 if content.len() < 5 {
643 return Err(Error::PacketContentTooShort(content.len()));
644 }
645 Ok(AudioData::S2C {
646 id,
647 from: (&content[2..]).read_be()?,
648 codec: CodecType::from_u8(content[4])
649 .ok_or_else(|| Error::InvalidCodec(content[4]))?,
650 data: &content[5..],
651 })
652 } else {
653 if content.len() < 3 {
654 return Err(Error::PacketContentTooShort(content.len()));
655 }
656 Ok(AudioData::C2S {
657 id,
658 codec: CodecType::from_u8(content[2])
659 .ok_or_else(|| Error::InvalidCodec(content[4]))?,
660 data: &content[3..],
661 })
662 }
663 } else if dir == Direction::S2C {
664 if content.len() < 5 {
665 return Err(Error::PacketContentTooShort(content.len()));
666 }
667 Ok(AudioData::S2CWhisper {
668 id,
669 from: (&content[2..]).read_be()?,
670 codec: CodecType::from_u8(content[4])
671 .ok_or_else(|| Error::InvalidCodec(content[4]))?,
672 data: &content[5..],
673 })
674 } else {
675 if content.len() < 3 {
676 return Err(Error::PacketContentTooShort(content.len()));
677 }
678 let codec =
679 CodecType::from_u8(content[2]).ok_or_else(|| Error::InvalidCodec(content[4]))?;
680 if newprotocol {
681 if content.len() < 14 {
682 return Err(Error::PacketContentTooShort(content.len()));
683 }
684 Ok(AudioData::C2SWhisperNew {
685 id,
686 codec,
687 whisper_type: content[3],
688 target: content[4],
689 target_id: (&content[5..]).read_be()?,
690 data: &content[13..],
691 })
692 } else {
693 if content.len() < 5 {
694 return Err(Error::PacketContentTooShort(content.len()));
695 }
696 let channel_count = content[3] as usize;
697 let client_count = content[4] as usize;
698 let channel_off = 5;
699 let client_off = channel_off + channel_count * 8;
700 let off = client_off + client_count * 2;
701 if content.len() < off {
702 return Err(Error::PacketContentTooShort(content.len()));
703 }
704
705 Ok(AudioData::C2SWhisper {
706 id,
707 codec,
708 channels: (0..channel_count)
709 .map(|i| (&content[channel_off + i * 8..]).read_be())
710 .collect::<::std::result::Result<Vec<_>, _>>()?,
711 clients: (0..client_count)
712 .map(|i| (&content[client_off + i * 2..]).read_be())
713 .collect::<::std::result::Result<Vec<_>, _>>()?,
714 data: &content[off..],
715 })
716 }
717 }
718 }
719
720 #[inline]
721 pub fn direction(&self) -> Direction {
722 match self {
723 AudioData::C2S { .. } => Direction::C2S,
724 AudioData::C2SWhisper { .. } => Direction::C2S,
725 AudioData::C2SWhisperNew { .. } => Direction::C2S,
726 AudioData::S2C { .. } => Direction::S2C,
727 AudioData::S2CWhisper { .. } => Direction::S2C,
728 }
729 }
730
731 #[inline]
732 pub fn packet_type(&self) -> PacketType {
733 match self {
734 AudioData::C2S { .. } => PacketType::Voice,
735 AudioData::C2SWhisper { .. } => PacketType::VoiceWhisper,
736 AudioData::C2SWhisperNew { .. } => PacketType::VoiceWhisper,
737 AudioData::S2C { .. } => PacketType::Voice,
738 AudioData::S2CWhisper { .. } => PacketType::VoiceWhisper,
739 }
740 }
741
742 #[inline]
743 pub fn codec(&self) -> CodecType {
744 match self {
745 AudioData::C2S { codec, .. } => *codec,
746 AudioData::C2SWhisper { codec, .. } => *codec,
747 AudioData::C2SWhisperNew { codec, .. } => *codec,
748 AudioData::S2C { codec, .. } => *codec,
749 AudioData::S2CWhisper { codec, .. } => *codec,
750 }
751 }
752
753 #[inline]
754 pub fn id(&self) -> u16 {
755 match self {
756 AudioData::C2S { id, .. } => *id,
757 AudioData::C2SWhisper { id, .. } => *id,
758 AudioData::C2SWhisperNew { id, .. } => *id,
759 AudioData::S2C { id, .. } => *id,
760 AudioData::S2CWhisper { id, .. } => *id,
761 }
762 }
763
764 #[inline]
765 pub fn flags(&self) -> Flags {
766 match self {
767 AudioData::C2S { .. } => Flags::empty(),
768 AudioData::C2SWhisper { .. } => Flags::empty(),
769 AudioData::C2SWhisperNew { .. } => Flags::NEWPROTOCOL,
770 AudioData::S2C { .. } => Flags::empty(),
771 AudioData::S2CWhisper { .. } => Flags::empty(),
772 }
773 }
774
775 #[inline]
776 pub fn data(&self) -> &[u8] {
777 match self {
778 AudioData::C2S { data, .. } => data,
779 AudioData::C2SWhisper { data, .. } => data,
780 AudioData::C2SWhisperNew { data, .. } => data,
781 AudioData::S2C { data, .. } => data,
782 AudioData::S2CWhisper { data, .. } => data,
783 }
784 }
785}
786
787impl<'a> InS2CInit<'a> {
788 #[inline]
789 pub fn packet(&self) -> &InPacket<'a> { &self.packet }
790 #[inline]
791 pub fn data(&self) -> &S2CInitData { &self.data }
792}
793
794impl<'a> InC2SInit<'a> {
795 #[inline]
796 pub fn packet(&self) -> &InPacket<'a> { &self.packet }
797 #[inline]
798 pub fn data(&self) -> &C2SInitData { &self.data }
799}
800
801impl<'a> InAudio<'a> {
802 #[inline]
803 pub fn packet(&self) -> &InPacket<'a> { &self.packet }
804 #[inline]
805 pub fn data(&self) -> &AudioData { &self.data }
806}
807
808impl fmt::Debug for InAudio<'_> {
809 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
810 match &self.data {
811 AudioData::C2S { id, codec, data } => {
812 write!(f, "Audio(id: {}, {:?}, {})", id, codec, HexSlice(data))?;
813 }
814 AudioData::C2SWhisper { id, codec, channels, clients, data } => {
815 write!(
816 f,
817 "Whisper(id: {}, {:?}, channels: {:?}, clients: {:?}, {})",
818 id,
819 codec,
820 channels,
821 clients,
822 HexSlice(data)
823 )?;
824 }
825 AudioData::C2SWhisperNew { id, codec, whisper_type, target, target_id, data } => {
826 write!(
827 f,
828 "WhisperNew(id: {}, {:?}, type: {}, target: {}, target_id: {}, {})",
829 id,
830 codec,
831 whisper_type,
832 target,
833 target_id,
834 HexSlice(data)
835 )?;
836 }
837 AudioData::S2C { id, from, codec, data } => {
838 write!(f, "Audio(id: {}, from: {}, {:?}, {})", id, from, codec, HexSlice(data))?;
839 }
840 AudioData::S2CWhisper { id, from, codec, data } => {
841 write!(f, "Whisper(id: {}, from: {}, {:?}, {})", id, from, codec, HexSlice(data))?;
842 }
843 }
844
845 Ok(())
846 }
847}
848
849impl OutPacket {
850 #[inline]
851 pub fn new(
852 mac: [u8; 8], packet_id: u16, client_id: Option<u16>, flags: Flags, packet_type: PacketType,
853 ) -> Self {
854 let dir = if client_id.is_some() { Direction::C2S } else { Direction::S2C };
855 let mut res = Self::new_with_dir(dir, flags, packet_type);
856 res.data[..8].copy_from_slice(&mac);
857 res.packet_id(packet_id);
858 if let Some(cid) = client_id {
859 res.client_id(cid);
860 }
861 res
862 }
863
864 #[inline]
866 pub fn new_with_dir(dir: Direction, flags: Flags, packet_type: PacketType) -> Self {
867 let data =
868 vec![
869 0;
870 if dir == Direction::S2C { crate::S2C_HEADER_LEN } else { crate::C2S_HEADER_LEN }
871 ];
872 let mut res = Self { dir, data };
873 res.flags(flags);
874 res.packet_type(packet_type);
875 res
876 }
877
878 #[inline]
879 pub fn new_from_data(dir: Direction, data: Vec<u8>) -> Self { Self { dir, data } }
880
881 #[inline]
882 pub fn into_vec(self) -> Vec<u8> { self.data }
883
884 #[inline]
885 fn content_offset(&self) -> usize {
886 if self.dir == Direction::S2C { crate::S2C_HEADER_LEN } else { crate::C2S_HEADER_LEN }
887 }
888
889 #[inline]
890 pub fn data(&self) -> &[u8] { &self.data }
891 #[inline]
892 pub fn data_mut(&mut self) -> &mut Vec<u8> { &mut self.data }
893 #[inline]
894 pub fn content(&self) -> &[u8] { &self.data[self.content_offset()..] }
895 #[inline]
896 pub fn content_mut(&mut self) -> &mut [u8] {
897 let off = self.content_offset();
898 &mut self.data[off..]
899 }
900 #[inline]
901 pub fn direction(&self) -> Direction { self.dir }
902 #[inline]
903 pub fn header(&self) -> InHeader { InHeader { direction: self.dir, data: self.header_bytes() } }
904 #[inline]
905 pub fn header_bytes(&self) -> &[u8] { &self.data[..self.content_offset()] }
906 #[inline]
907 pub fn packet(&self) -> InPacket { InPacket::new(self.dir, &self.data) }
908
909 #[inline]
910 pub fn mac(&mut self) -> &mut [u8; 8] { (&mut self.data[0..8]).try_into().unwrap() }
911 #[inline]
912 pub fn packet_id(&mut self, packet_id: u16) {
913 (&mut self.data[8..10]).write_be(packet_id).unwrap();
914 }
915 #[inline]
916 pub fn client_id(&mut self, client_id: u16) {
917 assert_eq!(
918 self.dir,
919 Direction::C2S,
920 "Client id is only valid for client to server packets"
921 );
922 (&mut self.data[10..12]).write_be(client_id).unwrap();
923 }
924 #[inline]
925 pub fn flags(&mut self, flags: Flags) {
926 let off = self.header().get_off();
927 self.data[off] = (self.data[off] & 0xf) | flags.bits();
928 }
929 #[inline]
930 pub fn packet_type(&mut self, packet_type: PacketType) {
931 let off = self.header().get_off();
932 self.data[off] = (self.data[off] & 0xf0) | packet_type.to_u8().unwrap();
933 }
934}
935
936impl OutUdpPacket {
937 #[inline]
938 pub fn new(generation_id: u32, data: OutPacket) -> Self { Self { generation_id, data } }
939
940 #[inline]
941 pub fn generation_id(&self) -> u32 { self.generation_id }
942 #[inline]
943 pub fn data(&self) -> &OutPacket { &self.data }
944
945 #[inline]
946 pub fn packet_id(&self) -> u16 {
947 if self.packet_type() == PacketType::Init {
948 if self.data.dir == Direction::S2C {
949 u16::from(self.data.content()[0])
950 } else {
951 u16::from(self.data.content()[4])
952 }
953 } else {
954 self.data.header().packet_id()
955 }
956 }
957 #[inline]
958 pub fn packet_type(&self) -> PacketType { self.data.header().packet_type() }
959}
960
961impl io::Write for EscapedWriter<'_> {
962 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
963 self.0.reserve(buf.len());
964 for c in buf {
965 match c {
966 b'\x0b' => self.0.extend_from_slice(b"\\v"),
967 b'\x0c' => self.0.extend_from_slice(b"\\f"),
968 b'\\' => self.0.extend_from_slice(b"\\\\"),
969 b'\t' => self.0.extend_from_slice(b"\\t"),
970 b'\r' => self.0.extend_from_slice(b"\\r"),
971 b'\n' => self.0.extend_from_slice(b"\\n"),
972 b'|' => self.0.extend_from_slice(b"\\p"),
973 b' ' => self.0.extend_from_slice(b"\\s"),
974 b'/' => self.0.extend_from_slice(b"\\/"),
975 c => self.0.push(*c),
976 }
977 }
978 Ok(buf.len())
979 }
980
981 #[inline]
982 fn flush(&mut self) -> io::Result<()> { Ok(()) }
983}
984
985impl OutCommand {
986 #[inline]
987 pub fn new(dir: Direction, flags: Flags, p_type: PacketType, name: &str) -> Self {
988 let mut res = Self(OutPacket::new_with_dir(dir, Flags::empty(), p_type));
989 res.0.flags(flags);
990 res.0.data.extend_from_slice(name.as_bytes());
991 res
992 }
993
994 #[inline]
996 pub fn write_bin_arg(&mut self, name: &str, value: &[u8]) {
997 if self.0.content().last() != Some(&b'|') && !self.0.content().is_empty() {
998 self.0.data.push(b' ');
999 }
1000 self.0.data.extend_from_slice(name.as_bytes());
1001 if !value.is_empty() {
1002 self.0.data.push(b'=');
1003 EscapedWriter(&mut self.0.data).write_all(value).unwrap();
1004 }
1005 }
1006
1007 #[inline]
1009 pub fn write_arg(&mut self, name: &str, value: &dyn fmt::Display) {
1010 if self.0.content().last() != Some(&b'|') && !self.0.content().is_empty() {
1011 self.0.data.push(b' ');
1012 }
1013 self.0.data.extend_from_slice(name.as_bytes());
1014 self.0.data.push(b'=');
1015 let len = self.0.data.len();
1016 write!(EscapedWriter(&mut self.0.data), "{}", value).unwrap();
1017 if self.0.data.len() == len {
1018 self.0.data.pop();
1020 }
1021 }
1022
1023 #[inline]
1025 pub fn start_new_part(&mut self) { self.0.data.push(b'|'); }
1026 #[inline]
1027 pub fn into_packet(self) -> OutPacket { self.0 }
1028}
1029
1030impl OutC2SInit0 {
1031 pub fn new(version: u32, timestamp: u32, random0: [u8; 4]) -> OutPacket {
1032 let mut res = OutPacket::new_with_dir(Direction::C2S, Flags::empty(), PacketType::Init);
1033 res.mac().copy_from_slice(b"TS3INIT1");
1034 res.packet_id(0x65);
1035 let content = res.data_mut();
1036 content.write_be(version).unwrap();
1037 content.write_be(0u8).unwrap();
1038 content.write_be(timestamp).unwrap();
1039 content.write_all(&random0).unwrap();
1040 content.write_all(&[0u8; 8]).unwrap();
1042 res
1043 }
1044}
1045
1046impl OutC2SInit2 {
1047 pub fn new(version: u32, random1: &[u8; 16], random0_r: [u8; 4]) -> OutPacket {
1048 let mut res = OutPacket::new_with_dir(Direction::C2S, Flags::empty(), PacketType::Init);
1049 res.mac().copy_from_slice(b"TS3INIT1");
1050 res.packet_id(0x65);
1051 let content = res.data_mut();
1052 content.write_be(version).unwrap();
1053 content.write_be(2u8).unwrap();
1054 content.write_all(random1).unwrap();
1055 content.write_all(&random0_r).unwrap();
1056 res
1057 }
1058}
1059
1060impl OutC2SInit4 {
1061 pub fn new(
1062 version: u32, x: &[u8; 64], n: &[u8; 64], level: u32, random2: &[u8; 100], y: &[u8; 64],
1063 alpha: &[u8], omega: &[u8], ip: &str,
1064 ) -> OutPacket {
1065 let mut res = OutPacket::new_with_dir(Direction::C2S, Flags::empty(), PacketType::Init);
1066 res.mac().copy_from_slice(b"TS3INIT1");
1067 res.packet_id(0x65);
1068 let content = res.data_mut();
1069 content.write_be(version).unwrap();
1070 content.write_be(4u8).unwrap();
1071 content.write_all(x).unwrap();
1072 content.write_all(n).unwrap();
1073 content.write_be(level).unwrap();
1074 content.write_all(random2).unwrap();
1075 content.write_all(y).unwrap();
1076 let ip = if ip.is_empty() { String::new() } else { format!("={}", ip) };
1077 content
1078 .write_all(
1079 format!(
1080 "clientinitiv alpha={} omega={} ot=1 ip{}",
1081 base64::encode(alpha),
1082 base64::encode(omega),
1083 ip
1084 )
1085 .as_bytes(),
1086 )
1087 .unwrap();
1088 res
1089 }
1090}
1091
1092impl OutS2CInit1 {
1093 pub fn new(random1: &[u8; 16], random0_r: [u8; 4]) -> OutPacket {
1094 let mut res = OutPacket::new_with_dir(Direction::S2C, Flags::empty(), PacketType::Init);
1095 res.mac().copy_from_slice(b"TS3INIT1");
1096 res.packet_id(0x65);
1097 let content = res.data_mut();
1098 content.write_be(1u8).unwrap();
1099 content.write_all(random1).unwrap();
1100 content.write_all(&random0_r).unwrap();
1101 res
1102 }
1103}
1104
1105impl OutS2CInit3 {
1106 pub fn new(x: &[u8; 64], n: &[u8; 64], level: u32, random2: &[u8; 100]) -> OutPacket {
1107 let mut res = OutPacket::new_with_dir(Direction::S2C, Flags::empty(), PacketType::Init);
1108 res.mac().copy_from_slice(b"TS3INIT1");
1109 res.packet_id(0x65);
1110 let content = res.data_mut();
1111 content.write_be(3u8).unwrap();
1112 content.write_all(x).unwrap();
1113 content.write_all(n).unwrap();
1114 content.write_be(level).unwrap();
1115 content.write_all(random2).unwrap();
1116 res
1117 }
1118}
1119
1120impl OutAck {
1121 pub fn new(dir: Direction, for_type: PacketType, packet_id: u16) -> OutPacket {
1123 let p_type = if for_type == PacketType::Command {
1124 PacketType::Ack
1125 } else if for_type == PacketType::CommandLow {
1126 PacketType::AckLow
1127 } else if for_type == PacketType::Ping {
1128 PacketType::Pong
1129 } else {
1130 panic!("Invalid packet type to create ack {:?}", for_type);
1131 };
1132
1133 let mut res = OutPacket::new_with_dir(dir, Flags::empty(), p_type);
1134 let content = res.data_mut();
1135 content.write_be(packet_id).unwrap();
1136 res
1137 }
1138}
1139
1140impl OutAudio {
1141 pub fn new(data: &AudioData) -> OutPacket {
1142 let mut res = OutPacket::new_with_dir(data.direction(), data.flags(), data.packet_type());
1143 let content = res.data_mut();
1144
1145 content.write_be(data.id()).unwrap();
1146 match data {
1147 AudioData::C2S { codec, data, .. } => {
1148 content.write_be(codec.to_u8().unwrap()).unwrap();
1149 content.extend_from_slice(data);
1150 }
1151 AudioData::C2SWhisper { codec, channels, clients, data, .. } => {
1152 content.write_be(codec.to_u8().unwrap()).unwrap();
1153 content.write_be(channels.len() as u8).unwrap();
1154 content.write_be(clients.len() as u8).unwrap();
1155
1156 for c in channels {
1157 content.write_be(*c).unwrap();
1158 }
1159 for c in clients {
1160 content.write_be(*c).unwrap();
1161 }
1162 content.extend_from_slice(data);
1163 }
1164 AudioData::C2SWhisperNew { codec, whisper_type, target, target_id, data, .. } => {
1165 content.write_be(codec.to_u8().unwrap()).unwrap();
1166 content.write_be(whisper_type.to_u8().unwrap()).unwrap();
1167 content.write_be(*target).unwrap();
1168 content.write_be(*target_id).unwrap();
1169 content.extend_from_slice(data);
1170 }
1171 AudioData::S2C { from, codec, data, .. }
1172 | AudioData::S2CWhisper { from, codec, data, .. } => {
1173 content.write_be(*from).unwrap();
1174 content.write_be(codec.to_u8().unwrap()).unwrap();
1175 content.extend_from_slice(data);
1176 }
1177 }
1178
1179 res
1180 }
1181}
1182
1183#[cfg(test)]
1184mod tests {
1185 use super::*;
1186
1187 fn test_audio_roundtrip(dir: Direction, data: &AudioData) {
1188 let out_p = OutAudio::new(data);
1189 let in_p = InPacket::try_new(dir, out_p.data()).unwrap();
1190 let audio = in_p.into_audio().unwrap();
1191 assert_eq!(audio.data(), data);
1192 }
1193
1194 #[test]
1195 fn test_audio_c2s() {
1196 let data = AudioData::C2S { codec: CodecType::OpusVoice, id: 0x1234, data: &[1, 2, 3] };
1197 test_audio_roundtrip(Direction::C2S, &data);
1198 }
1199
1200 #[test]
1201 fn test_audio_c2s_whisper() {
1202 let data = AudioData::C2SWhisper {
1203 codec: CodecType::OpusVoice,
1204 channels: vec![4, 5, 6],
1205 clients: vec![7, 8],
1206 id: 0x1234,
1207 data: &[1, 2, 3],
1208 };
1209 test_audio_roundtrip(Direction::C2S, &data);
1210 }
1211
1212 #[test]
1213 fn test_audio_c2s_whisper_new() {
1214 let data = AudioData::C2SWhisperNew {
1215 codec: CodecType::OpusVoice,
1216 whisper_type: 3,
1217 target: 4,
1218 target_id: 5,
1219 id: 0x1234,
1220 data: &[1, 2, 3],
1221 };
1222 test_audio_roundtrip(Direction::C2S, &data);
1223 }
1224
1225 #[test]
1226 fn test_audio_s2c() {
1227 let data = AudioData::S2C {
1228 codec: CodecType::OpusVoice,
1229 id: 0x1234,
1230 from: 0x5678,
1231 data: &[1, 2, 3],
1232 };
1233 test_audio_roundtrip(Direction::S2C, &data);
1234 }
1235
1236 #[test]
1237 fn test_audio_s2c_whisper() {
1238 let data = AudioData::S2CWhisper {
1239 codec: CodecType::OpusVoice,
1240 id: 0x1234,
1241 from: 0x5678,
1242 data: &[1, 2, 3],
1243 };
1244 test_audio_roundtrip(Direction::S2C, &data);
1245 }
1246}