Ver Fonte

Working UDP loopback.

whitequark há 8 anos atrás
pai
commit
8b89de2faa
6 ficheiros alterados com 127 adições e 38 exclusões
  1. 2 1
      README.md
  2. 23 4
      examples/smoltcpserver.rs
  3. 5 5
      src/iface/ethernet.rs
  4. 45 11
      src/socket/mod.rs
  5. 40 12
      src/socket/udp.rs
  6. 12 5
      src/wire/udp.rs

+ 2 - 1
README.md

@@ -101,7 +101,8 @@ cargo run --example smoltcpserver -- tap0
 
 It responds to:
 
-  * pings (`ping 192.168.69.1`).
+  * pings (`ping 192.168.69.1`),
+  * UDP packets on port 6969 (`socat stdio udp4-connect:192.168.69.1:6969 <<<"abcdefg"`).
 
 License
 -------

+ 23 - 4
examples/smoltcpserver.rs

@@ -2,10 +2,11 @@
 extern crate smoltcp;
 
 use std::env;
+use smoltcp::Error;
 use smoltcp::phy::{Tracer, TapInterface};
 use smoltcp::wire::{EthernetFrame, EthernetAddress, InternetAddress, InternetEndpoint};
 use smoltcp::iface::{SliceArpCache, EthernetInterface};
