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#[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 #[must_use]
39 #[inline(always)]
40 pub const fn new(ip_addr: IpAddr, port: u16) -> Self {
41 Self { ip_addr, port }
42 }
43
44 #[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 #[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 #[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 #[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 pub fn has_private_ip_addr(self) -> bool {
126 super::ip::private::is_private_ip(self.ip_addr)
127 }
128
129 #[must_use]
131 #[inline(always)]
132 pub fn from_std(addr: SocketAddr) -> Self {
133 Self::from(addr)
134 }
135
136 #[must_use]
138 #[inline(always)]
139 pub fn into_std(self) -> SocketAddr {
140 self.into()
141 }
142
143 #[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 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 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 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 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}