Skip to content

Commit

Permalink
TCP: retransmit ACK when receiving duplicate SEQ.
Browse files Browse the repository at this point in the history
whitequark committed Dec 31, 2016
1 parent 1c7f972 commit 5b4db5f
Showing 3 changed files with 53 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/phy/fault_injector.rs
Original file line number Diff line number Diff line change
@@ -122,7 +122,7 @@ impl<T: Device> Device for FaultInjector<T>
fn transmit(&mut self, length: usize) -> Result<Self::TxBuffer, Error> {
let buffer;
if check_rng(&mut self.state, self.config.drop_pct) {
net_trace!("rx: dropping a packet");
net_trace!("tx: dropping a packet");
buffer = None;
} else {
buffer = Some(try!(self.lower.transmit(length)));
41 changes: 41 additions & 0 deletions src/socket/tcp.rs
Original file line number Diff line number Diff line change
@@ -542,6 +542,9 @@ impl<'a> TcpSocket<'a> {
net_trace!("tcp:{}:{}: duplicate SEQ ({} in ..{})",
self.local_endpoint, self.remote_endpoint,
seq_number, next_remote_seq);
// If we've seen this sequence number already but the remote end is not aware
// of that, make sure we send the acknowledgement again.
self.remote_last_ack = next_remote_seq - 1;
return Ok(())
}
}
@@ -1656,4 +1659,42 @@ mod test {
assert_eq!(s.state, State::TimeWait);
recv!(s, []);
}

// =========================================================================================//
// Tests for retransmission on packet loss.
// =========================================================================================//
fn socket_recved() -> TcpSocket<'static> {
let mut s = socket_established();
send!(s, [TcpRepr {
seq_number: REMOTE_SEQ + 1,
ack_number: Some(LOCAL_SEQ + 1),
payload: &b"abcdef"[..],
..SEND_TEMPL
}]);
recv!(s, [TcpRepr {
seq_number: LOCAL_SEQ + 1,
ack_number: Some(REMOTE_SEQ + 1 + 6),
window_len: 58,
..RECV_TEMPL
}]);
s
}

#[test]
fn test_duplicate_seq_ack() {
let mut s = socket_recved();
// remote retransmission
send!(s, [TcpRepr {
seq_number: REMOTE_SEQ + 1,
ack_number: Some(LOCAL_SEQ + 1),
payload: &b"abcdef"[..],
..SEND_TEMPL
}]);
recv!(s, [TcpRepr {
seq_number: LOCAL_SEQ + 1,
ack_number: Some(REMOTE_SEQ + 1 + 6),
window_len: 58,
..RECV_TEMPL
}]);
}
}
11 changes: 11 additions & 0 deletions src/wire/tcp.rs
Original file line number Diff line number Diff line change
@@ -29,6 +29,17 @@ impl ops::Add<usize> for SeqNumber {
}
}

impl ops::Sub<usize> for SeqNumber {
type Output = SeqNumber;

fn sub(self, rhs: usize) -> SeqNumber {
if rhs > i32::MAX as usize {
panic!("attempt to subtract to sequence number with unsigned overflow")
}
SeqNumber(self.0.wrapping_sub(rhs as i32))
}
}

impl ops::AddAssign<usize> for SeqNumber {
fn add_assign(&mut self, rhs: usize) {
*self = *self + rhs;

0 comments on commit 5b4db5f

Please sign in to comment.