Skip to main content

moq_net/
setup.rs

1//! The SETUP exchange, and the credential a peer may present in it.
2//!
3//! Only [`Token`] is public; the SETUP messages themselves are wire internals.
4
5use bytes::Bytes;
6
7use crate::{
8	Version,
9	coding::{self, Decode, DecodeError, Encode, EncodeError, Sizer},
10	ietf, lite,
11};
12
13const CLIENT_SETUP: u8 = 0x20;
14const SERVER_SETUP: u8 = 0x21;
15
16/// Draft-17 unified SETUP message type (varint 0x2F00)
17pub(crate) const SETUP_V17: u64 = 0x2F00;
18
19/// A credential a moq-transport peer presented in its SETUP's `AUTHORIZATION TOKEN` option.
20///
21/// The transport never reads the bytes; verifying them is the application's job.
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct Token {
24	/// The wire Token Type, naming how [`value`](Self::value) is encoded.
25	pub kind: u64,
26	/// The token itself.
27	pub value: Vec<u8>,
28}
29
30impl Token {
31	/// Token Type 0: a format the endpoints agreed on out of band, such as a JWT.
32	pub const OUT_OF_BAND: u64 = 0x0;
33	/// Token Type 1: a Common Access Token (draft-ietf-moq-c4m).
34	pub const CAT: u64 = 0x1;
35}
36
37/// Draft-17+ unified SETUP message, with the same encoding for both client and server.
38#[derive(Debug, Clone)]
39pub(crate) struct Setup {
40	pub parameters: Bytes,
41}
42
43impl Setup {
44	fn check_version(v: Version) {
45		match v {
46			Version::Ietf(ietf::Version::Draft14 | ietf::Version::Draft15 | ietf::Version::Draft16)
47			| Version::Lite(_) => unreachable!("Setup is draft-17+ only"),
48			_ => {}
49		}
50	}
51}
52
53impl Encode<Version> for Setup {
54	fn encode<W: bytes::BufMut>(&self, w: &mut W, v: Version) -> Result<(), EncodeError> {
55		Self::check_version(v);
56		SETUP_V17.encode(w, v)?;
57		u16::try_from(self.parameters.len())
58			.map_err(|_| EncodeError::TooLarge)?
59			.encode(w, v)?;
60		if w.remaining_mut() < self.parameters.len() {
61			return Err(EncodeError::Short);
62		}
63		w.put_slice(&self.parameters);
64		Ok(())
65	}
66}
67
68impl Decode<Version> for Setup {
69	fn decode<R: bytes::Buf>(r: &mut R, v: Version) -> Result<Self, DecodeError> {
70		Self::check_version(v);
71		let kind = u64::decode(r, v)?;
72		if kind != SETUP_V17 {
73			return Err(DecodeError::InvalidValue);
74		}
75		let size = u16::decode(r, v)? as usize;
76		if r.remaining() < size {
77			return Err(DecodeError::Short);
78		}
79		let msg = r.copy_to_bytes(size);
80		Ok(Self { parameters: msg })
81	}
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, Eq)]
85enum SetupVersion {
86	Draft14,
87	Draft15Plus,
88	/// Draft17+ uses ALPN-only negotiation with no legacy SETUP message.
89	Modern,
90	LiteLegacy,
91	Unsupported,
92}
93
94impl SetupVersion {
95	fn from_version(v: Version) -> Self {
96		match v {
97			Version::Ietf(ietf::Version::Draft14) => Self::Draft14,
98			Version::Ietf(ietf::Version::Draft15) | Version::Ietf(ietf::Version::Draft16) => Self::Draft15Plus,
99			Version::Ietf(ietf::Version::Draft17)
100			| Version::Ietf(ietf::Version::Draft18)
101			| Version::Ietf(ietf::Version::Draft19)
102			| Version::Ietf(ietf::Version::Draft20)
103			| Version::Ietf(ietf::Version::Draft21)
104			| Version::Ietf(ietf::Version::Draft22) => Self::Modern,
105			Version::Lite(lite::Version::Lite01) | Version::Lite(lite::Version::Lite02) => Self::LiteLegacy,
106			Version::Lite(_) => Self::Unsupported,
107		}
108	}
109}
110
111/// A version-agnostic setup message sent by the client.
112#[derive(Debug, Clone)]
113pub(crate) struct Client {
114	/// The list of supported versions in preferred order.
115	pub versions: coding::Versions,
116
117	/// Parameters, unparsed because the IETF draft changed the encoding.
118	pub parameters: Bytes,
119}
120
121impl Client {
122	fn encode_inner<W: bytes::BufMut>(&self, w: &mut W, v: Version) -> Result<(), EncodeError> {
123		match SetupVersion::from_version(v) {
124			SetupVersion::Draft15Plus => {
125				// Draft15+: no versions list, parameters only.
126			}
127			SetupVersion::Draft14 | SetupVersion::LiteLegacy => self.versions.encode(w, v)?,
128			SetupVersion::Modern | SetupVersion::Unsupported => return Err(EncodeError::Version),
129		};
130		if w.remaining_mut() < self.parameters.len() {
131			return Err(EncodeError::Short);
132		}
133		w.put_slice(&self.parameters);
134		Ok(())
135	}
136}
137
138impl Decode<Version> for Client {
139	/// Decode a client setup message (draft-14 through draft-16 only).
140	fn decode<R: bytes::Buf>(r: &mut R, v: Version) -> Result<Self, DecodeError> {
141		let kind = u8::decode(r, v)?;
142		if kind != CLIENT_SETUP {
143			return Err(DecodeError::InvalidValue);
144		}
145
146		let size = match SetupVersion::from_version(v) {
147			SetupVersion::Draft14 | SetupVersion::Draft15Plus => u16::decode(r, v)? as usize,
148			SetupVersion::LiteLegacy => u64::decode(r, v)? as usize,
149			SetupVersion::Modern | SetupVersion::Unsupported => return Err(DecodeError::Version),
150		};
151
152		if r.remaining() < size {
153			return Err(DecodeError::Short);
154		}
155
156		let mut msg = r.copy_to_bytes(size);
157
158		let versions = match SetupVersion::from_version(v) {
159			SetupVersion::Draft15Plus => {
160				// Draft15+: no versions list, parameters only.
161				coding::Versions::from([v.into()])
162			}
163			SetupVersion::Draft14 | SetupVersion::LiteLegacy => coding::Versions::decode(&mut msg, v)?,
164			SetupVersion::Modern | SetupVersion::Unsupported => return Err(DecodeError::Version),
165		};
166
167		Ok(Self {
168			versions,
169			parameters: msg,
170		})
171	}
172}
173
174impl Encode<Version> for Client {
175	/// Encode a client setup message (draft-14 through draft-16 only).
176	fn encode<W: bytes::BufMut>(&self, w: &mut W, v: Version) -> Result<(), EncodeError> {
177		CLIENT_SETUP.encode(w, v)?;
178
179		let mut sizer = Sizer::default();
180		self.encode_inner(&mut sizer, v)?;
181		let size = sizer.size;
182
183		match SetupVersion::from_version(v) {
184			SetupVersion::Draft14 | SetupVersion::Draft15Plus => {
185				u16::try_from(size).map_err(|_| EncodeError::TooLarge)?.encode(w, v)?;
186			}
187			SetupVersion::LiteLegacy => (size as u64).encode(w, v)?,
188			SetupVersion::Modern | SetupVersion::Unsupported => return Err(EncodeError::Version),
189		}
190		self.encode_inner(w, v)
191	}
192}
193
194/// Sent by the server in response to a client setup.
195#[derive(Debug, Clone)]
196pub(crate) struct Server {
197	/// The list of supported versions in preferred order.
198	pub version: coding::Version,
199
200	/// Supported extensions.
201	pub parameters: Bytes,
202}
203
204impl Server {
205	fn encode_inner<W: bytes::BufMut>(&self, w: &mut W, v: Version) -> Result<(), EncodeError> {
206		match SetupVersion::from_version(v) {
207			SetupVersion::Draft15Plus => {
208				// Draft15+: No version field, parameters only.
209			}
210			SetupVersion::Draft14 | SetupVersion::LiteLegacy => self.version.encode(w, v)?,
211			SetupVersion::Modern | SetupVersion::Unsupported => return Err(EncodeError::Version),
212		};
213		if w.remaining_mut() < self.parameters.len() {
214			return Err(EncodeError::Short);
215		}
216		w.put_slice(&self.parameters);
217		Ok(())
218	}
219}
220
221impl Encode<Version> for Server {
222	/// Encode a server setup message (draft-14 through draft-16 only).
223	fn encode<W: bytes::BufMut>(&self, w: &mut W, v: Version) -> Result<(), EncodeError> {
224		SERVER_SETUP.encode(w, v)?;
225
226		let mut sizer = Sizer::default();
227		self.encode_inner(&mut sizer, v)?;
228		let size = sizer.size;
229
230		match SetupVersion::from_version(v) {
231			SetupVersion::Draft14 | SetupVersion::Draft15Plus => {
232				u16::try_from(size).map_err(|_| EncodeError::TooLarge)?.encode(w, v)?;
233			}
234			SetupVersion::LiteLegacy => (size as u64).encode(w, v)?,
235			SetupVersion::Modern | SetupVersion::Unsupported => return Err(EncodeError::Version),
236		}
237
238		self.encode_inner(w, v)
239	}
240}
241
242impl Decode<Version> for Server {
243	/// Decode a server setup message (draft-14 through draft-16 only).
244	fn decode<R: bytes::Buf>(r: &mut R, v: Version) -> Result<Self, DecodeError> {
245		let kind = u8::decode(r, v)?;
246		if kind != SERVER_SETUP {
247			return Err(DecodeError::InvalidValue);
248		}
249
250		let size = match SetupVersion::from_version(v) {
251			SetupVersion::Draft14 | SetupVersion::Draft15Plus => u16::decode(r, v)? as usize,
252			SetupVersion::LiteLegacy => u64::decode(r, v)? as usize,
253			SetupVersion::Modern | SetupVersion::Unsupported => return Err(DecodeError::Version),
254		};
255
256		if r.remaining() < size {
257			return Err(DecodeError::Short);
258		}
259
260		let mut msg = r.copy_to_bytes(size);
261		let version = match SetupVersion::from_version(v) {
262			SetupVersion::Draft15Plus => v.into(),
263			SetupVersion::Draft14 | SetupVersion::LiteLegacy => coding::Version::decode(&mut msg, v)?,
264			SetupVersion::Modern | SetupVersion::Unsupported => return Err(DecodeError::Version),
265		};
266
267		Ok(Self {
268			version,
269			parameters: msg,
270		})
271	}
272}