1use std::mem::{self, size_of, MaybeUninit};
2use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
3use std::{fmt, io};
4
5use crate::sys::{
6 sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET,
7 AF_INET6,
8};
9#[cfg(windows)]
10use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH_u;
11
12/// The address of a socket.
13///
14/// `SockAddr`s may be constructed directly to and from the standard library
15/// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types.
16#[derive(Clone)]
17pub struct SockAddr {
18 storage: sockaddr_storage,
19 len: socklen_t,
20}
21
22#[allow(clippy::len_without_is_empty)]
23impl SockAddr {
24 /// Create a `SockAddr` from the underlying storage and its length.
25 ///
26 /// # Safety
27 ///
28 /// Caller must ensure that the address family and length match the type of
29 /// storage address. For example if `storage.ss_family` is set to `AF_INET`
30 /// the `storage` must be initialised as `sockaddr_in`, setting the content
31 /// and length appropriately.
32 ///
33 /// # Examples
34 ///
35 /// ```
36 /// # fn main() -> std::io::Result<()> {
37 /// # #[cfg(unix)] {
38 /// use std::io;
39 /// use std::mem;
40 /// use std::os::unix::io::AsRawFd;
41 ///
42 /// use socket2::{SockAddr, Socket, Domain, Type};
43 ///
44 /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
45 ///
46 /// // Initialise a `SocketAddr` byte calling `getsockname(2)`.
47 /// let mut addr_storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
48 /// let mut len = mem::size_of_val(&addr_storage) as libc::socklen_t;
49 ///
50 /// // The `getsockname(2)` system call will intiliase `storage` for
51 /// // us, setting `len` to the correct length.
52 /// let res = unsafe {
53 /// libc::getsockname(
54 /// socket.as_raw_fd(),
55 /// (&mut addr_storage as *mut libc::sockaddr_storage).cast(),
56 /// &mut len,
57 /// )
58 /// };
59 /// if res == -1 {
60 /// return Err(io::Error::last_os_error());
61 /// }
62 ///
63 /// let address = unsafe { SockAddr::new(addr_storage, len) };
64 /// # drop(address);
65 /// # }
66 /// # Ok(())
67 /// # }
68 /// ```
69 pub const unsafe fn new(storage: sockaddr_storage, len: socklen_t) -> SockAddr {
70 SockAddr { storage, len }
71 }
72
73 /// Initialise a `SockAddr` by calling the function `init`.
74 ///
75 /// The type of the address storage and length passed to the function `init`
76 /// is OS/architecture specific.
77 ///
78 /// The address is zeroed before `init` is called and is thus valid to
79 /// dereference and read from. The length initialised to the maximum length
80 /// of the storage.
81 ///
82 /// # Safety
83 ///
84 /// Caller must ensure that the address family and length match the type of
85 /// storage address. For example if `storage.ss_family` is set to `AF_INET`
86 /// the `storage` must be initialised as `sockaddr_in`, setting the content
87 /// and length appropriately.
88 ///
89 /// # Examples
90 ///
91 /// ```
92 /// # fn main() -> std::io::Result<()> {
93 /// # #[cfg(unix)] {
94 /// use std::io;
95 /// use std::os::unix::io::AsRawFd;
96 ///
97 /// use socket2::{SockAddr, Socket, Domain, Type};
98 ///
99 /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
100 ///
101 /// // Initialise a `SocketAddr` byte calling `getsockname(2)`.
102 /// let (_, address) = unsafe {
103 /// SockAddr::init(|addr_storage, len| {
104 /// // The `getsockname(2)` system call will intiliase `storage` for
105 /// // us, setting `len` to the correct length.
106 /// if libc::getsockname(socket.as_raw_fd(), addr_storage.cast(), len) == -1 {
107 /// Err(io::Error::last_os_error())
108 /// } else {
109 /// Ok(())
110 /// }
111 /// })
112 /// }?;
113 /// # drop(address);
114 /// # }
115 /// # Ok(())
116 /// # }
117 /// ```
118 pub unsafe fn init<F, T>(init: F) -> io::Result<(T, SockAddr)>
119 where
120 F: FnOnce(*mut sockaddr_storage, *mut socklen_t) -> io::Result<T>,
121 {
122 const STORAGE_SIZE: socklen_t = size_of::<sockaddr_storage>() as socklen_t;
123 // NOTE: `SockAddr::unix` depends on the storage being zeroed before
124 // calling `init`.
125 // NOTE: calling `recvfrom` with an empty buffer also depends on the
126 // storage being zeroed before calling `init` as the OS might not
127 // initialise it.
128 let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
129 let mut len = STORAGE_SIZE;
130 init(storage.as_mut_ptr(), &mut len).map(|res| {
131 debug_assert!(len <= STORAGE_SIZE, "overflown address storage");
132 let addr = SockAddr {
133 // Safety: zeroed-out `sockaddr_storage` is valid, caller must
134 // ensure at least `len` bytes are valid.
135 storage: storage.assume_init(),
136 len,
137 };
138 (res, addr)
139 })
140 }
141
142 /// Returns this address's family.
143 pub const fn family(&self) -> sa_family_t {
144 self.storage.ss_family
145 }
146
147 /// Returns the size of this address in bytes.
148 pub const fn len(&self) -> socklen_t {
149 self.len
150 }
151
152 /// Returns a raw pointer to the address.
153 pub const fn as_ptr(&self) -> *const sockaddr {
154 &self.storage as *const _ as *const _
155 }
156
157 /// Returns a raw pointer to the address storage.
158 #[cfg(all(unix, not(target_os = "redox")))]
159 pub(crate) const fn as_storage_ptr(&self) -> *const sockaddr_storage {
160 &self.storage
161 }
162
163 /// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4)
164 /// or `AF_INET6` (IPv6) family, otherwise returns `None`.
165 pub fn as_socket(&self) -> Option<SocketAddr> {
166 if self.storage.ss_family == AF_INET as sa_family_t {
167 // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in.
168 let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in) };
169
170 let ip = crate::sys::from_in_addr(addr.sin_addr);
171 let port = u16::from_be(addr.sin_port);
172 Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
173 } else if self.storage.ss_family == AF_INET6 as sa_family_t {
174 // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6.
175 let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in6) };
176
177 let ip = crate::sys::from_in6_addr(addr.sin6_addr);
178 let port = u16::from_be(addr.sin6_port);
179 Some(SocketAddr::V6(SocketAddrV6::new(
180 ip,
181 port,
182 addr.sin6_flowinfo,
183 #[cfg(unix)]
184 addr.sin6_scope_id,
185 #[cfg(windows)]
186 unsafe {
187 *addr.u.sin6_scope_id()
188 },
189 )))
190 } else {
191 None
192 }
193 }
194
195 /// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET`
196 /// family.
197 pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> {
198 match self.as_socket() {
199 Some(SocketAddr::V4(addr)) => Some(addr),
200 _ => None,
201 }
202 }
203
204 /// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6`
205 /// family.
206 pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> {
207 match self.as_socket() {
208 Some(SocketAddr::V6(addr)) => Some(addr),
209 _ => None,
210 }
211 }
212}
213
214impl From<SocketAddr> for SockAddr {
215 fn from(addr: SocketAddr) -> SockAddr {
216 match addr {
217 SocketAddr::V4(addr: SocketAddrV4) => addr.into(),
218 SocketAddr::V6(addr: SocketAddrV6) => addr.into(),
219 }
220 }
221}
222
223impl From<SocketAddrV4> for SockAddr {
224 fn from(addr: SocketAddrV4) -> SockAddr {
225 let sockaddr_in = sockaddr_in {
226 sin_family: AF_INET as sa_family_t,
227 sin_port: addr.port().to_be(),
228 sin_addr: crate::sys::to_in_addr(addr.ip()),
229 sin_zero: Default::default(),
230 #[cfg(any(
231 target_os = "dragonfly",
232 target_os = "freebsd",
233 target_os = "haiku",
234 target_os = "ios",
235 target_os = "macos",
236 target_os = "netbsd",
237 target_os = "openbsd"
238 ))]
239 sin_len: 0,
240 };
241 let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
242 // Safety: A `sockaddr_in` is memory compatible with a `sockaddr_storage`
243 unsafe { (storage.as_mut_ptr() as *mut sockaddr_in).write(sockaddr_in) };
244 SockAddr {
245 storage: unsafe { storage.assume_init() },
246 len: mem::size_of::<sockaddr_in>() as socklen_t,
247 }
248 }
249}
250
251impl From<SocketAddrV6> for SockAddr {
252 fn from(addr: SocketAddrV6) -> SockAddr {
253 #[cfg(windows)]
254 let u = unsafe {
255 let mut u = mem::zeroed::<SOCKADDR_IN6_LH_u>();
256 *u.sin6_scope_id_mut() = addr.scope_id();
257 u
258 };
259
260 let sockaddr_in6 = sockaddr_in6 {
261 sin6_family: AF_INET6 as sa_family_t,
262 sin6_port: addr.port().to_be(),
263 sin6_addr: crate::sys::to_in6_addr(addr.ip()),
264 sin6_flowinfo: addr.flowinfo(),
265 #[cfg(unix)]
266 sin6_scope_id: addr.scope_id(),
267 #[cfg(windows)]
268 u,
269 #[cfg(any(
270 target_os = "dragonfly",
271 target_os = "freebsd",
272 target_os = "haiku",
273 target_os = "ios",
274 target_os = "macos",
275 target_os = "netbsd",
276 target_os = "openbsd"
277 ))]
278 sin6_len: 0,
279 #[cfg(any(target_os = "solaris", target_os = "illumos"))]
280 __sin6_src_id: 0,
281 };
282 let mut storage = MaybeUninit::<sockaddr_storage>::zeroed();
283 // Safety: A `sockaddr_in6` is memory compatible with a `sockaddr_storage`
284 unsafe { (storage.as_mut_ptr() as *mut sockaddr_in6).write(sockaddr_in6) };
285 SockAddr {
286 storage: unsafe { storage.assume_init() },
287 len: mem::size_of::<sockaddr_in6>() as socklen_t,
288 }
289 }
290}
291
292impl fmt::Debug for SockAddr {
293 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
294 let mut f: DebugStruct<'_, '_> = fmt.debug_struct(name:"SockAddr");
295 #[cfg(any(
296 target_os = "dragonfly",
297 target_os = "freebsd",
298 target_os = "haiku",
299 target_os = "hermit",
300 target_os = "ios",
301 target_os = "macos",
302 target_os = "netbsd",
303 target_os = "openbsd",
304 target_os = "vxworks",
305 target_os = "nto",
306 ))]
307 f.field("ss_len", &self.storage.ss_len);
308 f&mut DebugStruct<'_, '_>.field("ss_family", &self.storage.ss_family)
309 .field(name:"len", &self.len)
310 .finish()
311 }
312}
313
314#[test]
315fn ipv4() {
316 use std::net::Ipv4Addr;
317 let std: SocketAddrV4 = SocketAddrV4::new(ip:Ipv4Addr::new(1, 2, 3, 4), port:9876);
318 let addr: SockAddr = SockAddr::from(std);
319 assert_eq!(addr.family(), AF_INET as sa_family_t);
320 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
321 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
322 assert_eq!(addr.as_socket_ipv4(), Some(std));
323 assert!(addr.as_socket_ipv6().is_none());
324
325 let addr: SockAddr = SockAddr::from(SocketAddr::from(std));
326 assert_eq!(addr.family(), AF_INET as sa_family_t);
327 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
328 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
329 assert_eq!(addr.as_socket_ipv4(), Some(std));
330 assert!(addr.as_socket_ipv6().is_none());
331}
332
333#[test]
334fn ipv6() {
335 use std::net::Ipv6Addr;
336 let std: SocketAddrV6 = SocketAddrV6::new(ip:Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), port:9876, flowinfo:11, scope_id:12);
337 let addr: SockAddr = SockAddr::from(std);
338 assert_eq!(addr.family(), AF_INET6 as sa_family_t);
339 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
340 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
341 assert!(addr.as_socket_ipv4().is_none());
342 assert_eq!(addr.as_socket_ipv6(), Some(std));
343
344 let addr: SockAddr = SockAddr::from(SocketAddr::from(std));
345 assert_eq!(addr.family(), AF_INET6 as sa_family_t);
346 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
347 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
348 assert!(addr.as_socket_ipv4().is_none());
349 assert_eq!(addr.as_socket_ipv6(), Some(std));
350}
351