1use std::net::SocketAddr;
2
3use bytes::Buf;
4
5use crate::error::DecodeError;
6use crate::protocol::codec::RaknetCodec;
7use crate::protocol::constants::Magic;
8
9#[derive(Debug, Clone)]
10pub struct OpenConnectionRequest1 {
11 pub protocol_version: u8,
12 pub mtu: u16,
13 pub magic: Magic,
14}
15
16#[derive(Debug, Clone)]
17pub struct OpenConnectionReply1 {
18 pub server_guid: u64,
19 pub mtu: u16,
20 pub cookie: Option<u32>,
21 pub magic: Magic,
22}
23
24#[derive(Debug, Clone)]
25pub struct OpenConnectionRequest2 {
26 pub server_addr: SocketAddr,
27 pub mtu: u16,
28 pub client_guid: u64,
29 pub cookie: Option<u32>,
30 pub client_proof: bool,
31 pub parse_path: Request2ParsePath,
32 pub magic: Magic,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum Request2ParsePath {
37 StrictNoCookie,
38 StrictWithCookie,
39 AmbiguousPreferredNoCookie,
40 AmbiguousPreferredWithCookie,
41 LegacyHeuristic,
42}
43
44#[derive(Debug, Clone)]
45pub struct OpenConnectionReply2 {
46 pub server_guid: u64,
47 pub server_addr: SocketAddr,
48 pub mtu: u16,
49 pub use_encryption: bool,
50 pub magic: Magic,
51}
52
53pub(super) fn decode_request_1(
54 src: &mut impl Buf,
55 expected_magic: Magic,
56) -> Result<OpenConnectionRequest1, DecodeError> {
57 let magic = super::validate_magic(Magic::decode_raknet(src)?, expected_magic)?;
58 let protocol_version = u8::decode_raknet(src)?;
59 let padding_len = src.remaining();
60 let _ = src.copy_to_bytes(padding_len);
61
62 let mtu = (padding_len + 18) as u16;
63 Ok(OpenConnectionRequest1 {
64 protocol_version,
65 mtu,
66 magic,
67 })
68}
69
70pub(super) fn decode_reply_1(
71 src: &mut impl Buf,
72 expected_magic: Magic,
73) -> Result<OpenConnectionReply1, DecodeError> {
74 let magic = super::validate_magic(Magic::decode_raknet(src)?, expected_magic)?;
75 let server_guid = u64::decode_raknet(src)?;
76 let has_cookie = bool::decode_raknet(src)?;
77 let cookie = if has_cookie {
78 Some(u32::decode_raknet(src)?)
79 } else {
80 None
81 };
82 let mtu = u16::decode_raknet(src)?;
83
84 Ok(OpenConnectionReply1 {
85 server_guid,
86 mtu,
87 cookie,
88 magic,
89 })
90}
91
92pub(super) fn decode_request_2(
93 src: &mut impl Buf,
94 expected_magic: Magic,
95) -> Result<OpenConnectionRequest2, DecodeError> {
96 let magic = super::validate_magic(Magic::decode_raknet(src)?, expected_magic)?;
97 let remaining = src.copy_to_bytes(src.remaining());
98 let body = &remaining[..];
99
100 let strict_no_cookie = parse_request_2_candidate(body, false, true);
101 let strict_with_cookie = parse_request_2_candidate(body, true, true);
102
103 match (strict_no_cookie, strict_with_cookie) {
104 (Ok(candidate), Err(_)) => {
105 Ok(candidate.into_request(magic, Request2ParsePath::StrictNoCookie))
106 }
107 (Err(_), Ok(candidate)) => {
108 Ok(candidate.into_request(magic, Request2ParsePath::StrictWithCookie))
109 }
110 (Ok(no_cookie), Ok(with_cookie)) => {
111 let path = if matches!(body.first().copied(), Some(4 | 6)) {
112 Request2ParsePath::AmbiguousPreferredNoCookie
113 } else {
114 Request2ParsePath::AmbiguousPreferredWithCookie
115 };
116 let chosen = match path {
117 Request2ParsePath::AmbiguousPreferredNoCookie => no_cookie,
118 Request2ParsePath::AmbiguousPreferredWithCookie => with_cookie,
119 _ => unreachable!("ambiguous path must choose one strict candidate"),
120 };
121 Ok(chosen.into_request(magic, path))
122 }
123 (Err(_), Err(_)) => {
124 let legacy = parse_request_2_legacy(body)?;
125 Ok(legacy.into_request(magic, Request2ParsePath::LegacyHeuristic))
126 }
127 }
128}
129
130#[derive(Debug, Clone, Copy)]
131struct Request2Candidate {
132 server_addr: SocketAddr,
133 mtu: u16,
134 client_guid: u64,
135 cookie: Option<u32>,
136 client_proof: bool,
137}
138
139impl Request2Candidate {
140 fn into_request(self, magic: Magic, parse_path: Request2ParsePath) -> OpenConnectionRequest2 {
141 OpenConnectionRequest2 {
142 server_addr: self.server_addr,
143 mtu: self.mtu,
144 client_guid: self.client_guid,
145 cookie: self.cookie,
146 client_proof: self.client_proof,
147 parse_path,
148 magic,
149 }
150 }
151}
152
153fn parse_request_2_candidate(
154 mut body: &[u8],
155 with_cookie: bool,
156 strict_bool: bool,
157) -> Result<Request2Candidate, DecodeError> {
158 let mut cookie = None;
159 let mut client_proof = false;
160
161 if with_cookie {
162 if body.len() < 5 {
163 return Err(DecodeError::UnexpectedEof);
164 }
165 cookie = Some(u32::from_be_bytes([body[0], body[1], body[2], body[3]]));
166 let raw_proof = body[4];
167 if strict_bool && raw_proof > 1 {
168 return Err(DecodeError::InvalidRequest2Layout);
169 }
170 client_proof = raw_proof == 1;
171 body = &body[5..];
172 }
173
174 let server_addr = SocketAddr::decode_raknet(&mut body)?;
175 let mtu = u16::decode_raknet(&mut body)?;
176 let client_guid = u64::decode_raknet(&mut body)?;
177 if !body.is_empty() {
178 return Err(DecodeError::InvalidRequest2Layout);
179 }
180
181 Ok(Request2Candidate {
182 server_addr,
183 mtu,
184 client_guid,
185 cookie,
186 client_proof,
187 })
188}
189
190fn parse_request_2_legacy(body: &[u8]) -> Result<Request2Candidate, DecodeError> {
191 let mut with_cookie = false;
192 if let Some(first) = body.first().copied()
193 && first != 4
194 && first != 6
195 {
196 with_cookie = true;
197 }
198 parse_request_2_candidate(body, with_cookie, false)
199}
200
201pub(super) fn decode_reply_2(
202 src: &mut impl Buf,
203 expected_magic: Magic,
204) -> Result<OpenConnectionReply2, DecodeError> {
205 let magic = super::validate_magic(Magic::decode_raknet(src)?, expected_magic)?;
206 let server_guid = u64::decode_raknet(src)?;
207 let server_addr = SocketAddr::decode_raknet(src)?;
208 let mtu = u16::decode_raknet(src)?;
209 let use_encryption = bool::decode_raknet(src)?;
210
211 Ok(OpenConnectionReply2 {
212 server_guid,
213 server_addr,
214 mtu,
215 use_encryption,
216 magic,
217 })
218}