use std::hash::Hash; use std::mem::{self, size_of, MaybeUninit}; use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; use std::path::Path; use std::{fmt, io, ptr};
#[cfg(windows)] use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0;
/// The address of a socket. /// /// `SockAddr`s may be constructed directly to and from the standard library /// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types. #[derive(Clone)] pubstruct SockAddr {
storage: sockaddr_storage,
len: socklen_t,
}
#[allow(clippy::len_without_is_empty)] impl SockAddr { /// Create a `SockAddr` from the underlying storage and its length. /// /// # Safety /// /// Caller must ensure that the address family and length match the type of /// storage address. For example if `storage.ss_family` is set to `AF_INET` /// the `storage` must be initialised as `sockaddr_in`, setting the content /// and length appropriately. /// /// # Examples /// /// ``` /// # fn main() -> std::io::Result<()> { /// # #[cfg(unix)] { /// use std::io; /// use std::mem; /// use std::os::unix::io::AsRawFd; /// /// use socket2::{SockAddr, Socket, Domain, Type}; /// /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?; /// /// // Initialise a `SocketAddr` byte calling `getsockname(2)`. /// let mut addr_storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; /// let mut len = mem::size_of_val(&addr_storage) as libc::socklen_t; /// /// // The `getsockname(2)` system call will intiliase `storage` for /// // us, setting `len` to the correct length. /// let res = unsafe { /// libc::getsockname( /// socket.as_raw_fd(), /// (&mut addr_storage as *mut libc::sockaddr_storage).cast(), /// &mut len, /// ) /// }; /// if res == -1 { /// return Err(io::Error::last_os_error()); /// } /// /// let address = unsafe { SockAddr::new(addr_storage, len) }; /// # drop(address); /// # } /// # Ok(()) /// # } /// ``` pubconstunsafefn new(storage: sockaddr_storage, len: socklen_t) -> SockAddr {
SockAddr { storage, len }
}
/// Initialise a `SockAddr` by calling the function `init`. /// /// The type of the address storage and length passed to the function `init` /// is OS/architecture specific. /// /// The address is zeroed before `init` is called and is thus valid to /// dereference and read from. The length initialised to the maximum length /// of the storage. /// /// # Safety /// /// Caller must ensure that the address family and length match the type of /// storage address. For example if `storage.ss_family` is set to `AF_INET` /// the `storage` must be initialised as `sockaddr_in`, setting the content /// and length appropriately. /// /// # Examples /// /// ``` /// # fn main() -> std::io::Result<()> { /// # #[cfg(unix)] { /// use std::io; /// use std::os::unix::io::AsRawFd; /// /// use socket2::{SockAddr, Socket, Domain, Type}; /// /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?; /// /// // Initialise a `SocketAddr` byte calling `getsockname(2)`. /// let (_, address) = unsafe { /// SockAddr::try_init(|addr_storage, len| { /// // The `getsockname(2)` system call will intiliase `storage` for /// // us, setting `len` to the correct length. /// if libc::getsockname(socket.as_raw_fd(), addr_storage.cast(), len) == -1 { /// Err(io::Error::last_os_error()) /// } else { /// Ok(()) /// } /// }) /// }?; /// # drop(address); /// # } /// # Ok(()) /// # } /// ``` pubunsafefn try_init<F, T>(init: F) -> io::Result<(T, SockAddr)> where
F: FnOnce(*mut sockaddr_storage, *mut socklen_t) -> io::Result<T>,
{ const STORAGE_SIZE: socklen_t = size_of::<sockaddr_storage>() as socklen_t; // NOTE: `SockAddr::unix` depends on the storage being zeroed before // calling `init`. // NOTE: calling `recvfrom` with an empty buffer also depends on the // storage being zeroed before calling `init` as the OS might not // initialise it. letmut storage = MaybeUninit::<sockaddr_storage>::zeroed(); letmut len = STORAGE_SIZE;
init(storage.as_mut_ptr(), &mut len).map(|res| {
debug_assert!(len <= STORAGE_SIZE, "overflown address storage"); let addr = SockAddr { // Safety: zeroed-out `sockaddr_storage` is valid, caller must // ensure at least `len` bytes are valid.
storage: storage.assume_init(),
len,
};
(res, addr)
})
}
/// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path. /// /// Returns an error if the path is longer than `SUN_LEN`. pubfn unix<P>(path: P) -> io::Result<SockAddr> where
P: AsRef<Path>,
{ crate::sys::unix_sockaddr(path.as_ref())
}
/// Set the length of the address. /// /// # Safety /// /// Caller must ensure that the address up to `length` bytes are properly /// initialised. pubunsafefn set_length(&mutself, length: socklen_t) { self.len = length;
}
/// Returns this address's `Domain`. pubconstfn domain(&self) -> Domain {
Domain(self.storage.ss_family as c_int)
}
/// Returns the size of this address in bytes. pubconstfn len(&self) -> socklen_t { self.len
}
/// Returns a raw pointer to the address. pubconstfn as_ptr(&self) -> *const sockaddr {
ptr::addr_of!(self.storage).cast()
}
/// Retuns the address as the storage. pubconstfn as_storage(self) -> sockaddr_storage { self.storage
}
/// Returns true if this address is in the `AF_INET` (IPv4) family, false otherwise. pubconstfn is_ipv4(&self) -> bool { self.storage.ss_family == AF_INET as sa_family_t
}
/// Returns true if this address is in the `AF_INET6` (IPv6) family, false /// otherwise. pubconstfn is_ipv6(&self) -> bool { self.storage.ss_family == AF_INET6 as sa_family_t
}
/// Returns true if this address is of a unix socket (for local interprocess communication), /// i.e. it is from the `AF_UNIX` family, false otherwise. pubfn is_unix(&self) -> bool { self.storage.ss_family == AF_UNIX as sa_family_t
}
/// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4) /// or `AF_INET6` (IPv6) family, otherwise returns `None`. pubfn as_socket(&self) -> Option<SocketAddr> { ifself.storage.ss_family == AF_INET as sa_family_t { // SAFETY: if the `ss_family` field is `AF_INET` then storage must // be a `sockaddr_in`. let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in>()) }; let ip = crate::sys::from_in_addr(addr.sin_addr); let port = u16::from_be(addr.sin_port);
Some(SocketAddr::V4(SocketAddrV4::new(ip, port)))
} elseifself.storage.ss_family == AF_INET6 as sa_family_t { // SAFETY: if the `ss_family` field is `AF_INET6` then storage must // be a `sockaddr_in6`. let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in6>()) }; let ip = crate::sys::from_in6_addr(addr.sin6_addr); let port = u16::from_be(addr.sin6_port);
Some(SocketAddr::V6(SocketAddrV6::new(
ip,
port,
addr.sin6_flowinfo, #[cfg(unix)]
addr.sin6_scope_id, #[cfg(windows)] unsafe {
addr.Anonymous.sin6_scope_id
},
)))
} else {
None
}
}
/// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET` /// family. pubfn as_socket_ipv4(&self) -> Option<SocketAddrV4> { matchself.as_socket() {
Some(SocketAddr::V4(addr)) => Some(addr),
_ => None,
}
}
/// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6` /// family. pubfn as_socket_ipv6(&self) -> Option<SocketAddrV6> { matchself.as_socket() {
Some(SocketAddr::V6(addr)) => Some(addr),
_ => None,
}
}
/// Returns the initialised storage bytes. fn as_bytes(&self) -> &[u8] { // SAFETY: `self.storage` is a C struct which can always be treated a // slice of bytes. Futhermore we ensure we don't read any unitialised // bytes by using `self.len`. unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) }
}
}
fn test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr) {
assert!(calculate_hash(&a0) == calculate_hash(&a0));
assert!(calculate_hash(&a0) == calculate_hash(&a1)); // technically unequal values can have the same hash, in this case x != z and both have different hashes
assert!(calculate_hash(&a0) != calculate_hash(&b));
}
fn calculate_hash(x: &SockAddr) -> u64 { use std::collections::hash_map::DefaultHasher; use std::hash::Hasher;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.