libsip/client/
registration.rs1use crate::*;
2
3use std::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult};
4
5#[derive(Debug, PartialEq, Clone)]
11pub struct RegistrationManager {
12 account_uri: Uri,
14 local_uri: Uri,
16 cseq_counter: u32,
18 nonce_c: u32,
20 c_nonce: Option<String>,
22 auth_header: Option<AuthHeader>,
24 branch: String,
26 call_id: String,
28 expires_header: Option<u32>,
30 user: Option<String>,
32 pass: Option<String>,
34 realm: Option<String>,
36 nonce: Option<String>,
38}
39
40impl RegistrationManager {
41 pub fn new(account_uri: Uri, local_uri: Uri) -> RegistrationManager {
45 RegistrationManager {
46 account_uri,
47 local_uri,
48 cseq_counter: 444,
49 auth_header: None,
50 nonce_c: 1,
51 c_nonce: None,
52 branch: format!("{:x}", md5::compute(rand::random::<[u8; 16]>())),
53 call_id: format!("{:x}", md5::compute(rand::random::<[u8; 16]>())),
54 expires_header: None,
55 user: None,
56 pass: None,
57 realm: None,
58 nonce: None,
59 }
60 }
61
62 pub fn username<S: Into<String>>(&mut self, s: S) {
64 self.user = Some(s.into());
65 }
66
67 pub fn password<S: Into<String>>(&mut self, p: S) {
69 self.pass = Some(p.into());
70 }
71
72 pub fn get_request(&mut self, cfg: &HeaderWriteConfig) -> IoResult<SipMessage> {
76 self.cseq_counter += 1;
77 self.nonce_c += 1;
78 let to_header = self.account_uri.clone();
79 let from_header = self.account_uri.clone();
80 let mut contact_header = self.local_uri.clone();
81 let mut headers = vec![];
82
83 if let Some(name) = &self.user {
84 contact_header = contact_header.auth(UriAuth::new(name));
85 if let Some(auth_header) = &self.auth_header {
86 if let Some(pass) = &self.pass {
87 let ctx = AuthContext {
88 user: &name,
89 pass,
90 nc: self.nonce_c,
91 uri: &self.account_uri,
92 };
93 headers.push(Header::Authorization(auth_header.authenticate(ctx)?));
94 }
95 }
96 }
97 headers.push(Header::ContentLength(0));
98 headers.push(Header::To(NamedHeader::new(to_header)));
99 headers.push(Header::From(NamedHeader::new(from_header)));
100 headers.push(Header::Contact(NamedHeader::new(contact_header)));
101 headers.push(Header::CSeq(self.cseq_counter, Method::Register));
102 headers.push(Header::CallId(format!(
103 "{}@{}",
104 self.call_id,
105 self.account_uri.host()
106 )));
107 headers.push(self.via_header());
108 cfg.write_headers_vec(&mut headers);
109
110 if let Some(exp) = self.expires_header {
111 headers.push(Header::Expires(exp));
112 }
113 Ok(RequestGenerator::new()
114 .method(Method::Register)
115 .uri(self.account_uri.clone().authless())
116 .headers(headers)
117 .build()?)
118 }
119
120 pub fn set_challenge(&mut self, msg: SipMessage) -> IoResult<()> {
123 if let SipMessage::Response { headers, .. } = msg {
124 for item in headers.into_iter() {
125 match item {
126 Header::WwwAuthenticate(auth) => {
127 self.auth_header = Some(auth);
128 },
129 Header::Expires(expire) => {
130 self.expires_header = Some(expire);
131 },
132 _ => {},
133 }
134 }
135 Ok(())
136 } else {
137 Err(IoError::new(
138 IoErrorKind::InvalidInput,
139 "Challenge Response was not a SIP response",
140 ))
141 }
142 }
143
144 pub fn expires(&self) -> u32 {
146 self.expires_header.unwrap_or(60)
147 }
148
149 pub fn cseq(&self) -> u32 {
151 self.cseq_counter
152 }
153
154 pub fn via_header(&self) -> Header {
157 let via_uri = self
158 .local_uri
159 .clone()
160 .parameter(UriParam::Branch(self.branch.clone()))
161 .authless()
162 .schemaless();
163 Header::Via(ViaHeader {
164 uri: via_uri,
165 version: Default::default(),
166 transport: Transport::Udp,
167 })
168 }
169}