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: 1a618aac451d
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: 3bb3c9e078a9
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Dec 27, 2016

  1. Copy the full SHA
    67aa329 View commit details
  2. Copy the full SHA
    3bb3c9e View commit details
Showing with 99 additions and 40 deletions.
  1. +2 −1 examples/smoltcpserver.rs
  2. +97 −39 src/socket/tcp.rs
3 changes: 2 additions & 1 deletion examples/smoltcpserver.rs
Original file line number Diff line number Diff line change
@@ -122,7 +122,8 @@ fn main() {
socket.send_slice(&data[..]).unwrap();
}
} else if socket.can_send() {
socket.close()
socket.close();
debug!("tcp closed")
}
}

136 changes: 97 additions & 39 deletions src/socket/tcp.rs
Original file line number Diff line number Diff line change
@@ -131,15 +131,15 @@ impl fmt::Display for State {
match self {
&State::Closed => write!(f, "CLOSED"),
&State::Listen => write!(f, "LISTEN"),
&State::SynSent => write!(f, "SYN_SENT"),
&State::SynReceived => write!(f, "SYN_RECEIVED"),
&State::SynSent => write!(f, "SYN-SENT"),
&State::SynReceived => write!(f, "SYN-RECEIVED"),
&State::Established => write!(f, "ESTABLISHED"),
&State::FinWait1 => write!(f, "FIN_WAIT_1"),
&State::FinWait2 => write!(f, "FIN_WAIT_2"),
&State::CloseWait => write!(f, "CLOSE_WAIT"),
&State::FinWait1 => write!(f, "FIN-WAIT-1"),
&State::FinWait2 => write!(f, "FIN-WAIT-2"),
&State::CloseWait => write!(f, "CLOSE-WAIT"),
&State::Closing => write!(f, "CLOSING"),
&State::LastAck => write!(f, "LAST_ACK"),
&State::TimeWait => write!(f, "TIME_WAIT")
&State::LastAck => write!(f, "LAST-ACK"),
&State::TimeWait => write!(f, "TIME-WAIT")
}
}
}
@@ -267,17 +267,21 @@ impl<'a> TcpSocket<'a> {
// In the LISTEN state there is no established connection.
State::Listen =>
self.set_state(State::Closed),
// In the SYN_SENT state the remote endpoint is not yet synchronized and, upon
// In the SYN-SENT state the remote endpoint is not yet synchronized and, upon
// receiving an RST, will abort the connection.
State::SynSent =>
self.set_state(State::Closed),
// In the SYN_RECEIVED, ESTABLISHED and CLOSE_WAIT states the transmit half
// In the SYN-RECEIVED, ESTABLISHED and CLOSE-WAIT states the transmit half
// of the connection is open, and needs to be explicitly closed with a FIN.
State::SynReceived | State::Established =>
self.set_state(State::FinWait1),
State::CloseWait =>
self.set_state(State::LastAck),
// In the FIN_WAIT_1, FIN_WAIT_2, CLOSING, LAST_ACK, TIME_WAIT and CLOSED states,
State::SynReceived | State::Established => {
self.retransmit.reset();
self.set_state(State::FinWait1);
}
State::CloseWait => {
self.retransmit.reset();
self.set_state(State::LastAck);
}
// In the FIN-WAIT-1, FIN-WAIT-2, CLOSING, LAST-ACK, TIME-WAIT and CLOSED states,
// the transmit half of the connection is already closed, and no further
// action is needed.
State::FinWait1 | State::FinWait2 | State::Closing |
@@ -325,7 +329,7 @@ impl<'a> TcpSocket<'a> {
pub fn can_send(&self) -> bool {
match self.state {
State::Established => true,
// In CLOSE_WAIT, the remote endpoint has closed our receive half of the connection
// In CLOSE-WAIT, the remote endpoint has closed our receive half of the connection
// but we still can transmit indefinitely.
State::CloseWait => true,
_ => false
@@ -340,7 +344,7 @@ impl<'a> TcpSocket<'a> {
pub fn can_recv(&self) -> bool {
match self.state {
State::Established => true,
// In FIN_WAIT_1/2, we have closed our transmit half of the connection but
// In FIN-WAIT-1/2, we have closed our transmit half of the connection but
// we still can receive indefinitely.
State::FinWait1 | State::FinWait2 => true,
// If we have something in the receive buffer, we can receive that.
@@ -499,9 +503,9 @@ impl<'a> TcpSocket<'a> {
// Every acknowledgement must be for transmitted but unacknowledged data.
(state, TcpRepr { ack_number: Some(ack_number), .. }) => {
let control_len = match state {
// In SYN_SENT or SYN_RECEIVED, we've just sent a SYN.
// In SYN-SENT or SYN-RECEIVED, we've just sent a SYN.
State::SynSent | State::SynReceived => 1,
// In FIN_WAIT_1 or LAST_ACK, we've just sent a FIN.
// In FIN-WAIT-1 or LAST-ACK, we've just sent a FIN.
State::FinWait1 | State::LastAck => 1,
// In all other states we've already got acknowledgemetns for
// all of the control flags we sent.
@@ -519,7 +523,7 @@ impl<'a> TcpSocket<'a> {
}

match (self.state, repr) {
// In LISTEN and SYN_SENT states, we have not yet synchronized with the remote end.
// In LISTEN and SYN-SENT states, we have not yet synchronized with the remote end.
(State::Listen, _) => (),
(State::SynSent, _) => (),
// In all other states, segments must occupy a valid portion of the receive window.
@@ -546,7 +550,7 @@ impl<'a> TcpSocket<'a> {
(State::Listen, TcpRepr { control: TcpControl::Rst, .. }) =>
return Ok(()),

// RSTs in SYN_RECEIVED flip the socket back to the LISTEN state.
// RSTs in SYN-RECEIVED flip the socket back to the LISTEN state.
(State::SynReceived, TcpRepr { control: TcpControl::Rst, .. }) => {
net_trace!("tcp:{}:{}: received RST",
self.local_endpoint, self.remote_endpoint);
@@ -566,7 +570,7 @@ impl<'a> TcpSocket<'a> {
return Ok(())
}

// SYN packets in the LISTEN state change it to SYN_RECEIVED.
// SYN packets in the LISTEN state change it to SYN-RECEIVED.
(State::Listen, TcpRepr {
src_port, dst_port, control: TcpControl::Syn, seq_number, ack_number: None, ..
}) => {
@@ -580,7 +584,7 @@ impl<'a> TcpSocket<'a> {
self.retransmit.reset()
}

// ACK packets in the SYN_RECEIVED state change it to ESTABLISHED.
// ACK packets in the SYN-RECEIVED state change it to ESTABLISHED.
(State::SynReceived, TcpRepr { control: TcpControl::None, .. }) => {
self.local_seq_no += 1;
self.set_state(State::Established);
@@ -597,9 +601,17 @@ impl<'a> TcpSocket<'a> {
self.retransmit.reset()
}

// ACK packets in CLOSE_WAIT state do nothing.
// ACK packets in CLOSE-WAIT state do nothing.
(State::CloseWait, TcpRepr { control: TcpControl::None, .. }) => (),

// ACK packets in LAST-ACK state change it to CLOSED.
(State::LastAck, TcpRepr { control: TcpControl::None, .. }) => {
// Clear the remote endpoint, or we'll send an RST there.
self.remote_endpoint = IpEndpoint::default();
self.local_seq_no += 1;
self.set_state(State::Closed);
}

_ => {
net_trace!("tcp:{}:{}: unexpected packet {}",
self.local_endpoint, self.remote_endpoint, repr);
@@ -653,8 +665,12 @@ impl<'a> TcpSocket<'a> {

let mut should_send = false;
match self.state {
State::Closed | State::Listen => return Err(Error::Exhausted),
// We never transmit anything in the CLOSED, LISTEN, TIME-WAIT or FIN-WAIT-2 states.
State::Closed | State::Listen | State::TimeWait | State::FinWait2 => {
return Err(Error::Exhausted)
}

// We transmit a SYN|ACK in the SYN-RECEIVED state.
State::SynReceived => {
if !self.retransmit.check() { return Err(Error::Exhausted) }

@@ -664,16 +680,30 @@ impl<'a> TcpSocket<'a> {
should_send = true;
}

// We transmit a SYN in the SYN-SENT state.
State::SynSent => {
if !self.retransmit.check() { return Err(Error::Exhausted) }

repr.control = TcpControl::Syn;
repr.ack_number = None;
net_trace!("tcp:{}:{}: sending SYN",
self.local_endpoint, self.remote_endpoint);
should_send = true;
}

// We transmit data in the ESTABLISHED state,
// ACK in CLOSE-WAIT and CLOSING states,
// FIN in FIN-WAIT-1 and LAST-ACK states.
State::Established |
State::CloseWait => {
State::CloseWait | State::LastAck |
State::FinWait1 | State::Closing => {
// See if we should send data to the remote end because:
// 1. the retransmit timer has expired, or...
let mut may_send = self.retransmit.check();
let mut may_send = false;
// 1. the retransmit timer has expired or was reset, or...
if self.retransmit.check() { may_send = true }
// 2. we've got new data in the transmit buffer.
let remote_next_seq = self.local_seq_no + self.tx_buffer.len();
if self.remote_last_seq != remote_next_seq {
may_send = true;
}
if self.remote_last_seq != remote_next_seq { may_send = true }

if self.tx_buffer.len() > 0 && self.remote_win_len > 0 && may_send {
// We can send something, so let's do that.
@@ -699,9 +729,19 @@ impl<'a> TcpSocket<'a> {
self.remote_last_seq += data.len();
should_send = true;
}
}

_ => unreachable!()
match self.state {
State::FinWait1 | State::LastAck if may_send => {
// We should notify the other side that we've closed the transmit half
// of the connection.
net_trace!("tcp:{}:{}: sending FIN|ACK",
self.local_endpoint, self.remote_endpoint);
repr.control = TcpControl::Fin;
should_send = true;
},
_ => ()
}
}
}

let ack_number = self.remote_seq_no + self.rx_buffer.len();
@@ -938,7 +978,7 @@ mod test {
}

// =========================================================================================//
// Tests for the SYN_RECEIVED state.
// Tests for the SYN-RECEIVED state.
// =========================================================================================//
fn socket_syn_received() -> TcpSocket<'static> {
let mut s = socket();
@@ -972,7 +1012,7 @@ mod test {
}

// =========================================================================================//
// Tests for the SYN_SENT state.
// Tests for the SYN-SENT state.
// =========================================================================================//
fn socket_syn_sent() -> TcpSocket<'static> {
let mut s = socket();
@@ -1234,7 +1274,7 @@ mod test {
}

// =========================================================================================//
// Tests for the FIN_WAIT_1 state.
// Tests for the FIN-WAIT-1 state.
// =========================================================================================//
fn socket_fin_wait_1() -> TcpSocket<'static> {
let mut s = socket_established();
@@ -1250,7 +1290,7 @@ mod test {
}

// =========================================================================================//
// Tests for the FIN_WAIT_2 state.
// Tests for the FIN-WAIT-2 state.
// =========================================================================================//
fn socket_fin_wait_2() -> TcpSocket<'static> {
let mut s = socket_fin_wait_1();
@@ -1285,7 +1325,7 @@ mod test {
}

// =========================================================================================//
// Tests for the CLOSE_WAIT state.
// Tests for the CLOSE-WAIT state.
// =========================================================================================//
fn socket_close_wait() -> TcpSocket<'static> {
let mut s = socket_established();
@@ -1320,14 +1360,32 @@ mod test {
}

// =========================================================================================//
// Tests for the LAST_ACK state.
// Tests for the LAST-ACK state.
// =========================================================================================//
fn socket_last_ack() -> TcpSocket<'static> {
let mut s = socket_close_wait();
s.state = State::LastAck;
s
}

#[test]
fn test_last_ack_fin_ack() {
let mut s = socket_last_ack();
recv!(s, [TcpRepr {
control: TcpControl::Fin,
seq_number: LOCAL_SEQ + 1,
ack_number: Some(REMOTE_SEQ + 1 + 1),
..RECV_TEMPL
}]);
assert_eq!(s.state, State::LastAck);
send!(s, [TcpRepr {
seq_number: REMOTE_SEQ + 1 + 1,
ack_number: Some(LOCAL_SEQ + 1 + 1),
..SEND_TEMPL
}]);
assert_eq!(s.state, State::Closed);
}

#[test]
fn test_last_ack_close() {
let mut s = socket_last_ack();
@@ -1336,7 +1394,7 @@ mod test {
}

// =========================================================================================//
// Tests for the TIME_WAIT state.
// Tests for the TIME-WAIT state.
// =========================================================================================//
fn socket_time_wait() -> TcpSocket<'static> {
let mut s = socket_fin_wait_2();