1use core::fmt;
35use core::str::FromStr;
36
37#[cfg(feature = "std")]
38use super::IpAddr;
39use super::{Host, Port};
40
41#[cfg(feature = "serde")]
42use serde::{Deserialize, Serialize};
43
44#[cfg(feature = "arbitrary")]
45use arbitrary::Arbitrary;
46
47#[derive(Debug, Clone, PartialEq, Eq)]
49pub enum SocketAddrError {
50 MissingPortSeparator,
52 InvalidHost,
54 InvalidPort,
56 EmptyInput,
58}
59
60impl fmt::Display for SocketAddrError {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 match self {
63 Self::MissingPortSeparator => write!(f, "missing port separator ':'"),
64 Self::InvalidHost => write!(f, "invalid host"),
65 Self::InvalidPort => write!(f, "invalid port"),
66 Self::EmptyInput => write!(f, "empty input"),
67 }
68 }
69}
70
71#[cfg(feature = "std")]
72impl std::error::Error for SocketAddrError {}
73
74#[derive(Debug, Clone, PartialEq, Eq)]
76pub enum StdConversionError {
77 NotIpAddress,
79 PortZero,
81}
82
83impl fmt::Display for StdConversionError {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 match self {
86 Self::NotIpAddress => write!(
87 f,
88 "cannot convert to std::net::SocketAddr: host is not an IP address"
89 ),
90 Self::PortZero => write!(
91 f,
92 "cannot convert from std::net::SocketAddr: port 0 is not allowed"
93 ),
94 }
95 }
96}
97
98#[cfg(feature = "std")]
99impl std::error::Error for StdConversionError {}
100
101#[derive(Debug, Clone, PartialEq, Eq, Hash)]
131#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
132pub struct SocketAddr {
133 host: Host,
135 port: Port,
137}
138
139#[cfg(feature = "arbitrary")]
140impl<'a> Arbitrary<'a> for SocketAddr {
141 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
142 Ok(Self {
143 host: Host::arbitrary(u)?,
144 port: Port::arbitrary(u)?,
145 })
146 }
147}
148
149impl SocketAddr {
150 #[must_use]
163 #[inline]
164 pub const fn new(host: Host, port: Port) -> Self {
165 Self { host, port }
166 }
167
168 #[must_use]
180 #[inline]
181 pub const fn as_host(&self) -> &Host {
182 &self.host
183 }
184
185 #[must_use]
197 #[inline]
198 pub const fn as_port(&self) -> &Port {
199 &self.port
200 }
201
202 #[inline]
215 pub fn set_host(&mut self, host: Host) {
216 self.host = host;
217 }
218
219 #[inline]
232 pub const fn set_port(&mut self, port: Port) {
233 self.port = port;
234 }
235
236 #[must_use]
253 #[inline]
254 pub fn into_parts(self) -> (Host, Port) {
255 (self.host, self.port)
256 }
257
258 pub fn parse_str(s: &str) -> Result<Self, SocketAddrError> {
287 if s.is_empty() {
288 return Err(SocketAddrError::EmptyInput);
289 }
290
291 let Some(colon_pos) = s.rfind(':') else {
293 return Err(SocketAddrError::MissingPortSeparator);
294 };
295
296 let host_str = &s[..colon_pos];
298 let port_str = &s[colon_pos + 1..];
299
300 if host_str.is_empty() || port_str.is_empty() {
302 return Err(SocketAddrError::MissingPortSeparator);
303 }
304
305 let host_str = if host_str.starts_with('[') && host_str.ends_with(']') {
307 &host_str[1..host_str.len() - 1]
308 } else {
309 host_str
310 };
311
312 let host = Host::parse_str(host_str).map_err(|_| SocketAddrError::InvalidHost)?;
314
315 let port = port_str
317 .parse::<Port>()
318 .map_err(|_| SocketAddrError::InvalidPort)?;
319
320 Ok(Self { host, port })
321 }
322
323 #[must_use]
335 #[inline]
336 pub const fn is_ip(&self) -> bool {
337 self.host.is_ipaddr()
338 }
339
340 #[must_use]
352 #[inline]
353 pub const fn is_domain_name(&self) -> bool {
354 self.host.is_domainname()
355 }
356
357 #[must_use]
372 #[inline]
373 pub const fn is_hostname(&self) -> bool {
374 self.host.is_hostname()
375 }
376}
377
378impl FromStr for SocketAddr {
379 type Err = SocketAddrError;
380
381 fn from_str(s: &str) -> Result<Self, Self::Err> {
382 Self::parse_str(s)
383 }
384}
385
386impl fmt::Display for SocketAddr {
387 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388 match &self.host {
390 Host::IpAddr(ip) if ip.as_inner().is_ipv6() => {
391 write!(f, "[{}]:{}", self.host, self.port)
392 }
393 _ => write!(f, "{}:{}", self.host, self.port),
394 }
395 }
396}
397
398#[cfg(feature = "std")]
399impl TryFrom<std::net::SocketAddr> for SocketAddr {
400 type Error = StdConversionError;
401
402 fn try_from(addr: std::net::SocketAddr) -> Result<Self, Self::Error> {
403 let port = Port::new(addr.port()).map_err(|_| StdConversionError::PortZero)?;
404 Ok(Self {
405 host: Host::from_ipaddr(IpAddr::from(addr.ip())),
406 port,
407 })
408 }
409}
410
411#[cfg(feature = "std")]
412impl TryFrom<SocketAddr> for std::net::SocketAddr {
413 type Error = StdConversionError;
414
415 fn try_from(addr: SocketAddr) -> Result<Self, Self::Error> {
416 match addr.host {
417 Host::IpAddr(ip) => Ok(Self::new(ip.into(), addr.port.as_u16())),
418 Host::DomainName(_) | Host::Hostname(_) => Err(StdConversionError::NotIpAddress),
419 }
420 }
421}
422
423#[cfg(test)]
424mod tests {
425 use super::*;
426
427 #[test]
428 fn test_new() {
429 let host = Host::parse_str("192.168.1.1").unwrap();
430 let port = Port::new(8080).unwrap();
431 let addr = SocketAddr::new(host, port);
432 assert!(addr.as_host().is_ipaddr());
433 assert_eq!(addr.as_port().as_u16(), 8080);
434 }
435
436 #[test]
437 fn test_parse_ipv4() {
438 let addr: SocketAddr = "192.168.1.1:8080".parse().unwrap();
439 assert!(addr.as_host().is_ipaddr());
440 assert_eq!(addr.as_port().as_u16(), 8080);
441 assert_eq!(format!("{addr}"), "192.168.1.1:8080");
442 }
443
444 #[test]
445 fn test_parse_ipv6() {
446 let addr: SocketAddr = "[::1]:8080".parse().unwrap();
447 assert!(addr.as_host().is_ipaddr());
448 assert_eq!(addr.as_port().as_u16(), 8080);
449 }
450
451 #[test]
452 fn test_parse_domainname() {
453 let addr: SocketAddr = "example.com:443".parse().unwrap();
454 assert!(addr.as_host().is_domainname());
455 assert_eq!(addr.as_port().as_u16(), 443);
456 assert_eq!(format!("{addr}"), "example.com:443");
457 }
458
459 #[test]
460 fn test_parse_domainname_with_digits() {
461 let addr: SocketAddr = "123.example.com:443".parse().unwrap();
462 assert!(addr.as_host().is_domainname());
463 assert_eq!(addr.as_port().as_u16(), 443);
464 }
465
466 #[test]
467 fn test_parse_str_empty() {
468 assert!(SocketAddr::parse_str("").is_err());
469 }
470
471 #[test]
472 fn test_parse_str_missing_separator() {
473 assert!(SocketAddr::parse_str("192.168.1.1").is_err());
474 }
475
476 #[test]
477 fn test_parse_str_empty_host() {
478 assert!(SocketAddr::parse_str(":8080").is_err());
479 }
480
481 #[test]
482 fn test_parse_str_empty_port() {
483 assert!(SocketAddr::parse_str("192.168.1.1:").is_err());
484 }
485
486 #[test]
487 fn test_parse_str_invalid_host() {
488 assert!(SocketAddr::parse_str("-invalid:8080").is_err());
489 }
490
491 #[test]
492 fn test_parse_str_invalid_port() {
493 assert!(SocketAddr::parse_str("192.168.1.1:invalid").is_err());
494 }
495
496 #[test]
497 fn test_parse_str_port_zero() {
498 assert!(SocketAddr::parse_str("192.168.1.1:0").is_err());
499 }
500
501 #[test]
502 fn test_parse_str_port_out_of_range() {
503 assert!(SocketAddr::parse_str("192.168.1.1:99999").is_err());
504 }
505
506 #[test]
507 fn test_set_host() {
508 let mut addr: SocketAddr = "192.168.1.1:8080".parse().unwrap();
509 let new_host = Host::parse_str("10.0.0.1").unwrap();
510 addr.set_host(new_host);
511 assert_eq!(format!("{addr}"), "10.0.0.1:8080");
512 }
513
514 #[test]
515 fn test_set_port() {
516 let mut addr: SocketAddr = "192.168.1.1:8080".parse().unwrap();
517 let new_port = Port::new(9090).unwrap();
518 addr.set_port(new_port);
519 assert_eq!(format!("{addr}"), "192.168.1.1:9090");
520 }
521
522 #[test]
523 fn test_into_parts() {
524 let host = Host::parse_str("192.168.1.1").unwrap();
525 let port = Port::new(8080).unwrap();
526 let addr = SocketAddr::new(host, port);
527
528 let (h, p) = addr.into_parts();
529 assert!(h.is_ipaddr());
530 assert_eq!(p.as_u16(), 8080);
531 }
532
533 #[test]
534 fn test_as_host_and_as_port() {
535 let addr: SocketAddr = "192.168.1.1:8080".parse().unwrap();
536 assert!(addr.as_host().is_ipaddr());
537 assert_eq!(addr.as_port().as_u16(), 8080);
538 }
539
540 #[test]
541 fn test_is_ip() {
542 let addr: SocketAddr = "192.168.1.1:8080".parse().unwrap();
543 assert!(addr.is_ip());
544 assert!(!addr.is_domain_name());
545 assert!(!addr.is_hostname());
546 }
547
548 #[test]
549 fn test_is_domain_name() {
550 let addr: SocketAddr = "example.com:443".parse().unwrap();
551 assert!(!addr.is_ip());
552 assert!(addr.is_domain_name());
553 assert!(!addr.is_hostname());
554 }
555
556 #[test]
557 fn test_host_is_domainname() {
558 let addr: SocketAddr = "example.com:443".parse().unwrap();
559 assert!(addr.as_host().is_domainname());
560 }
561
562 #[test]
563 fn test_socket_addr_is_domain_name() {
564 let addr: SocketAddr = "example.com:443".parse().unwrap();
565 assert!(addr.is_domain_name());
566 }
567
568 #[test]
569 fn test_is_hostname() {
570 let hostname = crate::net::Hostname::new("localhost").unwrap();
571 let host = Host::from_hostname(hostname);
572 let port = Port::new(3000).unwrap();
573 let addr = SocketAddr::new(host, port);
574 assert!(!addr.is_ip());
575 assert!(!addr.is_domain_name());
576 assert!(addr.is_hostname());
577 }
578
579 #[test]
580 fn test_equality() {
581 let addr1: SocketAddr = "192.168.1.1:8080".parse().unwrap();
582 let addr2: SocketAddr = "192.168.1.1:8080".parse().unwrap();
583 let addr3: SocketAddr = "192.168.1.1:9090".parse().unwrap();
584 let addr4: SocketAddr = "10.0.0.1:8080".parse().unwrap();
585
586 assert_eq!(addr1, addr2);
587 assert_ne!(addr1, addr3);
588 assert_ne!(addr1, addr4);
589 }
590
591 #[test]
592 fn test_clone() {
593 let addr: SocketAddr = "192.168.1.1:8080".parse().unwrap();
594 let addr2 = addr.clone();
595 assert_eq!(addr, addr2);
596 }
597
598 #[test]
599 fn test_display() {
600 let addr: SocketAddr = "192.168.1.1:8080".parse().unwrap();
601 assert_eq!(format!("{addr}"), "192.168.1.1:8080");
602
603 let addr: SocketAddr = "example.com:443".parse().unwrap();
604 assert_eq!(format!("{addr}"), "example.com:443");
605
606 let addr: SocketAddr = "[::1]:8080".parse().unwrap();
608 assert_eq!(format!("{addr}"), "[::1]:8080");
609
610 let addr: SocketAddr = "[2001:db8::1]:443".parse().unwrap();
611 assert_eq!(format!("{addr}"), "[2001:db8::1]:443");
612 }
613
614 #[test]
615 fn test_debug() {
616 let addr: SocketAddr = "192.168.1.1:8080".parse().unwrap();
617 let debug = format!("{:?}", addr);
618 assert!(debug.contains("SocketAddr"));
619 }
620
621 #[test]
622 fn test_hash() {
623 use core::hash::Hash;
624 use core::hash::Hasher;
625
626 #[derive(Default)]
627 struct SimpleHasher(u64);
628
629 impl Hasher for SimpleHasher {
630 fn finish(&self) -> u64 {
631 self.0
632 }
633
634 fn write(&mut self, bytes: &[u8]) {
635 for byte in bytes {
636 self.0 = self.0.wrapping_mul(31).wrapping_add(*byte as u64);
637 }
638 }
639 }
640
641 let addr1: SocketAddr = "192.168.1.1:8080".parse().unwrap();
642 let addr2: SocketAddr = "192.168.1.1:8080".parse().unwrap();
643 let addr3: SocketAddr = "10.0.0.1:8080".parse().unwrap();
644
645 let mut hasher1 = SimpleHasher::default();
646 let mut hasher2 = SimpleHasher::default();
647 let mut hasher3 = SimpleHasher::default();
648
649 addr1.hash(&mut hasher1);
650 addr2.hash(&mut hasher2);
651 addr3.hash(&mut hasher3);
652
653 assert_eq!(hasher1.finish(), hasher2.finish());
654 assert_ne!(hasher1.finish(), hasher3.finish());
655 }
656
657 #[test]
658 fn test_parse_ipv6_with_brackets() {
659 let addr: SocketAddr = "[2001:db8::1]:8080".parse().unwrap();
660 assert!(addr.as_host().is_ipaddr());
661 assert_eq!(addr.as_port().as_u16(), 8080);
662 }
663
664 #[test]
665 fn test_parse_localhost() {
666 let addr: SocketAddr = "localhost:3000".parse().unwrap();
667 assert!(addr.as_host().is_domainname());
668 assert_eq!(addr.as_port().as_u16(), 3000);
669 }
670
671 #[test]
672 fn test_parse_system_port() {
673 let addr: SocketAddr = "192.168.1.1:80".parse().unwrap();
674 assert_eq!(addr.as_port().as_u16(), 80);
675 assert!(addr.as_port().is_system_port());
676 }
677
678 #[test]
679 fn test_parse_registered_port() {
680 let addr: SocketAddr = "192.168.1.1:8080".parse().unwrap();
681 assert_eq!(addr.as_port().as_u16(), 8080);
682 assert!(addr.as_port().is_registered_port());
683 }
684
685 #[test]
686 fn test_parse_dynamic_port() {
687 let addr: SocketAddr = "192.168.1.1:50000".parse().unwrap();
688 assert_eq!(addr.as_port().as_u16(), 50000);
689 assert!(addr.as_port().is_dynamic_port());
690 }
691
692 #[test]
693 fn test_error_display() {
694 let err = SocketAddrError::MissingPortSeparator;
695 assert_eq!(format!("{err}"), "missing port separator ':'");
696
697 let err = SocketAddrError::InvalidHost;
698 assert_eq!(format!("{err}"), "invalid host");
699
700 let err = SocketAddrError::InvalidPort;
701 assert_eq!(format!("{err}"), "invalid port");
702
703 let err = SocketAddrError::EmptyInput;
704 assert_eq!(format!("{err}"), "empty input");
705 }
706
707 #[test]
708 fn test_parse_str_method() {
709 let addr = SocketAddr::parse_str("192.168.1.1:8080").unwrap();
710 assert!(addr.as_host().is_ipaddr());
711 assert_eq!(addr.as_port().as_u16(), 8080);
712 }
713
714 #[test]
715 fn test_case_insensitive() {
716 let addr1: SocketAddr = "EXAMPLE.COM:443".parse().unwrap();
717 let addr2: SocketAddr = "example.com:443".parse().unwrap();
718 assert_eq!(addr1, addr2);
719 }
720
721 #[test]
722 fn test_ipv4_loopback() {
723 let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
724 assert!(addr.as_host().is_ipaddr());
725 }
726
727 #[test]
728 fn test_ipv4_private() {
729 let addr: SocketAddr = "10.0.0.1:8080".parse().unwrap();
730 assert!(addr.as_host().is_ipaddr());
731 }
732
733 #[test]
734 fn test_ipv6_loopback() {
735 let addr: SocketAddr = "[::1]:8080".parse().unwrap();
736 assert!(addr.as_host().is_ipaddr());
737 }
738
739 #[test]
740 fn test_numeric_domainname() {
741 let addr: SocketAddr = "123:8080".parse().unwrap();
742 assert!(addr.as_host().is_domainname());
743 }
744
745 #[test]
746 fn test_multi_label_domainname() {
747 let addr: SocketAddr = "api.v1.example.com:443".parse().unwrap();
748 assert!(addr.as_host().is_domainname());
749 }
750
751 #[test]
752 fn test_max_port() {
753 let addr: SocketAddr = "192.168.1.1:65535".parse().unwrap();
754 assert_eq!(addr.as_port().as_u16(), 65535);
755 }
756
757 #[test]
758 fn test_min_port() {
759 let addr: SocketAddr = "192.168.1.1:1".parse().unwrap();
760 assert_eq!(addr.as_port().as_u16(), 1);
761 }
762
763 #[cfg(feature = "std")]
764 #[test]
765 fn test_try_from_std_socket_addr() {
766 let std_addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080));
767 let addr = SocketAddr::try_from(std_addr).unwrap();
768 assert!(addr.as_host().is_ipaddr());
769 assert_eq!(addr.as_port().as_u16(), 8080);
770 }
771
772 #[cfg(feature = "std")]
773 #[test]
774 fn test_try_from_std_socket_addr_ipv6() {
775 let std_addr = std::net::SocketAddr::from(([0, 0, 0, 0, 0, 0, 0, 1], 8080));
776 let addr = SocketAddr::try_from(std_addr).unwrap();
777 assert!(addr.as_host().is_ipaddr());
778 assert_eq!(addr.as_port().as_u16(), 8080);
779 }
780
781 #[cfg(feature = "std")]
782 #[test]
783 fn test_try_from_std_socket_addr_port_zero_fails() {
784 let std_addr = std::net::SocketAddr::from(([127, 0, 0, 1], 0));
785 let result = SocketAddr::try_from(std_addr);
786 assert!(result.is_err());
787 assert_eq!(result.unwrap_err(), StdConversionError::PortZero);
788 }
789
790 #[cfg(feature = "std")]
791 #[test]
792 fn test_try_to_std_socket_addr_ip() {
793 let addr: SocketAddr = "192.168.1.1:8080".parse().unwrap();
794 let std_addr = std::net::SocketAddr::try_from(addr).unwrap();
795 assert_eq!(std_addr.ip(), std::net::IpAddr::from([192, 168, 1, 1]));
796 assert_eq!(std_addr.port(), 8080);
797 }
798
799 #[cfg(feature = "std")]
800 #[test]
801 fn test_try_to_std_socket_addr_domainname_fails() {
802 let addr: SocketAddr = "example.com:443".parse().unwrap();
803 let result = std::net::SocketAddr::try_from(addr);
804 assert!(result.is_err());
805 assert_eq!(result.unwrap_err(), StdConversionError::NotIpAddress);
806 }
807
808 #[cfg(feature = "std")]
809 #[test]
810 fn test_try_to_std_socket_addr_hostname_fails() {
811 let hostname = crate::net::Hostname::new("localhost").unwrap();
812 let host = Host::from_hostname(hostname);
813 let port = Port::new(3000).unwrap();
814 let addr = SocketAddr::new(host, port);
815 let result = std::net::SocketAddr::try_from(addr);
816 assert!(result.is_err());
817 assert_eq!(result.unwrap_err(), StdConversionError::NotIpAddress);
818 }
819
820 #[cfg(feature = "std")]
821 #[test]
822 fn test_std_conversion_error_display() {
823 let err = StdConversionError::NotIpAddress;
824 assert_eq!(
825 format!("{err}"),
826 "cannot convert to std::net::SocketAddr: host is not an IP address"
827 );
828
829 let err = StdConversionError::PortZero;
830 assert_eq!(
831 format!("{err}"),
832 "cannot convert from std::net::SocketAddr: port 0 is not allowed"
833 );
834 }
835
836 #[cfg(feature = "std")]
837 #[test]
838 fn test_roundtrip_std_socket_addr() {
839 let std_addr1 = std::net::SocketAddr::from(([192, 168, 1, 1], 8080));
840 let addr = SocketAddr::try_from(std_addr1).unwrap();
841 let std_addr2 = std::net::SocketAddr::try_from(addr).unwrap();
842 assert_eq!(std_addr1, std_addr2);
843 }
844}