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