webrtc_sdp/
address.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5extern crate url;
6use self::url::Host;
7use error::SdpParserInternalError;
8use std::convert::TryFrom;
9use std::fmt;
10use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
11use std::str::FromStr;
12
13#[derive(Clone, Debug)]
14#[cfg_attr(feature = "serialize", derive(Serialize))]
15pub enum Address {
16    Fqdn(String),
17    Ip(IpAddr),
18}
19
20impl fmt::Display for Address {
21    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22        match self {
23            Address::Fqdn(fqdn) => fqdn.fmt(f),
24            Address::Ip(ip) => ip.fmt(f),
25        }
26    }
27}
28
29impl FromStr for Address {
30    type Err = SdpParserInternalError;
31    fn from_str(s: &str) -> Result<Self, Self::Err> {
32        let mut e: Option<SdpParserInternalError> = None;
33        if s.find(':').is_some() {
34            match IpAddr::from_str(s) {
35                Ok(ip) => return Ok(Address::Ip(ip)),
36                Err(err) => e = Some(err.into()),
37            }
38        }
39        Host::parse(s)
40            .map(|host| match host {
41                Host::Domain(s) => Address::Fqdn(s),
42                Host::Ipv4(ip) => Address::Ip(IpAddr::V4(ip)),
43                Host::Ipv6(ip) => Address::Ip(IpAddr::V6(ip)),
44            })
45            .map_err(|err| e.unwrap_or_else(|| err.into()))
46    }
47}
48
49impl From<ExplicitlyTypedAddress> for Address {
50    fn from(item: ExplicitlyTypedAddress) -> Self {
51        match item {
52            ExplicitlyTypedAddress::Fqdn { domain, .. } => Address::Fqdn(domain),
53            ExplicitlyTypedAddress::Ip(ip) => Address::Ip(ip),
54        }
55    }
56}
57
58impl PartialEq for Address {
59    fn eq(&self, other: &Self) -> bool {
60        match (self, other) {
61            (Address::Fqdn(a), Address::Fqdn(b)) => a.to_lowercase() == b.to_lowercase(),
62            (Address::Ip(a), Address::Ip(b)) => a == b,
63            (_, _) => false,
64        }
65    }
66}
67
68#[derive(Clone, Copy, PartialEq, Debug)]
69#[cfg_attr(feature = "serialize", derive(Serialize))]
70pub enum AddressType {
71    IpV4 = 4,
72    IpV6 = 6,
73}
74
75impl fmt::Display for AddressType {
76    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77        match self {
78            AddressType::IpV4 => "IP4",
79            AddressType::IpV6 => "IP6",
80        }
81        .fmt(f)
82    }
83}
84
85impl FromStr for AddressType {
86    type Err = SdpParserInternalError;
87    fn from_str(s: &str) -> Result<Self, Self::Err> {
88        match s.to_uppercase().as_str() {
89            "IP4" => Ok(AddressType::IpV4),
90            "IP6" => Ok(AddressType::IpV6),
91            _ => Err(SdpParserInternalError::UnknownAddressType(s.to_owned())),
92        }
93    }
94}
95
96pub trait AddressTyped {
97    fn address_type(&self) -> AddressType;
98}
99
100impl AddressTyped for IpAddr {
101    fn address_type(&self) -> AddressType {
102        match self {
103            IpAddr::V4(_) => AddressType::IpV4,
104            IpAddr::V6(_) => AddressType::IpV6,
105        }
106    }
107}
108
109#[derive(Clone, Debug)]
110#[cfg_attr(feature = "serialize", derive(Serialize))]
111pub enum ExplicitlyTypedAddress {
112    Fqdn {
113        address_type: AddressType,
114        domain: String,
115    },
116    Ip(IpAddr),
117}
118
119impl fmt::Display for ExplicitlyTypedAddress {
120    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121        write!(f, "IN {} ", self.address_type())?;
122        match self {
123            ExplicitlyTypedAddress::Fqdn { domain, .. } => domain.fmt(f),
124            ExplicitlyTypedAddress::Ip(ip) => ip.fmt(f),
125        }
126    }
127}
128
129impl AddressTyped for ExplicitlyTypedAddress {
130    fn address_type(&self) -> AddressType {
131        match self {
132            ExplicitlyTypedAddress::Fqdn { address_type, .. } => *address_type,
133            ExplicitlyTypedAddress::Ip(ip) => ip.address_type(),
134        }
135    }
136}
137
138impl From<IpAddr> for ExplicitlyTypedAddress {
139    fn from(item: IpAddr) -> Self {
140        ExplicitlyTypedAddress::Ip(item)
141    }
142}
143
144impl From<Ipv4Addr> for ExplicitlyTypedAddress {
145    fn from(item: Ipv4Addr) -> Self {
146        ExplicitlyTypedAddress::Ip(IpAddr::V4(item))
147    }
148}
149
150impl From<Ipv6Addr> for ExplicitlyTypedAddress {
151    fn from(item: Ipv6Addr) -> Self {
152        ExplicitlyTypedAddress::Ip(IpAddr::V6(item))
153    }
154}
155
156impl TryFrom<(AddressType, &str)> for ExplicitlyTypedAddress {
157    type Error = SdpParserInternalError;
158    fn try_from(item: (AddressType, &str)) -> Result<Self, Self::Error> {
159        match Address::from_str(item.1)? {
160            Address::Ip(ip) => {
161                if ip.address_type() != item.0 {
162                    Err(SdpParserInternalError::AddressTypeMismatch {
163                        found: ip.address_type(),
164                        expected: item.0,
165                    })
166                } else {
167                    Ok(ExplicitlyTypedAddress::Ip(ip))
168                }
169            }
170            Address::Fqdn(domain) => Ok(ExplicitlyTypedAddress::Fqdn {
171                address_type: item.0,
172                domain,
173            }),
174        }
175    }
176}
177
178impl PartialEq for ExplicitlyTypedAddress {
179    fn eq(&self, other: &Self) -> bool {
180        match (self, other) {
181            (
182                ExplicitlyTypedAddress::Fqdn {
183                    address_type: a1,
184                    domain: d1,
185                },
186                ExplicitlyTypedAddress::Fqdn {
187                    address_type: a2,
188                    domain: d2,
189                },
190            ) => a1 == a2 && d1.to_lowercase() == d2.to_lowercase(),
191            (ExplicitlyTypedAddress::Ip(a), ExplicitlyTypedAddress::Ip(b)) => a == b,
192            (_, _) => false,
193        }
194    }
195}
196
197#[cfg(test)]
198#[path = "./address_tests.rs"]
199mod address_tests;