tcp: (fixes #529) Formatting issues in TCP Congestion Control Algorithms documentation
This commit is contained in:
committed by
Tom Henderson
parent
9e9c8d2bc2
commit
cc95f85330
@@ -464,11 +464,11 @@ by (1/cwnd) with a rounding off due to type casting into int.
|
||||
|
||||
if (m_cWndCnt >= w)
|
||||
{
|
||||
uint32_t delta = m_cWndCnt / w;
|
||||
uint32_t delta = m_cWndCnt / w;
|
||||
|
||||
m_cWndCnt -= delta * w;
|
||||
tcb->m_cWnd += delta * tcb->m_segmentSize;
|
||||
NS_LOG_DEBUG("Subtracting delta * w from m_cWndCnt " << delta * w);
|
||||
m_cWndCnt -= delta * w;
|
||||
tcb->m_cWnd += delta * tcb->m_segmentSize;
|
||||
NS_LOG_DEBUG("Subtracting delta * w from m_cWndCnt " << delta * w);
|
||||
}
|
||||
|
||||
|
||||
@@ -476,13 +476,13 @@ by (1/cwnd) with a rounding off due to type casting into int.
|
||||
:caption: New Reno `cwnd` update
|
||||
|
||||
if (segmentsAcked > 0)
|
||||
{
|
||||
double adder = static_cast<double>(tcb->m_segmentSize * tcb->m_segmentSize) / tcb->m_cWnd.Get();
|
||||
adder = std::max(1.0, adder);
|
||||
tcb->m_cWnd += static_cast<uint32_t>(adder);
|
||||
NS_LOG_INFO("In CongAvoid, updated to cwnd " << tcb->m_cWnd <<
|
||||
{
|
||||
double adder = static_cast<double>(tcb->m_segmentSize * tcb->m_segmentSize) / tcb->m_cWnd.Get();
|
||||
adder = std::max(1.0, adder);
|
||||
tcb->m_cWnd += static_cast<uint32_t>(adder);
|
||||
NS_LOG_INFO("In CongAvoid, updated to cwnd " << tcb->m_cWnd <<
|
||||
" ssthresh " << tcb->m_ssThresh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
So, there are two main difference between the TCP Linux Reno and TCP NewReno
|
||||
@@ -844,11 +844,11 @@ As a first approximation, the LEDBAT sender operates as shown below:
|
||||
|
||||
On receipt of an ACK::
|
||||
|
||||
currentdelay = acknowledgement.delay
|
||||
basedelay = min(basedelay, currentdelay)
|
||||
queuingdelay = currentdelay - basedelay
|
||||
offtarget =(TARGET - queuingdelay) / TARGET
|
||||
cWnd += GAIN * offtarget * bytesnewlyacked * MSS / cWnd
|
||||
currentdelay = acknowledgement.delay;
|
||||
basedelay = min(basedelay, currentdelay);
|
||||
queuingdelay = currentdelay - basedelay;
|
||||
offtarget =(TARGET - queuingdelay) / TARGET;
|
||||
cWnd += GAIN * offtarget * bytesnewlyacked * MSS / cWnd;
|
||||
|
||||
``TARGET`` is the maximum queueing delay that LEDBAT itself may introduce in the
|
||||
network, and ``GAIN`` determines the rate at which the cwnd responds to changes in
|
||||
@@ -899,14 +899,14 @@ On receipt of an ACK:
|
||||
|
||||
.. math::
|
||||
|
||||
One way delay = Receiver timestamp - Receiver timestamp echo reply
|
||||
Smoothed one way delay = 7/8 * Old Smoothed one way delay + 1/8 * one way delay
|
||||
If smoothed one way delay > owdMin + 15 * (owdMax - owdMin) / 100
|
||||
if LP_WITHIN_INF
|
||||
cwnd = 1
|
||||
else
|
||||
cwnd = cwnd / 2
|
||||
Inference timer is set
|
||||
\text{One way delay} &= \text{Receiver timestamp} - \text{Receiver timestamp echo reply} \\
|
||||
\text{Smoothed one way delay} &= \frac{7}{8} \times \text{Old Smoothed one way delay} + \frac{1}{8} \times \text{one way delay} \\
|
||||
\text{If smoothed one way delay} &> \text{owdMin} + \frac{15 \times (\text{owdMax} - \text{owdMin})}{100} \\
|
||||
&\text{if LP\_WITHIN\_INF} \\
|
||||
&\quad \text{cwnd} = 1 \\
|
||||
&\text{else} \\
|
||||
&\quad \text{cwnd} = \frac{\text{cwnd}}{2} \\
|
||||
&\text{Inference timer is set}
|
||||
|
||||
where owdMin and owdMax are the minimum and maximum one way delays experienced
|
||||
throughout the connection, LP_WITHIN_INF indicates if TCP-LP is in inference
|
||||
@@ -1056,31 +1056,36 @@ limiting the rate at which packets are sent. It caps the cwnd to one BDP
|
||||
and paces out packets at a rate which is adjusted based on the latest estimate
|
||||
of delivery rate. BBR algorithm is agnostic to packet losses and ECN marks.
|
||||
|
||||
pacing_gain controls the rate of sending data and cwnd_gain controls the amount
|
||||
``pacing_gain`` controls the rate of sending data and ``cwnd_gain`` controls the amount
|
||||
of data to send.
|
||||
|
||||
The following is a high level overview of BBR congestion control algorithm:
|
||||
|
||||
On receiving an ACK::
|
||||
|
||||
rtt = now - packet.sent_time
|
||||
update_minimum_rtt(rtt)
|
||||
delivery_rate = estimate_delivery_rate(packet)
|
||||
update_maximum_bandwidth(delivery_rate)
|
||||
rtt = now - packet.sent_time;
|
||||
update_minimum_rtt(rtt);
|
||||
delivery_rate = estimate_delivery_rate(packet);
|
||||
update_maximum_bandwidth(delivery_rate);
|
||||
|
||||
After transmitting a data packet::
|
||||
|
||||
bdp = max_bandwidth * min_rtt
|
||||
if (cwnd * bdp < inflight)
|
||||
return
|
||||
if (now > nextSendTime)
|
||||
{
|
||||
transmit(packet)
|
||||
nextSendTime = now + packet.size /(pacing_gain * max_bandwidth)
|
||||
}
|
||||
else
|
||||
return
|
||||
Schedule(nextSendTime, Send)
|
||||
bdp = max_bandwidth * min_rtt;
|
||||
if (cwnd * bdp < inflight)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (now > nextSendTime)
|
||||
{
|
||||
transmit(packet);
|
||||
nextSendTime = now + packet.size / (pacing_gain * max_bandwidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
Schedule(nextSendTime, Send);
|
||||
|
||||
|
||||
To enable BBR on all TCP sockets, the following configuration can be used::
|
||||
|
||||
@@ -1099,10 +1104,10 @@ In addition, the following unit tests have been written to validate the
|
||||
implementation of BBR in ns-3:
|
||||
|
||||
* BBR should enable (if not already done) TCP pacing feature.
|
||||
* Test to validate the values of pacing_gain and cwnd_gain in different phases
|
||||
* Test to validate the values of ``pacing_gain`` and ``cwnd_gain`` in different phases
|
||||
of BBR.
|
||||
|
||||
An example program, examples/tcp/tcp-bbr-example.cc, is provided to experiment
|
||||
An example program, ``examples/tcp/tcp-bbr-example.cc``, is provided to experiment
|
||||
with BBR for one long running flow. This example uses a simple topology
|
||||
consisting of one sender, one receiver and two routers to examine congestion
|
||||
window, throughput and queue control. A program similar to this has been run
|
||||
@@ -1190,43 +1195,43 @@ ECN capability is negotiated during the three-way TCP handshake:
|
||||
|
||||
::
|
||||
|
||||
if (m_useEcn == UseEcn_t::On)
|
||||
{
|
||||
SendEmptyPacket(TcpHeader::SYN | TcpHeader::ECE | TcpHeader::CWR);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendEmptyPacket(TcpHeader::SYN);
|
||||
}
|
||||
m_ecnState = ECN_DISABLED;
|
||||
if (m_useEcn == UseEcn_t::On)
|
||||
{
|
||||
SendEmptyPacket(TcpHeader::SYN | TcpHeader::ECE | TcpHeader::CWR);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendEmptyPacket(TcpHeader::SYN);
|
||||
}
|
||||
m_ecnState = ECN_DISABLED;
|
||||
|
||||
2. Receiver sends SYN + ACK + ECE
|
||||
|
||||
::
|
||||
|
||||
if (m_useEcn != UseEcn_t::Off &&(tcpHeader.GetFlags() &(TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::CWR | TcpHeader::ECE))
|
||||
{
|
||||
SendEmptyPacket(TcpHeader::SYN | TcpHeader::ACK |TcpHeader::ECE);
|
||||
m_ecnState = ECN_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
SendEmptyPacket(TcpHeader::SYN | TcpHeader::ACK);
|
||||
m_ecnState = ECN_DISABLED;
|
||||
}
|
||||
if (m_useEcn != UseEcn_t::Off &&(tcpHeader.GetFlags() &(TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::CWR | TcpHeader::ECE))
|
||||
{
|
||||
SendEmptyPacket(TcpHeader::SYN | TcpHeader::ACK |TcpHeader::ECE);
|
||||
m_ecnState = ECN_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
SendEmptyPacket(TcpHeader::SYN | TcpHeader::ACK);
|
||||
m_ecnState = ECN_DISABLED;
|
||||
}
|
||||
|
||||
3. Sender sends ACK
|
||||
|
||||
::
|
||||
|
||||
if (m_useEcn != UseEcn_t::Off && (tcpHeader.GetFlags() &(TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::ECE))
|
||||
{
|
||||
m_ecnState = ECN_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ecnState = ECN_DISABLED;
|
||||
}
|
||||
if (m_useEcn != UseEcn_t::Off && (tcpHeader.GetFlags() &(TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::ECE))
|
||||
{
|
||||
m_ecnState = ECN_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ecnState = ECN_DISABLED;
|
||||
}
|
||||
|
||||
Once the ECN-negotiation is successful, the sender sends data packets with ECT
|
||||
bits set in the IP header.
|
||||
@@ -1779,10 +1784,10 @@ The code is the following:
|
||||
|
||||
::
|
||||
|
||||
TcpZeroWindowTest::TcpZeroWindowTest(const std::string &desc)
|
||||
: TcpGeneralTest(desc)
|
||||
{
|
||||
}
|
||||
TcpZeroWindowTest::TcpZeroWindowTest(const std::string &desc)
|
||||
: TcpGeneralTest(desc)
|
||||
{
|
||||
}
|
||||
|
||||
Then, one should define the general parameters for the TCP connection, which
|
||||
will be one-sided (one node is acting as SENDER, while the other is acting as
|
||||
@@ -1808,15 +1813,15 @@ the method ConfigureEnvironment:
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
TcpZeroWindowTest::ConfigureEnvironment()
|
||||
{
|
||||
TcpGeneralTest::ConfigureEnvironment();
|
||||
SetAppPktCount(20);
|
||||
SetMTU(500);
|
||||
SetTransmitStart(Seconds(2.0));
|
||||
SetPropagationDelay(MilliSeconds(50));
|
||||
}
|
||||
void
|
||||
TcpZeroWindowTest::ConfigureEnvironment()
|
||||
{
|
||||
TcpGeneralTest::ConfigureEnvironment();
|
||||
SetAppPktCount(20);
|
||||
SetMTU(500);
|
||||
SetTransmitStart(Seconds(2.0));
|
||||
SetPropagationDelay(MilliSeconds(50));
|
||||
}
|
||||
|
||||
For other properties, set after the object creation, one can use
|
||||
ConfigureProperties ().
|
||||
@@ -1828,12 +1833,12 @@ documentation for an exhaustive list of the tunable properties.
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
TcpZeroWindowTest::ConfigureProperties()
|
||||
{
|
||||
TcpGeneralTest::ConfigureProperties();
|
||||
SetInitialCwnd(SENDER, 10);
|
||||
}
|
||||
void
|
||||
TcpZeroWindowTest::ConfigureProperties()
|
||||
{
|
||||
TcpGeneralTest::ConfigureProperties();
|
||||
SetInitialCwnd(SENDER, 10);
|
||||
}
|
||||
|
||||
To see the default value for the experiment, please see the implementation of
|
||||
both methods inside TcpGeneralTest class.
|
||||
@@ -1857,13 +1862,13 @@ following code):
|
||||
Ptr<TcpSocketMsgBase>
|
||||
TcpZeroWindowTest::CreateReceiverSocket(Ptr<Node> node)
|
||||
{
|
||||
Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateReceiverSocket(node);
|
||||
Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateReceiverSocket(node);
|
||||
|
||||
socket->SetAttribute("RcvBufSize", UintegerValue(0));
|
||||
Simulator::Schedule(Seconds(10.0),
|
||||
socket->SetAttribute("RcvBufSize", UintegerValue(0));
|
||||
Simulator::Schedule(Seconds(10.0),
|
||||
&TcpZeroWindowTest::IncreaseBufSize, this);
|
||||
|
||||
return socket;
|
||||
return socket;
|
||||
}
|
||||
|
||||
Even so, to check the active window update, we should schedule an increase
|
||||
@@ -1872,11 +1877,11 @@ IncreaseBufSize.
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
TcpZeroWindowTest::IncreaseBufSize()
|
||||
{
|
||||
SetRcvBufSize(RECEIVER, 2500);
|
||||
}
|
||||
void
|
||||
TcpZeroWindowTest::IncreaseBufSize()
|
||||
{
|
||||
SetRcvBufSize(RECEIVER, 2500);
|
||||
}
|
||||
|
||||
Which utilizes the SetRcvBufSize method to edit the RxBuffer object of the
|
||||
RECEIVER. As said before, check the Doxygen documentation for class TcpGeneralTest
|
||||
@@ -1897,17 +1902,17 @@ to be aware of the various possibilities that it offers.
|
||||
TcpGeneralTest::SetRcvBufSize(SocketWho who, uint32_t size)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
{
|
||||
m_senderSocket->SetRcvBufSize(size);
|
||||
}
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
{
|
||||
m_receiverSocket->SetRcvBufSize(size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
NS_FATAL_ERROR("Not defined");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Next, we can start to follow the TCP connection:
|
||||
@@ -1929,22 +1934,22 @@ the first SYN-ACK has 0 as advertised window size:
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
TcpZeroWindowTest::Tx(const Ptr<const Packet> p, const TcpHeader &h, SocketWho who)
|
||||
{
|
||||
...
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
NS_LOG_INFO("\tRECEIVER TX " << h << " size " << p->GetSize());
|
||||
void
|
||||
TcpZeroWindowTest::Tx(const Ptr<const Packet> p, const TcpHeader &h, SocketWho who)
|
||||
{
|
||||
...
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
NS_LOG_INFO("\tRECEIVER TX " << h << " size " << p->GetSize());
|
||||
|
||||
if (h.GetFlags() & TcpHeader::SYN)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(h.GetWindowSize(), 0,
|
||||
"RECEIVER window size is not 0 in the SYN-ACK");
|
||||
}
|
||||
}
|
||||
....
|
||||
}
|
||||
if (h.GetFlags() & TcpHeader::SYN)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(h.GetWindowSize(), 0,
|
||||
"RECEIVER window size is not 0 in the SYN-ACK");
|
||||
}
|
||||
}
|
||||
....
|
||||
}
|
||||
|
||||
Practically, we are checking that every SYN packet sent by the RECEIVER has the
|
||||
advertised window set to 0. The same thing is done also by checking, in the Rx
|
||||
@@ -1977,20 +1982,20 @@ processing of the SYN-ACK:
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
TcpZeroWindowTest::ProcessedAck(const Ptr<const TcpSocketState> tcb,
|
||||
const TcpHeader& h, SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
if (h.GetFlags() & TcpHeader::SYN)
|
||||
{
|
||||
EventId persistentEvent = GetPersistentEvent(SENDER);
|
||||
NS_TEST_ASSERT_MSG_EQ(persistentEvent.IsPending(), true,
|
||||
void
|
||||
TcpZeroWindowTest::ProcessedAck(const Ptr<const TcpSocketState> tcb,
|
||||
const TcpHeader& h, SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
if (h.GetFlags() & TcpHeader::SYN)
|
||||
{
|
||||
EventId persistentEvent = GetPersistentEvent(SENDER);
|
||||
NS_TEST_ASSERT_MSG_EQ(persistentEvent.IsPending(), true,
|
||||
"Persistent event not started");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Since we programmed the increase of the buffer size after 10 simulated seconds,
|
||||
we expect the persistent timer to fire before any rWnd changes. When it fires,
|
||||
@@ -2003,21 +2008,21 @@ again a zero window situation. At first, we investigates on what the sender send
|
||||
|
||||
if (Simulator::Now().GetSeconds() <= 6.0)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(p->GetSize() - h.GetSerializedSize(), 0,
|
||||
NS_TEST_ASSERT_MSG_EQ(p->GetSize() - h.GetSerializedSize(), 0,
|
||||
"Data packet sent anyway");
|
||||
}
|
||||
else if (Simulator::Now().GetSeconds() > 6.0 &&
|
||||
Simulator::Now().GetSeconds() <= 7.0)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(m_zeroWindowProbe, false, "Sent another probe");
|
||||
NS_TEST_ASSERT_MSG_EQ(m_zeroWindowProbe, false, "Sent another probe");
|
||||
|
||||
if (! m_zeroWindowProbe)
|
||||
if (! m_zeroWindowProbe)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(p->GetSize() - h.GetSerializedSize(), 1,
|
||||
"Data packet sent instead of window probe");
|
||||
NS_TEST_ASSERT_MSG_EQ(h.GetSequenceNumber(), SequenceNumber32(1),
|
||||
"Data packet sent instead of window probe");
|
||||
m_zeroWindowProbe = true;
|
||||
NS_TEST_ASSERT_MSG_EQ(p->GetSize() - h.GetSerializedSize(), 1,
|
||||
"Data packet sent instead of window probe");
|
||||
NS_TEST_ASSERT_MSG_EQ(h.GetSequenceNumber(), SequenceNumber32(1),
|
||||
"Data packet sent instead of window probe");
|
||||
m_zeroWindowProbe = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2034,14 +2039,14 @@ Only one probe is allowed, and this is the reason for the check at line 11.
|
||||
:linenos:
|
||||
:emphasize-lines: 6,7
|
||||
|
||||
if (Simulator::Now().GetSeconds() > 6.0 &&
|
||||
if (Simulator::Now().GetSeconds() > 6.0 &&
|
||||
Simulator::Now().GetSeconds() <= 7.0)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(h.GetSequenceNumber(), SequenceNumber32(1),
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(h.GetSequenceNumber(), SequenceNumber32(1),
|
||||
"Data packet sent instead of window probe");
|
||||
NS_TEST_ASSERT_MSG_EQ(h.GetWindowSize(), 0,
|
||||
NS_TEST_ASSERT_MSG_EQ(h.GetWindowSize(), 0,
|
||||
"No zero window advertised by RECEIVER");
|
||||
}
|
||||
}
|
||||
|
||||
For the RECEIVER, the interval between 6 and 7 seconds is when the zero-window
|
||||
segment is sent.
|
||||
@@ -2051,21 +2056,21 @@ exchange between the 7 and 10 seconds mark.
|
||||
|
||||
::
|
||||
|
||||
else if (Simulator::Now().GetSeconds() > 7.0 &&
|
||||
Simulator::Now().GetSeconds() < 10.0)
|
||||
{
|
||||
NS_FATAL_ERROR("No packets should be sent before the window update");
|
||||
}
|
||||
else if (Simulator::Now().GetSeconds() > 7.0 &&
|
||||
Simulator::Now().GetSeconds() < 10.0)
|
||||
{
|
||||
NS_FATAL_ERROR("No packets should be sent before the window update");
|
||||
}
|
||||
|
||||
The state checks are performed at the end of the methods, since they are valid
|
||||
in every condition:
|
||||
|
||||
::
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ(GetCongStateFrom(GetTcb(SENDER)), TcpSocketState::CA_OPEN,
|
||||
"Sender State is not OPEN");
|
||||
NS_TEST_ASSERT_MSG_EQ(GetCongStateFrom(GetTcb(RECEIVER)), TcpSocketState::CA_OPEN,
|
||||
"Receiver State is not OPEN");
|
||||
NS_TEST_ASSERT_MSG_EQ(GetCongStateFrom(GetTcb(SENDER)), TcpSocketState::CA_OPEN,
|
||||
"Sender State is not OPEN");
|
||||
NS_TEST_ASSERT_MSG_EQ(GetCongStateFrom(GetTcb(RECEIVER)), TcpSocketState::CA_OPEN,
|
||||
"Receiver State is not OPEN");
|
||||
|
||||
Now, the interesting part in the Tx method is to check that after the 10.0
|
||||
seconds mark (when the RECEIVER sends the active window update) the value of
|
||||
@@ -2073,11 +2078,11 @@ the window should be greater than zero (and precisely, set to 2500):
|
||||
|
||||
::
|
||||
|
||||
else if (Simulator::Now().GetSeconds() >= 10.0)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(h.GetWindowSize(), 2500,
|
||||
"Receiver window not updated");
|
||||
}
|
||||
else if (Simulator::Now().GetSeconds() >= 10.0)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(h.GetWindowSize(), 2500,
|
||||
"Receiver window not updated");
|
||||
}
|
||||
|
||||
To be sure that the sender receives the window update, we can use the Rx
|
||||
method:
|
||||
@@ -2102,18 +2107,18 @@ the connection ends with a success:
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
TcpZeroWindowTest::NormalClose(SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
m_senderFinished = true;
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
m_receiverFinished = true;
|
||||
}
|
||||
}
|
||||
void
|
||||
TcpZeroWindowTest::NormalClose(SocketWho who)
|
||||
{
|
||||
if (who == SENDER)
|
||||
{
|
||||
m_senderFinished = true;
|
||||
}
|
||||
else if (who == RECEIVER)
|
||||
{
|
||||
m_receiverFinished = true;
|
||||
}
|
||||
}
|
||||
|
||||
The method is called only if all bytes are transmitted successfully. Then, in
|
||||
the method FinalChecks(), we check all variables, which should be true (which
|
||||
@@ -2121,18 +2126,18 @@ indicates that we have perfectly closed the connection).
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
TcpZeroWindowTest::FinalChecks()
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(m_zeroWindowProbe, true,
|
||||
void
|
||||
TcpZeroWindowTest::FinalChecks()
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(m_zeroWindowProbe, true,
|
||||
"Zero window probe not sent");
|
||||
NS_TEST_ASSERT_MSG_EQ(m_windowUpdated, true,
|
||||
NS_TEST_ASSERT_MSG_EQ(m_windowUpdated, true,
|
||||
"Window has not updated during the connection");
|
||||
NS_TEST_ASSERT_MSG_EQ(m_senderFinished, true,
|
||||
NS_TEST_ASSERT_MSG_EQ(m_senderFinished, true,
|
||||
"Connection not closed successfully(SENDER)");
|
||||
NS_TEST_ASSERT_MSG_EQ(m_receiverFinished, true,
|
||||
NS_TEST_ASSERT_MSG_EQ(m_receiverFinished, true,
|
||||
"Connection not closed successfully(RECEIVER)");
|
||||
}
|
||||
}
|
||||
|
||||
To run the test, the usual way is
|
||||
|
||||
|
||||
Reference in New Issue
Block a user