1use crate::{
5 connection,
6 event::{api::SocketAddress, IntoEvent},
7 inet, random,
8};
9
10#[non_exhaustive]
11pub struct Context<'a> {
12 pub remote_address: SocketAddress<'a>,
13 pub peer_connection_id: &'a [u8],
14 pub random: &'a mut dyn random::Generator,
15}
16
17impl<'a> Context<'a> {
18 #[inline]
19 #[doc(hidden)]
20 pub fn new(
21 remote_address: &'a inet::SocketAddress,
22 peer_connection_id: &'a connection::PeerId,
23 random: &'a mut dyn random::Generator,
24 ) -> Self {
25 Self {
26 remote_address: remote_address.into_event(),
27 peer_connection_id: peer_connection_id.as_bytes(),
28 random,
29 }
30 }
31}
32
33pub trait Format: 'static + Send {
34 const TOKEN_LEN: usize;
35
36 fn generate_new_token(
39 &mut self,
40 context: &mut Context<'_>,
41 source_connection_id: &connection::LocalId,
42 output_buffer: &mut [u8],
43 ) -> Option<()>;
44
45 fn generate_retry_token(
47 &mut self,
48 context: &mut Context<'_>,
49 original_destination_connection_id: &connection::InitialId,
50 output_buffer: &mut [u8],
51 ) -> Option<()>;
52
53 fn validate_token(
57 &mut self,
58 context: &mut Context<'_>,
59 token: &[u8],
60 ) -> Option<connection::InitialId>;
61}
62
63#[derive(Clone, Copy, Debug, Eq, PartialEq)]
64pub enum Source {
65 RetryPacket,
66 NewTokenFrame,
67}
68
69#[cfg(any(test, feature = "testing"))]
70pub mod testing {
71 use super::*;
72 use crate::crypto::retry;
73
74 #[derive(Debug, Default)]
75 pub struct Format(());
76
77 impl super::Format for Format {
78 const TOKEN_LEN: usize = retry::example::TOKEN_LEN;
79
80 fn generate_new_token(
81 &mut self,
82 _context: &mut Context<'_>,
83 _source_connection_id: &connection::LocalId,
84 _output_buffer: &mut [u8],
85 ) -> Option<()> {
86 None
88 }
89
90 fn generate_retry_token(
91 &mut self,
92 _context: &mut Context<'_>,
93 _original_destination_connection_id: &connection::InitialId,
94 output_buffer: &mut [u8],
95 ) -> Option<()> {
96 output_buffer.copy_from_slice(&retry::example::TOKEN);
97 Some(())
98 }
99
100 fn validate_token(
101 &mut self,
102 _context: &mut Context<'_>,
103 token: &[u8],
104 ) -> Option<connection::InitialId> {
105 if token == retry::example::TOKEN {
106 return Some(connection::InitialId::TEST_ID);
107 }
108
109 None
110 }
111 }
112
113 impl Format {
114 pub fn new() -> Self {
115 Self(())
116 }
117 }
118}