Skip to content

Instantly share code, notes, and snippets.

@pjambet
Created November 22, 2020 22:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pjambet/5992351aa6b16a6cfb126cbb67db785b to your computer and use it in GitHub Desktop.
Save pjambet/5992351aa6b16a6cfb126cbb67db785b to your computer and use it in GitHub Desktop.
select/pselect in Rust
extern crate libc;
use std::{io,mem,ptr,time};
use std::os::unix::io::RawFd;
use std::net::TcpStream;
use std::os::unix::io::AsRawFd;
// use std::io::Read;
pub struct FdSet(libc::fd_set);
impl FdSet {
pub fn new() -> FdSet {
unsafe {
let mut raw_fd_set = mem::uninitialized::<libc::fd_set>();
// let mut raw_fd_set = mem::MaybeUninit::<libc::fd_set>::uninit().assume_init();
libc::FD_ZERO(&mut raw_fd_set);
FdSet(raw_fd_set)
}
}
pub fn clear(&mut self, fd: RawFd) {
unsafe {
libc::FD_CLR(fd, &mut self.0);
}
}
pub fn set(&mut self, fd: RawFd) {
unsafe {
libc::FD_SET(fd, &mut self.0);
}
}
pub fn is_set(&mut self, fd: RawFd) -> bool {
unsafe {
libc::FD_ISSET(fd, &mut self.0)
}
}
}
pub fn pselect (nfds: libc::c_int,
readfds: Option<&mut FdSet>,
writefds: Option<&mut FdSet>,
errorfds: Option<&mut FdSet>,
// timeout: Option<&libc::timeval>,
timeout: Option<&libc::timespec>,
sigmask: Option<&libc::sigset_t>) -> io::Result<usize> {
fn to_fdset_ptr (opt: Option<&mut FdSet>) -> *mut libc::fd_set {
match opt {
None => ptr::null_mut(),
Some(&mut FdSet(ref mut raw_fd_set)) => raw_fd_set,
}
}
fn to_ptr<T> (opt: Option<&T>) -> *const T {
match opt {
None => ptr::null::<T>(),
Some(p) => p,
}
}
match unsafe {
libc::pselect(nfds,
to_fdset_ptr(readfds),
to_fdset_ptr(writefds),
to_fdset_ptr(errorfds),
to_ptr(timeout),
to_ptr(sigmask))
// libc::select(nfds, to_fdset_ptr(readfds), to_fdset_ptr(None), to_fdset_ptr(None), to_ptr::<libc::timeval>(timeout) as *mut libc::timeval)
} {
-1 => Err(io::Error::last_os_error()),
res => Ok(res as usize),
}
}
pub fn make_timeval(duration: time::Duration) -> libc::timeval {
libc::timeval {
tv_sec: duration.as_secs() as i64,
tv_usec: duration.subsec_micros() as i32,
}
}
pub fn make_timespec(duration: time::Duration) -> libc::timespec {
libc::timespec {
tv_sec: duration.as_secs() as i64,
tv_nsec: duration.subsec_nanos() as i64,
}
}
fn main() {
let five_seconds = time::Duration::new(60, 0);
let mut buffer = [0; 2];
let mut fd_set = FdSet::new();
if let Ok(stream) = TcpStream::connect("localhost:2000") {
// let mut fd_set = FdSet::new();
// println!("{}", stream.read(&mut buffer).unwrap());
println!("Connected to the server!, {}", stream.as_raw_fd());
fd_set.clear(stream.as_raw_fd());
let raw_fd = stream.as_raw_fd();
fd_set.set(raw_fd);
println!("isset: {}", fd_set.is_set(stream.as_raw_fd()));
// if let Ok(res) = pselect(stream.as_raw_fd() + 1, Some(&mut fd_set), None, None, Some(&make_timeval(five_seconds)), None) {
if let Ok(res) = pselect(stream.as_raw_fd() + 1, Some(&mut fd_set), None, None, Some(&make_timespec(five_seconds)), None) {
println!("Got result back! {}", res);
} else {
println!("Failed to pselect");
}
} else {
println!("Couldn't connect to server...");
}
println!("Hello, world!");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment