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