1use super::append::DataLimits;
4use super::{ENVELOPE_BYTES, Envelope, EnvelopeError, EnvelopeLimits, Opcode, Packet};
5use crate::layout::{LayoutError, Reader};
6use smallvec::SmallVec;
7
8pub const OWNER_APPEND: u16 = 1;
10pub const OWNER_GROUPS: u16 = 1 << 7;
12pub const OWNER_ROUTING: u16 = 1 << 9;
14pub const OWNER_READ: u16 = 1 << 10;
16pub const OWNER_PROGRESS: u16 = 1 << 11;
18pub const OWNER_STREAM: u16 = 1 << 12;
20pub const CONSUMER: u32 = 2;
22pub const PRODUCER: u32 = 1;
24pub const OWNER: u32 = 4;
26const KNOWN_CAPABILITIES: u16 = 0x1fff;
28const MAX_PROPERTIES: usize = 32;
29const NAMES: [&[u8]; 10] = [
30 b"versions",
31 b"capabilities",
32 b"required-capabilities",
33 b"max-metadata-bytes",
34 b"max-payload-bytes",
35 b"max-batch-records",
36 b"max-payload-parts",
37 b"roles",
38 b"max-record-bytes",
39 b"superseded-hello",
40];
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub struct Parameters {
45 pub capabilities: u16,
47 pub required_capabilities: u16,
49 pub receive: DataLimits,
51 pub roles: u32,
53}
54
55impl Parameters {
56 pub fn streaming(receive: DataLimits, roles: u32) -> Result<Self, HandshakeError> {
59 let parameters = Self {
60 capabilities: OWNER_APPEND | OWNER_STREAM,
61 required_capabilities: OWNER_APPEND | OWNER_STREAM,
62 receive,
63 roles,
64 };
65 parameters.validate()?;
66 Ok(parameters)
67 }
68 pub fn reader(receive: DataLimits, roles: u32) -> Result<Self, HandshakeError> {
70 let mut parameters = Self::append(receive, roles)?;
71 parameters.capabilities = OWNER_READ;
72 parameters.required_capabilities = OWNER_READ;
73 Ok(parameters)
74 }
75
76 pub fn processing(receive: DataLimits, roles: u32) -> Result<Self, HandshakeError> {
78 let mut parameters = Self::reader(receive, roles)?;
79 parameters.capabilities |= OWNER_PROGRESS;
80 parameters.required_capabilities |= OWNER_PROGRESS;
81 parameters.validate()?;
82 Ok(parameters)
83 }
84
85 pub fn group(receive: DataLimits, roles: u32) -> Result<Self, HandshakeError> {
87 let mut parameters = Self::processing(receive, roles)?;
88 parameters.capabilities |= OWNER_GROUPS;
89 parameters.required_capabilities |= OWNER_GROUPS;
90 parameters.validate()?;
91 Ok(parameters)
92 }
93 pub fn append(receive: DataLimits, roles: u32) -> Result<Self, HandshakeError> {
95 let parameters = Self {
96 capabilities: OWNER_APPEND,
97 required_capabilities: OWNER_APPEND,
98 receive,
99 roles,
100 };
101 parameters.validate()?;
102 Ok(parameters)
103 }
104
105 pub fn validate(self) -> Result<(), HandshakeError> {
107 let sizes = [
108 self.receive.envelope.max_metadata_bytes,
109 self.receive.envelope.max_payload_bytes,
110 self.receive.max_records,
111 self.receive.max_parts,
112 self.receive.max_record_bytes,
113 ];
114 if sizes.iter().any(|&n| n == 0 || u32::try_from(n).is_err())
115 || self.receive.envelope.max_metadata_bytes < 512
116 || self.capabilities & !KNOWN_CAPABILITIES != 0
117 || (self.capabilities & OWNER_STREAM != 0 && self.capabilities & OWNER_APPEND == 0)
118 || (self.capabilities & OWNER_PROGRESS != 0 && self.capabilities & OWNER_READ == 0)
119 || (self.capabilities & OWNER_GROUPS != 0 && self.capabilities & OWNER_PROGRESS == 0)
120 || self.required_capabilities & !self.capabilities != 0
121 || self.roles == 0
122 || self.roles & !31 != 0
123 {
124 return Err(HandshakeError::Parameters);
125 }
126 Ok(())
127 }
128
129 pub fn select(self, remote: Self) -> Result<Self, HandshakeError> {
132 self.validate()?;
133 remote.validate()?;
134 let selected = self.capabilities & remote.capabilities;
135 if (self.required_capabilities | remote.required_capabilities) & !selected != 0 {
136 return Err(HandshakeError::Capabilities);
137 }
138 Ok(Self {
139 capabilities: selected,
140 ..self
141 })
142 }
143}
144
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
147pub struct Handshake {
148 pub superseded_hello: Option<u128>,
151 pub instance_id: u128,
153 pub hello_nonce: u128,
155 pub parameters: Parameters,
157}
158
159pub fn encode(
162 envelope: Envelope,
163 handshake: Handshake,
164 metadata: &mut Vec<u8>,
165 limits: EnvelopeLimits,
166) -> Result<[u8; ENVELOPE_BYTES], HandshakeError> {
167 validate_command(envelope, handshake)?;
168 let p = handshake.parameters;
169 let caps = capabilities(p.capabilities);
170 let required = capabilities(p.required_capabilities);
171 let properties: [(&[u8], &[u8]); 9] = [
172 (b"versions", &[0, 0, 0, 1, super::VERSION]),
173 (b"capabilities", caps.as_slice()),
174 (b"required-capabilities", required.as_slice()),
175 (
176 b"max-metadata-bytes",
177 &(p.receive.envelope.max_metadata_bytes as u32).to_be_bytes(),
178 ),
179 (
180 b"max-payload-bytes",
181 &(p.receive.envelope.max_payload_bytes as u32).to_be_bytes(),
182 ),
183 (
184 b"max-batch-records",
185 &(p.receive.max_records as u32).to_be_bytes(),
186 ),
187 (
188 b"max-payload-parts",
189 &(p.receive.max_parts as u32).to_be_bytes(),
190 ),
191 (b"roles", &p.roles.to_be_bytes()),
192 (
193 b"max-record-bytes",
194 &(p.receive.max_record_bytes as u32).to_be_bytes(),
195 ),
196 ];
197 let superseded = handshake.superseded_hello.map(u128::to_be_bytes);
198 let properties = properties.into_iter().chain(
199 superseded
200 .as_ref()
201 .map(|nonce| (&b"superseded-hello"[..], &nonce[..])),
202 );
203 let size = properties
205 .clone()
206 .try_fold(32_usize, |size, (name, value)| {
207 size.checked_add(5)?
208 .checked_add(name.len())?
209 .checked_add(value.len())
210 })
211 .ok_or(HandshakeError::Length)?;
212 let header = envelope.encode_header(size, 0, limits)?;
213 if metadata.capacity() < size {
214 return Err(HandshakeError::Capacity);
215 }
216 metadata.clear();
217 metadata.extend_from_slice(&handshake.instance_id.to_be_bytes());
218 metadata.extend_from_slice(&handshake.hello_nonce.to_be_bytes());
219 for (name, value) in properties {
220 write_property(metadata, name, value)?;
221 }
222 Ok(header)
223}
224
225fn write_property(metadata: &mut Vec<u8>, name: &[u8], value: &[u8]) -> Result<(), HandshakeError> {
227 let name_bytes = u8::try_from(name.len()).map_err(|_| HandshakeError::Properties)?;
228 let value_bytes = u32::try_from(value.len()).map_err(|_| HandshakeError::Properties)?;
229 metadata.push(name_bytes);
230 metadata.extend_from_slice(name);
231 metadata.extend_from_slice(&value_bytes.to_be_bytes());
232 metadata.extend_from_slice(value);
233 Ok(())
234}
235
236pub fn decode(packet: Packet<'_>, limits: EnvelopeLimits) -> Result<Handshake, HandshakeError> {
240 packet
241 .envelope
242 .validate_frames(packet.metadata.len(), packet.payload.len(), limits)?;
243 if !packet.payload.is_empty() {
244 return Err(HandshakeError::Command);
245 }
246 let mut reader = Reader::new(packet.metadata);
247 let instance_id = u128::from_be_bytes(reader.array()?);
248 let hello_nonce = u128::from_be_bytes(reader.array()?);
249 let values = read_properties(reader)?;
250 let mut v = [&[][..]; 9];
251 for (to, from) in v.iter_mut().zip(values) {
252 *to = from.ok_or(HandshakeError::Properties)?;
253 }
254 check_versions(v[0], packet.envelope.opcode)?;
255 let parameters = decode_parameters(&v)?;
256 let handshake = Handshake {
257 superseded_hello: values[9]
258 .map(|v| {
259 v.try_into()
260 .map(u128::from_be_bytes)
261 .map_err(|_| HandshakeError::Length)
262 })
263 .transpose()?,
264 instance_id,
265 hello_nonce,
266 parameters,
267 };
268 validate_command(packet.envelope, handshake)?;
269 Ok(handshake)
270}
271
272fn read_properties(mut reader: Reader<'_>) -> Result<[Option<&[u8]>; NAMES.len()], HandshakeError> {
275 let mut names: SmallVec<[&[u8]; MAX_PROPERTIES]> = SmallVec::new();
276 let mut values = [None; NAMES.len()];
277 while !reader.rest().is_empty() {
278 if names.len() == MAX_PROPERTIES {
279 return Err(HandshakeError::Properties);
280 }
281 let length = usize::from(reader.u8()?);
282 let name = reader.take(length)?;
283 if name.is_empty()
284 || !name.is_ascii()
285 || names.iter().any(|old| old.eq_ignore_ascii_case(name))
286 {
287 return Err(HandshakeError::Properties);
288 }
289 names.push(name);
290 let length = reader.u32()? as usize;
291 let value = reader.take(length)?;
292 if let Some(slot) = NAMES
293 .iter()
294 .zip(&mut values)
295 .find_map(|(known, slot)| known.eq_ignore_ascii_case(name).then_some(slot))
296 {
297 *slot = Some(value);
298 }
299 }
300 Ok(values)
301}
302
303fn check_versions(value: &[u8], opcode: Opcode) -> Result<(), HandshakeError> {
305 let mut versions = Reader::new(value);
306 let count = versions.u32()? as usize;
307 let versions = versions.rest();
308 if count == 0
309 || count > 256
310 || count != versions.len()
311 || !versions.contains(&super::VERSION)
312 || (opcode == Opcode::Welcome && versions != [super::VERSION])
313 {
314 return Err(HandshakeError::Version);
315 }
316 Ok(())
317}
318
319fn decode_parameters(v: &[&[u8]; 9]) -> Result<Parameters, HandshakeError> {
321 Ok(Parameters {
322 capabilities: decode_capabilities(v[1], false)?,
323 required_capabilities: decode_capabilities(v[2], true)?,
324 receive: DataLimits {
325 envelope: EnvelopeLimits {
326 max_metadata_bytes: number(v[3])? as usize,
327 max_payload_bytes: number(v[4])? as usize,
328 },
329 max_records: number(v[5])? as usize,
330 max_parts: number(v[6])? as usize,
331 max_record_bytes: number(v[8])? as usize,
332 },
333 roles: number(v[7])?,
334 })
335}
336
337fn validate_command(envelope: Envelope, handshake: Handshake) -> Result<(), HandshakeError> {
338 if !matches!(envelope.opcode, Opcode::Hello | Opcode::Welcome)
339 || envelope.response != (envelope.opcode == Opcode::Welcome)
340 || handshake.instance_id == 0
341 || handshake.hello_nonce == 0
342 || handshake.superseded_hello == Some(0)
343 || (envelope.opcode == Opcode::Hello && handshake.superseded_hello.is_some())
344 {
345 return Err(HandshakeError::Command);
346 }
347 handshake.parameters.validate()
348}
349
350#[expect(
351 clippy::arithmetic_side_effects,
352 reason = "capability ids lie in 1..=14"
353)]
354fn capabilities(bits: u16) -> SmallVec<[u8; 32]> {
355 let mut bytes = SmallVec::new();
356 bytes.extend_from_slice(&bits.count_ones().to_be_bytes());
357 for id in (1..=14_u16).filter(|id| bits & (1 << (id - 1)) != 0) {
358 bytes.extend_from_slice(&id.to_be_bytes());
359 }
360 bytes
361}
362
363#[expect(
364 clippy::arithmetic_side_effects,
365 reason = "the count is capped at 64 first, and set ids lie in 1..=14"
366)]
367fn decode_capabilities(bytes: &[u8], required: bool) -> Result<u16, HandshakeError> {
368 let mut reader = Reader::new(bytes);
369 let count = reader.u32()? as usize;
370 let bytes = reader.rest();
371 if count > 64 || bytes.len() != count * 2 {
372 return Err(HandshakeError::Capabilities);
373 }
374 let mut bits = 0;
375 let mut previous = 0;
376 for chunk in bytes.as_chunks::<2>().0 {
377 let id = u16::from_be_bytes(*chunk);
378 if id <= previous || (required && id > 14) {
379 return Err(HandshakeError::Capabilities);
380 }
381 previous = id;
382 if id <= 14 {
383 bits |= 1 << (id - 1);
384 }
385 }
386 Ok(bits)
387}
388
389fn number(bytes: &[u8]) -> Result<u32, HandshakeError> {
390 Ok(u32::from_be_bytes(
391 bytes.try_into().map_err(|_| HandshakeError::Length)?,
392 ))
393}
394
395#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
397pub enum HandshakeError {
398 #[error(transparent)]
400 Envelope(#[from] EnvelopeError),
401 #[error("invalid handshake command or identity")]
403 Command,
404 #[error("invalid handshake field length")]
406 Length,
407 #[error("invalid handshake properties")]
409 Properties,
410 #[error("no supported protocol version")]
412 Version,
413 #[error("unsupported handshake capabilities")]
415 Capabilities,
416 #[error("invalid handshake parameters")]
418 Parameters,
419 #[error("handshake encode buffer capacity exhausted")]
421 Capacity,
422}
423
424impl From<LayoutError> for HandshakeError {
425 fn from(_: LayoutError) -> Self {
426 Self::Length
427 }
428}