1 | use std::mem::{self, size_of, MaybeUninit}; |
2 | use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; |
3 | use std::{fmt, io}; |
4 | |
5 | use crate::sys::{ |
6 | sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET, |
7 | AF_INET6, |
8 | }; |
9 | #[cfg (windows)] |
10 | use 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)] |
17 | pub struct SockAddr { |
18 | storage: sockaddr_storage, |
19 | len: socklen_t, |
20 | } |
21 | |
22 | #[allow (clippy::len_without_is_empty)] |
23 | impl 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 | |
214 | impl 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 | |
223 | impl 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 | target_os = "nto" , |
239 | target_os = "espidf" , |
240 | target_os = "vita" , |
241 | ))] |
242 | sin_len: 0, |
243 | #[cfg (target_os = "vita" )] |
244 | sin_vport: addr.port().to_be(), |
245 | }; |
246 | let mut storage = MaybeUninit::<sockaddr_storage>::zeroed(); |
247 | // Safety: A `sockaddr_in` is memory compatible with a `sockaddr_storage` |
248 | unsafe { (storage.as_mut_ptr() as *mut sockaddr_in).write(sockaddr_in) }; |
249 | SockAddr { |
250 | storage: unsafe { storage.assume_init() }, |
251 | len: mem::size_of::<sockaddr_in>() as socklen_t, |
252 | } |
253 | } |
254 | } |
255 | |
256 | impl From<SocketAddrV6> for SockAddr { |
257 | fn from(addr: SocketAddrV6) -> SockAddr { |
258 | #[cfg (windows)] |
259 | let u = unsafe { |
260 | let mut u = mem::zeroed::<SOCKADDR_IN6_LH_u>(); |
261 | *u.sin6_scope_id_mut() = addr.scope_id(); |
262 | u |
263 | }; |
264 | |
265 | let sockaddr_in6 = sockaddr_in6 { |
266 | sin6_family: AF_INET6 as sa_family_t, |
267 | sin6_port: addr.port().to_be(), |
268 | sin6_addr: crate::sys::to_in6_addr(addr.ip()), |
269 | sin6_flowinfo: addr.flowinfo(), |
270 | #[cfg (unix)] |
271 | sin6_scope_id: addr.scope_id(), |
272 | #[cfg (windows)] |
273 | u, |
274 | #[cfg (any( |
275 | target_os = "dragonfly" , |
276 | target_os = "freebsd" , |
277 | target_os = "haiku" , |
278 | target_os = "ios" , |
279 | target_os = "macos" , |
280 | target_os = "netbsd" , |
281 | target_os = "openbsd" , |
282 | target_os = "nto" , |
283 | target_os = "espidf" , |
284 | target_os = "vita" , |
285 | ))] |
286 | sin6_len: 0, |
287 | #[cfg (target_os = "vita" )] |
288 | sin6_vport: addr.port().to_be(), |
289 | #[cfg (any(target_os = "solaris" , target_os = "illumos" ))] |
290 | __sin6_src_id: 0, |
291 | }; |
292 | let mut storage = MaybeUninit::<sockaddr_storage>::zeroed(); |
293 | // Safety: A `sockaddr_in6` is memory compatible with a `sockaddr_storage` |
294 | unsafe { (storage.as_mut_ptr() as *mut sockaddr_in6).write(sockaddr_in6) }; |
295 | SockAddr { |
296 | storage: unsafe { storage.assume_init() }, |
297 | len: mem::size_of::<sockaddr_in6>() as socklen_t, |
298 | } |
299 | } |
300 | } |
301 | |
302 | impl fmt::Debug for SockAddr { |
303 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
304 | let mut f: DebugStruct<'_, '_> = fmt.debug_struct(name:"SockAddr" ); |
305 | #[cfg (any( |
306 | target_os = "dragonfly" , |
307 | target_os = "freebsd" , |
308 | target_os = "haiku" , |
309 | target_os = "hermit" , |
310 | target_os = "ios" , |
311 | target_os = "macos" , |
312 | target_os = "netbsd" , |
313 | target_os = "openbsd" , |
314 | target_os = "vxworks" , |
315 | target_os = "nto" , |
316 | ))] |
317 | f.field("ss_len" , &self.storage.ss_len); |
318 | f&mut DebugStruct<'_, '_>.field("ss_family" , &self.storage.ss_family) |
319 | .field(name:"len" , &self.len) |
320 | .finish() |
321 | } |
322 | } |
323 | |
324 | #[test ] |
325 | fn ipv4() { |
326 | use std::net::Ipv4Addr; |
327 | let std: SocketAddrV4 = SocketAddrV4::new(ip:Ipv4Addr::new(1, 2, 3, 4), port:9876); |
328 | let addr: SockAddr = SockAddr::from(std); |
329 | assert_eq!(addr.family(), AF_INET as sa_family_t); |
330 | assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t); |
331 | assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std))); |
332 | assert_eq!(addr.as_socket_ipv4(), Some(std)); |
333 | assert!(addr.as_socket_ipv6().is_none()); |
334 | |
335 | let addr: SockAddr = SockAddr::from(SocketAddr::from(std)); |
336 | assert_eq!(addr.family(), AF_INET as sa_family_t); |
337 | assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t); |
338 | assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std))); |
339 | assert_eq!(addr.as_socket_ipv4(), Some(std)); |
340 | assert!(addr.as_socket_ipv6().is_none()); |
341 | } |
342 | |
343 | #[test ] |
344 | fn ipv6() { |
345 | use std::net::Ipv6Addr; |
346 | let std: SocketAddrV6 = SocketAddrV6::new(ip:Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), port:9876, flowinfo:11, scope_id:12); |
347 | let addr: SockAddr = SockAddr::from(std); |
348 | assert_eq!(addr.family(), AF_INET6 as sa_family_t); |
349 | assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t); |
350 | assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std))); |
351 | assert!(addr.as_socket_ipv4().is_none()); |
352 | assert_eq!(addr.as_socket_ipv6(), Some(std)); |
353 | |
354 | let addr: SockAddr = SockAddr::from(SocketAddr::from(std)); |
355 | assert_eq!(addr.family(), AF_INET6 as sa_family_t); |
356 | assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t); |
357 | assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std))); |
358 | assert!(addr.as_socket_ipv4().is_none()); |
359 | assert_eq!(addr.as_socket_ipv6(), Some(std)); |
360 | } |
361 | |