Skip to main content

active_call/useragent/
registration.rs

1use anyhow::Result;
2use rsip::{HostWithPort, Response, StatusCodeKind, Transport};
3use rsipstack::{
4    dialog::{authenticate::Credential, registration::Registration},
5    rsip_ext::RsipResponseExt, transport::SipAddr,
6};
7use serde::{Deserialize, Serialize};
8use std::time::Instant;
9use tokio_util::sync::CancellationToken;
10use tracing::{debug, warn};
11
12use super::public_address::{normalize_transport, should_update_address};
13
14#[derive(Debug, Deserialize, Clone, Serialize)]
15pub struct UserCredential {
16    pub username: String,
17    pub password: String,
18    pub realm: Option<String>,
19}
20
21#[derive(Debug, Deserialize, Clone, Serialize)]
22pub struct RegisterOption {
23    pub server: String,
24    pub username: String,
25    pub display_name: Option<String>,
26    pub disabled: Option<bool>,
27    pub credential: Option<UserCredential>,
28}
29
30impl From<UserCredential> for Credential {
31    fn from(val: UserCredential) -> Self {
32        Credential {
33            username: val.username,
34            password: val.password,
35            realm: val.realm,
36        }
37    }
38}
39
40impl RegisterOption {
41    pub fn aor(&self) -> String {
42        format!("{}@{}", self.username, self.server)
43    }
44}
45
46pub struct RegistrationHandle {
47    pub registration: Registration,
48    pub option: RegisterOption,
49    pub cancel_token: CancellationToken,
50    pub start_time: Instant,
51    pub last_update: Instant,
52    pub last_response: Option<Response>,
53}
54
55impl RegistrationHandle {
56    pub fn should_retry_registration_now(
57        &self,
58        local_addr: &SipAddr,
59        current_contact_address: &HostWithPort,
60        discovered_public_address: Option<&HostWithPort>,
61    ) -> bool {
62        if normalize_transport(local_addr.r#type.as_ref()) != Transport::Udp {
63            return false;
64        }
65
66        discovered_public_address
67            .is_some_and(|address| should_update_address(current_contact_address, address))
68    }
69
70    pub async fn do_register(
71        &mut self,
72        sip_server: &rsip::Uri,
73        expires: Option<u32>,
74        contact: &rsip::typed::Contact,
75    ) -> Result<(u32, Option<HostWithPort>)> {
76        self.registration.contact = Some(contact.clone());
77        let resp = match self
78            .registration
79            .register(sip_server.clone(), expires)
80            .await
81            .map_err(|e| anyhow::anyhow!("Registration failed: {}", e))
82        {
83            Ok(resp) => resp,
84            Err(e) => {
85                warn!("registration failed: {}", e);
86                return Err(anyhow::anyhow!("Registration failed: {}", e));
87            }
88        };
89        debug!(
90            user = self.option.aor(),
91            "registration response: {:?}", resp
92        );
93        match resp.status_code().kind() {
94            StatusCodeKind::Successful => {
95                self.last_update = Instant::now();
96                self.last_response = Some(resp);
97                Ok((
98                    self.registration.expires(),
99                    self.registration.public_address.clone(),
100                ))
101            }
102            _ => Err(anyhow::anyhow!("{:?}", resp.reason_phrase())),
103        }
104    }
105}