Improved timeout handling.
This commit is contained in:
+56
-25
@@ -14,13 +14,13 @@ use buffer_pool::{Buffer, BufferPool};
|
||||
use device::NetworkDevice;
|
||||
use error::{Error, Result};
|
||||
use self::ip::IpScheme;
|
||||
use self::udp_socket::UdpScheme;
|
||||
use self::tcp_socket::TcpScheme;
|
||||
use self::udp::UdpScheme;
|
||||
use self::tcp::TcpScheme;
|
||||
|
||||
mod ip;
|
||||
mod socket;
|
||||
mod udp_socket;
|
||||
mod tcp_socket;
|
||||
mod udp;
|
||||
mod tcp;
|
||||
|
||||
type SocketSet = Rc<RefCell<smoltcp::socket::SocketSet<'static, 'static, 'static>>>;
|
||||
|
||||
@@ -44,7 +44,8 @@ pub struct Smolnetd {
|
||||
impl Smolnetd {
|
||||
const INGRESS_PACKET_SIZE: usize = 2048;
|
||||
const SOCKET_BUFFER_SIZE: usize = 128; //packets
|
||||
const CHECK_TIMEOUT_MS: i64 = 10;
|
||||
const MIN_CHECK_TIMEOUT_MS: i64 = 10;
|
||||
const MAX_CHECK_TIMEOUT_MS: i64 = 500;
|
||||
|
||||
pub fn new(
|
||||
network_file: File,
|
||||
@@ -95,41 +96,76 @@ impl Smolnetd {
|
||||
}
|
||||
|
||||
pub fn on_ip_scheme_event(&mut self) -> Result<Option<()>> {
|
||||
self.ip_scheme.on_scheme_event()
|
||||
self.ip_scheme.on_scheme_event()?;
|
||||
self.poll()?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn on_udp_scheme_event(&mut self) -> Result<Option<()>> {
|
||||
self.udp_scheme.on_scheme_event()
|
||||
self.udp_scheme.on_scheme_event()?;
|
||||
self.poll()?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn on_tcp_scheme_event(&mut self) -> Result<Option<()>> {
|
||||
self.tcp_scheme.on_scheme_event()
|
||||
self.tcp_scheme.on_scheme_event()?;
|
||||
self.poll()?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn on_time_event(&mut self) -> Result<Option<()>> {
|
||||
let timeout = self.poll()?;
|
||||
self.schedule_timeout(timeout)?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn schedule_timeout(&mut self, timeout: i64) -> Result<()> {
|
||||
let mut time = syscall::data::TimeSpec::default();
|
||||
if self.time_file.read(&mut time)? < mem::size_of::<syscall::data::TimeSpec>() {
|
||||
panic!();
|
||||
return Err(Error::from_syscall_error(
|
||||
syscall::Error::new(syscall::EBADF),
|
||||
"Can't read current time",
|
||||
));
|
||||
}
|
||||
let mut time_ms = time.tv_sec * 1000i64 + i64::from(time.tv_nsec) / 1_000_000i64;
|
||||
time_ms += Smolnetd::CHECK_TIMEOUT_MS;
|
||||
time_ms += timeout;
|
||||
time.tv_sec = time_ms / 1000;
|
||||
time.tv_nsec = ((time_ms % 1000) * 1_000_000) as i32;
|
||||
self.time_file
|
||||
.write_all(&time)
|
||||
.map_err(|e| Error::from_io_error(e, "Failed to write to time file"))?;
|
||||
|
||||
self.poll().map(Some)?;
|
||||
Ok(None)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn poll(&mut self) -> Result<()> {
|
||||
let timestamp = self.get_timestamp();
|
||||
// trace!("Poll {}", timestamp);
|
||||
if let Err(err) = self.iface.poll(&mut *self.socket_set.borrow_mut(), timestamp) {
|
||||
error!("poll error: {}", err);
|
||||
}
|
||||
self.notify_sockets()
|
||||
fn poll(&mut self) -> Result<i64> {
|
||||
let mut iter_limit = 10usize;
|
||||
let timeout = loop {
|
||||
iter_limit -= 1;
|
||||
if iter_limit == 0 {
|
||||
break 0;
|
||||
}
|
||||
let timestamp = self.get_timestamp();
|
||||
match self.iface
|
||||
.poll(&mut *self.socket_set.borrow_mut(), timestamp)
|
||||
{
|
||||
Err(err) => {
|
||||
error!("poll error: {}", err);
|
||||
break 0;
|
||||
}
|
||||
Ok(None) => {
|
||||
break ::std::u64::MAX;
|
||||
}
|
||||
Ok(Some(n)) if n > 0 => {
|
||||
break n;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
self.notify_sockets()?;
|
||||
Ok(::std::cmp::min(
|
||||
::std::cmp::max(Smolnetd::MIN_CHECK_TIMEOUT_MS, timeout as i64),
|
||||
Smolnetd::MAX_CHECK_TIMEOUT_MS,
|
||||
))
|
||||
}
|
||||
|
||||
fn read_frames(&mut self) -> Result<usize> {
|
||||
@@ -158,11 +194,6 @@ impl Smolnetd {
|
||||
(duration.as_secs() * 1000) + u64::from(duration.subsec_nanos() / 1_000_000)
|
||||
}
|
||||
|
||||
fn network_fsync(&mut self) -> syscall::Result<usize> {
|
||||
use std::os::unix::io::AsRawFd;
|
||||
syscall::fsync(self.network_file.borrow_mut().as_raw_fd() as usize)
|
||||
}
|
||||
|
||||
fn notify_sockets(&mut self) -> Result<()> {
|
||||
self.ip_scheme.notify_sockets()?;
|
||||
self.udp_scheme.notify_sockets()?;
|
||||
|
||||
@@ -320,7 +320,7 @@ where
|
||||
trace!("Adding {} to wait queie", fd);
|
||||
let wait_queues = self.wait_queue_map
|
||||
.entry(socket_handle)
|
||||
.or_insert_with(|| WaitQueues::default());
|
||||
.or_insert_with(WaitQueues::default);
|
||||
|
||||
let queue = match packet.a {
|
||||
syscall::SYS_READ => Ok(&mut wait_queues.read_queue),
|
||||
|
||||
@@ -112,8 +112,8 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
|
||||
return Err(syscall::Error::new(syscall::EACCES));
|
||||
}
|
||||
|
||||
let rx_packets = vec![0; 65535];
|
||||
let tx_packets = vec![0; 65535];
|
||||
let rx_packets = vec![0; 65_535];
|
||||
let tx_packets = vec![0; 65_535];
|
||||
let rx_buffer = TcpSocketBuffer::new(rx_packets);
|
||||
let tx_buffer = TcpSocketBuffer::new(tx_packets);
|
||||
let mut tcp_socket = TcpSocket::new(rx_buffer, tx_buffer);
|
||||
@@ -142,7 +142,7 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
|
||||
file: &SchemeFile<Self>,
|
||||
port_set: &mut Self::SchemeDataT,
|
||||
) -> syscall::Result<()> {
|
||||
if let &SchemeFile::Socket(_) = file {
|
||||
if let SchemeFile::Socket(_) = *file {
|
||||
port_set.release_port(self.local_endpoint().port);
|
||||
}
|
||||
Ok(())
|
||||
@@ -156,14 +156,14 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
|
||||
if !self.is_open() {
|
||||
return Err(syscall::Error::new(syscall::EADDRNOTAVAIL));
|
||||
}
|
||||
return if self.can_send() {
|
||||
if self.can_send() {
|
||||
self.send_slice(buf).expect("Can't send slice");
|
||||
Ok(buf.len())
|
||||
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(syscall::Error::new(syscall::EWOULDBLOCK))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn read_buf(
|
||||
@@ -171,14 +171,14 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
|
||||
file: &mut SocketFile<Self::DataT>,
|
||||
buf: &mut [u8],
|
||||
) -> syscall::Result<usize> {
|
||||
return if self.can_recv() {
|
||||
if self.can_recv() {
|
||||
let length = self.recv_slice(buf).expect("Can't receive slice");
|
||||
Ok(length)
|
||||
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(syscall::Error::new(syscall::EWOULDBLOCK))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn dup(
|
||||
@@ -144,7 +144,7 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
|
||||
file: &SchemeFile<Self>,
|
||||
port_set: &mut Self::SchemeDataT,
|
||||
) -> syscall::Result<()> {
|
||||
if let &SchemeFile::Socket(_) = file {
|
||||
if let SchemeFile::Socket(_) = *file {
|
||||
port_set.release_port(self.endpoint().port);
|
||||
}
|
||||
Ok(())
|
||||
@@ -158,14 +158,14 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
|
||||
if !file.data.is_specified() {
|
||||
return Err(syscall::Error::new(syscall::EADDRNOTAVAIL));
|
||||
}
|
||||
return if self.can_send() {
|
||||
if self.can_send() {
|
||||
self.send_slice(buf, file.data).expect("Can't send slice");
|
||||
Ok(buf.len())
|
||||
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(syscall::Error::new(syscall::EWOULDBLOCK))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn read_buf(
|
||||
@@ -173,14 +173,14 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
|
||||
file: &mut SocketFile<Self::DataT>,
|
||||
buf: &mut [u8],
|
||||
) -> syscall::Result<usize> {
|
||||
return if self.can_recv() {
|
||||
if self.can_recv() {
|
||||
let (length, _) = self.recv_slice(buf).expect("Can't receive slice");
|
||||
Ok(length)
|
||||
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(syscall::Error::new(syscall::EWOULDBLOCK))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn dup(
|
||||
Reference in New Issue
Block a user