1use std::collections::VecDeque;
9use std::net::IpAddr;
10
11use sipx_media::Bridge;
12use sipx_sdp::Direction;
13use sipx_sip::{Method, Reason, Uri};
14use sipx_transport::Incoming;
15use tokio::sync::mpsc;
16
17use crate::call::{CouplingDialEvent, sleep_until};
18use crate::dispatch::CouplingInvitation;
19use crate::{Call, Calls, DialOptions, Dialing, Error, Invitation, Result, Ringing};
20
21const DEFERRED_CAPACITY: usize = 16;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum Leg {
26 One,
28 Two,
30}
31
32impl Leg {
33 const fn peer(self) -> Self {
34 match self {
35 Self::One => Self::Two,
36 Self::Two => Self::One,
37 }
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42struct PerLeg<T> {
43 one: T,
44 two: T,
45}
46
47impl<T> PerLeg<T> {
48 const fn new(one: T, two: T) -> Self {
49 Self { one, two }
50 }
51
52 const fn get(&self, leg: Leg) -> &T {
53 match leg {
54 Leg::One => &self.one,
55 Leg::Two => &self.two,
56 }
57 }
58
59 const fn get_mut(&mut self, leg: Leg) -> &mut T {
60 match leg {
61 Leg::One => &mut self.one,
62 Leg::Two => &mut self.two,
63 }
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub enum OfferAxis {
70 InitialInvite,
72 ReliableProvisional,
74 Prack,
76 Update,
78 Reinvite,
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
84pub enum OfferAction {
85 Relay {
87 source: Leg,
89 axis: OfferAxis,
91 },
92 Refuse {
94 status: u16,
96 },
97}
98
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100enum NegotiationState {
101 Idle,
102 Offering(OfferAxis),
103 Answering(OfferAxis),
104}
105
106impl NegotiationState {
107 const fn is_idle(self) -> bool {
108 matches!(self, Self::Idle)
109 }
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub enum CancelAction {
115 CancelPeer,
117 ByePeer,
119 AcknowledgeOnly,
121}
122
123#[derive(Debug, Clone, Copy, PartialEq, Eq)]
125pub enum FailureAction {
126 RejectPeer {
128 status: u16,
130 },
131 ByePeer,
133}
134
135#[derive(Debug)]
137pub struct CouplingState {
138 negotiation: PerLeg<NegotiationState>,
139 confirmed: PerLeg<bool>,
140}
141
142impl Default for CouplingState {
143 fn default() -> Self {
144 Self {
145 negotiation: PerLeg::new(NegotiationState::Idle, NegotiationState::Idle),
146 confirmed: PerLeg::new(false, false),
147 }
148 }
149}
150
151impl CouplingState {
152 #[must_use]
154 pub fn new() -> Self {
155 Self::default()
156 }
157
158 pub fn confirm(&mut self, leg: Leg) {
160 *self.confirmed.get_mut(leg) = true;
161 }
162
163 #[must_use]
165 pub fn is_confirmed(&self, leg: Leg) -> bool {
166 *self.confirmed.get(leg)
167 }
168
169 #[must_use]
175 pub fn begin_offer(&mut self, source: Leg, axis: OfferAxis) -> OfferAction {
176 let peer = source.peer();
177 match *self.negotiation.get(source) {
178 NegotiationState::Offering(_) => {
179 return OfferAction::Refuse { status: 491 };
180 }
181 NegotiationState::Answering(_) => return OfferAction::Refuse { status: 500 },
182 NegotiationState::Idle => {}
183 }
184 if !self.negotiation.get(peer).is_idle() {
185 return OfferAction::Refuse { status: 491 };
186 }
187 self.start(source, axis)
188 }
189
190 #[must_use]
194 pub fn complete(&mut self, source: Leg) -> bool {
195 if !self.matches_exchange(source) {
196 return false;
197 }
198 self.clear_exchange(source);
199 true
200 }
201
202 #[must_use]
207 pub fn fail(&mut self, source: Leg) -> bool {
208 self.complete(source)
209 }
210
211 #[must_use]
213 pub fn is_idle(&self) -> bool {
214 self.negotiation.one.is_idle() && self.negotiation.two.is_idle()
215 }
216
217 #[must_use]
219 pub fn cancel(&self, source: Leg) -> CancelAction {
220 match (self.is_confirmed(source), self.is_confirmed(source.peer())) {
221 (false, false) => CancelAction::CancelPeer,
222 (false, true) => CancelAction::ByePeer,
223 (true, _) => CancelAction::AcknowledgeOnly,
224 }
225 }
226
227 #[must_use]
229 pub fn final_failure(&self, source: Leg, status: u16) -> FailureAction {
230 if self.is_confirmed(source.peer()) {
231 FailureAction::ByePeer
232 } else {
233 FailureAction::RejectPeer { status }
234 }
235 }
236
237 fn start(&mut self, source: Leg, axis: OfferAxis) -> OfferAction {
238 let peer = source.peer();
239 *self.negotiation.get_mut(source) = NegotiationState::Answering(axis);
240 *self.negotiation.get_mut(peer) = NegotiationState::Offering(axis);
241 OfferAction::Relay { source, axis }
242 }
243
244 fn matches_exchange(&self, source: Leg) -> bool {
245 let peer = source.peer();
246 matches!(
247 (*self.negotiation.get(source), *self.negotiation.get(peer)),
248 (NegotiationState::Answering(one), NegotiationState::Offering(two)) if one == two
249 )
250 }
251
252 fn clear_exchange(&mut self, source: Leg) {
253 *self.negotiation.get_mut(source) = NegotiationState::Idle;
254 *self.negotiation.get_mut(source.peer()) = NegotiationState::Idle;
255 }
256}
257
258#[derive(Debug, Clone, Copy, PartialEq, Eq)]
260pub enum CouplingEnd {
261 Bye(Leg),
263 InboxClosed(Leg),
265}
266
267#[derive(Debug)]
269pub struct ConfirmedCoupling {
270 coupling: Coupling,
271 one_incoming: mpsc::Receiver<Incoming>,
272 two_incoming: mpsc::Receiver<Incoming>,
273}
274
275impl ConfirmedCoupling {
276 #[must_use]
278 pub fn into_parts(self) -> (Coupling, mpsc::Receiver<Incoming>, mpsc::Receiver<Incoming>) {
279 (self.coupling, self.one_incoming, self.two_incoming)
280 }
281}
282
283#[derive(Debug)]
285pub struct EarlyCoupling {
286 invitation: CouplingInvitation,
287 ringing: Ringing,
288 dialing: Option<Dialing>,
289 outgoing_incoming: mpsc::Receiver<Incoming>,
290 endpoint: sipx_transport::Handle,
291 media_address: IpAddr,
292 state: CouplingState,
293 deferred: PerLeg<VecDeque<Incoming>>,
294 delayed_offer_pending: bool,
295}
296
297async fn ring_source_leg(
298 endpoint: &sipx_transport::Handle,
299 incoming: &Incoming,
300 media_address: IpAddr,
301 delayed_direction: Option<Direction>,
302 answered_early: bool,
303) -> Result<Ringing> {
304 if let Some(direction) = delayed_direction {
305 crate::ring_offer_early(
306 endpoint,
307 incoming,
308 183,
309 "Session Progress",
310 media_address,
311 direction,
312 )
313 .await
314 } else if answered_early {
315 crate::ring_early(endpoint, incoming, 183, "Session Progress", media_address).await
316 } else {
317 crate::ring(endpoint, incoming, 180, "Ringing", true).await
318 }
319}
320
321fn outbound_failure_response(error: &Error) -> (u16, String) {
322 match error {
323 Error::Rejected { status, reason } => (*status, reason.clone()),
324 _ => (503, "Service Unavailable".to_owned()),
325 }
326}
327
328impl EarlyCoupling {
329 pub async fn dial(
335 invitation: Invitation,
336 calls: &Calls,
337 endpoint: &sipx_transport::Handle,
338 target: sipx_transport::Target,
339 to: &Uri,
340 options: &DialOptions,
341 media_address: IpAddr,
342 ) -> Result<Self> {
343 let source_offer = !invitation.request().request.body().is_empty();
344 let direction = relayed_direction(&invitation.request().request);
345 if source_offer && direction.is_none() {
346 invitation
347 .refuse(endpoint, 488, "Not Acceptable Here")
348 .await?;
349 return Err(Error::Sdp(
350 "the source initial INVITE carried no usable audio offer".to_owned(),
351 ));
352 }
353 let invitation = invitation.into_coupling();
354 let mut state = CouplingState::new();
355 if direction.is_some() {
356 let _relay = state.begin_offer(Leg::One, OfferAxis::InitialInvite);
357 }
358 let cancellation = invitation.cancellation();
359 let options = direction.map_or_else(
360 || options.clone(),
361 |direction| options.clone().with_initial_direction(direction),
362 );
363 let mut dialing = Box::pin(async {
364 match direction {
365 Some(_) => crate::dial_early(endpoint, target, to, &options)
366 .await
367 .map(|dialing| (dialing, None)),
368 None => {
369 crate::call::dial_early_without_offer_for_coupling(
370 endpoint, target, to, &options,
371 )
372 .await
373 }
374 }
375 });
376 let outbound = tokio::select! {
377 result = &mut dialing => match result {
378 Ok(outbound) => outbound,
379 Err(error) => {
380 let (status, reason) = outbound_failure_response(&error);
381 invitation.refuse(endpoint, status, reason).await?;
382 return Err(error);
383 }
384 },
385 () = cancellation.cancelled() => {
386 match dialing.await {
387 Ok((dialing, _)) => dialing.cancel().await,
388 Err(error) => tracing::debug!(%error, "outbound leg ended while cancellation waited for a provisional"),
389 }
390 return Err(Error::InvitationCancelled);
391 }
392 };
393 let (outbound, delayed_direction) = outbound;
394 let Some(dialog) = outbound.dialog() else {
395 let mut call = outbound.answered().await?;
396 call.hang_up().await?;
397 invitation
398 .refuse(endpoint, 503, "Service Unavailable")
399 .await?;
400 return Err(Error::NoDialog);
401 };
402 let outgoing_incoming = calls.register(dialog);
403 let answered_early = outbound.has_early_session();
404 if delayed_direction.is_some() {
405 let _relay = state.begin_offer(Leg::Two, OfferAxis::ReliableProvisional);
406 }
407 let ringing = ring_source_leg(
408 endpoint,
409 &invitation.incoming,
410 media_address,
411 delayed_direction,
412 answered_early,
413 )
414 .await;
415 let ringing = match ringing {
416 Ok(ringing) => ringing,
417 Err(error) => {
418 outbound.cancel().await;
419 let (status, reason) = outbound_failure_response(&error);
420 invitation.refuse(endpoint, status, reason).await?;
421 return Err(error);
422 }
423 };
424 if answered_early && ringing.has_early_session() {
425 let _completed = state.complete(Leg::One);
426 }
427 Ok(Self {
428 invitation,
429 ringing,
430 dialing: Some(outbound),
431 outgoing_incoming,
432 endpoint: endpoint.clone(),
433 media_address,
434 state,
435 deferred: PerLeg::new(VecDeque::new(), VecDeque::new()),
436 delayed_offer_pending: delayed_direction.is_some(),
437 })
438 }
439
440 #[must_use]
446 pub fn new(
447 invitation: Invitation,
448 ringing: Ringing,
449 dialing: Dialing,
450 outgoing_incoming: mpsc::Receiver<Incoming>,
451 endpoint: &sipx_transport::Handle,
452 media_address: IpAddr,
453 ) -> Self {
454 Self {
455 invitation: invitation.into_coupling(),
456 ringing,
457 dialing: Some(dialing),
458 outgoing_incoming,
459 endpoint: endpoint.clone(),
460 media_address,
461 state: CouplingState::new(),
462 deferred: PerLeg::new(VecDeque::new(), VecDeque::new()),
463 delayed_offer_pending: false,
464 }
465 }
466
467 #[must_use]
469 pub fn state(&self) -> &CouplingState {
470 &self.state
471 }
472
473 pub async fn confirmed(mut self) -> Result<ConfirmedCoupling> {
479 let cancellation = self.invitation.cancellation();
480 let mut outbound_call = None;
481
482 loop {
483 if outbound_call.is_some()
484 && (!self.ringing.has_early_session() || self.ringing.is_acknowledged())
485 {
486 return Box::pin(self.finish_confirmation(outbound_call.take())).await;
487 }
488 if let Some(request) = self.deferred.one.pop_front() {
489 self.handle_early_request(Leg::One, request, &mut outbound_call)
490 .await?;
491 continue;
492 }
493 if let Some(request) = self.deferred.two.pop_front() {
494 self.handle_early_request(Leg::Two, request, &mut outbound_call)
495 .await?;
496 continue;
497 }
498
499 tokio::select! {
500 () = cancellation.cancelled() => {
501 match self.state.cancel(Leg::One) {
502 CancelAction::CancelPeer => {
503 if let Some(dialing) = self.dialing.take() {
504 dialing.cancel().await;
505 }
506 }
507 CancelAction::ByePeer => {
508 if let Some(mut call) = outbound_call {
509 call.hang_up().await?;
510 }
511 }
512 CancelAction::AcknowledgeOnly => {}
513 }
514 return Err(Error::InvitationCancelled);
515 }
516 request = self.invitation.requests.recv() => {
517 let Some(request) = request else {
518 if let Some(mut call) = outbound_call {
519 call.hang_up().await?;
520 } else if let Some(dialing) = self.dialing.take() {
521 dialing.cancel().await;
522 }
523 return Err(Error::InvitationCancelled);
524 };
525 self.handle_early_request(Leg::One, request, &mut outbound_call).await?;
526 }
527 step = async {
528 if outbound_call.is_some() {
529 return Ok(CouplingDialEvent::Incoming(Box::new(
530 self.outgoing_incoming.recv().await,
531 )));
532 }
533 let Some(dialing) = self.dialing.as_mut() else {
534 return std::future::pending::<Result<CouplingDialEvent>>().await;
535 };
536 dialing.coupling_step(&mut self.outgoing_incoming).await
537 } => {
538 self.handle_dial_event(step, &mut outbound_call).await?;
539 }
540 }
541 }
542 }
543
544 async fn handle_dial_event(
545 &mut self,
546 event: Result<CouplingDialEvent>,
547 outbound_call: &mut Option<Call>,
548 ) -> Result<()> {
549 match event {
550 Ok(CouplingDialEvent::Progress) => Ok(()),
551 Ok(CouplingDialEvent::ReliableOffer(direction)) => {
552 match self
553 .state
554 .begin_offer(Leg::Two, OfferAxis::ReliableProvisional)
555 {
556 OfferAction::Relay { .. } => {}
557 OfferAction::Refuse { .. } => return Err(Error::NoDialog),
558 }
559 let ringing = crate::ring_offer_early(
560 &self.endpoint,
561 &self.invitation.incoming,
562 183,
563 "Session Progress",
564 self.media_address,
565 direction,
566 )
567 .await?;
568 self.ringing = ringing;
569 self.delayed_offer_pending = true;
570 Ok(())
571 }
572 Ok(CouplingDialEvent::Answered(call)) => {
573 self.state.confirm(Leg::Two);
574 *outbound_call = Some(*call);
575 self.dialing = None;
576 Ok(())
577 }
578 Ok(CouplingDialEvent::Incoming(request)) => {
579 let Some(request) = *request else {
580 if let Some(mut call) = outbound_call.take() {
581 if let Err(error) = call.hang_up().await {
586 tracing::warn!(%error, "could not hang up an orphaned coupled call");
587 }
588 } else if let Some(dialing) = self.dialing.take() {
589 dialing.cancel().await;
590 }
591 self.invitation
592 .refuse(&self.endpoint, 503, "Service Unavailable")
593 .await?;
594 return Err(Error::NoResponse);
595 };
596 if request.request.method != Method::Bye {
597 return self
598 .handle_early_request(Leg::Two, request, outbound_call)
599 .await;
600 }
601 let Some(call) = outbound_call.as_mut() else {
602 return Ok(());
603 };
604 if call.handle(&request).await? && call.is_ended() {
605 self.invitation
606 .refuse(&self.endpoint, 487, "Request Terminated")
607 .await?;
608 return Err(Error::Rejected {
609 status: 487,
610 reason: "Request Terminated".to_owned(),
611 });
612 }
613 Ok(())
614 }
615 Err(Error::Rejected { status, reason }) => {
616 self.dialing = None;
617 self.invitation
618 .refuse(&self.endpoint, status, reason.clone())
619 .await?;
620 Err(Error::Rejected { status, reason })
621 }
622 Err(error) => {
623 self.dialing = None;
624 self.invitation
625 .refuse(&self.endpoint, 503, "Service Unavailable")
626 .await?;
627 Err(error)
628 }
629 }
630 }
631
632 async fn finish_confirmation(self, outbound: Option<Call>) -> Result<ConfirmedCoupling> {
633 let Some(mut outbound) = outbound else {
634 return Err(Error::NoResponse);
635 };
636 if let Err(error) = self.invitation.claim() {
637 outbound.hang_up().await?;
638 return Err(error);
639 }
640 let inbound = if self.ringing.has_early_session() {
641 let mut ringing = self.ringing;
642 crate::answer_early(&self.endpoint, &self.invitation.incoming, &mut ringing).await
643 } else {
644 crate::answer_ringing(
645 &self.endpoint,
646 &self.invitation.incoming,
647 self.media_address,
648 &self.ringing,
649 )
650 .await
651 };
652 let inbound = match inbound {
653 Ok(inbound) => inbound,
654 Err(error) => {
655 if let Err(cleanup) = outbound.hang_up().await {
658 tracing::warn!(%cleanup, "could not end confirmed peer after inbound answer failed");
659 }
660 return Err(error);
661 }
662 };
663 Ok(ConfirmedCoupling {
664 coupling: Coupling::new(inbound, outbound),
665 one_incoming: self.invitation.requests,
666 two_incoming: self.outgoing_incoming,
667 })
668 }
669
670 async fn handle_early_request(
671 &mut self,
672 leg: Leg,
673 incoming: Incoming,
674 outbound_call: &mut Option<Call>,
675 ) -> Result<()> {
676 if leg == Leg::One && incoming.request.method == Method::Prack {
677 let matched = match self.ringing.on_prack(&incoming).await {
678 Ok(matched) => matched,
679 Err(error) => {
680 if self.delayed_offer_pending {
681 let _failed = self.state.fail(Leg::Two);
682 if let Some(dialing) = self.dialing.take() {
683 dialing.cancel().await;
684 }
685 self.invitation
686 .refuse(&self.endpoint, 488, "Not Acceptable Here")
687 .await?;
688 }
689 return Err(error);
690 }
691 };
692 if matched && self.delayed_offer_pending {
693 let Some(dialing) = self.dialing.as_mut() else {
694 return Err(Error::NoDialog);
695 };
696 if let Err(error) = dialing.complete_coupled_prack().await {
697 let _failed = self.state.fail(Leg::Two);
698 if let Some(dialing) = self.dialing.take() {
699 dialing.cancel().await;
700 }
701 return Err(error);
702 }
703 self.delayed_offer_pending = false;
704 let _completed = self.state.complete(Leg::Two);
705 }
706 return Ok(());
707 }
708 if incoming.request.method != Method::Update {
709 Call::refuse_with(&self.endpoint, &incoming, 405, "Method Not Allowed").await?;
710 return Ok(());
711 }
712 if !crate::update::carries_offer(&incoming.request) {
713 return self
714 .handle_offerless_update(leg, &incoming, outbound_call)
715 .await;
716 }
717 self.handle_early_offer(leg, incoming, outbound_call).await
718 }
719
720 async fn handle_offerless_update(
721 &mut self,
722 leg: Leg,
723 incoming: &Incoming,
724 outbound_call: &mut Option<Call>,
725 ) -> Result<()> {
726 let handled = match leg {
727 Leg::One => self.ringing.on_update(incoming).await?,
728 Leg::Two => match outbound_call {
729 Some(call) => call.handle(incoming).await?,
730 None => match self.dialing.as_mut() {
731 Some(dialing) => dialing.on_update(incoming).await?,
732 None => false,
733 },
734 },
735 };
736 if !handled {
737 Call::refuse_with(&self.endpoint, incoming, 481, "No Dialog").await?;
738 }
739 Ok(())
740 }
741
742 async fn handle_early_offer(
743 &mut self,
744 leg: Leg,
745 incoming: Incoming,
746 outbound_call: &mut Option<Call>,
747 ) -> Result<()> {
748 let Some(direction) = relayed_direction(&incoming.request) else {
749 return Call::refuse_with(&self.endpoint, &incoming, 488, "Not Acceptable Here").await;
750 };
751 match self.state.begin_offer(leg, OfferAxis::Update) {
752 OfferAction::Refuse { status } => {
753 let reason = if status == 491 {
754 "Request Pending"
755 } else {
756 "Server Internal Error"
757 };
758 return Call::refuse_with(&self.endpoint, &incoming, status, reason).await;
759 }
760 OfferAction::Relay { .. } => {}
761 }
762
763 let (relayed, inbox_closed) = match leg {
764 Leg::One => match outbound_call {
765 Some(call) => {
766 drive_early_outgoing_offer(
767 call.update(direction),
768 &mut self.state,
769 Leg::Two,
770 &mut self.outgoing_incoming,
771 &mut self.deferred.two,
772 &self.endpoint,
773 )
774 .await?
775 }
776 None => match self.dialing.as_mut() {
777 Some(dialing) => {
778 drive_early_outgoing_offer(
779 dialing.update(direction),
780 &mut self.state,
781 Leg::Two,
782 &mut self.outgoing_incoming,
783 &mut self.deferred.two,
784 &self.endpoint,
785 )
786 .await?
787 }
788 None => (Err(Error::NoDialog), false),
789 },
790 },
791 Leg::Two => {
792 drive_early_outgoing_offer(
793 self.ringing.update(direction),
794 &mut self.state,
795 Leg::One,
796 &mut self.invitation.requests,
797 &mut self.deferred.one,
798 &self.endpoint,
799 )
800 .await?
801 }
802 };
803 if let Err(error) = relayed {
804 let _settled = self.state.fail(leg);
805 if let Error::Rejected { status, reason } = error {
806 return Call::refuse_with(&self.endpoint, &incoming, status, reason).await;
807 }
808 return Err(error);
809 }
810
811 let handled = match leg {
812 Leg::One => self.ringing.on_update(&incoming).await,
813 Leg::Two => match outbound_call {
814 Some(call) => call.handle(&incoming).await,
815 None => match self.dialing.as_mut() {
816 Some(dialing) => dialing.on_update(&incoming).await,
817 None => Err(Error::NoDialog),
818 },
819 },
820 };
821 let _settled = match &handled {
822 Ok(_) => self.state.complete(leg),
823 Err(_) => self.state.fail(leg),
824 };
825 if !handled? {
826 Call::refuse_with(&self.endpoint, &incoming, 481, "No Dialog").await?;
827 }
828 if inbox_closed {
829 return Err(Error::NoResponse);
830 }
831 Ok(())
832 }
833}
834
835async fn drive_early_outgoing_offer<F>(
836 outgoing: F,
837 state: &mut CouplingState,
838 far_leg: Leg,
839 incoming: &mut mpsc::Receiver<Incoming>,
840 deferred: &mut VecDeque<Incoming>,
841 responder: &sipx_transport::Handle,
842) -> Result<(Result<()>, bool)>
843where
844 F: std::future::Future<Output = Result<()>>,
845{
846 tokio::pin!(outgoing);
847 let mut inbox_closed = false;
848 loop {
849 tokio::select! {
850 biased;
851 received = incoming.recv(), if !inbox_closed && deferred.len() < DEFERRED_CAPACITY => {
852 let Some(request) = received else {
853 inbox_closed = true;
854 continue;
855 };
856 let Some(axis) = offer_axis(&request) else {
857 deferred.push_back(request);
858 continue;
859 };
860 match state.begin_offer(far_leg, axis) {
861 OfferAction::Refuse { status } => {
862 let reason = if status == 491 {
863 "Request Pending"
864 } else {
865 "Server Internal Error"
866 };
867 Call::refuse_with(responder, &request, status, reason).await?;
868 }
869 OfferAction::Relay { .. } => deferred.push_back(request),
870 }
871 }
872 result = &mut outgoing => return Ok((result, inbox_closed)),
873 }
874 }
875}
876
877#[derive(Debug)]
879pub struct Coupling {
880 bridge: Option<Bridge>,
882 one: Call,
883 two: Call,
884 state: CouplingState,
885 deferred: PerLeg<VecDeque<Incoming>>,
886}
887
888impl Coupling {
889 #[must_use]
891 pub fn new(one: Call, two: Call) -> Self {
892 let mut state = CouplingState::new();
893 state.confirm(Leg::One);
894 state.confirm(Leg::Two);
895 Self {
896 bridge: None,
897 one,
898 two,
899 state,
900 deferred: PerLeg::new(VecDeque::new(), VecDeque::new()),
901 }
902 }
903
904 pub fn bridge_media(&mut self) -> bool {
909 let bridge = Bridge::connect(self.one.media_handle(), self.two.media_handle());
910 let transcoding = bridge.is_transcoding();
911 self.bridge = Some(bridge);
912 transcoding
913 }
914
915 #[must_use]
917 pub fn has_media_bridge(&self) -> bool {
918 self.bridge.is_some()
919 }
920
921 #[must_use]
923 pub fn state(&self) -> &CouplingState {
924 &self.state
925 }
926
927 pub fn state_mut(&mut self) -> &mut CouplingState {
929 &mut self.state
930 }
931
932 #[must_use]
934 pub fn calls(&self) -> (&Call, &Call) {
935 (&self.one, &self.two)
936 }
937
938 pub async fn run(
944 &mut self,
945 one_incoming: &mut mpsc::Receiver<Incoming>,
946 two_incoming: &mut mpsc::Receiver<Incoming>,
947 ) -> Result<CouplingEnd> {
948 loop {
949 if let Some(incoming) = self.deferred.one.pop_front() {
950 if let Some(end) = self
951 .handle(Leg::One, incoming, one_incoming, two_incoming)
952 .await?
953 {
954 return Ok(end);
955 }
956 continue;
957 }
958 if let Some(incoming) = self.deferred.two.pop_front() {
959 if let Some(end) = self
960 .handle(Leg::Two, incoming, one_incoming, two_incoming)
961 .await?
962 {
963 return Ok(end);
964 }
965 continue;
966 }
967 let one_deadline = self.one.session_deadline();
968 let two_deadline = self.two.session_deadline();
969 tokio::select! {
970 incoming = one_incoming.recv() => {
971 let Some(incoming) = incoming else {
972 self.two.hang_up().await?;
973 return Ok(CouplingEnd::InboxClosed(Leg::One));
974 };
975 if let Some(end) = self
976 .handle(Leg::One, incoming, one_incoming, two_incoming)
977 .await?
978 {
979 return Ok(end);
980 }
981 }
982 incoming = two_incoming.recv() => {
983 let Some(incoming) = incoming else {
984 self.one.hang_up().await?;
985 return Ok(CouplingEnd::InboxClosed(Leg::Two));
986 };
987 if let Some(end) = self
988 .handle(Leg::Two, incoming, one_incoming, two_incoming)
989 .await?
990 {
991 return Ok(end);
992 }
993 }
994 () = sleep_until(one_deadline) => {
995 if let Err(error) = self.one.on_session_deadline().await {
996 if self.one.is_ended() {
997 if let Err(cleanup_error) = self.two.hang_up().await {
1001 tracing::warn!(%cleanup_error, "could not clean up coupled peer");
1002 }
1003 }
1004 return Err(error);
1005 }
1006 }
1007 () = sleep_until(two_deadline) => {
1008 if let Err(error) = self.two.on_session_deadline().await {
1009 if self.two.is_ended() {
1010 if let Err(cleanup_error) = self.one.hang_up().await {
1014 tracing::warn!(%cleanup_error, "could not clean up coupled peer");
1015 }
1016 }
1017 return Err(error);
1018 }
1019 }
1020 }
1021 }
1022 }
1023
1024 async fn handle(
1025 &mut self,
1026 leg: Leg,
1027 incoming: Incoming,
1028 one_incoming: &mut mpsc::Receiver<Incoming>,
1029 two_incoming: &mut mpsc::Receiver<Incoming>,
1030 ) -> Result<Option<CouplingEnd>> {
1031 let is_bye = incoming.request.method == Method::Bye;
1032 if let Some(axis) = offer_axis(&incoming) {
1033 return self
1034 .relay_offer(leg, axis, incoming, one_incoming, two_incoming)
1035 .await;
1036 }
1037 let reason = incoming
1038 .request
1039 .headers
1040 .typed::<Reason>()
1041 .and_then(std::result::Result::ok)
1042 .and_then(|reason| reason.0.into_iter().next());
1043 let (call, peer) = match leg {
1044 Leg::One => (&mut self.one, &mut self.two),
1045 Leg::Two => (&mut self.two, &mut self.one),
1046 };
1047 if !call.handle(&incoming).await? {
1048 call.refuse_unclaimed(&incoming).await;
1049 return Ok(None);
1050 }
1051 if !is_bye || !call.is_ended() {
1052 return Ok(None);
1053 }
1054 match reason {
1055 Some(reason) => peer.hang_up_with_reason(reason).await?,
1056 None => peer.hang_up().await?,
1057 }
1058 Ok(Some(CouplingEnd::Bye(leg)))
1059 }
1060
1061 async fn relay_offer(
1062 &mut self,
1063 leg: Leg,
1064 axis: OfferAxis,
1065 incoming: Incoming,
1066 one_incoming: &mut mpsc::Receiver<Incoming>,
1067 two_incoming: &mut mpsc::Receiver<Incoming>,
1068 ) -> Result<Option<CouplingEnd>> {
1069 let source = self.call(leg);
1070 if !source.dialog.matches(&incoming.request) {
1071 source.refuse_unclaimed(&incoming).await;
1072 return Ok(None);
1073 }
1074 if source.dialog.is_out_of_order(&incoming.request) {
1075 source
1076 .refuse(&incoming, 500, "Server Internal Error")
1077 .await?;
1078 return Ok(None);
1079 }
1080 let Some(direction) = source.can_accept_offer(incoming.request.body()) else {
1081 source.refuse(&incoming, 488, "Not Acceptable Here").await?;
1082 return Ok(None);
1083 };
1084 match self.state.begin_offer(leg, axis) {
1085 OfferAction::Refuse { status } => {
1086 let reason = if status == 491 {
1087 "Request Pending"
1088 } else {
1089 "Server Internal Error"
1090 };
1091 self.call(leg).refuse(&incoming, status, reason).await?;
1092 return Ok(None);
1093 }
1094 OfferAction::Relay { .. } => {}
1095 }
1096
1097 let (relayed, inbox_closed) = match leg {
1098 Leg::One => {
1099 drive_outgoing_offer(
1100 &mut self.two,
1101 &mut self.state,
1102 Leg::Two,
1103 axis,
1104 direction,
1105 two_incoming,
1106 &mut self.deferred.two,
1107 )
1108 .await?
1109 }
1110 Leg::Two => {
1111 drive_outgoing_offer(
1112 &mut self.one,
1113 &mut self.state,
1114 Leg::One,
1115 axis,
1116 direction,
1117 one_incoming,
1118 &mut self.deferred.one,
1119 )
1120 .await?
1121 }
1122 };
1123
1124 if let Err(error) = relayed {
1125 let _settled = self.state.fail(leg);
1126 if let Error::Rejected { status, reason } = error {
1127 self.call(leg).refuse(&incoming, status, reason).await?;
1128 return Ok(None);
1129 }
1130 return Err(error);
1131 }
1132
1133 let handled = match leg {
1134 Leg::One => self.one.handle(&incoming).await,
1135 Leg::Two => self.two.handle(&incoming).await,
1136 };
1137 let _settled = match &handled {
1138 Ok(_) => self.state.complete(leg),
1139 Err(_) => self.state.fail(leg),
1140 };
1141 let handled = handled?;
1142 if !handled {
1143 self.call(leg).refuse_unclaimed(&incoming).await;
1144 }
1145 if self.bridge.is_some() {
1146 self.bridge_media();
1147 }
1148 if inbox_closed {
1149 self.call_mut(leg).hang_up().await?;
1150 return Ok(Some(CouplingEnd::InboxClosed(leg.peer())));
1151 }
1152 Ok(None)
1153 }
1154
1155 fn call(&self, leg: Leg) -> &Call {
1156 match leg {
1157 Leg::One => &self.one,
1158 Leg::Two => &self.two,
1159 }
1160 }
1161
1162 fn call_mut(&mut self, leg: Leg) -> &mut Call {
1163 match leg {
1164 Leg::One => &mut self.one,
1165 Leg::Two => &mut self.two,
1166 }
1167 }
1168}
1169
1170async fn drive_outgoing_offer(
1177 far: &mut Call,
1178 state: &mut CouplingState,
1179 far_leg: Leg,
1180 axis: OfferAxis,
1181 direction: Direction,
1182 incoming: &mut mpsc::Receiver<Incoming>,
1183 deferred: &mut VecDeque<Incoming>,
1184) -> Result<(Result<()>, bool)> {
1185 let responder = far.responder();
1186 let outgoing = async {
1187 if axis == OfferAxis::Update {
1188 far.update(direction).await
1189 } else {
1190 far.reinvite(direction).await
1191 }
1192 };
1193 tokio::pin!(outgoing);
1194 let mut inbox_closed = false;
1195
1196 loop {
1197 tokio::select! {
1198 biased;
1199 received = incoming.recv(), if !inbox_closed && deferred.len() < DEFERRED_CAPACITY => {
1200 let Some(request) = received else {
1201 inbox_closed = true;
1202 continue;
1203 };
1204 let Some(incoming_axis) = offer_axis(&request) else {
1205 deferred.push_back(request);
1206 continue;
1207 };
1208 match state.begin_offer(far_leg, incoming_axis) {
1209 OfferAction::Refuse { status } => {
1210 let reason = if status == 491 {
1211 "Request Pending"
1212 } else {
1213 "Server Internal Error"
1214 };
1215 Call::refuse_with(&responder, &request, status, reason).await?;
1216 }
1217 OfferAction::Relay { .. } => deferred.push_back(request),
1218 }
1219 }
1220 result = &mut outgoing => return Ok((result, inbox_closed)),
1221 }
1222 }
1223}
1224
1225fn offer_axis(incoming: &Incoming) -> Option<OfferAxis> {
1226 if !crate::update::carries_offer(&incoming.request) {
1227 return None;
1228 }
1229 match incoming.request.method {
1230 Method::Invite => Some(OfferAxis::Reinvite),
1231 Method::Update => Some(OfferAxis::Update),
1232 _ => None,
1233 }
1234}
1235
1236fn relayed_direction(request: &sipx_sip::Request) -> Option<Direction> {
1237 sipx_sdp::parse(&String::from_utf8_lossy(request.body()))
1238 .ok()
1239 .and_then(|description| {
1240 description
1241 .media
1242 .into_iter()
1243 .find(|media| media.media == "audio" && !media.is_rejected())
1244 .map(|media| media.direction())
1245 })
1246}
1247
1248#[cfg(test)]
1249#[allow(
1250 clippy::unwrap_used,
1251 clippy::expect_used,
1252 clippy::panic,
1253 clippy::indexing_slicing
1254)]
1255mod tests {
1256 use super::*;
1257
1258 fn request_with(body: &'static [u8]) -> sipx_sip::Request {
1259 let host = sipx_sip::HostName::new("callee.example").expect("valid host");
1260 let mut request =
1261 sipx_sip::Request::new(Method::Invite, Uri::sip(sipx_sip::Host::Name(host)));
1262 request.set_body(bytes::Bytes::from_static(body));
1263 request
1264 }
1265
1266 #[test]
1267 fn malformed_sdp_has_no_relay_direction() {
1268 assert_eq!(
1269 relayed_direction(&request_with(b"not a session description")),
1270 None
1271 );
1272 }
1273
1274 #[test]
1275 fn relay_preserves_endpoint_relative_direction() {
1276 let request = request_with(
1277 b"v=0\r\no=- 1 1 IN IP4 127.0.0.1\r\ns=-\r\nc=IN IP4 127.0.0.1\r\nt=0 0\r\nm=audio 4000 RTP/AVP 0\r\na=sendonly\r\n",
1278 );
1279 assert_eq!(relayed_direction(&request), Some(Direction::SendOnly));
1280 }
1281
1282 #[test]
1283 fn every_offer_axis_uses_two_per_leg_states_and_returns_to_idle() {
1284 for axis in [
1285 OfferAxis::InitialInvite,
1286 OfferAxis::ReliableProvisional,
1287 OfferAxis::Prack,
1288 OfferAxis::Update,
1289 OfferAxis::Reinvite,
1290 ] {
1291 let mut state = CouplingState::new();
1292 assert_eq!(
1293 state.begin_offer(Leg::One, axis),
1294 OfferAction::Relay {
1295 source: Leg::One,
1296 axis
1297 }
1298 );
1299 assert!(!state.is_idle());
1300 assert!(state.complete(Leg::One));
1301 assert!(state.is_idle());
1302 }
1303 }
1304
1305 #[test]
1306 fn glare_is_refused_and_a_new_retry_is_accepted_after_completion() {
1307 let mut state = CouplingState::new();
1308 assert!(matches!(
1309 state.begin_offer(Leg::One, OfferAxis::Reinvite),
1310 OfferAction::Relay { .. }
1311 ));
1312 assert_eq!(
1313 state.begin_offer(Leg::Two, OfferAxis::Update),
1314 OfferAction::Refuse { status: 491 }
1315 );
1316 assert_eq!(
1317 state.begin_offer(Leg::Two, OfferAxis::Prack),
1318 OfferAction::Refuse { status: 491 }
1319 );
1320 assert!(state.complete(Leg::One));
1321 assert_eq!(
1322 state.begin_offer(Leg::Two, OfferAxis::Update),
1323 OfferAction::Relay {
1324 source: Leg::Two,
1325 axis: OfferAxis::Update
1326 }
1327 );
1328 }
1329
1330 #[test]
1331 fn cancel_crosses_only_before_the_peer_is_confirmed() {
1332 let mut state = CouplingState::new();
1333 assert_eq!(state.cancel(Leg::One), CancelAction::CancelPeer);
1334 state.confirm(Leg::Two);
1335 assert_eq!(state.cancel(Leg::One), CancelAction::ByePeer);
1336 state.confirm(Leg::One);
1337 assert_eq!(state.cancel(Leg::One), CancelAction::AcknowledgeOnly);
1338 }
1339
1340 #[test]
1341 fn final_failure_preserves_status_until_the_peer_is_confirmed() {
1342 let mut state = CouplingState::new();
1343 assert_eq!(
1344 state.final_failure(Leg::Two, 486),
1345 FailureAction::RejectPeer { status: 486 }
1346 );
1347 assert_eq!(
1348 state.final_failure(Leg::Two, 503),
1349 FailureAction::RejectPeer { status: 503 }
1350 );
1351 state.confirm(Leg::One);
1352 assert_eq!(state.final_failure(Leg::Two, 486), FailureAction::ByePeer);
1353 }
1354}