1 use cfg_if::cfg_if; 2 use super::{GetSockOpt, SetSockOpt}; 3 use crate::Result; 4 use crate::errno::Errno; 5 use crate::sys::time::TimeVal; 6 use libc::{self, c_int, c_void, socklen_t}; 7 use std::mem::{ 8 self, 9 MaybeUninit 10 }; 11 use std::os::unix::io::RawFd; 12 use std::ffi::{OsStr, OsString}; 13 #[cfg(target_family = "unix")] 14 use std::os::unix::ffi::OsStrExt; 15 16 // Constants 17 // TCP_CA_NAME_MAX isn't defined in user space include files 18 #[cfg(any(target_os = "freebsd", target_os = "linux"))] 19 const TCP_CA_NAME_MAX: usize = 16; 20 21 /// Helper for implementing `SetSockOpt` for a given socket option. See 22 /// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). 23 /// 24 /// This macro aims to help implementing `SetSockOpt` for different socket options that accept 25 /// different kinds of data to be used with `setsockopt`. 26 /// 27 /// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option 28 /// you are implementing represents a simple type. 29 /// 30 /// # Arguments 31 /// 32 /// * `$name:ident`: name of the type you want to implement `SetSockOpt` for. 33 /// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets* 34 /// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), 35 /// and more. Please refer to your system manual for more options. Will be passed as the second 36 /// argument (`level`) to the `setsockopt` call. 37 /// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, 38 /// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) 39 /// to the `setsockopt` call. 40 /// * Type of the value that you are going to set. 41 /// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for 42 /// `bool`, `SetUsize` for `usize`, etc.). 43 macro_rules! setsockopt_impl { 44 ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => { 45 impl SetSockOpt for $name { 46 type Val = $ty; 47 48 fn set(&self, fd: RawFd, val: &$ty) -> Result<()> { 49 unsafe { 50 let setter: $setter = Set::new(val); 51 52 let res = libc::setsockopt(fd, $level, $flag, 53 setter.ffi_ptr(), 54 setter.ffi_len()); 55 Errno::result(res).map(drop) 56 } 57 } 58 } 59 } 60 } 61 62 /// Helper for implementing `GetSockOpt` for a given socket option. See 63 /// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html). 64 /// 65 /// This macro aims to help implementing `GetSockOpt` for different socket options that accept 66 /// different kinds of data to be use with `getsockopt`. 67 /// 68 /// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option 69 /// you are implementing represents a simple type. 70 /// 71 /// # Arguments 72 /// 73 /// * Name of the type you want to implement `GetSockOpt` for. 74 /// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`), *ip 75 /// protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), and more. Please refer 76 /// to your system manual for more options. Will be passed as the second argument (`level`) to 77 /// the `getsockopt` call. 78 /// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, 79 /// `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to 80 /// the `getsockopt` call. 81 /// * Type of the value that you are going to get. 82 /// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for 83 /// `bool`, `GetUsize` for `usize`, etc.). 84 macro_rules! getsockopt_impl { 85 ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => { 86 impl GetSockOpt for $name { 87 type Val = $ty; 88 89 fn get(&self, fd: RawFd) -> Result<$ty> { 90 unsafe { 91 let mut getter: $getter = Get::uninit(); 92 93 let res = libc::getsockopt(fd, $level, $flag, 94 getter.ffi_ptr(), 95 getter.ffi_len()); 96 Errno::result(res)?; 97 98 Ok(getter.assume_init()) 99 } 100 } 101 } 102 } 103 } 104 105 /// Helper to generate the sockopt accessors. See 106 /// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and 107 /// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html). 108 /// 109 /// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options 110 /// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively. 111 /// 112 /// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and 113 /// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros. 114 /// 115 /// # Arguments 116 /// 117 /// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or 118 /// both of them. 119 /// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for. 120 /// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets* 121 /// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), 122 /// and more. Please refer to your system manual for more options. Will be passed as the second 123 /// argument (`level`) to the `getsockopt`/`setsockopt` call. 124 /// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`, 125 /// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`) 126 /// to the `setsockopt`/`getsockopt` call. 127 /// * `$ty:ty`: type of the value that will be get/set. 128 /// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`. 129 /// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`. 130 macro_rules! sockopt_impl { 131 (GetOnly, $name:ident, $level:path, $flag:path, bool) => { 132 sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool); 133 }; 134 135 (GetOnly, $name:ident, $level:path, $flag:path, u8) => { 136 sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8); 137 }; 138 139 (GetOnly, $name:ident, $level:path, $flag:path, usize) => { 140 sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize); 141 }; 142 143 (SetOnly, $name:ident, $level:path, $flag:path, bool) => { 144 sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool); 145 }; 146 147 (SetOnly, $name:ident, $level:path, $flag:path, u8) => { 148 sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8); 149 }; 150 151 (SetOnly, $name:ident, $level:path, $flag:path, usize) => { 152 sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize); 153 }; 154 155 (Both, $name:ident, $level:path, $flag:path, bool) => { 156 sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool); 157 }; 158 159 (Both, $name:ident, $level:path, $flag:path, u8) => { 160 sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8); 161 }; 162 163 (Both, $name:ident, $level:path, $flag:path, usize) => { 164 sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize); 165 }; 166 167 (Both, $name:ident, $level:path, $flag:path, OsString<$array:ty>) => { 168 sockopt_impl!(Both, $name, $level, $flag, OsString, GetOsString<$array>, SetOsString); 169 }; 170 171 /* 172 * Matchers with generic getter types must be placed at the end, so 173 * they'll only match _after_ specialized matchers fail 174 */ 175 (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => { 176 sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>); 177 }; 178 179 (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => { 180 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 181 pub struct $name; 182 183 getsockopt_impl!($name, $level, $flag, $ty, $getter); 184 }; 185 186 (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => { 187 sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>); 188 }; 189 190 (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => { 191 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 192 pub struct $name; 193 194 setsockopt_impl!($name, $level, $flag, $ty, $setter); 195 }; 196 197 (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => { 198 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 199 pub struct $name; 200 201 setsockopt_impl!($name, $level, $flag, $ty, $setter); 202 getsockopt_impl!($name, $level, $flag, $ty, $getter); 203 }; 204 205 (Both, $name:ident, $level:path, $flag:path, $ty:ty) => { 206 sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>); 207 }; 208 } 209 210 /* 211 * 212 * ===== Define sockopts ===== 213 * 214 */ 215 216 sockopt_impl!(Both, ReuseAddr, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool); 217 sockopt_impl!(Both, ReusePort, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool); 218 sockopt_impl!(Both, TcpNoDelay, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool); 219 sockopt_impl!(Both, Linger, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger); 220 sockopt_impl!(SetOnly, IpAddMembership, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, super::IpMembershipRequest); 221 sockopt_impl!(SetOnly, IpDropMembership, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, super::IpMembershipRequest); 222 cfg_if! { 223 if #[cfg(any(target_os = "android", target_os = "linux"))] { 224 sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest); 225 sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest); 226 } else if #[cfg(any(target_os = "dragonfly", 227 target_os = "freebsd", 228 target_os = "ios", 229 target_os = "macos", 230 target_os = "netbsd", 231 target_os = "openbsd"))] { 232 sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest); 233 sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); 234 } 235 } 236 sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8); 237 sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool); 238 sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal); 239 sockopt_impl!(Both, SendTimeout, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal); 240 sockopt_impl!(Both, Broadcast, libc::SOL_SOCKET, libc::SO_BROADCAST, bool); 241 sockopt_impl!(Both, OobInline, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool); 242 sockopt_impl!(GetOnly, SocketError, libc::SOL_SOCKET, libc::SO_ERROR, i32); 243 sockopt_impl!(Both, KeepAlive, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool); 244 #[cfg(any(target_os = "android", target_os = "linux"))] 245 sockopt_impl!(GetOnly, PeerCredentials, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials); 246 #[cfg(any(target_os = "ios", 247 target_os = "macos"))] 248 sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32); 249 #[cfg(any(target_os = "android", 250 target_os = "dragonfly", 251 target_os = "freebsd", 252 target_os = "linux", 253 target_os = "nacl"))] 254 sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32); 255 #[cfg(not(target_os = "openbsd"))] 256 sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32); 257 #[cfg(not(target_os = "openbsd"))] 258 sockopt_impl!(Both, TcpKeepInterval, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32); 259 sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize); 260 sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize); 261 #[cfg(any(target_os = "android", target_os = "linux"))] 262 sockopt_impl!(SetOnly, RcvBufForce, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize); 263 #[cfg(any(target_os = "android", target_os = "linux"))] 264 sockopt_impl!(SetOnly, SndBufForce, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize); 265 sockopt_impl!(GetOnly, SockType, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType); 266 sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool); 267 #[cfg(any(target_os = "android", target_os = "linux"))] 268 sockopt_impl!(Both, BindToDevice, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>); 269 #[cfg(any(target_os = "android", target_os = "linux"))] 270 sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in); 271 sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); 272 #[cfg(any(target_os = "android", target_os = "linux"))] 273 sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool); 274 #[cfg(target_os = "openbsd")] 275 sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool); 276 #[cfg(target_os = "freebsd")] 277 sockopt_impl!(Both, BindAny, libc::IPPROTO_IP, libc::IP_BINDANY, bool); 278 #[cfg(target_os = "linux")] 279 sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32); 280 #[cfg(any(target_os = "android", target_os = "linux"))] 281 sockopt_impl!(Both, PassCred, libc::SOL_SOCKET, libc::SO_PASSCRED, bool); 282 #[cfg(any(target_os = "freebsd", target_os = "linux"))] 283 sockopt_impl!(Both, TcpCongestion, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>); 284 #[cfg(any( 285 target_os = "android", 286 target_os = "ios", 287 target_os = "linux", 288 target_os = "macos", 289 target_os = "netbsd", 290 ))] 291 sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool); 292 #[cfg(any( 293 target_os = "android", 294 target_os = "freebsd", 295 target_os = "ios", 296 target_os = "linux", 297 target_os = "macos", 298 target_os = "netbsd", 299 target_os = "openbsd", 300 ))] 301 sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool); 302 #[cfg(any( 303 target_os = "freebsd", 304 target_os = "ios", 305 target_os = "macos", 306 target_os = "netbsd", 307 target_os = "openbsd", 308 ))] 309 sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool); 310 #[cfg(any( 311 target_os = "freebsd", 312 target_os = "ios", 313 target_os = "macos", 314 target_os = "netbsd", 315 target_os = "openbsd", 316 ))] 317 sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool); 318 #[cfg(target_os = "linux")] 319 sockopt_impl!(Both, UdpGsoSegment, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int); 320 #[cfg(target_os = "linux")] 321 sockopt_impl!(Both, UdpGroSegment, libc::IPPROTO_UDP, libc::UDP_GRO, bool); 322 323 #[cfg(any(target_os = "android", target_os = "linux"))] 324 #[derive(Copy, Clone, Debug)] 325 pub struct AlgSetAeadAuthSize; 326 327 // ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len` 328 // See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222 329 #[cfg(any(target_os = "android", target_os = "linux"))] 330 impl SetSockOpt for AlgSetAeadAuthSize { 331 type Val = usize; 332 set(&self, fd: RawFd, val: &usize) -> Result<()>333 fn set(&self, fd: RawFd, val: &usize) -> Result<()> { 334 unsafe { 335 let res = libc::setsockopt(fd, 336 libc::SOL_ALG, 337 libc::ALG_SET_AEAD_AUTHSIZE, 338 ::std::ptr::null(), 339 *val as libc::socklen_t); 340 Errno::result(res).map(drop) 341 } 342 } 343 } 344 345 #[cfg(any(target_os = "android", target_os = "linux"))] 346 #[derive(Clone, Debug)] 347 pub struct AlgSetKey<T>(::std::marker::PhantomData<T>); 348 349 #[cfg(any(target_os = "android", target_os = "linux"))] 350 impl<T> Default for AlgSetKey<T> { default() -> Self351 fn default() -> Self { 352 AlgSetKey(Default::default()) 353 } 354 } 355 356 #[cfg(any(target_os = "android", target_os = "linux"))] 357 impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone { 358 type Val = T; 359 set(&self, fd: RawFd, val: &T) -> Result<()>360 fn set(&self, fd: RawFd, val: &T) -> Result<()> { 361 unsafe { 362 let res = libc::setsockopt(fd, 363 libc::SOL_ALG, 364 libc::ALG_SET_KEY, 365 val.as_ref().as_ptr() as *const _, 366 val.as_ref().len() as libc::socklen_t); 367 Errno::result(res).map(drop) 368 } 369 } 370 } 371 372 /* 373 * 374 * ===== Accessor helpers ===== 375 * 376 */ 377 378 /// Helper trait that describes what is expected from a `GetSockOpt` getter. 379 unsafe trait Get<T> { 380 /// Returns an uninitialized value. uninit() -> Self381 unsafe fn uninit() -> Self; 382 /// Returns a pointer to the stored value. This pointer will be passed to the system's 383 /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`). ffi_ptr(&mut self) -> *mut c_void384 fn ffi_ptr(&mut self) -> *mut c_void; 385 /// Returns length of the stored value. This pointer will be passed to the system's 386 /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`). ffi_len(&mut self) -> *mut socklen_t387 fn ffi_len(&mut self) -> *mut socklen_t; 388 /// Returns the hopefully initialized inner value. assume_init(self) -> T389 unsafe fn assume_init(self) -> T; 390 } 391 392 /// Helper trait that describes what is expected from a `SetSockOpt` setter. 393 unsafe trait Set<'a, T> { 394 /// Initialize the setter with a given value. new(val: &'a T) -> Self395 fn new(val: &'a T) -> Self; 396 /// Returns a pointer to the stored value. This pointer will be passed to the system's 397 /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`). ffi_ptr(&self) -> *const c_void398 fn ffi_ptr(&self) -> *const c_void; 399 /// Returns length of the stored value. This pointer will be passed to the system's 400 /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`). ffi_len(&self) -> socklen_t401 fn ffi_len(&self) -> socklen_t; 402 } 403 404 /// Getter for an arbitrary `struct`. 405 struct GetStruct<T> { 406 len: socklen_t, 407 val: MaybeUninit<T>, 408 } 409 410 unsafe impl<T> Get<T> for GetStruct<T> { uninit() -> Self411 unsafe fn uninit() -> Self { 412 GetStruct { 413 len: mem::size_of::<T>() as socklen_t, 414 val: MaybeUninit::uninit(), 415 } 416 } 417 ffi_ptr(&mut self) -> *mut c_void418 fn ffi_ptr(&mut self) -> *mut c_void { 419 self.val.as_mut_ptr() as *mut c_void 420 } 421 ffi_len(&mut self) -> *mut socklen_t422 fn ffi_len(&mut self) -> *mut socklen_t { 423 &mut self.len 424 } 425 assume_init(self) -> T426 unsafe fn assume_init(self) -> T { 427 assert_eq!(self.len as usize, mem::size_of::<T>(), "invalid getsockopt implementation"); 428 self.val.assume_init() 429 } 430 } 431 432 /// Setter for an arbitrary `struct`. 433 struct SetStruct<'a, T: 'static> { 434 ptr: &'a T, 435 } 436 437 unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> { new(ptr: &'a T) -> SetStruct<'a, T>438 fn new(ptr: &'a T) -> SetStruct<'a, T> { 439 SetStruct { ptr } 440 } 441 ffi_ptr(&self) -> *const c_void442 fn ffi_ptr(&self) -> *const c_void { 443 self.ptr as *const T as *const c_void 444 } 445 ffi_len(&self) -> socklen_t446 fn ffi_len(&self) -> socklen_t { 447 mem::size_of::<T>() as socklen_t 448 } 449 } 450 451 /// Getter for a boolean value. 452 struct GetBool { 453 len: socklen_t, 454 val: MaybeUninit<c_int>, 455 } 456 457 unsafe impl Get<bool> for GetBool { uninit() -> Self458 unsafe fn uninit() -> Self { 459 GetBool { 460 len: mem::size_of::<c_int>() as socklen_t, 461 val: MaybeUninit::uninit(), 462 } 463 } 464 ffi_ptr(&mut self) -> *mut c_void465 fn ffi_ptr(&mut self) -> *mut c_void { 466 self.val.as_mut_ptr() as *mut c_void 467 } 468 ffi_len(&mut self) -> *mut socklen_t469 fn ffi_len(&mut self) -> *mut socklen_t { 470 &mut self.len 471 } 472 assume_init(self) -> bool473 unsafe fn assume_init(self) -> bool { 474 assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation"); 475 self.val.assume_init() != 0 476 } 477 } 478 479 /// Setter for a boolean value. 480 struct SetBool { 481 val: c_int, 482 } 483 484 unsafe impl<'a> Set<'a, bool> for SetBool { new(val: &'a bool) -> SetBool485 fn new(val: &'a bool) -> SetBool { 486 SetBool { val: if *val { 1 } else { 0 } } 487 } 488 ffi_ptr(&self) -> *const c_void489 fn ffi_ptr(&self) -> *const c_void { 490 &self.val as *const c_int as *const c_void 491 } 492 ffi_len(&self) -> socklen_t493 fn ffi_len(&self) -> socklen_t { 494 mem::size_of::<c_int>() as socklen_t 495 } 496 } 497 498 /// Getter for an `u8` value. 499 struct GetU8 { 500 len: socklen_t, 501 val: MaybeUninit<u8>, 502 } 503 504 unsafe impl Get<u8> for GetU8 { uninit() -> Self505 unsafe fn uninit() -> Self { 506 GetU8 { 507 len: mem::size_of::<u8>() as socklen_t, 508 val: MaybeUninit::uninit(), 509 } 510 } 511 ffi_ptr(&mut self) -> *mut c_void512 fn ffi_ptr(&mut self) -> *mut c_void { 513 self.val.as_mut_ptr() as *mut c_void 514 } 515 ffi_len(&mut self) -> *mut socklen_t516 fn ffi_len(&mut self) -> *mut socklen_t { 517 &mut self.len 518 } 519 assume_init(self) -> u8520 unsafe fn assume_init(self) -> u8 { 521 assert_eq!(self.len as usize, mem::size_of::<u8>(), "invalid getsockopt implementation"); 522 self.val.assume_init() 523 } 524 } 525 526 /// Setter for an `u8` value. 527 struct SetU8 { 528 val: u8, 529 } 530 531 unsafe impl<'a> Set<'a, u8> for SetU8 { new(val: &'a u8) -> SetU8532 fn new(val: &'a u8) -> SetU8 { 533 SetU8 { val: *val as u8 } 534 } 535 ffi_ptr(&self) -> *const c_void536 fn ffi_ptr(&self) -> *const c_void { 537 &self.val as *const u8 as *const c_void 538 } 539 ffi_len(&self) -> socklen_t540 fn ffi_len(&self) -> socklen_t { 541 mem::size_of::<c_int>() as socklen_t 542 } 543 } 544 545 /// Getter for an `usize` value. 546 struct GetUsize { 547 len: socklen_t, 548 val: MaybeUninit<c_int>, 549 } 550 551 unsafe impl Get<usize> for GetUsize { uninit() -> Self552 unsafe fn uninit() -> Self { 553 GetUsize { 554 len: mem::size_of::<c_int>() as socklen_t, 555 val: MaybeUninit::uninit(), 556 } 557 } 558 ffi_ptr(&mut self) -> *mut c_void559 fn ffi_ptr(&mut self) -> *mut c_void { 560 self.val.as_mut_ptr() as *mut c_void 561 } 562 ffi_len(&mut self) -> *mut socklen_t563 fn ffi_len(&mut self) -> *mut socklen_t { 564 &mut self.len 565 } 566 assume_init(self) -> usize567 unsafe fn assume_init(self) -> usize { 568 assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation"); 569 self.val.assume_init() as usize 570 } 571 } 572 573 /// Setter for an `usize` value. 574 struct SetUsize { 575 val: c_int, 576 } 577 578 unsafe impl<'a> Set<'a, usize> for SetUsize { new(val: &'a usize) -> SetUsize579 fn new(val: &'a usize) -> SetUsize { 580 SetUsize { val: *val as c_int } 581 } 582 ffi_ptr(&self) -> *const c_void583 fn ffi_ptr(&self) -> *const c_void { 584 &self.val as *const c_int as *const c_void 585 } 586 ffi_len(&self) -> socklen_t587 fn ffi_len(&self) -> socklen_t { 588 mem::size_of::<c_int>() as socklen_t 589 } 590 } 591 592 /// Getter for a `OsString` value. 593 struct GetOsString<T: AsMut<[u8]>> { 594 len: socklen_t, 595 val: MaybeUninit<T>, 596 } 597 598 unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { uninit() -> Self599 unsafe fn uninit() -> Self { 600 GetOsString { 601 len: mem::size_of::<T>() as socklen_t, 602 val: MaybeUninit::uninit(), 603 } 604 } 605 ffi_ptr(&mut self) -> *mut c_void606 fn ffi_ptr(&mut self) -> *mut c_void { 607 self.val.as_mut_ptr() as *mut c_void 608 } 609 ffi_len(&mut self) -> *mut socklen_t610 fn ffi_len(&mut self) -> *mut socklen_t { 611 &mut self.len 612 } 613 assume_init(self) -> OsString614 unsafe fn assume_init(self) -> OsString { 615 let len = self.len as usize; 616 let mut v = self.val.assume_init(); 617 OsStr::from_bytes(&v.as_mut()[0..len]).to_owned() 618 } 619 } 620 621 /// Setter for a `OsString` value. 622 struct SetOsString<'a> { 623 val: &'a OsStr, 624 } 625 626 unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> { new(val: &'a OsString) -> SetOsString627 fn new(val: &'a OsString) -> SetOsString { 628 SetOsString { val: val.as_os_str() } 629 } 630 ffi_ptr(&self) -> *const c_void631 fn ffi_ptr(&self) -> *const c_void { 632 self.val.as_bytes().as_ptr() as *const c_void 633 } 634 ffi_len(&self) -> socklen_t635 fn ffi_len(&self) -> socklen_t { 636 self.val.len() as socklen_t 637 } 638 } 639 640 641 #[cfg(test)] 642 mod test { 643 #[cfg(any(target_os = "android", target_os = "linux"))] 644 #[test] can_get_peercred_on_unix_socket()645 fn can_get_peercred_on_unix_socket() { 646 use super::super::*; 647 648 let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap(); 649 let a_cred = getsockopt(a, super::PeerCredentials).unwrap(); 650 let b_cred = getsockopt(b, super::PeerCredentials).unwrap(); 651 assert_eq!(a_cred, b_cred); 652 assert!(a_cred.pid() != 0); 653 } 654 655 #[test] is_socket_type_unix()656 fn is_socket_type_unix() { 657 use super::super::*; 658 use crate::unistd::close; 659 660 let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap(); 661 let a_type = getsockopt(a, super::SockType).unwrap(); 662 assert_eq!(a_type, SockType::Stream); 663 close(a).unwrap(); 664 close(b).unwrap(); 665 } 666 667 #[test] is_socket_type_dgram()668 fn is_socket_type_dgram() { 669 use super::super::*; 670 use crate::unistd::close; 671 672 let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap(); 673 let s_type = getsockopt(s, super::SockType).unwrap(); 674 assert_eq!(s_type, SockType::Datagram); 675 close(s).unwrap(); 676 } 677 678 #[cfg(any(target_os = "freebsd", 679 target_os = "linux", 680 target_os = "nacl"))] 681 #[test] can_get_listen_on_tcp_socket()682 fn can_get_listen_on_tcp_socket() { 683 use super::super::*; 684 use crate::unistd::close; 685 686 let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); 687 let s_listening = getsockopt(s, super::AcceptConn).unwrap(); 688 assert!(!s_listening); 689 listen(s, 10).unwrap(); 690 let s_listening2 = getsockopt(s, super::AcceptConn).unwrap(); 691 assert!(s_listening2); 692 close(s).unwrap(); 693 } 694 695 } 696