瀏覽代碼

Implement a trait for sending and receiving frames.

whitequark 8 年之前
父節點
當前提交
6a8989381f
共有 4 個文件被更改,包括 72 次插入33 次删除
  1. 11 17
      examples/smoltcpdump.rs
  2. 1 1
      src/lib.rs
  3. 36 2
      src/phy/mod.rs
  4. 24 13
      src/phy/raw_socket.rs

+ 11 - 17
examples/smoltcpdump.rs

@@ -1,24 +1,16 @@
 extern crate smoltcp;
 
-use std::{env, io};
-use smoltcp::phy::RawSocket;
+use std::env;
+use smoltcp::phy::{Device, RawSocket};
 use smoltcp::wire::{EthernetFrame, EthernetProtocolType, ArpPacket};
 
-fn get<T>(result: Result<T, ()>) -> io::Result<T> {
-    result.map_err(|()| io::Error::new(io::ErrorKind::InvalidData,
-                                       "buffer too small"))
-          .into()
-}
-
-fn print_frame(socket: &mut RawSocket) -> io::Result<()> {
-    let buffer = try!(socket.capture());
-
-    let frame = try!(get(EthernetFrame::new(&buffer[..])));
+fn print_frame(buffer: &[u8]) -> Result<(), ()> {
+    let frame = try!(EthernetFrame::new(&buffer[..]));
     println!("{}", frame);
 
     match frame.ethertype() {
         EthernetProtocolType::Arp => {
-            let packet = try!(get(ArpPacket::new(frame.payload())));
+            let packet = try!(ArpPacket::new(frame.payload()));
             println!("| {}", packet);
         },
         _ => ()
@@ -31,9 +23,11 @@ fn main() {
     let ifname = env::args().nth(1).unwrap();
     let mut socket = RawSocket::new(ifname.as_ref()).unwrap();
     loop {
-        match print_frame(&mut socket) {
-            Ok(()) => (),
-            Err(e) => println!("Cannot print frame: {}", e)
-        }
+        socket.recv(|buffer| {
+            match print_frame(buffer) {
+                Ok(())  => (),
+                Err(()) => println!("buffer too small")
+            }
+        })
     }
 }

+ 1 - 1
src/lib.rs

@@ -1,4 +1,4 @@
-#![feature(range_contains)]
+#![feature(range_contains, associated_consts)]
 #![no_std]
 
 #[cfg(test)]

+ 36 - 2
src/phy/mod.rs

@@ -1,10 +1,44 @@
 //! Access to networking hardware.
 //!
-//! The `phy` module provides a way to capture and inject packets.
-//! It requires the standard library, and currently only works on Linux.
+//! The `phy` module provides an interface for sending and receiving frames
+//! through a physical (or perhaps virtualized) network device, [Device](trait.Device.html),
+//! as well as some useful implementations of that trait.
+//!
+//! Currently the only implementation, [RawSocket](struct.RawSocket.html), is based on
+//! Unix raw sockets, and only works on Linux.
 
 #[cfg(all(unix, feature = "std"))]
 mod raw_socket;
 
+/// An interface for sending and receiving raw network frames.
+///
+/// It is expected that a `Device` implementation would allocate memory for both sending
+/// and receiving packets from memory pools; hence, the stack borrows the buffer for a packet
+/// that it is about to receive, as well for a packet that it is about to send, from the device.
+pub trait Device {
+    /// Maximum transmission unit.
+    ///
+    /// The network device is unable to send or receive frames larger than the MTU.
+    /// In practice, MTU will fall between 64 and 9216 octets.
+    const MTU: usize;
+
+    /// Receives a frame.
+    ///
+    /// It is expected that a `recv` implementation, once a packet is written to memory
+    /// through DMA, would gain ownership of the underlying buffer, provide it for parsing,
+    /// and then return it to the network device.
+    fn recv<F: FnOnce(&[u8])>(&mut self, handler: F);
+
+    /// Transmits a frame.
+    ///
+    /// It is expected that a `send` implementation would gain ownership of a buffer with
+    /// the requested size, provide it for emission, and then schedule it to be read from
+    /// memory by the network device.
+    ///
+    /// # Panics
+    /// This function may panic if `size` is larger than `MTU`.
+    fn send<F: FnOnce(&mut [u8])>(&mut self, size: usize, handler: F);
+}
+
 #[cfg(all(unix, feature = "std"))]
 pub use self::raw_socket::RawSocket;

+ 24 - 13
src/phy/raw_socket.rs

@@ -78,24 +78,35 @@ impl RawSocket {
             })
         }
     }
+}
 
-    /// Captures a packet into the internal buffer, which is sized appropriately
-    /// for the interface MTU.
-    pub fn capture(&mut self) -> io::Result<&[u8]> {
-        unsafe {
+impl Drop for RawSocket {
+    fn drop(&mut self) {
+        unsafe { libc::close(self.sockfd); }
+    }
+}
+
+impl super::Device for RawSocket {
+    const MTU: usize = 1536;
+
+    fn recv<F: FnOnce(&[u8])>(&mut self, handler: F) {
+        let len = unsafe {
             let len = libc::recv(self.sockfd, self.buffer.as_mut_ptr() as *mut libc::c_void,
                                  self.buffer.len(), 0);
-            if len == -1 {
-                return Err(io::Error::last_os_error())
-            }
+            if len == -1 { Err(io::Error::last_os_error()).unwrap() }
+            len
+        };
 
-            Ok(&self.buffer[..len as usize])
-        }
+        handler(&self.buffer[..len as usize])
     }
-}
 
-impl Drop for RawSocket {
-    fn drop(&mut self) {
-        unsafe { libc::close(self.sockfd); }
+    fn send<F: FnOnce(&mut [u8])>(&mut self, size: usize, handler: F) {
+        handler(&mut self.buffer[..size]);
+
+        unsafe {
+            let len = libc::send(self.sockfd, self.buffer.as_ptr() as *const libc::c_void,
+                                 size, 0);
+            if len == -1 { Err(io::Error::last_os_error()).unwrap() }
+        }
     }
 }