Implement the TCP LAST-ACK state.
parent
874264503d
commit
979cd4c1bf
|
@ -122,7 +122,8 @@ fn main() {
|
|||
socket.send_slice(&data[..]).unwrap();
|
||||
}
|
||||
} else if socket.can_send() {
|
||||
socket.close()
|
||||
socket.close();
|
||||
debug!("tcp closed")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue