Browse Source

Replace EthernetInterface::new with EthernetInterfaceBuilder.

Dan Robertson 7 năm trước cách đây
mục cha
commit
ad56bacb56
6 tập tin đã thay đổi với 173 bổ sung45 xóa
  1. 7 3
      examples/client.rs
  2. 6 3
      examples/loopback.rs
  3. 7 3
      examples/ping.rs
  4. 6 3
      examples/server.rs
  5. 145 32
      src/iface/ethernet.rs
  6. 2 1
      src/iface/mod.rs

+ 7 - 3
examples/client.rs

@@ -12,7 +12,7 @@ use std::time::Instant;
 use std::os::unix::io::AsRawFd;
 use smoltcp::phy::wait as phy_wait;
 use smoltcp::wire::{EthernetAddress, Ipv4Address, IpAddress, IpCidr};
-use smoltcp::iface::{NeighborCache, EthernetInterface};
+use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
 use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
 
 fn main() {
@@ -42,8 +42,12 @@ fn main() {
     let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
     let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 2), 24)];
     let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
-    let mut iface = EthernetInterface::new(
-        device, neighbor_cache, ethernet_addr, ip_addrs, Some(default_v4_gw));
+    let mut iface = EthernetInterfaceBuilder::new(device)
+            .ethernet_addr(ethernet_addr)
+            .neighbor_cache(neighbor_cache)
+            .ip_addrs(ip_addrs)
+            .ipv4_gateway(default_v4_gw)
+            .finalize();
 
     let mut sockets = SocketSet::new(vec![]);
     let tcp_handle = sockets.add(tcp_socket);

+ 6 - 3
examples/loopback.rs

@@ -18,7 +18,7 @@ mod utils;
 use core::str;
 use smoltcp::phy::Loopback;
 use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
-use smoltcp::iface::{NeighborCache, EthernetInterface};
+use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
 use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
 
 #[cfg(not(feature = "std"))]
@@ -89,8 +89,11 @@ fn main() {
     let mut neighbor_cache = NeighborCache::new(&mut neighbor_cache_entries[..]);
 
     let mut ip_addrs = [IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8)];
-    let mut iface = EthernetInterface::new(
-        device, neighbor_cache, EthernetAddress::default(), &mut ip_addrs[..], None);
+    let mut iface = EthernetInterfaceBuilder::new(device)
+            .ethernet_addr(EthernetAddress::default())
+            .neighbor_cache(neighbor_cache)
+            .ip_addrs(ip_addrs)
+            .finalize();
 
     let server_socket = {
         // It is not strictly necessary to use a `static mut` and unsafe code here, but

+ 7 - 3
examples/ping.rs

@@ -15,7 +15,7 @@ use smoltcp::phy::Device;
 use smoltcp::phy::wait as phy_wait;
 use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr,
                     Ipv4Address, Icmpv4Repr, Icmpv4Packet};
-use smoltcp::iface::{NeighborCache, EthernetInterface};
+use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
 use smoltcp::socket::{SocketSet, IcmpSocket, IcmpSocketBuffer, IcmpPacketBuffer, IcmpEndpoint};
 use std::collections::HashMap;
 use byteorder::{ByteOrder, NetworkEndian};
@@ -58,8 +58,12 @@ fn main() {
     let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
     let ip_addr = IpCidr::new(IpAddress::from(local_addr), 24);
     let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
-    let mut iface = EthernetInterface::new(
-        device, neighbor_cache, ethernet_addr, [ip_addr], Some(default_v4_gw));
+    let mut iface = EthernetInterfaceBuilder::new(device)
+            .ethernet_addr(ethernet_addr)
+            .ip_addrs([ip_addr])
+            .ipv4_gateway(default_v4_gw)
+            .neighbor_cache(neighbor_cache)
+            .finalize();
 
     let mut sockets = SocketSet::new(vec![]);
     let icmp_handle = sockets.add(icmp_socket);

+ 6 - 3
examples/server.rs

@@ -13,7 +13,7 @@ use std::time::Instant;
 use std::os::unix::io::AsRawFd;
 use smoltcp::phy::wait as phy_wait;
 use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
-use smoltcp::iface::{NeighborCache, EthernetInterface};
+use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
 use smoltcp::socket::SocketSet;
 use smoltcp::socket::{UdpSocket, UdpSocketBuffer, UdpPacketBuffer};
 use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
@@ -56,8 +56,11 @@ fn main() {
 
     let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
     let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24)];
-    let mut iface = EthernetInterface::new(
-        device, neighbor_cache, ethernet_addr, ip_addrs, None);
+    let mut iface = EthernetInterfaceBuilder::new(device)
+            .ethernet_addr(ethernet_addr)
+            .neighbor_cache(neighbor_cache)
+            .ip_addrs(ip_addrs)
+            .finalize();
 
     let mut sockets = SocketSet::new(vec![]);
     let udp_handle  = sockets.add(udp_socket);

+ 145 - 32
src/iface/ethernet.rs

@@ -54,6 +54,132 @@ struct InterfaceInner<'b, 'c> {
     device_capabilities:    DeviceCapabilities,
 }
 
+/// A builder structure used for creating a Ethernet network
+/// interface.
+pub struct InterfaceBuilder <'b, 'c, DeviceT: for<'d> Device<'d>> {
+    device:              DeviceT,
+    ethernet_addr:       Option<EthernetAddress>,
+    neighbor_cache:      Option<NeighborCache<'b>>,
+    ip_addrs:            Option<ManagedSlice<'c, IpCidr>>,
+    ipv4_gateway:        Option<Ipv4Address>,
+}
+
+impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
+        where DeviceT: for<'d> Device<'d> {
+    /// Create a builder used for creating a network interface using the
+    /// given device and address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use std::collections::BTreeMap;
+    /// use smoltcp::iface::{EthernetInterfaceBuilder, NeighborCache};
+    /// # use smoltcp::phy::Loopback;
+    /// use smoltcp::wire::{EthernetAddress, IpCidr, IpAddress};
+    ///
+    /// let device = // ...
+    /// # Loopback::new();
+    /// let hw_addr = // ...
+    /// # EthernetAddress::default();
+    /// let neighbor_cache = // ...
+    /// # NeighborCache::new(BTreeMap::new());
+    /// let ip_addrs = // ...
+    /// # [];
+    /// let iface = EthernetInterfaceBuilder::new(device)
+    ///         .ethernet_addr(hw_addr)
+    ///         .neighbor_cache(neighbor_cache)
+    ///         .ip_addrs(ip_addrs)
+    ///         .finalize();
+    /// ```
+    pub fn new(device: DeviceT) -> InterfaceBuilder<'b, 'c, DeviceT> {
+        InterfaceBuilder {
+            device:              device,
+            ethernet_addr:       None,
+            neighbor_cache:      None,
+            ip_addrs:            None,
+            ipv4_gateway:        None
+        }
+    }
+
+    /// Set the Ethernet address the interface will use. See also
+    /// [ethernet_addr].
+    ///
+    /// # Panics
+    /// This function panics if the address is not unicast.
+    ///
+    /// [ethernet_addr]: struct.EthernetInterface.html#method.ethernet_addr
+    pub fn ethernet_addr(mut self, addr: EthernetAddress) -> InterfaceBuilder<'b, 'c, DeviceT> {
+        InterfaceInner::check_ethernet_addr(&addr);
+        self.ethernet_addr = Some(addr);
+        self
+    }
+
+    /// Set the IP addresses the interface will use. See also
+    /// [ip_addrs].
+    ///
+    /// # Panics
+    /// This function panics if any of the addresses is not unicast.
+    ///
+    /// [ip_addrs]: struct.EthernetInterface.html#method.ip_addrs
+    pub fn ip_addrs<T: Into<ManagedSlice<'c, IpCidr>>>(mut self, ips: T) -> InterfaceBuilder<'b, 'c, DeviceT> {
+        let ips = ips.into();
+        InterfaceInner::check_ip_addrs(&ips);
+        self.ip_addrs = Some(ips);
+        self
+    }
+
+    /// Set the IPv4 gateway the interface will use. See also
+    /// [ipv4_gateway].
+    ///
+    /// # Panics
+    /// This function panics if the given address is not unicast.
+    ///
+    /// [ipv4_gateway]: struct.EthernetInterface.html#method.ipv4_gateway
+    pub fn ipv4_gateway<T>(mut self, gateway: T) -> InterfaceBuilder<'b, 'c, DeviceT>
+            where T: Into<Ipv4Address> {
+        let addr = gateway.into();
+        InterfaceInner::check_gateway_addr(&addr);
+        self.ipv4_gateway = Some(addr);
+        self
+    }
+
+    /// Set the Neighbor Cache the interface will use.
+    pub fn neighbor_cache(mut self, neighbor_cache: NeighborCache<'b>) -> InterfaceBuilder<'b, 'c, DeviceT> {
+        self.neighbor_cache = Some(neighbor_cache);
+        self
+    }
+
+    /// Create a network interface using the previously provided configuration.
+    ///
+    /// # Panics
+    /// If a required option is not provided, this function will panic. Required
+    /// options are:
+    ///
+    /// - [ethernet_addr]
+    /// - [neighbor_cache]
+    /// - [ip_addrs]
+    ///
+    /// [ethernet_addr]: #method.ethernet_addr
+    /// [neighbor_cache]: #method.neighbor_cache
+    /// [ip_addrs]: #method.ip_addrs
+    pub fn finalize(self) -> Interface<'b, 'c, DeviceT> {
+        // TODO: Limit the number of required options.
+        match (self.ethernet_addr, self.neighbor_cache, self.ip_addrs) {
+            (Some(ethernet_addr), Some(neighbor_cache), Some(ip_addrs)) => {
+                let device_capabilities = self.device.capabilities();
+                Interface {
+                    device: self.device,
+                    inner: InterfaceInner {
+                        ethernet_addr, device_capabilities, neighbor_cache, 
+                        ip_addrs, ipv4_gateway: self.ipv4_gateway,
+                    }
+                }
+            },
+            _ => panic!("a required option was not set"),
+        }
+    }
+}
+
 #[derive(Debug, PartialEq)]
 enum Packet<'a> {
     None,
@@ -84,33 +210,6 @@ impl<'a> Packet<'a> {
 
 impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
         where DeviceT: for<'d> Device<'d> {
-    /// Create a network interface using the provided network device.
-    ///
-    /// # Panics
-    /// See the restrictions on [set_hardware_addr](#method.set_hardware_addr)
-    /// and [set_protocol_addrs](#method.set_protocol_addrs) functions.
-    pub fn new<ProtocolAddrsMT, Ipv4GatewayAddrT>
-              (device: DeviceT,
-               neighbor_cache: NeighborCache<'b>,
-               ethernet_addr: EthernetAddress,
-               ip_addrs: ProtocolAddrsMT,
-               ipv4_gateway: Ipv4GatewayAddrT) ->
-              Interface<'b, 'c, DeviceT>
-            where ProtocolAddrsMT: Into<ManagedSlice<'c, IpCidr>>,
-                  Ipv4GatewayAddrT: Into<Option<Ipv4Address>>, {
-        let ip_addrs = ip_addrs.into();
-        InterfaceInner::check_ethernet_addr(&ethernet_addr);
-        InterfaceInner::check_ip_addrs(&ip_addrs);
-
-        let inner = InterfaceInner {
-            ethernet_addr, ip_addrs, neighbor_cache,
-            ipv4_gateway: ipv4_gateway.into(),
-            device_capabilities: device.capabilities(),
-        };
-
-        Interface { device, inner }
-    }
-
     /// Get the Ethernet address of the interface.
     pub fn ethernet_addr(&self) -> EthernetAddress {
         self.inner.ethernet_addr
@@ -314,6 +413,12 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
         }
     }
 
+    fn check_gateway_addr(addr: &Ipv4Address) {
+        if !addr.is_unicast() {
+            panic!("gateway IP address {} is not unicast", addr);
+        }
+    }
+
     /// Check whether the interface has the given IP address assigned.
     fn has_ip_addr<T: Into<IpAddress>>(&self, addr: T) -> bool {
         let addr = addr.into();
@@ -795,6 +900,7 @@ mod test {
     use std::collections::BTreeMap;
     use {Result, Error};
 
+    use super::InterfaceBuilder;
     use iface::{NeighborCache, EthernetInterface};
     use phy::{self, Loopback, ChecksumCapabilities};
     use socket::SocketSet;
@@ -812,12 +918,13 @@ mod test {
         // Create a basic device
         let device = Loopback::new();
 
-        let neighbor_cache = NeighborCache::new(BTreeMap::new());
+        let iface = InterfaceBuilder::new(device)
+                .ethernet_addr(EthernetAddress::default())
+                .neighbor_cache(NeighborCache::new(BTreeMap::new()))
+                .ip_addrs([IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8)])
+                .finalize();
 
-        let ip_addr = IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8);
-        (EthernetInterface::new(device, neighbor_cache,
-            EthernetAddress::default(), [ip_addr], None),
-            SocketSet::new(vec![]))
+        (iface, SocketSet::new(vec![]))
     }
 
     #[derive(Debug, PartialEq)]
@@ -830,6 +937,12 @@ mod test {
         }
     }
 
+    #[test]
+    #[should_panic(expected = "a required option was not set")]
+    fn test_builder_initialization_panic() {
+        InterfaceBuilder::new(Loopback::new()).finalize();
+    }
+
     #[test]
     fn test_no_icmp_to_broadcast() {
         let (mut iface, mut socket_set) = create_loopback();

+ 2 - 1
src/iface/mod.rs

@@ -9,4 +9,5 @@ mod ethernet;
 pub use self::neighbor::Neighbor as Neighbor;
 pub(crate) use self::neighbor::Answer as NeighborAnswer;
 pub use self::neighbor::Cache as NeighborCache;
-pub use self::ethernet::Interface as EthernetInterface;
+pub use self::ethernet::{Interface as EthernetInterface,
+                         InterfaceBuilder as EthernetInterfaceBuilder};