Allow disabling any of: raw, TCP or UDP sockets.

This commit is contained in:
whitequark 2017-09-25 00:12:58 +00:00
parent 440b6f5556
commit a983c629b9
7 changed files with 87 additions and 27 deletions

View File

@ -9,16 +9,22 @@ matrix:
# actually test everything # actually test everything
- rust: nightly - rust: nightly
env: FEATURES='default' MODE='test' env: FEATURES='default' MODE='test'
- rust: nightly
env: FEATURES='std' MODE='test'
- rust: nightly
env: FEATURES='alloc' MODE='build'
- rust: nightly - rust: nightly
env: FEATURES='phy-raw_socket' MODE='build' env: FEATURES='phy-raw_socket' MODE='build'
- rust: nightly - rust: nightly
env: FEATURES='phy-tap_interface' MODE='build' env: FEATURES='phy-tap_interface' MODE='build'
- rust: nightly - rust: nightly
env: FEATURES='' MODE='build' env: FEATURES='socket-raw' MODE='build'
- rust: nightly
env: FEATURES='socket-udp' MODE='build'
- rust: nightly
env: FEATURES='socket-tcp' MODE='build'
- rust: nightly
env: FEATURES='socket-raw socket-udp socket-tcp' MODE='build'
- rust: nightly
env: FEATURES='socket-raw socket-udp socket-tcp std' MODE='build'
- rust: nightly
env: FEATURES='socket-raw socket-udp socket-tcp alloc' MODE='build'
script: script:
- cargo "$MODE" --no-default-features --features "$FEATURES" - cargo "$MODE" --no-default-features --features "$FEATURES"
notifications: notifications:

View File

@ -28,7 +28,12 @@ alloc = ["managed/alloc"]
verbose = [] verbose = []
"phy-raw_socket" = ["std", "libc"] "phy-raw_socket" = ["std", "libc"]
"phy-tap_interface" = ["std", "libc"] "phy-tap_interface" = ["std", "libc"]
default = ["std", "log", "phy-raw_socket", "phy-tap_interface"] "socket-raw" = []
"socket-udp" = []
"socket-tcp" = []
default = ["std", "log",
"phy-raw_socket", "phy-tap_interface",
"socket-raw", "socket-udp", "socket-tcp"]
[[example]] [[example]]
name = "tcpdump" name = "tcpdump"

View File

@ -127,6 +127,13 @@ Enable `smoltcp::phy::RawSocket` and `smoltcp::phy::TapInterface`, respectively.
These features are enabled by default. These features are enabled by default.
### Features `socket-raw`, `socket-udp`, and `socket-tcp`
Enable `smoltcp::socket::RawSocket`, `smoltcp::socket::UdpSocket`,
and `smoltcp::socket::TcpSocket`, respectively.
These features are enabled by default.
## Hosted usage examples ## Hosted usage examples
_smoltcp_, being a freestanding networking stack, needs to be able to transmit and receive _smoltcp_, being a freestanding networking stack, needs to be able to transmit and receive

View File

@ -10,8 +10,12 @@ use wire::{ArpPacket, ArpRepr, ArpOperation};
use wire::{Ipv4Packet, Ipv4Repr}; use wire::{Ipv4Packet, Ipv4Repr};
use wire::{Icmpv4Packet, Icmpv4Repr, Icmpv4DstUnreachable}; use wire::{Icmpv4Packet, Icmpv4Repr, Icmpv4DstUnreachable};
use wire::{IpAddress, IpProtocol, IpRepr}; use wire::{IpAddress, IpProtocol, IpRepr};
use wire::{UdpPacket, UdpRepr, TcpPacket, TcpRepr, TcpControl}; #[cfg(feature = "socket-udp")] use wire::{UdpPacket, UdpRepr};
use socket::{Socket, SocketSet, RawSocket, TcpSocket, UdpSocket, AsSocket}; #[cfg(feature = "socket-tcp")] use wire::{TcpPacket, TcpRepr, TcpControl};
use socket::{Socket, SocketSet, AsSocket};
#[cfg(feature = "socket-raw")] use socket::RawSocket;
#[cfg(feature = "socket-udp")] use socket::UdpSocket;
#[cfg(feature = "socket-tcp")] use socket::TcpSocket;
use super::ArpCache; use super::ArpCache;
/// An Ethernet network interface. /// An Ethernet network interface.
@ -30,8 +34,11 @@ enum Packet<'a> {
None, None,
Arp(ArpRepr), Arp(ArpRepr),
Icmpv4(Ipv4Repr, Icmpv4Repr<'a>), Icmpv4(Ipv4Repr, Icmpv4Repr<'a>),
#[cfg(feature = "socket-raw")]
Raw((IpRepr, &'a [u8])), Raw((IpRepr, &'a [u8])),
#[cfg(feature = "socket-udp")]
Udp((IpRepr, UdpRepr<'a>)), Udp((IpRepr, UdpRepr<'a>)),
#[cfg(feature = "socket-tcp")]
Tcp((IpRepr, TcpRepr<'a>)) Tcp((IpRepr, TcpRepr<'a>))
} }
@ -169,22 +176,25 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
let mut device_result = Ok(()); let mut device_result = Ok(());
let socket_result = let socket_result =
match socket { match socket {
#[cfg(feature = "socket-raw")]
&mut Socket::Raw(ref mut socket) => &mut Socket::Raw(ref mut socket) =>
socket.dispatch(|response| { socket.dispatch(|response| {
device_result = self.dispatch(timestamp, Packet::Raw(response)); device_result = self.dispatch(timestamp, Packet::Raw(response));
device_result device_result
}), }),
#[cfg(feature = "socket-udp")]
&mut Socket::Udp(ref mut socket) => &mut Socket::Udp(ref mut socket) =>
socket.dispatch(|response| { socket.dispatch(|response| {
device_result = self.dispatch(timestamp, Packet::Udp(response)); device_result = self.dispatch(timestamp, Packet::Udp(response));
device_result device_result
}), }),
#[cfg(feature = "socket-tcp")]
&mut Socket::Tcp(ref mut socket) => &mut Socket::Tcp(ref mut socket) =>
socket.dispatch(timestamp, &limits, |response| { socket.dispatch(timestamp, &limits, |response| {
device_result = self.dispatch(timestamp, Packet::Tcp(response)); device_result = self.dispatch(timestamp, Packet::Tcp(response));
device_result device_result
}), }),
&mut Socket::__Nonexhaustive => unreachable!() &mut Socket::__Nonexhaustive(_) => unreachable!()
}; };
match (device_result, socket_result) { match (device_result, socket_result) {
(Err(Error::Unaddressable), _) => break, // no one to transmit to (Err(Error::Unaddressable), _) => break, // no one to transmit to
@ -285,8 +295,11 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
let ip_repr = IpRepr::Ipv4(ipv4_repr); let ip_repr = IpRepr::Ipv4(ipv4_repr);
let ip_payload = ipv4_packet.payload(); let ip_payload = ipv4_packet.payload();
// Pass every IP packet to all raw sockets we have registered. #[cfg(feature = "socket-raw")]
let mut handled_by_raw_socket = false; let mut handled_by_raw_socket = false;
// Pass every IP packet to all raw sockets we have registered.
#[cfg(feature = "socket-raw")]
for raw_socket in sockets.iter_mut().filter_map( for raw_socket in sockets.iter_mut().filter_map(
<Socket as AsSocket<RawSocket>>::try_as_socket) { <Socket as AsSocket<RawSocket>>::try_as_socket) {
if !raw_socket.accepts(&ip_repr) { continue } if !raw_socket.accepts(&ip_repr) { continue }
@ -309,12 +322,19 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
match ipv4_repr.protocol { match ipv4_repr.protocol {
IpProtocol::Icmp => IpProtocol::Icmp =>
Self::process_icmpv4(ipv4_repr, ip_payload), Self::process_icmpv4(ipv4_repr, ip_payload),
#[cfg(feature = "socket-udp")]
IpProtocol::Udp => IpProtocol::Udp =>
Self::process_udp(sockets, ip_repr, ip_payload), Self::process_udp(sockets, ip_repr, ip_payload),
#[cfg(feature = "socket-tcp")]
IpProtocol::Tcp => IpProtocol::Tcp =>
Self::process_tcp(sockets, timestamp, ip_repr, ip_payload), Self::process_tcp(sockets, timestamp, ip_repr, ip_payload),
#[cfg(feature = "socket-raw")]
_ if handled_by_raw_socket => _ if handled_by_raw_socket =>
Ok(Packet::None), Ok(Packet::None),
_ => { _ => {
let icmp_reply_repr = Icmpv4Repr::DstUnreachable { let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
reason: Icmpv4DstUnreachable::ProtoUnreachable, reason: Icmpv4DstUnreachable::ProtoUnreachable,
@ -362,6 +382,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
} }
} }
#[cfg(feature = "socket-udp")]
fn process_udp<'frame>(sockets: &mut SocketSet, fn process_udp<'frame>(sockets: &mut SocketSet,
ip_repr: IpRepr, ip_payload: &'frame [u8]) -> ip_repr: IpRepr, ip_payload: &'frame [u8]) ->
Result<Packet<'frame>> { Result<Packet<'frame>> {
@ -403,6 +424,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
} }
} }
#[cfg(feature = "socket-tcp")]
fn process_tcp<'frame>(sockets: &mut SocketSet, timestamp: u64, fn process_tcp<'frame>(sockets: &mut SocketSet, timestamp: u64,
ip_repr: IpRepr, ip_payload: &'frame [u8]) -> ip_repr: IpRepr, ip_payload: &'frame [u8]) ->
Result<Packet<'frame>> { Result<Packet<'frame>> {
@ -454,17 +476,20 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
icmpv4_repr.emit(&mut Icmpv4Packet::new(payload)); icmpv4_repr.emit(&mut Icmpv4Packet::new(payload));
}) })
} }
#[cfg(feature = "socket-raw")]
Packet::Raw((ip_repr, raw_packet)) => { Packet::Raw((ip_repr, raw_packet)) => {
self.dispatch_ip(timestamp, ip_repr, |_ip_repr, payload| { self.dispatch_ip(timestamp, ip_repr, |_ip_repr, payload| {
payload.copy_from_slice(raw_packet); payload.copy_from_slice(raw_packet);
}) })
} }
#[cfg(feature = "socket-udp")]
Packet::Udp((ip_repr, udp_repr)) => { Packet::Udp((ip_repr, udp_repr)) => {
self.dispatch_ip(timestamp, ip_repr, |ip_repr, payload| { self.dispatch_ip(timestamp, ip_repr, |ip_repr, payload| {
udp_repr.emit(&mut UdpPacket::new(payload), udp_repr.emit(&mut UdpPacket::new(payload),
&ip_repr.src_addr(), &ip_repr.dst_addr()); &ip_repr.src_addr(), &ip_repr.dst_addr());
}) })
} }
#[cfg(feature = "socket-tcp")]
Packet::Tcp((ip_repr, mut tcp_repr)) => { Packet::Tcp((ip_repr, mut tcp_repr)) => {
let limits = self.device.limits(); let limits = self.device.limits();
self.dispatch_ip(timestamp, ip_repr, |ip_repr, payload| { self.dispatch_ip(timestamp, ip_repr, |ip_repr, payload| {

View File

@ -10,24 +10,28 @@
//! The interface implemented by this module uses explicit buffering: you decide on the good //! The interface implemented by this module uses explicit buffering: you decide on the good
//! size for a buffer, allocate it, and let the networking stack use it. //! size for a buffer, allocate it, and let the networking stack use it.
use core::marker::PhantomData;
use wire::IpRepr; use wire::IpRepr;
mod raw; #[cfg(feature = "socket-raw")] mod raw;
mod udp; #[cfg(feature = "socket-udp")] mod udp;
mod tcp; #[cfg(feature = "socket-tcp")] mod tcp;
mod set; mod set;
pub use self::raw::PacketBuffer as RawPacketBuffer; #[cfg(feature = "socket-raw")]
pub use self::raw::SocketBuffer as RawSocketBuffer; pub use self::raw::{PacketBuffer as RawPacketBuffer,
pub use self::raw::RawSocket; SocketBuffer as RawSocketBuffer,
RawSocket};
pub use self::udp::PacketBuffer as UdpPacketBuffer; #[cfg(feature = "socket-udp")]
pub use self::udp::SocketBuffer as UdpSocketBuffer; pub use self::udp::{PacketBuffer as UdpPacketBuffer,
pub use self::udp::UdpSocket; SocketBuffer as UdpSocketBuffer,
UdpSocket};
pub use self::tcp::SocketBuffer as TcpSocketBuffer; #[cfg(feature = "socket-tcp")]
pub use self::tcp::State as TcpState; pub use self::tcp::{SocketBuffer as TcpSocketBuffer,
pub use self::tcp::TcpSocket; State as TcpState,
TcpSocket};
pub use self::set::{Set as SocketSet, Item as SocketSetItem, Handle as SocketHandle}; pub use self::set::{Set as SocketSet, Item as SocketSetItem, Handle as SocketHandle};
pub use self::set::{Iter as SocketSetIter, IterMut as SocketSetIterMut}; pub use self::set::{Iter as SocketSetIter, IterMut as SocketSetIterMut};
@ -47,20 +51,26 @@ pub use self::set::{Iter as SocketSetIter, IterMut as SocketSetIterMut};
/// since the lower layers treat the packet as an opaque octet sequence. /// since the lower layers treat the packet as an opaque octet sequence.
#[derive(Debug)] #[derive(Debug)]
pub enum Socket<'a, 'b: 'a> { pub enum Socket<'a, 'b: 'a> {
#[cfg(feature = "socket-raw")]
Raw(RawSocket<'a, 'b>), Raw(RawSocket<'a, 'b>),
#[cfg(feature = "socket-udp")]
Udp(UdpSocket<'a, 'b>), Udp(UdpSocket<'a, 'b>),
#[cfg(feature = "socket-tcp")]
Tcp(TcpSocket<'a>), Tcp(TcpSocket<'a>),
#[doc(hidden)] #[doc(hidden)]
__Nonexhaustive __Nonexhaustive(PhantomData<(&'a (), &'b ())>)
} }
macro_rules! dispatch_socket { macro_rules! dispatch_socket {
($self_:expr, |$socket:ident [$( $mut_:tt )*]| $code:expr) => ({ ($self_:expr, |$socket:ident [$( $mut_:tt )*]| $code:expr) => ({
match $self_ { match $self_ {
#[cfg(feature = "socket-raw")]
&$( $mut_ )* Socket::Raw(ref $( $mut_ )* $socket) => $code, &$( $mut_ )* Socket::Raw(ref $( $mut_ )* $socket) => $code,
#[cfg(feature = "socket-udp")]
&$( $mut_ )* Socket::Udp(ref $( $mut_ )* $socket) => $code, &$( $mut_ )* Socket::Udp(ref $( $mut_ )* $socket) => $code,
#[cfg(feature = "socket-tcp")]
&$( $mut_ )* Socket::Tcp(ref $( $mut_ )* $socket) => $code, &$( $mut_ )* Socket::Tcp(ref $( $mut_ )* $socket) => $code,
&$( $mut_ )* Socket::__Nonexhaustive => unreachable!() &$( $mut_ )* Socket::__Nonexhaustive(_) => unreachable!()
} }
}) })
} }
@ -115,6 +125,9 @@ macro_rules! as_socket {
} }
} }
#[cfg(feature = "socket-raw")]
as_socket!(RawSocket<'a, 'b>, Raw); as_socket!(RawSocket<'a, 'b>, Raw);
#[cfg(feature = "socket-udp")]
as_socket!(UdpSocket<'a, 'b>, Udp); as_socket!(UdpSocket<'a, 'b>, Udp);
#[cfg(feature = "socket-tcp")]
as_socket!(TcpSocket<'a>, Tcp); as_socket!(TcpSocket<'a>, Tcp);

View File

@ -2,7 +2,7 @@ use managed::ManagedSlice;
use core::slice; use core::slice;
use super::Socket; use super::Socket;
use super::TcpState; #[cfg(feature = "socket-tcp")] use super::TcpState;
/// An item of a socket set. /// An item of a socket set.
/// ///
@ -68,7 +68,6 @@ impl<'a, 'b: 'a, 'c: 'a + 'b> Set<'a, 'b, 'c> {
return put(index, &mut sockets[index], socket) return put(index, &mut sockets[index], socket)
} }
} }
} }
/// Get a socket from the set by its handle. /// Get a socket from the set by its handle.
@ -139,17 +138,20 @@ impl<'a, 'b: 'a, 'c: 'a + 'b> Set<'a, 'b, 'c> {
let mut may_remove = false; let mut may_remove = false;
if let &mut Some(Item { refs: 0, ref mut socket }) = item { if let &mut Some(Item { refs: 0, ref mut socket }) = item {
match socket { match socket {
#[cfg(feature = "socket-raw")]
&mut Socket::Raw(_) => &mut Socket::Raw(_) =>
may_remove = true, may_remove = true,
#[cfg(feature = "socket-udp")]
&mut Socket::Udp(_) => &mut Socket::Udp(_) =>
may_remove = true, may_remove = true,
#[cfg(feature = "socket-tcp")]
&mut Socket::Tcp(ref mut socket) => &mut Socket::Tcp(ref mut socket) =>
if socket.state() == TcpState::Closed { if socket.state() == TcpState::Closed {
may_remove = true may_remove = true
} else { } else {
socket.close() socket.close()
}, },
&mut Socket::__Nonexhaustive => unreachable!() &mut Socket::__Nonexhaustive(_) => unreachable!()
} }
} }
if may_remove { if may_remove {

View File

@ -93,6 +93,8 @@ impl Assembler {
Assembler { contigs } Assembler { contigs }
} }
/// FIXME(whitequark): remove this once I'm certain enough that the assembler works well.
#[allow(dead_code)]
pub(crate) fn total_size(&self) -> usize { pub(crate) fn total_size(&self) -> usize {
self.contigs self.contigs
.iter() .iter()