]> git.proxmox.com Git - cargo.git/blob - vendor/socket2/src/sockaddr.rs
New upstream version 0.47.0
[cargo.git] / vendor / socket2 / src / sockaddr.rs
1 use std::fmt;
2 use std::mem::{self, MaybeUninit};
3 use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
4 use std::ptr;
5
6 #[cfg(any(unix, target_os = "redox"))]
7 use libc::{
8 sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET,
9 AF_INET6,
10 };
11 #[cfg(windows)]
12 use winapi::shared::ws2def::{
13 ADDRESS_FAMILY as sa_family_t, AF_INET, AF_INET6, SOCKADDR as sockaddr,
14 SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage,
15 };
16 #[cfg(windows)]
17 use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6;
18 #[cfg(windows)]
19 use winapi::um::ws2tcpip::socklen_t;
20
21 /// The address of a socket.
22 ///
23 /// `SockAddr`s may be constructed directly to and from the standard library
24 /// `SocketAddr`, `SocketAddrV4`, and `SocketAddrV6` types.
25 pub struct SockAddr {
26 storage: sockaddr_storage,
27 len: socklen_t,
28 }
29
30 impl fmt::Debug for SockAddr {
31 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
32 let mut builder = fmt.debug_struct("SockAddr");
33 builder.field("family", &self.family());
34 if let Some(addr) = self.as_inet() {
35 builder.field("inet", &addr);
36 } else if let Some(addr) = self.as_inet6() {
37 builder.field("inet6", &addr);
38 }
39 builder.finish()
40 }
41 }
42
43 impl SockAddr {
44 /// Constructs a `SockAddr` from its raw components.
45 pub unsafe fn from_raw_parts(addr: *const sockaddr, len: socklen_t) -> SockAddr {
46 let mut storage = MaybeUninit::<sockaddr_storage>::uninit();
47 ptr::copy_nonoverlapping(
48 addr as *const _ as *const u8,
49 &mut storage as *mut _ as *mut u8,
50 len as usize,
51 );
52
53 SockAddr {
54 // This is safe as we written the address to `storage` above.
55 storage: storage.assume_init(),
56 len: len,
57 }
58 }
59
60 /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
61 ///
62 /// This function is only available on Unix when the `unix` feature is
63 /// enabled.
64 ///
65 /// # Failure
66 ///
67 /// Returns an error if the path is longer than `SUN_LEN`.
68 #[cfg(all(unix, feature = "unix"))]
69 pub fn unix<P>(path: P) -> ::std::io::Result<SockAddr>
70 where
71 P: AsRef<::std::path::Path>,
72 {
73 use libc::{c_char, sockaddr_un, AF_UNIX};
74 use std::cmp::Ordering;
75 use std::io;
76 use std::os::unix::ffi::OsStrExt;
77
78 unsafe {
79 let mut addr = mem::zeroed::<sockaddr_un>();
80 addr.sun_family = AF_UNIX as sa_family_t;
81
82 let bytes = path.as_ref().as_os_str().as_bytes();
83
84 match (bytes.get(0), bytes.len().cmp(&addr.sun_path.len())) {
85 // Abstract paths don't need a null terminator
86 (Some(&0), Ordering::Greater) => {
87 return Err(io::Error::new(
88 io::ErrorKind::InvalidInput,
89 "path must be no longer than SUN_LEN",
90 ));
91 }
92 (Some(&0), _) => {}
93 (_, Ordering::Greater) | (_, Ordering::Equal) => {
94 return Err(io::Error::new(
95 io::ErrorKind::InvalidInput,
96 "path must be shorter than SUN_LEN",
97 ));
98 }
99 _ => {}
100 }
101
102 for (dst, src) in addr.sun_path.iter_mut().zip(bytes) {
103 *dst = *src as c_char;
104 }
105 // null byte for pathname is already there since we zeroed up front
106
107 let base = &addr as *const _ as usize;
108 let path = &addr.sun_path as *const _ as usize;
109 let sun_path_offset = path - base;
110
111 let mut len = sun_path_offset + bytes.len();
112 match bytes.get(0) {
113 Some(&0) | None => {}
114 Some(_) => len += 1,
115 }
116 Ok(SockAddr::from_raw_parts(
117 &addr as *const _ as *const _,
118 len as socklen_t,
119 ))
120 }
121 }
122
123 unsafe fn as_<T>(&self, family: sa_family_t) -> Option<T> {
124 if self.storage.ss_family != family {
125 return None;
126 }
127
128 Some(mem::transmute_copy(&self.storage))
129 }
130
131 /// Returns this address as a `SocketAddrV4` if it is in the `AF_INET`
132 /// family.
133 pub fn as_inet(&self) -> Option<SocketAddrV4> {
134 unsafe { self.as_(AF_INET as sa_family_t) }
135 }
136
137 /// Returns this address as a `SocketAddrV6` if it is in the `AF_INET6`
138 /// family.
139 pub fn as_inet6(&self) -> Option<SocketAddrV6> {
140 unsafe { self.as_(AF_INET6 as sa_family_t) }
141 }
142
143 /// Returns this address as a `SocketAddr` if it is in the `AF_INET`
144 /// or `AF_INET6` family, otherwise returns `None`.
145 pub fn as_std(&self) -> Option<SocketAddr> {
146 if let Some(addr) = self.as_inet() {
147 Some(SocketAddr::V4(addr))
148 } else if let Some(addr) = self.as_inet6() {
149 Some(SocketAddr::V6(addr))
150 } else {
151 None
152 }
153 }
154
155 /// Returns this address's family.
156 pub fn family(&self) -> sa_family_t {
157 self.storage.ss_family
158 }
159
160 /// Returns the size of this address in bytes.
161 pub fn len(&self) -> socklen_t {
162 self.len
163 }
164
165 /// Returns a raw pointer to the address.
166 pub fn as_ptr(&self) -> *const sockaddr {
167 &self.storage as *const _ as *const _
168 }
169 }
170
171 // SocketAddrV4 and SocketAddrV6 are just wrappers around sockaddr_in and sockaddr_in6
172
173 // check to make sure that the sizes at least match up
174 fn _size_checks(v4: SocketAddrV4, v6: SocketAddrV6) {
175 unsafe {
176 mem::transmute::<SocketAddrV4, sockaddr_in>(v4);
177 mem::transmute::<SocketAddrV6, sockaddr_in6>(v6);
178 }
179 }
180
181 impl From<SocketAddrV4> for SockAddr {
182 fn from(addr: SocketAddrV4) -> SockAddr {
183 unsafe {
184 SockAddr::from_raw_parts(
185 &addr as *const _ as *const _,
186 mem::size_of::<SocketAddrV4>() as socklen_t,
187 )
188 }
189 }
190 }
191
192 impl From<SocketAddrV6> for SockAddr {
193 fn from(addr: SocketAddrV6) -> SockAddr {
194 unsafe {
195 SockAddr::from_raw_parts(
196 &addr as *const _ as *const _,
197 mem::size_of::<SocketAddrV6>() as socklen_t,
198 )
199 }
200 }
201 }
202
203 impl From<SocketAddr> for SockAddr {
204 fn from(addr: SocketAddr) -> SockAddr {
205 match addr {
206 SocketAddr::V4(addr) => addr.into(),
207 SocketAddr::V6(addr) => addr.into(),
208 }
209 }
210 }
211
212 #[cfg(test)]
213 mod test {
214 use super::*;
215
216 #[test]
217 fn inet() {
218 let raw = "127.0.0.1:80".parse::<SocketAddrV4>().unwrap();
219 let addr = SockAddr::from(raw);
220 assert!(addr.as_inet6().is_none());
221 let addr = addr.as_inet().unwrap();
222 assert_eq!(raw, addr);
223 }
224
225 #[test]
226 fn inet6() {
227 let raw = "[2001:db8::ff00:42:8329]:80"
228 .parse::<SocketAddrV6>()
229 .unwrap();
230 let addr = SockAddr::from(raw);
231 assert!(addr.as_inet().is_none());
232 let addr = addr.as_inet6().unwrap();
233 assert_eq!(raw, addr);
234 }
235 }