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(Copy, Clone, Debug)] 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(Copy, Clone, Debug)] 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(Copy, Clone, Debug)] 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 ))] 280 sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool); 281 #[cfg(any( 282 target_os = "android", 283 target_os = "freebsd", 284 target_os = "ios", 285 target_os = "linux", 286 target_os = "macos" 287 ))] 288 sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool); 289 290 291 /* 292 * 293 * ===== Accessor helpers ===== 294 * 295 */ 296 297 /// Helper trait that describes what is expected from a `GetSockOpt` getter. 298 unsafe trait Get<T> { 299 /// Returns an empty value. blank() -> Self300 unsafe fn blank() -> Self; 301 /// Returns a pointer to the stored value. This pointer will be passed to the system's 302 /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`). ffi_ptr(&mut self) -> *mut c_void303 fn ffi_ptr(&mut self) -> *mut c_void; 304 /// Returns length of the stored value. This pointer will be passed to the system's 305 /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`). ffi_len(&mut self) -> *mut socklen_t306 fn ffi_len(&mut self) -> *mut socklen_t; 307 /// Returns the stored value. unwrap(self) -> T308 unsafe fn unwrap(self) -> T; 309 } 310 311 /// Helper trait that describes what is expected from a `SetSockOpt` setter. 312 unsafe trait Set<'a, T> { 313 /// Initialize the setter with a given value. new(val: &'a T) -> Self314 fn new(val: &'a T) -> Self; 315 /// Returns a pointer to the stored value. This pointer will be passed to the system's 316 /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`). ffi_ptr(&self) -> *const c_void317 fn ffi_ptr(&self) -> *const c_void; 318 /// Returns length of the stored value. This pointer will be passed to the system's 319 /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`). ffi_len(&self) -> socklen_t320 fn ffi_len(&self) -> socklen_t; 321 } 322 323 /// Getter for an arbitrary `struct`. 324 struct GetStruct<T> { 325 len: socklen_t, 326 val: T, 327 } 328 329 unsafe impl<T> Get<T> for GetStruct<T> { blank() -> Self330 unsafe fn blank() -> Self { 331 GetStruct { 332 len: mem::size_of::<T>() as socklen_t, 333 val: mem::zeroed(), 334 } 335 } 336 ffi_ptr(&mut self) -> *mut c_void337 fn ffi_ptr(&mut self) -> *mut c_void { 338 &mut self.val as *mut T as *mut c_void 339 } 340 ffi_len(&mut self) -> *mut socklen_t341 fn ffi_len(&mut self) -> *mut socklen_t { 342 &mut self.len 343 } 344 unwrap(self) -> T345 unsafe fn unwrap(self) -> T { 346 assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation"); 347 self.val 348 } 349 } 350 351 /// Setter for an arbitrary `struct`. 352 struct SetStruct<'a, T: 'static> { 353 ptr: &'a T, 354 } 355 356 unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> { new(ptr: &'a T) -> SetStruct<'a, T>357 fn new(ptr: &'a T) -> SetStruct<'a, T> { 358 SetStruct { ptr: ptr } 359 } 360 ffi_ptr(&self) -> *const c_void361 fn ffi_ptr(&self) -> *const c_void { 362 self.ptr as *const T as *const c_void 363 } 364 ffi_len(&self) -> socklen_t365 fn ffi_len(&self) -> socklen_t { 366 mem::size_of::<T>() as socklen_t 367 } 368 } 369 370 /// Getter for a boolean value. 371 struct GetBool { 372 len: socklen_t, 373 val: c_int, 374 } 375 376 unsafe impl Get<bool> for GetBool { blank() -> Self377 unsafe fn blank() -> Self { 378 GetBool { 379 len: mem::size_of::<c_int>() as socklen_t, 380 val: mem::zeroed(), 381 } 382 } 383 ffi_ptr(&mut self) -> *mut c_void384 fn ffi_ptr(&mut self) -> *mut c_void { 385 &mut self.val as *mut c_int as *mut c_void 386 } 387 ffi_len(&mut self) -> *mut socklen_t388 fn ffi_len(&mut self) -> *mut socklen_t { 389 &mut self.len 390 } 391 unwrap(self) -> bool392 unsafe fn unwrap(self) -> bool { 393 assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation"); 394 self.val != 0 395 } 396 } 397 398 /// Setter for a boolean value. 399 struct SetBool { 400 val: c_int, 401 } 402 403 unsafe impl<'a> Set<'a, bool> for SetBool { new(val: &'a bool) -> SetBool404 fn new(val: &'a bool) -> SetBool { 405 SetBool { val: if *val { 1 } else { 0 } } 406 } 407 ffi_ptr(&self) -> *const c_void408 fn ffi_ptr(&self) -> *const c_void { 409 &self.val as *const c_int as *const c_void 410 } 411 ffi_len(&self) -> socklen_t412 fn ffi_len(&self) -> socklen_t { 413 mem::size_of::<c_int>() as socklen_t 414 } 415 } 416 417 /// Getter for an `u8` value. 418 struct GetU8 { 419 len: socklen_t, 420 val: u8, 421 } 422 423 unsafe impl Get<u8> for GetU8 { blank() -> Self424 unsafe fn blank() -> Self { 425 GetU8 { 426 len: mem::size_of::<u8>() as socklen_t, 427 val: mem::zeroed(), 428 } 429 } 430 ffi_ptr(&mut self) -> *mut c_void431 fn ffi_ptr(&mut self) -> *mut c_void { 432 &mut self.val as *mut u8 as *mut c_void 433 } 434 ffi_len(&mut self) -> *mut socklen_t435 fn ffi_len(&mut self) -> *mut socklen_t { 436 &mut self.len 437 } 438 unwrap(self) -> u8439 unsafe fn unwrap(self) -> u8 { 440 assert!(self.len as usize == mem::size_of::<u8>(), "invalid getsockopt implementation"); 441 self.val as u8 442 } 443 } 444 445 /// Setter for an `u8` value. 446 struct SetU8 { 447 val: u8, 448 } 449 450 unsafe impl<'a> Set<'a, u8> for SetU8 { new(val: &'a u8) -> SetU8451 fn new(val: &'a u8) -> SetU8 { 452 SetU8 { val: *val as u8 } 453 } 454 ffi_ptr(&self) -> *const c_void455 fn ffi_ptr(&self) -> *const c_void { 456 &self.val as *const u8 as *const c_void 457 } 458 ffi_len(&self) -> socklen_t459 fn ffi_len(&self) -> socklen_t { 460 mem::size_of::<c_int>() as socklen_t 461 } 462 } 463 464 /// Getter for an `usize` value. 465 struct GetUsize { 466 len: socklen_t, 467 val: c_int, 468 } 469 470 unsafe impl Get<usize> for GetUsize { blank() -> Self471 unsafe fn blank() -> Self { 472 GetUsize { 473 len: mem::size_of::<c_int>() as socklen_t, 474 val: mem::zeroed(), 475 } 476 } 477 ffi_ptr(&mut self) -> *mut c_void478 fn ffi_ptr(&mut self) -> *mut c_void { 479 &mut self.val as *mut c_int as *mut c_void 480 } 481 ffi_len(&mut self) -> *mut socklen_t482 fn ffi_len(&mut self) -> *mut socklen_t { 483 &mut self.len 484 } 485 unwrap(self) -> usize486 unsafe fn unwrap(self) -> usize { 487 assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation"); 488 self.val as usize 489 } 490 } 491 492 /// Setter for an `usize` value. 493 struct SetUsize { 494 val: c_int, 495 } 496 497 unsafe impl<'a> Set<'a, usize> for SetUsize { new(val: &'a usize) -> SetUsize498 fn new(val: &'a usize) -> SetUsize { 499 SetUsize { val: *val as c_int } 500 } 501 ffi_ptr(&self) -> *const c_void502 fn ffi_ptr(&self) -> *const c_void { 503 &self.val as *const c_int as *const c_void 504 } 505 ffi_len(&self) -> socklen_t506 fn ffi_len(&self) -> socklen_t { 507 mem::size_of::<c_int>() as socklen_t 508 } 509 } 510 511 /// Getter for a `OsString` value. 512 struct GetOsString<T: AsMut<[u8]>> { 513 len: socklen_t, 514 val: T, 515 } 516 517 unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> { blank() -> Self518 unsafe fn blank() -> Self { 519 GetOsString { 520 len: mem::size_of::<T>() as socklen_t, 521 val: mem::zeroed(), 522 } 523 } 524 ffi_ptr(&mut self) -> *mut c_void525 fn ffi_ptr(&mut self) -> *mut c_void { 526 &mut self.val as *mut T as *mut c_void 527 } 528 ffi_len(&mut self) -> *mut socklen_t529 fn ffi_len(&mut self) -> *mut socklen_t { 530 &mut self.len 531 } 532 unwrap(mut self) -> OsString533 unsafe fn unwrap(mut self) -> OsString { 534 OsStr::from_bytes(self.val.as_mut()).to_owned() 535 } 536 } 537 538 /// Setter for a `OsString` value. 539 struct SetOsString<'a> { 540 val: &'a OsStr, 541 } 542 543 unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> { new(val: &'a OsString) -> SetOsString544 fn new(val: &'a OsString) -> SetOsString { 545 SetOsString { val: val.as_os_str() } 546 } 547 ffi_ptr(&self) -> *const c_void548 fn ffi_ptr(&self) -> *const c_void { 549 self.val.as_bytes().as_ptr() as *const c_void 550 } 551 ffi_len(&self) -> socklen_t552 fn ffi_len(&self) -> socklen_t { 553 self.val.len() as socklen_t 554 } 555 } 556 557 558 #[cfg(test)] 559 mod test { 560 #[cfg(any(target_os = "android", target_os = "linux"))] 561 #[test] can_get_peercred_on_unix_socket()562 fn can_get_peercred_on_unix_socket() { 563 use super::super::*; 564 565 let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap(); 566 let a_cred = getsockopt(a, super::PeerCredentials).unwrap(); 567 let b_cred = getsockopt(b, super::PeerCredentials).unwrap(); 568 assert_eq!(a_cred, b_cred); 569 assert!(a_cred.pid() != 0); 570 } 571 572 #[test] is_socket_type_unix()573 fn is_socket_type_unix() { 574 use super::super::*; 575 use ::unistd::close; 576 577 let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap(); 578 let a_type = getsockopt(a, super::SockType).unwrap(); 579 assert!(a_type == SockType::Stream); 580 close(a).unwrap(); 581 close(b).unwrap(); 582 } 583 584 #[test] is_socket_type_dgram()585 fn is_socket_type_dgram() { 586 use super::super::*; 587 use ::unistd::close; 588 589 let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap(); 590 let s_type = getsockopt(s, super::SockType).unwrap(); 591 assert!(s_type == SockType::Datagram); 592 close(s).unwrap(); 593 } 594 595 #[cfg(any(target_os = "freebsd", 596 target_os = "linux", 597 target_os = "nacl"))] 598 #[test] can_get_listen_on_tcp_socket()599 fn can_get_listen_on_tcp_socket() { 600 use super::super::*; 601 use ::unistd::close; 602 603 let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); 604 let s_listening = getsockopt(s, super::AcceptConn).unwrap(); 605 assert!(!s_listening); 606 listen(s, 10).unwrap(); 607 let s_listening2 = getsockopt(s, super::AcceptConn).unwrap(); 608 assert!(s_listening2); 609 close(s).unwrap(); 610 } 611 612 #[cfg(target_os = "linux")] 613 #[test] is_so_mark_functional()614 fn is_so_mark_functional() { 615 use super::super::*; 616 use ::unistd::Uid; 617 use ::std::io::{self, Write}; 618 619 if !Uid::current().is_root() { 620 let stderr = io::stderr(); 621 let mut handle = stderr.lock(); 622 writeln!(handle, "SO_MARK requires root privileges. Skipping test.").unwrap(); 623 return; 624 } 625 626 let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap(); 627 setsockopt(s, super::Mark, &1337).unwrap(); 628 let mark = getsockopt(s, super::Mark).unwrap(); 629 assert_eq!(mark, 1337); 630 } 631 } 632