Selaa lähdekoodia

Don't block forever in TapInterface.

Ideally Devices should be non-blocking, but that would be really
annoying to implement, so for now, to get the examples working,
I'm using this hack.
whitequark 8 vuotta sitten
vanhempi
commit
be9d0a202d
4 muutettua tiedostoa jossa 40 lisäystä ja 6 poistoa
  1. 3 1
      examples/client.rs
  2. 2 1
      examples/server.rs
  3. 25 1
      src/phy/sys/tap_interface.rs
  4. 10 3
      src/phy/tap_interface.rs

+ 3 - 1
examples/client.rs

@@ -8,6 +8,7 @@ mod utils;
 
 use std::str::{self, FromStr};
 use std::time::Instant;
+use smoltcp::Error;
 use smoltcp::wire::{EthernetAddress, IpAddress};
 use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface};
 use smoltcp::socket::{AsSocket, SocketSet};
@@ -49,6 +50,7 @@ fn main() {
                 debug!("connected");
             } else if !socket.is_active() && tcp_active {
                 debug!("disconnected");
+                break
             }
             tcp_active = socket.is_active();
 
@@ -79,7 +81,7 @@ fn main() {
         let timestamp_ms = (timestamp.as_secs() * 1000) +
                            (timestamp.subsec_nanos() / 1000000) as u64;
         match iface.poll(&mut sockets, timestamp_ms) {
-            Ok(()) => (),
+            Ok(()) | Err(Error::Exhausted) => (),
             Err(e) => debug!("poll error: {}", e)
         }
     }

+ 2 - 1
examples/server.rs

@@ -8,6 +8,7 @@ mod utils;
 
 use std::str;
 use std::time::Instant;
+use smoltcp::Error;
 use smoltcp::wire::{EthernetAddress, IpAddress};
 use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface};
 use smoltcp::socket::{AsSocket, SocketSet};
@@ -128,7 +129,7 @@ fn main() {
         let timestamp_ms = (timestamp.as_secs() * 1000) +
                            (timestamp.subsec_nanos() / 1000000) as u64;
         match iface.poll(&mut sockets, timestamp_ms) {
-            Ok(()) => (),
+            Ok(()) | Err(Error::Exhausted) => (),
             Err(e) => debug!("poll error: {}", e)
         }
     }

+ 25 - 1
src/phy/sys/tap_interface.rs

@@ -1,5 +1,6 @@
-use libc;
+use std::mem;
 use std::io;
+use libc;
 use super::*;
 
 #[cfg(target_os = "linux")]
@@ -29,7 +30,28 @@ impl TapInterfaceDesc {
         ifreq_ioctl(self.lower, &mut self.ifreq, imp::TUNSETIFF).map(|_| ())
     }
 
+    fn wait(&mut self, ms: u32) -> io::Result<bool> {
+        unsafe {
+            let mut readfds = mem::uninitialized::<libc::fd_set>();
+            libc::FD_ZERO(&mut readfds);
+            libc::FD_SET(self.lower, &mut readfds);
+            let mut writefds = mem::uninitialized::<libc::fd_set>();
+            libc::FD_ZERO(&mut writefds);
+            let mut exceptfds = mem::uninitialized::<libc::fd_set>();
+            libc::FD_ZERO(&mut exceptfds);
+            let mut timeout = libc::timeval { tv_sec: 0, tv_usec: (ms * 1_000) as i64 };
+            let res = libc::select(self.lower + 1, &mut readfds, &mut writefds, &mut exceptfds,
+                                   &mut timeout);
+            if res == -1 { return Err(io::Error::last_os_error()) }
+            Ok(res == 0)
+        }
+    }
+
     pub fn recv(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
+        // FIXME: here we don't wait forever, in case we need to send several packets in a row
+        // ideally this would be implemented by going full nonblocking
+        if self.wait(100)? { return Err(io::ErrorKind::TimedOut)? }
+
         unsafe {
             let len = libc::read(self.lower, buffer.as_mut_ptr() as *mut libc::c_void,
                                  buffer.len());
@@ -39,6 +61,8 @@ impl TapInterfaceDesc {
     }
 
     pub fn send(&mut self, buffer: &[u8]) -> io::Result<usize> {
+        self.wait(100)?;
+
         unsafe {
             let len = libc::write(self.lower, buffer.as_ptr() as *const libc::c_void,
                                   buffer.len());

+ 10 - 3
src/phy/tap_interface.rs

@@ -38,9 +38,16 @@ impl Device for TapInterface {
     fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
         let mut lower = self.lower.borrow_mut();
         let mut buffer = vec![0; self.mtu];
-        let size = lower.recv(&mut buffer[..]).unwrap();
-        buffer.resize(size, 0);
-        Ok(buffer)
+        match lower.recv(&mut buffer[..]) {
+            Ok(size) => {
+                buffer.resize(size, 0);
+                Ok(buffer)
+            }
+            Err(ref err) if err.kind() == io::ErrorKind::TimedOut => {
+                Err(Error::Exhausted)
+            }
+            Err(err) => panic!(err)
+        }
     }
 
     fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error> {