1use arrayvec::ArrayVec;
2use libtw2_buffer as buffer;
3use libtw2_buffer::with_buffer;
4use libtw2_buffer::Buffer;
5use libtw2_buffer::BufferRef;
6use libtw2_common::boilerplate_packed;
7use libtw2_common::bytes::FromBytesExt as _;
8use libtw2_common::num::Cast;
9use libtw2_common::pretty;
10use libtw2_common::unwrap_or_return;
11use libtw2_huffman::instances::TEEWORLDS as HUFFMAN;
12use libtw2_warn::Ignore;
13use libtw2_warn::Warn;
14use std::cmp;
15use std::fmt;
16use std::io::Write as _;
17use std::str;
18use zerocopy::AsBytes as _;
19use zerocopy_derive::AsBytes;
20use zerocopy_derive::FromBytes;
21use zerocopy_derive::FromZeroes;
22
23pub const CHUNK_HEADER_SIZE: usize = 2;
24pub const CHUNK_HEADER_SIZE_VITAL: usize = 3;
25pub const HEADER_SIZE: usize = 3;
26pub const MAX_PACKETSIZE: usize = 1400;
27pub const PADDING_SIZE_CONNLESS: usize = 3;
28pub const TOKEN_SIZE: usize = 4;
29
30pub const MAX_PAYLOAD: usize = 1390;
35
36pub const PACKETFLAG_CONTROL: u8 = 1 << 0;
37pub const PACKETFLAG_CONNLESS: u8 = 1 << 1;
38pub const PACKETFLAG_REQUEST_RESEND: u8 = 1 << 2;
39pub const PACKETFLAG_COMPRESSION: u8 = 1 << 3;
40
41pub const CHUNKFLAG_RESEND: u8 = 1 << 1;
42pub const CHUNKFLAG_VITAL: u8 = 1 << 0;
43
44pub const CTRLMSG_KEEPALIVE: u8 = 0;
45pub const CTRLMSG_CONNECT: u8 = 1;
46pub const CTRLMSG_CONNECTACCEPT: u8 = 2;
47pub const CTRLMSG_ACCEPT: u8 = 3;
48pub const CTRLMSG_CLOSE: u8 = 4;
49
50pub const TOKEN_NONE: Token = Token([0xff, 0xff, 0xff, 0xff]);
51pub const TOKEN_RESERVED: Token = Token([0x00, 0x00, 0x00, 0x00]);
52
53pub const CTRLMSG_CLOSE_REASON_LENGTH: usize = 127;
54pub const CTRLMSG_TOKEN_MAGIC: &[u8; 4] = b"TKEN";
55pub const CHUNK_FLAGS_BITS: u32 = 2;
56pub const CHUNK_SIZE_BITS: u32 = 10;
57pub const PACKET_FLAGS_BITS: u32 = 4;
58pub const SEQUENCE_BITS: u32 = 10;
59pub const SEQUENCE_MODULUS: u16 = 1 << SEQUENCE_BITS;
60
61pub fn chunk_header_size(vital: bool) -> usize {
62 if vital {
63 CHUNK_HEADER_SIZE_VITAL
64 } else {
65 CHUNK_HEADER_SIZE
66 }
67}
68
69#[derive(Debug)]
70pub enum Error {
71 Capacity(buffer::CapacityError),
72 TooLongData,
73}
74
75impl From<buffer::CapacityError> for Error {
76 fn from(e: buffer::CapacityError) -> Error {
77 Error::Capacity(e)
78 }
79}
80
81#[derive(Debug, Eq, PartialEq)]
82pub enum Warning {
83 ChunkHeaderPadding,
84 ChunkHeaderSequence,
85 ChunksNoChunks,
86 ChunksNumChunks,
87 ChunksUnknownData,
88 ConnlessPadding,
89 ControlConnectMissingTokenMagic,
90 ControlExcessData,
91 ControlFlags,
92 ControlNulTermination,
93 ControlNumChunks,
94 PacketHeaderPadding,
95}
96
97#[derive(Debug, Eq, PartialEq)]
98pub enum PacketReadError {
99 Compression,
100 ControlMissing,
101 ShortConnless,
102 TokenMissing,
103 TooLong,
104 TooShort,
105 UnknownControl,
106}
107
108#[derive(Clone, Copy)]
109pub enum ControlPacket<'a> {
110 KeepAlive,
111 Connect,
112 ConnectAccept,
113 Accept,
114 Close(&'a [u8]),
115}
116
117impl<'a> fmt::Debug for ControlPacket<'a> {
118 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119 match *self {
120 ControlPacket::KeepAlive => f.debug_tuple("KeepAlive").finish(),
121 ControlPacket::Connect => f.debug_tuple("Connect").finish(),
122 ControlPacket::ConnectAccept => f.debug_tuple("ConnectAccept").finish(),
123 ControlPacket::Accept => f.debug_tuple("Accept").finish(),
124 ControlPacket::Close(reason) => f
125 .debug_tuple("Close")
126 .field(&pretty::AlmostString::new(reason))
127 .finish(),
128 }
129 }
130}
131
132#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
133pub struct Token(pub [u8; TOKEN_SIZE]);
134
135impl fmt::Debug for Token {
136 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137 write!(f, "{:08x}", u32::from_be_bytes(self.0))
138 }
139}
140
141impl fmt::Display for Token {
142 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143 fmt::Debug::fmt(self, f)
144 }
145}
146
147impl Token {
148 pub fn random<F: FnMut(&mut [u8])>(mut f: F) -> Token {
149 loop {
150 let mut token = TOKEN_NONE;
151 f(&mut token.0);
152 if token != TOKEN_NONE && token != TOKEN_RESERVED {
153 return token;
154 }
155 }
156 }
157}
158
159#[derive(Clone, Copy, Debug)]
160pub struct ConnectedPacket<'a> {
161 pub ack: u16, pub token: Option<Token>,
163 pub type_: ConnectedPacketType<'a>,
164}
165
166#[derive(Clone, Copy, Debug)]
167pub enum ConnectedPacketType<'a> {
168 Chunks(bool, u8, &'a [u8]),
170 Control(ControlPacket<'a>),
171}
172
173#[derive(Clone, Copy, Debug)]
174pub enum Packet<'a> {
175 Connless(&'a [u8]),
176 Connected(ConnectedPacket<'a>),
177}
178
179#[derive(Clone, Copy, Debug)]
180pub struct Chunk<'a> {
181 pub data: &'a [u8],
182 pub vital: Option<(u16, bool)>,
184}
185
186#[derive(Clone, Debug)]
187pub struct ChunksIter<'a> {
188 data: &'a [u8],
189 initial_len: usize,
190 num_remaining_chunks: i32,
191 checked_num_chunks_warning: bool,
192}
193
194impl<'a> ChunksIter<'a> {
195 pub fn new(data: &'a [u8], num_chunks: u8) -> ChunksIter<'a> {
196 ChunksIter {
197 data: data,
198 initial_len: data.len(),
199 num_remaining_chunks: num_chunks.i32(),
200 checked_num_chunks_warning: false,
201 }
202 }
203 fn excess_data<W: Warn<Warning>>(&mut self, warn: &mut W) -> Option<Chunk<'static>> {
204 warn.warn(Warning::ChunksUnknownData);
205 self.data = &[];
206 None
207 }
208 pub fn pos(&self) -> usize {
209 self.initial_len - self.data.len()
210 }
211 pub fn next_warn<W>(&mut self, warn: &mut W) -> Option<Chunk<'a>>
212 where
213 W: Warn<Warning>,
214 {
215 if self.data.len() == 0 {
216 if !self.checked_num_chunks_warning {
217 self.checked_num_chunks_warning = true;
218 if self.num_remaining_chunks != 0 {
219 warn.warn(Warning::ChunksNumChunks);
220 }
221 }
222 return None;
223 }
224 let (header, sequence, chunk_data_and_rest) =
225 unwrap_or_return!(read_chunk_header(warn, self.data), self.excess_data(warn));
226 let vital = sequence.map(|s| (s, header.flags & CHUNKFLAG_RESEND != 0));
227 let size = header.size.usize();
228 if chunk_data_and_rest.len() < size {
229 return self.excess_data(warn);
230 }
231 let (chunk_data, rest) = chunk_data_and_rest.split_at(size);
232 self.data = rest;
233 self.num_remaining_chunks -= 1;
234 Some(Chunk {
235 data: chunk_data,
236 vital: vital,
237 })
238 }
239}
240
241impl<'a> Iterator for ChunksIter<'a> {
242 type Item = Chunk<'a>;
243 fn next(&mut self) -> Option<Chunk<'a>> {
244 self.next_warn(&mut Ignore)
245 }
246 fn size_hint(&self) -> (usize, Option<usize>) {
247 let len = self.clone().count();
248 (len, Some(len))
249 }
250}
251
252impl<'a> ExactSizeIterator for ChunksIter<'a> {}
253
254pub fn write_chunk<'a, B: Buffer<'a>>(
257 bytes: &[u8],
258 vital: Option<(u16, bool)>,
259 buffer: B,
260) -> Result<&'a [u8], buffer::CapacityError> {
261 with_buffer(buffer, |b| write_chunk_impl(bytes, vital, b))
262}
263
264pub fn write_chunk_impl<'d, 's>(
265 bytes: &[u8],
266 vital: Option<(u16, bool)>,
267 mut buffer: BufferRef<'d, 's>,
268) -> Result<&'d [u8], buffer::CapacityError> {
269 assert!(bytes.len() >> CHUNK_SIZE_BITS == 0);
270 let size = bytes.len().assert_u16();
271
272 let (sequence, resend) = vital.unwrap_or((0, false));
273 let resend_flag = if resend { CHUNKFLAG_RESEND } else { 0 };
274 let vital_flag = if vital.is_some() { CHUNKFLAG_VITAL } else { 0 };
275 let flags = vital_flag | resend_flag;
276
277 let header_nonvital = ChunkHeader {
278 flags: flags,
279 size: size,
280 };
281
282 let header1;
283 let header2;
284 let header: &[u8] = if vital.is_some() {
285 header1 = ChunkHeaderVital {
286 h: header_nonvital,
287 sequence: sequence,
288 }
289 .pack();
290 header1.as_bytes()
291 } else {
292 header2 = header_nonvital.pack();
293 header2.as_bytes()
294 };
295 buffer.write(header)?;
296 buffer.write(bytes)?;
297 Ok(buffer.initialized())
298}
299
300fn write_connless_packet<'a, B: Buffer<'a>>(payload: &[u8], buffer: B) -> Result<&'a [u8], Error> {
301 fn inner<'d, 's>(payload: &[u8], mut buffer: BufferRef<'d, 's>) -> Result<&'d [u8], Error> {
302 if payload.len() > MAX_PAYLOAD {
303 return Err(Error::TooLongData);
304 }
305 buffer.write(&[b'\xff'; HEADER_SIZE + PADDING_SIZE_CONNLESS])?;
306 buffer.write(payload)?;
307 Ok(buffer.initialized())
308 }
309
310 with_buffer(buffer, |b| inner(payload, b))
311}
312
313fn has_token_heuristic(control: bool, num_chunks: u8, payload: &[u8]) -> bool {
314 let payload_end_heuristic = if control {
315 let (&control, payload) = unwrap_or_return!(payload.split_first(), false);
316 match control {
317 CTRLMSG_CONNECT | CTRLMSG_CONNECTACCEPT => {
318 if payload.len() < 4 || &payload[0..4] != CTRLMSG_TOKEN_MAGIC {
319 return false;
320 }
321 1 + 4
322 }
323 CTRLMSG_CLOSE => {
324 let nul = payload
325 .iter()
326 .position(|&b| b == 0)
327 .unwrap_or(payload.len());
328 if payload.len() == 4 && (nul != 3 || str::from_utf8(&payload[0..3]).is_err()) {
348 return true;
349 }
350 1 + nul + 1
351 }
352 _ => 1,
353 }
354 } else {
355 let mut chunks_iter = ChunksIter::new(payload, num_chunks);
356 for _ in 0..num_chunks {
357 if chunks_iter.next_warn(&mut Ignore).is_none() {
358 return false;
359 }
360 }
361 chunks_iter.pos()
362 };
363 payload_end_heuristic + TOKEN_SIZE <= payload.len()
364}
365
366impl<'a> Packet<'a> {
367 pub fn is_initial(packet: &[u8]) -> bool {
368 if packet.len() > MAX_PACKETSIZE {
369 return false;
370 }
371 let (header, payload) =
372 unwrap_or_return!(PacketHeaderPacked::ref_and_rest_from(packet), false);
373 let header = header.unpack_warn(&mut Ignore);
374 if header.flags & PACKETFLAG_CONNLESS != 0 {
375 return true;
376 }
377 let ctrl = payload.first().copied();
378 header.flags & !PACKETFLAG_REQUEST_RESEND == PACKETFLAG_CONTROL
379 && (ctrl == Some(CTRLMSG_CONNECT) || ctrl == Some(CTRLMSG_ACCEPT))
380 }
381 fn needs_decompression(packet: &[u8]) -> bool {
382 if packet.len() > MAX_PACKETSIZE {
383 return false;
384 }
385 let (header, _) = unwrap_or_return!(PacketHeaderPacked::ref_and_rest_from(packet), false);
386 let header = header.unpack_warn(&mut Ignore);
387 header.flags & PACKETFLAG_CONNLESS == 0 && header.flags & PACKETFLAG_COMPRESSION != 0
388 }
389 pub fn read<'b, B, W>(
398 warn: &mut W,
399 bytes: &'b [u8],
400 token_hint: Option<bool>,
401 buffer: B,
402 ) -> Result<Packet<'b>, PacketReadError>
403 where
404 B: Buffer<'b>,
405 W: Warn<Warning>,
406 {
407 with_buffer(buffer, |b| {
408 Packet::read_impl(warn, bytes, token_hint, Some(b))
409 })
410 }
411 pub fn read_panic_on_decompression<'b, W>(
412 warn: &mut W,
413 bytes: &'b [u8],
414 token_hint: Option<bool>,
415 ) -> Result<Packet<'b>, PacketReadError>
416 where
417 W: Warn<Warning>,
418 {
419 Packet::read_impl(warn, bytes, token_hint, None)
420 }
421 fn read_impl<'d, 's, W>(
422 warn: &mut W,
423 bytes: &'d [u8],
424 token_hint: Option<bool>,
425 buffer: Option<BufferRef<'d, 's>>,
426 ) -> Result<Packet<'d>, PacketReadError>
427 where
428 W: Warn<Warning>,
429 {
430 use self::PacketReadError::*;
431
432 assert!(buffer
433 .as_ref()
434 .map(|b| b.remaining() >= MAX_PACKETSIZE)
435 .unwrap_or(true));
436 if bytes.len() > MAX_PACKETSIZE {
437 return Err(TooLong);
438 }
439 let (header, payload) =
440 unwrap_or_return!(PacketHeaderPacked::ref_and_rest_from(bytes), Err(TooShort));
441 let header = header.unpack_warn(warn);
442 if header.flags & PACKETFLAG_CONNLESS != 0 {
443 if payload.len() < PADDING_SIZE_CONNLESS {
444 return Err(ShortConnless);
445 }
446 let (padding, payload) = payload.split_at(PADDING_SIZE_CONNLESS);
447 if !padding.iter().all(|&b| b == 0xff) || !bytes[..3].iter().all(|&b| b == 0xff) {
448 warn.warn(Warning::ConnlessPadding);
449 }
450 return Ok(Packet::Connless(payload));
451 }
452
453 let payload = if header.flags & PACKETFLAG_COMPRESSION != 0 {
454 let mut buffer =
455 buffer.expect("read_panic_on_decompression called on compressed packet");
456 let decompressed = Packet::decompress(bytes, &mut buffer).map_err(|_| Compression)?;
457 let (_, payload) = PacketHeaderPacked::ref_and_rest_from(decompressed).unwrap();
458 payload
459 } else {
460 payload
461 };
462
463 if payload.len() > MAX_PACKETSIZE - HEADER_SIZE {
464 return Err(Compression);
465 }
466
467 let ack = header.ack;
468
469 let has_token = token_hint.unwrap_or_else(|| {
470 let control = header.flags & PACKETFLAG_CONTROL != 0;
471 has_token_heuristic(control, header.num_chunks, payload)
472 });
473
474 let (payload, token) = if has_token {
475 if payload.len() < TOKEN_SIZE {
476 return Err(TokenMissing);
477 }
478 let (payload, t_bytes) = payload.split_at(payload.len() - TOKEN_SIZE);
479 let token = Token([t_bytes[0], t_bytes[1], t_bytes[2], t_bytes[3]]);
480 (payload, Some(token))
481 } else {
482 (payload, None)
483 };
484
485 let type_ = if header.flags & PACKETFLAG_CONTROL != 0 {
486 if header.num_chunks != 0 {
487 warn.warn(Warning::ControlNumChunks);
488 }
489 if header.flags & PACKETFLAG_COMPRESSION != 0
490 || header.flags & PACKETFLAG_REQUEST_RESEND != 0
491 {
492 warn.warn(Warning::ControlFlags);
494 }
495
496 let (&control, payload) = unwrap_or_return!(payload.split_first(), Err(ControlMissing));
497 match control {
499 CTRLMSG_CONNECT | CTRLMSG_CONNECTACCEPT => {
500 if token.is_some() {
501 if !payload.starts_with(CTRLMSG_TOKEN_MAGIC) {
502 warn.warn(Warning::ControlConnectMissingTokenMagic);
503 if !payload.is_empty() {
504 warn.warn(Warning::ControlExcessData);
505 }
506 } else {
507 if payload.len() > CTRLMSG_TOKEN_MAGIC.len() {
508 warn.warn(Warning::ControlExcessData);
509 }
510 }
511 } else {
512 if !payload.is_empty() {
513 warn.warn(Warning::ControlExcessData);
514 }
515 }
516 }
517 CTRLMSG_CLOSE => {} _ => {
519 if payload.len() != 0 {
520 warn.warn(Warning::ControlExcessData);
521 }
522 }
523 }
524 let control = match control {
525 CTRLMSG_KEEPALIVE => ControlPacket::KeepAlive,
526 CTRLMSG_CONNECT => ControlPacket::Connect,
527 CTRLMSG_CONNECTACCEPT => ControlPacket::ConnectAccept,
528 CTRLMSG_ACCEPT => ControlPacket::Accept,
529 CTRLMSG_CLOSE => {
530 let nul = payload
531 .iter()
532 .position(|&b| b == 0)
533 .unwrap_or(payload.len());
534 let nul = cmp::min(nul, CTRLMSG_CLOSE_REASON_LENGTH);
535 if payload.len() != 0 && nul + 1 != payload.len() {
536 if nul + 1 < payload.len() {
537 warn.warn(Warning::ControlExcessData);
538 } else {
539 warn.warn(Warning::ControlNulTermination);
540 }
541 }
542 ControlPacket::Close(&payload[..nul])
543 }
544 _ => {
545 return Err(UnknownControl);
547 }
548 };
549
550 ConnectedPacketType::Control(control)
551 } else {
552 let request_resend = header.flags & PACKETFLAG_REQUEST_RESEND != 0;
553 if header.num_chunks == 0 && !request_resend {
554 warn.warn(Warning::ChunksNoChunks);
555 }
556 ConnectedPacketType::Chunks(request_resend, header.num_chunks, payload)
557 };
558
559 Ok(Packet::Connected(ConnectedPacket {
560 token: token,
561 ack: ack,
562 type_: type_,
563 }))
564 }
565 pub fn decompress_if_needed<B: Buffer<'a>>(
567 packet: &[u8],
568 buffer: B,
569 ) -> Result<bool, libtw2_huffman::DecompressionError> {
570 with_buffer(buffer, |b| Packet::decompress_if_needed_impl(packet, b))
571 }
572 fn decompress_if_needed_impl<'d, 's>(
573 packet: &[u8],
574 mut buffer: BufferRef<'d, 's>,
575 ) -> Result<bool, libtw2_huffman::DecompressionError> {
576 assert!(buffer.remaining() >= MAX_PACKETSIZE);
577 if !Packet::needs_decompression(packet) {
578 return Ok(false);
579 }
580 Packet::decompress(packet, &mut buffer)?;
581 Ok(true)
582 }
583
584 fn decompress<B: Buffer<'a>>(
585 packet: &[u8],
586 buffer: B,
587 ) -> Result<&'a [u8], libtw2_huffman::DecompressionError> {
588 with_buffer(buffer, |b| Packet::decompress_impl(packet, b))
589 }
590 fn decompress_impl<'d, 's>(
591 packet: &[u8],
592 mut buffer: BufferRef<'d, 's>,
593 ) -> Result<&'d [u8], libtw2_huffman::DecompressionError> {
594 assert!(buffer.remaining() >= MAX_PACKETSIZE);
595 assert!(Packet::needs_decompression(packet));
596 let (header, payload) = PacketHeaderPacked::ref_and_rest_from(packet)
597 .expect("packet passed to decompress too short for header");
598 let header = header.unpack_warn(&mut Ignore);
599 assert!(header.flags & PACKETFLAG_CONNLESS == 0);
600 assert!(header.flags & PACKETFLAG_COMPRESSION != 0);
601
602 let fake_header = PacketHeader {
603 flags: header.flags & !PACKETFLAG_COMPRESSION,
604 ack: header.ack,
605 num_chunks: header.num_chunks,
606 };
607 buffer.write(fake_header.pack().as_bytes()).unwrap();
608 HUFFMAN.decompress(payload, &mut buffer)?;
609
610 Ok(buffer.initialized())
611 }
612
613 pub fn write<'b, B: Buffer<'b>>(&self, buffer: B) -> Result<&'b [u8], Error> {
614 match *self {
615 Packet::Connected(ref p) => with_buffer(buffer, |b| p.write_impl(b)),
616 Packet::Connless(ref d) => write_connless_packet(d, buffer),
617 }
618 }
619}
620
621impl<'a> ConnectedPacket<'a> {
622 pub fn write<'b, B: Buffer<'b>>(&self, buffer: B) -> Result<&'b [u8], Error> {
623 with_buffer(buffer, |b| self.write_impl(b))
624 }
625
626 fn write_impl<'d, 's>(&self, mut buffer: BufferRef<'d, 's>) -> Result<&'d [u8], Error> {
627 match self.type_ {
628 ConnectedPacketType::Chunks(request_resend, num_chunks, payload) => {
629 let mut token_buffer: ArrayVec<[u8; 2048]> = ArrayVec::new();
630 let payload: &[u8] = if let Some(token) = self.token {
631 token_buffer.write(payload).unwrap();
632 token_buffer.write(&token.0).unwrap();
633 &token_buffer
634 } else {
635 payload
636 };
637 let mut compression_buffer: ArrayVec<[u8; 2048]> = ArrayVec::new();
638 let mut compression = 0;
639 let comp_result = HUFFMAN.compress(payload, &mut compression_buffer);
640 if comp_result
641 .map(|s| s.len() < payload.len())
642 .unwrap_or(false)
643 {
644 compression = PACKETFLAG_COMPRESSION;
645 }
646 let request_resend = if request_resend {
647 PACKETFLAG_REQUEST_RESEND
648 } else {
649 0
650 };
651 buffer.write(
652 PacketHeader {
653 flags: request_resend | compression,
654 ack: self.ack,
655 num_chunks: num_chunks,
656 }
657 .pack()
658 .as_bytes(),
659 )?;
660 buffer.write(if compression != 0 {
661 &compression_buffer
662 } else {
663 payload
664 })?;
665 Ok(buffer.initialized())
666 }
667 ConnectedPacketType::Control(c) => c.write(self.token, self.ack, buffer),
668 }
669 }
670}
671
672impl<'a> ControlPacket<'a> {
673 fn write<'d, 's>(
674 &self,
675 token: Option<Token>,
676 ack: u16,
677 mut buffer: BufferRef<'d, 's>,
678 ) -> Result<&'d [u8], Error> {
679 buffer.write(
680 PacketHeader {
681 flags: PACKETFLAG_CONTROL,
682 ack: ack,
683 num_chunks: 0,
684 }
685 .pack()
686 .as_bytes(),
687 )?;
688 let magic = match *self {
689 ControlPacket::KeepAlive => CTRLMSG_KEEPALIVE,
690 ControlPacket::Connect => CTRLMSG_CONNECT,
691 ControlPacket::ConnectAccept => CTRLMSG_CONNECTACCEPT,
692 ControlPacket::Accept => CTRLMSG_ACCEPT,
693 ControlPacket::Close(..) => CTRLMSG_CLOSE,
694 };
695 buffer.write(&[magic])?;
696 if matches!(*self, ControlPacket::Connect | ControlPacket::ConnectAccept) && token.is_some()
697 {
698 buffer.write(CTRLMSG_TOKEN_MAGIC)?;
699 }
700 match *self {
701 ControlPacket::Close(m) => {
702 assert!(m.iter().all(|&b| b != 0));
703 buffer.write(m)?;
704 buffer.write(&[0])?;
705 }
706 _ => {}
707 }
708 if let Some(token) = token {
709 buffer.write(&token.0)?;
710 }
711 let result = buffer.initialized();
712 assert!(result.len() <= MAX_PACKETSIZE);
713 Ok(result)
714 }
715}
716
717#[repr(C, packed)]
718#[derive(AsBytes, Clone, Copy, FromBytes, FromZeroes)]
719pub struct PacketHeaderPacked {
720 flags_padding_ack: u8, ack: u8,
722 num_chunks: u8,
723}
724
725#[derive(Copy, Clone, Debug, Eq, PartialEq)]
726pub struct PacketHeader {
727 pub flags: u8, pub ack: u16, pub num_chunks: u8,
730}
731
732impl PacketHeaderPacked {
733 pub fn unpack_warn<W: Warn<Warning>>(self, warn: &mut W) -> PacketHeader {
734 let PacketHeaderPacked {
735 flags_padding_ack,
736 ack,
737 num_chunks,
738 } = self;
739 if flags_padding_ack & 0b0010_0000 == 0 && flags_padding_ack & 0b0000_1100 != 0 {
741 warn.warn(Warning::PacketHeaderPadding);
742 }
743 PacketHeader {
744 flags: (flags_padding_ack & 0b1111_0000) >> 4,
745 ack: (((flags_padding_ack & 0b0000_0011) as u16) << 8) | (ack as u16),
746 num_chunks: num_chunks,
747 }
748 }
749 pub fn unpack(self) -> PacketHeader {
750 self.unpack_warn(&mut Ignore)
751 }
752}
753
754impl PacketHeader {
755 pub fn pack(self) -> PacketHeaderPacked {
756 let PacketHeader {
757 flags,
758 ack,
759 num_chunks,
760 } = self;
761 assert!(flags >> PACKET_FLAGS_BITS == 0);
763 assert!(ack >> SEQUENCE_BITS == 0);
764 PacketHeaderPacked {
765 flags_padding_ack: flags << 4 | (ack >> 8) as u8,
766 ack: ack as u8,
767 num_chunks: num_chunks,
768 }
769 }
770}
771
772#[derive(Copy, Clone, Debug, Eq, PartialEq)]
773pub struct ChunkHeader {
774 pub flags: u8, pub size: u16, }
777
778#[derive(Copy, Clone, Debug, Eq, PartialEq)]
779pub struct ChunkHeaderVital {
780 pub h: ChunkHeader,
781 pub sequence: u16, }
783
784#[repr(C, packed)]
785#[derive(AsBytes, Clone, Copy, FromBytes, FromZeroes)]
786pub struct ChunkHeaderPacked {
787 flags_size: u8, padding_size: u8, }
790
791#[repr(C, packed)]
792#[derive(AsBytes, Clone, Copy, FromBytes, FromZeroes)]
793pub struct ChunkHeaderVitalPacked {
794 flags_size: u8, sequence_size: u8, sequence: u8,
797}
798
799pub fn read_chunk_header<'a, W>(
801 warn: &mut W,
802 data: &'a [u8],
803) -> Option<(ChunkHeader, Option<u16>, &'a [u8])>
804where
805 W: Warn<Warning>,
806{
807 let (raw_header, chunk_data_and_rest) =
808 unwrap_or_return!(ChunkHeaderPacked::ref_and_rest_from(data));
809
810 let header = raw_header.unpack_warn(&mut Ignore);
811 Some(if header.flags & CHUNKFLAG_VITAL != 0 {
812 let (header, chunk_data_and_rest_vital) =
813 unwrap_or_return!(ChunkHeaderVitalPacked::ref_and_rest_from(data));
814 let header = header.unpack_warn(warn);
815 (header.h, Some(header.sequence), chunk_data_and_rest_vital)
816 } else {
817 raw_header.unpack_warn(warn);
818 (header, None, chunk_data_and_rest)
819 })
820}
821
822impl ChunkHeaderPacked {
823 pub fn unpack_warn<W: Warn<Warning>>(self, warn: &mut W) -> ChunkHeader {
824 let ChunkHeaderPacked {
825 flags_size,
826 padding_size,
827 } = self;
828 if padding_size & 0b1111_0000 != 0 {
829 warn.warn(Warning::ChunkHeaderPadding);
830 }
831 ChunkHeader {
832 flags: (flags_size & 0b1100_0000) >> 6,
833 size: ((((flags_size & 0b0011_1111) as u16) << 4)
834 | (padding_size & 0b0000_1111) as u16),
835 }
836 }
837 pub fn unpack(self) -> ChunkHeader {
838 self.unpack_warn(&mut Ignore)
839 }
840}
841
842impl ChunkHeader {
843 pub fn pack(self) -> ChunkHeaderPacked {
844 let ChunkHeader { flags, size } = self;
845 assert!(flags >> CHUNK_FLAGS_BITS == 0);
847 assert!(size >> CHUNK_SIZE_BITS == 0);
848 ChunkHeaderPacked {
849 flags_size: (flags & 0b11) << 6 | ((size & 0b11_1111_0000) >> 4) as u8,
850 padding_size: (size & 0b00_0000_1111) as u8,
851 }
852 }
853}
854
855impl ChunkHeaderVitalPacked {
856 pub fn unpack_warn<W: Warn<Warning>>(self, warn: &mut W) -> ChunkHeaderVital {
857 let ChunkHeaderVitalPacked {
858 flags_size,
859 sequence_size,
860 sequence,
861 } = self;
862 if (sequence_size & 0b0011_0000) >> 4 != (sequence & 0b1100_0000) >> 6 {
863 warn.warn(Warning::ChunkHeaderSequence);
864 }
865 ChunkHeaderVital {
866 h: ChunkHeaderPacked {
867 flags_size: flags_size,
868 padding_size: sequence_size & 0b0000_1111,
869 }
870 .unpack_warn(warn),
871 sequence: ((sequence_size & 0b1111_0000) as u16) << 2
872 | ((sequence & 0b1111_1111) as u16),
873 }
874 }
875 pub fn unpack(self) -> ChunkHeaderVital {
876 self.unpack_warn(&mut Ignore)
877 }
878}
879
880impl ChunkHeaderVital {
881 pub fn pack(self) -> ChunkHeaderVitalPacked {
882 let ChunkHeaderVital { h, sequence } = self;
883 assert!(sequence >> SEQUENCE_BITS == 0);
884 let ChunkHeaderPacked {
885 flags_size,
886 padding_size,
887 } = h.pack();
888 ChunkHeaderVitalPacked {
889 flags_size: flags_size,
890 sequence_size: (padding_size & 0b0000_1111) | ((sequence & 0b11_1100_0000) >> 2) as u8,
891 sequence: (sequence & 0b00_1111_1111) as u8,
892 }
893 }
894}
895
896boilerplate_packed!(PacketHeaderPacked, HEADER_SIZE, test_ph_size);
897boilerplate_packed!(ChunkHeaderPacked, CHUNK_HEADER_SIZE, test_ch_size);
898boilerplate_packed!(
899 ChunkHeaderVitalPacked,
900 CHUNK_HEADER_SIZE_VITAL,
901 test_chv_size
902);
903
904#[cfg(test)]
905mod test {
906 use super::ChunkHeader;
907 use super::ChunkHeaderPacked;
908 use super::ChunkHeaderVital;
909 use super::ChunkHeaderVitalPacked;
910 use super::ChunksIter;
911 use super::ConnectedPacket;
912 use super::ConnectedPacketType;
913 use super::Packet;
914 use super::PacketHeader;
915 use super::PacketHeaderPacked;
916 use super::PacketReadError;
917 use super::Warning;
918 use super::CHUNK_FLAGS_BITS;
919 use super::CHUNK_SIZE_BITS;
920 use super::MAX_PACKETSIZE;
921 use super::PACKET_FLAGS_BITS;
922 use super::SEQUENCE_BITS;
923 use libtw2_common::bytes::FromBytesExt;
924 use libtw2_warn::Ignore;
925 use libtw2_warn::Panic;
926 use libtw2_warn::Warn;
927 use quickcheck::quickcheck;
928 use zerocopy::AsBytes as _;
929
930 struct WarnVec<'a>(&'a mut Vec<Warning>);
931
932 impl<'a> Warn<Warning> for WarnVec<'a> {
933 fn warn(&mut self, warning: Warning) {
934 self.0.push(warning);
935 }
936 }
937
938 fn collect_warnings(
939 token_hint: Option<bool>,
940 input: &[u8],
941 strip_chunks_no_chunks: bool,
942 ) -> Vec<Warning> {
943 let mut result = vec![];
944 let mut buffer = Vec::with_capacity(4096);
945 let packet =
946 Packet::read(&mut WarnVec(&mut result), input, token_hint, &mut buffer).unwrap();
947 if let Packet::Connected(ConnectedPacket {
948 type_: ConnectedPacketType::Chunks(_, num_chunks, chunk_data),
949 ..
950 }) = packet
951 {
952 let mut chunks = ChunksIter::new(chunk_data, num_chunks);
953 while let Some(_) = chunks.next_warn(&mut WarnVec(&mut result)) {}
954 }
955 if strip_chunks_no_chunks {
956 result.retain(|w| *w != Warning::ChunksNoChunks);
957 }
958 result
959 }
960
961 fn assert_warnings(has_token: bool, skip_heur: bool, input: &[u8], warnings: &[Warning]) {
962 let strip = warnings != &[Warning::ChunksNoChunks];
963 assert_eq!(collect_warnings(Some(has_token), input, strip), warnings);
964 if !skip_heur {
965 assert_eq!(collect_warnings(None, input, strip), warnings);
966 }
967 }
968
969 pub fn assert_warn(has_token: bool, skip_heur: bool, input: &[u8], warning: Warning) {
970 assert_warnings(has_token, skip_heur, input, &[warning]);
971 }
972
973 pub fn assert_no_warn(has_token: bool, skip_heur: bool, input: &[u8]) {
974 assert_warnings(has_token, skip_heur, input, &[]);
975 }
976
977 pub fn assert_err(has_token: bool, skip_heur: bool, input: &[u8], error: PacketReadError) {
978 let mut buffer = Vec::with_capacity(4096);
979 assert_eq!(
980 Packet::read(&mut Panic, input, Some(has_token), &mut buffer).unwrap_err(),
981 error
982 );
983 if !skip_heur {
984 assert_eq!(
985 Packet::read(&mut Panic, input, None, &mut buffer).unwrap_err(),
986 error
987 );
988 }
989 }
990
991 quickcheck! {
992 fn packet_header_roundtrip(flags: u8, ack: u16, num_chunks: u8) -> bool {
993 let flags = flags ^ (flags >> PACKET_FLAGS_BITS << PACKET_FLAGS_BITS);
994 let ack = ack ^ (ack >> SEQUENCE_BITS << SEQUENCE_BITS);
995 let packet_header = PacketHeader {
996 flags: flags,
997 ack: ack,
998 num_chunks: num_chunks,
999 };
1000 packet_header == packet_header.pack().unpack()
1001 }
1002
1003 fn packet_header_unpack(v: (u8, u8, u8)) -> bool {
1004 let v0 = v.0 & 0b1111_0011;
1006 let bytes = &[v0, v.1, v.2];
1007 PacketHeaderPacked::ref_from_array(bytes).unpack().pack().as_bytes() == bytes
1008 }
1009
1010 fn chunk_header_roundtrip(flags: u8, size: u16, sequence: u16) -> bool {
1011 let flags = flags ^ (flags >> CHUNK_FLAGS_BITS << CHUNK_FLAGS_BITS);
1012 let size = size ^ (size >> CHUNK_SIZE_BITS << CHUNK_SIZE_BITS);
1013 let sequence = sequence ^ (sequence >> SEQUENCE_BITS << SEQUENCE_BITS);
1014 let chunk_header = ChunkHeader {
1015 flags: flags,
1016 size: size,
1017 };
1018 let chunk_header_vital = ChunkHeaderVital {
1019 h: chunk_header,
1020 sequence: sequence,
1021 };
1022 chunk_header == chunk_header.pack().unpack()
1023 && chunk_header_vital == chunk_header_vital.pack().unpack()
1024 }
1025
1026 fn chunk_header_unpack(v: (u8, u8, u8)) -> bool {
1027 let bytes2 = &[v.0, v.1];
1028 let bytes3 = &[v.0, v.1, v.2];
1029 let bytes2_result = &[v.0, v.1 & 0b0000_1111];
1030 let bytes3_result = &[v.0, v.1 | ((v.2 & 0b1100_0000) >> 2), v.2 | ((v.1 & 0b0011_0000) << 2)];
1031 ChunkHeaderPacked::ref_from_array(bytes2).unpack().pack().as_bytes() == bytes2_result
1032 && ChunkHeaderVitalPacked::ref_from_array(bytes3).unpack().pack().as_bytes() == bytes3_result
1033 }
1034
1035 fn packet_read_no_panic(data: Vec<u8>) -> bool {
1036 let mut buffer = [0; MAX_PACKETSIZE];
1037 let _ = Packet::read(&mut Ignore, &data, None, &mut buffer[..]);
1038 true
1039 }
1040 }
1041}
1042
1043#[cfg(test)]
1044#[rustfmt::skip]
1045mod test_no_token {
1046 use libtw2_warn::Ignore;
1047 use quickcheck::quickcheck;
1048 use super::MAX_PACKETSIZE;
1049 use super::Packet;
1050 use super::PacketReadError::*;
1051 use super::PacketReadError;
1052 use super::Warning::*;
1053 use super::Warning;
1054
1055 fn assert_warn(input: &[u8], warning: Warning) {
1056 super::test::assert_warn(false, false, input, warning);
1057 }
1058
1059 fn assert_no_warn(input: &[u8]) {
1060 super::test::assert_no_warn(false, false, input);
1061 }
1062
1063 fn assert_err(input: &[u8], error: PacketReadError) {
1064 super::test::assert_err(false, false, input, error);
1065 }
1066
1067 #[test] fn w_chp() { assert_warn(b"\x00\x00\x01\x00\xf0", ChunkHeaderPadding) }
1068 #[test] fn w_chs1() { assert_warn(b"\x00\x00\x01\x40\x20\x00", ChunkHeaderSequence) }
1069 #[test] fn w_chs2() { assert_warn(b"\x00\x00\x01\x40\x10\x00", ChunkHeaderSequence) }
1070 #[test] fn w_chs3() { assert_no_warn(b"\x00\x00\x01\x40\x70\xcf") }
1071 #[test] fn w_cud1() { assert_warn(b"\x00\x00\x00\xff", ChunksUnknownData) }
1072 #[test] fn w_cud2() { assert_warn(b"\x00\x00\x01\x00\x00\x00", ChunksUnknownData) }
1073 #[test] fn w_cud3() { assert_no_warn(b"\x00\x00\x01\x00\x00") }
1074 #[test] fn w_cnc1() { assert_warn(b"\x00\x00\x01", ChunksNumChunks) }
1075 #[test] fn w_cnc2() { assert_warn(b"\x00\x00\x00\x00\x00", ChunksNumChunks) }
1076 #[test] fn w_cnc_() { assert_warn(b"\x00\x00\x00", ChunksNoChunks) }
1077 #[test] fn w_cp1() { assert_warn(b"xe\x01\x02\x03\x04", ConnlessPadding) }
1078 #[test] fn w_cp2() { assert_warn(b"\xff\xff\xff\xff\xff\xfe", ConnlessPadding) }
1079 #[test] fn w_cp3() { assert_warn(b"\x7f\xff\xff\xff\xff\xff", ConnlessPadding) }
1080 #[test] fn w_cp4() { assert_no_warn(b"\xff\xff\xff\xff\xff\xff") }
1081 #[test] fn w_ced1() { assert_warn(b"\x10\x00\x00\x00\x00", ControlExcessData) }
1082 #[test] fn w_ced2() { assert_warn(b"\x10\x00\x00\x04\x00\x00", ControlExcessData) }
1083 #[test] fn w_cf1() { assert_warn(b"\x90\x00\x00\x15\x37", ControlFlags) }
1084 #[test] fn w_cf2() { assert_warn(b"\x50\x00\x00\x00", ControlFlags) }
1085 #[test] fn w_cnt1() { assert_warn(b"\x10\x00\x00\x04\x01", ControlNulTermination) }
1086 #[test] fn w_cnt2() { assert_no_warn(b"\x10\x00\x00\x04") }
1087 #[test] fn w_cnc() { assert_warn(b"\x10\x00\xff\x00", ControlNumChunks) }
1088 #[test] fn w_php1() { assert_warn(b"\x08\x00\x00", PacketHeaderPadding) }
1089 #[test] fn w_php2() { assert_warn(b"\x04\x00\x00", PacketHeaderPadding) }
1090
1091 #[test] fn e_cm() { assert_err(b"\x10\x00\x00", ControlMissing) }
1092 #[test] fn e_sc() { assert_err(b"\xff\xff\xff", ShortConnless) }
1093 #[test] fn e_tl() { assert_err(&[0; MAX_PACKETSIZE+1], TooLong) }
1094 #[test] fn e_ts1() { assert_err(b"\x00\x00", TooShort) }
1095 #[test] fn e_ts2() { assert_err(b"", TooShort) }
1096 #[test] fn e_uc1() { assert_err(b"\x10\x00\x00\x05", UnknownControl) }
1097 #[test] fn e_uc2() { assert_err(b"\x10\x00\x00\xff", UnknownControl) }
1098 #[test] fn e_c() { assert_err(b"\x80\x00\x00", Compression) }
1099
1100 quickcheck! {
1101 fn packet_read_no_panic(data: Vec<u8>) -> bool {
1102 let mut buffer = [0; MAX_PACKETSIZE];
1103 let _ = Packet::read(&mut Ignore, &data, Some(false), &mut buffer[..]);
1104 true
1105 }
1106 }
1107}
1108
1109#[cfg(test)]
1110#[rustfmt::skip]
1111mod test_token {
1112 use libtw2_warn::Ignore;
1113 use quickcheck::quickcheck;
1114 use super::MAX_PACKETSIZE;
1115 use super::Packet;
1116 use super::PacketReadError::*;
1117 use super::PacketReadError;
1118 use super::Warning::*;
1119 use super::Warning;
1120
1121 fn assert_warn(input: &[u8], warning: Warning) {
1122 super::test::assert_warn(true, false, input, warning);
1123 }
1124
1125 fn assert_warn_no_heur(input: &[u8], warning: Warning) {
1126 super::test::assert_warn(true, true, input, warning);
1127 }
1128
1129 fn assert_no_warn(input: &[u8]) {
1130 super::test::assert_no_warn(true, false, input);
1131 }
1132
1133 fn assert_no_warn_no_heur(input: &[u8]) {
1134 super::test::assert_no_warn(true, true, input);
1135 }
1136
1137 fn assert_err(input: &[u8], error: PacketReadError) {
1138 super::test::assert_err(true, false, input, error);
1139 }
1140
1141 fn assert_err_no_heur(input: &[u8], error: PacketReadError) {
1142 super::test::assert_err(true, true, input, error);
1143 }
1144
1145 #[test] fn w_chp() { assert_warn(b"\x00\x00\x01\x00\xf0\x12\x34\x56\x78", ChunkHeaderPadding) }
1146 #[test] fn w_chs1() { assert_warn(b"\x00\x00\x01\x40\x20\x00\x12\x34\x56\x78", ChunkHeaderSequence) }
1147 #[test] fn w_chs2() { assert_warn(b"\x00\x00\x01\x40\x10\x00\x12\x34\x56\x78", ChunkHeaderSequence) }
1148 #[test] fn w_chs3() { assert_no_warn(b"\x00\x00\x01\x40\x70\xcf\x12\x34\x56\x78") }
1149 #[test] fn w_cud1() { assert_warn(b"\x00\x00\x00\xff\x12\x34\x56\x78", ChunksUnknownData) }
1150 #[test] fn w_cud2() { assert_warn(b"\x00\x00\x01\x00\x00\x00\x12\x34\x56\x78", ChunksUnknownData) }
1151 #[test] fn w_cud3() { assert_no_warn(b"\x00\x00\x01\x00\x00\x12\x34\x56\x78") }
1152 #[test] fn w_cnc1() { assert_warn_no_heur(b"\x00\x00\x01\x12\x34\x56\x78", ChunksNumChunks) }
1153 #[test] fn w_cnc2() { assert_warn(b"\x00\x00\x00\x00\x00\x12\x34\x56\x78", ChunksNumChunks) }
1154 #[test] fn w_cnc_() { assert_warn(b"\x00\x00\x00\x12\x34\x56\x78", ChunksNoChunks) }
1155 #[test] fn w_cp1() { assert_warn(b"xe\x01\x02\x03\x04\x12\x34\x56\x78", ConnlessPadding) }
1156 #[test] fn w_cp2() { assert_warn(b"\xff\xff\xff\xff\xff\xfe\x12\x34\x56\x78", ConnlessPadding) }
1157 #[test] fn w_cp3() { assert_warn(b"\x7f\xff\xff\xff\xff\xff\x12\x34\x56\x78", ConnlessPadding) }
1158 #[test] fn w_cp4() { assert_no_warn(b"\xff\xff\xff\xff\xff\xff\x12\x34\x56\x78") }
1159 #[test] fn w_ced1() { assert_warn(b"\x10\x00\x00\x00\x00\x12\x34\x56\x78", ControlExcessData) }
1160 #[test] fn w_ced2() { assert_warn(b"\x10\x00\x00\x04\x00\x00\x12\x34\x56\x78", ControlExcessData) }
1161 #[test] fn w_cf1() { assert_warn(b"\x90\x00\x00\xb9\x3c\xd2\x85\x6b\x53\xdc\x00", ControlFlags) }
1162 #[test] fn w_cf2() { assert_warn(b"\x50\x00\x00\x00\x12\x34\x56\x78", ControlFlags) }
1163 #[test] fn w_cnt1() { assert_warn(b"\x10\x00\x00\x04\x01\x12\x34\x56\x78", ControlNulTermination) }
1164 #[test] fn w_cnt2() { assert_no_warn_no_heur(b"\x10\x00\x00\x04\x12\x34\x56\x78") }
1165 #[test] fn w_cnc() { assert_warn(b"\x10\x00\xff\x00\x12\x34\x56\x78", ControlNumChunks) }
1166 #[test] fn w_php1() { assert_warn(b"\x08\x00\x00\x12\x34\x56\x78", PacketHeaderPadding) }
1167 #[test] fn w_php2() { assert_warn(b"\x04\x00\x00\x12\x34\x56\x78", PacketHeaderPadding) }
1168
1169 #[test] fn e_cm() { assert_err_no_heur(b"\x10\x00\x00\x12\x34\x56\x78", ControlMissing) }
1170 #[test] fn e_sc() { assert_err(b"\xff\xff\xff", ShortConnless) }
1171 #[test] fn e_tl() { assert_err(&[0; MAX_PACKETSIZE+1], TooLong) }
1172 #[test] fn e_tm1() { assert_err_no_heur(b"\x00\x00\x00", TokenMissing) }
1173 #[test] fn e_tm2() { assert_err_no_heur(b"\x00\x00\x00\x12", TokenMissing) }
1174 #[test] fn e_tm3() { assert_err_no_heur(b"\x00\x00\x00\x12\x34\x56", TokenMissing) }
1175 #[test] fn e_ts1() { assert_err(b"\x00\x00", TooShort) }
1176 #[test] fn e_ts2() { assert_err(b"", TooShort) }
1177 #[test] fn e_uc1() { assert_err(b"\x10\x00\x00\x05\x12\x34\x56\x78", UnknownControl) }
1178 #[test] fn e_uc2() { assert_err(b"\x10\x00\x00\xff\x12\x34\x56\x78", UnknownControl) }
1179 #[test] fn e_c() { assert_err(b"\x80\x00\x00", Compression) }
1180
1181 quickcheck! {
1182 fn packet_read_no_panic(data: Vec<u8>) -> bool {
1183 let mut buffer = [0; MAX_PACKETSIZE];
1184 let _ = Packet::read(&mut Ignore, &data, Some(true), &mut buffer[..]);
1185 true
1186 }
1187 }
1188}