summaryrefslogtreecommitdiffstats
path: root/third_party/rust/socket2/src/sockaddr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/socket2/src/sockaddr.rs')
-rw-r--r--third_party/rust/socket2/src/sockaddr.rs215
1 files changed, 215 insertions, 0 deletions
diff --git a/third_party/rust/socket2/src/sockaddr.rs b/third_party/rust/socket2/src/sockaddr.rs
new file mode 100644
index 0000000000..c6c9ef1d44
--- /dev/null
+++ b/third_party/rust/socket2/src/sockaddr.rs
@@ -0,0 +1,215 @@
+use std::fmt;
+use std::mem;
+use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
+use std::ptr;
+
+#[cfg(any(unix, target_os = "redox"))]
+use libc::{
+ sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET,
+ AF_INET6,
+};
+#[cfg(windows)]
+use winapi::shared::ws2def::{
+ ADDRESS_FAMILY as sa_family_t, AF_INET, AF_INET6, SOCKADDR as sockaddr,
+ SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage,
+};
+#[cfg(windows)]
+use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6;
+#[cfg(windows)]
+use winapi::um::ws2tcpip::socklen_t;
+
+use crate::SockAddr;
+
+impl fmt::Debug for SockAddr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut builder = fmt.debug_struct("SockAddr");
+ builder.field("family", &self.family());
+ if let Some(addr) = self.as_inet() {
+ builder.field("inet", &addr);
+ } else if let Some(addr) = self.as_inet6() {
+ builder.field("inet6", &addr);
+ }
+ builder.finish()
+ }
+}
+
+impl SockAddr {
+ /// Constructs a `SockAddr` from its raw components.
+ pub unsafe fn from_raw_parts(addr: *const sockaddr, len: socklen_t) -> SockAddr {
+ let mut storage = mem::uninitialized::<sockaddr_storage>();
+ ptr::copy_nonoverlapping(
+ addr as *const _ as *const u8,
+ &mut storage as *mut _ as *mut u8,
+ len as usize,
+ );
+
+ SockAddr {
+ storage: storage,
+ len: len,
+ }
+ }
+
+ /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
+ ///
+ /// This function is only available on Unix when the `unix` feature is
+ /// enabled.
+ ///
+ /// # Failure
+ ///
+ /// Returns an error if the path is longer than `SUN_LEN`.
+ #[cfg(all(unix, feature = "unix"))]
+ pub fn unix<P>(path: P) -> ::std::io::Result<SockAddr>
+ where
+ P: AsRef<::std::path::Path>,
+ {
+ use libc::{c_char, sockaddr_un, AF_UNIX};
+ use std::cmp::Ordering;
+ use std::io;
+ use std::os::unix::ffi::OsStrExt;
+
+ unsafe {
+ let mut addr = mem::zeroed::<sockaddr_un>();
+ addr.sun_family = AF_UNIX as sa_family_t;
+
+ let bytes = path.as_ref().as_os_str().as_bytes();
+
+ match (bytes.get(0), bytes.len().cmp(&addr.sun_path.len())) {
+ // Abstract paths don't need a null terminator
+ (Some(&0), Ordering::Greater) => {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "path must be no longer than SUN_LEN",
+ ));
+ }
+ (Some(&0), _) => {}
+ (_, Ordering::Greater) | (_, Ordering::Equal) => {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "path must be shorter than SUN_LEN",
+ ));
+ }
+ _ => {}
+ }
+
+ for (dst, src) in addr.sun_path.iter_mut().zip(bytes) {
+ *dst = *src as c_char;
+ }
+ // null byte for pathname is already there since we zeroed up front
+
+ let base = &addr as *const _ as usize;
+ let path = &addr.sun_path as *const _ as usize;
+ let sun_path_offset = path - base;
+
+ let mut len = sun_path_offset + bytes.len();
+ match bytes.get(0) {
+ Some(&0) | None => {}
+ Some(_) => len += 1,
+ }
+ Ok(SockAddr::from_raw_parts(
+ &addr as *const _ as *const _,
+ len as socklen_t,
+ ))
+ }
+ }
+
+ unsafe fn as_<T>(&self, family: sa_family_t) -> Option<T> {
+ if self.storage.ss_family != family {
+ return None;
+ }
+
+ Some(mem::transmute_copy(&self.storage))
+ }
+
+ /// Returns this address as a `SocketAddrV4` if it is in the `AF_INET`
+ /// family.
+ pub fn as_inet(&self) -> Option<SocketAddrV4> {
+ unsafe { self.as_(AF_INET as sa_family_t) }
+ }
+
+ /// Returns this address as a `SocketAddrV6` if it is in the `AF_INET6`
+ /// family.
+ pub fn as_inet6(&self) -> Option<SocketAddrV6> {
+ unsafe { self.as_(AF_INET6 as sa_family_t) }
+ }
+
+ /// Returns this address's family.
+ pub fn family(&self) -> sa_family_t {
+ self.storage.ss_family
+ }
+
+ /// Returns the size of this address in bytes.
+ pub fn len(&self) -> socklen_t {
+ self.len
+ }
+
+ /// Returns a raw pointer to the address.
+ pub fn as_ptr(&self) -> *const sockaddr {
+ &self.storage as *const _ as *const _
+ }
+}
+
+// SocketAddrV4 and SocketAddrV6 are just wrappers around sockaddr_in and sockaddr_in6
+
+// check to make sure that the sizes at least match up
+fn _size_checks(v4: SocketAddrV4, v6: SocketAddrV6) {
+ unsafe {
+ mem::transmute::<SocketAddrV4, sockaddr_in>(v4);
+ mem::transmute::<SocketAddrV6, sockaddr_in6>(v6);
+ }
+}
+
+impl From<SocketAddrV4> for SockAddr {
+ fn from(addr: SocketAddrV4) -> SockAddr {
+ unsafe {
+ SockAddr::from_raw_parts(
+ &addr as *const _ as *const _,
+ mem::size_of::<SocketAddrV4>() as socklen_t,
+ )
+ }
+ }
+}
+
+impl From<SocketAddrV6> for SockAddr {
+ fn from(addr: SocketAddrV6) -> SockAddr {
+ unsafe {
+ SockAddr::from_raw_parts(
+ &addr as *const _ as *const _,
+ mem::size_of::<SocketAddrV6>() as socklen_t,
+ )
+ }
+ }
+}
+
+impl From<SocketAddr> for SockAddr {
+ fn from(addr: SocketAddr) -> SockAddr {
+ match addr {
+ SocketAddr::V4(addr) => addr.into(),
+ SocketAddr::V6(addr) => addr.into(),
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn inet() {
+ let raw = "127.0.0.1:80".parse::<SocketAddrV4>().unwrap();
+ let addr = SockAddr::from(raw);
+ assert!(addr.as_inet6().is_none());
+ let addr = addr.as_inet().unwrap();
+ assert_eq!(raw, addr);
+ }
+
+ #[test]
+ fn inet6() {
+ let raw = "[2001:db8::ff00:42:8329]:80"
+ .parse::<SocketAddrV6>()
+ .unwrap();
+ let addr = SockAddr::from(raw);
+ assert!(addr.as_inet().is_none());
+ let addr = addr.as_inet6().unwrap();
+ assert_eq!(raw, addr);
+ }
+}