1use crate::coding::Reader;
8use crate::packet::{VERSION_1, VERSION_2};
9
10pub const VERSION_INFORMATION: u64 = 0x11;
12
13pub fn compatible(from: u32, to: u32) -> bool {
16 from == to || matches!((from, to), (VERSION_1, VERSION_2) | (VERSION_2, VERSION_1))
17}
18
19pub fn encode(chosen: u32, available: &[u32]) -> Vec<u8> {
21 let mut v = Vec::with_capacity(4 + 4 * available.len());
22 v.extend_from_slice(&chosen.to_be_bytes());
23 for a in available {
24 v.extend_from_slice(&a.to_be_bytes());
25 }
26 v
27}
28
29pub fn decode(v: &[u8]) -> Option<(u32, Vec<u32>)> {
32 if v.len() < 4 || v.len() % 4 != 0 {
33 return None;
34 }
35 let mut r = Reader::new(v);
36 let chosen = r.u32()?;
37 if chosen == 0 {
38 return None;
39 }
40 let mut available = Vec::new();
41 while let Some(x) = r.u32() {
42 available.push(x);
43 }
44 Some((chosen, available))
45}
46
47pub fn hello_len(buf: &[u8]) -> Option<usize> {
50 if buf.len() < 4 {
51 return None;
52 }
53 Some(4 + ((buf[1] as usize) << 16 | (buf[2] as usize) << 8 | buf[3] as usize))
54}
55
56pub fn client_versions(hello: &[u8]) -> Option<(u32, Vec<u32>)> {
58 let mut r = Reader::new(hello);
59 if r.u8()? != 1 {
60 return None;
61 }
62 let len = (r.u8()? as usize) << 16 | (r.u16()? as usize);
63 let mut r = Reader::new(r.bytes(len)?);
64 r.bytes(2 + 32)?; let n = r.u8()? as usize;
66 r.bytes(n)?; let n = r.u16()? as usize;
68 r.bytes(n)?; let n = r.u8()? as usize;
70 r.bytes(n)?; let n = r.u16()? as usize;
72 let mut ext = Reader::new(r.bytes(n)?);
73 while !ext.is_empty() {
74 let ty = ext.u16()?;
75 let n = ext.u16()? as usize;
76 let body = ext.bytes(n)?;
77 if ty != 0x39 {
78 continue;
79 }
80 let mut tp = Reader::new(body);
81 while !tp.is_empty() {
82 let id = tp.varint()?;
83 let v = tp.vbytes()?;
84 if id == VERSION_INFORMATION {
85 return decode(v);
86 }
87 }
88 return None;
89 }
90 None
91}
92
93pub fn choose(started: u32, preferred: &[u32], client: Option<&(u32, Vec<u32>)>) -> u32 {
96 let Some((_, available)) = client else { return started };
97 preferred.iter().copied().find(|&v| compatible(started, v) && available.contains(&v)).unwrap_or(started)
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 fn hello(tp: &[u8]) -> Vec<u8> {
105 let mut ext = Vec::new();
106 ext.extend_from_slice(&0x0010u16.to_be_bytes()); ext.extend_from_slice(&3u16.to_be_bytes());
108 ext.extend_from_slice(&[0, 1, b'h']);
109 ext.extend_from_slice(&0x39u16.to_be_bytes());
110 ext.extend_from_slice(&(tp.len() as u16).to_be_bytes());
111 ext.extend_from_slice(tp);
112 let mut body = vec![3, 3];
113 body.extend_from_slice(&[7; 32]);
114 body.push(0);
115 body.extend_from_slice(&[0, 2, 0x13, 0x01]);
116 body.extend_from_slice(&[1, 0]);
117 body.extend_from_slice(&(ext.len() as u16).to_be_bytes());
118 body.extend_from_slice(&ext);
119 let mut m = vec![1, 0, (body.len() >> 8) as u8, body.len() as u8];
120 m.extend_from_slice(&body);
121 m
122 }
123
124 #[test]
125 fn reads_version_information_from_a_client_hello() {
126 let vi = encode(VERSION_1, &[VERSION_1, VERSION_2]);
127 let mut tp = vec![0x0f, 0x01, 0x07, VERSION_INFORMATION as u8, vi.len() as u8];
128 tp.extend_from_slice(&vi);
129 let h = hello(&tp);
130 assert_eq!(hello_len(&h), Some(h.len()));
131 let got = client_versions(&h).unwrap();
132 assert_eq!(got, (VERSION_1, vec![VERSION_1, VERSION_2]));
133 assert_eq!(choose(VERSION_1, &[VERSION_2, VERSION_1], Some(&got)), VERSION_2);
134 assert_eq!(choose(VERSION_1, &[VERSION_1, VERSION_2], Some(&got)), VERSION_1);
135 assert_eq!(choose(VERSION_1, &[VERSION_2, VERSION_1], None), VERSION_1);
136 let only = (VERSION_1, vec![VERSION_1]);
138 assert_eq!(choose(VERSION_1, &[VERSION_2, VERSION_1], Some(&only)), VERSION_1);
139 assert_eq!(client_versions(&hello(&[0x0f, 0x01, 0x07])), None);
141 assert_eq!(client_versions(&h[..h.len() - 1]), None);
142 assert_eq!(decode(&[0, 0, 0, 1, 2]), None);
143 assert_eq!(decode(&[0, 0, 0, 0]), None);
144 }
145}