1use crate::session::HARD_MAX_CONTROL_PAYLOAD_BYTES;
2use core::cell::Cell;
3use core::marker::PhantomData;
4
5const MAGIC: [u8; 8] = *b"NIPCAPP1";
6const VERSION_MAJOR: u16 = 1;
7const VERSION_MINOR: u16 = 0;
8pub(crate) const CONTROL_HEADER_LEN: usize = 72;
9pub const APPLICATION_CONTROL_KIND_MIN: u32 = 0x8000_0000;
11
12pub(crate) const fn control_wire_len(payload_len: usize) -> Option<usize> {
13 CONTROL_HEADER_LEN.checked_add(payload_len)
14}
15
16#[derive(Debug, Eq, PartialEq)]
18pub struct ControlFrame {
19 pub(crate) kind: u32,
20 pub(crate) payload: Vec<u8>,
21}
22
23impl ControlFrame {
24 pub const fn kind(&self) -> u32 {
26 self.kind
27 }
28
29 pub fn payload(&self) -> &[u8] {
31 &self.payload
32 }
33
34 pub fn into_payload(self) -> Vec<u8> {
36 self.payload
37 }
38}
39
40pub(crate) struct ControlState {
41 nonce: [u8; 32],
42 maximum_payload: u32,
43 next_send: u64,
44 next_receive: u64,
45 transaction_open: bool,
46 poisoned: bool,
47 pending_receive: bool,
48 not_sync: PhantomData<Cell<()>>,
49}
50
51impl ControlState {
52 pub(crate) fn new(nonce: [u8; 32], maximum_payload: u32) -> Option<Self> {
53 if nonce == [0; 32]
54 || maximum_payload == 0
55 || maximum_payload > HARD_MAX_CONTROL_PAYLOAD_BYTES
56 {
57 return None;
58 }
59 Some(Self {
60 nonce,
61 maximum_payload,
62 next_send: 1,
63 next_receive: 1,
64 transaction_open: false,
65 poisoned: false,
66 pending_receive: false,
67 not_sync: PhantomData,
68 })
69 }
70
71 #[cfg(test)]
72 pub(crate) fn encoded_len(&self, frame: &ControlFrame) -> Result<usize, ControlError> {
73 self.encoded_len_parts(frame.kind, frame.payload.len())
74 }
75
76 pub(crate) fn encoded_len_parts(
77 &self,
78 kind: u32,
79 payload_len: usize,
80 ) -> Result<usize, ControlError> {
81 self.check_local_parts(kind, payload_len)?;
82 control_wire_len(payload_len).ok_or(ControlError::LengthOverflow)
83 }
84
85 #[cfg(test)]
86 pub(crate) fn encode_into(
87 &mut self,
88 frame: &ControlFrame,
89 destination: &mut [u8],
90 ) -> Result<usize, ControlError> {
91 self.encode_parts_into(frame.kind, &frame.payload, destination)
92 }
93
94 pub(crate) fn encode_parts_into(
95 &mut self,
96 kind: u32,
97 payload: &[u8],
98 destination: &mut [u8],
99 ) -> Result<usize, ControlError> {
100 if self.transaction_open || self.pending_receive {
101 self.poisoned = true;
102 return Err(ControlError::TransactionConflict);
103 }
104 if self.next_send == u64::MAX {
105 self.poisoned = true;
106 return Err(ControlError::SequenceExhausted);
107 }
108 let required = self.encoded_len_parts(kind, payload.len())?;
109 if destination.len() < required {
110 return Err(ControlError::DestinationTooSmall);
111 }
112 destination[28..32].fill(0);
116 destination[..8].copy_from_slice(&MAGIC);
117 put_u16(destination, 8, VERSION_MAJOR);
118 put_u16(destination, 10, VERSION_MINOR);
119 put_u32(destination, 12, CONTROL_HEADER_LEN as u32);
120 put_u32(
121 destination,
122 16,
123 u32::try_from(required).map_err(|_| ControlError::LengthOverflow)?,
124 );
125 put_u32(
126 destination,
127 20,
128 u32::try_from(payload.len()).map_err(|_| ControlError::LengthOverflow)?,
129 );
130 put_u32(destination, 24, kind);
131 destination[32..64].copy_from_slice(&self.nonce);
132 put_u64(destination, 64, self.next_send);
133 destination[CONTROL_HEADER_LEN..required].copy_from_slice(payload);
134 self.next_send = self
135 .next_send
136 .checked_add(1)
137 .ok_or(ControlError::SequenceExhausted)?;
138 Ok(required)
139 }
140
141 #[cfg(test)]
142 pub(crate) fn decode(&mut self, source: &[u8]) -> Result<ControlFrame, ControlError> {
143 if source.len() < CONTROL_HEADER_LEN {
144 self.poisoned = true;
145 return Err(ControlError::Truncated);
146 }
147 let header = self.validate_header(&source[..CONTROL_HEADER_LEN])?;
148 let expected =
149 control_wire_len(header.payload_len()).ok_or(ControlError::LengthOverflow)?;
150 if source.len() != expected {
151 return Err(ControlError::NonCanonical);
152 }
153 header.finish(&source[CONTROL_HEADER_LEN..])
154 }
155
156 pub(crate) fn decode_owned(
157 &mut self,
158 mut source: Vec<u8>,
159 ) -> Result<ControlFrame, ControlError> {
160 if source.len() < CONTROL_HEADER_LEN {
161 self.poisoned = true;
162 return Err(ControlError::Truncated);
163 }
164 let header = self.validate_header(&source[..CONTROL_HEADER_LEN])?;
165 let payload_len = header.payload_len();
166 let expected = control_wire_len(payload_len).ok_or(ControlError::LengthOverflow)?;
167 if source.len() != expected {
168 return Err(ControlError::NonCanonical);
169 }
170 source.copy_within(CONTROL_HEADER_LEN..expected, 0);
171 source.truncate(payload_len);
172 header.finish_owned(source)
173 }
174
175 pub(crate) fn validate_header(
176 &mut self,
177 source: &[u8],
178 ) -> Result<PendingControlReceive<'_>, ControlError> {
179 let result = self.validate_header_inner(source);
180 if result.is_err() {
181 self.poisoned = true;
182 } else {
183 self.pending_receive = true;
184 }
185 result.map(|header| PendingControlReceive {
186 state: self,
187 kind: header.kind,
188 payload_len: header.payload_len,
189 committed: false,
190 })
191 }
192
193 pub(crate) fn begin_transaction(&mut self) -> Result<(), ControlError> {
194 if self.poisoned {
195 return Err(ControlError::Poisoned);
196 }
197 if self.transaction_open || self.pending_receive {
198 self.poisoned = true;
199 return Err(ControlError::TransactionConflict);
200 }
201 self.transaction_open = true;
202 Ok(())
203 }
204
205 pub(crate) fn end_transaction(&mut self) -> Result<(), ControlError> {
206 if self.poisoned {
207 return Err(ControlError::Poisoned);
208 }
209 if !self.transaction_open {
210 self.poisoned = true;
211 return Err(ControlError::TransactionConflict);
212 }
213 self.transaction_open = false;
214 Ok(())
215 }
216
217 pub(crate) fn poison(&mut self) {
218 self.poisoned = true;
219 }
220
221 pub(crate) const fn is_poisoned(&self) -> bool {
222 self.poisoned
223 }
224
225 pub(crate) const fn is_transaction_open(&self) -> bool {
226 self.transaction_open
227 }
228
229 fn check_local_parts(&self, kind: u32, payload_len: usize) -> Result<(), ControlError> {
230 if self.poisoned {
231 return Err(ControlError::Poisoned);
232 }
233 if self.transaction_open {
234 return Err(ControlError::TransactionConflict);
235 }
236 if kind < APPLICATION_CONTROL_KIND_MIN {
237 return Err(ControlError::ReservedKind);
238 }
239 let payload_len = u32::try_from(payload_len).map_err(|_| ControlError::LengthOverflow)?;
240 if payload_len > self.maximum_payload || payload_len > HARD_MAX_CONTROL_PAYLOAD_BYTES {
241 return Err(ControlError::PayloadTooLarge);
242 }
243 if self.next_send == u64::MAX {
244 return Err(ControlError::SequenceExhausted);
245 }
246 Ok(())
247 }
248
249 fn validate_header_inner(&self, source: &[u8]) -> Result<ValidatedControlHeader, ControlError> {
250 if self.poisoned {
251 return Err(ControlError::Poisoned);
252 }
253 if self.transaction_open {
254 return Err(ControlError::TransactionConflict);
255 }
256 if self.pending_receive {
257 return Err(ControlError::ReplayOrReorder);
258 }
259 if source.len() != CONTROL_HEADER_LEN {
260 return Err(ControlError::Truncated);
261 }
262 if source[..8] != MAGIC {
263 return Err(ControlError::BadMagic);
264 }
265 if get_u16(source, 8) != VERSION_MAJOR || get_u16(source, 10) != VERSION_MINOR {
266 return Err(ControlError::BadVersion);
267 }
268 if get_u32(source, 12) != CONTROL_HEADER_LEN as u32 || get_u32(source, 28) != 0 {
269 return Err(ControlError::NonCanonical);
270 }
271 let frame_len = get_u32(source, 16) as usize;
272 let payload_len = get_u32(source, 20);
273 let expected_len =
274 control_wire_len(payload_len as usize).ok_or(ControlError::LengthOverflow)?;
275 if frame_len != expected_len {
276 return Err(ControlError::NonCanonical);
277 }
278 if payload_len > self.maximum_payload || payload_len > HARD_MAX_CONTROL_PAYLOAD_BYTES {
279 return Err(ControlError::PayloadTooLarge);
280 }
281 let kind = get_u32(source, 24);
282 if kind < APPLICATION_CONTROL_KIND_MIN {
283 return Err(ControlError::ReservedKind);
284 }
285 if source[32..64] != self.nonce {
286 return Err(ControlError::WrongSession);
287 }
288 if get_u64(source, 64) != self.next_receive {
289 return Err(ControlError::ReplayOrReorder);
290 }
291 if self.next_receive == u64::MAX {
292 return Err(ControlError::SequenceExhausted);
293 }
294 Ok(ValidatedControlHeader { kind, payload_len })
295 }
296}
297
298pub(crate) struct ValidatedControlHeader {
299 kind: u32,
300 payload_len: u32,
301}
302
303pub(crate) struct PendingControlReceive<'a> {
304 state: &'a mut ControlState,
305 kind: u32,
306 payload_len: u32,
307 committed: bool,
308}
309
310impl PendingControlReceive<'_> {
311 pub(crate) const fn payload_len(&self) -> usize {
312 self.payload_len as usize
313 }
314
315 #[cfg(test)]
316 pub(crate) fn finish(self, payload_source: &[u8]) -> Result<ControlFrame, ControlError> {
317 if payload_source.len() != self.payload_len as usize {
318 return Err(ControlError::NonCanonical);
319 }
320 let mut payload = Vec::new();
321 payload
322 .try_reserve_exact(self.payload_len as usize)
323 .map_err(|_| ControlError::AllocationFailed)?;
324 payload.extend_from_slice(payload_source);
325 self.finish_owned(payload)
326 }
327
328 pub(crate) fn finish_owned(mut self, payload: Vec<u8>) -> Result<ControlFrame, ControlError> {
329 if payload.len() != self.payload_len as usize {
330 return Err(ControlError::NonCanonical);
331 }
332 self.state.next_receive = self
333 .state
334 .next_receive
335 .checked_add(1)
336 .ok_or(ControlError::SequenceExhausted)?;
337 self.state.pending_receive = false;
338 self.committed = true;
339 Ok(ControlFrame {
340 kind: self.kind,
341 payload,
342 })
343 }
344}
345
346impl Drop for PendingControlReceive<'_> {
347 fn drop(&mut self) {
348 if !self.committed {
349 self.state.pending_receive = false;
350 self.state.poisoned = true;
351 }
352 }
353}
354
355#[derive(Clone, Copy, Debug, Eq, PartialEq)]
357pub enum ControlError {
358 Poisoned,
360 Truncated,
362 BadMagic,
364 BadVersion,
366 NonCanonical,
368 WrongSession,
370 ReservedKind,
372 PayloadTooLarge,
374 ReplayOrReorder,
376 TransactionConflict,
378 SequenceExhausted,
380 LengthOverflow,
382 AllocationFailed,
384 DestinationTooSmall,
386}
387
388impl core::fmt::Display for ControlError {
389 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
390 write!(formatter, "application control failed: {self:?}")
391 }
392}
393
394impl std::error::Error for ControlError {}
395
396fn put_u16(bytes: &mut [u8], offset: usize, value: u16) {
397 bytes[offset..offset + 2].copy_from_slice(&value.to_le_bytes());
398}
399
400fn put_u32(bytes: &mut [u8], offset: usize, value: u32) {
401 bytes[offset..offset + 4].copy_from_slice(&value.to_le_bytes());
402}
403
404fn put_u64(bytes: &mut [u8], offset: usize, value: u64) {
405 bytes[offset..offset + 8].copy_from_slice(&value.to_le_bytes());
406}
407
408fn get_u16(bytes: &[u8], offset: usize) -> u16 {
409 u16::from_le_bytes(
410 bytes[offset..offset + 2]
411 .try_into()
412 .expect("fixed checked range"),
413 )
414}
415
416fn get_u32(bytes: &[u8], offset: usize) -> u32 {
417 u32::from_le_bytes(
418 bytes[offset..offset + 4]
419 .try_into()
420 .expect("fixed checked range"),
421 )
422}
423
424fn get_u64(bytes: &[u8], offset: usize) -> u64 {
425 u64::from_le_bytes(
426 bytes[offset..offset + 8]
427 .try_into()
428 .expect("fixed checked range"),
429 )
430}
431
432#[cfg(test)]
433#[path = "control_test.rs"]
434mod tests;