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: d73c2bdb8171
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: 0904645c1ba8
Choose a head ref
  • 2 commits
  • 4 files changed
  • 1 contributor

Commits on Jul 23, 2017

  1. Update README.

    whitequark committed Jul 23, 2017
    Copy the full SHA
    30fc358 View commit details
  2. Fix determination of local address from incoming packets.

    We've advertised this capability before in examples, but it did not
    actually work.
    whitequark committed Jul 23, 2017
    Copy the full SHA
    0904645 View commit details
Showing with 72 additions and 12 deletions.
  1. +24 −6 README.md
  2. +1 −1 examples/loopback.rs
  3. +38 −5 src/socket/tcp.rs
  4. +9 −0 src/wire/ip.rs
30 changes: 24 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -163,6 +163,13 @@ Note that packets dropped by the fault injector still get traced;
the `rx: randomly dropping a packet` message indicates that the packet *above* it got dropped,
and the `tx: randomly dropping a packet` message indicates that the packet *below* it was.

### Packet dumps

All examples provide a `--pcap` option that writes a [libpcap] file containing a view of every
packet as it is seen by _smoltcp_.

[libpcap]: https://wiki.wireshark.org/Development/LibpcapFileFormat

### examples/tcpdump.rs

_examples/tcpdump.rs_ is a tiny clone of the _tcpdump_ utility.
@@ -248,17 +255,28 @@ that do. Because of this, only one such example is provided.

### examples/loopback.rs

_examples/loopback.rs_ performs a simple exchange between two TCP socket via a loopback interface.
This example requires the `collections` feature to run.
_examples/loopback.rs_ sets up _smoltcp_ to talk with itself via a loopback interface.
Although it does not require `std`, this example still requires the `collections` feature to run.

Read its [source code](/examples/loopback.rs), then run it as:
Read its [source code](/examples/loopback.rs), then run it without `std`:

```sh
cargo run --example loopback
cargo run --example loopback --no-default-features --features collections
```

If the `std` feature is enabled, it will print logs and packet dumps; otherwise, nothing at all
will be displayed.
... or with `std`:

```sh
cargo run --example loopback -- --pcap loopback.pcap
```

It opens a server and a client TCP socket, and transfers a chunk of data. You can examine
the packet exchange by opening `loopback.pcap` in [Wireshark].

If the `std` feature is enabled, it will print logs and packet dumps, and fault injection
is possible; otherwise, nothing at all will be displayed and no options are accepted.

[wireshark]: https://wireshark.org

License
-------
2 changes: 1 addition & 1 deletion examples/loopback.rs
Original file line number Diff line number Diff line change
@@ -149,7 +149,7 @@ fn main() {
if !socket.is_open() {
if !did_connect {
socket.connect((IpAddress::v4(127, 0, 0, 1), 1234),
(IpAddress::v4(127, 0, 0, 1), 65000)).unwrap();
(IpAddress::Unspecified, 65000)).unwrap();
did_connect = true;
}
}
43 changes: 38 additions & 5 deletions src/socket/tcp.rs
Original file line number Diff line number Diff line change
@@ -368,7 +368,7 @@ impl<'a> TcpSocket<'a> {
/// Connect to a given endpoint.
///
/// The local port must be provided explicitly. Assuming `fn get_ephemeral_port() -> u16`
/// allocates a port from the 49152 to 65535 range, a connection may be established as follows:
/// allocates a port between 49152 and 65535, a connection may be established as follows:
///
/// ```rust,ignore
/// socket.connect((IpAddress::v4(10, 0, 0, 1), 80), get_ephemeral_port())
@@ -386,9 +386,16 @@ impl<'a> TcpSocket<'a> {

if self.is_open() { return Err(()) }
if remote_endpoint.port == 0 { return Err(()) }
if remote_endpoint.addr.is_unspecified() { return Err(()) }
if local_endpoint.port == 0 { return Err(()) }
if local_endpoint.addr.is_unspecified() { return Err(()) }

// 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(),
};
let local_endpoint = IpEndpoint { addr: local_addr, ..local_endpoint };

// Carry over the local sequence number.
let local_seq_no = self.local_seq_no;
@@ -852,6 +859,7 @@ impl<'a> TcpSocket<'a> {
}) => {
net_trace!("[{}]{}:{}: received SYN|ACK",
self.debug_id, self.local_endpoint, self.remote_endpoint);
self.local_endpoint = IpEndpoint::new(ip_repr.dst_addr(), repr.dst_port);
self.remote_last_seq = self.local_seq_no + 1;
self.remote_seq_no = seq_number + 1;
self.remote_last_ack = seq_number;
@@ -1269,6 +1277,8 @@ mod test {
let mut limits = DeviceLimits::default();
limits.max_transmission_unit = 1520;
let result = socket.dispatch(timestamp, &limits, &mut |ip_repr, payload| {
let ip_repr = ip_repr.lower(&[LOCAL_END.addr.into()]).unwrap();

assert_eq!(ip_repr.protocol(), IpProtocol::Tcp);
assert_eq!(ip_repr.src_addr(), LOCAL_IP);
assert_eq!(ip_repr.dst_addr(), REMOTE_IP);
@@ -1533,7 +1543,7 @@ mod test {
fn socket_syn_sent() -> TcpSocket<'static> {
let mut s = socket();
s.state = State::SynSent;
s.local_endpoint = LOCAL_END;
s.local_endpoint = IpEndpoint::new(IpAddress::v4(0, 0, 0, 0), LOCAL_PORT);
s.remote_endpoint = REMOTE_END;
s.local_seq_no = LOCAL_SEQ;
s
@@ -1542,14 +1552,37 @@ mod test {
#[test]
fn test_connect_validation() {
let mut s = socket();
assert_eq!(s.connect(REMOTE_END, (IpAddress::Unspecified, 80)), Err(()));
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(()));
}

#[test]
fn test_connect() {
let mut s = socket();
s.local_seq_no = LOCAL_SEQ;
s.connect(REMOTE_END, LOCAL_END.port).unwrap();
assert_eq!(s.local_endpoint, IpEndpoint::new(IpAddress::v4(0, 0, 0, 0), LOCAL_END.port));
recv!(s, [TcpRepr {
control: TcpControl::Syn,
seq_number: LOCAL_SEQ,
ack_number: None,
max_seg_size: Some(1480),
..RECV_TEMPL
}]);
send!(s, TcpRepr {
control: TcpControl::Syn,
seq_number: REMOTE_SEQ,
ack_number: Some(LOCAL_SEQ + 1),
max_seg_size: Some(1400),
..SEND_TEMPL
});
assert_eq!(s.local_endpoint, LOCAL_END);
}

#[test]
fn test_syn_sent_sanity() {
let mut s = socket();
9 changes: 9 additions & 0 deletions src/wire/ip.rs
Original file line number Diff line number Diff line change
@@ -71,6 +71,15 @@ impl Address {
&Address::Ipv4(addr) => addr.is_unspecified()
}
}

/// Return an unspecified address that has the same IP version as `self`.
pub fn as_unspecified(&self) -> Address {
match self {
&Address::Unspecified => Address::Unspecified,
// &Address::Ipv4 => Address::Ipv4(Ipv4Address::UNSPECIFIED),
&Address::Ipv4(_) => Address::Ipv4(Ipv4Address(/*FIXME*/[0x00; 4])),
}
}
}

impl Default for Address {