1use super::endpoint::EndpointInnerRef;
2use super::key::TransactionKey;
3use super::{SipConnection, TransactionState, TransactionTimer, TransactionType};
4use crate::dialog::DialogId;
5use crate::rsip;
6use crate::transaction::make_tag;
7use crate::transport::SipAddr;
8use crate::{Error, Result};
9use rsip::headers::ContentLength;
10use rsip::message::HasHeaders;
11use rsip::prelude::HeadersExt;
12use rsip::{Header, Method, Request, Response, SipMessage, StatusCode, StatusCodeKind};
13use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
14use tracing::{debug, info, trace};
15
16pub type TransactionEventReceiver = UnboundedReceiver<TransactionEvent>;
17pub type TransactionEventSender = UnboundedSender<TransactionEvent>;
18
19pub enum TransactionEvent {
56 Received(SipMessage, Option<SipConnection>),
57 Timer(TransactionTimer),
58 Respond(Response),
59 Terminate,
60}
61
62pub struct Transaction {
153 pub transaction_type: TransactionType,
154 pub key: TransactionKey,
155 pub original: Request,
156 pub destination: Option<SipAddr>,
157 pub state: TransactionState,
158 pub endpoint_inner: EndpointInnerRef,
159 pub connection: Option<SipConnection>,
160 pub last_response: Option<Response>,
161 pub last_ack: Option<Request>,
162 pub tu_receiver: TransactionEventReceiver,
163 pub tu_sender: TransactionEventSender,
164 pub timer_a: Option<u64>,
165 pub timer_b: Option<u64>,
166 pub timer_c: Option<u64>,
167 pub timer_d: Option<u64>,
168 pub timer_k: Option<u64>, pub timer_g: Option<u64>, is_cleaned_up: bool,
171}
172
173impl Transaction {
174 fn new(
175 transaction_type: TransactionType,
176 key: TransactionKey,
177 original: Request,
178 connection: Option<SipConnection>,
179 endpoint_inner: EndpointInnerRef,
180 ) -> Self {
181 let (tu_sender, tu_receiver) = unbounded_channel();
182 let state = if matches!(
183 transaction_type,
184 TransactionType::ServerInvite | TransactionType::ServerNonInvite
185 ) {
186 TransactionState::Trying
187 } else {
188 TransactionState::Nothing
189 };
190 trace!(%key, %state, "transaction created");
191 let tx = Self {
192 transaction_type,
193 endpoint_inner,
194 connection,
195 key,
196 original,
197 destination: None,
198 state,
199 last_response: None,
200 last_ack: None,
201 timer_a: None,
202 timer_b: None,
203 timer_c: None,
204 timer_d: None,
205 timer_k: None,
206 timer_g: None,
207 tu_receiver,
208 tu_sender,
209 is_cleaned_up: false,
210 };
211 tx.endpoint_inner
212 .attach_transaction(&tx.key, tx.tu_sender.clone());
213 tx
214 }
215
216 pub fn new_client(
217 key: TransactionKey,
218 original: Request,
219 endpoint_inner: EndpointInnerRef,
220 connection: Option<SipConnection>,
221 ) -> Self {
222 let tx_type = match original.method {
223 Method::Invite => TransactionType::ClientInvite,
224 _ => TransactionType::ClientNonInvite,
225 };
226 Transaction::new(tx_type, key, original, connection, endpoint_inner)
227 }
228
229 pub fn new_server(
230 key: TransactionKey,
231 original: Request,
232 endpoint_inner: EndpointInnerRef,
233 connection: Option<SipConnection>,
234 ) -> Self {
235 let tx_type = match original.method {
236 Method::Invite | Method::Ack => TransactionType::ServerInvite,
237 _ => TransactionType::ServerNonInvite,
238 };
239 Transaction::new(tx_type, key, original, connection, endpoint_inner)
240 }
241 pub async fn send(&mut self) -> Result<()> {
243 match self.transaction_type {
244 TransactionType::ClientInvite | TransactionType::ClientNonInvite => {}
245 _ => {
246 return Err(Error::TransactionError(
247 "send is only valid for client transactions".to_string(),
248 self.key.clone(),
249 ));
250 }
251 }
252 if self.connection.is_none() {
253 let target_uri = match &self.destination {
254 Some(addr) => addr,
255 None => &SipAddr::try_from(&self.original.uri)?,
256 };
257 let (connection, resolved_addr) = self
258 .endpoint_inner
259 .transport_layer
260 .lookup(target_uri, Some(&self.key))
261 .await?;
262 if !connection.is_reliable() {
264 self.destination.replace(resolved_addr);
265 }
266 self.connection.replace(connection);
267 }
268
269 let connection = self.connection.as_ref().ok_or(Error::TransactionError(
270 "no connection found".to_string(),
271 self.key.clone(),
272 ))?;
273 let content_length_header =
274 Header::ContentLength(ContentLength::from(self.original.body().len() as u32));
275 self.original
276 .headers_mut()
277 .unique_push(content_length_header);
278
279 let message = if let Some(ref inspector) = self.endpoint_inner.inspector {
280 inspector.before_send(self.original.to_owned().into())
281 } else {
282 self.original.to_owned().into()
283 };
284
285 connection.send(message, self.destination.as_ref()).await?;
286 self.transition(TransactionState::Calling).map(|_| ())
287 }
288
289 pub async fn reply_with(
290 &mut self,
291 status_code: StatusCode,
292 headers: Vec<rsip::Header>,
293 body: Option<Vec<u8>>,
294 ) -> Result<()> {
295 match status_code.kind() {
296 rsip::StatusCodeKind::Provisional => {}
297 _ => {
298 let to = self.original.to_header()?;
299 if to.tag()?.is_none() {
300 self.original
301 .headers
302 .unique_push(to.clone().with_tag(make_tag())?.into());
303 }
304 }
305 }
306 let mut resp = self
307 .endpoint_inner
308 .make_response(&self.original, status_code, body);
309 resp.headers.extend(headers);
310 self.respond(resp).await
311 }
312 pub async fn reply(&mut self, status_code: StatusCode) -> Result<()> {
314 self.reply_with(status_code, vec![], None).await
315 }
316 pub async fn respond(&mut self, response: Response) -> Result<()> {
318 match self.transaction_type {
319 TransactionType::ServerInvite | TransactionType::ServerNonInvite => {}
320 _ => {
321 return Err(Error::TransactionError(
322 "respond is only valid for server transactions".to_string(),
323 self.key.clone(),
324 ));
325 }
326 }
327
328 let new_state = match response.status_code.kind() {
329 rsip::StatusCodeKind::Provisional => match response.status_code {
330 rsip::StatusCode::Trying => TransactionState::Trying,
331 _ => TransactionState::Proceeding,
332 },
333 _ => match self.transaction_type {
334 TransactionType::ServerInvite => TransactionState::Completed,
335 _ => TransactionState::Terminated,
336 },
337 };
338 self.can_transition(&new_state)?;
340
341 let connection = self.connection.as_ref().ok_or(Error::TransactionError(
342 "no connection found".to_string(),
343 self.key.clone(),
344 ))?;
345
346 let response = if let Some(ref inspector) = self.endpoint_inner.inspector {
347 inspector.before_send(response.clone().to_owned().into())
348 } else {
349 response.to_owned().into()
350 };
351 trace!(key = %self.key, "responding with {}", response);
352
353 match response.clone() {
354 SipMessage::Response(resp) => self.last_response.replace(resp),
355 _ => None,
356 };
357 connection.send(response, self.destination.as_ref()).await?;
358 self.transition(new_state).map(|_| ())
359 }
360
361 fn can_transition(&self, target: &TransactionState) -> Result<()> {
362 match (&self.state, target) {
363 (&TransactionState::Nothing, &TransactionState::Calling)
364 | (&TransactionState::Nothing, &TransactionState::Trying)
365 | (&TransactionState::Nothing, &TransactionState::Proceeding)
366 | (&TransactionState::Nothing, &TransactionState::Terminated)
367 | (&TransactionState::Calling, &TransactionState::Trying)
368 | (&TransactionState::Calling, &TransactionState::Proceeding)
369 | (&TransactionState::Calling, &TransactionState::Completed)
370 | (&TransactionState::Calling, &TransactionState::Terminated)
371 | (&TransactionState::Trying, &TransactionState::Trying) | (&TransactionState::Trying, &TransactionState::Proceeding)
373 | (&TransactionState::Trying, &TransactionState::Completed)
374 | (&TransactionState::Trying, &TransactionState::Confirmed)
375 | (&TransactionState::Trying, &TransactionState::Terminated)
376 | (&TransactionState::Proceeding, &TransactionState::Completed)
377 | (&TransactionState::Proceeding, &TransactionState::Confirmed)
378 | (&TransactionState::Proceeding, &TransactionState::Terminated)
379 | (&TransactionState::Completed, &TransactionState::Confirmed)
380 | (&TransactionState::Completed, &TransactionState::Terminated)
381 | (&TransactionState::Confirmed, &TransactionState::Terminated) => Ok(()),
382 _ => {
383 Err(Error::TransactionError(
384 format!(
385 "invalid state transition from {} to {}",
386 self.state, target
387 ),
388 self.key.clone(),
389 ))
390 }
391 }
392 }
393 pub async fn send_cancel(&mut self, cancel: Request) -> Result<()> {
394 if self.transaction_type != TransactionType::ClientInvite {
395 return Err(Error::TransactionError(
396 "send_cancel is only valid for client invite transactions".to_string(),
397 self.key.clone(),
398 ));
399 }
400
401 match self.state {
402 TransactionState::Calling | TransactionState::Trying | TransactionState::Proceeding => {
403 if let Some(connection) = &self.connection {
404 let cancel = if let Some(ref inspector) = self.endpoint_inner.inspector {
405 inspector.before_send(cancel.to_owned().into())
406 } else {
407 cancel.to_owned().into()
408 };
409
410 connection.send(cancel, self.destination.as_ref()).await?;
411 }
412 self.transition(TransactionState::Completed).map(|_| ())
413 }
414 _ => Err(Error::TransactionError(
415 format!("invalid state for sending CANCEL {:?}", self.state),
416 self.key.clone(),
417 )),
418 }
419 }
420
421 pub async fn send_ack(&mut self, connection: Option<SipConnection>) -> Result<()> {
422 if self.transaction_type != TransactionType::ClientInvite {
423 return Err(Error::TransactionError(
424 "send_ack is only valid for client invite transactions".to_string(),
425 self.key.clone(),
426 ));
427 }
428
429 match self.state {
430 TransactionState::Completed => {} _ => {
432 return Err(Error::TransactionError(
433 format!("invalid state for sending ACK {:?}", self.state),
434 self.key.clone(),
435 ));
436 }
437 }
438 let ack = match self.last_ack.clone() {
439 Some(ack) => ack,
440 None => match self.last_response {
441 Some(ref resp) => self
442 .endpoint_inner
443 .make_ack(self.original.uri.clone(), resp)?,
444 None => {
445 return Err(Error::TransactionError(
446 "no last response found to send ACK".to_string(),
447 self.key.clone(),
448 ));
449 }
450 },
451 };
452
453 let ack = if let Some(ref inspector) = self.endpoint_inner.inspector {
454 inspector.before_send(ack.to_owned().into())
455 } else {
456 ack.to_owned().into()
457 };
458 match ack.clone() {
459 SipMessage::Request(ack) => self.last_ack.replace(ack),
460 _ => None,
461 };
462 if let Some(conn) = connection {
463 conn.send(ack, self.destination.as_ref()).await?;
464 }
465 self.transition(TransactionState::Terminated).map(|_| ())
467 }
468
469 pub async fn receive(&mut self) -> Option<SipMessage> {
470 while let Some(event) = self.tu_receiver.recv().await {
471 match event {
472 TransactionEvent::Received(msg, connection) => {
473 if let Some(msg) = match msg {
474 SipMessage::Request(req) => self.on_received_request(req, connection).await,
475 SipMessage::Response(resp) => {
476 self.on_received_response(resp, connection).await
477 }
478 } {
479 if let Some(ref inspector) = self.endpoint_inner.inspector {
480 return Some(inspector.after_received(msg));
481 }
482 return Some(msg);
483 }
484 }
485 TransactionEvent::Timer(t) => {
486 self.on_timer(t).await.ok();
487 }
488 TransactionEvent::Respond(response) => {
489 self.respond(response).await.ok();
490 }
491 TransactionEvent::Terminate => {
492 info!("received terminate event");
493 return None;
494 }
495 }
496 }
497 None
498 }
499
500 pub async fn send_trying(&mut self) -> Result<()> {
501 let response =
502 self.endpoint_inner
503 .make_response(&self.original, rsip::StatusCode::Trying, None);
504 self.respond(response).await
505 }
506
507 pub fn is_terminated(&self) -> bool {
508 self.state == TransactionState::Terminated
509 }
510}
511
512impl Transaction {
513 fn inform_tu_response(&mut self, response: Response) -> Result<()> {
514 self.tu_sender
515 .send(TransactionEvent::Received(
516 SipMessage::Response(response),
517 None,
518 ))
519 .map_err(|e| Error::TransactionError(e.to_string(), self.key.clone()))
520 }
521
522 async fn on_received_request(
523 &mut self,
524 req: Request,
525 connection: Option<SipConnection>,
526 ) -> Option<SipMessage> {
527 match self.transaction_type {
528 TransactionType::ClientInvite | TransactionType::ClientNonInvite => return None,
529 _ => {}
530 }
531
532 if self.connection.is_none() && connection.is_some() {
533 self.connection = connection;
534 }
535 if req.method == Method::Cancel {
536 match self.state {
537 TransactionState::Proceeding
538 | TransactionState::Trying
539 | TransactionState::Completed => {
540 if let Some(connection) = &self.connection {
541 let resp = self
542 .endpoint_inner
543 .make_response(&req, StatusCode::OK, None);
544
545 let resp = if let Some(ref inspector) = self.endpoint_inner.inspector {
546 inspector.before_send(resp.into())
547 } else {
548 resp.into()
549 };
550
551 connection.send(resp, self.destination.as_ref()).await.ok();
552 }
553 return Some(req.into()); }
555 _ => {
556 if let Some(connection) = &self.connection {
557 let resp = self.endpoint_inner.make_response(
558 &req,
559 StatusCode::CallTransactionDoesNotExist,
560 None,
561 );
562 let resp = if let Some(ref inspector) = self.endpoint_inner.inspector {
563 inspector.before_send(resp.into())
564 } else {
565 resp.into()
566 };
567 connection.send(resp, self.destination.as_ref()).await.ok();
568 }
569 }
570 };
571 return None;
572 }
573
574 match self.state {
575 TransactionState::Trying | TransactionState::Proceeding => {
576 if let Some(last_response) = &self.last_response {
578 self.respond(last_response.to_owned()).await.ok();
579 }
580 }
581 TransactionState::Completed | TransactionState::Confirmed => {
582 if req.method == Method::Ack {
583 self.transition(TransactionState::Confirmed).ok();
584 return Some(req.into());
585 }
586 }
587 _ => {}
588 }
589 None
590 }
591
592 async fn on_received_response(
593 &mut self,
594 resp: Response,
595 connection: Option<SipConnection>,
596 ) -> Option<SipMessage> {
597 match self.transaction_type {
598 TransactionType::ServerInvite | TransactionType::ServerNonInvite => return None,
599 _ => {}
600 }
601 let new_state = match resp.status_code.kind() {
602 StatusCodeKind::Provisional => {
603 if resp.status_code == rsip::StatusCode::Trying {
604 TransactionState::Trying
605 } else {
606 TransactionState::Proceeding
607 }
608 }
609 _ => {
610 if self.transaction_type == TransactionType::ClientInvite {
611 TransactionState::Completed
612 } else {
613 TransactionState::Terminated
614 }
615 }
616 };
617
618 self.can_transition(&new_state).ok()?;
619 if self.state == new_state {
620 return None;
622 }
623
624 self.last_response.replace(resp.clone());
625 self.transition(new_state).ok();
626 self.send_ack(connection).await.ok(); Some(SipMessage::Response(resp))
628 }
629
630 async fn on_timer(&mut self, timer: TransactionTimer) -> Result<()> {
631 match self.state {
632 TransactionState::Calling | TransactionState::Trying => {
633 if matches!(
634 self.transaction_type,
635 TransactionType::ClientInvite | TransactionType::ClientNonInvite
636 ) {
637 if let TransactionTimer::TimerA(key, duration) = timer {
638 if let Some(connection) = &self.connection {
640 let retry_message =
641 if let Some(ref inspector) = self.endpoint_inner.inspector {
642 inspector.before_send(self.original.to_owned().into())
643 } else {
644 self.original.to_owned().into()
645 };
646 connection
647 .send(retry_message, self.destination.as_ref())
648 .await?;
649 }
650 let duration = (duration * 2).min(self.endpoint_inner.option.t1x64);
652 let timer_a = self
653 .endpoint_inner
654 .timers
655 .timeout(duration, TransactionTimer::TimerA(key, duration));
656 self.timer_a.replace(timer_a);
657 } else if let TransactionTimer::TimerB(_) = timer {
658 let timeout_response = self.endpoint_inner.make_response(
659 &self.original,
660 rsip::StatusCode::RequestTimeout,
661 None,
662 );
663 self.inform_tu_response(timeout_response)?;
664 self.transition(TransactionState::Terminated)?;
665 }
666 }
667 }
668 TransactionState::Proceeding => {
669 if let TransactionTimer::TimerC(_) = timer {
670 let timeout_response = self.endpoint_inner.make_response(
672 &self.original,
673 rsip::StatusCode::RequestTimeout,
674 None,
675 );
676 self.inform_tu_response(timeout_response)?;
677 self.transition(TransactionState::Terminated)?;
678 }
679 }
680 TransactionState::Completed => {
681 if let TransactionTimer::TimerG(key, duration) = timer {
682 if let Some(last_response) = &self.last_response {
684 if let Some(connection) = &self.connection {
685 let last_response =
686 if let Some(ref inspector) = self.endpoint_inner.inspector {
687 inspector.before_send(last_response.to_owned().into())
688 } else {
689 last_response.to_owned().into()
690 };
691 connection
692 .send(last_response, self.destination.as_ref())
693 .await?;
694 }
695 }
696 let duration = (duration * 2).min(self.endpoint_inner.option.t1x64);
698 let timer_g = self
699 .endpoint_inner
700 .timers
701 .timeout(duration, TransactionTimer::TimerG(key, duration));
702 self.timer_g.replace(timer_g);
703 } else if let TransactionTimer::TimerD(_) = timer {
704 self.transition(TransactionState::Terminated)?;
705 } else if let TransactionTimer::TimerK(_) = timer {
706 self.transition(TransactionState::Terminated)?;
707 }
708 }
709 TransactionState::Confirmed => {
710 if let TransactionTimer::TimerK(_) = timer {
711 self.transition(TransactionState::Terminated)?;
712 }
713 }
714 _ => {}
715 }
716 Ok(())
717 }
718
719 fn transition(&mut self, state: TransactionState) -> Result<TransactionState> {
720 if self.state == state {
721 return Ok(self.state.clone());
722 }
723 match state {
724 TransactionState::Nothing => {}
725 TransactionState::Calling => {
726 let connection = self.connection.as_ref().ok_or(Error::TransactionError(
727 "no connection found".to_string(),
728 self.key.clone(),
729 ))?;
730
731 if matches!(
732 self.transaction_type,
733 TransactionType::ClientInvite | TransactionType::ClientNonInvite
734 ) {
735 if !connection.is_reliable() {
736 let timer_a = self.endpoint_inner.timers.timeout(
737 self.endpoint_inner.option.t1,
738 TransactionTimer::TimerA(
739 self.key.clone(),
740 self.endpoint_inner.option.t1,
741 ),
742 );
743 self.timer_a.replace(timer_a);
744 }
745 self.timer_b.replace(self.endpoint_inner.timers.timeout(
746 self.endpoint_inner.option.t1x64,
747 TransactionTimer::TimerB(self.key.clone()),
748 ));
749 }
750 }
751 TransactionState::Trying | TransactionState::Proceeding => {
752 self.timer_a
753 .take()
754 .map(|id| self.endpoint_inner.timers.cancel(id));
755 if matches!(self.transaction_type, TransactionType::ClientInvite) {
756 self.timer_b
757 .take()
758 .map(|id| self.endpoint_inner.timers.cancel(id));
759 if self.timer_c.is_none() {
760 let timer_c = self.endpoint_inner.timers.timeout(
762 self.endpoint_inner.option.timerc,
763 TransactionTimer::TimerC(self.key.clone()),
764 );
765 self.timer_c.replace(timer_c);
766 }
767 }
768 }
769 TransactionState::Completed => {
770 self.timer_a
771 .take()
772 .map(|id| self.endpoint_inner.timers.cancel(id));
773 self.timer_b
774 .take()
775 .map(|id| self.endpoint_inner.timers.cancel(id));
776 self.timer_c
777 .take()
778 .map(|id| self.endpoint_inner.timers.cancel(id));
779
780 if self.transaction_type == TransactionType::ServerInvite {
781 let connection = self.connection.as_ref().ok_or(Error::TransactionError(
783 "no connection found".to_string(),
784 self.key.clone(),
785 ))?;
786 if !connection.is_reliable() {
787 let timer_g = self.endpoint_inner.timers.timeout(
788 self.endpoint_inner.option.t1,
789 TransactionTimer::TimerG(
790 self.key.clone(),
791 self.endpoint_inner.option.t1,
792 ),
793 );
794 self.timer_g.replace(timer_g);
795 }
796 info!(key=%self.key, last = self.last_response.is_none(), "entered confirmed state, waiting for ACK");
797 match self.last_response {
798 Some(ref resp) => {
799 let dialog_id = DialogId::try_from(resp)?;
800 self.endpoint_inner
801 .waiting_ack
802 .write()
803 .as_mut()
804 .map(|wa| wa.insert(dialog_id, self.key.clone()))
805 .ok();
806 }
807 _ => {}
808 }
809 let timer_k = self.endpoint_inner.timers.timeout(
811 self.endpoint_inner.option.t4,
812 TransactionTimer::TimerK(self.key.clone()),
813 );
814 self.timer_k.replace(timer_k);
815 }
816 let timer_d = self.endpoint_inner.timers.timeout(
818 self.endpoint_inner.option.t1x64,
819 TransactionTimer::TimerD(self.key.clone()),
820 );
821 self.timer_d.replace(timer_d);
822 }
823 TransactionState::Confirmed => {
824 self.cleanup_timer();
825 let timer_k = self.endpoint_inner.timers.timeout(
826 self.endpoint_inner.option.t4,
827 TransactionTimer::TimerK(self.key.clone()),
828 );
829 self.timer_k.replace(timer_k);
830 }
831 TransactionState::Terminated => {
832 self.cleanup();
833 self.tu_sender.send(TransactionEvent::Terminate).ok(); }
835 }
836 debug!(
837 key = %self.key,
838 "transition: {:?} -> {:?}", self.state, state
839 );
840 self.state = state;
841 Ok(self.state.clone())
842 }
843
844 fn cleanup_timer(&mut self) {
845 self.timer_a
846 .take()
847 .map(|id| self.endpoint_inner.timers.cancel(id));
848 self.timer_b
849 .take()
850 .map(|id| self.endpoint_inner.timers.cancel(id));
851 self.timer_c
852 .take()
853 .map(|id| self.endpoint_inner.timers.cancel(id));
854 self.timer_d
855 .take()
856 .map(|id| self.endpoint_inner.timers.cancel(id));
857 self.timer_k
858 .take()
859 .map(|id| self.endpoint_inner.timers.cancel(id));
860 self.timer_g
861 .take()
862 .map(|id| self.endpoint_inner.timers.cancel(id));
863 }
864
865 fn cleanup(&mut self) {
866 if self.is_cleaned_up {
867 return;
868 }
869 self.is_cleaned_up = true;
870 self.cleanup_timer();
871
872 match self.last_response {
873 Some(ref resp) => match DialogId::try_from(resp) {
874 Ok(dialog_id) => self
875 .endpoint_inner
876 .waiting_ack
877 .write()
878 .as_mut()
879 .map(|wa| wa.remove(&dialog_id))
880 .ok(),
881 Err(_) => None,
882 },
883 _ => None,
884 };
885
886 let last_message = {
887 match self.transaction_type {
888 TransactionType::ClientInvite => {
889 if matches!(
892 self.state,
893 TransactionState::Proceeding | TransactionState::Trying
894 ) {
895 if self.last_ack.is_none() {
896 if let Some(ref resp) = self.last_response {
897 if let Ok(ack) = self
898 .endpoint_inner
899 .make_ack(self.original.uri.clone(), resp)
900 {
901 self.last_ack.replace(ack);
902 }
903 }
904 }
905 }
906 self.last_ack.take().map(SipMessage::Request)
907 }
908 TransactionType::ServerNonInvite => {
909 self.last_response.take().map(SipMessage::Response)
910 }
911 _ => None,
912 }
913 };
914 self.endpoint_inner
915 .detach_transaction(&self.key, last_message);
916 }
917}
918
919impl Drop for Transaction {
920 fn drop(&mut self) {
921 self.cleanup();
922 trace!(key=%self.key, state=%self.state, "transaction dropped");
923 }
924}