1use std::hash::Hash;
2use std::mem::{self, size_of, MaybeUninit};
3use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
4use std::path::Path;
5use std::{fmt, io, ptr};
6
7#[cfg(windows)]
8use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0;
9
10use crate::sys::{
11 c_int, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET,
12 AF_INET6, AF_UNIX,
13};
14use crate::Domain;
15
16#[derive(Clone)]
21pub struct SockAddr {
22 storage: sockaddr_storage,
23 len: socklen_t,
24}
25
26#[allow(clippy::len_without_is_empty)]
27impl SockAddr {
28 pub const unsafe fn new(storage: sockaddr_storage, len: socklen_t) -> SockAddr {
74 SockAddr { storage, len }
75 }
76
77 pub unsafe fn try_init<F, T>(init: F) -> io::Result<(T, SockAddr)>
123 where
124 F: FnOnce(*mut sockaddr_storage, *mut socklen_t) -> io::Result<T>,
125 {
126 const STORAGE_SIZE: socklen_t = size_of::<sockaddr_storage>() as socklen_t;
127 let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
133 let mut len = STORAGE_SIZE;
134 init(storage.as_mut_ptr(), &mut len).map(|res| {
135 debug_assert!(len <= STORAGE_SIZE, "overflown address storage");
136 let addr = SockAddr {
137 storage: storage.assume_init(),
140 len,
141 };
142 (res, addr)
143 })
144 }
145
146 pub fn unix<P>(path: P) -> io::Result<SockAddr>
150 where
151 P: AsRef<Path>,
152 {
153 crate::sys::unix_sockaddr(path.as_ref())
154 }
155
156 pub unsafe fn set_length(&mut self, length: socklen_t) {
163 self.len = length;
164 }
165
166 pub const fn family(&self) -> sa_family_t {
168 self.storage.ss_family
169 }
170
171 pub const fn domain(&self) -> Domain {
173 Domain(self.storage.ss_family as c_int)
174 }
175
176 pub const fn len(&self) -> socklen_t {
178 self.len
179 }
180
181 pub const fn as_ptr(&self) -> *const sockaddr {
183 ptr::addr_of!(self.storage).cast()
184 }
185
186 pub const fn as_storage(self) -> sockaddr_storage {
188 self.storage
189 }
190
191 pub const fn is_ipv4(&self) -> bool {
193 self.storage.ss_family == AF_INET as sa_family_t
194 }
195
196 pub const fn is_ipv6(&self) -> bool {
199 self.storage.ss_family == AF_INET6 as sa_family_t
200 }
201
202 pub fn is_unix(&self) -> bool {
205 self.storage.ss_family == AF_UNIX as sa_family_t
206 }
207
208 pub fn as_socket(&self) -> Option<SocketAddr> {
211 if self.storage.ss_family == AF_INET as sa_family_t {
212 let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in>()) };
215 let ip = crate::sys::from_in_addr(addr.sin_addr);
216 let port = u16::from_be(addr.sin_port);
217 Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
218 } else if self.storage.ss_family == AF_INET6 as sa_family_t {
219 let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in6>()) };
222 let ip = crate::sys::from_in6_addr(addr.sin6_addr);
223 let port = u16::from_be(addr.sin6_port);
224 Some(SocketAddr::V6(SocketAddrV6::new(
225 ip,
226 port,
227 addr.sin6_flowinfo,
228 #[cfg(unix)]
229 addr.sin6_scope_id,
230 #[cfg(windows)]
231 unsafe {
232 addr.Anonymous.sin6_scope_id
233 },
234 )))
235 } else {
236 None
237 }
238 }
239
240 pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
243 match self.as_socket() {
244 Some(SocketAddr::V4(addr)) => Some(addr),
245 _ => None,
246 }
247 }
248
249 pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
252 match self.as_socket() {
253 Some(SocketAddr::V6(addr)) => Some(addr),
254 _ => None,
255 }
256 }
257
258 fn as_bytes(&self) -> &[u8] {
260 unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) }
264 }
265}
266
267impl From<SocketAddr> for SockAddr {
268 fn from(addr: SocketAddr) -> SockAddr {
269 match addr {
270 SocketAddr::V4(addr) => addr.into(),
271 SocketAddr::V6(addr) => addr.into(),
272 }
273 }
274}
275
276impl From<SocketAddrV4> for SockAddr {
277 fn from(addr: SocketAddrV4) -> SockAddr {
278 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
280 let len = {
281 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in>() };
282 storage.sin_family = AF_INET as sa_family_t;
283 storage.sin_port = addr.port().to_be();
284 storage.sin_addr = crate::sys::to_in_addr(addr.ip());
285 storage.sin_zero = Default::default();
286 mem::size_of::<sockaddr_in>() as socklen_t
287 };
288 #[cfg(any(
289 target_os = "dragonfly",
290 target_os = "freebsd",
291 target_os = "haiku",
292 target_os = "hermit",
293 target_os = "ios",
294 target_os = "visionos",
295 target_os = "macos",
296 target_os = "netbsd",
297 target_os = "nto",
298 target_os = "openbsd",
299 target_os = "tvos",
300 target_os = "vxworks",
301 target_os = "watchos",
302 ))]
303 {
304 storage.ss_len = len as u8;
305 }
306 SockAddr { storage, len }
307 }
308}
309
310impl From<SocketAddrV6> for SockAddr {
311 fn from(addr: SocketAddrV6) -> SockAddr {
312 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
314 let len = {
315 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in6>() };
316 storage.sin6_family = AF_INET6 as sa_family_t;
317 storage.sin6_port = addr.port().to_be();
318 storage.sin6_addr = crate::sys::to_in6_addr(addr.ip());
319 storage.sin6_flowinfo = addr.flowinfo();
320 #[cfg(unix)]
321 {
322 storage.sin6_scope_id = addr.scope_id();
323 }
324 #[cfg(windows)]
325 {
326 storage.Anonymous = SOCKADDR_IN6_0 {
327 sin6_scope_id: addr.scope_id(),
328 };
329 }
330 mem::size_of::<sockaddr_in6>() as socklen_t
331 };
332 #[cfg(any(
333 target_os = "dragonfly",
334 target_os = "freebsd",
335 target_os = "haiku",
336 target_os = "hermit",
337 target_os = "ios",
338 target_os = "visionos",
339 target_os = "macos",
340 target_os = "netbsd",
341 target_os = "nto",
342 target_os = "openbsd",
343 target_os = "tvos",
344 target_os = "vxworks",
345 target_os = "watchos",
346 ))]
347 {
348 storage.ss_len = len as u8;
349 }
350 SockAddr { storage, len }
351 }
352}
353
354impl fmt::Debug for SockAddr {
355 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
356 let mut f = fmt.debug_struct("SockAddr");
357 #[cfg(any(
358 target_os = "dragonfly",
359 target_os = "freebsd",
360 target_os = "haiku",
361 target_os = "hermit",
362 target_os = "ios",
363 target_os = "visionos",
364 target_os = "macos",
365 target_os = "netbsd",
366 target_os = "nto",
367 target_os = "openbsd",
368 target_os = "tvos",
369 target_os = "vxworks",
370 target_os = "watchos",
371 ))]
372 f.field("ss_len", &self.storage.ss_len);
373 f.field("ss_family", &self.storage.ss_family)
374 .field("len", &self.len)
375 .finish()
376 }
377}
378
379impl PartialEq for SockAddr {
380 fn eq(&self, other: &Self) -> bool {
381 self.as_bytes() == other.as_bytes()
382 }
383}
384
385impl Eq for SockAddr {}
386
387impl Hash for SockAddr {
388 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
389 self.as_bytes().hash(state);
390 }
391}
392
393#[cfg(test)]
394mod tests {
395 use super::*;
396
397 #[test]
398 fn ipv4() {
399 use std::net::Ipv4Addr;
400 let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
401 let addr = SockAddr::from(std);
402 assert!(addr.is_ipv4());
403 assert!(!addr.is_ipv6());
404 assert!(!addr.is_unix());
405 assert_eq!(addr.family(), AF_INET as sa_family_t);
406 assert_eq!(addr.domain(), Domain::IPV4);
407 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
408 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
409 assert_eq!(addr.as_socket_ipv4(), Some(std));
410 assert!(addr.as_socket_ipv6().is_none());
411
412 let addr = SockAddr::from(SocketAddr::from(std));
413 assert_eq!(addr.family(), AF_INET as sa_family_t);
414 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
415 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
416 assert_eq!(addr.as_socket_ipv4(), Some(std));
417 assert!(addr.as_socket_ipv6().is_none());
418 #[cfg(unix)]
419 {
420 assert!(addr.as_pathname().is_none());
421 assert!(addr.as_abstract_namespace().is_none());
422 }
423 }
424
425 #[test]
426 fn ipv6() {
427 use std::net::Ipv6Addr;
428 let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
429 let addr = SockAddr::from(std);
430 assert!(addr.is_ipv6());
431 assert!(!addr.is_ipv4());
432 assert!(!addr.is_unix());
433 assert_eq!(addr.family(), AF_INET6 as sa_family_t);
434 assert_eq!(addr.domain(), Domain::IPV6);
435 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
436 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
437 assert!(addr.as_socket_ipv4().is_none());
438 assert_eq!(addr.as_socket_ipv6(), Some(std));
439
440 let addr = SockAddr::from(SocketAddr::from(std));
441 assert_eq!(addr.family(), AF_INET6 as sa_family_t);
442 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
443 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
444 assert!(addr.as_socket_ipv4().is_none());
445 assert_eq!(addr.as_socket_ipv6(), Some(std));
446 #[cfg(unix)]
447 {
448 assert!(addr.as_pathname().is_none());
449 assert!(addr.as_abstract_namespace().is_none());
450 }
451 }
452
453 #[test]
454 fn ipv4_eq() {
455 use std::net::Ipv4Addr;
456
457 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
458 let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
459
460 test_eq(
461 SockAddr::from(std1),
462 SockAddr::from(std1),
463 SockAddr::from(std2),
464 );
465 }
466
467 #[test]
468 fn ipv4_hash() {
469 use std::net::Ipv4Addr;
470
471 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
472 let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
473
474 test_hash(
475 SockAddr::from(std1),
476 SockAddr::from(std1),
477 SockAddr::from(std2),
478 );
479 }
480
481 #[test]
482 fn ipv6_eq() {
483 use std::net::Ipv6Addr;
484
485 let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
486 let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
487
488 test_eq(
489 SockAddr::from(std1),
490 SockAddr::from(std1),
491 SockAddr::from(std2),
492 );
493 }
494
495 #[test]
496 fn ipv6_hash() {
497 use std::net::Ipv6Addr;
498
499 let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
500 let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
501
502 test_hash(
503 SockAddr::from(std1),
504 SockAddr::from(std1),
505 SockAddr::from(std2),
506 );
507 }
508
509 #[test]
510 fn ipv4_ipv6_eq() {
511 use std::net::Ipv4Addr;
512 use std::net::Ipv6Addr;
513
514 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
515 let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
516
517 test_eq(
518 SockAddr::from(std1),
519 SockAddr::from(std1),
520 SockAddr::from(std2),
521 );
522
523 test_eq(
524 SockAddr::from(std2),
525 SockAddr::from(std2),
526 SockAddr::from(std1),
527 );
528 }
529
530 #[test]
531 fn ipv4_ipv6_hash() {
532 use std::net::Ipv4Addr;
533 use std::net::Ipv6Addr;
534
535 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
536 let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
537
538 test_hash(
539 SockAddr::from(std1),
540 SockAddr::from(std1),
541 SockAddr::from(std2),
542 );
543
544 test_hash(
545 SockAddr::from(std2),
546 SockAddr::from(std2),
547 SockAddr::from(std1),
548 );
549 }
550
551 #[allow(clippy::eq_op)] fn test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr) {
553 assert!(a0 == a0);
554 assert!(a0 == a1);
555 assert!(a1 == a0);
556 assert!(a0 != b);
557 assert!(b != a0);
558 }
559
560 fn test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr) {
561 assert!(calculate_hash(&a0) == calculate_hash(&a0));
562 assert!(calculate_hash(&a0) == calculate_hash(&a1));
563 assert!(calculate_hash(&a0) != calculate_hash(&b));
565 }
566
567 fn calculate_hash(x: &SockAddr) -> u64 {
568 use std::collections::hash_map::DefaultHasher;
569 use std::hash::Hasher;
570
571 let mut hasher = DefaultHasher::new();
572 x.hash(&mut hasher);
573 hasher.finish()
574 }
575}