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/// The address of a socket.
17///
18/// `SockAddr`s may be constructed directly to and from the standard library
19/// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types.
20#[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 /// Create a `SockAddr` from the underlying storage and its length.
29 ///
30 /// # Safety
31 ///
32 /// Caller must ensure that the address family and length match the type of
33 /// storage address. For example if `storage.ss_family` is set to `AF_INET`
34 /// the `storage` must be initialised as `sockaddr_in`, setting the content
35 /// and length appropriately.
36 ///
37 /// # Examples
38 ///
39 /// ```
40 /// # fn main() -> std::io::Result<()> {
41 /// # #[cfg(unix)] {
42 /// use std::io;
43 /// use std::mem;
44 /// use std::os::unix::io::AsRawFd;
45 ///
46 /// use socket2::{SockAddr, Socket, Domain, Type};
47 ///
48 /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
49 ///
50 /// // Initialise a `SocketAddr` byte calling `getsockname(2)`.
51 /// let mut addr_storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
52 /// let mut len = mem::size_of_val(&addr_storage) as libc::socklen_t;
53 ///
54 /// // The `getsockname(2)` system call will intiliase `storage` for
55 /// // us, setting `len` to the correct length.
56 /// let res = unsafe {
57 /// libc::getsockname(
58 /// socket.as_raw_fd(),
59 /// (&mut addr_storage as *mut libc::sockaddr_storage).cast(),
60 /// &mut len,
61 /// )
62 /// };
63 /// if res == -1 {
64 /// return Err(io::Error::last_os_error());
65 /// }
66 ///
67 /// let address = unsafe { SockAddr::new(addr_storage, len) };
68 /// # drop(address);
69 /// # }
70 /// # Ok(())
71 /// # }
72 /// ```
73 pub const unsafe fn new(storage: sockaddr_storage, len: socklen_t) -> SockAddr {
74 SockAddr { storage, len }
75 }
76
77 /// Initialise a `SockAddr` by calling the function `init`.
78 ///
79 /// The type of the address storage and length passed to the function `init`
80 /// is OS/architecture specific.
81 ///
82 /// The address is zeroed before `init` is called and is thus valid to
83 /// dereference and read from. The length initialised to the maximum length
84 /// of the storage.
85 ///
86 /// # Safety
87 ///
88 /// Caller must ensure that the address family and length match the type of
89 /// storage address. For example if `storage.ss_family` is set to `AF_INET`
90 /// the `storage` must be initialised as `sockaddr_in`, setting the content
91 /// and length appropriately.
92 ///
93 /// # Examples
94 ///
95 /// ```
96 /// # fn main() -> std::io::Result<()> {
97 /// # #[cfg(unix)] {
98 /// use std::io;
99 /// use std::os::unix::io::AsRawFd;
100 ///
101 /// use socket2::{SockAddr, Socket, Domain, Type};
102 ///
103 /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
104 ///
105 /// // Initialise a `SocketAddr` byte calling `getsockname(2)`.
106 /// let (_, address) = unsafe {
107 /// SockAddr::try_init(|addr_storage, len| {
108 /// // The `getsockname(2)` system call will intiliase `storage` for
109 /// // us, setting `len` to the correct length.
110 /// if libc::getsockname(socket.as_raw_fd(), addr_storage.cast(), len) == -1 {
111 /// Err(io::Error::last_os_error())
112 /// } else {
113 /// Ok(())
114 /// }
115 /// })
116 /// }?;
117 /// # drop(address);
118 /// # }
119 /// # Ok(())
120 /// # }
121 /// ```
122 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 // NOTE: `SockAddr::unix` depends on the storage being zeroed before
128 // calling `init`.
129 // NOTE: calling `recvfrom` with an empty buffer also depends on the
130 // storage being zeroed before calling `init` as the OS might not
131 // initialise it.
132 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 // Safety: zeroed-out `sockaddr_storage` is valid, caller must
138 // ensure at least `len` bytes are valid.
139 storage: storage.assume_init(),
140 len,
141 };
142 (res, addr)
143 })
144 }
145
146 /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
147 ///
148 /// Returns an error if the path is longer than `SUN_LEN`.
149 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 /// Set the length of the address.
157 ///
158 /// # Safety
159 ///
160 /// Caller must ensure that the address up to `length` bytes are properly
161 /// initialised.
162 pub unsafe fn set_length(&mut self, length: socklen_t) {
163 self.len = length;
164 }
165
166 /// Returns this address's family.
167 pub const fn family(&self) -> sa_family_t {
168 self.storage.ss_family
169 }
170
171 /// Returns this address's `Domain`.
172 pub const fn domain(&self) -> Domain {
173 Domain(self.storage.ss_family as c_int)
174 }
175
176 /// Returns the size of this address in bytes.
177 pub const fn len(&self) -> socklen_t {
178 self.len
179 }
180
181 /// Returns a raw pointer to the address.
182 pub const fn as_ptr(&self) -> *const sockaddr {
183 ptr::addr_of!(self.storage).cast()
184 }
185
186 /// Retuns the address as the storage.
187 pub const fn as_storage(self) -> sockaddr_storage {
188 self.storage
189 }
190
191 /// Returns true if this address is in the `AF_INET` (IPv4) family, false otherwise.
192 pub const fn is_ipv4(&self) -> bool {
193 self.storage.ss_family == AF_INET as sa_family_t
194 }
195
196 /// Returns true if this address is in the `AF_INET6` (IPv6) family, false
197 /// otherwise.
198 pub const fn is_ipv6(&self) -> bool {
199 self.storage.ss_family == AF_INET6 as sa_family_t
200 }
201
202 /// Returns true if this address is of a unix socket (for local interprocess communication),
203 /// i.e. it is from the `AF_UNIX` family, false otherwise.
204 pub fn is_unix(&self) -> bool {
205 self.storage.ss_family == AF_UNIX as sa_family_t
206 }
207
208 /// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4)
209 /// or `AF_INET6` (IPv6) family, otherwise returns `None`.
210 pub fn as_socket(&self) -> Option<SocketAddr> {
211 if self.storage.ss_family == AF_INET as sa_family_t {
212 // SAFETY: if the `ss_family` field is `AF_INET` then storage must
213 // be a `sockaddr_in`.
214 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 // SAFETY: if the `ss_family` field is `AF_INET6` then storage must
220 // be a `sockaddr_in6`.
221 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 /// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET`
241 /// family.
242 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 /// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6`
250 /// family.
251 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 /// Returns the initialised storage bytes.
259 fn as_bytes(&self) -> &[u8] {
260 // SAFETY: `self.storage` is a C struct which can always be treated a
261 // slice of bytes. Futhermore we ensure we don't read any unitialised
262 // bytes by using `self.len`.
263 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 // SAFETY: a `sockaddr_storage` of all zeros is valid.
279 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 = "macos",
295 target_os = "netbsd",
296 target_os = "nto",
297 target_os = "openbsd",
298 target_os = "tvos",
299 target_os = "vxworks",
300 target_os = "watchos",
301 ))]
302 {
303 storage.ss_len = len as u8;
304 }
305 SockAddr { storage, len }
306 }
307}
308
309impl From<SocketAddrV6> for SockAddr {
310 fn from(addr: SocketAddrV6) -> SockAddr {
311 // SAFETY: a `sockaddr_storage` of all zeros is valid.
312 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() };
313 let len = {
314 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in6>() };
315 storage.sin6_family = AF_INET6 as sa_family_t;
316 storage.sin6_port = addr.port().to_be();
317 storage.sin6_addr = crate::sys::to_in6_addr(addr.ip());
318 storage.sin6_flowinfo = addr.flowinfo();
319 #[cfg(unix)]
320 {
321 storage.sin6_scope_id = addr.scope_id();
322 }
323 #[cfg(windows)]
324 {
325 storage.Anonymous = SOCKADDR_IN6_0 {
326 sin6_scope_id: addr.scope_id(),
327 };
328 }
329 mem::size_of::<sockaddr_in6>() as socklen_t
330 };
331 #[cfg(any(
332 target_os = "dragonfly",
333 target_os = "freebsd",
334 target_os = "haiku",
335 target_os = "hermit",
336 target_os = "ios",
337 target_os = "macos",
338 target_os = "netbsd",
339 target_os = "nto",
340 target_os = "openbsd",
341 target_os = "tvos",
342 target_os = "vxworks",
343 target_os = "watchos",
344 ))]
345 {
346 storage.ss_len = len as u8;
347 }
348 SockAddr { storage, len }
349 }
350}
351
352impl fmt::Debug for SockAddr {
353 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
354 let mut f = fmt.debug_struct("SockAddr");
355 #[cfg(any(
356 target_os = "dragonfly",
357 target_os = "freebsd",
358 target_os = "haiku",
359 target_os = "hermit",
360 target_os = "ios",
361 target_os = "macos",
362 target_os = "netbsd",
363 target_os = "nto",
364 target_os = "openbsd",
365 target_os = "tvos",
366 target_os = "vxworks",
367 target_os = "watchos",
368 ))]
369 f.field("ss_len", &self.storage.ss_len);
370 f.field("ss_family", &self.storage.ss_family)
371 .field("len", &self.len)
372 .finish()
373 }
374}
375
376impl PartialEq for SockAddr {
377 fn eq(&self, other: &Self) -> bool {
378 self.as_bytes() == other.as_bytes()
379 }
380}
381
382impl Eq for SockAddr {}
383
384impl Hash for SockAddr {
385 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
386 self.as_bytes().hash(state);
387 }
388}
389
390#[cfg(test)]
391mod tests {
392 use super::*;
393
394 #[test]
395 fn ipv4() {
396 use std::net::Ipv4Addr;
397 let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
398 let addr = SockAddr::from(std);
399 assert!(addr.is_ipv4());
400 assert!(!addr.is_ipv6());
401 assert!(!addr.is_unix());
402 assert_eq!(addr.family(), AF_INET as sa_family_t);
403 assert_eq!(addr.domain(), Domain::IPV4);
404 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
405 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
406 assert_eq!(addr.as_socket_ipv4(), Some(std));
407 assert!(addr.as_socket_ipv6().is_none());
408
409 let addr = SockAddr::from(SocketAddr::from(std));
410 assert_eq!(addr.family(), AF_INET as sa_family_t);
411 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
412 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
413 assert_eq!(addr.as_socket_ipv4(), Some(std));
414 assert!(addr.as_socket_ipv6().is_none());
415 #[cfg(unix)]
416 {
417 assert!(addr.as_pathname().is_none());
418 assert!(addr.as_abstract_namespace().is_none());
419 }
420 }
421
422 #[test]
423 fn ipv6() {
424 use std::net::Ipv6Addr;
425 let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
426 let addr = SockAddr::from(std);
427 assert!(addr.is_ipv6());
428 assert!(!addr.is_ipv4());
429 assert!(!addr.is_unix());
430 assert_eq!(addr.family(), AF_INET6 as sa_family_t);
431 assert_eq!(addr.domain(), Domain::IPV6);
432 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
433 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
434 assert!(addr.as_socket_ipv4().is_none());
435 assert_eq!(addr.as_socket_ipv6(), Some(std));
436
437 let addr = SockAddr::from(SocketAddr::from(std));
438 assert_eq!(addr.family(), AF_INET6 as sa_family_t);
439 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
440 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
441 assert!(addr.as_socket_ipv4().is_none());
442 assert_eq!(addr.as_socket_ipv6(), Some(std));
443 #[cfg(unix)]
444 {
445 assert!(addr.as_pathname().is_none());
446 assert!(addr.as_abstract_namespace().is_none());
447 }
448 }
449
450 #[test]
451 fn ipv4_eq() {
452 use std::net::Ipv4Addr;
453
454 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
455 let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
456
457 test_eq(
458 SockAddr::from(std1),
459 SockAddr::from(std1),
460 SockAddr::from(std2),
461 );
462 }
463
464 #[test]
465 fn ipv4_hash() {
466 use std::net::Ipv4Addr;
467
468 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
469 let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
470
471 test_hash(
472 SockAddr::from(std1),
473 SockAddr::from(std1),
474 SockAddr::from(std2),
475 );
476 }
477
478 #[test]
479 fn ipv6_eq() {
480 use std::net::Ipv6Addr;
481
482 let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
483 let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
484
485 test_eq(
486 SockAddr::from(std1),
487 SockAddr::from(std1),
488 SockAddr::from(std2),
489 );
490 }
491
492 #[test]
493 fn ipv6_hash() {
494 use std::net::Ipv6Addr;
495
496 let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
497 let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
498
499 test_hash(
500 SockAddr::from(std1),
501 SockAddr::from(std1),
502 SockAddr::from(std2),
503 );
504 }
505
506 #[test]
507 fn ipv4_ipv6_eq() {
508 use std::net::Ipv4Addr;
509 use std::net::Ipv6Addr;
510
511 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
512 let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
513
514 test_eq(
515 SockAddr::from(std1),
516 SockAddr::from(std1),
517 SockAddr::from(std2),
518 );
519
520 test_eq(
521 SockAddr::from(std2),
522 SockAddr::from(std2),
523 SockAddr::from(std1),
524 );
525 }
526
527 #[test]
528 fn ipv4_ipv6_hash() {
529 use std::net::Ipv4Addr;
530 use std::net::Ipv6Addr;
531
532 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
533 let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
534
535 test_hash(
536 SockAddr::from(std1),
537 SockAddr::from(std1),
538 SockAddr::from(std2),
539 );
540
541 test_hash(
542 SockAddr::from(std2),
543 SockAddr::from(std2),
544 SockAddr::from(std1),
545 );
546 }
547
548 #[allow(clippy::eq_op)] // allow a0 == a0 check
549 fn test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr) {
550 assert!(a0 == a0);
551 assert!(a0 == a1);
552 assert!(a1 == a0);
553 assert!(a0 != b);
554 assert!(b != a0);
555 }
556
557 fn test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr) {
558 assert!(calculate_hash(&a0) == calculate_hash(&a0));
559 assert!(calculate_hash(&a0) == calculate_hash(&a1));
560 // technically unequal values can have the same hash, in this case x != z and both have different hashes
561 assert!(calculate_hash(&a0) != calculate_hash(&b));
562 }
563
564 fn calculate_hash(x: &SockAddr) -> u64 {
565 use std::collections::hash_map::DefaultHasher;
566 use std::hash::Hasher;
567
568 let mut hasher = DefaultHasher::new();
569 x.hash(&mut hasher);
570 hasher.finish()
571 }
572}
573