ftth_rsipstack/dialog/server_dialog.rs
1use super::dialog::{Dialog, DialogInnerRef, DialogState, TerminatedReason};
2use super::DialogId;
3use crate::dialog::dialog::DialogInner;
4use crate::rsip;
5use crate::transport::SipConnection;
6use crate::{
7 transaction::transaction::{Transaction, TransactionEvent},
8 Result,
9};
10use rsip::{prelude::HeadersExt, Header, Request, SipMessage, StatusCode};
11use std::sync::atomic::Ordering;
12use tokio_util::sync::CancellationToken;
13use tracing::{debug, info, trace, warn};
14
15/// Server-side INVITE Dialog (UAS)
16///
17/// `ServerInviteDialog` represents a server-side INVITE dialog in SIP. This is used
18/// when the local user agent acts as a User Agent Server (UAS) and receives
19/// an INVITE transaction from a remote party to establish a session.
20///
21/// # Key Features
22///
23/// * **Session Acceptance** - Accepts or rejects incoming INVITE requests
24/// * **In-dialog Requests** - Handles UPDATE, INFO, OPTIONS within established dialogs
25/// * **Session Termination** - Handles BYE for ending sessions
26/// * **Re-INVITE Support** - Supports session modification via re-INVITE
27/// * **ACK Handling** - Properly handles ACK for 2xx responses
28/// * **State Management** - Tracks dialog state transitions
29///
30/// # Dialog Lifecycle
31///
32/// 1. **Creation** - Dialog created when receiving INVITE
33/// 2. **Processing** - Can send provisional responses (1xx)
34/// 3. **Decision** - Accept (2xx) or reject (3xx-6xx) the INVITE
35/// 4. **Wait ACK** - If accepted, wait for ACK from client
36/// 5. **Confirmed** - ACK received, dialog established
37/// 6. **Active** - Can handle in-dialog requests
38/// 7. **Termination** - Receives BYE or sends BYE to end session
39///
40/// # Examples
41///
42/// ## Basic Call Handling
43///
44/// ```rust,no_run
45/// # use ftth_rsipstack::dialog::server_dialog::ServerInviteDialog;
46/// # fn example() -> ftth_rsipstack::Result<()> {
47/// # let dialog: ServerInviteDialog = todo!(); // Dialog is typically created by DialogLayer
48/// # let answer_sdp = vec![];
49/// // After receiving INVITE:
50///
51/// // Accept the call
52/// dialog.accept(None, Some(answer_sdp))?;
53///
54/// // Or reject the call
55/// dialog.reject(None, None)?;
56/// # Ok(())
57/// # }
58/// ```
59///
60/// ```rust,no_run
61/// # use ftth_rsipstack::dialog::server_dialog::ServerInviteDialog;
62/// # async fn example() -> ftth_rsipstack::Result<()> {
63/// # let dialog: ServerInviteDialog = todo!();
64/// // End an established call
65/// dialog.bye().await?;
66/// # Ok(())
67/// # }
68/// ```
69///
70/// ## Session Modification
71///
72/// ```rust,no_run
73/// # use ftth_rsipstack::dialog::server_dialog::ServerInviteDialog;
74/// # async fn example() -> ftth_rsipstack::Result<()> {
75/// # let dialog: ServerInviteDialog = todo!();
76/// # let new_sdp = vec![];
77/// // Send re-INVITE to modify session
78/// let headers = vec![
79/// rsip::Header::ContentType("application/sdp".into())
80/// ];
81/// let response = dialog.reinvite(Some(headers), Some(new_sdp)).await?;
82/// # Ok(())
83/// # }
84/// ```
85///
86/// # Thread Safety
87///
88/// ServerInviteDialog is thread-safe and can be cloned and shared across tasks.
89/// All operations are atomic and properly synchronized.
90#[derive(Clone)]
91pub struct ServerInviteDialog {
92 pub(super) inner: DialogInnerRef,
93}
94
95impl ServerInviteDialog {
96 /// Get the dialog identifier
97 ///
98 /// Returns the unique DialogId that identifies this dialog instance.
99 /// The DialogId consists of Call-ID, from-tag, and to-tag.
100 pub fn id(&self) -> DialogId {
101 self.inner.id.lock().unwrap().clone()
102 }
103
104 pub fn state(&self) -> DialogState {
105 self.inner.state.lock().unwrap().clone()
106 }
107
108 /// Get the cancellation token for this dialog
109 ///
110 /// Returns a reference to the CancellationToken that can be used to
111 /// cancel ongoing operations for this dialog.
112 pub fn cancel_token(&self) -> &CancellationToken {
113 &self.inner.cancel_token
114 }
115
116 /// Get the initial INVITE request
117 ///
118 /// Returns a reference to the initial INVITE request that created
119 /// this dialog. This can be used to access the original request
120 /// headers, body, and other information.
121 pub fn initial_request(&self) -> &Request {
122 &self.inner.initial_request
123 }
124
125 pub fn ringing(&self, headers: Option<Vec<Header>>, body: Option<Vec<u8>>) -> Result<()> {
126 if !self.inner.can_cancel() {
127 return Ok(());
128 }
129 info!(id = %self.id(), "sending ringing response");
130 let resp = self.inner.make_response(
131 &self.inner.initial_request,
132 if body.is_some() {
133 StatusCode::SessionProgress
134 } else {
135 StatusCode::Ringing
136 },
137 headers,
138 body,
139 );
140 self.inner
141 .tu_sender
142 .send(TransactionEvent::Respond(resp.clone()))?;
143 self.inner.transition(DialogState::Early(self.id(), resp))?;
144 Ok(())
145 }
146 /// Accept the incoming INVITE request
147 ///
148 /// Sends a 200 OK response to accept the incoming INVITE request.
149 /// This establishes the dialog and transitions it to the WaitAck state,
150 /// waiting for the ACK from the client.
151 ///
152 /// # Parameters
153 ///
154 /// * `headers` - Optional additional headers to include in the response
155 /// * `body` - Optional message body (typically SDP answer)
156 ///
157 /// # Returns
158 ///
159 /// * `Ok(())` - Response sent successfully
160 /// * `Err(Error)` - Failed to send response or transaction terminated
161 ///
162 /// # Examples
163 ///
164 /// ```rust,no_run
165 /// # use ftth_rsipstack::dialog::server_dialog::ServerInviteDialog;
166 /// # fn example() -> ftth_rsipstack::Result<()> {
167 /// # let dialog: ServerInviteDialog = todo!();
168 /// // Accept with SDP answer
169 /// let answer_sdp = b"v=0\r\no=- 123 456 IN IP4 192.168.1.1\r\n...";
170 /// let headers = vec![
171 /// rsip::Header::ContentType("application/sdp".into())
172 /// ];
173 /// dialog.accept(Some(headers), Some(answer_sdp.to_vec()))?;
174 /// # Ok(())
175 /// # }
176 /// ```
177 pub fn accept(&self, headers: Option<Vec<Header>>, body: Option<Vec<u8>>) -> Result<()> {
178 let resp = self.inner.make_response(
179 &self.inner.initial_request,
180 rsip::StatusCode::OK,
181 headers,
182 body,
183 );
184 let via = self.inner.initial_request.via_header()?;
185 let (via_transport, via_received) = SipConnection::parse_target_from_via(via)?;
186 let mut params = vec![];
187 if via_transport != rsip::transport::Transport::Udp {
188 params.push(rsip::param::Param::Transport(via_transport));
189 }
190 let contact = rsip::headers::typed::Contact {
191 uri: rsip::Uri {
192 host_with_port: via_received,
193 params,
194 ..Default::default()
195 },
196 display_name: None,
197 params: vec![],
198 };
199 debug!(id = %self.id(), "accepting dialog with contact: {}", contact);
200 self.inner
201 .remote_contact
202 .lock()
203 .unwrap()
204 .replace(contact.untyped());
205 self.inner
206 .tu_sender
207 .send(TransactionEvent::Respond(resp.clone()))?;
208
209 self.inner
210 .transition(DialogState::WaitAck(self.id(), resp))?;
211 Ok(())
212 }
213
214 /// Accept the incoming INVITE request with NAT-aware Contact header
215 ///
216 /// Sends a 200 OK response to accept the incoming INVITE request, automatically
217 /// adding a Contact header with the provided public address for proper NAT traversal.
218 /// This is the recommended method when working with NAT environments.
219 ///
220 /// # Parameters
221 ///
222 /// * `username` - SIP username for the Contact header
223 /// * `public_address` - Optional public address discovered via registration
224 /// * `local_address` - Local SIP address as fallback
225 /// * `headers` - Optional additional headers to include
226 /// * `body` - Optional SDP answer body
227 ///
228 /// # Returns
229 ///
230 /// * `Ok(())` - Response sent successfully
231 /// * `Err(Error)` - Failed to send response or transaction terminated
232 ///
233 /// # Examples
234 ///
235 /// ```rust,no_run
236 /// # use ftth_rsipstack::dialog::server_dialog::ServerInviteDialog;
237 /// # use ftth_rsipstack::transport::SipAddr;
238 /// # use std::net::{IpAddr, Ipv4Addr};
239 /// # fn example() -> ftth_rsipstack::Result<()> {
240 /// # let dialog: ServerInviteDialog = todo!();
241 /// # let local_addr: SipAddr = todo!();
242 /// let public_addr = Some(rsip::HostWithPort {
243 /// host: IpAddr::V4(Ipv4Addr::new(203, 0, 113, 1)).into(),
244 /// port: Some(5060.into()),
245 /// });
246 /// let answer_sdp = b"v=0\r\no=- 123 456 IN IP4 203.0.113.1\r\n...";
247 /// let headers = vec![
248 /// rsip::Header::ContentType("application/sdp".into())
249 /// ];
250 ///
251 /// dialog.accept_with_public_contact(
252 /// "alice",
253 /// public_addr,
254 /// &local_addr,
255 /// Some(headers),
256 /// Some(answer_sdp.to_vec())
257 /// )?;
258 /// # Ok(())
259 /// # }
260 /// ```
261 pub fn accept_with_public_contact(
262 &self,
263 username: &str,
264 public_address: Option<rsip::HostWithPort>,
265 local_address: &crate::transport::SipAddr,
266 headers: Option<Vec<Header>>,
267 body: Option<Vec<u8>>,
268 ) -> Result<()> {
269 use super::registration::Registration;
270
271 // Create NAT-aware Contact header
272 let contact_header =
273 Registration::create_nat_aware_contact(username, public_address, local_address);
274
275 // Combine provided headers with Contact header
276 let mut final_headers = headers.unwrap_or_default();
277 final_headers.push(contact_header.into());
278
279 // Use the regular accept method with the enhanced headers
280 self.accept(Some(final_headers), body)
281 }
282
283 /// Reject the incoming INVITE request
284 ///
285 /// Sends a reject response to reject the incoming INVITE request.
286 /// Sends a 603 Decline by default, or a custom status code if provided.
287 /// This terminates the dialog creation process.
288 ///
289 /// # Returns
290 ///
291 /// * `Ok(())` - Response sent successfully
292 /// * `Err(Error)` - Failed to send response or transaction terminated
293 ///
294 /// # Examples
295 ///
296 /// ```rust,no_run
297 /// # use ftth_rsipstack::dialog::server_dialog::ServerInviteDialog;
298 /// # fn example() -> ftth_rsipstack::Result<()> {
299 /// # let dialog: ServerInviteDialog = todo!();
300 /// // Reject the incoming call
301 /// dialog.reject(Some(rsip::StatusCode::BusyHere), Some("Busy here".into()))?;
302 /// # Ok(())
303 /// # }
304 /// ```
305 pub fn reject(&self, code: Option<rsip::StatusCode>, reason: Option<String>) -> Result<()> {
306 if self.inner.is_terminated() || self.inner.is_confirmed() {
307 return Ok(());
308 }
309 info!(id=%self.id(), ?code, ?reason, "rejecting dialog");
310 let headers = if let Some(reason) = reason {
311 Some(vec![rsip::Header::Other("Reason".into(), reason.into())])
312 } else {
313 None
314 };
315 let resp = self.inner.make_response(
316 &self.inner.initial_request,
317 code.unwrap_or(rsip::StatusCode::Decline),
318 headers,
319 None,
320 );
321 self.inner
322 .tu_sender
323 .send(TransactionEvent::Respond(resp))
324 .ok();
325 self.inner.transition(DialogState::Terminated(
326 self.id(),
327 TerminatedReason::UasDecline,
328 ))
329 }
330
331 /// Send a BYE request to terminate the dialog
332 ///
333 /// Sends a BYE request to gracefully terminate an established dialog.
334 /// This should only be called for confirmed dialogs. If the dialog
335 /// is not confirmed, this method returns immediately without error.
336 ///
337 /// # Returns
338 ///
339 /// * `Ok(())` - BYE was sent successfully or dialog not confirmed
340 /// * `Err(Error)` - Failed to send BYE request
341 ///
342 /// # Examples
343 ///
344 /// ```rust,no_run
345 /// # use ftth_rsipstack::dialog::server_dialog::ServerInviteDialog;
346 /// # async fn example() -> ftth_rsipstack::Result<()> {
347 /// # let dialog: ServerInviteDialog = todo!();
348 /// // End an established call
349 /// dialog.bye().await?;
350 /// # Ok(())
351 /// # }
352 /// ```
353 pub async fn bye(&self) -> Result<()> {
354 if !self.inner.is_confirmed() {
355 return Ok(());
356 }
357 info!(id=%self.id(), "sending bye request");
358
359 let request = self.inner.make_request_with_vias(
360 rsip::Method::Bye,
361 None,
362 self.inner.build_vias_from_request()?,
363 None,
364 None,
365 )?;
366
367 match self.inner.do_request(request).await {
368 Ok(_) => {}
369 Err(e) => {
370 info!(id=%self.id(),"bye error: {}", e);
371 }
372 };
373 self.inner
374 .transition(DialogState::Terminated(self.id(), TerminatedReason::UasBye))?;
375 Ok(())
376 }
377
378 /// Send a re-INVITE request to modify the session
379 ///
380 /// Sends a re-INVITE request within an established dialog to modify
381 /// the session parameters (e.g., change media, add/remove streams).
382 /// This can only be called for confirmed dialogs.
383 ///
384 /// # Parameters
385 ///
386 /// * `headers` - Optional additional headers to include
387 /// * `body` - Optional message body (typically new SDP)
388 ///
389 /// # Returns
390 ///
391 /// * `Ok(Some(Response))` - Response to the re-INVITE
392 /// * `Ok(None)` - Dialog not confirmed, no request sent
393 /// * `Err(Error)` - Failed to send re-INVITE
394 ///
395 /// # Examples
396 ///
397 /// ```rust,no_run
398 /// # use ftth_rsipstack::dialog::server_dialog::ServerInviteDialog;
399 /// # async fn example() -> ftth_rsipstack::Result<()> {
400 /// # let dialog: ServerInviteDialog = todo!();
401 /// let new_sdp = b"v=0\r\no=- 123 456 IN IP4 192.168.1.1\r\n...";
402 /// let response = dialog.reinvite(None, Some(new_sdp.to_vec())).await?;
403 /// # Ok(())
404 /// # }
405 /// ```
406 pub async fn reinvite(
407 &self,
408 headers: Option<Vec<rsip::Header>>,
409 body: Option<Vec<u8>>,
410 ) -> Result<Option<rsip::Response>> {
411 if !self.inner.is_confirmed() {
412 return Ok(None);
413 }
414 info!(id=%self.id(), "sending re-invite request, body: \n{:?}", body);
415 let request = self.inner.make_request_with_vias(
416 rsip::Method::Invite,
417 None,
418 self.inner.build_vias_from_request()?,
419 headers,
420 body,
421 )?;
422 let resp = self.inner.do_request(request.clone()).await;
423 match resp {
424 Ok(Some(ref resp)) => {
425 if resp.status_code == StatusCode::OK {
426 self.inner
427 .transition(DialogState::Updated(self.id(), request))?;
428 }
429 }
430 _ => {}
431 }
432 resp
433 }
434
435 /// Send an UPDATE request to modify session parameters
436 ///
437 /// Sends an UPDATE request within an established dialog to modify
438 /// session parameters without the complexity of a re-INVITE.
439 /// This is typically used for smaller session modifications.
440 ///
441 /// # Parameters
442 ///
443 /// * `headers` - Optional additional headers to include
444 /// * `body` - Optional message body (typically SDP)
445 ///
446 /// # Returns
447 ///
448 /// * `Ok(Some(Response))` - Response to the UPDATE
449 /// * `Ok(None)` - Dialog not confirmed, no request sent
450 /// * `Err(Error)` - Failed to send UPDATE
451 ///
452 /// # Examples
453 ///
454 /// ```rust,no_run
455 /// # use ftth_rsipstack::dialog::server_dialog::ServerInviteDialog;
456 /// # async fn example() -> ftth_rsipstack::Result<()> {
457 /// # let dialog: ServerInviteDialog = todo!();
458 /// # let sdp_body = vec![];
459 /// let response = dialog.update(None, Some(sdp_body)).await?;
460 /// # Ok(())
461 /// # }
462 /// ```
463 pub async fn update(
464 &self,
465 headers: Option<Vec<rsip::Header>>,
466 body: Option<Vec<u8>>,
467 ) -> Result<Option<rsip::Response>> {
468 if !self.inner.is_confirmed() {
469 return Ok(None);
470 }
471 info!(id=%self.id(), "sending update request, body: \n{:?}", body);
472 let request = self.inner.make_request_with_vias(
473 rsip::Method::Update,
474 None,
475 self.inner.build_vias_from_request()?,
476 headers,
477 body,
478 )?;
479 self.inner.do_request(request.clone()).await
480 }
481
482 /// Send an INFO request for mid-dialog information
483 ///
484 /// Sends an INFO request within an established dialog to exchange
485 /// application-level information. This is commonly used for DTMF
486 /// tones, but can carry any application-specific data.
487 ///
488 /// # Parameters
489 ///
490 /// * `headers` - Optional additional headers to include
491 /// * `body` - Optional message body (application-specific data)
492 ///
493 /// # Returns
494 ///
495 /// * `Ok(Some(Response))` - Response to the INFO
496 /// * `Ok(None)` - Dialog not confirmed, no request sent
497 /// * `Err(Error)` - Failed to send INFO
498 ///
499 /// # Examples
500 ///
501 /// ```rust,no_run
502 /// # use ftth_rsipstack::dialog::server_dialog::ServerInviteDialog;
503 /// # async fn example() -> ftth_rsipstack::Result<()> {
504 /// # let dialog: ServerInviteDialog = todo!();
505 /// // Send DTMF tone
506 /// let dtmf_body = b"Signal=1\r\nDuration=100\r\n";
507 /// let headers = vec![
508 /// rsip::Header::ContentType("application/dtmf-relay".into())
509 /// ];
510 /// let response = dialog.info(Some(headers), Some(dtmf_body.to_vec())).await?;
511 /// # Ok(())
512 /// # }
513 /// ```
514 pub async fn info(
515 &self,
516 headers: Option<Vec<rsip::Header>>,
517 body: Option<Vec<u8>>,
518 ) -> Result<Option<rsip::Response>> {
519 if !self.inner.is_confirmed() {
520 return Ok(None);
521 }
522 info!(id=%self.id(), "sending info request, body: \n{:?}", body);
523 let request = self.inner.make_request_with_vias(
524 rsip::Method::Info,
525 None,
526 self.inner.build_vias_from_request()?,
527 headers,
528 body,
529 )?;
530 self.inner.do_request(request.clone()).await
531 }
532
533 /// Handle incoming transaction for this dialog
534 ///
535 /// Processes incoming SIP requests that are routed to this dialog.
536 /// This method handles sequence number validation and dispatches
537 /// to appropriate handlers based on the request method and dialog state.
538 ///
539 /// # Parameters
540 ///
541 /// * `tx` - The incoming transaction to handle
542 ///
543 /// # Returns
544 ///
545 /// * `Ok(())` - Request handled successfully
546 /// * `Err(Error)` - Failed to handle request
547 ///
548 /// # Supported Methods
549 ///
550 /// * `ACK` - Confirms 2xx response (transitions to Confirmed state)
551 /// * `BYE` - Terminates the dialog
552 /// * `INFO` - Handles information exchange
553 /// * `OPTIONS` - Handles capability queries
554 /// * `UPDATE` - Handles session updates
555 /// * `INVITE` - Handles initial INVITE or re-INVITE
556 pub async fn handle(&mut self, tx: &mut Transaction) -> Result<()> {
557 debug!(
558 id = %self.id(),
559 "handle request: {} state:{}",
560 tx.original,
561 self.inner.state.lock().unwrap()
562 );
563
564 let cseq = tx.original.cseq_header()?.seq()?;
565 let remote_seq = self.inner.remote_seq.load(Ordering::Relaxed);
566 if remote_seq > 0 && cseq < remote_seq {
567 info!(
568 id=%self.id(),
569 "received old request {} remote_seq: {} > {}",
570 tx.original.method(),
571 remote_seq,
572 cseq
573 );
574 // discard old request
575 return Ok(());
576 }
577
578 self.inner
579 .remote_seq
580 .compare_exchange(remote_seq, cseq, Ordering::Relaxed, Ordering::Relaxed)
581 .ok();
582
583 if self.inner.is_confirmed() {
584 match tx.original.method {
585 rsip::Method::Cancel => {
586 info!(id=%self.id(),
587 "invalid request received {} {}",
588 tx.original.method, tx.original.uri
589 );
590 tx.reply(rsip::StatusCode::OK).await?;
591 return Ok(());
592 }
593 rsip::Method::Invite | rsip::Method::Ack => {
594 info!(id=%self.id(),
595 "invalid request received {} {}",
596 tx.original.method, tx.original.uri
597 );
598 return Err(crate::Error::DialogError(
599 "invalid request in confirmed state".to_string(),
600 self.id(),
601 rsip::StatusCode::MethodNotAllowed,
602 ));
603 }
604 rsip::Method::Bye => return self.handle_bye(tx).await,
605 rsip::Method::Info => return self.handle_info(tx).await,
606 rsip::Method::Options => return self.handle_options(tx).await,
607 rsip::Method::Update => return self.handle_update(tx).await,
608 _ => {
609 info!(id=%self.id(),"invalid request method: {:?}", tx.original.method);
610 tx.reply(rsip::StatusCode::MethodNotAllowed).await?;
611 return Err(crate::Error::DialogError(
612 "invalid request".to_string(),
613 self.id(),
614 rsip::StatusCode::MethodNotAllowed,
615 ));
616 }
617 }
618 } else {
619 match tx.original.method {
620 rsip::Method::Ack => {
621 self.inner.tu_sender.send(TransactionEvent::Received(
622 tx.original.clone().into(),
623 tx.connection.clone(),
624 ))?;
625 }
626 _ => {}
627 }
628 }
629 self.handle_invite(tx).await
630 }
631
632 async fn handle_bye(&mut self, tx: &mut Transaction) -> Result<()> {
633 info!(id = %self.id(), "received bye {}", tx.original.uri);
634 self.inner
635 .transition(DialogState::Terminated(self.id(), TerminatedReason::UacBye))?;
636 tx.reply(rsip::StatusCode::OK).await?;
637 Ok(())
638 }
639
640 async fn handle_info(&mut self, tx: &mut Transaction) -> Result<()> {
641 info!(id = %self.id(), "received info {}", tx.original.uri);
642 self.inner
643 .transition(DialogState::Info(self.id(), tx.original.clone()))?;
644 tx.reply(rsip::StatusCode::OK).await?;
645 Ok(())
646 }
647
648 async fn handle_options(&mut self, tx: &mut Transaction) -> Result<()> {
649 info!(id = %self.id(), "received options {}", tx.original.uri);
650 self.inner
651 .transition(DialogState::Options(self.id(), tx.original.clone()))?;
652 tx.reply(rsip::StatusCode::OK).await?;
653 Ok(())
654 }
655
656 async fn handle_update(&mut self, tx: &mut Transaction) -> Result<()> {
657 info!(id = %self.id(), "received update {}", tx.original.uri);
658 self.inner
659 .transition(DialogState::Updated(self.id(), tx.original.clone()))?;
660 tx.reply(rsip::StatusCode::OK).await?;
661 Ok(())
662 }
663
664 async fn handle_invite(&mut self, tx: &mut Transaction) -> Result<()> {
665 let handle_loop = async {
666 if !self.inner.is_confirmed() && matches!(tx.original.method, rsip::Method::Invite) {
667 match self.inner.transition(DialogState::Calling(self.id())) {
668 Ok(_) => {
669 tx.send_trying().await.ok();
670 }
671 Err(_) => {}
672 }
673 }
674
675 while let Some(msg) = tx.receive().await {
676 match msg {
677 SipMessage::Request(req) => match req.method {
678 rsip::Method::Ack => {
679 if self.inner.is_terminated() {
680 // dialog already terminated, ignore
681 break;
682 }
683 info!(id = %self.id(),"received ack {}", req.uri);
684 match req.contact_header() {
685 Ok(contact) => {
686 self.inner
687 .remote_contact
688 .lock()
689 .unwrap()
690 .replace(contact.clone());
691 }
692 _ => {}
693 }
694
695 self.inner.transition(DialogState::Confirmed(
696 self.id(),
697 tx.last_response.clone().unwrap_or_default(),
698 ))?;
699 DialogInner::serve_keepalive_options(self.inner.clone());
700 break;
701 }
702 rsip::Method::Cancel => {
703 info!(id = %self.id(),"received cancel {}", req.uri);
704 tx.reply(rsip::StatusCode::RequestTerminated).await?;
705 self.inner.transition(DialogState::Terminated(
706 self.id(),
707 TerminatedReason::UacCancel,
708 ))?;
709 }
710 _ => {}
711 },
712 SipMessage::Response(_) => {}
713 }
714 }
715 Ok::<(), crate::Error>(())
716 };
717 match handle_loop.await {
718 Ok(_) => {
719 trace!(id = %self.id(),"process done");
720 Ok(())
721 }
722 Err(e) => {
723 warn!(id = %self.id(),"handle_invite error: {:?}", e);
724 Err(e)
725 }
726 }
727 }
728}
729
730impl TryFrom<&Dialog> for ServerInviteDialog {
731 type Error = crate::Error;
732
733 fn try_from(dlg: &Dialog) -> Result<Self> {
734 match dlg {
735 Dialog::ServerInvite(dlg) => Ok(dlg.clone()),
736 _ => Err(crate::Error::DialogError(
737 "Dialog is not a ServerInviteDialog".to_string(),
738 dlg.id(),
739 rsip::StatusCode::BadRequest,
740 )),
741 }
742 }
743}