rust_rcs_client/connection/
p_cscf_connection_config.rs

1// Copyright 2023 宋昊文
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::net::{IpAddr, Ipv4Addr};
16
17use rust_rcs_core::{
18    dns::DnsConfig,
19    ffi::net_ctrl::{get_active_network_info, get_dns_info, get_dns_servers, get_network_type},
20};
21
22use crate::provisioning::ims_application::{ImsApplication, SignallingProtocol, TransportProto};
23
24pub enum ServiceType {
25    SipD2U,
26    SipD2T,
27    SipsD2T,
28}
29
30impl ServiceType {
31    pub fn get_string_repr(&self) -> String {
32        match self {
33            ServiceType::SipD2U => String::from("SIP+D2U"),
34
35            ServiceType::SipD2T => String::from("SIP+D2T"),
36
37            ServiceType::SipsD2T => String::from("SIPS+D2T"),
38        }
39    }
40}
41
42pub struct PCscfConnectionConfig {
43    p: usize,
44    p_cscf_addresses: Vec<(String, String)>,
45    transport_proto: TransportProto,
46}
47
48impl PCscfConnectionConfig {
49    pub fn new() -> PCscfConnectionConfig {
50        PCscfConnectionConfig {
51            p: 0,
52            p_cscf_addresses: Vec::new(),
53            transport_proto: TransportProto::create_default(),
54        }
55    }
56
57    pub fn update_configuration(&mut self, ims_app: &ImsApplication) {
58        let mut p_cscf_addresses = Vec::new();
59
60        for (address, address_type) in ims_app.get_lbo_p_cscf_addresses() {
61            p_cscf_addresses.push((String::from(address), String::from(address_type)));
62        }
63
64        let mut transport_proto = TransportProto::create_default();
65        if let Some(gsma_ext) = ims_app.get_ims_gsma_extension() {
66            if let Some(proto) = gsma_ext.get_info().get_transport_proto_info() {
67                transport_proto = proto;
68            }
69        }
70
71        self.p = 0;
72        self.p_cscf_addresses = p_cscf_addresses;
73        self.transport_proto = transport_proto;
74    }
75
76    pub fn get_next(
77        &mut self,
78    ) -> Option<(
79        DnsConfig,
80        ServiceType,
81        String,
82        Option<String>,
83        Option<IpAddr>,
84        Option<u16>,
85    )> {
86        if let Some(network_info) = get_active_network_info() {
87            let network_type = get_network_type(&network_info);
88
89            let dns_info = get_dns_info(&network_info);
90
91            if let Some(dns_info) = dns_info {
92                let dns_servers = get_dns_servers(&dns_info);
93
94                let dns_config = DnsConfig {
95                    server_addrs: dns_servers,
96                };
97
98                if self.p_cscf_addresses.len() > 0 {
99                    self.p = if self.p_cscf_addresses.len() > 1 {
100                        self.p % self.p_cscf_addresses.len()
101                    } else {
102                        0
103                    };
104                    let p_cscf_address = self.p_cscf_addresses.get(self.p);
105                    self.p += 1;
106                    if let Some((address, address_type)) = p_cscf_address {
107                        let proto = if network_type == 2 {
108                            &self.transport_proto.ps_signalling
109                        } else if network_type == 3 {
110                            &self.transport_proto.ps_signalling_roaming
111                        } else {
112                            &self.transport_proto.wifi_signalling
113                        };
114
115                        let mut host: Option<String> = None;
116                        let mut addr: Option<IpAddr> = None;
117                        let mut port: Option<u16> = None;
118                        if address_type == "FQDN" {
119                            host = Some(String::from(address));
120                        } else if address_type == "IPv4" {
121                            if let Some(idx) = address.find(':') {
122                                let v4_addr = &address[..idx];
123                                let v4_port = &address[idx + 1..];
124                                let v4_addr: Result<Ipv4Addr, _> = v4_addr.parse();
125                                if let Ok(v4_addr) = v4_addr {
126                                    addr = Some(IpAddr::V4(v4_addr));
127                                } else {
128                                    return self.get_next();
129                                }
130                                let v4_port: Result<u16, _> = v4_port.parse();
131                                if let Ok(v4_port) = v4_port {
132                                    port = Some(v4_port);
133                                } else {
134                                    return self.get_next();
135                                }
136                            } else {
137                                let v4_addr: Result<Ipv4Addr, _> = address.parse();
138                                if let Ok(v4_addr) = v4_addr {
139                                    addr = Some(IpAddr::V4(v4_addr));
140                                } else {
141                                    return self.get_next();
142                                }
143                            }
144                        } else {
145                            return self.get_next();
146                        }
147
148                        let service_type = match proto {
149                            SignallingProtocol::SIPoUDP => ServiceType::SipD2U,
150
151                            SignallingProtocol::SIPoTCP => ServiceType::SipD2T,
152
153                            SignallingProtocol::SIPoTLS => ServiceType::SipsD2T,
154                        };
155
156                        return Some((
157                            dns_config,
158                            service_type,
159                            String::from(address),
160                            host,
161                            addr,
162                            port,
163                        ));
164                    }
165                }
166            }
167        }
168
169        None
170    }
171}