Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ed0828b11c1f
Choose a base ref
...
head repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 53a3875452f8
Choose a head ref
  • 4 commits
  • 4 files changed
  • 1 contributor

Commits on Jul 27, 2017

  1. Copy the full SHA
    d422f45 View commit details
  2. Update a stale docstring.

    whitequark committed Jul 27, 2017
    Copy the full SHA
    50ae82d View commit details
  3. Copy the full SHA
    10585ad View commit details
  4. Copy the full SHA
    53a3875 View commit details
Showing with 83 additions and 46 deletions.
  1. +1 −1 examples/server.rs
  2. +32 −25 src/lib.rs
  3. +44 −15 src/socket/tcp.rs
  4. +6 −5 src/wire/ip.rs
2 changes: 1 addition & 1 deletion examples/server.rs
Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@ fn main() {
// udp:6969: respond "yo dawg"
{
let socket: &mut UdpSocket = sockets.get_mut(udp_handle).as_socket();
if socket.endpoint().is_unspecified() {
if !socket.endpoint().is_specified() {
socket.bind(6969)
}

57 changes: 32 additions & 25 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -97,49 +97,56 @@ pub mod iface;
pub mod socket;

/// The error type for the networking stack.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
/// An incoming packet could not be parsed.
/// An operation cannot proceed because a buffer is empty or full.
Exhausted,
/// An operation is not permitted in the current state.
Illegal,
/// An endpoint or address of a remote host could not be translated to a lower level address.
/// E.g. there was no an Ethernet address corresponding to an IPv4 address in the ARP cache,
/// or a TCP connection attempt was made to an unspecified endpoint.
Unaddressable,

/// An incoming packet could not be parsed because some of its fields were out of bounds
/// of the received data.
Truncated,
/// An incoming packet could not be recognized and was dropped.
/// E.g. a packet with an unknown EtherType.
Unrecognized,
/// An incoming packet was recognized but contained invalid control information.
/// E.g. a packet with IPv4 EtherType but containing a value other than 4
/// in the version field.
Malformed,
/// An incoming packet had an incorrect checksum and was dropped.
Checksum,
/// An incoming packet has been fragmented and was dropped.
/// An incoming packet could not be recognized and was dropped.
/// E.g. an Ethernet packet with an unknown EtherType.
Unrecognized,
/// An incoming IP packet has been split into several IP fragments and was dropped,
/// since IP reassembly is not supported.
Fragmented,
/// An outgoing packet could not be sent because a protocol address could not be mapped
/// to hardware address. E.g. an IPv4 packet did not have an Ethernet address
/// corresponding to its IPv4 destination address.
Unaddressable,
/// A buffer for incoming packets is empty, or a buffer for outgoing packets is full.
Exhausted,
/// An incoming packet does not match the socket endpoint.
Rejected,
/// An incoming packet was recognized by a stateful socket and contained invalid control
/// information that caused the socket to drop it.
/// An incoming packet was recognized but was self-contradictory.
/// E.g. a TCP packet with both SYN and FIN flags set.
Malformed,
/// An incoming packet was recognized but contradicted internal state.
/// E.g. a TCP packet addressed to a socket that doesn't exist.
Dropped,

// Implementation detail.
#[doc(hidden)]
Rejected,

#[doc(hidden)]
__Nonexhaustive
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Error::Exhausted => write!(f, "buffer space exhausted"),
&Error::Illegal => write!(f, "illegal operation"),
&Error::Unaddressable => write!(f, "unaddressable destination"),
&Error::Truncated => write!(f, "truncated packet"),
&Error::Unrecognized => write!(f, "unrecognized packet"),
&Error::Malformed => write!(f, "malformed packet"),
&Error::Checksum => write!(f, "checksum error"),
&Error::Unrecognized => write!(f, "unrecognized packet"),
&Error::Fragmented => write!(f, "fragmented packet"),
&Error::Unaddressable => write!(f, "unaddressable destination"),
&Error::Exhausted => write!(f, "buffer space exhausted"),
&Error::Rejected => write!(f, "rejected by socket"),
&Error::Malformed => write!(f, "malformed packet"),
&Error::Dropped => write!(f, "dropped by socket"),
&Error::Rejected => write!(f, "rejected by socket"),
&Error::__Nonexhaustive => unreachable!()
}
}
59 changes: 44 additions & 15 deletions src/socket/tcp.rs
Original file line number Diff line number Diff line change
@@ -377,23 +377,23 @@ impl<'a> TcpSocket<'a> {
/// The local address may optionally be provided.
///
/// This function returns an error if the socket was open; see [is_open](#method.is_open).
/// It also returns an error if the local or remote port is zero, or if
/// the local or remote address is unspecified.
pub fn connect<T, U>(&mut self, remote_endpoint: T, local_endpoint: U) -> Result<(), ()>
/// It also returns an error if the local or remote port is zero, or if the remote address
/// is unspecified.
pub fn connect<T, U>(&mut self, remote_endpoint: T, local_endpoint: U) -> Result<(), Error>
where T: Into<IpEndpoint>, U: Into<IpEndpoint> {
let remote_endpoint = remote_endpoint.into();
let local_endpoint = local_endpoint.into();

if self.is_open() { return Err(()) }
if remote_endpoint.port == 0 { return Err(()) }
if local_endpoint.port == 0 { return Err(()) }
if self.is_open() { return Err(Error::Illegal) }
if !remote_endpoint.is_specified() { return Err(Error::Unaddressable) }
if local_endpoint.port == 0 { return Err(Error::Unaddressable) }

// If local address is not provided, use an unspecified address but a specified protocol.
// This lets us lower IpRepr later to determine IP header size and calculate MSS,
// but without committing to a specific address right away.
let local_addr = match remote_endpoint.addr {
IpAddress::Unspecified => return Err(()),
_ => remote_endpoint.addr.as_unspecified(),
IpAddress::Unspecified => return Err(Error::Unaddressable),
_ => remote_endpoint.addr.to_unspecified(),
};
let local_endpoint = IpEndpoint { addr: local_addr, ..local_endpoint };

@@ -982,7 +982,7 @@ impl<'a> TcpSocket<'a> {
pub(crate) fn dispatch<F, R>(&mut self, timestamp: u64, limits: &DeviceLimits,
emit: &mut F) -> Result<R, Error>
where F: FnMut(&IpRepr, &IpPayload) -> Result<R, Error> {
if self.remote_endpoint.is_unspecified() { return Err(Error::Exhausted) }
if !self.remote_endpoint.is_specified() { return Err(Error::Exhausted) }

let mut repr = TcpRepr {
src_port: self.local_endpoint.port,
@@ -1585,12 +1585,14 @@ mod test {
#[test]
fn test_connect_validation() {
let mut s = socket();
assert_eq!(s.connect(REMOTE_END, (IpAddress::Unspecified, 80)), Ok(()));
assert_eq!(s.connect(REMOTE_END, (IpAddress::v4(0, 0, 0, 0), 80)), Err(()));
assert_eq!(s.connect(REMOTE_END, (IpAddress::v4(10, 0, 0, 0), 0)), Err(()));
assert_eq!(s.connect((IpAddress::Unspecified, 80), LOCAL_END), Err(()));
assert_eq!(s.connect((IpAddress::v4(0, 0, 0, 0), 80), LOCAL_END), Err(()));
assert_eq!(s.connect((IpAddress::v4(10, 0, 0, 0), 0), LOCAL_END), Err(()));
assert_eq!(s.connect((IpAddress::v4(0, 0, 0, 0), 80), LOCAL_END),
Err(Error::Unaddressable));
assert_eq!(s.connect(REMOTE_END, (IpAddress::v4(10, 0, 0, 0), 0)),
Err(Error::Unaddressable));
assert_eq!(s.connect((IpAddress::v4(10, 0, 0, 0), 0), LOCAL_END),
Err(Error::Unaddressable));
assert_eq!(s.connect((IpAddress::Unspecified, 80), LOCAL_END),
Err(Error::Unaddressable));
}

#[test]
@@ -1616,6 +1618,33 @@ mod test {
assert_eq!(s.local_endpoint, LOCAL_END);
}

#[test]
fn test_connect_unspecified_local() {
let mut s = socket();
assert_eq!(s.connect(REMOTE_END, (IpAddress::v4(0, 0, 0, 0), 80)),
Ok(()));
s.abort();
assert_eq!(s.connect(REMOTE_END, (IpAddress::Unspecified, 80)),
Ok(()));
s.abort();
}

#[test]
fn test_connect_specified_local() {
let mut s = socket();
assert_eq!(s.connect(REMOTE_END, (IpAddress::v4(10, 0, 0, 2), 80)),
Ok(()));
}

#[test]
fn test_connect_twice() {
let mut s = socket();
assert_eq!(s.connect(REMOTE_END, (IpAddress::Unspecified, 80)),
Ok(()));
assert_eq!(s.connect(REMOTE_END, (IpAddress::Unspecified, 80)),
Err(Error::Illegal));
}

#[test]
fn test_syn_sent_sanity() {
let mut s = socket();
11 changes: 6 additions & 5 deletions src/wire/ip.rs
Original file line number Diff line number Diff line change
@@ -73,7 +73,7 @@ impl Address {
}

/// Return an unspecified address that has the same IP version as `self`.
pub fn as_unspecified(&self) -> Address {
pub fn to_unspecified(&self) -> Address {
match self {
&Address::Unspecified => Address::Unspecified,
// &Address::Ipv4 => Address::Ipv4(Ipv4Address::UNSPECIFIED),
@@ -120,9 +120,9 @@ impl Endpoint {
Endpoint { addr: addr, port: port }
}

/// Query whether the endpoint has an unspecified address.
pub fn is_unspecified(&self) -> bool {
self.addr.is_unspecified()
/// Query whether the endpoint has a specified address and port.
pub fn is_specified(&self) -> bool {
!self.addr.is_unspecified() && self.port != 0
}
}

@@ -353,7 +353,8 @@ pub mod checksum {
])
},

_ => panic!("Unexpected pseudo header ")
_ => panic!("Unexpected pseudo header addresses: {}, {}",
src_addr, dst_addr)
}
}
}