From 74d1eb86b600b25000fc1db9411a19199d505860 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 17 Jan 2017 01:24:51 +0000 Subject: [PATCH] Add TcpSocket::abort(). --- src/socket/tcp.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/socket/tcp.rs b/src/socket/tcp.rs index e563477..2d18942 100644 --- a/src/socket/tcp.rs +++ b/src/socket/tcp.rs @@ -354,6 +354,17 @@ impl<'a> TcpSocket<'a> { } } + /// Aborts the connection, if any. + /// + /// This function instantly closes the socket. One reset packet will be sent to the remote + /// endpoint. + /// + /// In terms of the TCP state machine, the socket may be in any state and is moved to + /// the `CLOSED` state. + pub fn abort(&mut self) { + self.set_state(State::Closed); + } + /// Return whether the socket is passively listening for incoming connections. /// /// In terms of the TCP state machine, the socket must be in the `LISTEN` state. @@ -787,6 +798,27 @@ impl<'a> TcpSocket<'a> { payload: &[] }; + if self.state == State::Closed { + // If we have a specified local and remote endpoint, but are in the CLOSED state, + // we've ended up here after aborting a connection. Send exactly one RST packet. + net_trace!("[{}]{}:{}: sending RST", + self.debug_id, self.local_endpoint, self.remote_endpoint); + + repr.control = TcpControl::Rst; + repr.ack_number = Some(self.remote_seq_no); + let ip_repr = IpRepr::Unspecified { + src_addr: self.local_endpoint.addr, + dst_addr: self.remote_endpoint.addr, + protocol: IpProtocol::Tcp, + payload_len: repr.buffer_len() + }; + let result = emit(&ip_repr, &repr); + + self.local_endpoint = IpEndpoint::default(); + self.remote_endpoint = IpEndpoint::default(); + return result + } + if self.retransmit.may_send_old(timestamp) { // The retransmit timer has expired, so assume all in-flight data that // has not been acknowledged is lost. @@ -1517,6 +1549,19 @@ mod test { sanity!(s, socket_fin_wait_1()); } + #[test] + fn test_established_abort() { + let mut s = socket_established(); + s.abort(); + assert_eq!(s.state, State::Closed); + recv!(s, [TcpRepr { + control: TcpControl::Rst, + seq_number: LOCAL_SEQ + 1, + ack_number: Some(REMOTE_SEQ + 1), + ..RECV_TEMPL + }]); + } + // =========================================================================================// // Tests for the FIN-WAIT-1 state. // =========================================================================================//