Implement the TCP LAST-ACK state.

v0.7.x
whitequark 2016-12-27 23:27:33 +00:00
parent 874264503d
commit 979cd4c1bf
2 changed files with 73 additions and 14 deletions

View File

@ -122,7 +122,8 @@ fn main() {
socket.send_slice(&data[..]).unwrap();
}
} else if socket.can_send() {
socket.close()
socket.close();
debug!("tcp closed")
}
}

View File

@ -273,10 +273,14 @@ impl<'a> TcpSocket<'a> {
self.set_state(State::Closed),
// 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),
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.
@ -600,6 +604,14 @@ impl<'a> TcpSocket<'a> {
// 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();
@ -1328,6 +1368,24 @@ mod test {
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();