-use smoltcp::socket::{Socket, UdpSocket, UdpBuffer, UdpBufferElem};
+use smoltcp::socket::{UdpSocket, AsSocket, UdpBuffer, UdpBufferElem};
 
 fn main() {
     let ifname = env::args().nth(1).unwrap();
@@ -22,16 +23,34 @@ fn main() {
 
     let udp_rx_buffer = UdpBuffer::new(vec![UdpBufferElem::new(vec![0; 2048])]);
     let udp_tx_buffer = UdpBuffer::new(vec![UdpBufferElem::new(vec![0; 2048])]);
-    let mut udp_socket = UdpSocket::new(endpoint, udp_rx_buffer, udp_tx_buffer);
+    let udp_socket = UdpSocket::new(endpoint, udp_rx_buffer, udp_tx_buffer);
 
-    let mut sockets: [&mut Socket; 1] = [&mut udp_socket];
+    let mut sockets = [udp_socket];
     let mut iface = EthernetInterface::new(device, arp_cache,
         hardware_addr, &mut protocol_addrs[..], &mut sockets[..]);
 
     loop {
         match iface.poll() {
             Ok(()) => (),
-            Err(e) => println!("{}", e)
+            Err(e) => println!("error {}", e)
+        }
+
+        let udp_socket = iface.sockets()[0].as_socket();
+        let client = match udp_socket.recv() {
+            Ok((endpoint, data)) => {
+                println!("data {:?} from {}", &data[..8], endpoint);
+                Some(endpoint)
+            }
+            Err(Error::Exhausted) => {
+                None
+            }
+            Err(e) => {
+                println!("error {}", e);
+                None
+            }
+        };
+        if let Some(endpoint) = client {
+            udp_socket.send_slice(endpoint, "hihihi".as_bytes()).unwrap()
         }
     }
 }

+ 5 - 5
src/iface/ethernet.rs

@@ -21,21 +21,21 @@ pub struct Interface<'a,
     DeviceT:        Device,
     ArpCacheT:      ArpCache,
     ProtocolAddrsT: BorrowMut<[InternetAddress]>,
-    SocketsT:       BorrowMut<[&'a mut Socket]>
+    SocketsT:       BorrowMut<[Socket<'a>]>
 > {
     device:         DeviceT,
     arp_cache:      ArpCacheT,
     hardware_addr:  EthernetAddress,
     protocol_addrs: ProtocolAddrsT,
     sockets:        SocketsT,
-    phantom:        PhantomData<&'a mut Socket>
+    phantom:        PhantomData<Socket<'a>>
 }
 
 impl<'a,
     DeviceT:        Device,
     ArpCacheT:      ArpCache,
     ProtocolAddrsT: BorrowMut<[InternetAddress]>,
-    SocketsT:       BorrowMut<[&'a mut Socket]>
+    SocketsT:       BorrowMut<[Socket<'a>]>
 > Interface<'a, DeviceT, ArpCacheT, ProtocolAddrsT, SocketsT> {
     /// Create a network interface using the provided network device.
     ///
@@ -106,8 +106,8 @@ impl<'a,
     }
 
     /// Get the set of sockets owned by the interface.
-    pub fn with_sockets<R, F: FnOnce(&mut [&'a mut Socket]) -> R>(&mut self, f: F) -> R {
-        f(self.sockets.borrow_mut())
+    pub fn sockets(&mut self) -> &mut [Socket<'a>] {
+        self.sockets.borrow_mut()
     }
 
     /// Receive and process a packet, if available.

+ 45 - 11
src/socket/mod.rs

@@ -33,10 +33,9 @@ pub trait PacketRepr {
 
 /// A network socket.
 ///
-/// This interface abstracts the various types of sockets based on the IP protocol.
-/// It is necessarily implemented as a trait, and not as an enumeration, to allow using different
-/// buffer types in sockets assigned to the same interface. To access a socket through this
-/// interface, cast it using `.as::<T>()`.
+/// This enumeration abstracts the various types of sockets based on the IP protocol.
+/// To downcast a `Socket` value down to a concrete socket, use
+/// the [AsSocket](trait.AsSocket.html) trait, and call e.g. `socket.as_socket::<UdpSocket<_>>()`.
 ///
 /// The `collect` and `dispatch` functions are fundamentally asymmetric and thus differ in
 /// their use of the [trait PacketRepr](trait.PacketRepr.html). When `collect` is called,
@@ -45,7 +44,13 @@ pub trait PacketRepr {
 /// which is rather inelegant. Conversely, when `dispatch` is called, the packet length is
 /// not yet known and the packet storage has to be allocated; but the `&PacketRepr` is sufficient
 /// since the lower layers treat the packet as an opaque octet sequence.
-pub trait Socket {
+pub enum Socket<'a> {
+    Udp(UdpSocket<'a>),
+    #[doc(hidden)]
+    __Nonexhaustive
+}
+
+impl<'a> Socket<'a> {
     /// Process a packet received from a network interface.
     ///
     /// This function checks if the packet contained in the payload matches the socket endpoint,
@@ -53,9 +58,15 @@ pub trait Socket {
     /// is returned.
     ///
     /// This function is used internally by the networking stack.
-    fn collect(&mut self, src_addr: &Address, dst_addr: &Address,
-               protocol: ProtocolType, payload: &[u8])
-        -> Result<(), Error>;
+    pub fn collect(&mut self, src_addr: &Address, dst_addr: &Address,
+                   protocol: ProtocolType, payload: &[u8])
+            -> Result<(), Error> {
+        match self {
+            &mut Socket::Udp(ref mut socket) =>
+                socket.collect(src_addr, dst_addr, protocol, payload),
+            &mut Socket::__Nonexhaustive => unreachable!()
+        }
+    }
 
     /// Prepare a packet to be transmitted to a network interface.
     ///
@@ -64,7 +75,30 @@ pub trait Socket {
     /// is returned.
     ///
     /// This function is used internally by the networking stack.
-    fn dispatch(&mut self, f: &mut FnMut(&Address, &Address,
-                                         ProtocolType, &PacketRepr) -> Result<(), Error>)
-        -> Result<(), Error>;
+    pub fn dispatch(&mut self, f: &mut FnMut(&Address, &Address,
+                                             ProtocolType, &PacketRepr) -> Result<(), Error>)
+            -> Result<(), Error> {
+        match self {
+            &mut Socket::Udp(ref mut socket) =>
+                socket.dispatch(f),
+            &mut Socket::__Nonexhaustive => unreachable!()
+        }
+    }
+}
+
+/// A conversion trait for network sockets.
+///
+/// This trait is used to concisely downcast [Socket](trait.Socket.html) values to their
+/// concrete types.
+pub trait AsSocket<T> {
+    fn as_socket(&mut self) -> &mut T;
+}
+
+impl<'a> AsSocket<UdpSocket<'a>> for Socket<'a> {
+    fn as_socket(&mut self) -> &mut UdpSocket<'a> {
+        match self {
+            &mut Socket::Udp(ref mut socket) => socket,
+            _ => panic!(".as_socket::<UdpSocket> called on wrong socket type")
+        }
+    }
 }

+ 40 - 12
src/socket/udp.rs

@@ -25,6 +25,14 @@ impl<'a> BufferElem<'a> {
             payload:  payload.into()
         }
     }
+
+    fn as_ref<'b>(&'b self) -> &'b [u8] {
+        &self.payload[..self.size]
+    }
+
+    fn as_mut<'b>(&'b mut self) -> &'b mut [u8] {
+        &mut self.payload[..self.size]
+    }
 }
 
 /// An UDP packet buffer.
@@ -108,12 +116,12 @@ pub struct UdpSocket<'a> {
 impl<'a> UdpSocket<'a> {
     /// Create an UDP socket with the given buffers.
     pub fn new(endpoint: Endpoint, rx_buffer: Buffer<'a>, tx_buffer: Buffer<'a>)
-            -> UdpSocket<'a> {
-        UdpSocket {
+            -> Socket<'a> {
+        Socket::Udp(UdpSocket {
             endpoint:  endpoint,
             rx_buffer: rx_buffer,
             tx_buffer: tx_buffer
-        }
+        })
     }
 
     /// Enqueue a packet to be sent to a given remote endpoint, and return a pointer
@@ -125,21 +133,40 @@ impl<'a> UdpSocket<'a> {
         let packet_buf = try!(self.tx_buffer.enqueue());
         packet_buf.endpoint = endpoint;
         packet_buf.size = size;
-        Ok(&mut packet_buf.payload.borrow_mut()[..size])
+        Ok(&mut packet_buf.as_mut()[..size])
+    }
+
+    /// Enqueue a packete to be sent to a given remote endpoint, and fill it from a slice.
+    ///
+    /// See also [send](#method.send).
+    pub fn send_slice(&mut self, endpoint: Endpoint, data: &[u8]) -> Result<(), Error> {
+        let buffer = try!(self.send(endpoint, data.len()));
+        Ok(buffer.copy_from_slice(data))
     }
 
     /// Dequeue a packet received from a remote endpoint, and return the endpoint as well
     /// as a pointer to the payload.
     ///
     /// This function returns `Err(Error::Exhausted)` if the receive buffer is empty.
-    pub fn recv<R, F>(&mut self) -> Result<(Endpoint, &[u8]), Error> {
+    pub fn recv(&mut self) -> Result<(Endpoint, &[u8]), Error> {
         let packet_buf = try!(self.rx_buffer.dequeue());
-        Ok((packet_buf.endpoint, &packet_buf.payload[..packet_buf.size]))
+        Ok((packet_buf.endpoint, &packet_buf.as_ref()[..packet_buf.size]))
+    }
+
+    /// Dequeue a packet received from a remote endpoint, and return the endpoint as well
+    /// as copy the payload into the given slice.
+    ///
+    /// This function returns `Err(Error::Exhausted)` if the received packet has payload
+    /// larger than the provided slice. See also [recv](#method.recv).
+    pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<(Endpoint, usize), Error> {
+        let (endpoint, buffer) = try!(self.recv());
+        if data.len() < buffer.len() { return Err(Error::Exhausted) }
+        data[..buffer.len()].copy_from_slice(buffer);
+        Ok((endpoint, buffer.len()))
     }
-}
 
-impl<'a> Socket for UdpSocket<'a> {
-    fn collect(&mut self, src_addr: &Address, dst_addr: &Address,
+    /// See [Socket::collect](enum.Socket.html#method.collect).
+    pub fn collect(&mut self, src_addr: &Address, dst_addr: &Address,
                protocol: ProtocolType, payload: &[u8])
             -> Result<(), Error> {
         if protocol != ProtocolType::Udp { return Err(Error::Rejected) }
@@ -155,11 +182,12 @@ impl<'a> Socket for UdpSocket<'a> {
         let packet_buf = try!(self.rx_buffer.enqueue());
         packet_buf.endpoint = Endpoint { addr: *src_addr, port: repr.src_port };
         packet_buf.size = repr.payload.len();
-        packet_buf.payload.borrow_mut()[..repr.payload.len()].copy_from_slice(repr.payload);
+        packet_buf.as_mut()[..repr.payload.len()].copy_from_slice(repr.payload);
         Ok(())
     }
 
-    fn dispatch(&mut self, f: &mut FnMut(&Address, &Address,
+    /// See [Socket::dispatch](enum.Socket.html#method.dispatch).
+    pub fn dispatch(&mut self, f: &mut FnMut(&Address, &Address,
                                          ProtocolType, &PacketRepr) -> Result<(), Error>)
             -> Result<(), Error> {
         let packet_buf = try!(self.tx_buffer.dequeue());
@@ -169,7 +197,7 @@ impl<'a> Socket for UdpSocket<'a> {
           &UdpRepr {
             src_port: self.endpoint.port,
             dst_port: packet_buf.endpoint.port,
-            payload:  &packet_buf.payload[..]
+            payload:  &packet_buf.as_ref()[..]
           })
     }
 }

+ 12 - 5
src/wire/udp.rs

@@ -12,13 +12,18 @@ pub struct Packet<T: AsRef<[u8]>> {
 }
 
 mod field {
+    #![allow(non_snake_case)]
+
     use wire::field::*;
 
     pub const SRC_PORT: Field = 0..2;
     pub const DST_PORT: Field = 2..4;
     pub const LENGTH:   Field = 4..6;
     pub const CHECKSUM: Field = 6..8;
-    pub const PAYLOAD:  Rest  = 8..;
+
+    pub fn PAYLOAD(length: u16) -> Field {
+        CHECKSUM.end..(length as usize)
+    }
 }
 
 impl<T: AsRef<[u8]>> Packet<T> {
@@ -90,8 +95,9 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
     /// Return a pointer to the payload.
     #[inline(always)]
     pub fn payload(&self) -> &'a [u8] {
+        let length = self.len();
         let data = self.buffer.as_ref();
-        &data[field::PAYLOAD]
+        &data[field::PAYLOAD(length)]
     }
 }
 
@@ -147,8 +153,9 @@ impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Packet<&'a mut T> {
     /// Return a mutable pointer to the type-specific data.
     #[inline(always)]
     pub fn payload_mut(&mut self) -> &mut [u8] {
+        let length = self.len();
         let mut data = self.buffer.as_mut();
-        &mut data[field::PAYLOAD]
+        &mut data[field::PAYLOAD(length)]
     }
 }
 
@@ -191,7 +198,7 @@ impl<'a> Repr<'a> {
 
     /// Return the length of a packet that will be emitted from this high-level representation.
     pub fn len(&self) -> usize {
-        field::PAYLOAD.start + self.payload.len()
+        field::CHECKSUM.end + self.payload.len()
     }
 
     /// Emit a high-level representation into an User Datagram Protocol packet.
@@ -201,7 +208,7 @@ impl<'a> Repr<'a> {
             where T: AsRef<[u8]> + AsMut<[u8]> {
         packet.set_src_port(self.src_port);
         packet.set_dst_port(self.dst_port);
-        packet.set_len((field::PAYLOAD.start + self.payload.len()) as u16);
+        packet.set_len((field::CHECKSUM.end + self.payload.len()) as u16);
         packet.payload_mut().copy_from_slice(self.payload);
         packet.fill_checksum(src_addr, dst_addr)
     }