Skip to main content

rama_net/address/
socket_address.rs

1use core::fmt;
2use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
3use core::str::FromStr;
4
5use crate::std::{self as std, string::String, vec::Vec};
6
7use crate::address::ip::{
8    IPV4_BROADCAST, IPV4_LOCALHOST, IPV4_UNSPECIFIED, IPV6_LOCALHOST, IPV6_UNSPECIFIED,
9};
10use crate::address::parse_utils::try_to_parse_str_to_ip;
11
12use rama_core::error::BoxErrorExt as _;
13use rama_core::error::{BoxError, ErrorContext};
14use rama_utils::macros::generate_set_and_with;
15
16/// An [`IpAddr`] with an associated port (u16)
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub struct SocketAddress {
19    pub ip_addr: IpAddr,
20    pub port: u16,
21}
22
23impl PartialEq<SocketAddr> for SocketAddress {
24    fn eq(&self, other: &SocketAddr) -> bool {
25        self.port == other.port() && self.ip_addr == other.ip()
26    }
27}
28
29impl PartialEq<SocketAddress> for SocketAddr {
30    #[inline(always)]
31    fn eq(&self, other: &SocketAddress) -> bool {
32        other.eq(self)
33    }
34}
35
36impl SocketAddress {
37    /// creates a new [`SocketAddress`]
38    #[must_use]
39    #[inline(always)]
40    pub const fn new(ip_addr: IpAddr, port: u16) -> Self {
41        Self { ip_addr, port }
42    }
43
44    /// creates a new local ipv4 [`SocketAddress`] for the given port
45    ///
46    /// # Example
47    ///
48    /// ```
49    /// use rama_net::address::SocketAddress;
50    ///
51    /// let addr = SocketAddress::local_ipv4(8080);
52    /// assert_eq!("127.0.0.1:8080", addr.to_string());
53    /// ```
54    #[must_use]
55    #[inline(always)]
56    pub const fn local_ipv4(port: u16) -> Self {
57        Self {
58            ip_addr: IPV4_LOCALHOST,
59            port,
60        }
61    }
62
63    /// creates a new local ipv6 [`SocketAddress`] for the given port.
64    ///
65    /// # Example
66    ///
67    /// ```
68    /// use rama_net::address::SocketAddress;
69    ///
70    /// let addr = SocketAddress::local_ipv6(8080);
71    /// assert_eq!("[::1]:8080", addr.to_string());
72    /// ```
73    #[must_use]
74    #[inline(always)]
75    pub const fn local_ipv6(port: u16) -> Self {
76        Self {
77            ip_addr: IPV6_LOCALHOST,
78            port,
79        }
80    }
81
82    /// creates a new default ipv4 [`SocketAddress`] for the given port
83    ///
84    /// # Example
85    ///
86    /// ```
87    /// use rama_net::address::SocketAddress;
88    ///
89    /// let addr = SocketAddress::default_ipv4(8080);
90    /// assert_eq!("0.0.0.0:8080", addr.to_string());
91    /// ```
92    #[must_use]
93    #[inline(always)]
94    pub const fn default_ipv4(port: u16) -> Self {
95        Self {
96            ip_addr: IPV4_UNSPECIFIED,
97            port,
98        }
99    }
100
101    /// creates a new default ipv6 [`SocketAddress`] for the given port.
102    ///
103    /// # Example
104    ///
105    /// ```
106    /// use rama_net::address::SocketAddress;
107    ///
108    /// let addr = SocketAddress::default_ipv6(8080);
109    /// assert_eq!("[::]:8080", addr.to_string());
110    /// ```
111    #[must_use]
112    #[inline(always)]
113    pub const fn default_ipv6(port: u16) -> Self {
114        Self {
115            ip_addr: IPV6_UNSPECIFIED,
116            port,
117        }
118    }
119
120    #[must_use]
121    #[inline(always)]
122    /// Returns `true` when the [`SocketAddress`]'s ip address
123    /// belongs to a range that should be treated as
124    /// private instead of a normal public-Internet destination.
125    pub fn has_private_ip_addr(self) -> bool {
126        super::ip::private::is_private_ip(self.ip_addr)
127    }
128
129    /// Create a [`SocketAddress`] from the std [`SocketAddr`] version.
130    #[must_use]
131    #[inline(always)]
132    pub fn from_std(addr: SocketAddr) -> Self {
133        Self::from(addr)
134    }
135
136    /// Turn the [`SocketAddress`] into the std [`SocketAddr`] version.
137    #[must_use]
138    #[inline(always)]
139    pub fn into_std(self) -> SocketAddr {
140        self.into()
141    }
142
143    /// creates a new broadcast ipv4 [`SocketAddress`] for the given port
144    ///
145    /// # Example
146    ///
147    /// ```
148    /// use rama_net::address::SocketAddress;
149    ///
150    /// let addr = SocketAddress::broadcast_ipv4(8080);
151    /// assert_eq!("255.255.255.255:8080", addr.to_string());
152    /// ```
153    #[must_use]
154    #[inline(always)]
155    pub const fn broadcast_ipv4(port: u16) -> Self {
156        Self {
157            ip_addr: IPV4_BROADCAST,
158            port,
159        }
160    }
161
162    generate_set_and_with! {
163        /// Set [`IpAddr`] as the ip of [`SocketAddress`]
164        pub fn ip(mut self, ip_addr: IpAddr) -> Self {
165            self.ip_addr = ip_addr;
166            self
167        }
168    }
169
170    generate_set_and_with! {
171        /// Set [`Ipv4Addr`] as the ip of [`SocketAddress`]
172        pub fn ipv4(mut self, ip_addr: Ipv4Addr) -> Self {
173            self.ip_addr = IpAddr::V4(ip_addr);
174            self
175        }
176    }
177
178    generate_set_and_with! {
179        /// Set [`Ipv6Addr`] as the ip of [`SocketAddress`]
180        pub fn ipv6(mut self, ip_addr: Ipv6Addr) -> Self {
181            self.ip_addr = IpAddr::V6(ip_addr);
182            self
183        }
184    }
185
186    generate_set_and_with! {
187        /// Set port (u16) of [`SocketAddress`]
188        pub fn port(mut self, port: u16) -> Self {
189            self.port = port;
190            self
191        }
192    }
193}
194
195#[cfg(feature = "std")]
196impl From<SocketAddress> for crate::socket::core::SockAddr {
197    #[inline]
198    fn from(addr: SocketAddress) -> Self {
199        let std_addr: SocketAddr = addr.into();
200        std_addr.into()
201    }
202}
203
204#[cfg(feature = "std")]
205impl From<&SocketAddress> for crate::socket::core::SockAddr {
206    #[inline]
207    fn from(addr: &SocketAddress) -> Self {
208        let std_addr: SocketAddr = (*addr).into();
209        std_addr.into()
210    }
211}
212
213impl From<SocketAddr> for SocketAddress {
214    fn from(addr: SocketAddr) -> Self {
215        Self {
216            ip_addr: addr.ip(),
217            port: addr.port(),
218        }
219    }
220}
221
222impl From<&SocketAddr> for SocketAddress {
223    fn from(addr: &SocketAddr) -> Self {
224        Self {
225            ip_addr: addr.ip(),
226            port: addr.port(),
227        }
228    }
229}
230
231impl From<SocketAddrV4> for SocketAddress {
232    fn from(value: SocketAddrV4) -> Self {
233        Self {
234            ip_addr: (*value.ip()).into(),
235            port: value.port(),
236        }
237    }
238}
239
240impl From<SocketAddrV6> for SocketAddress {
241    fn from(value: SocketAddrV6) -> Self {
242        Self {
243            ip_addr: (*value.ip()).into(),
244            port: value.port(),
245        }
246    }
247}
248
249impl From<SocketAddress> for SocketAddr {
250    fn from(addr: SocketAddress) -> Self {
251        Self::new(addr.ip_addr, addr.port)
252    }
253}
254
255impl From<(IpAddr, u16)> for SocketAddress {
256    #[inline]
257    fn from((ip_addr, port): (IpAddr, u16)) -> Self {
258        Self { ip_addr, port }
259    }
260}
261
262impl From<(Ipv4Addr, u16)> for SocketAddress {
263    #[inline]
264    fn from((ip, port): (Ipv4Addr, u16)) -> Self {
265        Self {
266            ip_addr: ip.into(),
267            port,
268        }
269    }
270}
271
272impl From<([u8; 4], u16)> for SocketAddress {
273    #[inline]
274    fn from((ip, port): ([u8; 4], u16)) -> Self {
275        let ip: IpAddr = ip.into();
276        (ip, port).into()
277    }
278}
279
280impl From<(Ipv6Addr, u16)> for SocketAddress {
281    #[inline]
282    fn from((ip, port): (Ipv6Addr, u16)) -> Self {
283        Self {
284            ip_addr: ip.into(),
285            port,
286        }
287    }
288}
289
290impl From<([u16; 8], u16)> for SocketAddress {
291    #[inline]
292    fn from((ip, port): ([u16; 8], u16)) -> Self {
293        let ip: IpAddr = ip.into();
294        (ip, port).into()
295    }
296}
297
298impl From<([u8; 16], u16)> for SocketAddress {
299    #[inline]
300    fn from((ip, port): ([u8; 16], u16)) -> Self {
301        let ip: IpAddr = ip.into();
302        (ip, port).into()
303    }
304}
305
306impl fmt::Display for SocketAddress {
307    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308        match &self.ip_addr {
309            IpAddr::V4(ip) => write!(f, "{}:{}", ip, self.port),
310            IpAddr::V6(ip) => write!(f, "[{}]:{}", ip, self.port),
311        }
312    }
313}
314
315impl FromStr for SocketAddress {
316    type Err = BoxError;
317
318    fn from_str(s: &str) -> Result<Self, Self::Err> {
319        Self::try_from(s)
320    }
321}
322
323impl TryFrom<String> for SocketAddress {
324    type Error = BoxError;
325
326    fn try_from(s: String) -> Result<Self, Self::Error> {
327        s.as_str().try_into()
328    }
329}
330
331impl TryFrom<&String> for SocketAddress {
332    type Error = BoxError;
333
334    fn try_from(value: &String) -> Result<Self, Self::Error> {
335        value.as_str().try_into()
336    }
337}
338
339impl TryFrom<&str> for SocketAddress {
340    type Error = BoxError;
341
342    fn try_from(s: &str) -> Result<Self, Self::Error> {
343        let (ip_addr, port) = crate::address::parse_utils::split_port_from_str(s)?;
344        let ip_addr =
345            try_to_parse_str_to_ip(ip_addr).context("parse ip address from socket address")?;
346        match ip_addr {
347            IpAddr::V6(_) if !s.starts_with('[') => Err(BoxError::from_static_str(
348                "missing brackets for IPv6 address with port",
349            )),
350            _ => Ok(Self { ip_addr, port }),
351        }
352    }
353}
354
355impl TryFrom<Vec<u8>> for SocketAddress {
356    type Error = BoxError;
357
358    fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
359        Self::try_from(bytes.as_slice())
360    }
361}
362
363impl TryFrom<&[u8]> for SocketAddress {
364    type Error = BoxError;
365
366    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
367        let s = core::str::from_utf8(bytes).context("parse sock address from bytes")?;
368        s.try_into()
369    }
370}
371
372use rama_utils::macros::serde_str::impl_serde_str;
373
374impl_serde_str!(display SocketAddress);
375
376#[cfg(test)]
377mod tests {
378    use super::*;
379
380    fn assert_eq(s: &str, sock_address: SocketAddress, ip_addr: &str, port: u16) {
381        assert_eq!(sock_address.ip_addr.to_string(), ip_addr, "parsing: {s}");
382        assert_eq!(sock_address.port, port, "parsing: {s}");
383    }
384
385    #[test]
386    fn test_parse_valid() {
387        for (s, (expected_ip_addr, expected_port)) in [
388            ("[::1]:80", ("::1", 80)),
389            ("127.0.0.1:80", ("127.0.0.1", 80)),
390            (
391                "[2001:db8:3333:4444:5555:6666:7777:8888]:80",
392                ("2001:db8:3333:4444:5555:6666:7777:8888", 80),
393            ),
394        ] {
395            let msg = format!("parsing '{s}'");
396
397            assert_eq(s, s.parse().expect(&msg), expected_ip_addr, expected_port);
398            assert_eq(
399                s,
400                s.try_into().expect(&msg),
401                expected_ip_addr,
402                expected_port,
403            );
404            assert_eq(
405                s,
406                s.to_owned().try_into().expect(&msg),
407                expected_ip_addr,
408                expected_port,
409            );
410            assert_eq(
411                s,
412                s.as_bytes().try_into().expect(&msg),
413                expected_ip_addr,
414                expected_port,
415            );
416            assert_eq(
417                s,
418                s.as_bytes().to_vec().try_into().expect(&msg),
419                expected_ip_addr,
420                expected_port,
421            );
422        }
423    }
424
425    #[test]
426    fn test_parse_invalid() {
427        for s in [
428            "",
429            "-",
430            ".",
431            ":",
432            ":80",
433            "-.",
434            ".-",
435            "::1",
436            "127.0.0.1",
437            "[::1]",
438            "2001:db8:3333:4444:5555:6666:7777:8888",
439            "[2001:db8:3333:4444:5555:6666:7777:8888]",
440            "example.com",
441            "example.com:",
442            "example.com:-1",
443            "example.com:999999",
444            "example.com:80",
445            "example:com",
446            "[127.0.0.1]:80",
447            "2001:db8:3333:4444:5555:6666:7777:8888:80",
448        ] {
449            let msg = format!("parsing '{s}'");
450            assert!(s.parse::<SocketAddress>().is_err(), "{msg}");
451            assert!(SocketAddress::try_from(s).is_err(), "{msg}");
452            assert!(SocketAddress::try_from(s.to_owned()).is_err(), "{msg}");
453            assert!(SocketAddress::try_from(s.as_bytes()).is_err(), "{msg}");
454            assert!(
455                SocketAddress::try_from(s.as_bytes().to_vec()).is_err(),
456                "{msg}",
457            );
458        }
459    }
460
461    #[test]
462    fn test_parse_display() {
463        for (s, expected) in [("[::1]:80", "[::1]:80"), ("127.0.0.1:80", "127.0.0.1:80")] {
464            let msg = format!("parsing '{s}'");
465            let socket_address: SocketAddress = s.parse().expect(&msg);
466            assert_eq!(socket_address.to_string(), expected, "{msg}");
467        }
468    }
469}