Implement the TCP CLOSING state.
This commit is contained in:
parent
3e7a1ee575
commit
94963faf12
|
@ -175,8 +175,8 @@ impl Retransmit {
|
|||
pub struct TcpSocket<'a> {
|
||||
/// State of the socket.
|
||||
state: State,
|
||||
/// Address passed to `listen()`. `listen_address` is set when `listen()` is called and
|
||||
/// used every time the socket is reset back to the `LISTEN` state.
|
||||
/// Address passed to listen(). Listen address is set when listen() is called and
|
||||
/// used every time the socket is reset back to the LISTEN state.
|
||||
listen_address: IpAddress,
|
||||
/// Current local endpoint. This is used for both filtering the incoming packets and
|
||||
/// setting the source address. When listening or initiating connection on/from
|
||||
|
@ -184,7 +184,9 @@ pub struct TcpSocket<'a> {
|
|||
/// any packets are sent.
|
||||
local_endpoint: IpEndpoint,
|
||||
/// Current remote endpoint. This is used for both filtering the incoming packets and
|
||||
/// setting the destination address.
|
||||
/// setting the destination address. If the remote endpoint is unspecified, it means that
|
||||
/// aborting the connection will not send an RST, and, in TIME-WAIT state, will not
|
||||
/// send an ACK.
|
||||
remote_endpoint: IpEndpoint,
|
||||
/// The sequence number corresponding to the beginning of the transmit buffer.
|
||||
/// I.e. an ACK(local_seq_no+n) packet removes n bytes from the transmit buffer.
|
||||
|
@ -621,6 +623,13 @@ impl<'a> TcpSocket<'a> {
|
|||
self.retransmit.reset();
|
||||
}
|
||||
|
||||
// ACK packets in CLOSING state change it to TIME-WAIT.
|
||||
(State::Closing, TcpRepr { control: TcpControl::None, .. }) => {
|
||||
// Clear the remote endpoint, or we'll send an ACK there.
|
||||
self.remote_endpoint = IpEndpoint::default();
|
||||
self.set_state(State::TimeWait);
|
||||
}
|
||||
|
||||
// ACK packets in CLOSE-WAIT state do nothing.
|
||||
(State::CloseWait, TcpRepr { control: TcpControl::None, .. }) => (),
|
||||
|
||||
|
@ -668,6 +677,8 @@ impl<'a> TcpSocket<'a> {
|
|||
/// See [Socket::dispatch](enum.Socket.html#method.dispatch).
|
||||
pub fn dispatch<F, R>(&mut self, emit: &mut F) -> Result<R, Error>
|
||||
where F: FnMut(&IpRepr, &IpPayload) -> Result<R, Error> {
|
||||
if self.remote_endpoint.is_unspecified() { return Err(Error::Exhausted) }
|
||||
|
||||
let ip_repr = IpRepr::Unspecified {
|
||||
src_addr: self.local_endpoint.addr,
|
||||
dst_addr: self.remote_endpoint.addr,
|
||||
|
@ -1364,6 +1375,7 @@ mod test {
|
|||
..SEND_TEMPL
|
||||
}]);
|
||||
assert_eq!(s.state, State::TimeWait);
|
||||
assert!(!s.remote_endpoint.is_unspecified());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1379,11 +1391,28 @@ mod test {
|
|||
fn socket_closing() -> TcpSocket<'static> {
|
||||
let mut s = socket_fin_wait_1();
|
||||
s.state = State::Closing;
|
||||
s.local_seq_no = LOCAL_SEQ + 1 + 1;
|
||||
s.remote_seq_no = REMOTE_SEQ + 1 + 1;
|
||||
s.remote_last_ack = REMOTE_SEQ + 1 + 1;
|
||||
s
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_closing_ack_fin() {
|
||||
let mut s = socket_closing();
|
||||
recv!(s, [TcpRepr {
|
||||
seq_number: LOCAL_SEQ + 1 + 1,
|
||||
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
||||
..RECV_TEMPL
|
||||
}]);
|
||||
send!(s, [TcpRepr {
|
||||
seq_number: REMOTE_SEQ + 1 + 1,
|
||||
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
||||
..SEND_TEMPL
|
||||
}]);
|
||||
assert_eq!(s.state, State::TimeWait);
|
||||
assert!(s.remote_endpoint.is_unspecified());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_closing_close() {
|
||||
let mut s = socket_closing();
|
||||
|
|
|
@ -91,6 +91,11 @@ impl Endpoint {
|
|||
pub fn new(addr: Address, port: u16) -> Endpoint {
|
||||
Endpoint { addr: addr, port: port }
|
||||
}
|
||||
|
||||
/// Query whether the endpoint has an unspecified address.
|
||||
pub fn is_unspecified(&self) -> bool {
|
||||
self.addr.is_unspecified()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Endpoint {
|
||||
|
|
Loading…
Reference in New Issue