1use std::hash::Hash;
2use std::mem::{self, size_of};
3use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
4#[cfg(not(target_os = "wasi"))]
5use std::path::Path;
6use std::{fmt, io, ptr};
7
8#[cfg(windows)]
9use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0;
10
11#[cfg(not(target_os = "wasi"))]
12use crate::sys::AF_UNIX;
13use crate::sys::{c_int, sockaddr_in, sockaddr_in6, sockaddr_storage, AF_INET, AF_INET6};
14use crate::Domain;
15
16#[allow(non_camel_case_types)]
18pub type socklen_t = crate::sys::socklen_t;
19
20#[allow(non_camel_case_types)]
22pub type sa_family_t = crate::sys::sa_family_t;
23
24#[repr(transparent)]
32pub struct SockAddrStorage {
33 storage: sockaddr_storage,
34}
35
36impl SockAddrStorage {
37 #[inline]
39 pub fn zeroed() -> Self {
40 unsafe { mem::zeroed() }
42 }
43
44 #[inline]
46 pub fn size_of(&self) -> socklen_t {
47 size_of::<Self>() as socklen_t
48 }
49
50 #[inline]
73 pub unsafe fn view_as<T>(&mut self) -> &mut T {
74 assert!(size_of::<T>() <= size_of::<Self>());
75 &mut *(self as *mut Self as *mut T)
78 }
79}
80
81impl std::fmt::Debug for SockAddrStorage {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 f.debug_struct("sockaddr_storage")
84 .field("ss_family", &self.storage.ss_family)
85 .finish_non_exhaustive()
86 }
87}
88
89#[derive(Clone)]
94pub struct SockAddr {
95 storage: sockaddr_storage,
96 len: socklen_t,
97}
98
99#[allow(clippy::len_without_is_empty)]
100impl SockAddr {
101 pub const unsafe fn new(storage: SockAddrStorage, len: socklen_t) -> SockAddr {
146 SockAddr {
147 storage: storage.storage,
148 len: len as socklen_t,
149 }
150 }
151
152 pub unsafe fn try_init<F, T>(init: F) -> io::Result<(T, SockAddr)>
198 where
199 F: FnOnce(*mut SockAddrStorage, *mut socklen_t) -> io::Result<T>,
200 {
201 const STORAGE_SIZE: socklen_t = size_of::<sockaddr_storage>() as socklen_t;
202 let mut storage = SockAddrStorage::zeroed();
208 let mut len = STORAGE_SIZE;
209 init(&mut storage, &mut len).map(|res| {
210 debug_assert!(len <= STORAGE_SIZE, "overflown address storage");
211 (res, SockAddr::new(storage, len))
212 })
213 }
214
215 #[cfg(not(target_os = "wasi"))]
219 pub fn unix<P>(path: P) -> io::Result<SockAddr>
220 where
221 P: AsRef<Path>,
222 {
223 crate::sys::unix_sockaddr(path.as_ref())
224 }
225
226 pub unsafe fn set_length(&mut self, length: socklen_t) {
233 self.len = length;
234 }
235
236 pub const fn family(&self) -> sa_family_t {
238 self.storage.ss_family
239 }
240
241 pub const fn domain(&self) -> Domain {
243 Domain(self.storage.ss_family as c_int)
244 }
245
246 pub const fn len(&self) -> socklen_t {
248 self.len
249 }
250
251 pub const fn as_ptr(&self) -> *const SockAddrStorage {
253 &self.storage as *const sockaddr_storage as *const SockAddrStorage
254 }
255
256 pub const fn as_storage(self) -> SockAddrStorage {
258 SockAddrStorage {
259 storage: self.storage,
260 }
261 }
262
263 pub const fn is_ipv4(&self) -> bool {
265 self.storage.ss_family == AF_INET as sa_family_t
266 }
267
268 pub const fn is_ipv6(&self) -> bool {
271 self.storage.ss_family == AF_INET6 as sa_family_t
272 }
273
274 #[cfg(not(target_os = "wasi"))]
277 pub fn is_unix(&self) -> bool {
278 self.storage.ss_family == AF_UNIX as sa_family_t
279 }
280
281 pub fn as_socket(&self) -> Option<SocketAddr> {
284 if self.storage.ss_family == AF_INET as sa_family_t {
285 let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in>()) };
288 let ip = crate::sys::from_in_addr(addr.sin_addr);
289 let port = u16::from_be(addr.sin_port);
290 Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
291 } else if self.storage.ss_family == AF_INET6 as sa_family_t {
292 let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in6>()) };
295 let ip = crate::sys::from_in6_addr(addr.sin6_addr);
296 let port = u16::from_be(addr.sin6_port);
297 Some(SocketAddr::V6(SocketAddrV6::new(
298 ip,
299 port,
300 addr.sin6_flowinfo,
301 #[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
302 addr.sin6_scope_id,
303 #[cfg(windows)]
304 unsafe {
305 addr.Anonymous.sin6_scope_id
306 },
307 )))
308 } else {
309 None
310 }
311 }
312
313 pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
316 match self.as_socket() {
317 Some(SocketAddr::V4(addr)) => Some(addr),
318 _ => None,
319 }
320 }
321
322 pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
325 match self.as_socket() {
326 Some(SocketAddr::V6(addr)) => Some(addr),
327 _ => None,
328 }
329 }
330
331 fn as_bytes(&self) -> &[u8] {
333 unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) }
337 }
338}
339
340impl From<SocketAddr> for SockAddr {
341 fn from(addr: SocketAddr) -> SockAddr {
342 match addr {
343 SocketAddr::V4(addr) => addr.into(),
344 SocketAddr::V6(addr) => addr.into(),
345 }
346 }
347}
348
349impl From<SocketAddrV4> for SockAddr {
350 fn from(addr: SocketAddrV4) -> SockAddr {
351 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
353 let len = {
354 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in>() };
355 storage.sin_family = AF_INET as sa_family_t;
356 storage.sin_port = addr.port().to_be();
357 storage.sin_addr = crate::sys::to_in_addr(addr.ip());
358 #[cfg(not(target_os = "wasi"))]
359 {
360 storage.sin_zero = Default::default();
361 }
362 mem::size_of::<sockaddr_in>() as socklen_t
363 };
364 #[cfg(any(
365 target_os = "dragonfly",
366 target_os = "freebsd",
367 target_os = "haiku",
368 target_os = "hermit",
369 target_os = "ios",
370 target_os = "visionos",
371 target_os = "macos",
372 target_os = "netbsd",
373 target_os = "nto",
374 target_os = "openbsd",
375 target_os = "tvos",
376 target_os = "vxworks",
377 target_os = "watchos",
378 ))]
379 {
380 storage.ss_len = len as u8;
381 }
382 SockAddr { storage, len }
383 }
384}
385
386impl From<SocketAddrV6> for SockAddr {
387 fn from(addr: SocketAddrV6) -> SockAddr {
388 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
390 let len = {
391 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in6>() };
392 storage.sin6_family = AF_INET6 as sa_family_t;
393 storage.sin6_port = addr.port().to_be();
394 storage.sin6_addr = crate::sys::to_in6_addr(addr.ip());
395 storage.sin6_flowinfo = addr.flowinfo();
396 #[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
397 {
398 storage.sin6_scope_id = addr.scope_id();
399 }
400 #[cfg(windows)]
401 {
402 storage.Anonymous = SOCKADDR_IN6_0 {
403 sin6_scope_id: addr.scope_id(),
404 };
405 }
406 mem::size_of::<sockaddr_in6>() as socklen_t
407 };
408 #[cfg(any(
409 target_os = "dragonfly",
410 target_os = "freebsd",
411 target_os = "haiku",
412 target_os = "hermit",
413 target_os = "ios",
414 target_os = "visionos",
415 target_os = "macos",
416 target_os = "netbsd",
417 target_os = "nto",
418 target_os = "openbsd",
419 target_os = "tvos",
420 target_os = "vxworks",
421 target_os = "watchos",
422 ))]
423 {
424 storage.ss_len = len as u8;
425 }
426 SockAddr { storage, len }
427 }
428}
429
430impl fmt::Debug for SockAddr {
431 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
432 let mut f = fmt.debug_struct("SockAddr");
433 #[cfg(any(
434 target_os = "dragonfly",
435 target_os = "freebsd",
436 target_os = "haiku",
437 target_os = "hermit",
438 target_os = "ios",
439 target_os = "visionos",
440 target_os = "macos",
441 target_os = "netbsd",
442 target_os = "nto",
443 target_os = "openbsd",
444 target_os = "tvos",
445 target_os = "vxworks",
446 target_os = "watchos",
447 ))]
448 f.field("ss_len", &self.storage.ss_len);
449 f.field("ss_family", &self.storage.ss_family)
450 .field("len", &self.len)
451 .finish()
452 }
453}
454
455impl PartialEq for SockAddr {
456 fn eq(&self, other: &Self) -> bool {
457 self.as_bytes() == other.as_bytes()
458 }
459}
460
461impl Eq for SockAddr {}
462
463impl Hash for SockAddr {
464 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
465 self.as_bytes().hash(state);
466 }
467}
468
469#[cfg(test)]
470mod tests {
471 use super::*;
472
473 #[test]
474 fn ipv4() {
475 use std::net::Ipv4Addr;
476 let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
477 let addr = SockAddr::from(std);
478 assert!(addr.is_ipv4());
479 assert!(!addr.is_ipv6());
480 #[cfg(not(target_os = "wasi"))]
481 assert!(!addr.is_unix());
482 assert_eq!(addr.family(), AF_INET as sa_family_t);
483 assert_eq!(addr.domain(), Domain::IPV4);
484 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
485 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
486 assert_eq!(addr.as_socket_ipv4(), Some(std));
487 assert!(addr.as_socket_ipv6().is_none());
488
489 let addr = SockAddr::from(SocketAddr::from(std));
490 assert_eq!(addr.family(), AF_INET as sa_family_t);
491 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
492 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
493 assert_eq!(addr.as_socket_ipv4(), Some(std));
494 assert!(addr.as_socket_ipv6().is_none());
495 #[cfg(all(unix, not(target_os = "wasi")))]
496 {
497 assert!(addr.as_pathname().is_none());
498 assert!(addr.as_abstract_namespace().is_none());
499 }
500 }
501
502 #[test]
503 fn ipv6() {
504 use std::net::Ipv6Addr;
505 let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
506 let addr = SockAddr::from(std);
507 assert!(addr.is_ipv6());
508 assert!(!addr.is_ipv4());
509 #[cfg(not(target_os = "wasi"))]
510 assert!(!addr.is_unix());
511 assert_eq!(addr.family(), AF_INET6 as sa_family_t);
512 assert_eq!(addr.domain(), Domain::IPV6);
513 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
514 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
515 assert!(addr.as_socket_ipv4().is_none());
516 assert_eq!(addr.as_socket_ipv6(), Some(std));
517
518 let addr = SockAddr::from(SocketAddr::from(std));
519 assert_eq!(addr.family(), AF_INET6 as sa_family_t);
520 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
521 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
522 assert!(addr.as_socket_ipv4().is_none());
523 assert_eq!(addr.as_socket_ipv6(), Some(std));
524 #[cfg(all(unix, not(target_os = "wasi")))]
525 {
526 assert!(addr.as_pathname().is_none());
527 assert!(addr.as_abstract_namespace().is_none());
528 }
529 }
530
531 #[test]
532 fn ipv4_eq() {
533 use std::net::Ipv4Addr;
534
535 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
536 let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
537
538 test_eq(
539 SockAddr::from(std1),
540 SockAddr::from(std1),
541 SockAddr::from(std2),
542 );
543 }
544
545 #[test]
546 fn ipv4_hash() {
547 use std::net::Ipv4Addr;
548
549 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
550 let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
551
552 test_hash(
553 SockAddr::from(std1),
554 SockAddr::from(std1),
555 SockAddr::from(std2),
556 );
557 }
558
559 #[test]
560 fn ipv6_eq() {
561 use std::net::Ipv6Addr;
562
563 let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
564 let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
565
566 test_eq(
567 SockAddr::from(std1),
568 SockAddr::from(std1),
569 SockAddr::from(std2),
570 );
571 }
572
573 #[test]
574 fn ipv6_hash() {
575 use std::net::Ipv6Addr;
576
577 let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
578 let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
579
580 test_hash(
581 SockAddr::from(std1),
582 SockAddr::from(std1),
583 SockAddr::from(std2),
584 );
585 }
586
587 #[test]
588 fn ipv4_ipv6_eq() {
589 use std::net::Ipv4Addr;
590 use std::net::Ipv6Addr;
591
592 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
593 let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
594
595 test_eq(
596 SockAddr::from(std1),
597 SockAddr::from(std1),
598 SockAddr::from(std2),
599 );
600
601 test_eq(
602 SockAddr::from(std2),
603 SockAddr::from(std2),
604 SockAddr::from(std1),
605 );
606 }
607
608 #[test]
609 fn ipv4_ipv6_hash() {
610 use std::net::Ipv4Addr;
611 use std::net::Ipv6Addr;
612
613 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
614 let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
615
616 test_hash(
617 SockAddr::from(std1),
618 SockAddr::from(std1),
619 SockAddr::from(std2),
620 );
621
622 test_hash(
623 SockAddr::from(std2),
624 SockAddr::from(std2),
625 SockAddr::from(std1),
626 );
627 }
628
629 #[allow(clippy::eq_op)] fn test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr) {
631 assert!(a0 == a0);
632 assert!(a0 == a1);
633 assert!(a1 == a0);
634 assert!(a0 != b);
635 assert!(b != a0);
636 }
637
638 fn test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr) {
639 assert!(calculate_hash(&a0) == calculate_hash(&a0));
640 assert!(calculate_hash(&a0) == calculate_hash(&a1));
641 assert!(calculate_hash(&a0) != calculate_hash(&b));
643 }
644
645 fn calculate_hash(x: &SockAddr) -> u64 {
646 use std::collections::hash_map::DefaultHasher;
647 use std::hash::Hasher;
648
649 let mut hasher = DefaultHasher::new();
650 x.hash(&mut hasher);
651 hasher.finish()
652 }
653}