1use alloc::boxed::Box;
11use alloc::collections::VecDeque;
12use alloc::vec;
13use alloc::vec::Vec;
14
15use crate::envelope::{Body, Envelope};
16use crate::error::Error;
17use crate::identity::{EndpointIdentity, EndpointSigner};
18use crate::types::{
19 AttemptId, CloseCode, EnvelopeId, FederationId, WebRtcBinding, MAX_SEEN_ENVELOPES, PROTOCOL_ID,
20};
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum Phase {
25 Idle,
27 OfferSent,
29 OfferReceived,
31 AnswerSent,
33 AnswerReceived,
35 Established,
37 Closed,
39}
40
41#[derive(Debug, Clone, Copy)]
42struct NegotiationIds {
43 offer: EnvelopeId,
44 answer: Option<EnvelopeId>,
45}
46
47#[derive(Debug, Clone, PartialEq, Eq)]
49pub enum Action {
50 Send(Box<Envelope>),
52 ApplyOffer {
54 binding: WebRtcBinding,
56 description: Vec<u8>,
58 },
59 ApplyAnswer {
61 binding: WebRtcBinding,
63 description: Vec<u8>,
65 },
66 AddCandidate {
68 sequence: u32,
70 candidate: Vec<u8>,
72 },
73 OpenControlChannel,
75 DeliverCfr {
77 envelope_id: EnvelopeId,
79 remote_endpoint: Box<EndpointIdentity>,
81 payload: Vec<u8>,
83 },
84 CloseTransport {
86 reason: CloseCode,
88 },
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub struct ControlChannelConfig {
94 pub label: &'static str,
96 pub protocol: &'static str,
98 pub ordered: bool,
100 pub reliable: bool,
102 pub binary: bool,
104}
105
106pub const CONTROL_CHANNEL: ControlChannelConfig = ControlChannelConfig {
108 label: "org.nixort.cfr.fcp.control/1",
109 protocol: PROTOCOL_ID,
110 ordered: true,
111 reliable: true,
112 binary: true,
113};
114
115#[derive(Debug)]
117pub struct Connection {
118 federation: FederationId,
119 attempt: AttemptId,
120 local: EndpointIdentity,
121 remote: EndpointIdentity,
122 phase: Phase,
123 negotiation: Option<NegotiationIds>,
124 seen: VecDeque<EnvelopeId>,
125}
126
127impl Connection {
128 pub fn new(
130 federation: FederationId,
131 attempt: AttemptId,
132 local: EndpointIdentity,
133 remote: EndpointIdentity,
134 ) -> Result<Self, Error> {
135 if local == remote {
136 return Err(Error::SameEndpoint);
137 }
138 Ok(Self {
139 federation,
140 attempt,
141 local,
142 remote,
143 phase: Phase::Idle,
144 negotiation: None,
145 seen: VecDeque::new(),
146 })
147 }
148
149 pub const fn federation(&self) -> FederationId {
151 self.federation
152 }
153
154 pub const fn attempt(&self) -> AttemptId {
156 self.attempt
157 }
158
159 pub const fn local_endpoint(&self) -> EndpointIdentity {
161 self.local
162 }
163
164 pub const fn remote_endpoint(&self) -> EndpointIdentity {
166 self.remote
167 }
168
169 pub const fn phase(&self) -> Phase {
171 self.phase
172 }
173
174 pub fn begin_offer<S: EndpointSigner>(
176 &mut self,
177 signer: &S,
178 binding: WebRtcBinding,
179 description: Vec<u8>,
180 ) -> Result<Vec<Action>, Error> {
181 self.require_local_signer(signer)?;
182 if self.phase != Phase::Idle {
183 return Err(Error::InvalidState);
184 }
185 let offer = Envelope::sign(
186 signer,
187 self.federation,
188 self.attempt,
189 self.remote,
190 Body::Offer {
191 binding,
192 description,
193 },
194 )?;
195 self.negotiation = Some(NegotiationIds {
196 offer: offer.id()?,
197 answer: None,
198 });
199 self.phase = Phase::OfferSent;
200 Ok(vec![
201 Action::OpenControlChannel,
202 Action::Send(Box::new(offer)),
203 ])
204 }
205
206 pub fn answer<S: EndpointSigner>(
208 &mut self,
209 signer: &S,
210 binding: WebRtcBinding,
211 description: Vec<u8>,
212 ) -> Result<Action, Error> {
213 self.require_local_signer(signer)?;
214 if self.phase != Phase::OfferReceived {
215 return Err(Error::InvalidState);
216 }
217 let offer_id = self.negotiation.ok_or(Error::InvalidState)?.offer;
218 let answer = Envelope::sign(
219 signer,
220 self.federation,
221 self.attempt,
222 self.remote,
223 Body::Answer {
224 offer_id,
225 binding,
226 description,
227 },
228 )?;
229 self.negotiation = Some(NegotiationIds {
230 offer: offer_id,
231 answer: Some(answer.id()?),
232 });
233 self.phase = Phase::AnswerSent;
234 Ok(Action::Send(Box::new(answer)))
235 }
236
237 pub fn candidate<S: EndpointSigner>(
239 &self,
240 signer: &S,
241 sequence: u32,
242 candidate: Vec<u8>,
243 ) -> Result<Action, Error> {
244 self.require_local_signer(signer)?;
245 if !matches!(
246 self.phase,
247 Phase::OfferSent
248 | Phase::OfferReceived
249 | Phase::AnswerSent
250 | Phase::AnswerReceived
251 | Phase::Established
252 ) {
253 return Err(Error::InvalidState);
254 }
255 let ids = self.negotiation.ok_or(Error::InvalidState)?;
256 let parent_id = ids.answer.unwrap_or(ids.offer);
257 let envelope = Envelope::sign(
258 signer,
259 self.federation,
260 self.attempt,
261 self.remote,
262 Body::Candidate {
263 parent_id,
264 sequence,
265 candidate,
266 },
267 )?;
268 Ok(Action::Send(Box::new(envelope)))
269 }
270
271 pub fn cfr_control<S: EndpointSigner>(
273 &self,
274 signer: &S,
275 payload: Vec<u8>,
276 ) -> Result<Action, Error> {
277 self.require_local_signer(signer)?;
278 if self.phase != Phase::Established {
279 return Err(Error::InvalidState);
280 }
281 Ok(Action::Send(Box::new(Envelope::sign(
282 signer,
283 self.federation,
284 self.attempt,
285 self.remote,
286 Body::CfrControl { payload },
287 )?)))
288 }
289
290 pub fn close<S: EndpointSigner>(
292 &mut self,
293 signer: &S,
294 reason: CloseCode,
295 ) -> Result<Action, Error> {
296 self.require_local_signer(signer)?;
297 if matches!(self.phase, Phase::Idle | Phase::Closed) {
298 return Err(Error::InvalidState);
299 }
300 self.phase = Phase::Closed;
301 Ok(Action::Send(Box::new(Envelope::sign(
302 signer,
303 self.federation,
304 self.attempt,
305 self.remote,
306 Body::Close { reason },
307 )?)))
308 }
309
310 pub fn receive(&mut self, envelope: Envelope) -> Result<Vec<Action>, Error> {
312 self.validate_inbound(&envelope)?;
313 let id = envelope.id()?;
314 let remote_endpoint = envelope.sender;
315 if self.seen.iter().any(|known| known == &id) {
316 return Ok(Vec::new());
317 }
318 let actions = match envelope.body {
319 Body::Offer {
320 binding,
321 description,
322 } => {
323 if self.phase == Phase::OfferSent {
324 return Err(Error::Glare);
325 }
326 if self.phase != Phase::Idle {
327 return Err(Error::InvalidState);
328 }
329 self.negotiation = Some(NegotiationIds {
330 offer: id,
331 answer: None,
332 });
333 self.phase = Phase::OfferReceived;
334 vec![Action::ApplyOffer {
335 binding,
336 description,
337 }]
338 }
339 Body::Answer {
340 offer_id,
341 binding,
342 description,
343 } => {
344 if self.phase != Phase::OfferSent
345 || self.negotiation.ok_or(Error::InvalidState)?.offer != offer_id
346 {
347 return Err(Error::InvalidState);
348 }
349 let offer = self.negotiation.ok_or(Error::InvalidState)?.offer;
350 self.negotiation = Some(NegotiationIds {
351 offer,
352 answer: Some(id),
353 });
354 self.phase = Phase::AnswerReceived;
355 vec![Action::ApplyAnswer {
356 binding,
357 description,
358 }]
359 }
360 Body::Candidate {
361 parent_id,
362 sequence,
363 candidate,
364 } => {
365 self.validate_candidate_parent(parent_id)?;
366 vec![Action::AddCandidate {
367 sequence,
368 candidate,
369 }]
370 }
371 Body::Close { reason } => {
372 if matches!(self.phase, Phase::Idle | Phase::Closed) {
373 return Err(Error::InvalidState);
374 }
375 self.phase = Phase::Closed;
376 vec![Action::CloseTransport { reason }]
377 }
378 Body::CfrControl { payload } => {
379 if self.phase != Phase::Established {
380 return Err(Error::InvalidState);
381 }
382 vec![Action::DeliverCfr {
383 envelope_id: id,
384 remote_endpoint: Box::new(remote_endpoint),
385 payload,
386 }]
387 }
388 };
389 self.note_seen(id);
390 Ok(actions)
391 }
392
393 pub fn transport_connected(&mut self) -> Result<Vec<Action>, Error> {
395 if !matches!(self.phase, Phase::AnswerSent | Phase::AnswerReceived) {
396 return Err(Error::InvalidState);
397 }
398 self.phase = Phase::Established;
399 Ok(Vec::new())
400 }
401
402 pub fn transport_failed(&mut self) -> Result<(), Error> {
404 if matches!(self.phase, Phase::Idle | Phase::Closed) {
405 return Err(Error::InvalidState);
406 }
407 self.phase = Phase::Closed;
408 Ok(())
409 }
410
411 fn require_local_signer<S: EndpointSigner>(&self, signer: &S) -> Result<(), Error> {
412 if signer.endpoint() != self.local {
413 return Err(Error::WrongLocalSigner);
414 }
415 Ok(())
416 }
417
418 fn validate_inbound(&self, envelope: &Envelope) -> Result<(), Error> {
419 if envelope.federation != self.federation {
420 return Err(Error::WrongFederation);
421 }
422 if envelope.attempt != self.attempt {
423 return Err(Error::WrongAttempt);
424 }
425 if envelope.sender != self.remote {
426 return Err(Error::WrongSender);
427 }
428 if envelope.recipient != self.local {
429 return Err(Error::WrongRecipient);
430 }
431 envelope.verify()
432 }
433
434 fn validate_candidate_parent(&self, parent: EnvelopeId) -> Result<(), Error> {
435 let ids = self.negotiation.ok_or(Error::InvalidState)?;
436 if !matches!(
437 self.phase,
438 Phase::OfferSent
439 | Phase::OfferReceived
440 | Phase::AnswerSent
441 | Phase::AnswerReceived
442 | Phase::Established
443 ) {
444 return Err(Error::InvalidState);
445 }
446 if parent != ids.offer && ids.answer != Some(parent) {
447 return Err(Error::WrongCandidateParent);
448 }
449 Ok(())
450 }
451
452 fn note_seen(&mut self, id: EnvelopeId) {
453 if self.seen.len() == MAX_SEEN_ENVELOPES {
454 let _ = self.seen.pop_front();
455 }
456 self.seen.push_back(id);
457 }
458}