pub struct FdIter {
#[cfg(any(
target_os = "linux",
target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "netbsd",
target_os = "solaris",
target_os = "illumos",
))]
pub(crate) dirfd_iter: Option<super::dirfd::DirFdIter>,
pub(crate) curfd: libc::c_int,
pub(crate) possible: bool,
pub(crate) maxfd: Option<libc::c_int>,
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
pub(crate) skip_nfds: bool,
}
impl FdIter {
fn get_maxfd_direct(&self) -> libc::c_int {
#[cfg(target_os = "netbsd")]
unsafe {
*libc::__errno() = 0;
let maxfd = libc::fcntl(0, libc::F_MAXFD);
if maxfd >= 0 {
return maxfd;
} else if maxfd == -1 && *libc::__errno() == 0 {
return -1;
}
}
#[cfg(target_os = "freebsd")]
if !self.skip_nfds {
let mib = [
libc::CTL_KERN,
libc::KERN_PROC,
crate::sys::KERN_PROC_NFDS,
0,
];
let mut nfds: libc::c_int = 0;
let mut oldlen = core::mem::size_of::<libc::c_int>();
if unsafe {
libc::sysctl(
mib.as_ptr(),
mib.len() as libc::c_uint,
&mut nfds as *mut libc::c_int as *mut libc::c_void,
&mut oldlen,
core::ptr::null(),
0,
)
} == 0
{
if let Some(maxfd) = Self::nfds_to_maxfd(nfds) {
return maxfd;
}
}
}
#[cfg(target_os = "openbsd")]
if !self.skip_nfds {
if let Some(maxfd) = Self::nfds_to_maxfd(unsafe { crate::sys::getdtablecount() }) {
return maxfd;
}
}
let fdlimit = unsafe { libc::sysconf(libc::_SC_OPEN_MAX) };
fdlimit.max(1024).min(65536) as libc::c_int - 1
}
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
#[inline]
fn nfds_to_maxfd(nfds: libc::c_int) -> Option<libc::c_int> {
if nfds == 0 {
return Some(-1);
} else if nfds < 0 {
return None;
} else if nfds >= 100 {
return None;
}
let mut nfds_found = 0;
for fd in 0..(nfds * 2) {
if crate::util::is_fd_valid(fd) {
nfds_found += 1;
if nfds_found >= nfds {
return Some(fd);
}
}
}
None
}
#[inline]
fn get_maxfd(&mut self) -> libc::c_int {
match self.maxfd {
Some(maxfd) => maxfd,
None => {
let maxfd = self.get_maxfd_direct();
debug_assert!(maxfd >= -1);
self.maxfd = Some(maxfd);
maxfd
}
}
}
#[inline]
pub fn is_possible_iter(&self) -> bool {
self.possible
}
}
impl Iterator for FdIter {
type Item = libc::c_int;
fn next(&mut self) -> Option<Self::Item> {
#[cfg(any(
target_os = "linux",
target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "netbsd",
target_os = "solaris",
target_os = "illumos",
))]
if let Some(dfd_iter) = self.dirfd_iter.as_mut() {
match dfd_iter.next() {
Ok(Some(fd)) => {
debug_assert!(fd >= self.curfd);
self.curfd = fd + 1;
return Some(fd);
}
Ok(None) => return None,
Err(_) => self.dirfd_iter = None,
}
}
let maxfd = self.get_maxfd();
while self.curfd <= maxfd {
let fd = self.curfd;
self.curfd += 1;
if self.possible || crate::util::is_fd_valid(fd) {
return Some(fd);
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
#[cfg(any(
target_os = "linux",
target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "netbsd",
target_os = "solaris",
target_os = "illumos",
))]
if let Some(dfd_iter) = self.dirfd_iter.as_ref() {
return dfd_iter.size_hint();
}
if let Some(maxfd) = self.maxfd {
if maxfd == -1 {
return (0, Some(0));
}
debug_assert!(maxfd > 0);
let diff = (maxfd as usize + 1).saturating_sub(self.curfd as usize);
(if self.possible { diff } else { 0 }, Some(diff))
} else {
(0, Some(libc::c_int::MAX as usize))
}
}
#[inline]
fn min(mut self) -> Option<Self::Item> {
self.next()
}
#[inline]
fn max(self) -> Option<Self::Item> {
self.last()
}
}
impl core::iter::FusedIterator for FdIter {}