srt/packet/data.rs
1use bitflags::bitflags;
2use bytes::{Buf, BufMut, Bytes};
3
4use std::cmp::min;
5use std::fmt;
6
7use super::PacketParseError;
8use crate::protocol::TimeStamp;
9use crate::{MsgNumber, SeqNumber, SocketID};
10
11/// A UDT packet carrying data
12///
13/// ```ignore,
14/// 0 1 2 3
15/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
16/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17/// |0| Packet Sequence Number |
18/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19/// |FF |O| Message Number |
20/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21/// | Time Stamp |
22/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23/// | Destination Socket ID |
24/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25/// ```
26/// (from <https://tools.ietf.org/html/draft-gg-udt-03>)
27#[derive(Clone, PartialEq, Eq)]
28pub struct DataPacket {
29 /// The sequence number is packet based, so if packet n has
30 /// sequence number `i`, the next would have `i + 1`
31
32 /// Represented by a 31 bit unsigned integer, so
33 /// Sequence number is wrapped after it recahed 2^31 - 1
34 pub seq_number: SeqNumber,
35
36 /// Message location and delivery order
37 /// Represented by the first two bits in the second row of 4 bytes
38 pub message_loc: PacketLocation,
39
40 /// In order delivery, the third bit in the second row of 4 bytes
41 pub in_order_delivery: bool,
42
43 /// The message number, is the ID of the message being passed
44 /// Represented by the final 29 bits of the third row
45 /// It's only 29 bits long, so it's wrapped after 2^29 - 1
46 pub message_number: MsgNumber,
47
48 /// The timestamp, relative to when the connection was created.
49 pub timestamp: TimeStamp,
50
51 /// The dest socket id, used for UDP multiplexing
52 pub dest_sockid: SocketID,
53
54 /// The rest of the packet, the payload
55 pub payload: Bytes,
56}
57
58bitflags! {
59 /// Signifies the packet location in a message for a data packet
60 /// The bitflag just represents the first byte in the second line
61 /// FIRST | LAST means it's the only one
62 /// FIRST means it's the beginning of a longer message
63 /// 0 means it's the middle of a longer message
64 pub struct PacketLocation: u8 {
65 const MIDDLE = 0b0000_0000;
66 const FIRST = 0b1000_0000;
67 const LAST = 0b0100_0000;
68 const ONLY = Self::FIRST.bits | Self::LAST.bits;
69 }
70}
71
72impl DataPacket {
73 pub fn parse(buf: &mut impl Buf) -> Result<DataPacket, PacketParseError> {
74 // get the sequence number, which is the last 31 bits of the header
75 let seq_number = SeqNumber::new_truncate(buf.get_u32());
76
77 // the first two bits of the second line (second_line >> 24) is the location
78 let message_loc = PacketLocation::from_bits_truncate(buf.bytes()[0]);
79
80 // in order delivery is the third bit
81 let in_order_delivery = (buf.bytes()[0] & 0b0010_0000) != 0;
82
83 let message_number = MsgNumber::new_truncate(buf.get_u32());
84 let timestamp = TimeStamp::from_micros(buf.get_u32());
85 let dest_sockid = SocketID(buf.get_u32());
86
87 Ok(DataPacket {
88 seq_number,
89 message_loc,
90 in_order_delivery,
91 message_number,
92 timestamp,
93 dest_sockid,
94 payload: buf.to_bytes(),
95 })
96 }
97
98 pub fn serialize(&self, into: &mut impl BufMut) {
99 assert!(self.seq_number.as_raw() & (1 << 31) == 0);
100
101 into.put_u32(self.seq_number.as_raw());
102
103 // the format is first two bits are the message location, third is in order delivery, and the rest is message number
104 // message number is garunteed have it's first three bits as zero
105 into.put_u32(
106 self.message_number.as_raw()
107 | ((u32::from(self.message_loc.bits() | (self.in_order_delivery as u8) << 5))
108 << 24),
109 );
110 into.put_u32(self.timestamp.as_micros());
111 into.put_u32(self.dest_sockid.0);
112 into.put(&self.payload[..]);
113 }
114}
115
116impl fmt::Debug for DataPacket {
117 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
118 write!(
119 f,
120 "{{DATA sn={} loc={:?} msgno={} ts={:.4} dst={:?} payload=[len={}, start={:?}]}}",
121 self.seq_number.0,
122 self.message_loc,
123 self.message_number.0,
124 self.timestamp.as_secs_f64(),
125 self.dest_sockid,
126 self.payload.len(),
127 self.payload.slice(..min(8, self.payload.len())),
128 )
129 }
130}