2017-06-26 16:09:27 +08:00
|
|
|
// Heads up! Before working on this file you should read, at least, RFC 793 and
|
2017-09-23 02:40:23 +08:00
|
|
|
// the parts of RFC 1122 that discuss TCP. Consult RFC 7414 when implementing
|
|
|
|
// a new feature.
|
2017-06-26 16:09:27 +08:00
|
|
|
|
2018-08-20 04:32:27 +08:00
|
|
|
use core::{cmp, fmt, mem};
|
2020-10-20 19:22:46 +08:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
use core::task::Waker;
|
2016-12-19 03:40:11 +08:00
|
|
|
|
2020-12-27 07:11:30 +08:00
|
|
|
use crate::{Error, Result};
|
|
|
|
use crate::phy::DeviceCapabilities;
|
|
|
|
use crate::time::{Duration, Instant};
|
|
|
|
use crate::socket::{Socket, SocketMeta, SocketHandle, PollAt};
|
|
|
|
use crate::storage::{Assembler, RingBuffer};
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
use crate::socket::WakerRegistration;
|
|
|
|
use crate::wire::{IpProtocol, IpRepr, IpAddress, IpEndpoint, TcpSeqNumber, TcpRepr, TcpControl};
|
|
|
|
|
2017-12-22 21:13:43 +08:00
|
|
|
/// A TCP socket ring buffer.
|
2017-09-07 08:09:34 +08:00
|
|
|
pub type SocketBuffer<'a> = RingBuffer<'a, u8>;
|
2016-12-21 06:57:21 +08:00
|
|
|
|
2018-01-06 03:38:23 +08:00
|
|
|
/// The state of a TCP socket, according to [RFC 793].
|
|
|
|
///
|
|
|
|
/// [RFC 793]: https://tools.ietf.org/html/rfc793
|
2016-12-23 15:30:57 +08:00
|
|
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
|
|
pub enum State {
|
|
|
|
Closed,
|
|
|
|
Listen,
|
|
|
|
SynSent,
|
|
|
|
SynReceived,
|
|
|
|
Established,
|
|
|
|
FinWait1,
|
|
|
|
FinWait2,
|
|
|
|
CloseWait,
|
|
|
|
Closing,
|
|
|
|
LastAck,
|
|
|
|
TimeWait
|
2016-12-21 06:57:21 +08:00
|
|
|
}
|
|
|
|
|
2016-12-23 15:30:57 +08:00
|
|
|
impl fmt::Display for State {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2020-12-26 16:28:05 +08:00
|
|
|
match *self {
|
|
|
|
State::Closed => write!(f, "CLOSED"),
|
|
|
|
State::Listen => write!(f, "LISTEN"),
|
|
|
|
State::SynSent => write!(f, "SYN-SENT"),
|
|
|
|
State::SynReceived => write!(f, "SYN-RECEIVED"),
|
|
|
|
State::Established => write!(f, "ESTABLISHED"),
|
|
|
|
State::FinWait1 => write!(f, "FIN-WAIT-1"),
|
|
|
|
State::FinWait2 => write!(f, "FIN-WAIT-2"),
|
|
|
|
State::CloseWait => write!(f, "CLOSE-WAIT"),
|
|
|
|
State::Closing => write!(f, "CLOSING"),
|
|
|
|
State::LastAck => write!(f, "LAST-ACK"),
|
|
|
|
State::TimeWait => write!(f, "TIME-WAIT")
|
2016-12-21 06:57:21 +08:00
|
|
|
}
|
|
|
|
}
|
2016-12-23 15:30:57 +08:00
|
|
|
}
|
2016-12-21 06:57:21 +08:00
|
|
|
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
enum Timer {
|
2017-09-16 18:54:59 +08:00
|
|
|
Idle {
|
2018-02-11 00:32:41 +08:00
|
|
|
keep_alive_at: Option<Instant>,
|
2017-09-16 18:54:59 +08:00
|
|
|
},
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
Retransmit {
|
2018-02-11 00:32:41 +08:00
|
|
|
expires_at: Instant,
|
|
|
|
delay: Duration
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
},
|
2018-05-18 00:28:27 +08:00
|
|
|
FastRetransmit,
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
Close {
|
2018-02-11 00:32:41 +08:00
|
|
|
expires_at: Instant
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}
|
2016-12-21 06:57:21 +08:00
|
|
|
}
|
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
const RETRANSMIT_DELAY: Duration = Duration { millis: 100 };
|
|
|
|
const CLOSE_DELAY: Duration = Duration { millis: 10_000 };
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
|
2017-09-16 18:54:59 +08:00
|
|
|
impl Default for Timer {
|
|
|
|
fn default() -> Timer {
|
|
|
|
Timer::Idle { keep_alive_at: None }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
impl Timer {
|
2018-02-11 00:32:41 +08:00
|
|
|
fn should_keep_alive(&self, timestamp: Instant) -> bool {
|
2017-09-16 18:54:59 +08:00
|
|
|
match *self {
|
|
|
|
Timer::Idle { keep_alive_at: Some(keep_alive_at) }
|
|
|
|
if timestamp >= keep_alive_at => {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
fn should_retransmit(&self, timestamp: Instant) -> Option<Duration> {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
match *self {
|
|
|
|
Timer::Retransmit { expires_at, delay }
|
|
|
|
if timestamp >= expires_at => {
|
|
|
|
Some(timestamp - expires_at + delay)
|
2018-05-18 00:28:27 +08:00
|
|
|
},
|
|
|
|
Timer::FastRetransmit => Some(Duration::from_millis(0)),
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
_ => None
|
|
|
|
}
|
2016-12-23 15:30:57 +08:00
|
|
|
}
|
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
fn should_close(&self, timestamp: Instant) -> bool {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
match *self {
|
|
|
|
Timer::Close { expires_at }
|
|
|
|
if timestamp >= expires_at => {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
_ => false
|
2016-12-31 16:35:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-17 03:11:04 +08:00
|
|
|
fn poll_at(&self) -> PollAt {
|
2017-08-30 03:35:09 +08:00
|
|
|
match *self {
|
2018-05-17 03:11:04 +08:00
|
|
|
Timer::Idle { keep_alive_at: Some(keep_alive_at) } => PollAt::Time(keep_alive_at),
|
|
|
|
Timer::Idle { keep_alive_at: None } => PollAt::Ingress,
|
|
|
|
Timer::Retransmit { expires_at, .. } => PollAt::Time(expires_at),
|
2018-05-18 00:28:27 +08:00
|
|
|
Timer::FastRetransmit => PollAt::Now,
|
2018-05-17 03:11:04 +08:00
|
|
|
Timer::Close { expires_at } => PollAt::Time(expires_at),
|
2017-08-30 03:35:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
fn set_for_idle(&mut self, timestamp: Instant, interval: Option<Duration>) {
|
2017-09-16 18:54:59 +08:00
|
|
|
*self = Timer::Idle {
|
|
|
|
keep_alive_at: interval.map(|interval| timestamp + interval)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_keep_alive(&mut self) {
|
|
|
|
match *self {
|
|
|
|
Timer::Idle { ref mut keep_alive_at }
|
|
|
|
if keep_alive_at.is_none() => {
|
2018-02-11 00:32:41 +08:00
|
|
|
*keep_alive_at = Some(Instant::from_millis(0))
|
2017-09-16 18:54:59 +08:00
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
fn rewind_keep_alive(&mut self, timestamp: Instant, interval: Option<Duration>) {
|
2017-09-16 18:54:59 +08:00
|
|
|
match self {
|
|
|
|
&mut Timer::Idle { ref mut keep_alive_at } => {
|
|
|
|
*keep_alive_at = interval.map(|interval| timestamp + interval)
|
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}
|
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
fn set_for_retransmit(&mut self, timestamp: Instant) {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
match *self {
|
2018-06-12 14:19:04 +08:00
|
|
|
Timer::Idle { .. } | Timer::FastRetransmit { .. } => {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
*self = Timer::Retransmit {
|
|
|
|
expires_at: timestamp + RETRANSMIT_DELAY,
|
|
|
|
delay: RETRANSMIT_DELAY,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Timer::Retransmit { expires_at, delay }
|
|
|
|
if timestamp >= expires_at => {
|
|
|
|
*self = Timer::Retransmit {
|
|
|
|
expires_at: timestamp + delay,
|
|
|
|
delay: delay * 2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Timer::Retransmit { .. } => (),
|
|
|
|
Timer::Close { .. } => ()
|
2016-12-31 16:35:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-18 00:28:27 +08:00
|
|
|
fn set_for_fast_retransmit(&mut self) {
|
|
|
|
*self = Timer::FastRetransmit
|
|
|
|
}
|
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
fn set_for_close(&mut self, timestamp: Instant) {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
*self = Timer::Close {
|
|
|
|
expires_at: timestamp + CLOSE_DELAY
|
2016-12-31 16:35:07 +08:00
|
|
|
}
|
2016-12-21 06:57:21 +08:00
|
|
|
}
|
2017-10-28 16:32:08 +08:00
|
|
|
|
|
|
|
fn is_retransmit(&self) -> bool {
|
|
|
|
match *self {
|
2018-05-18 00:28:27 +08:00
|
|
|
Timer::Retransmit {..} | Timer::FastRetransmit => true,
|
2017-10-28 16:32:08 +08:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
2016-12-21 06:57:21 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 01:49:40 +08:00
|
|
|
/// A Transmission Control Protocol socket.
|
|
|
|
///
|
|
|
|
/// A TCP socket may passively listen for connections or actively connect to another endpoint.
|
|
|
|
/// Note that, for listening sockets, there is no "backlog"; to be able to simultaneously
|
|
|
|
/// accept several connections, as many sockets must be allocated, or any new connection
|
|
|
|
/// attempts will be reset.
|
2016-12-21 03:51:52 +08:00
|
|
|
#[derive(Debug)]
|
2016-12-23 15:30:57 +08:00
|
|
|
pub struct TcpSocket<'a> {
|
2017-11-22 11:50:09 +08:00
|
|
|
pub(crate) meta: SocketMeta,
|
2016-12-25 17:22:49 +08:00
|
|
|
state: State,
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
timer: Timer,
|
2017-09-22 17:51:04 +08:00
|
|
|
assembler: Assembler,
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
rx_buffer: SocketBuffer<'a>,
|
2020-06-12 04:12:38 +08:00
|
|
|
rx_fin_received: bool,
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
tx_buffer: SocketBuffer<'a>,
|
2017-09-18 19:05:40 +08:00
|
|
|
/// Interval after which, if no inbound packets are received, the connection is aborted.
|
2018-02-11 00:32:41 +08:00
|
|
|
timeout: Option<Duration>,
|
2017-09-16 18:54:59 +08:00
|
|
|
/// Interval at which keep-alive packets will be sent.
|
2018-02-11 00:32:41 +08:00
|
|
|
keep_alive: Option<Duration>,
|
2017-10-15 08:05:55 +08:00
|
|
|
/// The time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
|
2017-12-10 11:09:50 +08:00
|
|
|
hop_limit: Option<u8>,
|
2016-12-28 12:56:49 +08:00
|
|
|
/// 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.
|
2016-12-26 21:54:26 +08:00
|
|
|
listen_address: IpAddress,
|
2016-12-27 00:59:39 +08:00
|
|
|
/// Current local endpoint. This is used for both filtering the incoming packets and
|
|
|
|
/// setting the source address. When listening or initiating connection on/from
|
|
|
|
/// an unspecified address, this field is updated with the chosen source address before
|
|
|
|
/// any packets are sent.
|
2016-12-25 17:22:49 +08:00
|
|
|
local_endpoint: IpEndpoint,
|
2016-12-27 00:59:39 +08:00
|
|
|
/// Current remote endpoint. This is used for both filtering the incoming packets and
|
2016-12-28 12:56:49 +08:00
|
|
|
/// 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.
|
2016-12-25 17:22:49 +08:00
|
|
|
remote_endpoint: IpEndpoint,
|
2016-12-27 00:59:39 +08:00
|
|
|
/// 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.
|
2016-12-28 02:34:13 +08:00
|
|
|
local_seq_no: TcpSeqNumber,
|
2016-12-27 00:59:39 +08:00
|
|
|
/// The sequence number corresponding to the beginning of the receive buffer.
|
|
|
|
/// I.e. userspace reading n bytes adds n to remote_seq_no.
|
2016-12-28 02:34:13 +08:00
|
|
|
remote_seq_no: TcpSeqNumber,
|
2016-12-27 00:59:39 +08:00
|
|
|
/// The last sequence number sent.
|
|
|
|
/// I.e. in an idle socket, local_seq_no+tx_buffer.len().
|
2017-08-30 18:04:33 +08:00
|
|
|
remote_last_seq: TcpSeqNumber,
|
2016-12-27 00:59:39 +08:00
|
|
|
/// The last acknowledgement number sent.
|
|
|
|
/// I.e. in an idle socket, remote_seq_no+rx_buffer.len().
|
2017-08-31 06:40:07 +08:00
|
|
|
remote_last_ack: Option<TcpSeqNumber>,
|
2017-08-31 08:08:40 +08:00
|
|
|
/// The last window length sent.
|
|
|
|
remote_last_win: u16,
|
2018-08-20 04:32:27 +08:00
|
|
|
/// The sending window scaling factor advertised to remotes which support RFC 1323.
|
|
|
|
/// It is zero if the window <= 64KiB and/or the remote does not support it.
|
|
|
|
remote_win_shift: u8,
|
2020-12-18 23:06:23 +08:00
|
|
|
/// The remote window size, relative to local_seq_no
|
|
|
|
/// I.e. we're allowed to send octets until local_seq_no+remote_win_len
|
2016-12-25 19:09:50 +08:00
|
|
|
remote_win_len: usize,
|
2018-06-24 22:35:29 +08:00
|
|
|
/// The receive window scaling factor for remotes which support RFC 1323, None if unsupported.
|
|
|
|
remote_win_scale: Option<u8>,
|
2019-01-01 04:45:20 +08:00
|
|
|
/// Whether or not the remote supports selective ACK as described in RFC 2018.
|
|
|
|
remote_has_sack: bool,
|
2017-01-27 11:06:52 +08:00
|
|
|
/// The maximum number of data octets that the remote side may receive.
|
|
|
|
remote_mss: usize,
|
2017-09-18 19:05:40 +08:00
|
|
|
/// The timestamp of the last packet received.
|
2018-02-11 00:32:41 +08:00
|
|
|
remote_last_ts: Option<Instant>,
|
2019-01-01 04:45:20 +08:00
|
|
|
/// The sequence number of the last packet recived, used for sACK
|
|
|
|
local_rx_last_seq: Option<TcpSeqNumber>,
|
2018-06-09 07:11:10 +08:00
|
|
|
/// The ACK number of the last packet recived.
|
2018-05-18 00:28:27 +08:00
|
|
|
local_rx_last_ack: Option<TcpSeqNumber>,
|
2018-06-09 07:11:10 +08:00
|
|
|
/// The number of packets recived directly after
|
2018-05-18 00:28:27 +08:00
|
|
|
/// each other which have the same ACK number.
|
|
|
|
local_rx_dup_acks: u8,
|
2020-10-20 19:22:46 +08:00
|
|
|
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
rx_waker: WakerRegistration,
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
tx_waker: WakerRegistration,
|
|
|
|
|
2016-12-21 03:51:52 +08:00
|
|
|
}
|
|
|
|
|
2017-03-05 11:52:47 +08:00
|
|
|
const DEFAULT_MSS: usize = 536;
|
|
|
|
|
2016-12-23 15:30:57 +08:00
|
|
|
impl<'a> TcpSocket<'a> {
|
2018-08-20 04:32:27 +08:00
|
|
|
#[allow(unused_comparisons)] // small usize platforms always pass rx_capacity check
|
2016-12-23 15:30:57 +08:00
|
|
|
/// Create a socket using the given buffers.
|
2018-01-28 22:36:23 +08:00
|
|
|
pub fn new<T>(rx_buffer: T, tx_buffer: T) -> TcpSocket<'a>
|
2016-12-23 15:30:57 +08:00
|
|
|
where T: Into<SocketBuffer<'a>> {
|
2017-09-22 17:51:04 +08:00
|
|
|
let (rx_buffer, tx_buffer) = (rx_buffer.into(), tx_buffer.into());
|
2018-08-20 04:32:27 +08:00
|
|
|
let rx_capacity = rx_buffer.capacity();
|
|
|
|
|
|
|
|
// From RFC 1323:
|
|
|
|
// [...] the above constraints imply that 2 * the max window size must be less
|
|
|
|
// than 2**31 [...] Thus, the shift count must be limited to 14 (which allows
|
|
|
|
// windows of 2**30 = 1 Gbyte).
|
|
|
|
if rx_capacity > (1 << 30) {
|
|
|
|
panic!("receiving buffer too large, cannot exceed 1 GiB")
|
2016-12-23 15:30:57 +08:00
|
|
|
}
|
2018-08-20 04:32:27 +08:00
|
|
|
let rx_cap_log2 = mem::size_of::<usize>() * 8 -
|
|
|
|
rx_capacity.leading_zeros() as usize;
|
2016-12-23 15:30:57 +08:00
|
|
|
|
2018-01-28 22:36:23 +08:00
|
|
|
TcpSocket {
|
2017-11-22 11:50:09 +08:00
|
|
|
meta: SocketMeta::default(),
|
2016-12-25 17:22:49 +08:00
|
|
|
state: State::Closed,
|
2017-09-16 18:54:59 +08:00
|
|
|
timer: Timer::default(),
|
2017-09-22 17:51:04 +08:00
|
|
|
assembler: Assembler::new(rx_buffer.capacity()),
|
|
|
|
tx_buffer: tx_buffer,
|
|
|
|
rx_buffer: rx_buffer,
|
2020-06-12 04:12:38 +08:00
|
|
|
rx_fin_received: false,
|
2017-09-18 19:05:40 +08:00
|
|
|
timeout: None,
|
2017-09-16 18:54:59 +08:00
|
|
|
keep_alive: None,
|
2017-12-10 11:09:50 +08:00
|
|
|
hop_limit: None,
|
2016-12-26 21:54:26 +08:00
|
|
|
listen_address: IpAddress::default(),
|
2016-12-25 17:22:49 +08:00
|
|
|
local_endpoint: IpEndpoint::default(),
|
|
|
|
remote_endpoint: IpEndpoint::default(),
|
2017-08-23 06:32:05 +08:00
|
|
|
local_seq_no: TcpSeqNumber::default(),
|
|
|
|
remote_seq_no: TcpSeqNumber::default(),
|
2017-08-30 18:04:33 +08:00
|
|
|
remote_last_seq: TcpSeqNumber::default(),
|
2017-08-31 06:40:07 +08:00
|
|
|
remote_last_ack: None,
|
2017-08-31 08:08:40 +08:00
|
|
|
remote_last_win: 0,
|
2016-12-27 00:59:39 +08:00
|
|
|
remote_win_len: 0,
|
2018-08-20 04:32:27 +08:00
|
|
|
remote_win_shift: rx_cap_log2.saturating_sub(16) as u8,
|
2018-06-24 22:35:29 +08:00
|
|
|
remote_win_scale: None,
|
2019-01-01 04:45:20 +08:00
|
|
|
remote_has_sack: false,
|
2017-03-05 11:52:47 +08:00
|
|
|
remote_mss: DEFAULT_MSS,
|
2017-09-18 19:05:40 +08:00
|
|
|
remote_last_ts: None,
|
2018-05-18 00:28:27 +08:00
|
|
|
local_rx_last_ack: None,
|
2019-01-01 04:45:20 +08:00
|
|
|
local_rx_last_seq: None,
|
2018-05-18 00:28:27 +08:00
|
|
|
local_rx_dup_acks: 0,
|
2020-10-20 19:22:46 +08:00
|
|
|
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
rx_waker: WakerRegistration::new(),
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
tx_waker: WakerRegistration::new(),
|
2018-01-28 22:36:23 +08:00
|
|
|
}
|
2016-12-23 15:30:57 +08:00
|
|
|
}
|
|
|
|
|
2020-10-20 19:22:46 +08:00
|
|
|
/// Register a waker for receive operations.
|
|
|
|
///
|
|
|
|
/// The waker is woken on state changes that might affect the return value
|
|
|
|
/// of `recv` method calls, such as receiving data, or the socket closing.
|
|
|
|
///
|
|
|
|
/// Notes:
|
|
|
|
///
|
|
|
|
/// - Only one waker can be registered at a time. If another waker was previously registered,
|
|
|
|
/// it is overwritten and will no longer be woken.
|
|
|
|
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
|
|
|
|
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `recv` has
|
|
|
|
/// necessarily changed.
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
pub fn register_recv_waker(&mut self, waker: &Waker) {
|
|
|
|
self.rx_waker.register(waker)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Register a waker for send operations.
|
|
|
|
///
|
|
|
|
/// The waker is woken on state changes that might affect the return value
|
|
|
|
/// of `send` method calls, such as space becoming available in the transmit
|
|
|
|
/// buffer, or the socket closing.
|
|
|
|
///
|
|
|
|
/// Notes:
|
|
|
|
///
|
|
|
|
/// - Only one waker can be registered at a time. If another waker was previously registered,
|
|
|
|
/// it is overwritten and will no longer be woken.
|
|
|
|
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
|
|
|
|
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `send` has
|
|
|
|
/// necessarily changed.
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
pub fn register_send_waker(&mut self, waker: &Waker) {
|
|
|
|
self.tx_waker.register(waker)
|
|
|
|
}
|
|
|
|
|
2017-10-05 11:02:41 +08:00
|
|
|
/// Return the socket handle.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-10-05 11:02:41 +08:00
|
|
|
pub fn handle(&self) -> SocketHandle {
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle
|
2017-01-17 07:35:21 +08:00
|
|
|
}
|
|
|
|
|
2017-09-18 19:05:40 +08:00
|
|
|
/// Return the timeout duration.
|
|
|
|
///
|
|
|
|
/// See also the [set_timeout](#method.set_timeout) method.
|
2018-02-11 00:32:41 +08:00
|
|
|
pub fn timeout(&self) -> Option<Duration> {
|
2017-09-18 19:05:40 +08:00
|
|
|
self.timeout
|
|
|
|
}
|
|
|
|
|
2018-08-20 04:32:27 +08:00
|
|
|
/// Return the current window field value, including scaling according to RFC 1323.
|
|
|
|
///
|
|
|
|
/// Used in internal calculations as well as packet generation.
|
|
|
|
///
|
|
|
|
#[inline]
|
|
|
|
fn scaled_window(&self) -> u16 {
|
|
|
|
cmp::min(self.rx_buffer.window() >> self.remote_win_shift as usize,
|
|
|
|
(1 << 16) - 1) as u16
|
|
|
|
}
|
|
|
|
|
2017-09-18 19:05:40 +08:00
|
|
|
/// Set the timeout duration.
|
|
|
|
///
|
|
|
|
/// A socket with a timeout duration set will abort the connection if either of the following
|
|
|
|
/// occurs:
|
|
|
|
///
|
|
|
|
/// * After a [connect](#method.connect) call, the remote endpoint does not respond within
|
|
|
|
/// the specified duration;
|
|
|
|
/// * After establishing a connection, there is data in the transmit buffer and the remote
|
|
|
|
/// endpoint exceeds the specified duration between any two packets it sends;
|
|
|
|
/// * After enabling [keep-alive](#method.set_keep_alive), the remote endpoint exceeds
|
|
|
|
/// the specified duration between any two packets it sends.
|
2018-02-11 00:32:41 +08:00
|
|
|
pub fn set_timeout(&mut self, duration: Option<Duration>) {
|
2017-09-22 14:16:58 +08:00
|
|
|
self.timeout = duration
|
2017-09-18 19:05:40 +08:00
|
|
|
}
|
|
|
|
|
2017-09-16 18:54:59 +08:00
|
|
|
/// Return the keep-alive interval.
|
|
|
|
///
|
|
|
|
/// See also the [set_keep_alive](#method.set_keep_alive) method.
|
2018-02-11 00:32:41 +08:00
|
|
|
pub fn keep_alive(&self) -> Option<Duration> {
|
2017-09-16 18:54:59 +08:00
|
|
|
self.keep_alive
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the keep-alive interval.
|
|
|
|
///
|
2017-09-18 19:05:40 +08:00
|
|
|
/// An idle socket with a keep-alive interval set will transmit a "challenge ACK" packet
|
2017-09-16 18:54:59 +08:00
|
|
|
/// every time it receives no communication during that interval. As a result, three things
|
|
|
|
/// may happen:
|
|
|
|
///
|
|
|
|
/// * The remote endpoint is fine and answers with an ACK packet.
|
|
|
|
/// * The remote endpoint has rebooted and answers with an RST packet.
|
|
|
|
/// * The remote endpoint has crashed and does not answer.
|
|
|
|
///
|
|
|
|
/// The keep-alive functionality together with the timeout functionality allows to react
|
|
|
|
/// to these error conditions.
|
2018-02-11 00:32:41 +08:00
|
|
|
pub fn set_keep_alive(&mut self, interval: Option<Duration>) {
|
2017-09-16 18:54:59 +08:00
|
|
|
self.keep_alive = interval;
|
|
|
|
if self.keep_alive.is_some() {
|
|
|
|
// If the connection is idle and we've just set the option, it would not take effect
|
|
|
|
// until the next packet, unless we wind up the timer explicitly.
|
|
|
|
self.timer.set_keep_alive();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-15 08:05:55 +08:00
|
|
|
/// Return the time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
|
|
|
|
///
|
2017-12-10 11:09:50 +08:00
|
|
|
/// See also the [set_hop_limit](#method.set_hop_limit) method
|
|
|
|
pub fn hop_limit(&self) -> Option<u8> {
|
|
|
|
self.hop_limit
|
2017-10-15 08:05:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
|
|
|
|
///
|
2017-12-10 11:09:50 +08:00
|
|
|
/// A socket without an explicitly set hop limit value uses the default [IANA recommended]
|
2017-10-25 07:04:33 +08:00
|
|
|
/// value (64).
|
2017-10-15 08:05:55 +08:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
2017-12-10 11:09:50 +08:00
|
|
|
/// This function panics if a hop limit value of 0 is given. See [RFC 1122 § 3.2.1.7].
|
2017-10-15 08:05:55 +08:00
|
|
|
///
|
|
|
|
/// [IANA recommended]: https://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml
|
|
|
|
/// [RFC 1122 § 3.2.1.7]: https://tools.ietf.org/html/rfc1122#section-3.2.1.7
|
2017-12-10 11:09:50 +08:00
|
|
|
pub fn set_hop_limit(&mut self, hop_limit: Option<u8>) {
|
|
|
|
// A host MUST NOT send a datagram with a hop limit value of 0
|
|
|
|
if let Some(0) = hop_limit {
|
2017-10-25 07:04:33 +08:00
|
|
|
panic!("the time-to-live value of a packet must not be zero")
|
2017-10-15 08:05:55 +08:00
|
|
|
}
|
2017-10-25 07:04:33 +08:00
|
|
|
|
2017-12-10 11:09:50 +08:00
|
|
|
self.hop_limit = hop_limit
|
2017-10-15 08:05:55 +08:00
|
|
|
}
|
|
|
|
|
2016-12-21 03:51:52 +08:00
|
|
|
/// Return the local endpoint.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-23 15:30:57 +08:00
|
|
|
pub fn local_endpoint(&self) -> IpEndpoint {
|
2016-12-25 17:22:49 +08:00
|
|
|
self.local_endpoint
|
2016-12-21 03:51:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the remote endpoint.
|
2016-12-31 00:55:31 +08:00
|
|
|
#[inline]
|
2016-12-23 15:30:57 +08:00
|
|
|
pub fn remote_endpoint(&self) -> IpEndpoint {
|
2016-12-25 17:22:49 +08:00
|
|
|
self.remote_endpoint
|
2016-12-21 03:51:52 +08:00
|
|
|
}
|
2016-12-21 06:57:21 +08:00
|
|
|
|
2017-01-17 08:21:03 +08:00
|
|
|
/// Return the connection state, in terms of the TCP state machine.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-01-17 08:21:03 +08:00
|
|
|
pub fn state(&self) -> State {
|
|
|
|
self.state
|
|
|
|
}
|
|
|
|
|
2017-03-05 11:52:47 +08:00
|
|
|
fn reset(&mut self) {
|
2018-08-20 04:32:27 +08:00
|
|
|
let rx_cap_log2 = mem::size_of::<usize>() * 8 -
|
|
|
|
self.rx_buffer.capacity().leading_zeros() as usize;
|
|
|
|
|
2017-04-22 00:01:49 +08:00
|
|
|
self.state = State::Closed;
|
2017-09-16 18:54:59 +08:00
|
|
|
self.timer = Timer::default();
|
2017-09-22 17:51:04 +08:00
|
|
|
self.assembler = Assembler::new(self.rx_buffer.capacity());
|
|
|
|
self.tx_buffer.clear();
|
|
|
|
self.rx_buffer.clear();
|
2020-06-12 04:12:38 +08:00
|
|
|
self.rx_fin_received = false;
|
2017-09-16 18:54:59 +08:00
|
|
|
self.keep_alive = None;
|
2017-09-18 19:05:40 +08:00
|
|
|
self.timeout = None;
|
2017-12-10 11:09:50 +08:00
|
|
|
self.hop_limit = None;
|
2017-03-05 11:52:47 +08:00
|
|
|
self.listen_address = IpAddress::default();
|
|
|
|
self.local_endpoint = IpEndpoint::default();
|
|
|
|
self.remote_endpoint = IpEndpoint::default();
|
2017-08-23 06:32:05 +08:00
|
|
|
self.local_seq_no = TcpSeqNumber::default();
|
|
|
|
self.remote_seq_no = TcpSeqNumber::default();
|
2017-08-30 18:04:33 +08:00
|
|
|
self.remote_last_seq = TcpSeqNumber::default();
|
2017-08-31 06:40:07 +08:00
|
|
|
self.remote_last_ack = None;
|
2017-08-31 08:08:40 +08:00
|
|
|
self.remote_last_win = 0;
|
2017-03-05 11:52:47 +08:00
|
|
|
self.remote_win_len = 0;
|
2018-06-24 22:35:29 +08:00
|
|
|
self.remote_win_scale = None;
|
2018-08-20 04:32:27 +08:00
|
|
|
self.remote_win_shift = rx_cap_log2.saturating_sub(16) as u8;
|
2017-03-05 11:52:47 +08:00
|
|
|
self.remote_mss = DEFAULT_MSS;
|
2017-09-18 19:05:40 +08:00
|
|
|
self.remote_last_ts = None;
|
2020-10-20 19:22:46 +08:00
|
|
|
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
{
|
|
|
|
self.rx_waker.wake();
|
|
|
|
self.tx_waker.wake();
|
|
|
|
}
|
2017-03-05 11:52:47 +08:00
|
|
|
}
|
|
|
|
|
2016-12-23 15:30:57 +08:00
|
|
|
/// Start listening on the given endpoint.
|
|
|
|
///
|
2017-07-30 09:17:48 +08:00
|
|
|
/// This function returns `Err(Error::Illegal)` if the socket was already open
|
|
|
|
/// (see [is_open](#method.is_open)), and `Err(Error::Unaddressable)`
|
|
|
|
/// if the port in the given endpoint is zero.
|
2017-07-27 21:51:02 +08:00
|
|
|
pub fn listen<T>(&mut self, local_endpoint: T) -> Result<()>
|
2017-03-05 11:52:47 +08:00
|
|
|
where T: Into<IpEndpoint> {
|
|
|
|
let local_endpoint = local_endpoint.into();
|
2017-07-27 22:53:06 +08:00
|
|
|
if local_endpoint.port == 0 { return Err(Error::Unaddressable) }
|
2017-03-05 11:52:47 +08:00
|
|
|
|
2017-07-27 21:51:02 +08:00
|
|
|
if self.is_open() { return Err(Error::Illegal) }
|
2016-12-23 15:59:38 +08:00
|
|
|
|
2017-03-05 11:52:47 +08:00
|
|
|
self.reset();
|
|
|
|
self.listen_address = local_endpoint.addr;
|
|
|
|
self.local_endpoint = local_endpoint;
|
2016-12-25 17:22:49 +08:00
|
|
|
self.remote_endpoint = IpEndpoint::default();
|
2016-12-23 15:59:38 +08:00
|
|
|
self.set_state(State::Listen);
|
2016-12-28 01:49:40 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2017-03-05 11:52:47 +08:00
|
|
|
/// Connect to a given endpoint.
|
|
|
|
///
|
|
|
|
/// The local port must be provided explicitly. Assuming `fn get_ephemeral_port() -> u16`
|
2017-07-24 07:07:55 +08:00
|
|
|
/// allocates a port between 49152 and 65535, a connection may be established as follows:
|
2017-03-05 11:52:47 +08:00
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// socket.connect((IpAddress::v4(10, 0, 0, 1), 80), get_ephemeral_port())
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// The local address may optionally be provided.
|
|
|
|
///
|
|
|
|
/// This function returns an error if the socket was open; see [is_open](#method.is_open).
|
2017-07-27 19:26:39 +08:00
|
|
|
/// It also returns an error if the local or remote port is zero, or if the remote address
|
|
|
|
/// is unspecified.
|
2017-07-27 21:51:02 +08:00
|
|
|
pub fn connect<T, U>(&mut self, remote_endpoint: T, local_endpoint: U) -> Result<()>
|
2017-03-05 11:52:47 +08:00
|
|
|
where T: Into<IpEndpoint>, U: Into<IpEndpoint> {
|
|
|
|
let remote_endpoint = remote_endpoint.into();
|
|
|
|
let local_endpoint = local_endpoint.into();
|
|
|
|
|
2017-07-27 20:27:33 +08:00
|
|
|
if self.is_open() { return Err(Error::Illegal) }
|
|
|
|
if !remote_endpoint.is_specified() { return Err(Error::Unaddressable) }
|
|
|
|
if local_endpoint.port == 0 { return Err(Error::Unaddressable) }
|
2017-07-24 07:07:55 +08:00
|
|
|
|
|
|
|
// If local address is not provided, use an unspecified address but a specified protocol.
|
|
|
|
// This lets us lower IpRepr later to determine IP header size and calculate MSS,
|
|
|
|
// but without committing to a specific address right away.
|
2020-04-16 15:55:17 +08:00
|
|
|
let local_addr = match local_endpoint.addr {
|
|
|
|
IpAddress::Unspecified => remote_endpoint.addr.to_unspecified(),
|
|
|
|
ip => ip,
|
2017-07-24 07:07:55 +08:00
|
|
|
};
|
|
|
|
let local_endpoint = IpEndpoint { addr: local_addr, ..local_endpoint };
|
2017-03-05 11:52:47 +08:00
|
|
|
|
|
|
|
// Carry over the local sequence number.
|
|
|
|
let local_seq_no = self.local_seq_no;
|
|
|
|
|
|
|
|
self.reset();
|
|
|
|
self.local_endpoint = local_endpoint;
|
|
|
|
self.remote_endpoint = remote_endpoint;
|
|
|
|
self.local_seq_no = local_seq_no;
|
2017-08-30 18:04:33 +08:00
|
|
|
self.remote_last_seq = local_seq_no;
|
2017-03-05 11:52:47 +08:00
|
|
|
self.set_state(State::SynSent);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
/// Close the transmit half of the full-duplex connection.
|
|
|
|
///
|
|
|
|
/// Note that there is no corresponding function for the receive half of the full-duplex
|
|
|
|
/// connection; only the remote end can close it. If you no longer wish to receive any
|
|
|
|
/// data and would like to reuse the socket right away, use [abort](#method.abort).
|
|
|
|
pub fn close(&mut self) {
|
|
|
|
match self.state {
|
|
|
|
// In the LISTEN state there is no established connection.
|
|
|
|
State::Listen =>
|
|
|
|
self.set_state(State::Closed),
|
2016-12-28 07:28:57 +08:00
|
|
|
// In the SYN-SENT state the remote endpoint is not yet synchronized and, upon
|
2016-12-28 06:43:16 +08:00
|
|
|
// receiving an RST, will abort the connection.
|
|
|
|
State::SynSent =>
|
|
|
|
self.set_state(State::Closed),
|
2016-12-28 07:28:57 +08:00
|
|
|
// In the SYN-RECEIVED, ESTABLISHED and CLOSE-WAIT states the transmit half
|
2016-12-28 06:43:16 +08:00
|
|
|
// of the connection is open, and needs to be explicitly closed with a FIN.
|
2017-09-16 18:54:59 +08:00
|
|
|
State::SynReceived | State::Established =>
|
|
|
|
self.set_state(State::FinWait1),
|
|
|
|
State::CloseWait =>
|
|
|
|
self.set_state(State::LastAck),
|
2016-12-28 07:28:57 +08:00
|
|
|
// In the FIN-WAIT-1, FIN-WAIT-2, CLOSING, LAST-ACK, TIME-WAIT and CLOSED states,
|
2016-12-28 06:43:16 +08:00
|
|
|
// the transmit half of the connection is already closed, and no further
|
|
|
|
// action is needed.
|
|
|
|
State::FinWait1 | State::FinWait2 | State::Closing |
|
|
|
|
State::TimeWait | State::LastAck | State::Closed => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-17 09:24:51 +08:00
|
|
|
/// 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);
|
|
|
|
}
|
|
|
|
|
2017-01-15 19:00:04 +08:00
|
|
|
/// Return whether the socket is passively listening for incoming connections.
|
2017-01-17 08:21:03 +08:00
|
|
|
///
|
|
|
|
/// In terms of the TCP state machine, the socket must be in the `LISTEN` state.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-01-15 19:00:04 +08:00
|
|
|
pub fn is_listening(&self) -> bool {
|
|
|
|
match self.state {
|
|
|
|
State::Listen => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:54:45 +08:00
|
|
|
/// Return whether the socket is open.
|
2016-12-28 01:49:40 +08:00
|
|
|
///
|
|
|
|
/// This function returns true if the socket will process incoming or dispatch outgoing
|
|
|
|
/// packets. Note that this does not mean that it is possible to send or receive data through
|
|
|
|
/// the socket; for that, use [can_send](#method.can_send) or [can_recv](#method.can_recv).
|
2017-01-17 08:21:03 +08:00
|
|
|
///
|
2017-09-24 16:23:46 +08:00
|
|
|
/// In terms of the TCP state machine, the socket must not be in the `CLOSED`
|
|
|
|
/// or `TIME-WAIT` states.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2016-12-28 01:49:40 +08:00
|
|
|
pub fn is_open(&self) -> bool {
|
|
|
|
match self.state {
|
|
|
|
State::Closed => false,
|
|
|
|
State::TimeWait => false,
|
|
|
|
_ => true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-14 17:13:25 +08:00
|
|
|
/// Return whether a connection is active.
|
2016-12-28 02:54:45 +08:00
|
|
|
///
|
|
|
|
/// This function returns true if the socket is actively exchanging packets with
|
|
|
|
/// a remote endpoint. Note that this does not mean that it is possible to send or receive
|
|
|
|
/// data through the socket; for that, use [can_send](#method.can_send) or
|
|
|
|
/// [can_recv](#method.can_recv).
|
|
|
|
///
|
|
|
|
/// If a connection is established, [abort](#method.close) will send a reset to
|
|
|
|
/// the remote endpoint.
|
2017-01-17 08:21:03 +08:00
|
|
|
///
|
|
|
|
/// In terms of the TCP state machine, the socket must be in the `CLOSED`, `TIME-WAIT`,
|
|
|
|
/// or `LISTEN` state.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-01-14 17:13:25 +08:00
|
|
|
pub fn is_active(&self) -> bool {
|
2016-12-28 02:54:45 +08:00
|
|
|
match self.state {
|
|
|
|
State::Closed => false,
|
|
|
|
State::TimeWait => false,
|
|
|
|
State::Listen => false,
|
|
|
|
_ => true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-28 01:49:40 +08:00
|
|
|
/// Return whether the transmit half of the full-duplex connection is open.
|
|
|
|
///
|
|
|
|
/// This function returns true if it's possible to send data and have it arrive
|
|
|
|
/// to the remote endpoint. However, it does not make any guarantees about the state
|
|
|
|
/// of the transmit buffer, and even if it returns true, [send](#method.send) may
|
|
|
|
/// not be able to enqueue any octets.
|
2017-01-17 08:21:03 +08:00
|
|
|
///
|
|
|
|
/// In terms of the TCP state machine, the socket must be in the `ESTABLISHED` or
|
|
|
|
/// `CLOSE-WAIT` state.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-01-14 14:51:29 +08:00
|
|
|
pub fn may_send(&self) -> bool {
|
2016-12-28 01:49:40 +08:00
|
|
|
match self.state {
|
|
|
|
State::Established => true,
|
2016-12-28 07:28:57 +08:00
|
|
|
// In CLOSE-WAIT, the remote endpoint has closed our receive half of the connection
|
2016-12-28 01:49:40 +08:00
|
|
|
// but we still can transmit indefinitely.
|
|
|
|
State::CloseWait => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return whether the receive half of the full-duplex connection is open.
|
|
|
|
///
|
|
|
|
/// This function returns true if it's possible to receive data from the remote endpoint.
|
|
|
|
/// It will return true while there is data in the receive buffer, and if there isn't,
|
|
|
|
/// as long as the remote endpoint has not closed the connection.
|
2017-01-17 08:21:03 +08:00
|
|
|
///
|
|
|
|
/// In terms of the TCP state machine, the socket must be in the `ESTABLISHED`,
|
|
|
|
/// `FIN-WAIT-1`, or `FIN-WAIT-2` state, or have data in the receive buffer instead.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-01-14 14:51:29 +08:00
|
|
|
pub fn may_recv(&self) -> bool {
|
2016-12-28 01:49:40 +08:00
|
|
|
match self.state {
|
|
|
|
State::Established => true,
|
2016-12-28 07:28:57 +08:00
|
|
|
// In FIN-WAIT-1/2, we have closed our transmit half of the connection but
|
2016-12-28 01:49:40 +08:00
|
|
|
// we still can receive indefinitely.
|
|
|
|
State::FinWait1 | State::FinWait2 => true,
|
2016-12-28 04:17:46 +08:00
|
|
|
// If we have something in the receive buffer, we can receive that.
|
|
|
|
_ if self.rx_buffer.len() > 0 => true,
|
2016-12-28 01:49:40 +08:00
|
|
|
_ => false
|
|
|
|
}
|
2016-12-21 03:51:52 +08:00
|
|
|
}
|
|
|
|
|
2017-01-17 08:21:03 +08:00
|
|
|
/// Check whether the transmit half of the full-duplex connection is open
|
|
|
|
/// (see [may_send](#method.may_send), and the transmit buffer is not full.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-01-14 14:51:29 +08:00
|
|
|
pub fn can_send(&self) -> bool {
|
2017-01-14 14:55:29 +08:00
|
|
|
if !self.may_send() { return false }
|
|
|
|
|
2017-09-09 07:23:40 +08:00
|
|
|
!self.tx_buffer.is_full()
|
2017-01-14 14:51:29 +08:00
|
|
|
}
|
|
|
|
|
2019-11-06 07:07:12 +08:00
|
|
|
/// Return the maximum number of bytes inside the recv buffer.
|
|
|
|
#[inline]
|
|
|
|
pub fn recv_capacity(&self) -> usize {
|
|
|
|
self.rx_buffer.capacity()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the maximum number of bytes inside the transmit buffer.
|
|
|
|
#[inline]
|
|
|
|
pub fn send_capacity(&self) -> usize {
|
|
|
|
self.tx_buffer.capacity()
|
|
|
|
}
|
|
|
|
|
2017-01-17 08:21:03 +08:00
|
|
|
/// Check whether the receive half of the full-duplex connection buffer is open
|
|
|
|
/// (see [may_recv](#method.may_recv), and the receive buffer is not empty.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-01-14 14:51:29 +08:00
|
|
|
pub fn can_recv(&self) -> bool {
|
2017-01-14 14:55:29 +08:00
|
|
|
if !self.may_recv() { return false }
|
|
|
|
|
2017-09-09 07:23:40 +08:00
|
|
|
!self.rx_buffer.is_empty()
|
2017-01-14 14:51:29 +08:00
|
|
|
}
|
|
|
|
|
2017-11-01 03:24:54 +08:00
|
|
|
fn send_impl<'b, F, R>(&'b mut self, f: F) -> Result<R>
|
|
|
|
where F: FnOnce(&'b mut SocketBuffer<'a>) -> (usize, R) {
|
2017-07-27 21:51:02 +08:00
|
|
|
if !self.may_send() { return Err(Error::Illegal) }
|
2016-12-28 01:49:40 +08:00
|
|
|
|
2017-09-18 19:05:40 +08:00
|
|
|
// The connection might have been idle for a long time, and so remote_last_ts
|
|
|
|
// would be far in the past. Unless we clear it here, we'll abort the connection
|
|
|
|
// down over in dispatch() by erroneously detecting it as timed out.
|
|
|
|
if self.tx_buffer.is_empty() { self.remote_last_ts = None }
|
|
|
|
|
2017-09-08 05:17:31 +08:00
|
|
|
let _old_length = self.tx_buffer.len();
|
2017-11-01 03:24:54 +08:00
|
|
|
let (size, result) = f(&mut self.tx_buffer);
|
|
|
|
if size > 0 {
|
2017-01-19 20:23:32 +08:00
|
|
|
#[cfg(any(test, feature = "verbose"))]
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: tx buffer: enqueueing {} octets (now {})",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-11-01 03:24:54 +08:00
|
|
|
size, _old_length + size);
|
2016-12-26 22:50:12 +08:00
|
|
|
}
|
2017-11-01 03:24:54 +08:00
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Call `f` with the largest contiguous slice of octets in the transmit buffer,
|
|
|
|
/// and enqueue the amount of elements returned by `f`.
|
|
|
|
///
|
|
|
|
/// This function returns `Err(Error::Illegal) if the transmit half of
|
|
|
|
/// the connection is not open; see [may_send](#method.may_send).
|
|
|
|
pub fn send<'b, F, R>(&'b mut self, f: F) -> Result<R>
|
|
|
|
where F: FnOnce(&'b mut [u8]) -> (usize, R) {
|
|
|
|
self.send_impl(|tx_buffer| {
|
|
|
|
tx_buffer.enqueue_many_with(f)
|
|
|
|
})
|
2016-12-26 22:50:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Enqueue a sequence of octets to be sent, and fill it from a slice.
|
|
|
|
///
|
2019-06-22 15:45:56 +08:00
|
|
|
/// This function returns the amount of octets actually enqueued, which is limited
|
2016-12-26 22:50:12 +08:00
|
|
|
/// by the amount of free space in the transmit buffer; down to zero.
|
|
|
|
///
|
|
|
|
/// See also [send](#method.send).
|
2017-07-27 21:51:02 +08:00
|
|
|
pub fn send_slice(&mut self, data: &[u8]) -> Result<usize> {
|
2017-11-01 03:24:54 +08:00
|
|
|
self.send_impl(|tx_buffer| {
|
|
|
|
let size = tx_buffer.enqueue_slice(data);
|
|
|
|
(size, size)
|
|
|
|
})
|
2016-12-26 22:50:12 +08:00
|
|
|
}
|
|
|
|
|
2020-06-12 04:12:38 +08:00
|
|
|
fn recv_error_check(&mut self) -> Result<()> {
|
2017-01-27 06:04:05 +08:00
|
|
|
// We may have received some data inside the initial SYN, but until the connection
|
|
|
|
// is fully open we must not dequeue any data, as it may be overwritten by e.g.
|
2017-11-01 03:24:54 +08:00
|
|
|
// another (stale) SYN. (We do not support TCP Fast Open.)
|
2020-06-12 04:12:38 +08:00
|
|
|
if !self.may_recv() {
|
|
|
|
if self.rx_fin_received {
|
|
|
|
return Err(Error::Finished)
|
|
|
|
}
|
|
|
|
return Err(Error::Illegal)
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn recv_impl<'b, F, R>(&'b mut self, f: F) -> Result<R>
|
|
|
|
where F: FnOnce(&'b mut SocketBuffer<'a>) -> (usize, R) {
|
|
|
|
self.recv_error_check()?;
|
2016-12-28 01:49:40 +08:00
|
|
|
|
2017-09-23 01:38:58 +08:00
|
|
|
let _old_length = self.rx_buffer.len();
|
2017-11-01 03:24:54 +08:00
|
|
|
let (size, result) = f(&mut self.rx_buffer);
|
|
|
|
self.remote_seq_no += size;
|
|
|
|
if size > 0 {
|
2017-01-19 20:23:32 +08:00
|
|
|
#[cfg(any(test, feature = "verbose"))]
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: rx buffer: dequeueing {} octets (now {})",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-11-01 03:24:54 +08:00
|
|
|
size, _old_length - size);
|
2016-12-26 22:50:12 +08:00
|
|
|
}
|
2017-11-01 03:24:54 +08:00
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Call `f` with the largest contiguous slice of octets in the receive buffer,
|
|
|
|
/// and dequeue the amount of elements returned by `f`.
|
|
|
|
///
|
2020-06-12 04:24:13 +08:00
|
|
|
/// This function errors if the receive half of the connection is not open.
|
|
|
|
///
|
|
|
|
/// If the receive half has been gracefully closed (with a FIN packet), `Err(Error::Finished)`
|
|
|
|
/// is returned. In this case, the previously received data is guaranteed to be complete.
|
|
|
|
///
|
|
|
|
/// In all other cases, `Err(Error::Illegal)` is returned and previously received data (if any)
|
|
|
|
/// may be incomplete (truncated).
|
2017-11-01 03:24:54 +08:00
|
|
|
pub fn recv<'b, F, R>(&'b mut self, f: F) -> Result<R>
|
|
|
|
where F: FnOnce(&'b mut [u8]) -> (usize, R) {
|
|
|
|
self.recv_impl(|rx_buffer| {
|
|
|
|
rx_buffer.dequeue_many_with(f)
|
|
|
|
})
|
2016-12-26 22:50:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Dequeue a sequence of received octets, and fill a slice from it.
|
|
|
|
///
|
2019-06-22 15:45:56 +08:00
|
|
|
/// This function returns the amount of octets actually dequeued, which is limited
|
|
|
|
/// by the amount of occupied space in the receive buffer; down to zero.
|
2016-12-26 22:50:12 +08:00
|
|
|
///
|
|
|
|
/// See also [recv](#method.recv).
|
2017-07-27 21:51:02 +08:00
|
|
|
pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<usize> {
|
2017-11-01 03:24:54 +08:00
|
|
|
self.recv_impl(|rx_buffer| {
|
|
|
|
let size = rx_buffer.dequeue_slice(data);
|
|
|
|
(size, size)
|
|
|
|
})
|
2016-12-28 01:49:40 +08:00
|
|
|
}
|
|
|
|
|
2017-08-21 14:12:09 +08:00
|
|
|
/// Peek at a sequence of received octets without removing them from
|
|
|
|
/// the receive buffer, and return a pointer to it.
|
|
|
|
///
|
|
|
|
/// This function otherwise behaves identically to [recv](#method.recv).
|
|
|
|
pub fn peek(&mut self, size: usize) -> Result<&[u8]> {
|
2020-06-12 04:12:38 +08:00
|
|
|
self.recv_error_check()?;
|
2017-08-21 14:12:09 +08:00
|
|
|
|
2017-09-08 07:47:42 +08:00
|
|
|
let buffer = self.rx_buffer.get_allocated(0, size);
|
2017-08-21 14:12:09 +08:00
|
|
|
if buffer.len() > 0 {
|
|
|
|
#[cfg(any(test, feature = "verbose"))]
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: rx buffer: peeking at {} octets",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-08-21 14:12:09 +08:00
|
|
|
buffer.len());
|
|
|
|
}
|
|
|
|
Ok(buffer)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Peek at a sequence of received octets without removing them from
|
|
|
|
/// the receive buffer, and fill a slice from it.
|
|
|
|
///
|
|
|
|
/// This function otherwise behaves identically to [recv_slice](#method.recv_slice).
|
|
|
|
pub fn peek_slice(&mut self, data: &mut [u8]) -> Result<usize> {
|
|
|
|
let buffer = self.peek(data.len())?;
|
|
|
|
let data = &mut data[..buffer.len()];
|
|
|
|
data.copy_from_slice(buffer);
|
|
|
|
Ok(buffer.len())
|
|
|
|
}
|
|
|
|
|
2017-08-31 21:22:20 +08:00
|
|
|
/// Return the amount of octets queued in the transmit buffer.
|
|
|
|
///
|
|
|
|
/// Note that the Berkeley sockets interface does not have an equivalent of this API.
|
|
|
|
pub fn send_queue(&self) -> usize {
|
|
|
|
self.tx_buffer.len()
|
|
|
|
}
|
|
|
|
|
2019-06-22 15:03:15 +08:00
|
|
|
/// Return the amount of octets queued in the receive buffer. This value can be larger than
|
|
|
|
/// the slice read by the next `recv` or `peek` call because it includes all queued octets,
|
|
|
|
/// and not only the octets that may be returned as a contiguous slice.
|
2017-08-31 21:22:20 +08:00
|
|
|
///
|
|
|
|
/// Note that the Berkeley sockets interface does not have an equivalent of this API.
|
|
|
|
pub fn recv_queue(&self) -> usize {
|
|
|
|
self.rx_buffer.len()
|
|
|
|
}
|
|
|
|
|
2016-12-28 01:49:40 +08:00
|
|
|
fn set_state(&mut self, state: State) {
|
|
|
|
if self.state != state {
|
|
|
|
if self.remote_endpoint.addr.is_unspecified() {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}: state={}=>{}",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint,
|
2017-01-17 07:35:21 +08:00
|
|
|
self.state, state);
|
2016-12-28 01:49:40 +08:00
|
|
|
} else {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: state={}=>{}",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-01-17 07:35:21 +08:00
|
|
|
self.state, state);
|
2016-12-28 01:49:40 +08:00
|
|
|
}
|
|
|
|
}
|
2020-10-20 19:22:46 +08:00
|
|
|
|
|
|
|
self.state = state;
|
|
|
|
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
{
|
|
|
|
// Wake all tasks waiting. Even if we haven't received/sent data, this
|
|
|
|
// is needed because return values of functions may change depending on the state.
|
|
|
|
// For example, a pending read has to fail with an error if the socket is closed.
|
|
|
|
self.rx_waker.wake();
|
|
|
|
self.tx_waker.wake();
|
|
|
|
}
|
2016-12-26 22:50:12 +08:00
|
|
|
}
|
|
|
|
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
pub(crate) fn reply(ip_repr: &IpRepr, repr: &TcpRepr) -> (IpRepr, TcpRepr<'static>) {
|
|
|
|
let reply_repr = TcpRepr {
|
|
|
|
src_port: repr.dst_port,
|
|
|
|
dst_port: repr.src_port,
|
2017-08-23 06:32:05 +08:00
|
|
|
control: TcpControl::None,
|
|
|
|
seq_number: TcpSeqNumber(0),
|
|
|
|
ack_number: None,
|
|
|
|
window_len: 0,
|
2018-06-24 22:35:29 +08:00
|
|
|
window_scale: None,
|
2017-08-23 06:32:05 +08:00
|
|
|
max_seg_size: None,
|
2019-01-01 04:45:20 +08:00
|
|
|
sack_permitted: false,
|
|
|
|
sack_ranges: [None, None, None],
|
2017-08-23 06:32:05 +08:00
|
|
|
payload: &[]
|
|
|
|
};
|
|
|
|
let ip_reply_repr = IpRepr::Unspecified {
|
|
|
|
src_addr: ip_repr.dst_addr(),
|
|
|
|
dst_addr: ip_repr.src_addr(),
|
|
|
|
protocol: IpProtocol::Tcp,
|
2017-10-15 08:05:55 +08:00
|
|
|
payload_len: reply_repr.buffer_len(),
|
2017-12-10 11:09:50 +08:00
|
|
|
hop_limit: 64
|
2017-08-23 06:32:05 +08:00
|
|
|
};
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
(ip_reply_repr, reply_repr)
|
2017-08-23 06:32:05 +08:00
|
|
|
}
|
|
|
|
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
pub(crate) fn rst_reply(ip_repr: &IpRepr, repr: &TcpRepr) -> (IpRepr, TcpRepr<'static>) {
|
|
|
|
debug_assert!(repr.control != TcpControl::Rst);
|
2017-08-23 06:32:05 +08:00
|
|
|
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
let (ip_reply_repr, mut reply_repr) = Self::reply(ip_repr, repr);
|
2017-08-23 06:32:05 +08:00
|
|
|
|
|
|
|
// See https://www.snellman.net/blog/archive/2016-02-01-tcp-rst/ for explanation
|
|
|
|
// of why we sometimes send an RST and sometimes an RST|ACK
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
reply_repr.control = TcpControl::Rst;
|
|
|
|
reply_repr.seq_number = repr.ack_number.unwrap_or_default();
|
|
|
|
if repr.control == TcpControl::Syn {
|
2017-08-28 14:01:13 +08:00
|
|
|
reply_repr.ack_number = Some(repr.seq_number + repr.segment_len());
|
2017-08-23 06:32:05 +08:00
|
|
|
}
|
|
|
|
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
(ip_reply_repr, reply_repr)
|
|
|
|
}
|
|
|
|
|
2018-05-08 01:07:57 +08:00
|
|
|
fn ack_reply(&mut self, ip_repr: &IpRepr, repr: &TcpRepr) -> (IpRepr, TcpRepr<'static>) {
|
2019-01-01 04:45:20 +08:00
|
|
|
let (mut ip_reply_repr, mut reply_repr) = Self::reply(ip_repr, repr);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
|
2017-09-22 18:14:26 +08:00
|
|
|
// From RFC 793:
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
// [...] an empty acknowledgment segment containing the current send-sequence number
|
|
|
|
// and an acknowledgment indicating the next sequence number expected
|
|
|
|
// to be received.
|
2017-08-30 18:04:33 +08:00
|
|
|
reply_repr.seq_number = self.remote_last_seq;
|
2020-06-12 06:29:04 +08:00
|
|
|
reply_repr.ack_number = Some(self.remote_seq_no + self.rx_buffer.len());
|
|
|
|
self.remote_last_ack = reply_repr.ack_number;
|
2018-08-20 04:32:27 +08:00
|
|
|
|
|
|
|
// From RFC 1323:
|
|
|
|
// The window field [...] of every outgoing segment, with the exception of SYN
|
|
|
|
// segments, is right-shifted by [advertised scale value] bits[...]
|
|
|
|
reply_repr.window_len = self.scaled_window();
|
2018-05-08 01:07:57 +08:00
|
|
|
self.remote_last_win = reply_repr.window_len;
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
|
2019-01-01 04:45:20 +08:00
|
|
|
// If the remote supports selective acknowledgement, add the option to the outgoing
|
|
|
|
// segment.
|
|
|
|
if self.remote_has_sack {
|
|
|
|
net_debug!("sending sACK option with current assembler ranges");
|
|
|
|
|
|
|
|
// RFC 2018: The first SACK block (i.e., the one immediately following the kind and
|
|
|
|
// length fields in the option) MUST specify the contiguous block of data containing
|
|
|
|
// the segment which triggered this ACK, unless that segment advanced the
|
|
|
|
// Acknowledgment Number field in the header.
|
|
|
|
reply_repr.sack_ranges[0] = None;
|
|
|
|
|
|
|
|
if let Some(last_seg_seq) = self.local_rx_last_seq.map(|s| s.0 as u32) {
|
|
|
|
reply_repr.sack_ranges[0] = self.assembler.iter_data(
|
|
|
|
reply_repr.ack_number.map(|s| s.0 as usize).unwrap_or(0))
|
|
|
|
.map(|(left, right)| (left as u32, right as u32))
|
|
|
|
.skip_while(|(left, right)| *left > last_seg_seq || *right < last_seg_seq)
|
|
|
|
.next();
|
|
|
|
}
|
|
|
|
|
|
|
|
if reply_repr.sack_ranges[0].is_none() {
|
|
|
|
// The matching segment was removed from the assembler, meaning the acknowledgement
|
|
|
|
// number has advanced, or there was no previous sACK.
|
|
|
|
//
|
|
|
|
// While the RFC says we SHOULD keep a list of reported sACK ranges, and iterate
|
|
|
|
// through those, that is currently infeasable. Instead, we offer the range with
|
|
|
|
// the lowest sequence number (if one exists) to hint at what segments would
|
|
|
|
// most quickly advance the acknowledgement number.
|
|
|
|
reply_repr.sack_ranges[0] = self.assembler.iter_data(
|
|
|
|
reply_repr.ack_number.map(|s| s.0 as usize).unwrap_or(0))
|
|
|
|
.map(|(left, right)| (left as u32, right as u32))
|
|
|
|
.next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Since the sACK option may have changed the length of the payload, update that.
|
|
|
|
ip_reply_repr.set_payload_len(reply_repr.buffer_len());
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
(ip_reply_repr, reply_repr)
|
2017-08-23 06:32:05 +08:00
|
|
|
}
|
|
|
|
|
2017-09-01 05:44:41 +08:00
|
|
|
pub(crate) fn accepts(&self, ip_repr: &IpRepr, repr: &TcpRepr) -> bool {
|
|
|
|
if self.state == State::Closed { return false }
|
2016-12-21 03:51:52 +08:00
|
|
|
|
2017-08-21 15:28:07 +08:00
|
|
|
// If we're still listening for SYNs and the packet has an ACK, it cannot
|
|
|
|
// be destined to this socket, but another one may well listen on the same
|
|
|
|
// local endpoint.
|
2017-09-01 05:44:41 +08:00
|
|
|
if self.state == State::Listen && repr.ack_number.is_some() { return false }
|
2017-08-21 15:28:07 +08:00
|
|
|
|
2016-12-25 17:22:49 +08:00
|
|
|
// Reject packets with a wrong destination.
|
2017-09-01 05:44:41 +08:00
|
|
|
if self.local_endpoint.port != repr.dst_port { return false }
|
2016-12-25 17:22:49 +08:00
|
|
|
if !self.local_endpoint.addr.is_unspecified() &&
|
2017-09-01 05:44:41 +08:00
|
|
|
self.local_endpoint.addr != ip_repr.dst_addr() { return false }
|
2016-12-23 15:30:57 +08:00
|
|
|
|
2016-12-25 17:22:49 +08:00
|
|
|
// Reject packets from a source to which we aren't connected.
|
|
|
|
if self.remote_endpoint.port != 0 &&
|
2017-09-01 05:44:41 +08:00
|
|
|
self.remote_endpoint.port != repr.src_port { return false }
|
2016-12-25 17:22:49 +08:00
|
|
|
if !self.remote_endpoint.addr.is_unspecified() &&
|
2017-09-01 05:44:41 +08:00
|
|
|
self.remote_endpoint.addr != ip_repr.src_addr() { return false }
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
pub(crate) fn process(&mut self, timestamp: Instant, ip_repr: &IpRepr, repr: &TcpRepr) ->
|
2017-09-01 05:44:41 +08:00
|
|
|
Result<Option<(IpRepr, TcpRepr<'static>)>> {
|
|
|
|
debug_assert!(self.accepts(ip_repr, repr));
|
2016-12-23 15:30:57 +08:00
|
|
|
|
2017-01-24 05:02:28 +08:00
|
|
|
// Consider how much the sequence number space differs from the transmit buffer space.
|
|
|
|
let (sent_syn, sent_fin) = match self.state {
|
|
|
|
// In SYN-SENT or SYN-RECEIVED, we've just sent a SYN.
|
|
|
|
State::SynSent | State::SynReceived => (true, false),
|
|
|
|
// In FIN-WAIT-1, LAST-ACK, or CLOSING, we've just sent a FIN.
|
|
|
|
State::FinWait1 | State::LastAck | State::Closing => (false, true),
|
|
|
|
// In all other states we've already got acknowledgemetns for
|
|
|
|
// all of the control flags we sent.
|
|
|
|
_ => (false, false)
|
|
|
|
};
|
|
|
|
let control_len = (sent_syn as usize) + (sent_fin as usize);
|
|
|
|
|
2016-12-25 19:09:50 +08:00
|
|
|
// Reject unacceptable acknowledgements.
|
2016-12-23 15:30:57 +08:00
|
|
|
match (self.state, repr) {
|
2016-12-28 04:08:50 +08:00
|
|
|
// An RST received in response to initial SYN is acceptable if it acknowledges
|
2016-12-26 21:10:39 +08:00
|
|
|
// the initial SYN.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::SynSent, &TcpRepr {
|
2017-08-21 15:28:07 +08:00
|
|
|
control: TcpControl::Rst, ack_number: None, ..
|
|
|
|
}) => {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_debug!("{}:{}:{}: unacceptable RST (expecting RST|ACK) \
|
2016-12-26 21:10:39 +08:00
|
|
|
in response to initial SYN",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-08-25 11:52:30 +08:00
|
|
|
return Err(Error::Dropped)
|
2016-12-26 21:10:39 +08:00
|
|
|
}
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::SynSent, &TcpRepr {
|
2016-12-26 21:10:39 +08:00
|
|
|
control: TcpControl::Rst, ack_number: Some(ack_number), ..
|
|
|
|
}) => {
|
2017-03-05 13:31:12 +08:00
|
|
|
if ack_number != self.local_seq_no + 1 {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_debug!("{}:{}:{}: unacceptable RST|ACK in response to initial SYN",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-08-25 11:52:30 +08:00
|
|
|
return Err(Error::Dropped)
|
2016-12-26 21:10:39 +08:00
|
|
|
}
|
|
|
|
}
|
2016-12-28 04:17:35 +08:00
|
|
|
// Any other RST need only have a valid sequence number.
|
2017-08-28 12:50:57 +08:00
|
|
|
(_, &TcpRepr { control: TcpControl::Rst, .. }) => (),
|
2017-08-21 15:28:07 +08:00
|
|
|
// The initial SYN cannot contain an acknowledgement.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::Listen, &TcpRepr { ack_number: None, .. }) => (),
|
2017-08-21 15:28:07 +08:00
|
|
|
// This case is handled above.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::Listen, &TcpRepr { ack_number: Some(_), .. }) => unreachable!(),
|
2016-12-25 17:22:49 +08:00
|
|
|
// Every packet after the initial SYN must be an acknowledgement.
|
2017-08-28 12:50:57 +08:00
|
|
|
(_, &TcpRepr { ack_number: None, .. }) => {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_debug!("{}:{}:{}: expecting an ACK",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-08-25 11:52:30 +08:00
|
|
|
return Err(Error::Dropped)
|
2016-12-25 17:22:49 +08:00
|
|
|
}
|
2020-08-17 13:44:58 +08:00
|
|
|
// Any ACK in the SYN-SENT state must have the SYN flag set.
|
|
|
|
(State::SynSent, &TcpRepr {
|
|
|
|
control: TcpControl::None, ack_number: Some(_), ..
|
|
|
|
}) => {
|
|
|
|
net_debug!("{}:{}:{}: expecting a SYN|ACK",
|
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
|
|
|
self.abort();
|
|
|
|
return Err(Error::Dropped)
|
|
|
|
}
|
2016-12-25 19:09:50 +08:00
|
|
|
// Every acknowledgement must be for transmitted but unacknowledged data.
|
2017-08-28 12:50:57 +08:00
|
|
|
(_, &TcpRepr { ack_number: Some(ack_number), .. }) => {
|
2016-12-28 02:34:13 +08:00
|
|
|
let unacknowledged = self.tx_buffer.len() + control_len;
|
2017-06-26 16:09:27 +08:00
|
|
|
if ack_number < self.local_seq_no {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_debug!("{}:{}:{}: duplicate ACK ({} not in {}...{})",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-06-26 16:09:27 +08:00
|
|
|
ack_number, self.local_seq_no, self.local_seq_no + unacknowledged);
|
|
|
|
return Err(Error::Dropped)
|
|
|
|
}
|
2017-09-08 08:06:31 +08:00
|
|
|
|
2017-06-26 16:09:27 +08:00
|
|
|
if ack_number > self.local_seq_no + unacknowledged {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_debug!("{}:{}:{}: unacceptable ACK ({} not in {}...{})",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2016-12-25 17:22:49 +08:00
|
|
|
ack_number, self.local_seq_no, self.local_seq_no + unacknowledged);
|
2017-09-08 08:06:31 +08:00
|
|
|
return Ok(Some(self.ack_reply(ip_repr, &repr)))
|
2016-12-25 17:22:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-23 15:30:57 +08:00
|
|
|
|
2018-01-06 04:54:06 +08:00
|
|
|
let window_start = self.remote_seq_no + self.rx_buffer.len();
|
|
|
|
let window_end = self.remote_seq_no + self.rx_buffer.capacity();
|
|
|
|
let segment_start = repr.seq_number;
|
|
|
|
let segment_end = repr.seq_number + repr.segment_len();
|
|
|
|
|
2017-09-22 17:51:04 +08:00
|
|
|
let payload_offset;
|
2017-08-31 05:10:23 +08:00
|
|
|
match self.state {
|
2016-12-28 07:28:57 +08:00
|
|
|
// In LISTEN and SYN-SENT states, we have not yet synchronized with the remote end.
|
2017-09-22 17:51:04 +08:00
|
|
|
State::Listen | State::SynSent =>
|
|
|
|
payload_offset = 0,
|
2016-12-26 21:54:26 +08:00
|
|
|
// In all other states, segments must occupy a valid portion of the receive window.
|
2017-08-31 05:10:23 +08:00
|
|
|
_ => {
|
2017-09-22 17:51:04 +08:00
|
|
|
let mut segment_in_window = true;
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
|
2017-09-06 07:23:50 +08:00
|
|
|
if window_start == window_end && segment_start != segment_end {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_debug!("{}:{}:{}: non-zero-length segment with zero receive window, \
|
2017-09-06 07:23:50 +08:00
|
|
|
will only send an ACK",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-09-22 17:51:04 +08:00
|
|
|
segment_in_window = false;
|
2017-09-06 07:23:50 +08:00
|
|
|
}
|
|
|
|
|
2017-12-21 18:39:54 +08:00
|
|
|
if segment_start == segment_end && segment_end == window_start - 1 {
|
|
|
|
net_debug!("{}:{}:{}: received a keep-alive or window probe packet, \
|
|
|
|
will send an ACK",
|
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
|
|
|
segment_in_window = false;
|
|
|
|
} else if !((window_start <= segment_start && segment_start <= window_end) &&
|
|
|
|
(window_start <= segment_end && segment_end <= window_end)) {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_debug!("{}:{}:{}: segment not in receive window \
|
2017-08-31 05:10:23 +08:00
|
|
|
({}..{} not intersecting {}..{}), will send challenge ACK",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-08-31 05:10:23 +08:00
|
|
|
segment_start, segment_end, window_start, window_end);
|
2017-09-22 17:51:04 +08:00
|
|
|
segment_in_window = false;
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}
|
|
|
|
|
2017-09-22 17:51:04 +08:00
|
|
|
if segment_in_window {
|
|
|
|
// We've checked that segment_start >= window_start above.
|
|
|
|
payload_offset = (segment_start - window_start) as usize;
|
2019-01-01 04:45:20 +08:00
|
|
|
self.local_rx_last_seq = Some(repr.seq_number);
|
2017-09-22 17:51:04 +08:00
|
|
|
} else {
|
2017-06-26 16:09:27 +08:00
|
|
|
// If we're in the TIME-WAIT state, restart the TIME-WAIT timeout, since
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
// the remote end may not have realized we've closed the connection.
|
2017-04-22 00:01:49 +08:00
|
|
|
if self.state == State::TimeWait {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
self.timer.set_for_close(timestamp);
|
2017-04-22 00:01:49 +08:00
|
|
|
}
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
|
|
|
|
return Ok(Some(self.ack_reply(ip_repr, &repr)))
|
2016-12-26 21:54:26 +08:00
|
|
|
}
|
2016-12-25 19:09:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-07 18:17:30 +08:00
|
|
|
// Compute the amount of acknowledged octets, removing the SYN and FIN bits
|
|
|
|
// from the sequence space.
|
|
|
|
let mut ack_len = 0;
|
|
|
|
let mut ack_of_fin = false;
|
|
|
|
if repr.control != TcpControl::Rst {
|
|
|
|
if let Some(ack_number) = repr.ack_number {
|
|
|
|
ack_len = ack_number - self.local_seq_no;
|
|
|
|
// There could have been no data sent before the SYN, so we always remove it
|
|
|
|
// from the sequence space.
|
|
|
|
if sent_syn {
|
|
|
|
ack_len -= 1
|
|
|
|
}
|
|
|
|
// We could've sent data before the FIN, so only remove FIN from the sequence
|
|
|
|
// space if all of that data is acknowledged.
|
|
|
|
if sent_fin && self.tx_buffer.len() + 1 == ack_len {
|
|
|
|
ack_len -= 1;
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: received ACK of FIN",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-03-07 18:17:30 +08:00
|
|
|
ack_of_fin = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-06 04:54:06 +08:00
|
|
|
// Disregard control flags we don't care about or shouldn't act on yet.
|
|
|
|
let mut control = repr.control;
|
|
|
|
control = control.quash_psh();
|
|
|
|
|
|
|
|
// If a FIN is received at the end of the current segment but the start of the segment
|
|
|
|
// is not at the start of the receive window, disregard this FIN.
|
|
|
|
if control == TcpControl::Fin && window_start != segment_start {
|
|
|
|
control = TcpControl::None;
|
|
|
|
}
|
|
|
|
|
2016-12-25 19:09:50 +08:00
|
|
|
// Validate and update the state.
|
2018-01-06 04:54:06 +08:00
|
|
|
match (self.state, control) {
|
2017-08-01 19:15:12 +08:00
|
|
|
// RSTs are not accepted in the LISTEN state.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::Listen, TcpControl::Rst) =>
|
2017-08-01 19:15:12 +08:00
|
|
|
return Err(Error::Dropped),
|
2016-12-26 21:54:26 +08:00
|
|
|
|
2016-12-28 07:28:57 +08:00
|
|
|
// RSTs in SYN-RECEIVED flip the socket back to the LISTEN state.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::SynReceived, TcpControl::Rst) => {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: received RST",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2016-12-26 21:54:26 +08:00
|
|
|
self.local_endpoint.addr = self.listen_address;
|
|
|
|
self.remote_endpoint = IpEndpoint::default();
|
|
|
|
self.set_state(State::Listen);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
return Ok(None)
|
2016-12-26 21:54:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// RSTs in any other state close the socket.
|
2017-08-28 12:50:57 +08:00
|
|
|
(_, TcpControl::Rst) => {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: received RST",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-01-17 00:34:24 +08:00
|
|
|
self.set_state(State::Closed);
|
2016-12-26 21:54:26 +08:00
|
|
|
self.local_endpoint = IpEndpoint::default();
|
|
|
|
self.remote_endpoint = IpEndpoint::default();
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
return Ok(None)
|
2016-12-26 21:54:26 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 07:28:57 +08:00
|
|
|
// SYN packets in the LISTEN state change it to SYN-RECEIVED.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::Listen, TcpControl::Syn) => {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}: received SYN",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint);
|
2017-08-28 12:50:57 +08:00
|
|
|
self.local_endpoint = IpEndpoint::new(ip_repr.dst_addr(), repr.dst_port);
|
|
|
|
self.remote_endpoint = IpEndpoint::new(ip_repr.src_addr(), repr.src_port);
|
2016-12-28 02:34:13 +08:00
|
|
|
// FIXME: use something more secure here
|
2017-08-28 12:50:57 +08:00
|
|
|
self.local_seq_no = TcpSeqNumber(-repr.seq_number.0);
|
|
|
|
self.remote_seq_no = repr.seq_number + 1;
|
2017-08-30 18:04:33 +08:00
|
|
|
self.remote_last_seq = self.local_seq_no;
|
2019-01-01 04:45:20 +08:00
|
|
|
self.remote_has_sack = repr.sack_permitted;
|
2017-08-28 12:50:57 +08:00
|
|
|
if let Some(max_seg_size) = repr.max_seg_size {
|
2017-01-27 11:06:52 +08:00
|
|
|
self.remote_mss = max_seg_size as usize
|
|
|
|
}
|
2018-06-24 22:35:29 +08:00
|
|
|
self.remote_win_scale = repr.window_scale;
|
2018-08-20 04:32:27 +08:00
|
|
|
// No window scaling means don't do any window shifting
|
|
|
|
if self.remote_win_scale.is_none() {
|
|
|
|
self.remote_win_shift = 0;
|
|
|
|
}
|
2016-12-23 15:59:38 +08:00
|
|
|
self.set_state(State::SynReceived);
|
2017-09-16 18:54:59 +08:00
|
|
|
self.timer.set_for_idle(timestamp, self.keep_alive);
|
2016-12-23 15:30:57 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 07:28:57 +08:00
|
|
|
// ACK packets in the SYN-RECEIVED state change it to ESTABLISHED.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::SynReceived, TcpControl::None) => {
|
2016-12-23 16:05:50 +08:00
|
|
|
self.set_state(State::Established);
|
2017-09-16 18:54:59 +08:00
|
|
|
self.timer.set_for_idle(timestamp, self.keep_alive);
|
2016-12-25 19:09:50 +08:00
|
|
|
}
|
2016-12-23 16:05:50 +08:00
|
|
|
|
2017-07-24 07:51:56 +08:00
|
|
|
// FIN packets in the SYN-RECEIVED state change it to CLOSE-WAIT.
|
|
|
|
// It's not obvious from RFC 793 that this is permitted, but
|
|
|
|
// 7th and 8th steps in the "SEGMENT ARRIVES" event describe this behavior.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::SynReceived, TcpControl::Fin) => {
|
2017-07-24 07:51:56 +08:00
|
|
|
self.remote_seq_no += 1;
|
2020-06-12 04:12:38 +08:00
|
|
|
self.rx_fin_received = true;
|
2017-07-24 07:51:56 +08:00
|
|
|
self.set_state(State::CloseWait);
|
2017-09-16 18:54:59 +08:00
|
|
|
self.timer.set_for_idle(timestamp, self.keep_alive);
|
2017-07-24 07:51:56 +08:00
|
|
|
}
|
|
|
|
|
2017-03-05 11:52:47 +08:00
|
|
|
// SYN|ACK packets in the SYN-SENT state change it to ESTABLISHED.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::SynSent, TcpControl::Syn) => {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: received SYN|ACK",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-07-24 07:07:55 +08:00
|
|
|
self.local_endpoint = IpEndpoint::new(ip_repr.dst_addr(), repr.dst_port);
|
2017-08-28 12:50:57 +08:00
|
|
|
self.remote_seq_no = repr.seq_number + 1;
|
2017-08-30 18:04:33 +08:00
|
|
|
self.remote_last_seq = self.local_seq_no + 1;
|
2017-09-24 19:26:51 +08:00
|
|
|
self.remote_last_ack = Some(repr.seq_number);
|
2017-08-28 12:50:57 +08:00
|
|
|
if let Some(max_seg_size) = repr.max_seg_size {
|
2017-03-05 11:52:47 +08:00
|
|
|
self.remote_mss = max_seg_size as usize;
|
|
|
|
}
|
|
|
|
self.set_state(State::Established);
|
2017-09-16 18:54:59 +08:00
|
|
|
self.timer.set_for_idle(timestamp, self.keep_alive);
|
2017-03-05 11:52:47 +08:00
|
|
|
}
|
|
|
|
|
2017-10-28 16:32:08 +08:00
|
|
|
// ACK packets in ESTABLISHED state reset the retransmit timer,
|
|
|
|
// except for duplicate ACK packets which preserve it.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::Established, TcpControl::None) => {
|
2017-10-28 16:32:08 +08:00
|
|
|
if !self.timer.is_retransmit() || ack_len != 0 {
|
|
|
|
self.timer.set_for_idle(timestamp, self.keep_alive);
|
|
|
|
}
|
2017-01-25 13:42:02 +08:00
|
|
|
},
|
2016-12-25 19:09:50 +08:00
|
|
|
|
2016-12-27 21:34:48 +08:00
|
|
|
// FIN packets in ESTABLISHED state indicate the remote side has closed.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::Established, TcpControl::Fin) => {
|
2016-12-27 22:04:30 +08:00
|
|
|
self.remote_seq_no += 1;
|
2020-06-12 04:12:38 +08:00
|
|
|
self.rx_fin_received = true;
|
2016-12-27 21:34:48 +08:00
|
|
|
self.set_state(State::CloseWait);
|
2017-09-16 18:54:59 +08:00
|
|
|
self.timer.set_for_idle(timestamp, self.keep_alive);
|
2016-12-28 12:02:43 +08:00
|
|
|
}
|
|
|
|
|
2017-01-25 13:36:42 +08:00
|
|
|
// ACK packets in FIN-WAIT-1 state change it to FIN-WAIT-2, if we've already
|
2017-03-07 18:17:30 +08:00
|
|
|
// sent everything in the transmit buffer. If not, they reset the retransmit timer.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::FinWait1, TcpControl::None) => {
|
2017-03-07 18:17:30 +08:00
|
|
|
if ack_of_fin {
|
2017-01-25 13:36:42 +08:00
|
|
|
self.set_state(State::FinWait2);
|
|
|
|
}
|
2017-09-16 18:54:59 +08:00
|
|
|
self.timer.set_for_idle(timestamp, self.keep_alive);
|
2016-12-28 12:02:43 +08:00
|
|
|
}
|
|
|
|
|
2017-04-22 00:01:49 +08:00
|
|
|
// FIN packets in FIN-WAIT-1 state change it to CLOSING, or to TIME-WAIT
|
|
|
|
// if they also acknowledge our FIN.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::FinWait1, TcpControl::Fin) => {
|
2016-12-28 12:02:43 +08:00
|
|
|
self.remote_seq_no += 1;
|
2020-06-12 04:12:38 +08:00
|
|
|
self.rx_fin_received = true;
|
2017-03-07 18:17:30 +08:00
|
|
|
if ack_of_fin {
|
|
|
|
self.set_state(State::TimeWait);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
self.timer.set_for_close(timestamp);
|
2017-03-07 18:17:30 +08:00
|
|
|
} else {
|
|
|
|
self.set_state(State::Closing);
|
2017-09-16 18:54:59 +08:00
|
|
|
self.timer.set_for_idle(timestamp, self.keep_alive);
|
2017-03-07 18:17:30 +08:00
|
|
|
}
|
2016-12-27 21:34:48 +08:00
|
|
|
}
|
|
|
|
|
2020-06-12 04:01:48 +08:00
|
|
|
// Data packets in FIN-WAIT-2 reset the idle timer.
|
|
|
|
(State::FinWait2, TcpControl::None) => {
|
|
|
|
self.timer.set_for_idle(timestamp, self.keep_alive);
|
|
|
|
}
|
|
|
|
|
2016-12-28 12:10:17 +08:00
|
|
|
// FIN packets in FIN-WAIT-2 state change it to TIME-WAIT.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::FinWait2, TcpControl::Fin) => {
|
2016-12-28 12:10:17 +08:00
|
|
|
self.remote_seq_no += 1;
|
2020-06-12 04:12:38 +08:00
|
|
|
self.rx_fin_received = true;
|
2016-12-28 12:10:17 +08:00
|
|
|
self.set_state(State::TimeWait);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
self.timer.set_for_close(timestamp);
|
2016-12-28 12:10:17 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 12:56:49 +08:00
|
|
|
// ACK packets in CLOSING state change it to TIME-WAIT.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::Closing, TcpControl::None) => {
|
2017-03-07 18:17:30 +08:00
|
|
|
if ack_of_fin {
|
|
|
|
self.set_state(State::TimeWait);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
self.timer.set_for_close(timestamp);
|
2017-03-07 18:17:30 +08:00
|
|
|
} else {
|
2017-09-16 18:54:59 +08:00
|
|
|
self.timer.set_for_idle(timestamp, self.keep_alive);
|
2017-03-07 18:17:30 +08:00
|
|
|
}
|
2016-12-28 12:56:49 +08:00
|
|
|
}
|
|
|
|
|
2017-01-25 13:42:02 +08:00
|
|
|
// ACK packets in CLOSE-WAIT state reset the retransmit timer.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::CloseWait, TcpControl::None) => {
|
2017-09-16 18:54:59 +08:00
|
|
|
self.timer.set_for_idle(timestamp, self.keep_alive);
|
2017-01-25 13:42:02 +08:00
|
|
|
}
|
2016-12-27 22:13:42 +08:00
|
|
|
|
2016-12-28 07:28:57 +08:00
|
|
|
// ACK packets in LAST-ACK state change it to CLOSED.
|
2017-08-28 12:50:57 +08:00
|
|
|
(State::LastAck, TcpControl::None) => {
|
2016-12-28 07:27:33 +08:00
|
|
|
// Clear the remote endpoint, or we'll send an RST there.
|
2017-01-17 00:34:24 +08:00
|
|
|
self.set_state(State::Closed);
|
2017-09-24 19:26:51 +08:00
|
|
|
self.local_endpoint = IpEndpoint::default();
|
2016-12-28 07:27:33 +08:00
|
|
|
self.remote_endpoint = IpEndpoint::default();
|
|
|
|
}
|
|
|
|
|
2016-12-25 19:09:50 +08:00
|
|
|
_ => {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_debug!("{}:{}:{}: unexpected packet {}",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint, repr);
|
2017-08-25 11:52:30 +08:00
|
|
|
return Err(Error::Dropped)
|
2016-12-23 16:05:50 +08:00
|
|
|
}
|
2016-12-25 19:09:50 +08:00
|
|
|
}
|
2016-12-23 16:05:50 +08:00
|
|
|
|
2017-09-18 19:05:40 +08:00
|
|
|
// Update remote state.
|
|
|
|
self.remote_last_ts = Some(timestamp);
|
2018-06-24 22:35:29 +08:00
|
|
|
|
|
|
|
// RFC 1323: The window field (SEG.WND) in the header of every incoming segment, with the
|
|
|
|
// exception of SYN segments, is left-shifted by Snd.Wind.Scale bits before updating SND.WND.
|
|
|
|
self.remote_win_len = (repr.window_len as usize) << (self.remote_win_scale.unwrap_or(0) as usize);
|
2017-08-25 13:50:43 +08:00
|
|
|
|
2017-03-07 18:17:30 +08:00
|
|
|
if ack_len > 0 {
|
2017-08-25 13:50:43 +08:00
|
|
|
// Dequeue acknowledged octets.
|
2017-09-22 17:51:04 +08:00
|
|
|
debug_assert!(self.tx_buffer.len() >= ack_len);
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: tx buffer: dequeueing {} octets (now {})",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-03-07 18:17:30 +08:00
|
|
|
ack_len, self.tx_buffer.len() - ack_len);
|
2017-09-23 01:10:51 +08:00
|
|
|
self.tx_buffer.dequeue_allocated(ack_len);
|
2020-10-20 19:22:46 +08:00
|
|
|
|
|
|
|
// There's new room available in tx_buffer, wake the waiting task if any.
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
self.tx_waker.wake();
|
2017-03-07 18:17:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(ack_number) = repr.ack_number {
|
2018-06-09 07:11:10 +08:00
|
|
|
// TODO: When flow control is implemented,
|
|
|
|
// refractor the following block within that implementation
|
|
|
|
|
|
|
|
// Detect and react to duplicate ACKs by:
|
|
|
|
// 1. Check if duplicate ACK and change self.local_rx_dup_acks accordingly
|
|
|
|
// 2. If exactly 3 duplicate ACKs recived, set for fast retransmit
|
|
|
|
// 3. Update the last received ACK (self.local_rx_last_ack)
|
|
|
|
match self.local_rx_last_ack {
|
|
|
|
// Duplicate ACK if payload empty and ACK doesn't move send window ->
|
|
|
|
// Increment duplicate ACK count and set for retransmit if we just recived
|
|
|
|
// the third duplicate ACK
|
2018-06-12 14:19:48 +08:00
|
|
|
Some(ref last_rx_ack) if
|
2018-06-09 07:11:10 +08:00
|
|
|
repr.payload.len() == 0 &&
|
2018-06-12 14:19:48 +08:00
|
|
|
*last_rx_ack == ack_number &&
|
|
|
|
ack_number < self.remote_last_seq => {
|
2018-06-09 07:11:10 +08:00
|
|
|
// Increment duplicate ACK count
|
|
|
|
self.local_rx_dup_acks = self.local_rx_dup_acks.saturating_add(1);
|
|
|
|
|
|
|
|
net_debug!("{}:{}:{}: received duplicate ACK for seq {} (duplicate nr {}{})",
|
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint, ack_number,
|
|
|
|
self.local_rx_dup_acks, if self.local_rx_dup_acks == u8::max_value() { "+" } else { "" });
|
|
|
|
|
|
|
|
if self.local_rx_dup_acks == 3 {
|
|
|
|
self.timer.set_for_fast_retransmit();
|
|
|
|
net_debug!("{}:{}:{}: started fast retransmit",
|
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// No duplicate ACK -> Reset state and update last recived ACK
|
|
|
|
_ => {
|
|
|
|
if self.local_rx_dup_acks > 0 {
|
|
|
|
self.local_rx_dup_acks = 0;
|
|
|
|
net_debug!("{}:{}:{}: reset duplicate ACK count",
|
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
|
|
|
}
|
|
|
|
self.local_rx_last_ack = Some(ack_number);
|
|
|
|
}
|
|
|
|
};
|
2017-09-22 17:51:04 +08:00
|
|
|
// We've processed everything in the incoming segment, so advance the local
|
|
|
|
// sequence number past it.
|
2016-12-25 19:09:50 +08:00
|
|
|
self.local_seq_no = ack_number;
|
2017-12-23 03:31:04 +08:00
|
|
|
// During retransmission, if an earlier segment got lost but later was
|
|
|
|
// successfully received, self.local_seq_no can move past self.remote_last_seq.
|
|
|
|
// Do not attempt to retransmit the latter segments; not only this is pointless
|
|
|
|
// in theory but also impossible in practice, since they have been already
|
|
|
|
// deallocated from the buffer.
|
|
|
|
if self.remote_last_seq < self.local_seq_no {
|
|
|
|
self.remote_last_seq = self.local_seq_no
|
|
|
|
}
|
2016-12-25 19:09:50 +08:00
|
|
|
}
|
|
|
|
|
2017-09-22 17:51:04 +08:00
|
|
|
let payload_len = repr.payload.len();
|
|
|
|
if payload_len == 0 { return Ok(None) }
|
|
|
|
|
2017-09-23 02:57:47 +08:00
|
|
|
let assembler_was_empty = self.assembler.is_empty();
|
|
|
|
|
2017-09-22 17:51:04 +08:00
|
|
|
// Try adding payload octets to the assembler.
|
|
|
|
match self.assembler.add(payload_offset, payload_len) {
|
|
|
|
Ok(()) => {
|
|
|
|
debug_assert!(self.assembler.total_size() == self.rx_buffer.capacity());
|
|
|
|
// Place payload octets into the buffer.
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: rx buffer: receiving {} octets at offset {}",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-09-22 17:51:04 +08:00
|
|
|
payload_len, payload_offset);
|
2017-09-23 01:10:51 +08:00
|
|
|
self.rx_buffer.write_unallocated(payload_offset, repr.payload);
|
2017-09-22 17:51:04 +08:00
|
|
|
}
|
|
|
|
Err(()) => {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_debug!("{}:{}:{}: assembler: too many holes to add {} octets at offset {}",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-09-22 17:51:04 +08:00
|
|
|
payload_len, payload_offset);
|
|
|
|
return Err(Error::Dropped)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(contig_len) = self.assembler.remove_front() {
|
|
|
|
debug_assert!(self.assembler.total_size() == self.rx_buffer.capacity());
|
|
|
|
// Enqueue the contiguous data octets in front of the buffer.
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: rx buffer: enqueueing {} octets (now {})",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-09-22 17:51:04 +08:00
|
|
|
contig_len, self.rx_buffer.len() + contig_len);
|
2017-09-23 01:10:51 +08:00
|
|
|
self.rx_buffer.enqueue_unallocated(contig_len);
|
2020-10-20 19:22:46 +08:00
|
|
|
|
|
|
|
// There's new data in rx_buffer, notify waiting task if any.
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
self.rx_waker.wake();
|
2017-08-25 13:50:43 +08:00
|
|
|
}
|
2017-09-06 07:23:50 +08:00
|
|
|
|
2017-09-23 02:57:47 +08:00
|
|
|
if !self.assembler.is_empty() {
|
|
|
|
// Print the ranges recorded in the assembler.
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: assembler: {}",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-09-22 17:51:04 +08:00
|
|
|
self.assembler);
|
2017-09-23 02:57:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Per RFC 5681, we should send an immediate ACK when either:
|
|
|
|
// 1) an out-of-order segment is received, or
|
|
|
|
// 2) a segment arrives that fills in all or part of a gap in sequence space.
|
|
|
|
if !self.assembler.is_empty() || !assembler_was_empty {
|
|
|
|
// Note that we change the transmitter state here.
|
|
|
|
// This is fine because smoltcp assumes that it can always transmit zero or one
|
|
|
|
// packets for every packet it receives.
|
2017-12-21 18:39:54 +08:00
|
|
|
net_trace!("{}:{}:{}: ACKing incoming segment",
|
2017-12-18 20:47:42 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-09-22 17:51:04 +08:00
|
|
|
Ok(Some(self.ack_reply(ip_repr, &repr)))
|
2017-09-23 02:57:47 +08:00
|
|
|
} else {
|
|
|
|
Ok(None)
|
2017-09-22 17:51:04 +08:00
|
|
|
}
|
2016-12-23 15:30:57 +08:00
|
|
|
}
|
2016-12-21 03:51:52 +08:00
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
fn timed_out(&self, timestamp: Instant) -> bool {
|
2017-09-18 19:05:40 +08:00
|
|
|
match (self.remote_last_ts, self.timeout) {
|
|
|
|
(Some(remote_last_ts), Some(timeout)) =>
|
|
|
|
timestamp >= remote_last_ts + timeout,
|
|
|
|
(_, _) =>
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-24 19:26:51 +08:00
|
|
|
fn seq_to_transmit(&self) -> bool {
|
2020-12-26 10:04:17 +08:00
|
|
|
// We can send data if we have data that:
|
|
|
|
// - hasn't been sent before
|
|
|
|
// - fits in the remote window
|
|
|
|
let can_data = self.remote_last_seq
|
|
|
|
< self.local_seq_no + core::cmp::min(self.remote_win_len, self.tx_buffer.len());
|
|
|
|
|
|
|
|
// Do we have to send a FIN?
|
2020-12-26 10:12:48 +08:00
|
|
|
let want_fin = match self.state {
|
|
|
|
State::FinWait1 => true,
|
|
|
|
State::LastAck => true,
|
|
|
|
_ => false,
|
|
|
|
};
|
2020-12-26 10:04:17 +08:00
|
|
|
|
|
|
|
// Can we actually send the FIN? We can send it if:
|
|
|
|
// 1. We have unsent data that fits in the remote window.
|
|
|
|
// 2. We have no unsent data.
|
|
|
|
// This condition matches only if #2, because #1 is already covered by can_data and we're ORing them.
|
|
|
|
let can_fin =
|
|
|
|
want_fin && self.remote_last_seq == self.local_seq_no + self.tx_buffer.len();
|
|
|
|
|
|
|
|
can_data || can_fin
|
2017-08-30 18:04:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn ack_to_transmit(&self) -> bool {
|
2017-08-31 06:40:07 +08:00
|
|
|
if let Some(remote_last_ack) = self.remote_last_ack {
|
|
|
|
remote_last_ack < self.remote_seq_no + self.rx_buffer.len()
|
|
|
|
} else {
|
2017-09-24 19:26:51 +08:00
|
|
|
false
|
2017-08-31 06:40:07 +08:00
|
|
|
}
|
2017-08-30 18:04:33 +08:00
|
|
|
}
|
|
|
|
|
2017-09-24 19:26:51 +08:00
|
|
|
fn window_to_update(&self) -> bool {
|
2020-06-25 07:51:33 +08:00
|
|
|
match self.state {
|
|
|
|
State::SynSent | State::SynReceived | State::Established | State::FinWait1 | State::FinWait2 =>
|
|
|
|
(self.rx_buffer.window() >> self.remote_win_shift) as u16 > self.remote_last_win,
|
|
|
|
_ => false,
|
|
|
|
}
|
2017-09-24 19:26:51 +08:00
|
|
|
}
|
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
pub(crate) fn dispatch<F>(&mut self, timestamp: Instant, caps: &DeviceCapabilities,
|
2017-08-28 11:50:40 +08:00
|
|
|
emit: F) -> Result<()>
|
|
|
|
where F: FnOnce((IpRepr, TcpRepr)) -> Result<()> {
|
2017-07-27 20:27:33 +08:00
|
|
|
if !self.remote_endpoint.is_specified() { return Err(Error::Exhausted) }
|
2016-12-28 12:56:49 +08:00
|
|
|
|
2017-09-18 19:05:40 +08:00
|
|
|
if self.remote_last_ts.is_none() {
|
|
|
|
// We get here in exactly two cases:
|
|
|
|
// 1) This socket just transitioned into SYN-SENT.
|
|
|
|
// 2) This socket had an empty transmit buffer and some data was added there.
|
|
|
|
// Both are similar in that the socket has been quiet for an indefinite
|
|
|
|
// period of time, it isn't anymore, and the local endpoint is talking.
|
|
|
|
// So, we start counting the timeout not from the last received packet
|
|
|
|
// but from the first transmitted one.
|
|
|
|
self.remote_last_ts = Some(timestamp);
|
|
|
|
}
|
|
|
|
|
2017-09-24 19:26:51 +08:00
|
|
|
// Check if any state needs to be changed because of a timer.
|
2017-09-18 19:05:40 +08:00
|
|
|
if self.timed_out(timestamp) {
|
|
|
|
// If a timeout expires, we should abort the connection.
|
2017-10-05 11:02:41 +08:00
|
|
|
net_debug!("{}:{}:{}: timeout exceeded",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-09-18 19:05:40 +08:00
|
|
|
self.set_state(State::Closed);
|
2017-09-24 19:26:51 +08:00
|
|
|
} else if !self.seq_to_transmit() {
|
2017-08-30 18:04:33 +08:00
|
|
|
if let Some(retransmit_delta) = self.timer.should_retransmit(timestamp) {
|
|
|
|
// If a retransmit timer expired, we should resend data starting at the last ACK.
|
2018-05-15 22:49:53 +08:00
|
|
|
net_debug!("{}:{}:{}: retransmitting at t+{}",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-08-30 18:04:33 +08:00
|
|
|
retransmit_delta);
|
|
|
|
self.remote_last_seq = self.local_seq_no;
|
|
|
|
}
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}
|
|
|
|
|
2017-09-24 19:26:51 +08:00
|
|
|
// Decide whether we're sending a packet.
|
|
|
|
if self.seq_to_transmit() {
|
|
|
|
// If we have data to transmit and it fits into partner's window, do it.
|
2017-12-18 20:47:42 +08:00
|
|
|
net_trace!("{}:{}:{}: outgoing segment will send data or flags",
|
2017-12-15 13:23:58 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-09-24 19:26:51 +08:00
|
|
|
} else if self.ack_to_transmit() {
|
|
|
|
// If we have data to acknowledge, do it.
|
2017-12-18 20:47:42 +08:00
|
|
|
net_trace!("{}:{}:{}: outgoing segment will acknowledge",
|
2017-12-15 13:23:58 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-09-24 19:26:51 +08:00
|
|
|
} else if self.window_to_update() {
|
|
|
|
// If we have window length increase to advertise, do it.
|
2017-12-18 20:47:42 +08:00
|
|
|
net_trace!("{}:{}:{}: outgoing segment will update window",
|
2017-12-15 13:23:58 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-09-24 19:26:51 +08:00
|
|
|
} else if self.state == State::Closed {
|
|
|
|
// If we need to abort the connection, do it.
|
2017-12-18 20:47:42 +08:00
|
|
|
net_trace!("{}:{}:{}: outgoing segment will abort connection",
|
2017-12-15 13:23:58 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-09-24 19:26:51 +08:00
|
|
|
} else if self.timer.should_retransmit(timestamp).is_some() {
|
|
|
|
// If we have packets to retransmit, do it.
|
2017-12-15 13:23:58 +08:00
|
|
|
net_trace!("{}:{}:{}: retransmit timer expired",
|
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-09-24 19:26:51 +08:00
|
|
|
} else if self.timer.should_keep_alive(timestamp) {
|
|
|
|
// If we need to transmit a keep-alive packet, do it.
|
2017-12-15 13:23:58 +08:00
|
|
|
net_trace!("{}:{}:{}: keep-alive timer expired",
|
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-09-24 19:26:51 +08:00
|
|
|
} else if self.timer.should_close(timestamp) {
|
|
|
|
// If we have spent enough time in the TIME-WAIT state, close the socket.
|
2017-12-15 13:23:58 +08:00
|
|
|
net_trace!("{}:{}:{}: TIME-WAIT timer expired",
|
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
|
|
|
self.reset();
|
|
|
|
return Err(Error::Exhausted)
|
2017-09-24 19:26:51 +08:00
|
|
|
} else {
|
|
|
|
return Err(Error::Exhausted)
|
|
|
|
}
|
|
|
|
|
2017-09-22 14:01:59 +08:00
|
|
|
// Construct the lowered IP representation.
|
|
|
|
// We might need this to calculate the MSS, so do it early.
|
|
|
|
let mut ip_repr = IpRepr::Unspecified {
|
|
|
|
src_addr: self.local_endpoint.addr,
|
|
|
|
dst_addr: self.remote_endpoint.addr,
|
|
|
|
protocol: IpProtocol::Tcp,
|
2017-12-10 11:09:50 +08:00
|
|
|
hop_limit: self.hop_limit.unwrap_or(64),
|
2017-09-22 14:01:59 +08:00
|
|
|
payload_len: 0
|
|
|
|
}.lower(&[])?;
|
|
|
|
|
|
|
|
// Construct the basic TCP representation, an empty ACK packet.
|
|
|
|
// We'll adjust this to be more specific as needed.
|
2016-12-23 15:30:57 +08:00
|
|
|
let mut repr = TcpRepr {
|
2017-01-27 09:09:34 +08:00
|
|
|
src_port: self.local_endpoint.port,
|
|
|
|
dst_port: self.remote_endpoint.port,
|
|
|
|
control: TcpControl::None,
|
2017-08-30 18:04:33 +08:00
|
|
|
seq_number: self.remote_last_seq,
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
ack_number: Some(self.remote_seq_no + self.rx_buffer.len()),
|
2018-08-20 04:32:27 +08:00
|
|
|
window_len: self.scaled_window(),
|
2018-06-24 22:35:29 +08:00
|
|
|
window_scale: None,
|
2017-01-27 09:09:34 +08:00
|
|
|
max_seg_size: None,
|
2019-01-01 04:45:20 +08:00
|
|
|
sack_permitted: false,
|
|
|
|
sack_ranges: [None, None, None],
|
2017-01-27 09:09:34 +08:00
|
|
|
payload: &[]
|
2016-12-23 15:30:57 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
match self.state {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
// We transmit an RST in the CLOSED state. If we ended up in the CLOSED state
|
|
|
|
// with a specified endpoint, it means that the socket was aborted.
|
|
|
|
State::Closed => {
|
|
|
|
repr.control = TcpControl::Rst;
|
2016-12-28 07:27:33 +08:00
|
|
|
}
|
2016-12-23 16:05:50 +08:00
|
|
|
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
// We never transmit anything in the LISTEN state.
|
|
|
|
State::Listen => return Err(Error::Exhausted),
|
|
|
|
|
2016-12-28 07:28:57 +08:00
|
|
|
// We transmit a SYN in the SYN-SENT state.
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
// We transmit a SYN|ACK in the SYN-RECEIVED state.
|
|
|
|
State::SynSent | State::SynReceived => {
|
2016-12-28 07:27:33 +08:00
|
|
|
repr.control = TcpControl::Syn;
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
if self.state == State::SynSent {
|
|
|
|
repr.ack_number = None;
|
2018-08-20 04:32:27 +08:00
|
|
|
repr.window_scale = Some(self.remote_win_shift);
|
2019-01-01 04:45:20 +08:00
|
|
|
repr.sack_permitted = true;
|
2018-06-24 22:35:29 +08:00
|
|
|
} else {
|
2019-01-01 04:45:20 +08:00
|
|
|
repr.sack_permitted = self.remote_has_sack;
|
2018-08-20 04:32:27 +08:00
|
|
|
repr.window_scale = self.remote_win_scale.map(
|
|
|
|
|_| self.remote_win_shift);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}
|
2016-12-28 07:27:33 +08:00
|
|
|
}
|
|
|
|
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
// We transmit data in all states where we may have data in the buffer,
|
|
|
|
// or the transmit half of the connection is still open:
|
|
|
|
// the ESTABLISHED, FIN-WAIT-1, CLOSE-WAIT and LAST-ACK states.
|
|
|
|
State::Established | State::FinWait1 | State::CloseWait | State::LastAck => {
|
|
|
|
// Extract as much data as the remote side can receive in this packet
|
|
|
|
// from the transmit buffer.
|
2017-08-30 18:04:33 +08:00
|
|
|
let offset = self.remote_last_seq - self.local_seq_no;
|
2020-12-18 23:06:23 +08:00
|
|
|
let win_limit = self.local_seq_no + self.remote_win_len - self.remote_last_seq;
|
|
|
|
let size = cmp::min(cmp::min(win_limit, self.remote_mss),
|
2020-10-23 21:13:18 +08:00
|
|
|
caps.max_transmission_unit - ip_repr.buffer_len() - repr.mss_header_len());
|
2017-09-08 07:47:42 +08:00
|
|
|
repr.payload = self.tx_buffer.get_allocated(offset, size);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
// If we've sent everything we had in the buffer, follow it with the PSH or FIN
|
|
|
|
// flags, depending on whether the transmit half of the connection is open.
|
|
|
|
if offset + repr.payload.len() == self.tx_buffer.len() {
|
|
|
|
match self.state {
|
|
|
|
State::FinWait1 | State::LastAck =>
|
|
|
|
repr.control = TcpControl::Fin,
|
2017-09-24 21:38:07 +08:00
|
|
|
State::Established | State::CloseWait if repr.payload.len() > 0 =>
|
2017-08-25 14:03:54 +08:00
|
|
|
repr.control = TcpControl::Psh,
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
_ => ()
|
2016-12-31 16:35:07 +08:00
|
|
|
}
|
2016-12-28 07:27:33 +08:00
|
|
|
}
|
|
|
|
}
|
2016-12-31 16:35:07 +08:00
|
|
|
|
2020-12-18 23:26:41 +08:00
|
|
|
// We do not transmit data in the FIN-WAIT-2 state, but we may transmit
|
|
|
|
// ACKs for incoming data.
|
|
|
|
State::FinWait2 => {}
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
|
2017-12-15 13:23:58 +08:00
|
|
|
// We do not transmit data or control flags in the CLOSING or TIME-WAIT states,
|
|
|
|
// but we may retransmit an ACK.
|
|
|
|
State::Closing | State::TimeWait => ()
|
2016-12-21 03:51:52 +08:00
|
|
|
}
|
2016-12-23 15:30:57 +08:00
|
|
|
|
2017-09-24 21:38:07 +08:00
|
|
|
// There might be more than one reason to send a packet. E.g. the keep-alive timer
|
|
|
|
// has expired, and we also have data in transmit buffer. Since any packet that occupies
|
|
|
|
// sequence space will elicit an ACK, we only need to send an explicit packet if we
|
|
|
|
// couldn't fill the sequence space with anything.
|
|
|
|
let is_keep_alive;
|
|
|
|
if self.timer.should_keep_alive(timestamp) && repr.is_empty() {
|
|
|
|
repr.seq_number = repr.seq_number - 1;
|
|
|
|
repr.payload = b"\x00"; // RFC 1122 says we should do this
|
|
|
|
is_keep_alive = true;
|
|
|
|
} else {
|
|
|
|
is_keep_alive = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trace a summary of what will be sent.
|
|
|
|
if is_keep_alive {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: sending a keep-alive",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint);
|
2017-09-24 21:38:07 +08:00
|
|
|
} else if repr.payload.len() > 0 {
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: tx buffer: sending {} octets at offset {}",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-08-31 20:39:05 +08:00
|
|
|
repr.payload.len(), self.remote_last_seq - self.local_seq_no);
|
2017-09-24 21:38:07 +08:00
|
|
|
}
|
|
|
|
if repr.control != TcpControl::None || repr.payload.len() == 0 {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
let flags =
|
|
|
|
match (repr.control, repr.ack_number) {
|
|
|
|
(TcpControl::Syn, None) => "SYN",
|
|
|
|
(TcpControl::Syn, Some(_)) => "SYN|ACK",
|
|
|
|
(TcpControl::Fin, Some(_)) => "FIN|ACK",
|
|
|
|
(TcpControl::Rst, Some(_)) => "RST|ACK",
|
2017-08-25 14:03:54 +08:00
|
|
|
(TcpControl::Psh, Some(_)) => "PSH|ACK",
|
|
|
|
(TcpControl::None, Some(_)) => "ACK",
|
2017-09-24 21:38:07 +08:00
|
|
|
_ => "<unreachable>"
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
};
|
2017-10-05 11:02:41 +08:00
|
|
|
net_trace!("{}:{}:{}: sending {}",
|
2017-11-22 11:50:09 +08:00
|
|
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
2017-08-31 20:39:05 +08:00
|
|
|
flags);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}
|
2016-12-31 16:35:07 +08:00
|
|
|
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
if repr.control == TcpControl::Syn {
|
2017-09-24 19:26:51 +08:00
|
|
|
// Fill the MSS option. See RFC 6691 for an explanation of this calculation.
|
2017-09-16 17:04:07 +08:00
|
|
|
let mut max_segment_size = caps.max_transmission_unit;
|
2017-09-22 14:01:59 +08:00
|
|
|
max_segment_size -= ip_repr.buffer_len();
|
2018-06-24 22:35:29 +08:00
|
|
|
max_segment_size -= repr.mss_header_len();
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
repr.max_seg_size = Some(max_segment_size as u16);
|
|
|
|
}
|
2017-01-27 11:35:22 +08:00
|
|
|
|
2017-09-24 19:26:51 +08:00
|
|
|
// Actually send the packet. If this succeeds, it means the packet is in
|
|
|
|
// the device buffer, and its transmission is imminent. If not, we might have
|
|
|
|
// a number of problems, e.g. we need neighbor discovery.
|
|
|
|
//
|
|
|
|
// Bailing out if the packet isn't placed in the device buffer allows us
|
|
|
|
// to not waste time waiting for the retransmit timer on packets that we know
|
|
|
|
// for sure will not be successfully transmitted.
|
2017-09-22 18:14:26 +08:00
|
|
|
ip_repr.set_payload_len(repr.buffer_len());
|
2017-08-28 11:50:40 +08:00
|
|
|
emit((ip_repr, repr))?;
|
2017-03-07 19:21:49 +08:00
|
|
|
|
2017-09-16 18:54:59 +08:00
|
|
|
// We've sent something, whether useful data or a keep-alive packet, so rewind
|
|
|
|
// the keep-alive timer.
|
|
|
|
self.timer.rewind_keep_alive(timestamp, self.keep_alive);
|
|
|
|
|
2017-09-24 19:26:51 +08:00
|
|
|
// Leave the rest of the state intact if sending a keep-alive packet, since those
|
|
|
|
// carry a fake segment.
|
2017-09-16 18:54:59 +08:00
|
|
|
if is_keep_alive { return Ok(()) }
|
|
|
|
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
// We've sent a packet successfully, so we can update the internal state now.
|
2017-08-30 18:04:33 +08:00
|
|
|
self.remote_last_seq = repr.seq_number + repr.segment_len();
|
2017-08-31 06:40:07 +08:00
|
|
|
self.remote_last_ack = repr.ack_number;
|
2017-08-31 08:08:40 +08:00
|
|
|
self.remote_last_win = repr.window_len;
|
2017-01-27 10:49:06 +08:00
|
|
|
|
2017-09-24 19:26:51 +08:00
|
|
|
if !self.seq_to_transmit() && repr.segment_len() > 0 {
|
2017-09-16 18:54:59 +08:00
|
|
|
// If we've transmitted all data we could (and there was something at all,
|
2017-08-30 18:04:33 +08:00
|
|
|
// data or flag, to transmit, not just an ACK), wind up the retransmit timer.
|
|
|
|
self.timer.set_for_retransmit(timestamp);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}
|
2017-03-07 19:21:49 +08:00
|
|
|
|
2017-09-24 19:26:51 +08:00
|
|
|
if self.state == State::Closed {
|
|
|
|
// When aborting a connection, forget about it after sending a single RST packet.
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
self.local_endpoint = IpEndpoint::default();
|
|
|
|
self.remote_endpoint = IpEndpoint::default();
|
2016-12-27 22:04:30 +08:00
|
|
|
}
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
|
2017-08-28 11:50:40 +08:00
|
|
|
Ok(())
|
2016-12-23 15:30:57 +08:00
|
|
|
}
|
2017-08-30 03:35:09 +08:00
|
|
|
|
2018-05-17 03:11:04 +08:00
|
|
|
pub(crate) fn poll_at(&self) -> PollAt {
|
2017-09-24 19:26:51 +08:00
|
|
|
// The logic here mirrors the beginning of dispatch() closely.
|
|
|
|
if !self.remote_endpoint.is_specified() {
|
|
|
|
// No one to talk to, nothing to transmit.
|
2018-05-17 03:11:04 +08:00
|
|
|
PollAt::Ingress
|
2017-09-24 19:26:51 +08:00
|
|
|
} else if self.remote_last_ts.is_none() {
|
|
|
|
// Socket stopped being quiet recently, we need to acquire a timestamp.
|
2018-05-17 03:11:04 +08:00
|
|
|
PollAt::Now
|
2017-09-24 19:26:51 +08:00
|
|
|
} else if self.state == State::Closed {
|
|
|
|
// Socket was aborted, we have an RST packet to transmit.
|
2018-05-17 03:11:04 +08:00
|
|
|
PollAt::Now
|
2017-09-24 19:26:51 +08:00
|
|
|
} else if self.seq_to_transmit() || self.ack_to_transmit() || self.window_to_update() {
|
|
|
|
// We have a data or flag packet to transmit.
|
2018-05-17 03:11:04 +08:00
|
|
|
PollAt::Now
|
2017-09-24 19:26:51 +08:00
|
|
|
} else {
|
2018-02-11 00:32:41 +08:00
|
|
|
let timeout_poll_at = match (self.remote_last_ts, self.timeout) {
|
2017-09-24 19:26:51 +08:00
|
|
|
// If we're transmitting or retransmitting data, we need to poll at the moment
|
|
|
|
// when the timeout would expire.
|
2018-05-17 03:11:04 +08:00
|
|
|
(Some(remote_last_ts), Some(timeout)) => PollAt::Time(remote_last_ts + timeout),
|
2017-09-24 19:26:51 +08:00
|
|
|
// Otherwise we have no timeout.
|
2018-05-17 03:11:04 +08:00
|
|
|
(_, _) => PollAt::Ingress,
|
2018-02-11 00:32:41 +08:00
|
|
|
};
|
2017-09-24 19:04:55 +08:00
|
|
|
|
2017-09-24 19:26:51 +08:00
|
|
|
// We wait for the earliest of our timers to fire.
|
2018-05-17 03:11:04 +08:00
|
|
|
*[self.timer.poll_at(), timeout_poll_at]
|
2017-09-24 19:26:51 +08:00
|
|
|
.iter()
|
2018-05-17 03:11:04 +08:00
|
|
|
.filter(|x| !x.is_ingress())
|
|
|
|
.min().unwrap_or(&PollAt::Ingress)
|
2017-09-24 19:26:51 +08:00
|
|
|
}
|
2017-08-30 03:35:09 +08:00
|
|
|
}
|
2016-12-23 15:30:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-15 20:39:06 +08:00
|
|
|
impl<'a, 'b> Into<Socket<'a, 'b>> for TcpSocket<'a> {
|
|
|
|
fn into(self) -> Socket<'a, 'b> {
|
2018-01-28 22:36:23 +08:00
|
|
|
Socket::Tcp(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-30 14:59:01 +08:00
|
|
|
impl<'a> fmt::Write for TcpSocket<'a> {
|
|
|
|
fn write_str(&mut self, slice: &str) -> fmt::Result {
|
|
|
|
let slice = slice.as_bytes();
|
|
|
|
if self.send_slice(slice) == Ok(slice.len()) {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(fmt::Error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-19 03:40:11 +08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2017-11-13 16:45:07 +08:00
|
|
|
use core::i32;
|
2018-08-20 04:32:27 +08:00
|
|
|
use std::vec::Vec;
|
2020-12-27 07:11:30 +08:00
|
|
|
use crate::wire::{IpAddress, IpRepr, IpCidr};
|
|
|
|
use crate::wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2, MOCK_IP_ADDR_3, MOCK_UNSPECIFIED};
|
2016-12-19 03:40:11 +08:00
|
|
|
use super::*;
|
|
|
|
|
2017-12-24 21:28:59 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Constants
|
|
|
|
// =========================================================================================//
|
2016-12-31 16:35:07 +08:00
|
|
|
|
2016-12-28 02:34:13 +08:00
|
|
|
const LOCAL_PORT: u16 = 80;
|
|
|
|
const REMOTE_PORT: u16 = 49500;
|
2017-12-24 21:28:59 +08:00
|
|
|
const LOCAL_END: IpEndpoint = IpEndpoint { addr: MOCK_IP_ADDR_1, port: LOCAL_PORT };
|
|
|
|
const REMOTE_END: IpEndpoint = IpEndpoint { addr: MOCK_IP_ADDR_2, port: REMOTE_PORT };
|
2016-12-28 02:34:13 +08:00
|
|
|
const LOCAL_SEQ: TcpSeqNumber = TcpSeqNumber(10000);
|
|
|
|
const REMOTE_SEQ: TcpSeqNumber = TcpSeqNumber(-10000);
|
2016-12-25 05:52:23 +08:00
|
|
|
|
2017-09-08 08:53:19 +08:00
|
|
|
const SEND_IP_TEMPL: IpRepr = IpRepr::Unspecified {
|
2017-12-24 21:28:59 +08:00
|
|
|
src_addr: MOCK_IP_ADDR_1, dst_addr: MOCK_IP_ADDR_2,
|
2017-10-15 08:05:55 +08:00
|
|
|
protocol: IpProtocol::Tcp, payload_len: 20,
|
2017-12-10 11:09:50 +08:00
|
|
|
hop_limit: 64
|
2017-09-08 08:53:19 +08:00
|
|
|
};
|
2016-12-25 05:52:23 +08:00
|
|
|
const SEND_TEMPL: TcpRepr<'static> = TcpRepr {
|
|
|
|
src_port: REMOTE_PORT, dst_port: LOCAL_PORT,
|
2017-08-25 14:03:54 +08:00
|
|
|
control: TcpControl::None,
|
2016-12-28 02:34:13 +08:00
|
|
|
seq_number: TcpSeqNumber(0), ack_number: Some(TcpSeqNumber(0)),
|
2018-06-24 22:35:29 +08:00
|
|
|
window_len: 256, window_scale: None,
|
|
|
|
max_seg_size: None,
|
2019-01-01 04:45:20 +08:00
|
|
|
sack_permitted: false,
|
|
|
|
sack_ranges: [None, None, None],
|
2017-01-27 09:09:34 +08:00
|
|
|
payload: &[]
|
2016-12-25 05:52:23 +08:00
|
|
|
};
|
2017-09-15 14:05:41 +08:00
|
|
|
const _RECV_IP_TEMPL: IpRepr = IpRepr::Unspecified {
|
2017-12-24 21:28:59 +08:00
|
|
|
src_addr: MOCK_IP_ADDR_1, dst_addr: MOCK_IP_ADDR_2,
|
2017-10-15 08:05:55 +08:00
|
|
|
protocol: IpProtocol::Tcp, payload_len: 20,
|
2017-12-10 11:09:50 +08:00
|
|
|
hop_limit: 64
|
2017-09-08 08:53:19 +08:00
|
|
|
};
|
2016-12-25 05:52:23 +08:00
|
|
|
const RECV_TEMPL: TcpRepr<'static> = TcpRepr {
|
|
|
|
src_port: LOCAL_PORT, dst_port: REMOTE_PORT,
|
2017-08-25 14:03:54 +08:00
|
|
|
control: TcpControl::None,
|
2016-12-28 02:34:13 +08:00
|
|
|
seq_number: TcpSeqNumber(0), ack_number: Some(TcpSeqNumber(0)),
|
2018-06-24 22:35:29 +08:00
|
|
|
window_len: 64, window_scale: None,
|
|
|
|
max_seg_size: None,
|
2019-01-01 04:45:20 +08:00
|
|
|
sack_permitted: false,
|
|
|
|
sack_ranges: [None, None, None],
|
2017-01-27 09:09:34 +08:00
|
|
|
payload: &[]
|
2016-12-25 05:52:23 +08:00
|
|
|
};
|
|
|
|
|
2017-12-24 21:28:59 +08:00
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
const BASE_MSS: u16 = 1460;
|
|
|
|
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
|
|
|
const BASE_MSS: u16 = 1480;
|
|
|
|
|
|
|
|
// =========================================================================================//
|
|
|
|
// Helper functions
|
|
|
|
// =========================================================================================//
|
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
fn send(socket: &mut TcpSocket, timestamp: Instant, repr: &TcpRepr) ->
|
2017-08-28 12:09:17 +08:00
|
|
|
Result<Option<TcpRepr<'static>>> {
|
2016-12-26 20:38:40 +08:00
|
|
|
let ip_repr = IpRepr::Unspecified {
|
2017-12-24 21:28:59 +08:00
|
|
|
src_addr: MOCK_IP_ADDR_2,
|
|
|
|
dst_addr: MOCK_IP_ADDR_1,
|
2017-01-14 19:07:06 +08:00
|
|
|
protocol: IpProtocol::Tcp,
|
2017-10-15 08:05:55 +08:00
|
|
|
payload_len: repr.buffer_len(),
|
2017-12-10 11:09:50 +08:00
|
|
|
hop_limit: 64
|
2016-12-26 20:38:40 +08:00
|
|
|
};
|
2017-12-22 17:50:26 +08:00
|
|
|
net_trace!("send: {}", repr);
|
2017-09-01 05:44:41 +08:00
|
|
|
|
2017-09-08 08:53:19 +08:00
|
|
|
assert!(socket.accepts(&ip_repr, repr));
|
2017-08-28 12:50:57 +08:00
|
|
|
match socket.process(timestamp, &ip_repr, repr) {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
Ok(Some((_ip_repr, repr))) => {
|
2017-12-22 17:50:26 +08:00
|
|
|
net_trace!("recv: {}", repr);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
Ok(Some(repr))
|
|
|
|
}
|
|
|
|
Ok(None) => Ok(None),
|
|
|
|
Err(err) => Err(err)
|
|
|
|
}
|
2016-12-26 20:38:40 +08:00
|
|
|
}
|
|
|
|
|
2018-02-11 00:32:41 +08:00
|
|
|
fn recv<F>(socket: &mut TcpSocket, timestamp: Instant, mut f: F)
|
2017-07-27 21:51:02 +08:00
|
|
|
where F: FnMut(Result<TcpRepr>) {
|
2017-09-16 17:04:07 +08:00
|
|
|
let mut caps = DeviceCapabilities::default();
|
|
|
|
caps.max_transmission_unit = 1520;
|
|
|
|
let result = socket.dispatch(timestamp, &caps, |(ip_repr, tcp_repr)| {
|
2017-10-03 15:28:00 +08:00
|
|
|
let ip_repr = ip_repr.lower(&[IpCidr::new(LOCAL_END.addr, 24)]).unwrap();
|
2017-07-24 07:07:55 +08:00
|
|
|
|
2016-12-26 20:38:40 +08:00
|
|
|
assert_eq!(ip_repr.protocol(), IpProtocol::Tcp);
|
2017-12-24 21:28:59 +08:00
|
|
|
assert_eq!(ip_repr.src_addr(), MOCK_IP_ADDR_1);
|
|
|
|
assert_eq!(ip_repr.dst_addr(), MOCK_IP_ADDR_2);
|
2017-09-22 18:14:26 +08:00
|
|
|
assert_eq!(ip_repr.payload_len(), tcp_repr.buffer_len());
|
2016-12-26 20:38:40 +08:00
|
|
|
|
2017-12-22 17:50:26 +08:00
|
|
|
net_trace!("recv: {}", tcp_repr);
|
2017-08-28 11:50:40 +08:00
|
|
|
Ok(f(Ok(tcp_repr)))
|
2016-12-26 20:38:40 +08:00
|
|
|
});
|
|
|
|
match result {
|
|
|
|
Ok(()) => (),
|
|
|
|
Err(e) => f(Err(e))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-25 05:52:23 +08:00
|
|
|
macro_rules! send {
|
2016-12-31 16:35:07 +08:00
|
|
|
($socket:ident, $repr:expr) =>
|
|
|
|
(send!($socket, time 0, $repr));
|
2016-12-26 20:38:40 +08:00
|
|
|
($socket:ident, $repr:expr, $result:expr) =>
|
2016-12-31 16:35:07 +08:00
|
|
|
(send!($socket, time 0, $repr, $result));
|
|
|
|
($socket:ident, time $time:expr, $repr:expr) =>
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
(send!($socket, time $time, $repr, Ok(None)));
|
2016-12-31 16:35:07 +08:00
|
|
|
($socket:ident, time $time:expr, $repr:expr, $result:expr) =>
|
2018-02-11 00:32:41 +08:00
|
|
|
(assert_eq!(send(&mut $socket, Instant::from_millis($time), &$repr), $result));
|
2016-12-25 05:52:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! recv {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
($socket:ident, [$( $repr:expr ),*]) => ({
|
2016-12-26 20:38:40 +08:00
|
|
|
$( recv!($socket, Ok($repr)); )*
|
|
|
|
recv!($socket, Err(Error::Exhausted))
|
|
|
|
});
|
|
|
|
($socket:ident, $result:expr) =>
|
2016-12-31 16:35:07 +08:00
|
|
|
(recv!($socket, time 0, $result));
|
|
|
|
($socket:ident, time $time:expr, $result:expr) =>
|
2018-02-11 00:32:41 +08:00
|
|
|
(recv(&mut $socket, Instant::from_millis($time), |result| {
|
2017-06-26 07:12:25 +08:00
|
|
|
// Most of the time we don't care about the PSH flag.
|
2017-08-25 14:03:54 +08:00
|
|
|
let result = result.map(|mut repr| {
|
2017-09-22 14:29:25 +08:00
|
|
|
repr.control = repr.control.quash_psh();
|
2017-08-25 14:03:54 +08:00
|
|
|
repr
|
|
|
|
});
|
|
|
|
assert_eq!(result, $result)
|
2017-06-26 07:12:25 +08:00
|
|
|
}));
|
|
|
|
($socket:ident, time $time:expr, $result:expr, exact) =>
|
2018-02-11 00:32:41 +08:00
|
|
|
(recv(&mut $socket, Instant::from_millis($time), |repr| assert_eq!(repr, $result)));
|
2016-12-25 05:52:23 +08:00
|
|
|
}
|
|
|
|
|
2017-01-14 20:56:58 +08:00
|
|
|
macro_rules! sanity {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
($socket1:expr, $socket2:expr) => ({
|
2017-01-14 20:56:58 +08:00
|
|
|
let (s1, s2) = ($socket1, $socket2);
|
|
|
|
assert_eq!(s1.state, s2.state, "state");
|
|
|
|
assert_eq!(s1.listen_address, s2.listen_address, "listen_address");
|
|
|
|
assert_eq!(s1.local_endpoint, s2.local_endpoint, "local_endpoint");
|
|
|
|
assert_eq!(s1.remote_endpoint, s2.remote_endpoint, "remote_endpoint");
|
|
|
|
assert_eq!(s1.local_seq_no, s2.local_seq_no, "local_seq_no");
|
|
|
|
assert_eq!(s1.remote_seq_no, s2.remote_seq_no, "remote_seq_no");
|
2017-08-30 18:04:33 +08:00
|
|
|
assert_eq!(s1.remote_last_seq, s2.remote_last_seq, "remote_last_seq");
|
2017-01-14 20:56:58 +08:00
|
|
|
assert_eq!(s1.remote_last_ack, s2.remote_last_ack, "remote_last_ack");
|
2017-08-31 08:08:40 +08:00
|
|
|
assert_eq!(s1.remote_last_win, s2.remote_last_win, "remote_last_win");
|
2017-01-14 20:56:58 +08:00
|
|
|
assert_eq!(s1.remote_win_len, s2.remote_win_len, "remote_win_len");
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
assert_eq!(s1.timer, s2.timer, "timer");
|
|
|
|
})
|
2017-01-14 20:56:58 +08:00
|
|
|
}
|
|
|
|
|
2017-12-22 17:50:26 +08:00
|
|
|
#[cfg(feature = "log")]
|
2016-12-25 05:52:23 +08:00
|
|
|
fn init_logger() {
|
2019-06-22 16:31:11 +08:00
|
|
|
struct Logger;
|
|
|
|
static LOGGER: Logger = Logger;
|
2016-12-25 05:52:23 +08:00
|
|
|
|
|
|
|
impl log::Log for Logger {
|
2019-06-22 16:31:11 +08:00
|
|
|
fn enabled(&self, _metadata: &log::Metadata) -> bool {
|
2016-12-25 05:52:23 +08:00
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2019-06-22 16:31:11 +08:00
|
|
|
fn log(&self, record: &log::Record) {
|
2016-12-25 05:52:23 +08:00
|
|
|
println!("{}", record.args());
|
|
|
|
}
|
2019-06-22 16:31:11 +08:00
|
|
|
|
|
|
|
fn flush(&self) {
|
|
|
|
}
|
2016-12-25 05:52:23 +08:00
|
|
|
}
|
|
|
|
|
2019-06-22 16:31:11 +08:00
|
|
|
// If it fails, that just means we've already set it to the same value.
|
|
|
|
let _ = log::set_logger(&LOGGER);
|
2019-06-22 16:31:11 +08:00
|
|
|
log::set_max_level(log::LevelFilter::Trace);
|
2016-12-25 05:52:23 +08:00
|
|
|
|
2020-12-26 14:59:24 +08:00
|
|
|
println!();
|
2016-12-25 05:52:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn socket() -> TcpSocket<'static> {
|
2018-08-20 04:32:27 +08:00
|
|
|
socket_with_buffer_sizes(64, 64)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn socket_with_buffer_sizes(tx_len: usize, rx_len: usize) -> TcpSocket<'static> {
|
2017-12-22 17:50:26 +08:00
|
|
|
#[cfg(feature = "log")]
|
2016-12-25 05:52:23 +08:00
|
|
|
init_logger();
|
|
|
|
|
2018-08-20 04:32:27 +08:00
|
|
|
let rx_buffer = SocketBuffer::new(vec![0; rx_len]);
|
|
|
|
let tx_buffer = SocketBuffer::new(vec![0; tx_len]);
|
2018-01-28 22:36:23 +08:00
|
|
|
TcpSocket::new(rx_buffer, tx_buffer)
|
2016-12-25 05:52:23 +08:00
|
|
|
}
|
|
|
|
|
2019-01-01 04:45:20 +08:00
|
|
|
fn socket_syn_received_with_buffer_sizes(
|
|
|
|
tx_len: usize,
|
|
|
|
rx_len: usize
|
|
|
|
) -> TcpSocket<'static> {
|
|
|
|
let mut s = socket_with_buffer_sizes(tx_len, rx_len);
|
2017-12-24 21:28:59 +08:00
|
|
|
s.state = State::SynReceived;
|
|
|
|
s.local_endpoint = LOCAL_END;
|
|
|
|
s.remote_endpoint = REMOTE_END;
|
|
|
|
s.local_seq_no = LOCAL_SEQ;
|
|
|
|
s.remote_seq_no = REMOTE_SEQ + 1;
|
|
|
|
s.remote_last_seq = LOCAL_SEQ;
|
|
|
|
s.remote_win_len = 256;
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
2019-01-01 04:45:20 +08:00
|
|
|
fn socket_syn_received() -> TcpSocket<'static> {
|
|
|
|
socket_syn_received_with_buffer_sizes(64, 64)
|
|
|
|
}
|
|
|
|
|
2017-12-24 21:28:59 +08:00
|
|
|
fn socket_syn_sent() -> TcpSocket<'static> {
|
|
|
|
let mut s = socket();
|
|
|
|
s.state = State::SynSent;
|
|
|
|
s.local_endpoint = IpEndpoint::new(MOCK_UNSPECIFIED, LOCAL_PORT);
|
|
|
|
s.remote_endpoint = REMOTE_END;
|
|
|
|
s.local_seq_no = LOCAL_SEQ;
|
|
|
|
s.remote_last_seq = LOCAL_SEQ;
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
2020-04-16 15:55:17 +08:00
|
|
|
fn socket_syn_sent_with_local_ipendpoint(local: IpEndpoint) -> TcpSocket<'static> {
|
|
|
|
let mut s = socket();
|
|
|
|
s.state = State::SynSent;
|
|
|
|
s.local_endpoint = local;
|
|
|
|
s.remote_endpoint = REMOTE_END;
|
|
|
|
s.local_seq_no = LOCAL_SEQ;
|
|
|
|
s.remote_last_seq = LOCAL_SEQ;
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
2019-01-01 04:45:20 +08:00
|
|
|
fn socket_established_with_buffer_sizes(tx_len: usize, rx_len: usize) -> TcpSocket<'static> {
|
|
|
|
let mut s = socket_syn_received_with_buffer_sizes(tx_len, rx_len);
|
2017-12-24 21:28:59 +08:00
|
|
|
s.state = State::Established;
|
|
|
|
s.local_seq_no = LOCAL_SEQ + 1;
|
|
|
|
s.remote_last_seq = LOCAL_SEQ + 1;
|
|
|
|
s.remote_last_ack = Some(REMOTE_SEQ + 1);
|
|
|
|
s.remote_last_win = 64;
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
2019-01-01 04:45:20 +08:00
|
|
|
fn socket_established() -> TcpSocket<'static> {
|
|
|
|
socket_established_with_buffer_sizes(64, 64)
|
|
|
|
}
|
|
|
|
|
2017-12-24 21:28:59 +08:00
|
|
|
fn socket_fin_wait_1() -> TcpSocket<'static> {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.state = State::FinWait1;
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
|
|
|
fn socket_fin_wait_2() -> TcpSocket<'static> {
|
|
|
|
let mut s = socket_fin_wait_1();
|
|
|
|
s.state = State::FinWait2;
|
|
|
|
s.local_seq_no = LOCAL_SEQ + 1 + 1;
|
|
|
|
s.remote_last_seq = LOCAL_SEQ + 1 + 1;
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
|
|
|
fn socket_closing() -> TcpSocket<'static> {
|
|
|
|
let mut s = socket_fin_wait_1();
|
|
|
|
s.state = State::Closing;
|
|
|
|
s.remote_last_seq = LOCAL_SEQ + 1 + 1;
|
|
|
|
s.remote_seq_no = REMOTE_SEQ + 1 + 1;
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
|
|
|
fn socket_time_wait(from_closing: bool) -> TcpSocket<'static> {
|
|
|
|
let mut s = socket_fin_wait_2();
|
|
|
|
s.state = State::TimeWait;
|
|
|
|
s.remote_seq_no = REMOTE_SEQ + 1 + 1;
|
|
|
|
if from_closing {
|
|
|
|
s.remote_last_ack = Some(REMOTE_SEQ + 1 + 1);
|
|
|
|
}
|
2018-02-11 00:32:41 +08:00
|
|
|
s.timer = Timer::Close { expires_at: Instant::from_secs(1) + CLOSE_DELAY };
|
2017-12-24 21:28:59 +08:00
|
|
|
s
|
|
|
|
}
|
|
|
|
|
|
|
|
fn socket_close_wait() -> TcpSocket<'static> {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.state = State::CloseWait;
|
|
|
|
s.remote_seq_no = REMOTE_SEQ + 1 + 1;
|
|
|
|
s.remote_last_ack = Some(REMOTE_SEQ + 1 + 1);
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
|
|
|
fn socket_last_ack() -> TcpSocket<'static> {
|
|
|
|
let mut s = socket_close_wait();
|
|
|
|
s.state = State::LastAck;
|
|
|
|
s
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2016-12-26 21:54:26 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for the CLOSED state.
|
|
|
|
// =========================================================================================//
|
2016-12-26 20:44:41 +08:00
|
|
|
#[test]
|
2017-01-17 00:58:45 +08:00
|
|
|
fn test_closed_reject() {
|
2017-09-15 14:05:41 +08:00
|
|
|
let s = socket();
|
2016-12-28 06:43:16 +08:00
|
|
|
assert_eq!(s.state, State::Closed);
|
2016-12-26 20:44:41 +08:00
|
|
|
|
2017-09-08 08:53:19 +08:00
|
|
|
let tcp_repr = TcpRepr {
|
2016-12-26 20:44:41 +08:00
|
|
|
control: TcpControl::Syn,
|
|
|
|
..SEND_TEMPL
|
2017-09-08 08:53:19 +08:00
|
|
|
};
|
|
|
|
assert!(!s.accepts(&SEND_IP_TEMPL, &tcp_repr));
|
2016-12-26 20:44:41 +08:00
|
|
|
}
|
|
|
|
|
2017-01-17 08:24:47 +08:00
|
|
|
#[test]
|
|
|
|
fn test_closed_reject_after_listen() {
|
|
|
|
let mut s = socket();
|
|
|
|
s.listen(LOCAL_END).unwrap();
|
|
|
|
s.close();
|
|
|
|
|
2017-09-08 08:53:19 +08:00
|
|
|
let tcp_repr = TcpRepr {
|
2017-01-17 08:24:47 +08:00
|
|
|
control: TcpControl::Syn,
|
|
|
|
..SEND_TEMPL
|
2017-09-08 08:53:19 +08:00
|
|
|
};
|
|
|
|
assert!(!s.accepts(&SEND_IP_TEMPL, &tcp_repr));
|
2017-01-17 08:24:47 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
#[test]
|
|
|
|
fn test_closed_close() {
|
|
|
|
let mut s = socket();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
2016-12-26 21:54:26 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for the LISTEN state.
|
|
|
|
// =========================================================================================//
|
|
|
|
fn socket_listen() -> TcpSocket<'static> {
|
2016-12-26 20:51:47 +08:00
|
|
|
let mut s = socket();
|
|
|
|
s.state = State::Listen;
|
|
|
|
s.local_endpoint = IpEndpoint::new(IpAddress::default(), LOCAL_PORT);
|
2016-12-26 21:54:26 +08:00
|
|
|
s
|
|
|
|
}
|
2016-12-25 05:52:23 +08:00
|
|
|
|
2019-01-01 04:45:20 +08:00
|
|
|
#[test]
|
|
|
|
fn test_listen_sack_option() {
|
|
|
|
let mut s = socket_listen();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: None,
|
|
|
|
sack_permitted: false,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert!(!s.remote_has_sack);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
max_seg_size: Some(BASE_MSS),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
|
|
|
|
let mut s = socket_listen();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: None,
|
|
|
|
sack_permitted: true,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert!(s.remote_has_sack);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
max_seg_size: Some(BASE_MSS),
|
|
|
|
sack_permitted: true,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
|
2018-08-20 04:32:27 +08:00
|
|
|
#[test]
|
|
|
|
fn test_listen_syn_win_scale_buffers() {
|
|
|
|
for (buffer_size, shift_amt) in &[
|
|
|
|
(64, 0),
|
|
|
|
(128, 0),
|
|
|
|
(1024, 0),
|
|
|
|
(65535, 0),
|
|
|
|
(65536, 1),
|
|
|
|
(65537, 1),
|
|
|
|
(131071, 1),
|
|
|
|
(131072, 2),
|
|
|
|
(524287, 3),
|
|
|
|
(524288, 4),
|
|
|
|
(655350, 4),
|
|
|
|
(1048576, 5),
|
|
|
|
] {
|
|
|
|
let mut s = socket_with_buffer_sizes(64, *buffer_size);
|
|
|
|
s.state = State::Listen;
|
|
|
|
s.local_endpoint = IpEndpoint::new(IpAddress::default(), LOCAL_PORT);
|
|
|
|
assert_eq!(s.remote_win_shift, *shift_amt);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: None,
|
|
|
|
window_scale: Some(0),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.remote_win_shift, *shift_amt);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
max_seg_size: Some(BASE_MSS),
|
|
|
|
window_scale: Some(*shift_amt),
|
|
|
|
window_len: cmp::min(*buffer_size >> *shift_amt, 65535) as u16,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-14 20:56:58 +08:00
|
|
|
#[test]
|
|
|
|
fn test_listen_sanity() {
|
|
|
|
let mut s = socket();
|
|
|
|
s.listen(LOCAL_PORT).unwrap();
|
|
|
|
sanity!(s, socket_listen());
|
|
|
|
}
|
|
|
|
|
2017-03-05 11:52:47 +08:00
|
|
|
#[test]
|
|
|
|
fn test_listen_validation() {
|
|
|
|
let mut s = socket();
|
2017-07-27 21:51:02 +08:00
|
|
|
assert_eq!(s.listen(0), Err(Error::Unaddressable));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_listen_twice() {
|
|
|
|
let mut s = socket();
|
|
|
|
assert_eq!(s.listen(80), Ok(()));
|
|
|
|
assert_eq!(s.listen(80), Err(Error::Illegal));
|
2017-03-05 11:52:47 +08:00
|
|
|
}
|
|
|
|
|
2017-01-14 20:56:58 +08:00
|
|
|
#[test]
|
|
|
|
fn test_listen_syn() {
|
|
|
|
let mut s = socket_listen();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: None,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
sanity!(s, socket_syn_received());
|
|
|
|
}
|
|
|
|
|
2016-12-26 21:54:26 +08:00
|
|
|
#[test]
|
2017-01-17 12:43:51 +08:00
|
|
|
fn test_listen_syn_reject_ack() {
|
2017-09-15 14:05:41 +08:00
|
|
|
let s = socket_listen();
|
2017-09-08 08:53:19 +08:00
|
|
|
|
|
|
|
let tcp_repr = TcpRepr {
|
2016-12-25 05:52:23 +08:00
|
|
|
control: TcpControl::Syn,
|
2016-12-25 19:09:50 +08:00
|
|
|
seq_number: REMOTE_SEQ,
|
2016-12-26 21:54:26 +08:00
|
|
|
ack_number: Some(LOCAL_SEQ),
|
2016-12-25 05:52:23 +08:00
|
|
|
..SEND_TEMPL
|
2017-09-08 08:53:19 +08:00
|
|
|
};
|
|
|
|
assert!(!s.accepts(&SEND_IP_TEMPL, &tcp_repr));
|
|
|
|
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.state, State::Listen);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_listen_rst() {
|
|
|
|
let mut s = socket_listen();
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-26 21:54:26 +08:00
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: None,
|
2016-12-25 05:52:23 +08:00
|
|
|
..SEND_TEMPL
|
2017-08-01 19:15:12 +08:00
|
|
|
}, Err(Error::Dropped));
|
2016-12-25 05:52:23 +08:00
|
|
|
}
|
2016-12-25 19:09:50 +08:00
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
#[test]
|
|
|
|
fn test_listen_close() {
|
|
|
|
let mut s = socket_listen();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
2016-12-26 21:54:26 +08:00
|
|
|
// =========================================================================================//
|
2016-12-28 07:28:57 +08:00
|
|
|
// Tests for the SYN-RECEIVED state.
|
2016-12-26 21:54:26 +08:00
|
|
|
// =========================================================================================//
|
2016-12-26 20:44:41 +08:00
|
|
|
|
2017-01-14 19:22:19 +08:00
|
|
|
#[test]
|
2017-07-24 07:51:56 +08:00
|
|
|
fn test_syn_received_ack() {
|
2017-01-14 19:22:19 +08:00
|
|
|
let mut s = socket_syn_received();
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS),
|
2017-01-14 19:22:19 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
2017-01-14 20:56:58 +08:00
|
|
|
assert_eq!(s.state, State::Established);
|
|
|
|
sanity!(s, socket_established());
|
2017-01-14 19:22:19 +08:00
|
|
|
}
|
|
|
|
|
2017-07-24 07:51:56 +08:00
|
|
|
#[test]
|
|
|
|
fn test_syn_received_fin() {
|
|
|
|
let mut s = socket_syn_received();
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS),
|
2017-07-24 07:51:56 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..SEND_TEMPL
|
2017-09-06 07:23:50 +08:00
|
|
|
});
|
|
|
|
recv!(s, [TcpRepr {
|
2017-08-25 13:50:43 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6 + 1),
|
|
|
|
window_len: 58,
|
|
|
|
..RECV_TEMPL
|
2017-09-06 07:23:50 +08:00
|
|
|
}]);
|
2017-07-24 07:51:56 +08:00
|
|
|
assert_eq!(s.state, State::CloseWait);
|
|
|
|
sanity!(s, TcpSocket {
|
2017-08-31 06:40:07 +08:00
|
|
|
remote_last_ack: Some(REMOTE_SEQ + 1 + 6 + 1),
|
2017-08-31 08:08:40 +08:00
|
|
|
remote_last_win: 58,
|
2017-07-24 07:51:56 +08:00
|
|
|
..socket_close_wait()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-12-26 20:44:41 +08:00
|
|
|
#[test]
|
2016-12-26 21:54:26 +08:00
|
|
|
fn test_syn_received_rst() {
|
|
|
|
let mut s = socket_syn_received();
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS),
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-26 21:54:26 +08:00
|
|
|
control: TcpControl::Rst,
|
2017-01-14 19:22:19 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
2016-12-26 20:51:47 +08:00
|
|
|
ack_number: Some(LOCAL_SEQ),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.state, State::Listen);
|
|
|
|
assert_eq!(s.local_endpoint, IpEndpoint::new(IpAddress::Unspecified, LOCAL_END.port));
|
|
|
|
assert_eq!(s.remote_endpoint, IpEndpoint::default());
|
2016-12-26 21:10:39 +08:00
|
|
|
}
|
|
|
|
|
2018-06-24 22:35:29 +08:00
|
|
|
#[test]
|
|
|
|
fn test_syn_received_no_window_scaling() {
|
|
|
|
let mut s = socket_listen();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: None,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state(), State::SynReceived);
|
|
|
|
assert_eq!(s.local_endpoint(), LOCAL_END);
|
|
|
|
assert_eq!(s.remote_endpoint(), REMOTE_END);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
max_seg_size: Some(BASE_MSS),
|
|
|
|
window_scale: None,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
window_scale: None,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.remote_win_scale, None);
|
|
|
|
}
|
|
|
|
|
2018-08-20 04:32:27 +08:00
|
|
|
#[test]
|
|
|
|
fn test_syn_received_window_scaling() {
|
|
|
|
for scale in 0..14 {
|
|
|
|
let mut s = socket_listen();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: None,
|
|
|
|
window_scale: Some(scale),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state(), State::SynReceived);
|
|
|
|
assert_eq!(s.local_endpoint(), LOCAL_END);
|
|
|
|
assert_eq!(s.remote_endpoint(), REMOTE_END);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
max_seg_size: Some(BASE_MSS),
|
|
|
|
window_scale: Some(0),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
window_scale: None,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.remote_win_scale, Some(scale));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
#[test]
|
|
|
|
fn test_syn_received_close() {
|
|
|
|
let mut s = socket_syn_received();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::FinWait1);
|
|
|
|
}
|
|
|
|
|
2016-12-26 21:54:26 +08:00
|
|
|
// =========================================================================================//
|
2016-12-28 07:28:57 +08:00
|
|
|
// Tests for the SYN-SENT state.
|
2016-12-26 21:54:26 +08:00
|
|
|
// =========================================================================================//
|
2016-12-26 21:10:39 +08:00
|
|
|
|
2017-03-05 11:52:47 +08:00
|
|
|
#[test]
|
|
|
|
fn test_connect_validation() {
|
|
|
|
let mut s = socket();
|
2017-12-24 21:28:59 +08:00
|
|
|
assert_eq!(s.connect((IpAddress::Unspecified, 80), LOCAL_END),
|
2017-07-27 20:27:33 +08:00
|
|
|
Err(Error::Unaddressable));
|
2017-12-24 21:28:59 +08:00
|
|
|
assert_eq!(s.connect(REMOTE_END, (MOCK_UNSPECIFIED, 0)),
|
2017-07-27 20:27:33 +08:00
|
|
|
Err(Error::Unaddressable));
|
2017-12-24 21:28:59 +08:00
|
|
|
assert_eq!(s.connect((MOCK_UNSPECIFIED, 0), LOCAL_END),
|
2017-07-27 20:27:33 +08:00
|
|
|
Err(Error::Unaddressable));
|
|
|
|
assert_eq!(s.connect((IpAddress::Unspecified, 80), LOCAL_END),
|
|
|
|
Err(Error::Unaddressable));
|
2020-04-16 15:55:17 +08:00
|
|
|
s.connect(REMOTE_END, LOCAL_END).expect("Connect failed with valid parameters");
|
|
|
|
assert_eq!(s.local_endpoint(), LOCAL_END);
|
|
|
|
assert_eq!(s.remote_endpoint(), REMOTE_END);
|
2017-03-05 11:52:47 +08:00
|
|
|
}
|
|
|
|
|
2017-07-24 07:07:55 +08:00
|
|
|
#[test]
|
|
|
|
fn test_connect() {
|
|
|
|
let mut s = socket();
|
|
|
|
s.local_seq_no = LOCAL_SEQ;
|
|
|
|
s.connect(REMOTE_END, LOCAL_END.port).unwrap();
|
2017-12-24 21:28:59 +08:00
|
|
|
assert_eq!(s.local_endpoint, IpEndpoint::new(MOCK_UNSPECIFIED, LOCAL_END.port));
|
2017-07-24 07:07:55 +08:00
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: None,
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS),
|
2018-06-24 22:35:29 +08:00
|
|
|
window_scale: Some(0),
|
2019-01-01 04:45:20 +08:00
|
|
|
sack_permitted: true,
|
2017-07-24 07:07:55 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS - 80),
|
2018-06-24 22:35:29 +08:00
|
|
|
window_scale: Some(0),
|
2017-07-24 07:07:55 +08:00
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.local_endpoint, LOCAL_END);
|
|
|
|
}
|
|
|
|
|
2017-07-27 20:27:33 +08:00
|
|
|
#[test]
|
|
|
|
fn test_connect_unspecified_local() {
|
|
|
|
let mut s = socket();
|
2017-12-24 21:28:59 +08:00
|
|
|
assert_eq!(s.connect(REMOTE_END, (MOCK_UNSPECIFIED, 80)),
|
2017-07-27 20:27:33 +08:00
|
|
|
Ok(()));
|
|
|
|
s.abort();
|
|
|
|
assert_eq!(s.connect(REMOTE_END, (IpAddress::Unspecified, 80)),
|
|
|
|
Ok(()));
|
|
|
|
s.abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_connect_specified_local() {
|
|
|
|
let mut s = socket();
|
2017-12-24 21:28:59 +08:00
|
|
|
assert_eq!(s.connect(REMOTE_END, (MOCK_IP_ADDR_2, 80)),
|
2017-07-27 20:27:33 +08:00
|
|
|
Ok(()));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_connect_twice() {
|
|
|
|
let mut s = socket();
|
|
|
|
assert_eq!(s.connect(REMOTE_END, (IpAddress::Unspecified, 80)),
|
|
|
|
Ok(()));
|
|
|
|
assert_eq!(s.connect(REMOTE_END, (IpAddress::Unspecified, 80)),
|
|
|
|
Err(Error::Illegal));
|
|
|
|
}
|
|
|
|
|
2017-03-05 11:52:47 +08:00
|
|
|
#[test]
|
|
|
|
fn test_syn_sent_sanity() {
|
|
|
|
let mut s = socket();
|
|
|
|
s.local_seq_no = LOCAL_SEQ;
|
|
|
|
s.connect(REMOTE_END, LOCAL_END).unwrap();
|
2020-04-16 15:55:17 +08:00
|
|
|
sanity!(s, socket_syn_sent_with_local_ipendpoint(LOCAL_END));
|
2017-03-05 11:52:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_syn_sent_syn_ack() {
|
|
|
|
let mut s = socket_syn_sent();
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: None,
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS),
|
2018-06-24 22:35:29 +08:00
|
|
|
window_scale: Some(0),
|
2019-01-01 04:45:20 +08:00
|
|
|
sack_permitted: true,
|
2017-03-05 11:52:47 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS - 80),
|
2018-06-24 22:35:29 +08:00
|
|
|
window_scale: Some(0),
|
2017-03-05 11:52:47 +08:00
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2017-08-25 14:47:12 +08:00
|
|
|
recv!(s, time 1000, Err(Error::Exhausted));
|
2017-03-05 11:52:47 +08:00
|
|
|
assert_eq!(s.state, State::Established);
|
2017-08-25 14:47:12 +08:00
|
|
|
sanity!(s, socket_established());
|
2017-03-05 11:52:47 +08:00
|
|
|
}
|
|
|
|
|
2016-12-26 21:54:26 +08:00
|
|
|
#[test]
|
|
|
|
fn test_syn_sent_rst() {
|
|
|
|
let mut s = socket_syn_sent();
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-26 21:54:26 +08:00
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: REMOTE_SEQ,
|
2017-03-05 13:31:12 +08:00
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
2016-12-26 21:54:26 +08:00
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_syn_sent_rst_no_ack() {
|
|
|
|
let mut s = socket_syn_sent();
|
2016-12-26 21:10:39 +08:00
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: None,
|
|
|
|
..SEND_TEMPL
|
2017-08-25 11:52:30 +08:00
|
|
|
}, Err(Error::Dropped));
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.state, State::SynSent);
|
2016-12-26 21:10:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2016-12-26 21:54:26 +08:00
|
|
|
fn test_syn_sent_rst_bad_ack() {
|
|
|
|
let mut s = socket_syn_sent();
|
2016-12-26 21:10:39 +08:00
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: REMOTE_SEQ,
|
2016-12-28 02:34:13 +08:00
|
|
|
ack_number: Some(TcpSeqNumber(1234)),
|
2016-12-26 21:10:39 +08:00
|
|
|
..SEND_TEMPL
|
2017-08-25 11:52:30 +08:00
|
|
|
}, Err(Error::Dropped));
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.state, State::SynSent);
|
2016-12-26 20:51:47 +08:00
|
|
|
}
|
|
|
|
|
2020-08-17 13:44:58 +08:00
|
|
|
#[test]
|
|
|
|
fn test_syn_sent_bad_ack() {
|
|
|
|
let mut s = socket_syn_sent();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::None,
|
|
|
|
ack_number: Some(TcpSeqNumber(1)),
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Err(Error::Dropped));
|
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
#[test]
|
|
|
|
fn test_syn_sent_close() {
|
|
|
|
let mut s = socket();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
2018-08-20 04:32:27 +08:00
|
|
|
#[test]
|
|
|
|
fn test_syn_sent_win_scale_buffers() {
|
|
|
|
for (buffer_size, shift_amt) in &[
|
|
|
|
(64, 0),
|
|
|
|
(128, 0),
|
|
|
|
(1024, 0),
|
|
|
|
(65535, 0),
|
|
|
|
(65536, 1),
|
|
|
|
(65537, 1),
|
|
|
|
(131071, 1),
|
|
|
|
(131072, 2),
|
|
|
|
(524287, 3),
|
|
|
|
(524288, 4),
|
|
|
|
(655350, 4),
|
|
|
|
(1048576, 5),
|
|
|
|
] {
|
|
|
|
let mut s = socket_with_buffer_sizes(64, *buffer_size);
|
|
|
|
assert_eq!(s.remote_win_shift, *shift_amt);
|
|
|
|
s.connect(REMOTE_END, LOCAL_END).unwrap();
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
ack_number: None,
|
|
|
|
max_seg_size: Some(BASE_MSS),
|
|
|
|
window_scale: Some(*shift_amt),
|
|
|
|
window_len: cmp::min(*buffer_size >> *shift_amt, 65535) as u16,
|
2019-01-01 04:45:20 +08:00
|
|
|
sack_permitted: true,
|
2018-08-20 04:32:27 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 21:54:26 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for the ESTABLISHED state.
|
|
|
|
// =========================================================================================//
|
|
|
|
|
|
|
|
#[test]
|
2016-12-27 00:59:39 +08:00
|
|
|
fn test_established_recv() {
|
2016-12-26 21:54:26 +08:00
|
|
|
let mut s = socket_established();
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-26 21:54:26 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..SEND_TEMPL
|
2017-09-06 07:23:50 +08:00
|
|
|
});
|
|
|
|
recv!(s, [TcpRepr {
|
2016-12-26 21:54:26 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
2016-12-27 00:29:33 +08:00
|
|
|
window_len: 58,
|
2016-12-26 21:54:26 +08:00
|
|
|
..RECV_TEMPL
|
2017-09-06 07:23:50 +08:00
|
|
|
}]);
|
2017-09-08 05:17:31 +08:00
|
|
|
assert_eq!(s.rx_buffer.dequeue_many(6), &b"abcdef"[..]);
|
2016-12-26 21:54:26 +08:00
|
|
|
}
|
2016-12-26 20:44:41 +08:00
|
|
|
|
2019-01-01 04:45:20 +08:00
|
|
|
fn setup_rfc2018_cases() -> (TcpSocket<'static>, Vec<u8>) {
|
|
|
|
// This is a utility function used by the tests for RFC 2018 cases. It configures a socket
|
|
|
|
// in a particular way suitable for those cases.
|
|
|
|
//
|
|
|
|
// RFC 2018: Assume the left window edge is 5000 and that the data transmitter sends [...]
|
|
|
|
// segments, each containing 500 data bytes.
|
|
|
|
let mut s = socket_established_with_buffer_sizes(4000, 4000);
|
|
|
|
s.remote_has_sack = true;
|
|
|
|
|
|
|
|
// create a segment that is 500 bytes long
|
|
|
|
let mut segment: Vec<u8> = Vec::with_capacity(500);
|
|
|
|
|
|
|
|
// move the last ack to 5000 by sending ten of them
|
|
|
|
for _ in 0..50 { segment.extend_from_slice(b"abcdefghij") }
|
|
|
|
for offset in (0..5000).step_by(500) {
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1 + offset,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &segment,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + offset + 500),
|
|
|
|
window_len: 3500,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
s.recv(|data| {
|
|
|
|
assert_eq!(data.len(), 500);
|
|
|
|
assert_eq!(data, segment.as_slice());
|
|
|
|
(500, ())
|
|
|
|
}).unwrap();
|
|
|
|
}
|
|
|
|
assert_eq!(s.remote_last_win, 3500);
|
|
|
|
(s, segment)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_established_rfc2018_cases() {
|
|
|
|
// This test case verifies the exact scenarios described on pages 8-9 of RFC 2018. Please
|
|
|
|
// ensure its behavior does not deviate from those scenarios.
|
|
|
|
|
|
|
|
let (mut s, segment) = setup_rfc2018_cases();
|
|
|
|
// RFC 2018:
|
|
|
|
//
|
|
|
|
// Case 2: The first segment is dropped but the remaining 7 are received.
|
|
|
|
//
|
|
|
|
// Upon receiving each of the last seven packets, the data receiver will return a TCP ACK
|
|
|
|
// segment that acknowledges sequence number 5000 and contains a SACK option specifying one
|
|
|
|
// block of queued data:
|
|
|
|
//
|
|
|
|
// Triggering ACK Left Edge Right Edge
|
|
|
|
// Segment
|
|
|
|
//
|
|
|
|
// 5000 (lost)
|
|
|
|
// 5500 5000 5500 6000
|
|
|
|
// 6000 5000 5500 6500
|
|
|
|
// 6500 5000 5500 7000
|
|
|
|
// 7000 5000 5500 7500
|
|
|
|
// 7500 5000 5500 8000
|
|
|
|
// 8000 5000 5500 8500
|
|
|
|
// 8500 5000 5500 9000
|
|
|
|
//
|
|
|
|
for offset in (500..3500).step_by(500) {
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1 + offset + 5000,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &segment,
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 5000),
|
|
|
|
window_len: 4000,
|
|
|
|
sack_ranges: [
|
|
|
|
Some((REMOTE_SEQ.0 as u32 + 1 + 5500,
|
|
|
|
REMOTE_SEQ.0 as u32 + 1 + 5500 + offset as u32)),
|
|
|
|
None, None],
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-20 04:32:27 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_sliding_window_recv() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
// Update our scaling parameters for a TCP with a scaled buffer.
|
|
|
|
assert_eq!(s.rx_buffer.len(), 0);
|
|
|
|
s.rx_buffer = SocketBuffer::new(vec![0; 262143]);
|
|
|
|
s.assembler = Assembler::new(s.rx_buffer.capacity());
|
|
|
|
s.remote_win_scale = Some(0);
|
|
|
|
s.remote_last_win = 65535;
|
|
|
|
s.remote_win_shift = 2;
|
|
|
|
|
|
|
|
// Create a TCP segment that will mostly fill an IP frame.
|
|
|
|
let mut segment: Vec<u8> = Vec::with_capacity(1400);
|
|
|
|
for _ in 0..100 { segment.extend_from_slice(b"abcdefghijklmn") }
|
|
|
|
assert_eq!(segment.len(), 1400);
|
|
|
|
|
|
|
|
// Send the frame
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &segment,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
|
|
|
|
// Ensure that the received window size is shifted right by 2.
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1400),
|
|
|
|
window_len: 65185,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
|
2016-12-26 22:24:17 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_send() {
|
|
|
|
let mut s = socket_established();
|
2016-12-27 00:59:39 +08:00
|
|
|
// First roundtrip after establishing.
|
2016-12-31 16:35:07 +08:00
|
|
|
s.send_slice(b"abcdef").unwrap();
|
2016-12-26 22:24:17 +08:00
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
assert_eq!(s.tx_buffer.len(), 6);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-26 22:24:17 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-26 22:24:17 +08:00
|
|
|
assert_eq!(s.tx_buffer.len(), 0);
|
2016-12-27 00:59:39 +08:00
|
|
|
// Second roundtrip.
|
2016-12-31 16:35:07 +08:00
|
|
|
s.send_slice(b"foobar").unwrap();
|
2016-12-27 00:59:39 +08:00
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"foobar"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-27 00:59:39 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6 + 6),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-27 00:59:39 +08:00
|
|
|
assert_eq!(s.tx_buffer.len(), 0);
|
2016-12-26 22:24:17 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 04:39:46 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_send_no_ack_send() {
|
|
|
|
let mut s = socket_established();
|
2016-12-31 16:35:07 +08:00
|
|
|
s.send_slice(b"abcdef").unwrap();
|
2016-12-28 04:39:46 +08:00
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2016-12-31 16:35:07 +08:00
|
|
|
s.send_slice(b"foobar").unwrap();
|
2016-12-28 04:39:46 +08:00
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"foobar"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
|
2016-12-28 04:08:50 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_send_buf_gt_win() {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
let mut data = [0; 32];
|
|
|
|
for (i, elem) in data.iter_mut().enumerate() {
|
|
|
|
*elem = i as u8
|
|
|
|
}
|
|
|
|
|
2016-12-28 04:08:50 +08:00
|
|
|
let mut s = socket_established();
|
|
|
|
s.remote_win_len = 16;
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
s.send_slice(&data[..]).unwrap();
|
2016-12-28 04:08:50 +08:00
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
payload: &data[0..16],
|
|
|
|
..RECV_TEMPL
|
2016-12-28 04:08:50 +08:00
|
|
|
}]);
|
|
|
|
}
|
|
|
|
|
2017-11-13 16:45:07 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_send_wrap() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
let local_seq_start = TcpSeqNumber(i32::MAX - 1);
|
|
|
|
s.local_seq_no = local_seq_start + 1;
|
|
|
|
s.remote_last_seq = local_seq_start + 1;
|
|
|
|
s.send_slice(b"abc").unwrap();
|
|
|
|
recv!(s, time 1000, Ok(TcpRepr {
|
|
|
|
seq_number: local_seq_start + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2016-12-26 21:54:26 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_no_ack() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: None,
|
|
|
|
..SEND_TEMPL
|
2017-08-25 11:52:30 +08:00
|
|
|
}, Err(Error::Dropped));
|
2016-12-26 21:54:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_established_bad_ack() {
|
|
|
|
let mut s = socket_established();
|
2016-12-26 20:44:41 +08:00
|
|
|
// Already acknowledged data.
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
2016-12-28 02:34:13 +08:00
|
|
|
ack_number: Some(TcpSeqNumber(LOCAL_SEQ.0 - 1)),
|
2016-12-26 20:44:41 +08:00
|
|
|
..SEND_TEMPL
|
2017-01-17 00:58:45 +08:00
|
|
|
}, Err(Error::Dropped));
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.local_seq_no, LOCAL_SEQ + 1);
|
2016-12-26 20:44:41 +08:00
|
|
|
// Data not yet transmitted.
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 10),
|
|
|
|
..SEND_TEMPL
|
2017-09-08 08:06:31 +08:00
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.local_seq_no, LOCAL_SEQ + 1);
|
2016-12-26 20:44:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2016-12-26 21:54:26 +08:00
|
|
|
fn test_established_bad_seq() {
|
|
|
|
let mut s = socket_established();
|
2016-12-26 20:44:41 +08:00
|
|
|
// Data outside of receive window.
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 256,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.remote_seq_no, REMOTE_SEQ + 1);
|
2016-12-26 20:44:41 +08:00
|
|
|
}
|
|
|
|
|
2016-12-27 21:34:48 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_fin() {
|
|
|
|
let mut s = socket_established();
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-27 21:34:48 +08:00
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-27 21:34:48 +08:00
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2017-01-14 20:56:58 +08:00
|
|
|
assert_eq!(s.state, State::CloseWait);
|
2017-08-25 14:47:12 +08:00
|
|
|
sanity!(s, socket_close_wait());
|
2016-12-27 21:34:48 +08:00
|
|
|
}
|
|
|
|
|
2018-01-06 04:54:06 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_fin_after_missing() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"123456"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
|
|
|
assert_eq!(s.state, State::Established);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6 + 6),
|
|
|
|
window_len: 52,
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
|
|
|
assert_eq!(s.state, State::Established);
|
|
|
|
}
|
|
|
|
|
2016-12-27 21:34:48 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_send_fin() {
|
|
|
|
let mut s = socket_established();
|
2016-12-31 16:35:07 +08:00
|
|
|
s.send_slice(b"abcdef").unwrap();
|
|
|
|
send!(s, TcpRepr {
|
2016-12-27 21:34:48 +08:00
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-27 21:34:48 +08:00
|
|
|
assert_eq!(s.state, State::CloseWait);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
|
2016-12-25 19:09:50 +08:00
|
|
|
#[test]
|
2016-12-26 21:54:26 +08:00
|
|
|
fn test_established_rst() {
|
|
|
|
let mut s = socket_established();
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-26 21:54:26 +08:00
|
|
|
control: TcpControl::Rst,
|
2016-12-25 19:09:50 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
2016-12-28 04:17:35 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_rst_no_ack() {
|
|
|
|
let mut s = socket_established();
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-28 04:17:35 +08:00
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: None,
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 04:17:35 +08:00
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_close() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::FinWait1);
|
2017-01-14 20:56:58 +08:00
|
|
|
sanity!(s, socket_fin_wait_1());
|
2016-12-28 06:43:16 +08:00
|
|
|
}
|
|
|
|
|
2017-01-17 09:24:51 +08:00
|
|
|
#[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
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
|
2020-06-12 06:29:04 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_rst_bad_seq() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: REMOTE_SEQ, // Wrong seq
|
|
|
|
ack_number: None,
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
|
|
|
|
|
|
|
assert_eq!(s.state, State::Established);
|
|
|
|
|
|
|
|
// Send something to advance seq by 1
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1, // correct seq
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"a"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
|
|
|
|
// Send wrong rst again, check that the challenge ack is correctly updated
|
|
|
|
// The ack number must be updated even if we don't call dispatch on the socket
|
|
|
|
// See https://github.com/smoltcp-rs/smoltcp/issues/338
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: REMOTE_SEQ, // Wrong seq
|
|
|
|
ack_number: None,
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 2), // this has changed
|
|
|
|
window_len: 63,
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
// =========================================================================================//
|
2016-12-28 07:28:57 +08:00
|
|
|
// Tests for the FIN-WAIT-1 state.
|
2016-12-28 06:43:16 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
|
2016-12-28 12:02:43 +08:00
|
|
|
#[test]
|
|
|
|
fn test_fin_wait_1_fin_ack() {
|
|
|
|
let mut s = socket_fin_wait_1();
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-28 12:02:43 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 12:02:43 +08:00
|
|
|
assert_eq!(s.state, State::FinWait2);
|
2017-08-30 03:47:04 +08:00
|
|
|
sanity!(s, socket_fin_wait_2());
|
2016-12-28 12:02:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_fin_wait_1_fin_fin() {
|
|
|
|
let mut s = socket_fin_wait_1();
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-28 12:02:43 +08:00
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 12:02:43 +08:00
|
|
|
assert_eq!(s.state, State::Closing);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
sanity!(s, socket_closing());
|
2016-12-28 12:02:43 +08:00
|
|
|
}
|
|
|
|
|
2017-01-23 20:07:07 +08:00
|
|
|
#[test]
|
|
|
|
fn test_fin_wait_1_fin_with_data_queued() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.remote_win_len = 6;
|
|
|
|
s.send_slice(b"abcdef123456").unwrap();
|
|
|
|
s.close();
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
recv!(s, Ok(TcpRepr {
|
2017-01-23 20:07:07 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}));
|
2017-01-25 13:36:42 +08:00
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state, State::FinWait1);
|
2017-01-23 20:07:07 +08:00
|
|
|
}
|
|
|
|
|
2020-06-12 04:01:48 +08:00
|
|
|
#[test]
|
|
|
|
fn test_fin_wait_1_recv() {
|
|
|
|
let mut s = socket_fin_wait_1();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state, State::FinWait1);
|
|
|
|
s.recv(|data| {
|
|
|
|
assert_eq!(data, b"abc");
|
|
|
|
(3, ())
|
|
|
|
}).unwrap();
|
|
|
|
}
|
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
#[test]
|
|
|
|
fn test_fin_wait_1_close() {
|
|
|
|
let mut s = socket_fin_wait_1();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::FinWait1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// =========================================================================================//
|
2016-12-28 07:28:57 +08:00
|
|
|
// Tests for the FIN-WAIT-2 state.
|
2016-12-28 06:43:16 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
|
2016-12-28 12:10:17 +08:00
|
|
|
#[test]
|
|
|
|
fn test_fin_wait_2_fin() {
|
|
|
|
let mut s = socket_fin_wait_2();
|
2017-04-22 00:01:49 +08:00
|
|
|
send!(s, time 1_000, TcpRepr {
|
2016-12-28 12:10:17 +08:00
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 12:10:17 +08:00
|
|
|
assert_eq!(s.state, State::TimeWait);
|
2017-01-14 20:56:58 +08:00
|
|
|
sanity!(s, socket_time_wait(false));
|
2016-12-28 12:10:17 +08:00
|
|
|
}
|
|
|
|
|
2020-06-12 04:01:48 +08:00
|
|
|
#[test]
|
|
|
|
fn test_fin_wait_2_recv() {
|
|
|
|
let mut s = socket_fin_wait_2();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state, State::FinWait2);
|
|
|
|
s.recv(|data| {
|
|
|
|
assert_eq!(data, b"abc");
|
|
|
|
(3, ())
|
|
|
|
}).unwrap();
|
2020-12-18 23:26:41 +08:00
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 3),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2020-06-12 04:01:48 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
#[test]
|
|
|
|
fn test_fin_wait_2_close() {
|
|
|
|
let mut s = socket_fin_wait_2();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::FinWait2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for the CLOSING state.
|
|
|
|
// =========================================================================================//
|
|
|
|
|
2016-12-28 12:56:49 +08:00
|
|
|
#[test]
|
|
|
|
fn test_closing_ack_fin() {
|
|
|
|
let mut s = socket_closing();
|
|
|
|
recv!(s, [TcpRepr {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1 + 1,
|
2016-12-28 12:56:49 +08:00
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2017-04-22 00:01:49 +08:00
|
|
|
send!(s, time 1_000, TcpRepr {
|
2016-12-28 12:56:49 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 12:56:49 +08:00
|
|
|
assert_eq!(s.state, State::TimeWait);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
sanity!(s, socket_time_wait(true));
|
2016-12-28 12:56:49 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
#[test]
|
|
|
|
fn test_closing_close() {
|
|
|
|
let mut s = socket_closing();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::Closing);
|
|
|
|
}
|
|
|
|
|
2016-12-28 12:10:17 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for the TIME-WAIT state.
|
|
|
|
// =========================================================================================//
|
|
|
|
|
2016-12-28 13:33:12 +08:00
|
|
|
#[test]
|
|
|
|
fn test_time_wait_from_fin_wait_2_ack() {
|
|
|
|
let mut s = socket_time_wait(false);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_time_wait_from_closing_no_ack() {
|
|
|
|
let mut s = socket_time_wait(true);
|
|
|
|
recv!(s, []);
|
|
|
|
}
|
|
|
|
|
2016-12-28 12:10:17 +08:00
|
|
|
#[test]
|
|
|
|
fn test_time_wait_close() {
|
2016-12-28 13:33:12 +08:00
|
|
|
let mut s = socket_time_wait(false);
|
2016-12-28 12:10:17 +08:00
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::TimeWait);
|
|
|
|
}
|
|
|
|
|
2017-04-22 00:01:49 +08:00
|
|
|
#[test]
|
|
|
|
fn test_time_wait_retransmit() {
|
|
|
|
let mut s = socket_time_wait(false);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2017-04-22 00:01:49 +08:00
|
|
|
send!(s, time 5_000, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
..SEND_TEMPL
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
2018-02-11 00:32:41 +08:00
|
|
|
assert_eq!(s.timer, Timer::Close { expires_at: Instant::from_secs(5) + CLOSE_DELAY });
|
2017-04-22 00:01:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_time_wait_timeout() {
|
|
|
|
let mut s = socket_time_wait(false);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
assert_eq!(s.state, State::TimeWait);
|
|
|
|
recv!(s, time 60_000, Err(Error::Exhausted));
|
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
2016-12-27 22:13:42 +08:00
|
|
|
// =========================================================================================//
|
2016-12-28 07:28:57 +08:00
|
|
|
// Tests for the CLOSE-WAIT state.
|
2016-12-27 22:13:42 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_close_wait_ack() {
|
|
|
|
let mut s = socket_close_wait();
|
2016-12-31 16:35:07 +08:00
|
|
|
s.send_slice(b"abcdef").unwrap();
|
2016-12-27 22:13:42 +08:00
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-27 22:13:42 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-27 22:13:42 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
#[test]
|
|
|
|
fn test_close_wait_close() {
|
|
|
|
let mut s = socket_close_wait();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::LastAck);
|
2017-01-14 20:56:58 +08:00
|
|
|
sanity!(s, socket_last_ack());
|
2016-12-28 06:43:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// =========================================================================================//
|
2016-12-28 07:28:57 +08:00
|
|
|
// Tests for the LAST-ACK state.
|
2016-12-28 06:43:16 +08:00
|
|
|
// =========================================================================================//
|
2016-12-28 07:27:33 +08:00
|
|
|
#[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);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-28 07:27:33 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 07:27:33 +08:00
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
2016-12-28 06:43:16 +08:00
|
|
|
#[test]
|
|
|
|
fn test_last_ack_close() {
|
|
|
|
let mut s = socket_last_ack();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::LastAck);
|
|
|
|
}
|
|
|
|
|
2016-12-26 21:54:26 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for transitioning through multiple states.
|
|
|
|
// =========================================================================================//
|
2017-12-24 21:28:59 +08:00
|
|
|
|
2016-12-26 21:54:26 +08:00
|
|
|
#[test]
|
|
|
|
fn test_listen() {
|
|
|
|
let mut s = socket();
|
2016-12-28 02:04:02 +08:00
|
|
|
s.listen(IpEndpoint::new(IpAddress::default(), LOCAL_PORT)).unwrap();
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.state, State::Listen);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_three_way_handshake() {
|
2016-12-28 12:02:43 +08:00
|
|
|
let mut s = socket_listen();
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-26 21:54:26 +08:00
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: None,
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.state(), State::SynReceived);
|
|
|
|
assert_eq!(s.local_endpoint(), LOCAL_END);
|
|
|
|
assert_eq!(s.remote_endpoint(), REMOTE_END);
|
2016-12-26 20:38:40 +08:00
|
|
|
recv!(s, [TcpRepr {
|
2016-12-26 21:54:26 +08:00
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS),
|
2016-12-25 19:19:50 +08:00
|
|
|
..RECV_TEMPL
|
2016-12-26 20:38:40 +08:00
|
|
|
}]);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-26 21:54:26 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-26 21:54:26 +08:00
|
|
|
assert_eq!(s.state(), State::Established);
|
|
|
|
assert_eq!(s.local_seq_no, LOCAL_SEQ + 1);
|
|
|
|
assert_eq!(s.remote_seq_no, REMOTE_SEQ + 1);
|
2016-12-25 19:09:50 +08:00
|
|
|
}
|
2016-12-28 12:02:43 +08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_remote_close() {
|
|
|
|
let mut s = socket_established();
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-28 12:02:43 +08:00
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 12:02:43 +08:00
|
|
|
assert_eq!(s.state, State::CloseWait);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::LastAck);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-28 12:02:43 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 13:33:12 +08:00
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_local_close() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::FinWait1);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-28 13:33:12 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 13:33:12 +08:00
|
|
|
assert_eq!(s.state, State::FinWait2);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-28 13:33:12 +08:00
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 13:33:12 +08:00
|
|
|
assert_eq!(s.state, State::TimeWait);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_simultaneous_close() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::FinWait1);
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
recv!(s, [TcpRepr { // due to reordering, this is logically located...
|
2016-12-28 13:33:12 +08:00
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-28 13:33:12 +08:00
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 13:33:12 +08:00
|
|
|
assert_eq!(s.state, State::Closing);
|
|
|
|
recv!(s, [TcpRepr {
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1 + 1,
|
2016-12-28 13:33:12 +08:00
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
// ... at this point
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-28 13:33:12 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
..SEND_TEMPL
|
2016-12-31 16:35:07 +08:00
|
|
|
});
|
2016-12-28 13:33:12 +08:00
|
|
|
assert_eq!(s.state, State::TimeWait);
|
|
|
|
recv!(s, []);
|
2016-12-28 12:02:43 +08:00
|
|
|
}
|
2016-12-31 09:24:55 +08:00
|
|
|
|
2017-01-25 11:58:03 +08:00
|
|
|
#[test]
|
|
|
|
fn test_simultaneous_close_combined_fin_ack() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::FinWait1);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state, State::TimeWait);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
}
|
|
|
|
|
2017-01-14 19:22:19 +08:00
|
|
|
#[test]
|
|
|
|
fn test_fin_with_data() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.send_slice(b"abcdef").unwrap();
|
|
|
|
s.close();
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}])
|
|
|
|
}
|
|
|
|
|
2017-01-24 05:02:28 +08:00
|
|
|
#[test]
|
2017-03-07 18:17:30 +08:00
|
|
|
fn test_mutual_close_with_data_1() {
|
2017-01-24 05:02:28 +08:00
|
|
|
let mut s = socket_established();
|
|
|
|
s.send_slice(b"abcdef").unwrap();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::FinWait1);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6 + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-03-07 18:17:30 +08:00
|
|
|
#[test]
|
|
|
|
fn test_mutual_close_with_data_2() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.send_slice(b"abcdef").unwrap();
|
|
|
|
s.close();
|
|
|
|
assert_eq!(s.state, State::FinWait1);
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6 + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state, State::FinWait2);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6 + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6 + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
assert_eq!(s.state, State::TimeWait);
|
|
|
|
}
|
|
|
|
|
2016-12-31 09:24:55 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for retransmission on packet loss.
|
|
|
|
// =========================================================================================//
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_duplicate_seq_ack() {
|
|
|
|
let mut s = socket_recved();
|
|
|
|
// remote retransmission
|
2016-12-31 16:35:07 +08:00
|
|
|
send!(s, TcpRepr {
|
2016-12-31 09:24:55 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..SEND_TEMPL
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}, Ok(Some(TcpRepr {
|
2017-06-26 16:09:27 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
|
|
|
window_len: 58,
|
|
|
|
..RECV_TEMPL
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
})));
|
2017-06-26 16:09:27 +08:00
|
|
|
}
|
|
|
|
|
2016-12-31 16:35:07 +08:00
|
|
|
#[test]
|
|
|
|
fn test_data_retransmit() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.send_slice(b"abcdef").unwrap();
|
|
|
|
recv!(s, time 1000, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 1050, Err(Error::Exhausted));
|
|
|
|
recv!(s, time 1100, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
}
|
2017-01-14 14:55:29 +08:00
|
|
|
|
2017-08-30 18:04:33 +08:00
|
|
|
#[test]
|
|
|
|
fn test_data_retransmit_bursts() {
|
|
|
|
let mut s = socket_established();
|
2020-12-18 23:06:23 +08:00
|
|
|
s.remote_mss = 6;
|
2017-08-30 18:04:33 +08:00
|
|
|
s.send_slice(b"abcdef012345").unwrap();
|
|
|
|
|
|
|
|
recv!(s, time 0, Ok(TcpRepr {
|
|
|
|
control: TcpControl::None,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}), exact);
|
|
|
|
recv!(s, time 0, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Psh,
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"012345"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}), exact);
|
|
|
|
recv!(s, time 0, Err(Error::Exhausted));
|
|
|
|
|
|
|
|
recv!(s, time 50, Err(Error::Exhausted));
|
|
|
|
|
|
|
|
recv!(s, time 100, Ok(TcpRepr {
|
|
|
|
control: TcpControl::None,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}), exact);
|
|
|
|
recv!(s, time 150, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Psh,
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"012345"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}), exact);
|
|
|
|
recv!(s, time 200, Err(Error::Exhausted));
|
|
|
|
}
|
|
|
|
|
2017-01-14 14:55:29 +08:00
|
|
|
#[test]
|
2017-01-14 19:22:19 +08:00
|
|
|
fn test_send_data_after_syn_ack_retransmit() {
|
|
|
|
let mut s = socket_syn_received();
|
|
|
|
recv!(s, time 50, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS),
|
2017-01-14 19:22:19 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 150, Ok(TcpRepr { // retransmit
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS),
|
2017-01-14 19:22:19 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state(), State::Established);
|
2017-01-14 14:55:29 +08:00
|
|
|
s.send_slice(b"abcdef").unwrap();
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}])
|
|
|
|
}
|
2017-01-14 19:22:19 +08:00
|
|
|
|
2017-10-28 16:32:08 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_retransmit_for_dup_ack() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
// Duplicate ACKs do not replace the retransmission timer
|
|
|
|
s.send_slice(b"abc").unwrap();
|
|
|
|
recv!(s, time 1000, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
// Retransmit timer is on because all data was sent
|
|
|
|
assert_eq!(s.tx_buffer.len(), 3);
|
|
|
|
// ACK nothing new
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
// Retransmit
|
|
|
|
recv!(s, time 4000, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2017-01-23 19:34:30 +08:00
|
|
|
#[test]
|
2017-01-25 13:42:02 +08:00
|
|
|
fn test_established_retransmit_reset_after_ack() {
|
2017-01-23 19:34:30 +08:00
|
|
|
let mut s = socket_established();
|
|
|
|
s.remote_win_len = 6;
|
|
|
|
s.send_slice(b"abcdef").unwrap();
|
|
|
|
s.send_slice(b"123456").unwrap();
|
|
|
|
s.send_slice(b"ABCDEF").unwrap();
|
|
|
|
recv!(s, time 1000, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
send!(s, time 1005, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6),
|
|
|
|
window_len: 6,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
recv!(s, time 1010, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"123456"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
send!(s, time 1015, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6 + 6),
|
|
|
|
window_len: 6,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
recv!(s, time 1020, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"ABCDEF"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
}
|
2017-01-25 13:42:02 +08:00
|
|
|
|
2017-12-23 03:31:04 +08:00
|
|
|
#[test]
|
|
|
|
fn test_established_queue_during_retransmission() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.remote_mss = 6;
|
|
|
|
s.send_slice(b"abcdef123456ABCDEF").unwrap();
|
|
|
|
recv!(s, time 1000, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
})); // this one is dropped
|
|
|
|
recv!(s, time 1005, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"123456"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
})); // this one is received
|
|
|
|
recv!(s, time 1010, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"ABCDEF"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
})); // also dropped
|
|
|
|
recv!(s, time 2000, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
})); // retransmission
|
|
|
|
send!(s, time 2005, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6 + 6),
|
|
|
|
..SEND_TEMPL
|
|
|
|
}); // acknowledgement of both segments
|
|
|
|
recv!(s, time 2010, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"ABCDEF"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
})); // retransmission of only unacknowledged data
|
|
|
|
}
|
|
|
|
|
2017-01-25 13:42:02 +08:00
|
|
|
#[test]
|
|
|
|
fn test_close_wait_retransmit_reset_after_ack() {
|
|
|
|
let mut s = socket_close_wait();
|
|
|
|
s.remote_win_len = 6;
|
|
|
|
s.send_slice(b"abcdef").unwrap();
|
|
|
|
s.send_slice(b"123456").unwrap();
|
|
|
|
s.send_slice(b"ABCDEF").unwrap();
|
|
|
|
recv!(s, time 1000, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
send!(s, time 1005, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6),
|
|
|
|
window_len: 6,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
recv!(s, time 1010, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
payload: &b"123456"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
send!(s, time 1015, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6 + 6),
|
|
|
|
window_len: 6,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
recv!(s, time 1020, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
payload: &b"ABCDEF"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
}
|
2017-01-25 14:01:58 +08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_fin_wait_1_retransmit_reset_after_ack() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.remote_win_len = 6;
|
|
|
|
s.send_slice(b"abcdef").unwrap();
|
|
|
|
s.send_slice(b"123456").unwrap();
|
|
|
|
s.send_slice(b"ABCDEF").unwrap();
|
|
|
|
s.close();
|
|
|
|
recv!(s, time 1000, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
send!(s, time 1005, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6),
|
|
|
|
window_len: 6,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
recv!(s, time 1010, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"123456"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
send!(s, time 1015, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 6 + 6),
|
|
|
|
window_len: 6,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
recv!(s, time 1020, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"ABCDEF"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
}
|
2017-01-27 11:06:52 +08:00
|
|
|
|
2018-05-18 00:28:27 +08:00
|
|
|
#[test]
|
|
|
|
fn test_fast_retransmit_after_triple_duplicate_ack() {
|
|
|
|
let mut s = socket_established();
|
2020-12-18 23:06:23 +08:00
|
|
|
s.remote_mss = 6;
|
2018-05-18 00:28:27 +08:00
|
|
|
|
2018-06-09 07:11:10 +08:00
|
|
|
// Normal ACK of previously recived segment
|
|
|
|
send!(s, time 0, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
|
|
|
|
// Send a long string of text divided into several packets
|
|
|
|
// because of previously recieved "window_len"
|
|
|
|
s.send_slice(b"xxxxxxyyyyyywwwwwwzzzzzz").unwrap();
|
|
|
|
// This packet is lost
|
2018-05-18 00:28:27 +08:00
|
|
|
recv!(s, time 1000, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"xxxxxx"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 1005, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2018-06-09 07:11:10 +08:00
|
|
|
payload: &b"yyyyyy"[..],
|
2018-05-18 00:28:27 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 1010, Ok(TcpRepr {
|
2018-06-09 07:11:10 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1 + (6 * 2),
|
2018-05-18 00:28:27 +08:00
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2018-06-09 07:11:10 +08:00
|
|
|
payload: &b"wwwwww"[..],
|
2018-05-18 00:28:27 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 1015, Ok(TcpRepr {
|
2018-06-09 07:11:10 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1 + (6 * 3),
|
2018-05-18 00:28:27 +08:00
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2018-06-09 07:11:10 +08:00
|
|
|
payload: &b"zzzzzz"[..],
|
2018-05-18 00:28:27 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
2018-06-09 07:11:10 +08:00
|
|
|
|
|
|
|
// First duplicate ACK
|
|
|
|
send!(s, time 1050, TcpRepr {
|
2018-05-18 00:28:27 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
2018-06-09 07:11:10 +08:00
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
2018-05-18 00:28:27 +08:00
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
2018-06-09 07:11:10 +08:00
|
|
|
// Second duplicate ACK
|
|
|
|
send!(s, time 1055, TcpRepr {
|
2018-05-18 00:28:27 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
2018-06-09 07:11:10 +08:00
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
2018-05-18 00:28:27 +08:00
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
2018-06-09 07:11:10 +08:00
|
|
|
// Third duplicate ACK
|
2018-05-18 00:28:27 +08:00
|
|
|
// Should trigger a fast retransmit of dropped packet
|
2018-06-09 07:11:10 +08:00
|
|
|
send!(s, time 1060, TcpRepr {
|
2018-05-18 00:28:27 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
2018-06-09 07:11:10 +08:00
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
2018-05-18 00:28:27 +08:00
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
2018-06-09 07:11:10 +08:00
|
|
|
|
2018-05-18 00:28:27 +08:00
|
|
|
// Fast retransmit packet
|
2018-06-09 07:11:10 +08:00
|
|
|
recv!(s, time 1100, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
2018-05-18 00:28:27 +08:00
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2018-06-09 07:11:10 +08:00
|
|
|
payload: &b"xxxxxx"[..],
|
2018-05-18 00:28:27 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
2018-06-09 07:11:10 +08:00
|
|
|
|
2018-06-12 14:19:04 +08:00
|
|
|
recv!(s, time 1105, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"yyyyyy"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 1110, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + (6 * 2),
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"wwwwww"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 1115, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + (6 * 3),
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"zzzzzz"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
|
|
|
|
// After all was send out, enter *normal* retransmission,
|
|
|
|
// don't stay in fast retransmission.
|
|
|
|
assert!(match s.timer {
|
|
|
|
Timer::Retransmit { expires_at, .. } => expires_at > Instant::from_millis(1115),
|
|
|
|
_ => false,
|
|
|
|
});
|
|
|
|
|
2018-05-18 00:28:27 +08:00
|
|
|
// ACK all recived segments
|
2018-06-09 07:11:10 +08:00
|
|
|
send!(s, time 1120, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + (6 * 4)),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_fast_retransmit_duplicate_detection_with_data() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
|
2018-06-12 14:19:48 +08:00
|
|
|
s.send_slice(b"abc").unwrap(); // This is lost
|
|
|
|
recv!(s, time 1000, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
|
2018-06-09 07:11:10 +08:00
|
|
|
// Normal ACK of previously recieved segment
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
// First duplicate
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
// Second duplicate
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
|
2018-06-12 14:19:48 +08:00
|
|
|
assert_eq!(s.local_rx_dup_acks, 2,
|
|
|
|
"duplicate ACK counter is not set");
|
|
|
|
|
2018-06-09 07:11:10 +08:00
|
|
|
// This packet has content, hence should not be detected
|
|
|
|
// as a duplicate ACK and should reset the duplicate ACK count
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"xxxxxx"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
|
|
|
|
recv!(s, [TcpRepr {
|
2018-06-12 14:19:48 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1 + 3,
|
2018-06-09 07:11:10 +08:00
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
|
|
|
window_len: 58,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
|
|
|
|
assert_eq!(s.local_rx_dup_acks, 0,
|
|
|
|
"duplicate ACK counter is not reset when reciving data");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_fast_retransmit_duplicate_detection() {
|
|
|
|
let mut s = socket_established();
|
2020-12-18 23:06:23 +08:00
|
|
|
s.remote_mss = 6;
|
2018-06-09 07:11:10 +08:00
|
|
|
|
|
|
|
// Normal ACK of previously recived segment
|
|
|
|
send!(s, time 0, TcpRepr {
|
2018-05-18 00:28:27 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
2018-06-09 07:11:10 +08:00
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
2018-05-18 00:28:27 +08:00
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
2018-06-09 07:11:10 +08:00
|
|
|
|
2018-06-12 14:19:48 +08:00
|
|
|
// First duplicate, should not be counted as there is nothing to resend
|
|
|
|
send!(s, time 0, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
|
|
|
|
assert_eq!(s.local_rx_dup_acks, 0,
|
|
|
|
"duplicate ACK counter is set but wound not transmit data");
|
|
|
|
|
2018-06-09 07:11:10 +08:00
|
|
|
// Send a long string of text divided into several packets
|
2020-12-18 23:06:23 +08:00
|
|
|
// because of small remote_mss
|
2018-06-09 07:11:10 +08:00
|
|
|
s.send_slice(b"xxxxxxyyyyyywwwwwwzzzzzz").unwrap();
|
|
|
|
|
|
|
|
// This packet is reordered in network
|
|
|
|
recv!(s, time 1000, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"xxxxxx"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 1005, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"yyyyyy"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 1010, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + (6 * 2),
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"wwwwww"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 1015, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + (6 * 3),
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"zzzzzz"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
|
|
|
|
// First duplicate ACK
|
|
|
|
send!(s, time 1050, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
// Second duplicate ACK
|
|
|
|
send!(s, time 1055, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
// Reordered packet arrives which should reset duplicate ACK count
|
|
|
|
send!(s, time 1060, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + (6 * 3)),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
|
|
|
|
assert_eq!(s.local_rx_dup_acks, 0,
|
|
|
|
"duplicate ACK counter is not reset when reciving ACK which updates send window");
|
|
|
|
|
|
|
|
// ACK all recived segments
|
|
|
|
send!(s, time 1120, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + (6 * 4)),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_fast_retransmit_dup_acks_counter() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
|
2018-06-12 14:19:48 +08:00
|
|
|
s.send_slice(b"abc").unwrap(); // This is lost
|
|
|
|
recv!(s, time 0, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
|
2018-06-09 07:11:10 +08:00
|
|
|
send!(s, time 0, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
|
|
|
|
// A lot of retransmits happen here
|
|
|
|
s.local_rx_dup_acks = u8::max_value() - 1;
|
|
|
|
|
|
|
|
// Send 3 more ACKs, which could overflow local_rx_dup_acks,
|
2019-06-22 14:50:58 +08:00
|
|
|
// but intended behaviour is that we saturate the bounds
|
2018-06-09 07:11:10 +08:00
|
|
|
// of local_rx_dup_acks
|
|
|
|
send!(s, time 0, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
send!(s, time 0, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
send!(s, time 0, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.local_rx_dup_acks, u8::max_value(), "duplicate ACK count should not overflow but saturate");
|
2018-05-18 00:28:27 +08:00
|
|
|
}
|
|
|
|
|
2017-08-30 18:04:33 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for window management.
|
|
|
|
// =========================================================================================//
|
|
|
|
|
2017-01-27 11:06:52 +08:00
|
|
|
#[test]
|
|
|
|
fn test_maximum_segment_size() {
|
|
|
|
let mut s = socket_listen();
|
|
|
|
s.tx_buffer = SocketBuffer::new(vec![0; 32767]);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: None,
|
|
|
|
max_seg_size: Some(1000),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS),
|
2017-01-27 11:06:52 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
window_len: 32767,
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
s.send_slice(&[0; 1200][..]).unwrap();
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
recv!(s, Ok(TcpRepr {
|
2017-01-27 11:06:52 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &[0; 1000][..],
|
|
|
|
..RECV_TEMPL
|
Radically simplify and optimize TCP packet dispatch.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.
2017-08-25 10:59:51 +08:00
|
|
|
}));
|
2017-01-27 11:06:52 +08:00
|
|
|
}
|
2017-03-07 19:21:49 +08:00
|
|
|
|
2020-06-25 07:51:33 +08:00
|
|
|
#[test]
|
|
|
|
fn test_close_wait_no_window_update() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &[1,2,3,4],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state, State::CloseWait);
|
|
|
|
|
|
|
|
// we ack the FIN, with the reduced window size.
|
|
|
|
recv!(s, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 6),
|
|
|
|
window_len: 60,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
|
|
|
|
let rx_buf = &mut [0; 32];
|
|
|
|
assert_eq!(s.recv_slice(rx_buf), Ok(4));
|
|
|
|
|
|
|
|
// check that we do NOT send a window update even if it has changed.
|
|
|
|
recv!(s, Err(Error::Exhausted));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_time_wait_no_window_update() {
|
|
|
|
let mut s = socket_fin_wait_2();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 2),
|
|
|
|
payload: &[1,2,3,4],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state, State::TimeWait);
|
|
|
|
|
|
|
|
// we ack the FIN, with the reduced window size.
|
|
|
|
recv!(s, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 2,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 6),
|
|
|
|
window_len: 60,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
|
|
|
|
let rx_buf = &mut [0; 32];
|
|
|
|
assert_eq!(s.recv_slice(rx_buf), Ok(4));
|
|
|
|
|
|
|
|
// check that we do NOT send a window update even if it has changed.
|
|
|
|
recv!(s, Err(Error::Exhausted));
|
|
|
|
}
|
|
|
|
|
2017-06-26 07:12:25 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for flow control.
|
|
|
|
// =========================================================================================//
|
|
|
|
|
|
|
|
#[test]
|
2017-08-25 14:27:00 +08:00
|
|
|
fn test_psh_transmit() {
|
2017-06-26 07:12:25 +08:00
|
|
|
let mut s = socket_established();
|
2020-12-18 23:06:23 +08:00
|
|
|
s.remote_mss = 6;
|
2017-06-26 07:12:25 +08:00
|
|
|
s.send_slice(b"abcdef").unwrap();
|
|
|
|
s.send_slice(b"123456").unwrap();
|
|
|
|
recv!(s, time 0, Ok(TcpRepr {
|
2017-08-25 14:03:54 +08:00
|
|
|
control: TcpControl::None,
|
2017-06-26 07:12:25 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}), exact);
|
|
|
|
recv!(s, time 0, Ok(TcpRepr {
|
2017-08-25 14:03:54 +08:00
|
|
|
control: TcpControl::Psh,
|
2017-06-26 07:12:25 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"123456"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}), exact);
|
|
|
|
}
|
2017-08-25 14:27:00 +08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_psh_receive() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Psh,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..SEND_TEMPL
|
2017-09-06 07:23:50 +08:00
|
|
|
});
|
|
|
|
recv!(s, [TcpRepr {
|
2017-08-25 14:27:00 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
|
|
|
window_len: 58,
|
|
|
|
..RECV_TEMPL
|
2017-09-06 07:23:50 +08:00
|
|
|
}]);
|
2017-08-25 14:27:00 +08:00
|
|
|
}
|
2017-08-28 14:01:13 +08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_zero_window_ack() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.rx_buffer = SocketBuffer::new(vec![0; 6]);
|
2017-09-22 17:51:04 +08:00
|
|
|
s.assembler = Assembler::new(s.rx_buffer.capacity());
|
2017-08-28 14:01:13 +08:00
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..SEND_TEMPL
|
2017-09-06 07:23:50 +08:00
|
|
|
});
|
|
|
|
recv!(s, [TcpRepr {
|
2017-08-28 14:01:13 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
|
|
|
window_len: 0,
|
|
|
|
..RECV_TEMPL
|
2017-09-06 07:23:50 +08:00
|
|
|
}]);
|
2017-08-28 14:01:13 +08:00
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"123456"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
|
|
|
window_len: 0,
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
|
|
|
}
|
2017-08-31 07:09:31 +08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_zero_window_ack_on_window_growth() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.rx_buffer = SocketBuffer::new(vec![0; 6]);
|
2017-09-22 17:51:04 +08:00
|
|
|
s.assembler = Assembler::new(s.rx_buffer.capacity());
|
2017-08-31 07:09:31 +08:00
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..SEND_TEMPL
|
2017-09-06 07:23:50 +08:00
|
|
|
});
|
|
|
|
recv!(s, [TcpRepr {
|
2017-08-31 07:09:31 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
|
|
|
window_len: 0,
|
|
|
|
..RECV_TEMPL
|
2017-09-06 07:23:50 +08:00
|
|
|
}]);
|
2017-08-31 07:09:31 +08:00
|
|
|
recv!(s, time 0, Err(Error::Exhausted));
|
2017-11-01 03:24:54 +08:00
|
|
|
s.recv(|buffer| {
|
|
|
|
assert_eq!(&buffer[..3], b"abc");
|
|
|
|
(3, ())
|
|
|
|
}).unwrap();
|
2017-08-31 08:08:40 +08:00
|
|
|
recv!(s, time 0, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
|
|
|
window_len: 3,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 0, Err(Error::Exhausted));
|
2017-11-01 03:24:54 +08:00
|
|
|
s.recv(|buffer| {
|
|
|
|
assert_eq!(buffer, b"def");
|
|
|
|
(buffer.len(), ())
|
|
|
|
}).unwrap();
|
2017-08-31 07:09:31 +08:00
|
|
|
recv!(s, time 0, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
|
|
|
window_len: 6,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
}
|
2017-08-31 20:39:05 +08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_fill_peer_window() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.remote_mss = 6;
|
|
|
|
s.send_slice(b"abcdef123456!@#$%^").unwrap();
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}, TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"123456"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}, TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"!@#$%^"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
}
|
2017-09-01 05:44:41 +08:00
|
|
|
|
2018-05-08 01:07:57 +08:00
|
|
|
#[test]
|
|
|
|
fn test_announce_window_after_read() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.rx_buffer = SocketBuffer::new(vec![0; 6]);
|
|
|
|
s.assembler = Assembler::new(s.rx_buffer.capacity());
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 3),
|
|
|
|
window_len: 3,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
// Test that `dispatch` updates `remote_last_win`
|
|
|
|
assert_eq!(s.remote_last_win, s.rx_buffer.window() as u16);
|
|
|
|
s.recv(|buffer| {
|
|
|
|
(buffer.len(), ())
|
|
|
|
}).unwrap();
|
|
|
|
assert!(s.window_to_update());
|
|
|
|
recv!(s, [TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 3),
|
|
|
|
window_len: 6,
|
|
|
|
..RECV_TEMPL
|
|
|
|
}]);
|
|
|
|
assert_eq!(s.remote_last_win, s.rx_buffer.window() as u16);
|
|
|
|
// Provoke immediate ACK to test that `process` updates `remote_last_win`
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"def"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 3),
|
|
|
|
window_len: 6,
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 3,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 9),
|
|
|
|
window_len: 0,
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
|
|
|
assert_eq!(s.remote_last_win, s.rx_buffer.window() as u16);
|
|
|
|
s.recv(|buffer| {
|
|
|
|
(buffer.len(), ())
|
|
|
|
}).unwrap();
|
|
|
|
assert!(s.window_to_update());
|
|
|
|
}
|
|
|
|
|
2017-09-18 19:05:40 +08:00
|
|
|
// =========================================================================================//
|
2017-09-22 17:51:04 +08:00
|
|
|
// Tests for timeouts.
|
2017-09-18 19:05:40 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
|
2017-09-24 19:26:51 +08:00
|
|
|
#[test]
|
|
|
|
fn test_listen_timeout() {
|
|
|
|
let mut s = socket_listen();
|
2018-02-11 00:32:41 +08:00
|
|
|
s.set_timeout(Some(Duration::from_millis(100)));
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Ingress);
|
2017-09-24 19:26:51 +08:00
|
|
|
}
|
|
|
|
|
2017-09-18 19:05:40 +08:00
|
|
|
#[test]
|
|
|
|
fn test_connect_timeout() {
|
|
|
|
let mut s = socket();
|
|
|
|
s.local_seq_no = LOCAL_SEQ;
|
|
|
|
s.connect(REMOTE_END, LOCAL_END.port).unwrap();
|
2018-02-11 00:32:41 +08:00
|
|
|
s.set_timeout(Some(Duration::from_millis(100)));
|
2017-09-18 19:05:40 +08:00
|
|
|
recv!(s, time 150, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Syn,
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: None,
|
2017-12-24 21:28:59 +08:00
|
|
|
max_seg_size: Some(BASE_MSS),
|
2018-06-24 22:35:29 +08:00
|
|
|
window_scale: Some(0),
|
2019-01-01 04:45:20 +08:00
|
|
|
sack_permitted: true,
|
2017-09-18 19:05:40 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
assert_eq!(s.state, State::SynSent);
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(250)));
|
2017-09-18 19:05:40 +08:00
|
|
|
recv!(s, time 250, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(TcpSeqNumber(0)),
|
2018-06-24 22:35:29 +08:00
|
|
|
window_scale: None,
|
2017-09-18 19:05:40 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_established_timeout() {
|
|
|
|
let mut s = socket_established();
|
2018-02-11 00:32:41 +08:00
|
|
|
s.set_timeout(Some(Duration::from_millis(200)));
|
2017-09-18 19:05:40 +08:00
|
|
|
recv!(s, time 250, Err(Error::Exhausted));
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(450)));
|
2017-09-18 19:05:40 +08:00
|
|
|
s.send_slice(b"abcdef").unwrap();
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Now);
|
2017-09-18 19:05:40 +08:00
|
|
|
recv!(s, time 255, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(355)));
|
2017-09-18 19:05:40 +08:00
|
|
|
recv!(s, time 355, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(455)));
|
2017-09-18 19:05:40 +08:00
|
|
|
recv!(s, time 500, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_established_keep_alive_timeout() {
|
|
|
|
let mut s = socket_established();
|
2018-02-11 00:32:41 +08:00
|
|
|
s.set_keep_alive(Some(Duration::from_millis(50)));
|
|
|
|
s.set_timeout(Some(Duration::from_millis(100)));
|
2017-09-18 19:05:40 +08:00
|
|
|
recv!(s, time 100, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &[0],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 100, Err(Error::Exhausted));
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(150)));
|
2017-09-18 19:05:40 +08:00
|
|
|
send!(s, time 105, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(155)));
|
2017-09-18 19:05:40 +08:00
|
|
|
recv!(s, time 155, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &[0],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 155, Err(Error::Exhausted));
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(205)));
|
2017-09-18 19:05:40 +08:00
|
|
|
recv!(s, time 200, Err(Error::Exhausted));
|
|
|
|
recv!(s, time 205, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, time 205, Err(Error::Exhausted));
|
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
2017-09-24 19:04:55 +08:00
|
|
|
#[test]
|
|
|
|
fn test_fin_wait_1_timeout() {
|
|
|
|
let mut s = socket_fin_wait_1();
|
2018-02-11 00:32:41 +08:00
|
|
|
s.set_timeout(Some(Duration::from_millis(200)));
|
2017-09-24 19:04:55 +08:00
|
|
|
recv!(s, time 100, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(200)));
|
2017-09-24 19:04:55 +08:00
|
|
|
recv!(s, time 400, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_last_ack_timeout() {
|
|
|
|
let mut s = socket_last_ack();
|
2018-02-11 00:32:41 +08:00
|
|
|
s.set_timeout(Some(Duration::from_millis(200)));
|
2017-09-24 19:04:55 +08:00
|
|
|
recv!(s, time 100, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(200)));
|
2017-09-24 19:04:55 +08:00
|
|
|
recv!(s, time 400, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: LOCAL_SEQ + 1 + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
assert_eq!(s.state, State::Closed);
|
|
|
|
}
|
|
|
|
|
2017-09-24 19:26:51 +08:00
|
|
|
#[test]
|
|
|
|
fn test_closed_timeout() {
|
|
|
|
let mut s = socket_established();
|
2018-02-11 00:32:41 +08:00
|
|
|
s.set_timeout(Some(Duration::from_millis(200)));
|
|
|
|
s.remote_last_ts = Some(Instant::from_millis(100));
|
2017-09-24 19:26:51 +08:00
|
|
|
s.abort();
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Now);
|
2017-09-24 19:26:51 +08:00
|
|
|
recv!(s, time 100, Ok(TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Ingress);
|
2017-09-24 19:26:51 +08:00
|
|
|
}
|
|
|
|
|
2017-09-16 18:54:59 +08:00
|
|
|
// =========================================================================================//
|
2017-09-22 17:51:04 +08:00
|
|
|
// Tests for keep-alive.
|
2017-09-16 18:54:59 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_responds_to_keep_alive() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sends_keep_alive() {
|
|
|
|
let mut s = socket_established();
|
2018-02-11 00:32:41 +08:00
|
|
|
s.set_keep_alive(Some(Duration::from_millis(100)));
|
2017-09-16 18:54:59 +08:00
|
|
|
|
|
|
|
// drain the forced keep-alive packet
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Now);
|
2017-09-16 18:54:59 +08:00
|
|
|
recv!(s, time 0, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &[0],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(100)));
|
2017-09-16 18:54:59 +08:00
|
|
|
recv!(s, time 95, Err(Error::Exhausted));
|
|
|
|
recv!(s, time 100, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &[0],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(200)));
|
2017-09-16 18:54:59 +08:00
|
|
|
recv!(s, time 195, Err(Error::Exhausted));
|
|
|
|
recv!(s, time 200, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &[0],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
|
|
|
|
send!(s, time 250, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
2018-05-17 03:11:04 +08:00
|
|
|
assert_eq!(s.poll_at(), PollAt::Time(Instant::from_millis(350)));
|
2017-09-16 18:54:59 +08:00
|
|
|
recv!(s, time 345, Err(Error::Exhausted));
|
|
|
|
recv!(s, time 350, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"\x00"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2017-10-25 07:04:33 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for time-to-live configuration.
|
|
|
|
// =========================================================================================//
|
|
|
|
|
|
|
|
#[test]
|
2017-12-10 11:09:50 +08:00
|
|
|
fn test_set_hop_limit() {
|
2017-10-25 07:04:33 +08:00
|
|
|
let mut s = socket_syn_received();
|
|
|
|
let mut caps = DeviceCapabilities::default();
|
|
|
|
caps.max_transmission_unit = 1520;
|
|
|
|
|
2017-12-10 11:09:50 +08:00
|
|
|
s.set_hop_limit(Some(0x2a));
|
2018-02-11 00:32:41 +08:00
|
|
|
assert_eq!(s.dispatch(Instant::from_millis(0), &caps, |(ip_repr, _)| {
|
2017-12-24 21:28:59 +08:00
|
|
|
assert_eq!(ip_repr.hop_limit(), 0x2a);
|
2017-10-25 07:04:33 +08:00
|
|
|
Ok(())
|
|
|
|
}), Ok(()));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "the time-to-live value of a packet must not be zero")]
|
2017-12-10 11:09:50 +08:00
|
|
|
fn test_set_hop_limit_zero() {
|
2017-10-25 07:04:33 +08:00
|
|
|
let mut s = socket_syn_received();
|
2017-12-10 11:09:50 +08:00
|
|
|
s.set_hop_limit(Some(0));
|
2017-10-25 07:04:33 +08:00
|
|
|
}
|
|
|
|
|
2017-09-01 05:44:41 +08:00
|
|
|
// =========================================================================================//
|
2017-09-22 17:51:04 +08:00
|
|
|
// Tests for reassembly.
|
|
|
|
// =========================================================================================//
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_out_of_order() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 3,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"def"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
2017-11-01 03:24:54 +08:00
|
|
|
s.recv(|buffer| {
|
|
|
|
assert_eq!(buffer, b"");
|
|
|
|
(buffer.len(), ())
|
|
|
|
}).unwrap();
|
2017-09-22 17:51:04 +08:00
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..SEND_TEMPL
|
2017-09-23 02:57:47 +08:00
|
|
|
}, Ok(Some(TcpRepr {
|
2017-09-22 17:51:04 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
|
|
|
window_len: 58,
|
|
|
|
..RECV_TEMPL
|
2017-09-23 02:57:47 +08:00
|
|
|
})));
|
2017-11-01 03:24:54 +08:00
|
|
|
s.recv(|buffer| {
|
|
|
|
assert_eq!(buffer, b"abcdef");
|
|
|
|
(buffer.len(), ())
|
|
|
|
}).unwrap();
|
2017-09-22 17:51:04 +08:00
|
|
|
}
|
|
|
|
|
2017-09-23 01:10:51 +08:00
|
|
|
#[test]
|
2017-11-01 03:24:54 +08:00
|
|
|
fn test_buffer_wraparound_rx() {
|
2017-09-23 01:10:51 +08:00
|
|
|
let mut s = socket_established();
|
|
|
|
s.rx_buffer = SocketBuffer::new(vec![0; 6]);
|
|
|
|
s.assembler = Assembler::new(s.rx_buffer.capacity());
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
2017-11-01 03:24:54 +08:00
|
|
|
s.recv(|buffer| {
|
|
|
|
assert_eq!(buffer, b"abc");
|
|
|
|
(buffer.len(), ())
|
|
|
|
}).unwrap();
|
2017-09-23 01:10:51 +08:00
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 3,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"defghi"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
let mut data = [0; 6];
|
|
|
|
assert_eq!(s.recv_slice(&mut data[..]), Ok(6));
|
|
|
|
assert_eq!(data, &b"defghi"[..]);
|
|
|
|
}
|
|
|
|
|
2017-11-01 03:24:54 +08:00
|
|
|
#[test]
|
|
|
|
fn test_buffer_wraparound_tx() {
|
|
|
|
let mut s = socket_established();
|
2018-05-25 06:00:00 +08:00
|
|
|
s.tx_buffer = SocketBuffer::new(vec![b'.'; 9]);
|
|
|
|
assert_eq!(s.send_slice(b"xxxyyy"), Ok(6));
|
|
|
|
assert_eq!(s.tx_buffer.dequeue_many(3), &b"xxx"[..]);
|
|
|
|
assert_eq!(s.tx_buffer.len(), 3);
|
|
|
|
|
|
|
|
// "abcdef" not contiguous in tx buffer
|
|
|
|
assert_eq!(s.send_slice(b"abcdef"), Ok(6));
|
2017-11-01 03:24:54 +08:00
|
|
|
recv!(s, Ok(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
2018-05-25 06:00:00 +08:00
|
|
|
payload: &b"yyyabc"[..],
|
2017-11-01 03:24:54 +08:00
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
recv!(s, Ok(TcpRepr {
|
2018-05-25 06:00:00 +08:00
|
|
|
seq_number: LOCAL_SEQ + 1 + 6,
|
2017-11-01 03:24:54 +08:00
|
|
|
ack_number: Some(REMOTE_SEQ + 1),
|
|
|
|
payload: &b"def"[..],
|
|
|
|
..RECV_TEMPL
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2020-06-12 04:12:38 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for graceful vs ungraceful rx close
|
|
|
|
// =========================================================================================//
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_rx_close_fin() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
s.recv(|data| {
|
|
|
|
assert_eq!(data, b"abc");
|
|
|
|
(3, ())
|
|
|
|
}).unwrap();
|
|
|
|
assert_eq!(s.recv(|_| (0, ())), Err(Error::Finished));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_rx_close_fin_in_fin_wait_1() {
|
|
|
|
let mut s = socket_fin_wait_1();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state, State::Closing);
|
|
|
|
s.recv(|data| {
|
|
|
|
assert_eq!(data, b"abc");
|
|
|
|
(3, ())
|
|
|
|
}).unwrap();
|
|
|
|
assert_eq!(s.recv(|_| (0, ())), Err(Error::Finished));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_rx_close_fin_in_fin_wait_2() {
|
|
|
|
let mut s = socket_fin_wait_2();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1 + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
assert_eq!(s.state, State::TimeWait);
|
|
|
|
s.recv(|data| {
|
|
|
|
assert_eq!(data, b"abc");
|
|
|
|
(3, ())
|
|
|
|
}).unwrap();
|
|
|
|
assert_eq!(s.recv(|_| (0, ())), Err(Error::Finished));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_rx_close_fin_with_hole() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Fin,
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"ghi"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 3),
|
|
|
|
window_len: 61,
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
|
|
|
s.recv(|data| {
|
|
|
|
assert_eq!(data, b"abc");
|
|
|
|
(3, ())
|
|
|
|
}).unwrap();
|
|
|
|
s.recv(|data| {
|
|
|
|
assert_eq!(data, b"");
|
|
|
|
(0, ())
|
|
|
|
}).unwrap();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 9,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
// Error must be `Illegal` even if we've received a FIN,
|
|
|
|
// because we are missing data.
|
|
|
|
assert_eq!(s.recv(|_| (0, ())), Err(Error::Illegal));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_rx_close_rst() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 3,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
s.recv(|data| {
|
|
|
|
assert_eq!(data, b"abc");
|
|
|
|
(3, ())
|
|
|
|
}).unwrap();
|
|
|
|
assert_eq!(s.recv(|_| (0, ())), Err(Error::Illegal));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_rx_close_rst_with_hole() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abc"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 6,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"ghi"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
}, Ok(Some(TcpRepr {
|
|
|
|
seq_number: LOCAL_SEQ + 1,
|
|
|
|
ack_number: Some(REMOTE_SEQ + 1 + 3),
|
|
|
|
window_len: 61,
|
|
|
|
..RECV_TEMPL
|
|
|
|
})));
|
|
|
|
send!(s, TcpRepr {
|
|
|
|
control: TcpControl::Rst,
|
|
|
|
seq_number: REMOTE_SEQ + 1 + 9,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
..SEND_TEMPL
|
|
|
|
});
|
|
|
|
s.recv(|data| {
|
|
|
|
assert_eq!(data, b"abc");
|
|
|
|
(3, ())
|
|
|
|
}).unwrap();
|
|
|
|
assert_eq!(s.recv(|_| (0, ())), Err(Error::Illegal));
|
|
|
|
}
|
|
|
|
|
2017-09-22 17:51:04 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
// Tests for packet filtering.
|
2017-09-01 05:44:41 +08:00
|
|
|
// =========================================================================================//
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_doesnt_accept_wrong_port() {
|
|
|
|
let mut s = socket_established();
|
|
|
|
s.rx_buffer = SocketBuffer::new(vec![0; 6]);
|
2017-09-22 17:51:04 +08:00
|
|
|
s.assembler = Assembler::new(s.rx_buffer.capacity());
|
2017-09-01 05:44:41 +08:00
|
|
|
|
2017-09-08 08:53:19 +08:00
|
|
|
let tcp_repr = TcpRepr {
|
2017-09-01 05:44:41 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
dst_port: LOCAL_PORT + 1,
|
|
|
|
..SEND_TEMPL
|
2017-09-08 08:53:19 +08:00
|
|
|
};
|
|
|
|
assert!(!s.accepts(&SEND_IP_TEMPL, &tcp_repr));
|
2017-09-01 05:44:41 +08:00
|
|
|
|
2017-09-08 08:53:19 +08:00
|
|
|
let tcp_repr = TcpRepr {
|
2017-09-01 05:44:41 +08:00
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
src_port: REMOTE_PORT + 1,
|
|
|
|
..SEND_TEMPL
|
2017-09-08 08:53:19 +08:00
|
|
|
};
|
|
|
|
assert!(!s.accepts(&SEND_IP_TEMPL, &tcp_repr));
|
2017-09-01 05:44:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_doesnt_accept_wrong_ip() {
|
|
|
|
let s = socket_established();
|
|
|
|
|
|
|
|
let tcp_repr = TcpRepr {
|
|
|
|
seq_number: REMOTE_SEQ + 1,
|
|
|
|
ack_number: Some(LOCAL_SEQ + 1),
|
|
|
|
payload: &b"abcdef"[..],
|
|
|
|
..SEND_TEMPL
|
|
|
|
};
|
|
|
|
|
|
|
|
let ip_repr = IpRepr::Unspecified {
|
2017-12-24 21:28:59 +08:00
|
|
|
src_addr: MOCK_IP_ADDR_2,
|
|
|
|
dst_addr: MOCK_IP_ADDR_1,
|
2017-09-01 05:44:41 +08:00
|
|
|
protocol: IpProtocol::Tcp,
|
2017-10-15 08:05:55 +08:00
|
|
|
payload_len: tcp_repr.buffer_len(),
|
2017-12-10 11:09:50 +08:00
|
|
|
hop_limit: 64
|
2017-09-01 05:44:41 +08:00
|
|
|
};
|
|
|
|
assert!(s.accepts(&ip_repr, &tcp_repr));
|
|
|
|
|
|
|
|
let ip_repr_wrong_src = IpRepr::Unspecified {
|
2017-12-24 21:28:59 +08:00
|
|
|
src_addr: MOCK_IP_ADDR_3,
|
|
|
|
dst_addr: MOCK_IP_ADDR_1,
|
2017-09-01 05:44:41 +08:00
|
|
|
protocol: IpProtocol::Tcp,
|
2017-10-15 08:05:55 +08:00
|
|
|
payload_len: tcp_repr.buffer_len(),
|
2017-12-10 11:09:50 +08:00
|
|
|
hop_limit: 64
|
2017-09-01 05:44:41 +08:00
|
|
|
};
|
|
|
|
assert!(!s.accepts(&ip_repr_wrong_src, &tcp_repr));
|
|
|
|
|
|
|
|
let ip_repr_wrong_dst = IpRepr::Unspecified {
|
2017-12-24 21:28:59 +08:00
|
|
|
src_addr: MOCK_IP_ADDR_2,
|
|
|
|
dst_addr: MOCK_IP_ADDR_3,
|
2017-09-01 05:44:41 +08:00
|
|
|
protocol: IpProtocol::Tcp,
|
2017-10-15 08:05:55 +08:00
|
|
|
payload_len: tcp_repr.buffer_len(),
|
2017-12-10 11:09:50 +08:00
|
|
|
hop_limit: 64
|
2017-09-01 05:44:41 +08:00
|
|
|
};
|
|
|
|
assert!(!s.accepts(&ip_repr_wrong_dst, &tcp_repr));
|
|
|
|
}
|
2017-12-24 21:28:59 +08:00
|
|
|
|
|
|
|
// =========================================================================================//
|
|
|
|
// Timer tests
|
|
|
|
// =========================================================================================//
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_timer_retransmit() {
|
|
|
|
let mut r = Timer::default();
|
2018-02-11 00:32:41 +08:00
|
|
|
assert_eq!(r.should_retransmit(Instant::from_secs(1)), None);
|
|
|
|
r.set_for_retransmit(Instant::from_millis(1000));
|
|
|
|
assert_eq!(r.should_retransmit(Instant::from_millis(1000)), None);
|
|
|
|
assert_eq!(r.should_retransmit(Instant::from_millis(1050)), None);
|
|
|
|
assert_eq!(r.should_retransmit(Instant::from_millis(1101)), Some(Duration::from_millis(101)));
|
|
|
|
r.set_for_retransmit(Instant::from_millis(1101));
|
|
|
|
assert_eq!(r.should_retransmit(Instant::from_millis(1101)), None);
|
|
|
|
assert_eq!(r.should_retransmit(Instant::from_millis(1150)), None);
|
|
|
|
assert_eq!(r.should_retransmit(Instant::from_millis(1200)), None);
|
|
|
|
assert_eq!(r.should_retransmit(Instant::from_millis(1301)), Some(Duration::from_millis(300)));
|
|
|
|
r.set_for_idle(Instant::from_millis(1301), None);
|
|
|
|
assert_eq!(r.should_retransmit(Instant::from_millis(1350)), None);
|
2017-12-24 21:28:59 +08:00
|
|
|
}
|
|
|
|
|
2016-12-19 03:40:11 +08:00
|
|
|
}
|