diff --git a/Cargo.toml b/Cargo.toml index b441f44..430915c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ required-features = ["std", "phy-tap_interface", "socket-tcp", "socket-udp"] [[example]] name = "loopback" -required-features = ["alloc", "proto-ipv4"] +required-features = ["log", "socket-tcp"] # This is really a test, but it requires root privileges for setup (the tap interface) # so it is built as an example. diff --git a/examples/client.rs b/examples/client.rs index d67760a..31d7cdc 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -59,6 +59,9 @@ fn main() { let mut tcp_active = false; loop { + let timestamp = utils::millis_since(startup_time); + iface.poll(&mut sockets, timestamp).expect("poll error"); + { let mut socket = sockets.get::(tcp_handle); if socket.is_active() && !tcp_active { @@ -92,8 +95,6 @@ fn main() { } } - let timestamp = utils::millis_since(startup_time); - let poll_at = iface.poll(&mut sockets, timestamp).expect("poll error"); - phy_wait(fd, poll_at.map(|at| at.saturating_sub(timestamp))).expect("wait error"); + phy_wait(fd, iface.poll_delay(&sockets, timestamp)).expect("wait error"); } } diff --git a/examples/httpclient.rs b/examples/httpclient.rs index ea16658..436f96d 100644 --- a/examples/httpclient.rs +++ b/examples/httpclient.rs @@ -59,6 +59,9 @@ fn main() { let mut state = State::Connect; loop { + let timestamp = utils::millis_since(startup_time); + iface.poll(&mut sockets, timestamp).expect("poll error"); + { let mut socket = sockets.get::(tcp_handle); @@ -94,8 +97,6 @@ fn main() { } } - let timestamp = utils::millis_since(startup_time); - let poll_at = iface.poll(&mut sockets, timestamp).expect("poll error"); - phy_wait(fd, poll_at.map(|at| at.saturating_sub(timestamp))).expect("wait error"); + phy_wait(fd, iface.poll_delay(&sockets, timestamp)).expect("wait error"); } } diff --git a/examples/loopback.rs b/examples/loopback.rs index 27e7a1c..496d8fb 100644 --- a/examples/loopback.rs +++ b/examples/loopback.rs @@ -124,6 +124,8 @@ fn main() { let mut did_connect = false; let mut done = false; while !done && clock.elapsed() < 10_000 { + iface.poll(&mut socket_set, clock.elapsed()).expect("poll error"); + { let mut socket = socket_set.get::(server_handle); if !socket.is_active() && !socket.is_listening() { @@ -161,16 +163,14 @@ fn main() { } } - match iface.poll(&mut socket_set, clock.elapsed()) { - Ok(Some(poll_at)) if poll_at < clock.elapsed() => + match iface.poll_delay(&socket_set, clock.elapsed()) { + Some(0) => debug!("resuming"), - Ok(Some(poll_at)) => { - let delay = poll_at - clock.elapsed(); + Some(delay) => { debug!("sleeping for {} ms", delay); clock.advance(delay) } - Ok(None) => clock.advance(1), - Err(e) => debug!("poll error: {}", e) + None => clock.advance(1) } } diff --git a/examples/ping.rs b/examples/ping.rs index ba6a43e..15ab2a9 100644 --- a/examples/ping.rs +++ b/examples/ping.rs @@ -77,6 +77,9 @@ fn main() { let endpoint = IpAddress::Ipv4(remote_addr); loop { + let timestamp = utils::millis_since(startup_time); + iface.poll(&mut sockets, timestamp).expect("poll error"); + { let mut socket = sockets.get::(icmp_handle); if !socket.is_open() { @@ -141,7 +144,7 @@ fn main() { let timestamp = utils::millis_since(startup_time); - let poll_at = iface.poll(&mut sockets, timestamp).expect("poll error"); + let poll_at = iface.poll_at(&sockets, timestamp); let resume_at = [poll_at, Some(send_at)].iter().flat_map(|x| *x).min(); phy_wait(fd, resume_at.map(|at| at.saturating_sub(timestamp))).expect("wait error"); } diff --git a/examples/server.rs b/examples/server.rs index bb01892..2d22a9d 100644 --- a/examples/server.rs +++ b/examples/server.rs @@ -71,6 +71,9 @@ fn main() { let mut tcp_6970_active = false; loop { + let timestamp = utils::millis_since(startup_time); + iface.poll(&mut sockets, timestamp).expect("poll error"); + // udp:6969: respond "hello" { let mut socket = sockets.get::(udp_handle); @@ -187,8 +190,6 @@ fn main() { } } - let timestamp = utils::millis_since(startup_time); - let poll_at = iface.poll(&mut sockets, timestamp).expect("poll error"); - phy_wait(fd, poll_at.map(|at| at.saturating_sub(timestamp))).expect("wait error"); + phy_wait(fd, iface.poll_delay(&sockets, timestamp)).expect("wait error"); } } diff --git a/examples/stress.rs b/examples/stress.rs index b88811c..e031ec0 100644 --- a/examples/stress.rs +++ b/examples/stress.rs @@ -41,7 +41,7 @@ fn client(kind: Client) { match result { Ok(0) => break, Ok(result) => { - print!("(P:{})", result); + // print!("(P:{})", result); processed += result } Err(err) => panic!("cannot process: {}", err) @@ -54,6 +54,9 @@ fn client(kind: Client) { static CLIENT_DONE: AtomicBool = ATOMIC_BOOL_INIT; fn main() { + #[cfg(feature = "log")] + utils::setup_logging("info"); + let (mut opts, mut free) = utils::create_options(); utils::add_tap_options(&mut opts, &mut free); utils::add_middleware_options(&mut opts, &mut free); @@ -97,6 +100,9 @@ fn main() { let mut processed = 0; while !CLIENT_DONE.load(Ordering::SeqCst) { + let timestamp = utils::millis_since(startup_time); + iface.poll(&mut sockets, timestamp).expect("poll error"); + // tcp:1234: emit data { let mut socket = sockets.get::(tcp1_handle); @@ -133,8 +139,6 @@ fn main() { } } - let timestamp = utils::millis_since(startup_time); - let poll_at = iface.poll(&mut sockets, timestamp).expect("poll error"); - phy_wait(fd, poll_at.map(|at| at.saturating_sub(timestamp))).expect("wait error"); + phy_wait(fd, iface.poll_delay(&sockets, timestamp)).expect("wait error"); } } diff --git a/examples/utils.rs b/examples/utils.rs index 90dc265..684c15d 100644 --- a/examples/utils.rs +++ b/examples/utils.rs @@ -14,7 +14,9 @@ use log::{LogLevel, LogLevelFilter, LogRecord}; use env_logger::LogBuilder; use getopts::{Options, Matches}; -use smoltcp::phy::{Device, EthernetTracer, FaultInjector, TapInterface}; +use smoltcp::phy::{Device, EthernetTracer, FaultInjector}; +#[cfg(feature = "phy-tap_interface")] +use smoltcp::phy::TapInterface; use smoltcp::phy::{PcapWriter, PcapSink, PcapMode, PcapLinkType}; #[cfg(feature = "log")] diff --git a/src/iface/ethernet.rs b/src/iface/ethernet.rs index 0290dc4..a3c3552 100644 --- a/src/iface/ethernet.rs +++ b/src/iface/ethernet.rs @@ -261,10 +261,9 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT> /// The timestamp must be a number of milliseconds, monotonically increasing /// since an arbitrary moment in time, such as system startup. /// - /// This function returns a _soft deadline_ for calling it the next time. - /// That is, if `iface.poll(&mut sockets, 1000)` returns `Ok(Some(2000))`, - /// it harmless (but wastes energy) to call it 500 ms later, and potentially - /// harmful (impacting quality of service) to call it 1500 ms later. + /// This function returns a boolean value indicating whether any packets were + /// processed or emitted, and thus, whether the readiness of any socket might + /// have changed. /// /// # Errors /// This method will routinely return errors in response to normal network @@ -276,18 +275,50 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT> /// packets containing any unsupported protocol, option, or form, which is /// a very common occurrence and on a production system it should not even /// be logged. - pub fn poll(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result> { - self.socket_egress(sockets, timestamp)?; - - if self.socket_ingress(sockets, timestamp)? { - Ok(Some(0)) - } else { - Ok(sockets.iter().filter_map(|socket| { - let socket_poll_at = socket.poll_at(); - socket.meta().poll_at(socket_poll_at, |ip_addr| - self.inner.has_neighbor(&ip_addr, timestamp)) - }).min()) + pub fn poll(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result { + let mut readiness_may_have_changed = false; + loop { + let processed_any = self.socket_ingress(sockets, timestamp)?; + let emitted_any = self.socket_egress(sockets, timestamp)?; + if processed_any || emitted_any { + readiness_may_have_changed = true; + } else { + break + } } + Ok(readiness_may_have_changed) + } + + /// Return a _soft deadline_ for calling [poll] the next time. + /// That is, if `iface.poll_at(&sockets, 1000)` returns `Ok(Some(2000))`, + /// you should call call [poll] in 1000 ms; it is harmless (but wastes energy) + /// to call it 500 ms later, and potentially harmful (impacting quality of service) + /// to call it 1500 ms later. + /// + /// The timestamp argument is the same as for [poll]. + /// + /// [poll]: #method.poll + pub fn poll_at(&self, sockets: &SocketSet, timestamp: u64) -> Option { + sockets.iter().filter_map(|socket| { + let socket_poll_at = socket.poll_at(); + socket.meta().poll_at(socket_poll_at, |ip_addr| + self.inner.has_neighbor(&ip_addr, timestamp)) + }).min() + } + + /// Return an _advisory wait time_ for calling [poll] the next time. + /// That is, if `iface.poll_at(&sockets, 1000)` returns `Ok(Some(1000))`, + /// you should call call [poll] in 1000 ms; it is harmless (but wastes energy) + /// to call it 500 ms later, and potentially harmful (impacting quality of service) + /// to call it 1500 ms later. + /// + /// This is a shortcut for `poll_at(..., timestamp).map(|at| at.saturating_sub(timestamp))`. + /// + /// The timestamp argument is the same as for [poll]. + /// + /// [poll]: #method.poll + pub fn poll_delay(&self, sockets: &SocketSet, timestamp: u64) -> Option { + self.poll_at(sockets, timestamp).map(|at| at.saturating_sub(timestamp)) } fn socket_ingress(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result { @@ -298,29 +329,29 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT> None => break, Some(tokens) => tokens, }; - let dispatch_result = rx_token.consume(timestamp, |frame| { - let response = inner.process_ethernet(sockets, timestamp, &frame).map_err(|err| { + rx_token.consume(timestamp, |frame| { + inner.process_ethernet(sockets, timestamp, &frame).map_err(|err| { net_debug!("cannot process ingress packet: {}", err); net_debug!("packet dump follows:\n{}", PrettyPrinter::>::new("", &frame)); err - })?; - processed_any = true; - - inner.dispatch(tx_token, timestamp, response) - }); - dispatch_result.map_err(|err| { - net_debug!("cannot dispatch response packet: {}", err); - err + }).and_then(|response| { + processed_any = true; + inner.dispatch(tx_token, timestamp, response).map_err(|err| { + net_debug!("cannot dispatch response packet: {}", err); + err + }) + }) })?; } Ok(processed_any) } - fn socket_egress(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result<()> { + fn socket_egress(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result { let mut caps = self.device.capabilities(); caps.max_transmission_unit -= EthernetFrame::<&[u8]>::header_len(); + let mut emitted_any = false; for mut socket in sockets.iter_mut() { if !socket.meta_mut().egress_permitted(|ip_addr| self.inner.has_neighbor(&ip_addr, timestamp)) { @@ -392,10 +423,10 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT> socket.meta().handle, err); return Err(err) } - (Ok(()), Ok(())) => () + (Ok(()), Ok(())) => emitted_any = true } } - Ok(()) + Ok(emitted_any) } }