A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tcp-socket-base.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2007 Georgia Tech Research Corporation
3 * Copyright (c) 2010 Adrian Sai-wah Tam
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
19 */
20
21#define NS_LOG_APPEND_CONTEXT \
22 if (m_node) \
23 { \
24 std::clog << " [node " << m_node->GetId() << "] "; \
25 }
26
27#include "tcp-socket-base.h"
28
29#include "ipv4-end-point.h"
30#include "ipv4-route.h"
32#include "ipv4.h"
33#include "ipv6-end-point.h"
34#include "ipv6-l3-protocol.h"
35#include "ipv6-route.h"
37#include "rtt-estimator.h"
38#include "tcp-congestion-ops.h"
39#include "tcp-header.h"
40#include "tcp-l4-protocol.h"
42#include "tcp-option-sack.h"
43#include "tcp-option-ts.h"
44#include "tcp-option-winscale.h"
45#include "tcp-rate-ops.h"
46#include "tcp-recovery-ops.h"
47#include "tcp-rx-buffer.h"
48#include "tcp-tx-buffer.h"
49
50#include "ns3/abort.h"
51#include "ns3/data-rate.h"
52#include "ns3/double.h"
53#include "ns3/inet-socket-address.h"
54#include "ns3/inet6-socket-address.h"
55#include "ns3/log.h"
56#include "ns3/node.h"
57#include "ns3/object.h"
58#include "ns3/packet.h"
59#include "ns3/pointer.h"
60#include "ns3/simulation-singleton.h"
61#include "ns3/simulator.h"
62#include "ns3/trace-source-accessor.h"
63#include "ns3/uinteger.h"
64
65#include <algorithm>
66#include <math.h>
67
68namespace ns3
69{
70
71NS_LOG_COMPONENT_DEFINE("TcpSocketBase");
72
73NS_OBJECT_ENSURE_REGISTERED(TcpSocketBase);
74
75TypeId
77{
78 static TypeId tid =
79 TypeId("ns3::TcpSocketBase")
81 .SetGroupName("Internet")
82 .AddConstructor<TcpSocketBase>()
83 // .AddAttribute ("TcpState", "State in TCP state machine",
84 // TypeId::ATTR_GET,
85 // EnumValue (CLOSED),
86 // MakeEnumAccessor (&TcpSocketBase::m_state),
87 // MakeEnumChecker (CLOSED, "Closed"))
88 .AddAttribute("MaxSegLifetime",
89 "Maximum segment lifetime in seconds, use for TIME_WAIT state transition "
90 "to CLOSED state",
91 DoubleValue(120), /* RFC793 says MSL=2 minutes*/
93 MakeDoubleChecker<double>(0))
94 .AddAttribute("MaxWindowSize",
95 "Max size of advertised window",
96 UintegerValue(65535),
98 MakeUintegerChecker<uint16_t>())
99 .AddAttribute("IcmpCallback",
100 "Callback invoked whenever an icmp error is received on this socket.",
104 .AddAttribute("IcmpCallback6",
105 "Callback invoked whenever an icmpv6 error is received on this socket.",
109 .AddAttribute("WindowScaling",
110 "Enable or disable Window Scaling option",
111 BooleanValue(true),
114 .AddAttribute("Sack",
115 "Enable or disable Sack option",
116 BooleanValue(true),
119 .AddAttribute("Timestamp",
120 "Enable or disable Timestamp option",
121 BooleanValue(true),
124 .AddAttribute(
125 "MinRto",
126 "Minimum retransmit timeout value",
127 TimeValue(Seconds(1.0)), // RFC 6298 says min RTO=1 sec, but Linux uses 200ms.
128 // See http://www.postel.org/pipermail/end2end-interest/2004-November/004402.html
131 .AddAttribute(
132 "ClockGranularity",
133 "Clock Granularity used in RTO calculations",
134 TimeValue(MilliSeconds(1)), // RFC6298 suggest to use fine clock granularity
138 .AddAttribute("TxBuffer",
139 "TCP Tx buffer",
140 PointerValue(),
142 MakePointerChecker<TcpTxBuffer>())
143 .AddAttribute("RxBuffer",
144 "TCP Rx buffer",
145 PointerValue(),
147 MakePointerChecker<TcpRxBuffer>())
148 .AddAttribute("CongestionOps",
149 "Pointer to TcpCongestionOps object",
150 PointerValue(),
152 MakePointerChecker<TcpCongestionOps>())
153 .AddAttribute(
154 "ReTxThreshold",
155 "Threshold for fast retransmit",
156 UintegerValue(3),
158 MakeUintegerChecker<uint32_t>())
159 .AddAttribute("LimitedTransmit",
160 "Enable limited transmit",
161 BooleanValue(true),
164 .AddAttribute("UseEcn",
165 "Parameter to set ECN functionality",
167 MakeEnumAccessor<TcpSocketState::UseEcn_t>(&TcpSocketBase::SetUseEcn),
169 "Off",
171 "On",
173 "AcceptOnly"))
174 .AddTraceSource("RTO",
175 "Retransmission timeout",
177 "ns3::TracedValueCallback::Time")
178 .AddTraceSource("RTT",
179 "Last RTT sample",
181 "ns3::TracedValueCallback::Time")
182 .AddTraceSource("NextTxSequence",
183 "Next sequence number to send (SND.NXT)",
185 "ns3::SequenceNumber32TracedValueCallback")
186 .AddTraceSource("HighestSequence",
187 "Highest sequence number ever sent in socket's life time",
189 "ns3::TracedValueCallback::SequenceNumber32")
190 .AddTraceSource("State",
191 "TCP state",
193 "ns3::TcpStatesTracedValueCallback")
194 .AddTraceSource("CongState",
195 "TCP Congestion machine state",
197 "ns3::TcpSocketState::TcpCongStatesTracedValueCallback")
198 .AddTraceSource("EcnState",
199 "Trace ECN state change of socket",
201 "ns3::TcpSocketState::EcnStatesTracedValueCallback")
202 .AddTraceSource("AdvWND",
203 "Advertised Window Size",
205 "ns3::TracedValueCallback::Uint32")
206 .AddTraceSource("RWND",
207 "Remote side's flow control window",
209 "ns3::TracedValueCallback::Uint32")
210 .AddTraceSource("BytesInFlight",
211 "Socket estimation of bytes in flight",
213 "ns3::TracedValueCallback::Uint32")
214 .AddTraceSource("HighestRxSequence",
215 "Highest sequence number received from peer",
217 "ns3::TracedValueCallback::SequenceNumber32")
218 .AddTraceSource("HighestRxAck",
219 "Highest ack received from peer",
221 "ns3::TracedValueCallback::SequenceNumber32")
222 .AddTraceSource("PacingRate",
223 "The current TCP pacing rate",
225 "ns3::TracedValueCallback::DataRate")
226 .AddTraceSource("CongestionWindow",
227 "The TCP connection's congestion window",
229 "ns3::TracedValueCallback::Uint32")
230 .AddTraceSource("CongestionWindowInflated",
231 "The TCP connection's congestion window inflates as in older RFC",
233 "ns3::TracedValueCallback::Uint32")
234 .AddTraceSource("SlowStartThreshold",
235 "TCP slow start threshold (bytes)",
237 "ns3::TracedValueCallback::Uint32")
238 .AddTraceSource("Tx",
239 "Send tcp packet to IP protocol",
241 "ns3::TcpSocketBase::TcpTxRxTracedCallback")
242 .AddTraceSource("Rx",
243 "Receive tcp packet from IP protocol",
245 "ns3::TcpSocketBase::TcpTxRxTracedCallback")
246 .AddTraceSource("EcnEchoSeq",
247 "Sequence of last received ECN Echo",
249 "ns3::SequenceNumber32TracedValueCallback")
250 .AddTraceSource("EcnCeSeq",
251 "Sequence of last received CE",
253 "ns3::SequenceNumber32TracedValueCallback")
254 .AddTraceSource("EcnCwrSeq",
255 "Sequence of last received CWR",
257 "ns3::SequenceNumber32TracedValueCallback");
258 return tid;
259}
260
261TypeId
263{
265}
266
268 : TcpSocket()
269{
270 NS_LOG_FUNCTION(this);
271 m_txBuffer = CreateObject<TcpTxBuffer>();
272 m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
273 m_tcb = CreateObject<TcpSocketState>();
274 m_rateOps = CreateObject<TcpRateLinux>();
275
276 m_tcb->m_rxBuffer = CreateObject<TcpRxBuffer>();
277
280
282
283 bool ok;
284
286 "PacingRate",
288 NS_ASSERT(ok == true);
289
290 ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
292 NS_ASSERT(ok == true);
293
294 ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
296 NS_ASSERT(ok == true);
297
298 ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
300 NS_ASSERT(ok == true);
301
302 ok = m_tcb->TraceConnectWithoutContext("CongState",
304 NS_ASSERT(ok == true);
305
306 ok = m_tcb->TraceConnectWithoutContext("EcnState",
308 NS_ASSERT(ok == true);
309
310 ok =
311 m_tcb->TraceConnectWithoutContext("NextTxSequence",
313 NS_ASSERT(ok == true);
314
315 ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
317 NS_ASSERT(ok == true);
318
319 ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
321 NS_ASSERT(ok == true);
322
324 NS_ASSERT(ok == true);
325}
326
328 : TcpSocket(sock),
329 // copy object::m_tid and socket::callbacks
330 m_dupAckCount(sock.m_dupAckCount),
331 m_delAckCount(0),
332 m_delAckMaxCount(sock.m_delAckMaxCount),
333 m_noDelay(sock.m_noDelay),
334 m_synCount(sock.m_synCount),
335 m_synRetries(sock.m_synRetries),
336 m_dataRetrCount(sock.m_dataRetrCount),
337 m_dataRetries(sock.m_dataRetries),
338 m_rto(sock.m_rto),
339 m_minRto(sock.m_minRto),
340 m_clockGranularity(sock.m_clockGranularity),
341 m_delAckTimeout(sock.m_delAckTimeout),
342 m_persistTimeout(sock.m_persistTimeout),
343 m_cnTimeout(sock.m_cnTimeout),
344 m_endPoint(nullptr),
345 m_endPoint6(nullptr),
346 m_node(sock.m_node),
347 m_tcp(sock.m_tcp),
348 m_state(sock.m_state),
349 m_errno(sock.m_errno),
350 m_closeNotified(sock.m_closeNotified),
351 m_closeOnEmpty(sock.m_closeOnEmpty),
352 m_shutdownSend(sock.m_shutdownSend),
353 m_shutdownRecv(sock.m_shutdownRecv),
354 m_connected(sock.m_connected),
355 m_msl(sock.m_msl),
356 m_maxWinSize(sock.m_maxWinSize),
357 m_bytesAckedNotProcessed(sock.m_bytesAckedNotProcessed),
358 m_rWnd(sock.m_rWnd),
359 m_highRxMark(sock.m_highRxMark),
360 m_highRxAckMark(sock.m_highRxAckMark),
361 m_sackEnabled(sock.m_sackEnabled),
362 m_winScalingEnabled(sock.m_winScalingEnabled),
363 m_rcvWindShift(sock.m_rcvWindShift),
364 m_sndWindShift(sock.m_sndWindShift),
365 m_timestampEnabled(sock.m_timestampEnabled),
366 m_timestampToEcho(sock.m_timestampToEcho),
367 m_recover(sock.m_recover),
368 m_recoverActive(sock.m_recoverActive),
369 m_retxThresh(sock.m_retxThresh),
370 m_limitedTx(sock.m_limitedTx),
371 m_isFirstPartialAck(sock.m_isFirstPartialAck),
372 m_txTrace(sock.m_txTrace),
373 m_rxTrace(sock.m_rxTrace),
374 m_pacingTimer(Timer::CANCEL_ON_DESTROY),
375 m_ecnEchoSeq(sock.m_ecnEchoSeq),
376 m_ecnCESeq(sock.m_ecnCESeq),
377 m_ecnCWRSeq(sock.m_ecnCWRSeq)
378{
379 NS_LOG_FUNCTION(this);
380 NS_LOG_LOGIC("Invoked the copy constructor");
381 // Copy the rtt estimator if it is set
382 if (sock.m_rtt)
383 {
384 m_rtt = sock.m_rtt->Copy();
385 }
386 // Reset all callbacks to null
387 Callback<void, Ptr<Socket>> vPS = MakeNullCallback<void, Ptr<Socket>>();
388 Callback<void, Ptr<Socket>, const Address&> vPSA =
389 MakeNullCallback<void, Ptr<Socket>, const Address&>();
390 Callback<void, Ptr<Socket>, uint32_t> vPSUI = MakeNullCallback<void, Ptr<Socket>, uint32_t>();
391 SetConnectCallback(vPS, vPS);
392 SetDataSentCallback(vPSUI);
393 SetSendCallback(vPSUI);
394 SetRecvCallback(vPS);
396 m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
397 m_tcb = CopyObject(sock.m_tcb);
399
402
403 if (sock.m_congestionControl)
404 {
407 }
408
409 if (sock.m_recoveryOps)
410 {
411 m_recoveryOps = sock.m_recoveryOps->Fork();
412 }
413
414 m_rateOps = CreateObject<TcpRateLinux>();
416 {
418 }
419
420 bool ok;
421
423 "PacingRate",
425
426 ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
428 NS_ASSERT(ok == true);
429
430 ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
432 NS_ASSERT(ok == true);
433
434 ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
436 NS_ASSERT(ok == true);
437
438 ok = m_tcb->TraceConnectWithoutContext("CongState",
440 NS_ASSERT(ok == true);
441
442 ok = m_tcb->TraceConnectWithoutContext("EcnState",
444 NS_ASSERT(ok == true);
445
446 ok =
447 m_tcb->TraceConnectWithoutContext("NextTxSequence",
449 NS_ASSERT(ok == true);
450
451 ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
453 NS_ASSERT(ok == true);
454
455 ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
457 NS_ASSERT(ok == true);
458
460 NS_ASSERT(ok == true);
461}
462
464{
465 NS_LOG_FUNCTION(this);
466 m_node = nullptr;
467 if (m_endPoint != nullptr)
468 {
470 /*
471 * Upon Bind, an Ipv4Endpoint is allocated and set to m_endPoint, and
472 * DestroyCallback is set to TcpSocketBase::Destroy. If we called
473 * m_tcp->DeAllocate, it will destroy its Ipv4EndpointDemux::DeAllocate,
474 * which in turn destroys my m_endPoint, and in turn invokes
475 * TcpSocketBase::Destroy to nullify m_node, m_endPoint, and m_tcp.
476 */
477 NS_ASSERT(m_endPoint != nullptr);
478 m_tcp->DeAllocate(m_endPoint);
479 NS_ASSERT(m_endPoint == nullptr);
480 }
481 if (m_endPoint6 != nullptr)
482 {
484 NS_ASSERT(m_endPoint6 != nullptr);
485 m_tcp->DeAllocate(m_endPoint6);
486 NS_ASSERT(m_endPoint6 == nullptr);
487 }
488 m_tcp = nullptr;
490}
491
492/* Associate a node with this TCP socket */
493void
495{
496 m_node = node;
497}
498
499/* Associate the L4 protocol (e.g. mux/demux) with this socket */
500void
502{
503 m_tcp = tcp;
504}
505
506/* Set an RTT estimator with this socket */
507void
509{
510 m_rtt = rtt;
511}
512
513/* Inherit from Socket class: Returns error code */
516{
517 return m_errno;
518}
519
520/* Inherit from Socket class: Returns socket type, NS3_SOCK_STREAM */
523{
524 return NS3_SOCK_STREAM;
525}
526
527/* Inherit from Socket class: Returns associated node */
530{
531 return m_node;
532}
533
534/* Inherit from Socket class: Bind socket to an end-point in TcpL4Protocol */
535int
537{
538 NS_LOG_FUNCTION(this);
539 m_endPoint = m_tcp->Allocate();
540 if (nullptr == m_endPoint)
541 {
543 return -1;
544 }
545
546 m_tcp->AddSocket(this);
547
548 return SetupCallback();
549}
550
551int
553{
554 NS_LOG_FUNCTION(this);
555 m_endPoint6 = m_tcp->Allocate6();
556 if (nullptr == m_endPoint6)
557 {
559 return -1;
560 }
561
562 m_tcp->AddSocket(this);
563
564 return SetupCallback();
565}
566
567/* Inherit from Socket class: Bind socket (with specific address) to an end-point in TcpL4Protocol
568 */
569int
571{
572 NS_LOG_FUNCTION(this << address);
574 {
576 Ipv4Address ipv4 = transport.GetIpv4();
577 uint16_t port = transport.GetPort();
578 if (ipv4 == Ipv4Address::GetAny() && port == 0)
579 {
580 m_endPoint = m_tcp->Allocate();
581 }
582 else if (ipv4 == Ipv4Address::GetAny() && port != 0)
583 {
584 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), port);
585 }
586 else if (ipv4 != Ipv4Address::GetAny() && port == 0)
587 {
588 m_endPoint = m_tcp->Allocate(ipv4);
589 }
590 else if (ipv4 != Ipv4Address::GetAny() && port != 0)
591 {
592 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), ipv4, port);
593 }
594 if (nullptr == m_endPoint)
595 {
597 return -1;
598 }
599 }
600 else if (Inet6SocketAddress::IsMatchingType(address))
601 {
603 Ipv6Address ipv6 = transport.GetIpv6();
604 uint16_t port = transport.GetPort();
605 if (ipv6 == Ipv6Address::GetAny() && port == 0)
606 {
607 m_endPoint6 = m_tcp->Allocate6();
608 }
609 else if (ipv6 == Ipv6Address::GetAny() && port != 0)
610 {
611 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), port);
612 }
613 else if (ipv6 != Ipv6Address::GetAny() && port == 0)
614 {
615 m_endPoint6 = m_tcp->Allocate6(ipv6);
616 }
617 else if (ipv6 != Ipv6Address::GetAny() && port != 0)
618 {
619 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), ipv6, port);
620 }
621 if (nullptr == m_endPoint6)
622 {
624 return -1;
625 }
626 }
627 else
628 {
630 return -1;
631 }
632
633 m_tcp->AddSocket(this);
634
635 NS_LOG_LOGIC("TcpSocketBase " << this << " got an endpoint: " << m_endPoint);
636
637 return SetupCallback();
638}
639
640void
642{
644 (m_state == CLOSED) || threshold == m_tcb->m_initialSsThresh,
645 "TcpSocketBase::SetSSThresh() cannot change initial ssThresh after connection started.");
646
647 m_tcb->m_initialSsThresh = threshold;
648}
649
652{
653 return m_tcb->m_initialSsThresh;
654}
655
656void
658{
660 (m_state == CLOSED) || cwnd == m_tcb->m_initialCWnd,
661 "TcpSocketBase::SetInitialCwnd() cannot change initial cwnd after connection started.");
662
663 m_tcb->m_initialCWnd = cwnd;
664}
665
668{
669 return m_tcb->m_initialCWnd;
670}
671
672/* Inherit from Socket class: Initiate connection to a remote address:port */
673int
675{
676 NS_LOG_FUNCTION(this << address);
677
678 // If haven't do so, Bind() this socket first
680 {
681 if (m_endPoint == nullptr)
682 {
683 if (Bind() == -1)
684 {
685 NS_ASSERT(m_endPoint == nullptr);
686 return -1; // Bind() failed
687 }
688 NS_ASSERT(m_endPoint != nullptr);
689 }
691 m_endPoint->SetPeer(transport.GetIpv4(), transport.GetPort());
692 m_endPoint6 = nullptr;
693
694 // Get the appropriate local address and port number from the routing protocol and set up
695 // endpoint
696 if (SetupEndpoint() != 0)
697 {
698 NS_LOG_ERROR("Route to destination does not exist ?!");
699 return -1;
700 }
701 }
702 else if (Inet6SocketAddress::IsMatchingType(address))
703 {
704 // If we are operating on a v4-mapped address, translate the address to
705 // a v4 address and re-call this function
707 Ipv6Address v6Addr = transport.GetIpv6();
708 if (v6Addr.IsIpv4MappedAddress())
709 {
710 Ipv4Address v4Addr = v6Addr.GetIpv4MappedAddress();
711 return Connect(InetSocketAddress(v4Addr, transport.GetPort()));
712 }
713
714 if (m_endPoint6 == nullptr)
715 {
716 if (Bind6() == -1)
717 {
718 NS_ASSERT(m_endPoint6 == nullptr);
719 return -1; // Bind() failed
720 }
721 NS_ASSERT(m_endPoint6 != nullptr);
722 }
723 m_endPoint6->SetPeer(v6Addr, transport.GetPort());
724 m_endPoint = nullptr;
725
726 // Get the appropriate local address and port number from the routing protocol and set up
727 // endpoint
728 if (SetupEndpoint6() != 0)
729 {
730 NS_LOG_ERROR("Route to destination does not exist ?!");
731 return -1;
732 }
733 }
734 else
735 {
737 return -1;
738 }
739
740 // Re-initialize parameters in case this socket is being reused after CLOSE
741 m_rtt->Reset();
744
745 // DoConnect() will do state-checking and send a SYN packet
746 return DoConnect();
747}
748
749/* Inherit from Socket class: Listen on the endpoint for an incoming connection */
750int
752{
753 NS_LOG_FUNCTION(this);
754
755 // Linux quits EINVAL if we're not in CLOSED state, so match what they do
756 if (m_state != CLOSED)
757 {
759 return -1;
760 }
761 // In other cases, set the state to LISTEN and done
762 NS_LOG_DEBUG("CLOSED -> LISTEN");
763 m_state = LISTEN;
764 return 0;
765}
766
767/* Inherit from Socket class: Kill this socket and signal the peer (if any) */
768int
770{
771 NS_LOG_FUNCTION(this);
772 /// \internal
773 /// First we check to see if there is any unread rx data.
774 /// \bugid{426} claims we should send reset in this case.
775 if (m_tcb->m_rxBuffer->Size() != 0)
776 {
777 NS_LOG_WARN("Socket " << this << " << unread rx data during close. Sending reset."
778 << "This is probably due to a bad sink application; check its code");
779 SendRST();
780 return 0;
781 }
782
783 if (m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence) > 0)
784 { // App close with pending data must wait until all data transmitted
785 if (!m_closeOnEmpty)
786 {
787 m_closeOnEmpty = true;
788 NS_LOG_INFO("Socket " << this << " deferring close, state " << TcpStateName[m_state]);
789 }
790 return 0;
791 }
792 return DoClose();
793}
794
795/* Inherit from Socket class: Signal a termination of send */
796int
798{
799 NS_LOG_FUNCTION(this);
800
801 // this prevents data from being added to the buffer
802 m_shutdownSend = true;
803 m_closeOnEmpty = true;
804 // if buffer is already empty, send a fin now
805 // otherwise fin will go when buffer empties.
806 if (m_txBuffer->Size() == 0)
807 {
809 {
810 NS_LOG_INFO("Empty tx buffer, send fin");
812
813 if (m_state == ESTABLISHED)
814 { // On active close: I am the first one to send FIN
815 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
817 }
818 else
819 { // On passive close: Peer sent me FIN already
820 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
822 }
823 }
824 }
825
826 return 0;
827}
828
829/* Inherit from Socket class: Signal a termination of receive */
830int
832{
833 NS_LOG_FUNCTION(this);
834 m_shutdownRecv = true;
835 return 0;
836}
837
838/* Inherit from Socket class: Send a packet. Parameter flags is not used.
839 Packet has no TCP header. Invoked by upper-layer application */
840int
842{
843 NS_LOG_FUNCTION(this << p);
844 NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Send()");
846 {
847 // Store the packet into Tx buffer
848 if (!m_txBuffer->Add(p))
849 { // TxBuffer overflow, send failed
851 return -1;
852 }
853 if (m_shutdownSend)
854 {
856 return -1;
857 }
858
862 m_txBuffer->TailSequence(),
864 m_txBuffer->GetLost(),
865 m_txBuffer->GetRetransmitsCount());
866
867 // Submit the data to lower layers
868 NS_LOG_LOGIC("txBufSize=" << m_txBuffer->Size() << " state " << TcpStateName[m_state]);
869 if ((m_state == ESTABLISHED || m_state == CLOSE_WAIT) && AvailableWindow() > 0)
870 { // Try to send the data out: Add a little step to allow the application
871 // to fill the buffer
873 {
876 this,
878 }
879 }
880 return p->GetSize();
881 }
882 else
883 { // Connection not established yet
885 return -1; // Send failure
886 }
887}
888
889/* Inherit from Socket class: In TcpSocketBase, it is same as Send() call */
890int
891TcpSocketBase::SendTo(Ptr<Packet> p, uint32_t flags, const Address& /* address */)
892{
893 return Send(p, flags); // SendTo() and Send() are the same
894}
895
896/* Inherit from Socket class: Return data to upper-layer application. Parameter flags
897 is not used. Data is returned as a packet of size no larger than maxSize */
900{
901 NS_LOG_FUNCTION(this);
902 NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Recv()");
903 if (m_tcb->m_rxBuffer->Size() == 0 && m_state == CLOSE_WAIT)
904 {
905 return Create<Packet>(); // Send EOF on connection close
906 }
907 Ptr<Packet> outPacket = m_tcb->m_rxBuffer->Extract(maxSize);
908 return outPacket;
909}
910
911/* Inherit from Socket class: Recv and return the remote's address */
914{
915 NS_LOG_FUNCTION(this << maxSize << flags);
916 Ptr<Packet> packet = Recv(maxSize, flags);
917 // Null packet means no data to read, and an empty packet indicates EOF
918 if (packet && packet->GetSize() != 0)
919 {
920 if (m_endPoint != nullptr)
921 {
922 fromAddress =
924 }
925 else if (m_endPoint6 != nullptr)
926 {
927 fromAddress =
929 }
930 else
931 {
932 fromAddress = InetSocketAddress(Ipv4Address::GetZero(), 0);
933 }
934 }
935 return packet;
936}
937
938/* Inherit from Socket class: Get the max number of bytes an app can send */
941{
942 NS_LOG_FUNCTION(this);
943 return m_txBuffer->Available();
944}
945
946/* Inherit from Socket class: Get the max number of bytes an app can read */
949{
950 NS_LOG_FUNCTION(this);
951 return m_tcb->m_rxBuffer->Available();
952}
953
954/* Inherit from Socket class: Return local address:port */
955int
957{
958 NS_LOG_FUNCTION(this);
959 if (m_endPoint != nullptr)
960 {
962 }
963 else if (m_endPoint6 != nullptr)
964 {
966 }
967 else
968 { // It is possible to call this method on a socket without a name
969 // in which case, behavior is unspecified
970 // Should this return an InetSocketAddress or an Inet6SocketAddress?
972 }
973 return 0;
974}
975
976int
978{
979 NS_LOG_FUNCTION(this << address);
980
981 if (!m_endPoint && !m_endPoint6)
982 {
984 return -1;
985 }
986
987 if (m_endPoint)
988 {
990 }
991 else if (m_endPoint6)
992 {
994 }
995 else
996 {
997 NS_ASSERT(false);
998 }
999
1000 return 0;
1001}
1002
1003/* Inherit from Socket class: Bind this socket to the specified NetDevice */
1004void
1006{
1007 NS_LOG_FUNCTION(netdevice);
1008 Socket::BindToNetDevice(netdevice); // Includes sanity check
1009 if (m_endPoint != nullptr)
1010 {
1011 m_endPoint->BindToNetDevice(netdevice);
1012 }
1013
1014 if (m_endPoint6 != nullptr)
1015 {
1016 m_endPoint6->BindToNetDevice(netdevice);
1017 }
1018}
1019
1020/* Clean up after Bind. Set up callback functions in the end-point. */
1021int
1023{
1024 NS_LOG_FUNCTION(this);
1025
1026 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
1027 {
1028 return -1;
1029 }
1030 if (m_endPoint != nullptr)
1031 {
1038 }
1039 if (m_endPoint6 != nullptr)
1040 {
1047 }
1048
1049 return 0;
1050}
1051
1052/* Perform the real connection tasks: Send SYN if allowed, RST if invalid */
1053int
1055{
1056 NS_LOG_FUNCTION(this);
1057
1058 // A new connection is allowed only if this socket does not have a connection
1059 if (m_state == CLOSED || m_state == LISTEN || m_state == SYN_SENT || m_state == LAST_ACK ||
1061 { // send a SYN packet and change state into SYN_SENT
1062 // send a SYN packet with ECE and CWR flags set if sender is ECN capable
1064 {
1066 }
1067 else
1068 {
1070 }
1071 NS_LOG_DEBUG(TcpStateName[m_state] << " -> SYN_SENT");
1072 m_state = SYN_SENT;
1073 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED; // because sender is not yet aware about
1074 // receiver's ECN capability
1075 }
1076 else if (m_state != TIME_WAIT)
1077 { // In states SYN_RCVD, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, and CLOSING, an connection
1078 // exists. We send RST, tear down everything, and close this socket.
1079 SendRST();
1081 }
1082 return 0;
1083}
1084
1085/* Do the action to close the socket. Usually send a packet with appropriate
1086 flags depended on the current m_state. */
1087int
1089{
1090 NS_LOG_FUNCTION(this);
1091 switch (m_state)
1092 {
1093 case SYN_RCVD:
1094 case ESTABLISHED:
1095 // send FIN to close the peer
1097 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
1099 break;
1100 case CLOSE_WAIT:
1101 // send FIN+ACK to close the peer
1103 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
1104 m_state = LAST_ACK;
1105 break;
1106 case SYN_SENT:
1107 case CLOSING:
1108 // Send RST if application closes in SYN_SENT and CLOSING
1109 SendRST();
1111 break;
1112 case LISTEN:
1113 // In this state, move to CLOSED and tear down the end point
1115 break;
1116 case LAST_ACK:
1117 case CLOSED:
1118 case FIN_WAIT_1:
1119 case FIN_WAIT_2:
1120 case TIME_WAIT:
1121 default: /* mute compiler */
1122 // Do nothing in these five states
1123 break;
1124 }
1125 return 0;
1126}
1127
1128/* Peacefully close the socket by notifying the upper layer and deallocate end point */
1129void
1131{
1132 NS_LOG_FUNCTION(this);
1133
1134 if (!m_closeNotified)
1135 {
1137 m_closeNotified = true;
1138 }
1140 {
1142 }
1143 NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSED");
1144 m_state = CLOSED;
1146}
1147
1148/* Tell if a sequence number range is out side the range that my rx buffer can
1149 accept */
1150bool
1152{
1153 if (m_state == LISTEN || m_state == SYN_SENT || m_state == SYN_RCVD)
1154 { // Rx buffer in these states are not initialized.
1155 return false;
1156 }
1157 if (m_state == LAST_ACK || m_state == CLOSING || m_state == CLOSE_WAIT)
1158 { // In LAST_ACK and CLOSING states, it only wait for an ACK and the
1159 // sequence number must equals to m_rxBuffer->NextRxSequence ()
1160 return (m_tcb->m_rxBuffer->NextRxSequence() != head);
1161 }
1162
1163 // In all other cases, check if the sequence number is in range
1164 return (tail < m_tcb->m_rxBuffer->NextRxSequence() ||
1165 m_tcb->m_rxBuffer->MaxRxSequence() <= head);
1166}
1167
1168/* Function called by the L3 protocol when it received a packet to pass on to
1169 the TCP. This function is registered as the "RxCallback" function in
1170 SetupCallback(), which invoked by Bind(), and CompleteFork() */
1171void
1173 Ipv4Header header,
1174 uint16_t port,
1175 Ptr<Ipv4Interface> incomingInterface)
1176{
1177 NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint->GetPeerAddress() << ":"
1178 << m_endPoint->GetPeerPort() << " to " << m_endPoint->GetLocalAddress()
1179 << ":" << m_endPoint->GetLocalPort());
1180
1181 Address fromAddress = InetSocketAddress(header.GetSource(), port);
1183
1184 TcpHeader tcpHeader;
1185 uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1186
1187 if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1188 bytesRemoved,
1189 packet->GetSize() - bytesRemoved))
1190 {
1191 return;
1192 }
1193
1194 if (header.GetEcn() == Ipv4Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1195 {
1196 NS_LOG_INFO("Received CE flag is valid");
1198 m_ecnCESeq = tcpHeader.GetSequenceNumber();
1201 }
1202 else if (header.GetEcn() != Ipv4Header::ECN_NotECT &&
1204 {
1206 }
1207
1208 DoForwardUp(packet, fromAddress, toAddress);
1209}
1210
1211void
1213 Ipv6Header header,
1214 uint16_t port,
1215 Ptr<Ipv6Interface> incomingInterface)
1216{
1217 NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint6->GetPeerAddress() << ":"
1219 << ":" << m_endPoint6->GetLocalPort());
1220
1221 Address fromAddress = Inet6SocketAddress(header.GetSource(), port);
1223
1224 TcpHeader tcpHeader;
1225 uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1226
1227 if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1228 bytesRemoved,
1229 packet->GetSize() - bytesRemoved))
1230 {
1231 return;
1232 }
1233
1234 if (header.GetEcn() == Ipv6Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1235 {
1236 NS_LOG_INFO("Received CE flag is valid");
1238 m_ecnCESeq = tcpHeader.GetSequenceNumber();
1241 }
1242 else if (header.GetEcn() != Ipv6Header::ECN_NotECT)
1243 {
1245 }
1246
1247 DoForwardUp(packet, fromAddress, toAddress);
1248}
1249
1250void
1252 uint8_t icmpTtl,
1253 uint8_t icmpType,
1254 uint8_t icmpCode,
1255 uint32_t icmpInfo)
1256{
1257 NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1258 << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1259 << icmpInfo);
1260 if (!m_icmpCallback.IsNull())
1261 {
1262 m_icmpCallback(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1263 }
1264}
1265
1266void
1268 uint8_t icmpTtl,
1269 uint8_t icmpType,
1270 uint8_t icmpCode,
1271 uint32_t icmpInfo)
1272{
1273 NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1274 << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1275 << icmpInfo);
1276 if (!m_icmpCallback6.IsNull())
1277 {
1278 m_icmpCallback6(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1279 }
1280}
1281
1282bool
1284 const uint32_t tcpHeaderSize,
1285 const uint32_t tcpPayloadSize)
1286{
1287 if (tcpHeaderSize == 0 || tcpHeaderSize > 60)
1288 {
1289 NS_LOG_ERROR("Bytes removed: " << tcpHeaderSize << " invalid");
1290 return false; // Discard invalid packet
1291 }
1292 else if (tcpPayloadSize > 0 && OutOfRange(seq, seq + tcpPayloadSize))
1293 {
1294 // Discard fully out of range data packets
1295 NS_LOG_WARN("At state " << TcpStateName[m_state] << " received packet of seq [" << seq
1296 << ":" << seq + tcpPayloadSize << ") out of range ["
1297 << m_tcb->m_rxBuffer->NextRxSequence() << ":"
1298 << m_tcb->m_rxBuffer->MaxRxSequence() << ")");
1299 // Acknowledgement should be sent for all unacceptable packets (RFC793, p.69)
1301 return false;
1302 }
1303 return true;
1304}
1305
1306void
1307TcpSocketBase::DoForwardUp(Ptr<Packet> packet, const Address& fromAddress, const Address& toAddress)
1308{
1309 // in case the packet still has a priority tag attached, remove it
1310 SocketPriorityTag priorityTag;
1311 packet->RemovePacketTag(priorityTag);
1312
1313 // Peel off TCP header
1314 TcpHeader tcpHeader;
1315 packet->RemoveHeader(tcpHeader);
1316 SequenceNumber32 seq = tcpHeader.GetSequenceNumber();
1317
1318 if (m_state == ESTABLISHED && !(tcpHeader.GetFlags() & TcpHeader::RST))
1319 {
1320 // Check if the sender has responded to ECN echo by reducing the Congestion Window
1321 if (tcpHeader.GetFlags() & TcpHeader::CWR)
1322 {
1323 // Check if a packet with CE bit set is received. If there is no CE bit set, then change
1324 // the state to ECN_IDLE to stop sending ECN Echo messages. If there is CE bit set, the
1325 // packet should continue sending ECN Echo messages
1326 //
1328 {
1331 }
1332 }
1333 }
1334
1335 m_rxTrace(packet, tcpHeader, this);
1336
1337 if (tcpHeader.GetFlags() & TcpHeader::SYN)
1338 {
1339 /* The window field in a segment where the SYN bit is set (i.e., a <SYN>
1340 * or <SYN,ACK>) MUST NOT be scaled (from RFC 7323 page 9). But should be
1341 * saved anyway..
1342 */
1343 m_rWnd = tcpHeader.GetWindowSize();
1344
1346 {
1348 }
1349 else
1350 {
1351 m_winScalingEnabled = false;
1352 }
1353
1355 {
1357 }
1358 else
1359 {
1360 m_sackEnabled = false;
1361 m_txBuffer->SetSackEnabled(false);
1362 }
1363
1364 // When receiving a <SYN> or <SYN-ACK> we should adapt TS to the other end
1365 if (tcpHeader.HasOption(TcpOption::TS) && m_timestampEnabled)
1366 {
1368 tcpHeader.GetSequenceNumber());
1369 }
1370 else
1371 {
1372 m_timestampEnabled = false;
1373 }
1374
1375 // Initialize cWnd and ssThresh
1379
1380 if (tcpHeader.GetFlags() & TcpHeader::ACK)
1381 {
1382 EstimateRtt(tcpHeader);
1383 m_highRxAckMark = tcpHeader.GetAckNumber();
1384 }
1385 }
1386 else if (tcpHeader.GetFlags() & TcpHeader::ACK)
1387 {
1388 NS_ASSERT(!(tcpHeader.GetFlags() & TcpHeader::SYN));
1390 {
1391 if (!tcpHeader.HasOption(TcpOption::TS))
1392 {
1393 // Ignoring segment without TS, RFC 7323
1394 NS_LOG_LOGIC("At state " << TcpStateName[m_state] << " received packet of seq ["
1395 << seq << ":" << seq + packet->GetSize()
1396 << ") without TS option. Silently discard it");
1397 return;
1398 }
1399 else
1400 {
1402 tcpHeader.GetSequenceNumber());
1403 }
1404 }
1405
1406 EstimateRtt(tcpHeader);
1407 UpdateWindowSize(tcpHeader);
1408 }
1409
1410 if (m_rWnd.Get() == 0 && m_persistEvent.IsExpired())
1411 { // Zero window: Enter persist state to send 1 byte to probe
1412 NS_LOG_LOGIC(this << " Enter zerowindow persist state");
1414 this << " Cancelled ReTxTimeout event which was set to expire at "
1415 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
1417 NS_LOG_LOGIC("Schedule persist timeout at time "
1418 << Simulator::Now().GetSeconds() << " to expire at time "
1419 << (Simulator::Now() + m_persistTimeout).GetSeconds());
1423 }
1424
1425 // TCP state machine code in different process functions
1426 // C.f.: tcp_rcv_state_process() in tcp_input.c in Linux kernel
1427 switch (m_state)
1428 {
1429 case ESTABLISHED:
1430 ProcessEstablished(packet, tcpHeader);
1431 break;
1432 case LISTEN:
1433 ProcessListen(packet, tcpHeader, fromAddress, toAddress);
1434 break;
1435 case TIME_WAIT:
1436 // Do nothing
1437 break;
1438 case CLOSED:
1439 // Send RST if the incoming packet is not a RST
1440 if ((tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG)) != TcpHeader::RST)
1441 { // Since m_endPoint is not configured yet, we cannot use SendRST here
1442 TcpHeader h;
1443 Ptr<Packet> p = Create<Packet>();
1446 h.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
1447 h.SetSourcePort(tcpHeader.GetDestinationPort());
1448 h.SetDestinationPort(tcpHeader.GetSourcePort());
1450 AddOptions(h);
1451 m_txTrace(p, h, this);
1452 m_tcp->SendPacket(p, h, toAddress, fromAddress, m_boundnetdevice);
1453 }
1454 break;
1455 case SYN_SENT:
1456 ProcessSynSent(packet, tcpHeader);
1457 break;
1458 case SYN_RCVD:
1459 ProcessSynRcvd(packet, tcpHeader, fromAddress, toAddress);
1460 break;
1461 case FIN_WAIT_1:
1462 case FIN_WAIT_2:
1463 case CLOSE_WAIT:
1464 ProcessWait(packet, tcpHeader);
1465 break;
1466 case CLOSING:
1467 ProcessClosing(packet, tcpHeader);
1468 break;
1469 case LAST_ACK:
1470 ProcessLastAck(packet, tcpHeader);
1471 break;
1472 default: // mute compiler
1473 break;
1474 }
1475
1476 if (m_rWnd.Get() != 0 && m_persistEvent.IsRunning())
1477 { // persist probes end, the other end has increased the window
1479 NS_LOG_LOGIC(this << " Leaving zerowindow persist state");
1481
1483 }
1484}
1485
1486/* Received a packet upon ESTABLISHED state. This function is mimicking the
1487 role of tcp_rcv_established() in tcp_input.c in Linux kernel. */
1488void
1490{
1491 NS_LOG_FUNCTION(this << tcpHeader);
1492
1493 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
1494 uint8_t tcpflags =
1496
1497 // Different flags are different events
1498 if (tcpflags == TcpHeader::ACK)
1499 {
1500 if (tcpHeader.GetAckNumber() < m_txBuffer->HeadSequence())
1501 {
1502 // Case 1: If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored.
1503 // Pag. 72 RFC 793
1504 NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1505 << " SND.UNA = " << m_txBuffer->HeadSequence());
1506
1507 // TODO: RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation]
1508 }
1509 else if (tcpHeader.GetAckNumber() > m_tcb->m_highTxMark)
1510 {
1511 // If the ACK acks something not yet sent (SEG.ACK > HighTxMark) then
1512 // send an ACK, drop the segment, and return.
1513 // Pag. 72 RFC 793
1514 NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1515 << " HighTxMark = " << m_tcb->m_highTxMark);
1516
1517 // Receiver sets ECE flags when it receives a packet with CE bit on or sender hasn’t
1518 // responded to ECN echo sent by receiver
1521 {
1524 << " -> ECN_SENDING_ECE");
1526 }
1527 else
1528 {
1530 }
1531 }
1532 else
1533 {
1534 // SND.UNA < SEG.ACK =< HighTxMark
1535 // Pag. 72 RFC 793
1536 ReceivedAck(packet, tcpHeader);
1537 }
1538 }
1539 else if (tcpflags == TcpHeader::SYN)
1540 { // Received SYN, old NS-3 behaviour is to set state to SYN_RCVD and
1541 // respond with a SYN+ACK. But it is not a legal state transition as of
1542 // RFC793. Thus this is ignored.
1543 }
1544 else if (tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
1545 { // No action for received SYN+ACK, it is probably a duplicated packet
1546 }
1547 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
1548 { // Received FIN or FIN+ACK, bring down this socket nicely
1549 PeerClose(packet, tcpHeader);
1550 }
1551 else if (tcpflags == 0)
1552 { // No flags means there is only data
1553 ReceivedData(packet, tcpHeader);
1554 if (m_tcb->m_rxBuffer->Finished())
1555 {
1556 PeerClose(packet, tcpHeader);
1557 }
1558 }
1559 else
1560 { // Received RST or the TCP flags is invalid, in either case, terminate this socket
1561 if (tcpflags != TcpHeader::RST)
1562 { // this must be an invalid flag, send reset
1563 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
1564 << " received. Reset packet is sent.");
1565 SendRST();
1566 }
1568 }
1569}
1570
1571bool
1573{
1574 NS_LOG_FUNCTION(this << static_cast<uint32_t>(kind));
1575
1576 switch (kind)
1577 {
1578 case TcpOption::TS:
1579 return m_timestampEnabled;
1581 return m_winScalingEnabled;
1583 case TcpOption::SACK:
1584 return m_sackEnabled;
1585 default:
1586 break;
1587 }
1588 return false;
1589}
1590
1591void
1592TcpSocketBase::ReadOptions(const TcpHeader& tcpHeader, uint32_t* bytesSacked)
1593{
1594 NS_LOG_FUNCTION(this << tcpHeader);
1595
1596 for (const auto& option : tcpHeader.GetOptionList())
1597 {
1598 // Check only for ACK options here
1599 switch (option->GetKind())
1600 {
1601 case TcpOption::SACK:
1602 *bytesSacked = ProcessOptionSack(option);
1603 break;
1604 default:
1605 continue;
1606 }
1607 }
1608}
1609
1610// Sender should reduce the Congestion Window as a response to receiver's
1611// ECN Echo notification only once per window
1612void
1614{
1615 NS_LOG_FUNCTION(this << currentDelivered);
1617 NS_LOG_DEBUG("Reduce ssThresh to " << m_tcb->m_ssThresh);
1618 // Do not update m_cWnd, under assumption that recovery process will
1619 // gradually bring it down to m_ssThresh. Update the 'inflated' value of
1620 // cWnd used for tracing, however.
1625 // CWR state will be exited when the ack exceeds the m_recover variable.
1626 // Do not set m_recoverActive (which applies to a loss-based recovery)
1627 // m_recover corresponds to Linux tp->high_seq
1629 if (!m_congestionControl->HasCongControl())
1630 {
1631 // If there is a recovery algorithm, invoke it.
1632 m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1633 NS_LOG_INFO("Enter CWR recovery mode; set cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1634 << m_tcb->m_ssThresh << ", recover to "
1635 << m_recover);
1636 }
1637}
1638
1639void
1641{
1642 NS_LOG_FUNCTION(this);
1644
1646
1647 if (!m_sackEnabled)
1648 {
1649 // One segment has left the network, PLUS the head is lost
1650 m_txBuffer->AddRenoSack();
1651 m_txBuffer->MarkHeadAsLost();
1652 }
1653 else
1654 {
1655 if (!m_txBuffer->IsLost(m_txBuffer->HeadSequence()))
1656 {
1657 // We received 3 dupacks, but the head is not marked as lost
1658 // (received less than 3 SACK block ahead).
1659 // Manually set it as lost.
1660 m_txBuffer->MarkHeadAsLost();
1661 }
1662 }
1663
1664 // RFC 6675, point (4):
1665 // (4) Invoke fast retransmit and enter loss recovery as follows:
1666 // (4.1) RecoveryPoint = HighData
1668 m_recoverActive = true;
1669
1672
1673 // (4.2) ssthresh = cwnd = (FlightSize / 2)
1674 // If SACK is not enabled, still consider the head as 'in flight' for
1675 // compatibility with old ns-3 versions
1676 uint32_t bytesInFlight =
1678 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, bytesInFlight);
1679
1680 if (!m_congestionControl->HasCongControl())
1681 {
1682 m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1683 NS_LOG_INFO(m_dupAckCount << " dupack. Enter fast recovery mode."
1684 << "Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1685 << m_tcb->m_ssThresh << " at fast recovery seqnum " << m_recover
1686 << " calculated in flight: " << bytesInFlight);
1687 }
1688
1689 // (4.3) Retransmit the first data segment presumed dropped
1691 NS_ASSERT_MSG(sz > 0, "SendDataPacket returned zero, indicating zero bytes were sent");
1692 // (4.4) Run SetPipe ()
1693 // (4.5) Proceed to step (C)
1694 // these steps are done after the ProcessAck function (SendPendingData)
1695}
1696
1697void
1699{
1700 NS_LOG_FUNCTION(this);
1701 // NOTE: We do not count the DupAcks received in CA_LOSS, because we
1702 // don't know if they are generated by a spurious retransmission or because
1703 // of a real packet loss. With SACK, it is easy to know, but we do not consider
1704 // dupacks. Without SACK, there are some heuristics in the RFC 6582, but
1705 // for now, we do not implement it, leading to ignoring the dupacks.
1707 {
1708 return;
1709 }
1710
1711 // RFC 6675, Section 5, 3rd paragraph:
1712 // If the incoming ACK is a duplicate acknowledgment per the definition
1713 // in Section 2 (regardless of its status as a cumulative
1714 // acknowledgment), and the TCP is not currently in loss recovery
1715 // the TCP MUST increase DupAcks by one ...
1717 {
1718 ++m_dupAckCount;
1719 }
1720
1722 {
1723 // From Open we go Disorder
1725 "From OPEN->DISORDER but with " << m_dupAckCount << " dup ACKs");
1726
1729
1730 NS_LOG_DEBUG("CA_OPEN -> CA_DISORDER");
1731 }
1732
1734 {
1735 if (!m_sackEnabled)
1736 {
1737 // If we are in recovery and we receive a dupack, one segment
1738 // has left the network. This is equivalent to a SACK of one block.
1739 m_txBuffer->AddRenoSack();
1740 }
1741 if (!m_congestionControl->HasCongControl())
1742 {
1743 m_recoveryOps->DoRecovery(m_tcb, currentDelivered);
1744 NS_LOG_INFO(m_dupAckCount << " Dupack received in fast recovery mode."
1745 "Increase cwnd to "
1746 << m_tcb->m_cWnd);
1747 }
1748 }
1750 {
1751 // m_dupackCount should not exceed its threshold in CA_DISORDER state
1752 // when m_recoverActive has not been set. When recovery point
1753 // have been set after timeout, the sender could enter into CA_DISORDER
1754 // after receiving new ACK smaller than m_recover. After that, m_dupackCount
1755 // can be equal and larger than m_retxThresh and we should avoid entering
1756 // CA_RECOVERY and reducing sending rate again.
1758
1759 // RFC 6675, Section 5, continuing:
1760 // ... and take the following steps:
1761 // (1) If DupAcks >= DupThresh, go to step (4).
1762 // Sequence number comparison (m_highRxAckMark >= m_recover) will take
1763 // effect only when m_recover has been set. Hence, we can avoid to use
1764 // m_recover in the last congestion event and fail to enter
1765 // CA_RECOVERY when sequence number is advanced significantly since
1766 // the last congestion event, which could be common for
1767 // bandwidth-greedy application in high speed and reliable network
1768 // (such as datacenter network) whose sending rate is constrained by
1769 // TCP socket buffer size at receiver side.
1770 if ((m_dupAckCount == m_retxThresh) &&
1772 {
1773 EnterRecovery(currentDelivered);
1775 }
1776 // (2) If DupAcks < DupThresh but IsLost (HighACK + 1) returns true
1777 // (indicating at least three segments have arrived above the current
1778 // cumulative acknowledgment point, which is taken to indicate loss)
1779 // go to step (4). Note that m_highRxAckMark is (HighACK + 1)
1780 else if (m_txBuffer->IsLost(m_highRxAckMark))
1781 {
1782 EnterRecovery(currentDelivered);
1784 }
1785 else
1786 {
1787 // (3) The TCP MAY transmit previously unsent data segments as per
1788 // Limited Transmit [RFC5681] ...except that the number of octets
1789 // which may be sent is governed by pipe and cwnd as follows:
1790 //
1791 // (3.1) Set HighRxt to HighACK.
1792 // Not clear in RFC. We don't do this here, since we still have
1793 // to retransmit the segment.
1794
1795 if (!m_sackEnabled && m_limitedTx)
1796 {
1797 m_txBuffer->AddRenoSack();
1798
1799 // In limited transmit, cwnd Infl is not updated.
1800 }
1801 }
1802 }
1803}
1804
1805/* Process the newly received ACK */
1806void
1808{
1809 NS_LOG_FUNCTION(this << tcpHeader);
1810
1811 NS_ASSERT(0 != (tcpHeader.GetFlags() & TcpHeader::ACK));
1813
1814 uint32_t previousLost = m_txBuffer->GetLost();
1815 uint32_t priorInFlight = m_tcb->m_bytesInFlight.Get();
1816
1817 // RFC 6675, Section 5, 1st paragraph:
1818 // Upon the receipt of any ACK containing SACK information, the
1819 // scoreboard MUST be updated via the Update () routine (done in ReadOptions)
1820 uint32_t bytesSacked = 0;
1821 uint64_t previousDelivered = m_rateOps->GetConnectionRate().m_delivered;
1822 ReadOptions(tcpHeader, &bytesSacked);
1823
1824 SequenceNumber32 ackNumber = tcpHeader.GetAckNumber();
1825 SequenceNumber32 oldHeadSequence = m_txBuffer->HeadSequence();
1826
1827 if (ackNumber < oldHeadSequence)
1828 {
1829 NS_LOG_DEBUG("Possibly received a stale ACK (ack number < head sequence)");
1830 // If there is any data piggybacked, store it into m_rxBuffer
1831 if (packet->GetSize() > 0)
1832 {
1833 ReceivedData(packet, tcpHeader);
1834 }
1835 return;
1836 }
1837 if ((ackNumber > oldHeadSequence) && (ackNumber < m_recover) &&
1839 {
1840 uint32_t segAcked = (ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
1841 for (uint32_t i = 0; i < segAcked; i++)
1842 {
1843 if (m_txBuffer->IsRetransmittedDataAcked(ackNumber - (i * m_tcb->m_segmentSize)))
1844 {
1846 NS_LOG_DEBUG("Ack Number " << ackNumber << "is ACK of retransmitted packet.");
1847 }
1848 }
1849 }
1850
1851 m_txBuffer->DiscardUpTo(ackNumber, MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
1852
1853 auto currentDelivered =
1854 static_cast<uint32_t>(m_rateOps->GetConnectionRate().m_delivered - previousDelivered);
1855 m_tcb->m_lastAckedSackedBytes = currentDelivered;
1856
1857 if (m_tcb->m_congState == TcpSocketState::CA_CWR && (ackNumber > m_recover))
1858 {
1859 // Recovery is over after the window exceeds m_recover
1860 // (although it may be re-entered below if ECE is still set)
1863 if (!m_congestionControl->HasCongControl())
1864 {
1866 m_recoveryOps->ExitRecovery(m_tcb);
1868 }
1869 }
1870
1871 if (ackNumber > oldHeadSequence && (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED) &&
1872 (tcpHeader.GetFlags() & TcpHeader::ECE))
1873 {
1874 if (m_ecnEchoSeq < ackNumber)
1875 {
1876 NS_LOG_INFO("Received ECN Echo is valid");
1877 m_ecnEchoSeq = ackNumber;
1881 {
1882 EnterCwr(currentDelivered);
1883 }
1884 }
1885 }
1887 !(tcpHeader.GetFlags() & TcpHeader::ECE))
1888 {
1890 }
1891
1892 // Update bytes in flight before processing the ACK for proper calculation of congestion window
1893 NS_LOG_INFO("Update bytes in flight before processing the ACK.");
1894 BytesInFlight();
1895
1896 // RFC 6675 Section 5: 2nd, 3rd paragraph and point (A), (B) implementation
1897 // are inside the function ProcessAck
1898 ProcessAck(ackNumber, (bytesSacked > 0), currentDelivered, oldHeadSequence);
1899 m_tcb->m_isRetransDataAcked = false;
1900
1901 if (m_congestionControl->HasCongControl())
1902 {
1903 uint32_t currentLost = m_txBuffer->GetLost();
1904 uint32_t lost =
1905 (currentLost > previousLost) ? currentLost - previousLost : previousLost - currentLost;
1906 auto rateSample = m_rateOps->GenerateSample(currentDelivered,
1907 lost,
1908 false,
1909 priorInFlight,
1910 m_tcb->m_minRtt);
1911 auto rateConn = m_rateOps->GetConnectionRate();
1912 m_congestionControl->CongControl(m_tcb, rateConn, rateSample);
1913 }
1914
1915 // If there is any data piggybacked, store it into m_rxBuffer
1916 if (packet->GetSize() > 0)
1917 {
1918 ReceivedData(packet, tcpHeader);
1919 }
1920
1921 // RFC 6675, Section 5, point (C), try to send more data. NB: (C) is implemented
1922 // inside SendPendingData
1924}
1925
1926void
1928 bool scoreboardUpdated,
1929 uint32_t currentDelivered,
1930 const SequenceNumber32& oldHeadSequence)
1931{
1932 NS_LOG_FUNCTION(this << ackNumber << scoreboardUpdated);
1933 // RFC 6675, Section 5, 2nd paragraph:
1934 // If the incoming ACK is a cumulative acknowledgment, the TCP MUST
1935 // reset DupAcks to zero.
1936 bool exitedFastRecovery = false;
1937 uint32_t oldDupAckCount = m_dupAckCount; // remember the old value
1938 m_tcb->m_lastAckedSeq = ackNumber; // Update lastAckedSeq
1939 uint32_t bytesAcked = 0;
1940
1941 /* In RFC 5681 the definition of duplicate acknowledgment was strict:
1942 *
1943 * (a) the receiver of the ACK has outstanding data,
1944 * (b) the incoming acknowledgment carries no data,
1945 * (c) the SYN and FIN bits are both off,
1946 * (d) the acknowledgment number is equal to the greatest acknowledgment
1947 * received on the given connection (TCP.UNA from [RFC793]),
1948 * (e) the advertised window in the incoming acknowledgment equals the
1949 * advertised window in the last incoming acknowledgment.
1950 *
1951 * With RFC 6675, this definition has been reduced:
1952 *
1953 * (a) the ACK is carrying a SACK block that identifies previously
1954 * unacknowledged and un-SACKed octets between HighACK (TCP.UNA) and
1955 * HighData (m_highTxMark)
1956 */
1957
1958 bool isDupack = m_sackEnabled ? scoreboardUpdated
1959 : ackNumber == oldHeadSequence && ackNumber < m_tcb->m_highTxMark;
1960
1961 NS_LOG_DEBUG("ACK of " << ackNumber << " SND.UNA=" << oldHeadSequence
1962 << " SND.NXT=" << m_tcb->m_nextTxSequence
1964 << " with m_recover: " << m_recover);
1965
1966 // RFC 6675, Section 5, 3rd paragraph:
1967 // If the incoming ACK is a duplicate acknowledgment per the definition
1968 // in Section 2 (regardless of its status as a cumulative
1969 // acknowledgment), and the TCP is not currently in loss recovery
1970 if (isDupack)
1971 {
1972 // loss recovery check is done inside this function thanks to
1973 // the congestion state machine
1974 DupAck(currentDelivered);
1975 }
1976
1977 if (ackNumber == oldHeadSequence && ackNumber == m_tcb->m_highTxMark)
1978 {
1979 // Dupack, but the ACK is precisely equal to the nextTxSequence
1980 return;
1981 }
1982 else if (ackNumber == oldHeadSequence && ackNumber > m_tcb->m_highTxMark)
1983 {
1984 // ACK of the FIN bit ... nextTxSequence is not updated since we
1985 // don't have anything to transmit
1986 NS_LOG_DEBUG("Update nextTxSequence manually to " << ackNumber);
1987 m_tcb->m_nextTxSequence = ackNumber;
1988 }
1989 else if (ackNumber == oldHeadSequence)
1990 {
1991 // DupAck. Artificially call PktsAcked: after all, one segment has been ACKed.
1992 m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_lastRtt);
1993 }
1994 else if (ackNumber > oldHeadSequence)
1995 {
1996 // Please remember that, with SACK, we can enter here even if we
1997 // received a dupack.
1998 bytesAcked = ackNumber - oldHeadSequence;
1999 uint32_t segsAcked = bytesAcked / m_tcb->m_segmentSize;
2001 bytesAcked -= bytesAcked % m_tcb->m_segmentSize;
2002
2004 {
2005 segsAcked += 1;
2006 bytesAcked += m_tcb->m_segmentSize;
2008 }
2009
2010 // Dupack count is reset to eventually fast-retransmit after 3 dupacks.
2011 // Any SACK-ed segment will be cleaned up by DiscardUpTo.
2012 // In the case that we advanced SND.UNA, but the ack contains SACK blocks,
2013 // we do not reset. At the third one we will retransmit.
2014 // If we are already in recovery, this check is useless since dupAcks
2015 // are not considered in this phase. When from Recovery we go back
2016 // to open, then dupAckCount is reset anyway.
2017 if (!isDupack)
2018 {
2019 m_dupAckCount = 0;
2020 }
2021
2022 // RFC 6675, Section 5, part (B)
2023 // (B) Upon receipt of an ACK that does not cover RecoveryPoint, the
2024 // following actions MUST be taken:
2025 //
2026 // (B.1) Use Update () to record the new SACK information conveyed
2027 // by the incoming ACK.
2028 // (B.2) Use SetPipe () to re-calculate the number of octets still
2029 // in the network.
2030 //
2031 // (B.1) is done at the beginning, while (B.2) is delayed to part (C) while
2032 // trying to transmit with SendPendingData. We are not allowed to exit
2033 // the CA_RECOVERY phase. Just process this partial ack (RFC 5681)
2034 if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
2035 {
2036 if (!m_sackEnabled)
2037 {
2038 // Manually set the head as lost, it will be retransmitted.
2039 NS_LOG_INFO("Partial ACK. Manually setting head as lost");
2040 m_txBuffer->MarkHeadAsLost();
2041 }
2042
2043 // Before retransmitting the packet perform DoRecovery and check if
2044 // there is available window
2045 if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2046 {
2047 m_recoveryOps->DoRecovery(m_tcb, currentDelivered);
2048 }
2049
2050 // If the packet is already retransmitted do not retransmit it
2051 if (!m_txBuffer->IsRetransmittedDataAcked(ackNumber + m_tcb->m_segmentSize))
2052 {
2053 DoRetransmit(); // Assume the next seq is lost. Retransmit lost packet
2055 }
2056
2057 // This partial ACK acknowledge the fact that one segment has been
2058 // previously lost and now successfully received. All others have
2059 // been processed when they come under the form of dupACKs
2060 m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_lastRtt);
2061 NewAck(ackNumber, m_isFirstPartialAck);
2062
2064 {
2065 NS_LOG_DEBUG("Partial ACK of " << ackNumber
2066 << " and this is the first (RTO will be reset);"
2067 " cwnd set to "
2068 << m_tcb->m_cWnd << " recover seq: " << m_recover
2069 << " dupAck count: " << m_dupAckCount);
2070 m_isFirstPartialAck = false;
2071 }
2072 else
2073 {
2074 NS_LOG_DEBUG("Partial ACK of "
2075 << ackNumber
2076 << " and this is NOT the first (RTO will not be reset)"
2077 " cwnd set to "
2078 << m_tcb->m_cWnd << " recover seq: " << m_recover
2079 << " dupAck count: " << m_dupAckCount);
2080 }
2081 }
2082 // From RFC 6675 section 5.1
2083 // In addition, a new recovery phase (as described in Section 5) MUST NOT
2084 // be initiated until HighACK is greater than or equal to the new value
2085 // of RecoveryPoint.
2086 else if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_LOSS)
2087 {
2088 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_lastRtt);
2089 m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2090
2091 NS_LOG_DEBUG(" Cong Control Called, cWnd=" << m_tcb->m_cWnd
2092 << " ssTh=" << m_tcb->m_ssThresh);
2093 if (!m_sackEnabled)
2094 {
2096 m_txBuffer->GetSacked() == 0,
2097 "Some segment got dup-acked in CA_LOSS state: " << m_txBuffer->GetSacked());
2098 }
2099 NewAck(ackNumber, true);
2100 }
2102 {
2103 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_lastRtt);
2104 // TODO: need to check behavior if marking is compounded by loss
2105 // and/or packet reordering
2106 if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2107 {
2108 m_recoveryOps->DoRecovery(m_tcb, currentDelivered);
2109 }
2110 NewAck(ackNumber, true);
2111 }
2112 else
2113 {
2115 {
2116 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_lastRtt);
2117 }
2119 {
2120 if (segsAcked >= oldDupAckCount)
2121 {
2122 m_congestionControl->PktsAcked(m_tcb,
2123 segsAcked - oldDupAckCount,
2124 m_tcb->m_lastRtt);
2125 }
2126
2127 if (!isDupack)
2128 {
2129 // The network reorder packets. Linux changes the counting lost
2130 // packet algorithm from FACK to NewReno. We simply go back in Open.
2133 NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2134 << " exiting CA_DISORDER -> CA_OPEN");
2135 }
2136 else
2137 {
2138 NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2139 << " but still in CA_DISORDER");
2140 }
2141 }
2142 // RFC 6675, Section 5:
2143 // Once a TCP is in the loss recovery phase, the following procedure
2144 // MUST be used for each arriving ACK:
2145 // (A) An incoming cumulative ACK for a sequence number greater than
2146 // RecoveryPoint signals the end of loss recovery, and the loss
2147 // recovery phase MUST be terminated. Any information contained in
2148 // the scoreboard for sequence numbers greater than the new value of
2149 // HighACK SHOULD NOT be cleared when leaving the loss recovery
2150 // phase.
2152 {
2153 m_isFirstPartialAck = true;
2154
2155 // Recalculate the segs acked, that are from m_recover to ackNumber
2156 // (which are the ones we have not passed to PktsAcked and that
2157 // can increase cWnd)
2158 // TODO: check consistency for dynamic segment size
2159 segsAcked =
2160 static_cast<uint32_t>(ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
2161 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_lastRtt);
2165 exitedFastRecovery = true;
2166 m_dupAckCount = 0; // From recovery to open, reset dupack
2167
2168 NS_LOG_DEBUG(segsAcked << " segments acked in CA_RECOVER, ack of " << ackNumber
2169 << ", exiting CA_RECOVERY -> CA_OPEN");
2170 }
2172 {
2173 m_isFirstPartialAck = true;
2174
2175 // Recalculate the segs acked, that are from m_recover to ackNumber
2176 // (which are the ones we have not passed to PktsAcked and that
2177 // can increase cWnd)
2178 segsAcked = (ackNumber - m_recover) / m_tcb->m_segmentSize;
2179
2180 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_lastRtt);
2181
2184 NS_LOG_DEBUG(segsAcked << " segments acked in CA_LOSS, ack of" << ackNumber
2185 << ", exiting CA_LOSS -> CA_OPEN");
2186 }
2187
2188 if (ackNumber >= m_recover)
2189 {
2190 // All lost segments in the congestion event have been
2191 // retransmitted successfully. The recovery point (m_recover)
2192 // should be deactivated.
2193 m_recoverActive = false;
2194 }
2195
2196 if (exitedFastRecovery)
2197 {
2198 NewAck(ackNumber, true);
2200 m_recoveryOps->ExitRecovery(m_tcb);
2201 NS_LOG_DEBUG("Leaving Fast Recovery; BytesInFlight() = "
2202 << BytesInFlight() << "; cWnd = " << m_tcb->m_cWnd);
2203 }
2205 {
2206 m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2207
2209
2210 NS_LOG_LOGIC("Congestion control called: "
2211 << " cWnd: " << m_tcb->m_cWnd << " ssTh: " << m_tcb->m_ssThresh
2212 << " segsAcked: " << segsAcked);
2213
2214 NewAck(ackNumber, true);
2215 }
2216 }
2217 }
2218 // Update the pacing rate, since m_congestionControl->IncreaseWindow() or
2219 // m_congestionControl->PktsAcked () may change m_tcb->m_cWnd
2220 // Make sure that control reaches the end of this function and there is no
2221 // return in between
2223}
2224
2225/* Received a packet upon LISTEN state. */
2226void
2228 const TcpHeader& tcpHeader,
2229 const Address& fromAddress,
2230 const Address& toAddress)
2231{
2232 NS_LOG_FUNCTION(this << tcpHeader);
2233
2234 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2235 uint8_t tcpflags =
2237
2238 // Fork a socket if received a SYN. Do nothing otherwise.
2239 // C.f.: the LISTEN part in tcp_v4_do_rcv() in tcp_ipv4.c in Linux kernel
2240 if (tcpflags != TcpHeader::SYN)
2241 {
2242 return;
2243 }
2244
2245 // Call socket's notify function to let the server app know we got a SYN
2246 // If the server app refuses the connection, do nothing
2247 if (!NotifyConnectionRequest(fromAddress))
2248 {
2249 return;
2250 }
2251 // Clone the socket, simulate fork
2252 Ptr<TcpSocketBase> newSock = Fork();
2253 NS_LOG_LOGIC("Cloned a TcpSocketBase " << newSock);
2255 newSock,
2256 packet,
2257 tcpHeader,
2258 fromAddress,
2259 toAddress);
2260}
2261
2262/* Received a packet upon SYN_SENT */
2263void
2265{
2266 NS_LOG_FUNCTION(this << tcpHeader);
2267
2268 // Extract the flags. PSH and URG are disregarded.
2269 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2270
2271 if (tcpflags == 0)
2272 { // Bare data, accept it and move to ESTABLISHED state. This is not a normal behaviour. Remove
2273 // this?
2274 NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2278 m_connected = true;
2281 ReceivedData(packet, tcpHeader);
2283 }
2284 else if (tcpflags & TcpHeader::ACK && !(tcpflags & TcpHeader::SYN))
2285 { // Ignore ACK in SYN_SENT
2286 }
2287 else if (tcpflags & TcpHeader::SYN && !(tcpflags & TcpHeader::ACK))
2288 { // Received SYN, move to SYN_RCVD state and respond with SYN+ACK
2289 NS_LOG_DEBUG("SYN_SENT -> SYN_RCVD");
2290 m_state = SYN_RCVD;
2292 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2293 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2294 * the traffic is ECN capable and sender has sent ECN SYN packet
2295 */
2296
2299 {
2300 NS_LOG_INFO("Received ECN SYN packet");
2304 }
2305 else
2306 {
2309 }
2310 }
2311 else if (tcpflags & (TcpHeader::SYN | TcpHeader::ACK) &&
2313 { // Handshake completed
2314 NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2318 m_connected = true;
2320 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2322 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2323 // Before sending packets, update the pacing rate based on RTT measurement so far
2326
2327 /* Check if we received an ECN SYN-ACK packet. Change the ECN state of sender to ECN_IDLE if
2328 * receiver has sent an ECN SYN-ACK packet and the traffic is ECN Capable
2329 */
2331 (tcpflags & (TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::ECE))
2332 {
2333 NS_LOG_INFO("Received ECN SYN-ACK packet.");
2336 }
2337 else
2338 {
2340 }
2343 // Always respond to first data packet to speed up the connection.
2344 // Remove to get the behaviour of old NS-3 code.
2346 }
2347 else
2348 { // Other in-sequence input
2349 if (!(tcpflags & TcpHeader::RST))
2350 { // When (1) rx of FIN+ACK; (2) rx of FIN; (3) rx of bad flags
2351 NS_LOG_LOGIC("Illegal flag combination "
2352 << TcpHeader::FlagsToString(tcpHeader.GetFlags())
2353 << " received in SYN_SENT. Reset packet is sent.");
2354 SendRST();
2355 }
2357 }
2358}
2359
2360/* Received a packet upon SYN_RCVD */
2361void
2363 const TcpHeader& tcpHeader,
2364 const Address& fromAddress,
2365 const Address& /* toAddress */)
2366{
2367 NS_LOG_FUNCTION(this << tcpHeader);
2368
2369 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2370 uint8_t tcpflags =
2372
2373 if (tcpflags == 0 ||
2374 (tcpflags == TcpHeader::ACK &&
2376 { // If it is bare data, accept it and move to ESTABLISHED state. This is
2377 // possibly due to ACK lost in 3WHS. If in-sequence ACK is received, the
2378 // handshake is completed nicely.
2379 NS_LOG_DEBUG("SYN_RCVD -> ESTABLISHED");
2383 m_connected = true;
2386 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2387 if (m_endPoint)
2388 {
2389 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2390 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2391 }
2392 else if (m_endPoint6)
2393 {
2394 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2395 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2396 }
2397 // Always respond to first data packet to speed up the connection.
2398 // Remove to get the behaviour of old NS-3 code.
2400 NotifyNewConnectionCreated(this, fromAddress);
2401 ReceivedAck(packet, tcpHeader);
2402 // Update the pacing rate based on RTT measurement so far
2404 // As this connection is established, the socket is available to send data now
2405 if (GetTxAvailable() > 0)
2406 {
2408 }
2409 }
2410 else if (tcpflags == TcpHeader::SYN)
2411 { // Probably the peer lost my SYN+ACK
2412 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2413 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2414 * sender has sent an ECN SYN packet and the traffic is ECN Capable
2415 */
2417 (tcpHeader.GetFlags() & (TcpHeader::CWR | TcpHeader::ECE)) ==
2419 {
2420 NS_LOG_INFO("Received ECN SYN packet");
2424 }
2425 else
2426 {
2429 }
2430 }
2431 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2432 {
2433 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2434 { // In-sequence FIN before connection complete. Set up connection and close.
2435 m_connected = true;
2438 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2439 if (m_endPoint)
2440 {
2441 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2442 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2443 }
2444 else if (m_endPoint6)
2445 {
2446 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2447 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2448 }
2449 NotifyNewConnectionCreated(this, fromAddress);
2450 PeerClose(packet, tcpHeader);
2451 }
2452 }
2453 else
2454 { // Other in-sequence input
2455 if (tcpflags != TcpHeader::RST)
2456 { // When (1) rx of SYN+ACK; (2) rx of FIN; (3) rx of bad flags
2457 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2458 << " received. Reset packet is sent.");
2459 if (m_endPoint)
2460 {
2461 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2462 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2463 }
2464 else if (m_endPoint6)
2465 {
2466 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2467 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2468 }
2469 SendRST();
2470 }
2472 }
2473}
2474
2475/* Received a packet upon CLOSE_WAIT, FIN_WAIT_1, or FIN_WAIT_2 states */
2476void
2478{
2479 NS_LOG_FUNCTION(this << tcpHeader);
2480
2481 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2482 uint8_t tcpflags =
2484
2485 if (packet->GetSize() > 0 && !(tcpflags & TcpHeader::ACK))
2486 { // Bare data, accept it
2487 ReceivedData(packet, tcpHeader);
2488 }
2489 else if (tcpflags == TcpHeader::ACK)
2490 { // Process the ACK, and if in FIN_WAIT_1, conditionally move to FIN_WAIT_2
2491 ReceivedAck(packet, tcpHeader);
2492 if (m_state == FIN_WAIT_1 && m_txBuffer->Size() == 0 &&
2493 tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2494 { // This ACK corresponds to the FIN sent
2495 NS_LOG_DEBUG("FIN_WAIT_1 -> FIN_WAIT_2");
2497 }
2498 }
2499 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2500 { // Got FIN, respond with ACK and move to next state
2501 if (tcpflags & TcpHeader::ACK)
2502 { // Process the ACK first
2503 ReceivedAck(packet, tcpHeader);
2504 }
2505 m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber());
2506 }
2507 else if (tcpflags == TcpHeader::SYN || tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
2508 { // Duplicated SYN or SYN+ACK, possibly due to spurious retransmission
2509 return;
2510 }
2511 else
2512 { // This is a RST or bad flags
2513 if (tcpflags != TcpHeader::RST)
2514 {
2515 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2516 << " received. Reset packet is sent.");
2517 SendRST();
2518 }
2520 return;
2521 }
2522
2523 // Check if the close responder sent an in-sequence FIN, if so, respond ACK
2524 if ((m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2) && m_tcb->m_rxBuffer->Finished())
2525 {
2526 if (m_state == FIN_WAIT_1)
2527 {
2528 NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2529 m_state = CLOSING;
2530 if (m_txBuffer->Size() == 0 &&
2531 tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2532 { // This ACK corresponds to the FIN sent
2533 TimeWait();
2534 }
2535 }
2536 else if (m_state == FIN_WAIT_2)
2537 {
2538 TimeWait();
2539 }
2541 if (!m_shutdownRecv)
2542 {
2544 }
2545 }
2546}
2547
2548/* Received a packet upon CLOSING */
2549void
2551{
2552 NS_LOG_FUNCTION(this << tcpHeader);
2553
2554 // Extract the flags. PSH and URG are disregarded.
2555 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2556
2557 if (tcpflags == TcpHeader::ACK)
2558 {
2559 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2560 { // This ACK corresponds to the FIN sent
2561 TimeWait();
2562 }
2563 }
2564 else
2565 { // CLOSING state means simultaneous close, i.e. no one is sending data to
2566 // anyone. If anything other than ACK is received, respond with a reset.
2567 if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2568 { // FIN from the peer as well. We can close immediately.
2570 }
2571 else if (tcpflags != TcpHeader::RST)
2572 { // Receive of SYN or SYN+ACK or bad flags or pure data
2573 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2574 << " received. Reset packet is sent.");
2575 SendRST();
2576 }
2578 }
2579}
2580
2581/* Received a packet upon LAST_ACK */
2582void
2584{
2585 NS_LOG_FUNCTION(this << tcpHeader);
2586
2587 // Extract the flags. PSH and URG are disregarded.
2588 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2589
2590 if (tcpflags == 0)
2591 {
2592 ReceivedData(packet, tcpHeader);
2593 }
2594 else if (tcpflags == TcpHeader::ACK)
2595 {
2596 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2597 { // This ACK corresponds to the FIN sent. This socket closed peacefully.
2599 }
2600 }
2601 else if (tcpflags == TcpHeader::FIN)
2602 { // Received FIN again, the peer probably lost the FIN+ACK
2604 }
2605 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK) || tcpflags == TcpHeader::RST)
2606 {
2608 }
2609 else
2610 { // Received a SYN or SYN+ACK or bad flags
2611 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2612 << " received. Reset packet is sent.");
2613 SendRST();
2615 }
2616}
2617
2618/* Peer sent me a FIN. Remember its sequence in rx buffer. */
2619void
2621{
2622 NS_LOG_FUNCTION(this << tcpHeader);
2623
2624 // Ignore all out of range packets
2625 if (tcpHeader.GetSequenceNumber() < m_tcb->m_rxBuffer->NextRxSequence() ||
2626 tcpHeader.GetSequenceNumber() > m_tcb->m_rxBuffer->MaxRxSequence())
2627 {
2628 return;
2629 }
2630 // For any case, remember the FIN position in rx buffer first
2631 m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber() +
2632 SequenceNumber32(p->GetSize()));
2633 NS_LOG_LOGIC("Accepted FIN at seq "
2634 << tcpHeader.GetSequenceNumber() + SequenceNumber32(p->GetSize()));
2635 // If there is any piggybacked data, process it
2636 if (p->GetSize())
2637 {
2638 ReceivedData(p, tcpHeader);
2639 }
2640 // Return if FIN is out of sequence, otherwise move to CLOSE_WAIT state by DoPeerClose
2641 if (!m_tcb->m_rxBuffer->Finished())
2642 {
2643 return;
2644 }
2645
2646 // Simultaneous close: Application invoked Close() when we are processing this FIN packet
2647 if (m_state == FIN_WAIT_1)
2648 {
2649 NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2650 m_state = CLOSING;
2651 return;
2652 }
2653
2654 DoPeerClose(); // Change state, respond with ACK
2655}
2656
2657/* Received a in-sequence FIN. Close down this socket. */
2658void
2660{
2662 m_state == FIN_WAIT_2);
2663
2664 // Move the state to CLOSE_WAIT
2665 NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSE_WAIT");
2667
2668 if (!m_closeNotified)
2669 {
2670 // The normal behaviour for an application is that, when the peer sent a in-sequence
2671 // FIN, the app should prepare to close. The app has two choices at this point: either
2672 // respond with ShutdownSend() call to declare that it has nothing more to send and
2673 // the socket can be closed immediately; or remember the peer's close request, wait
2674 // until all its existing data are pushed into the TCP socket, then call Close()
2675 // explicitly.
2676 NS_LOG_LOGIC("TCP " << this << " calling NotifyNormalClose");
2678 m_closeNotified = true;
2679 }
2680 if (m_shutdownSend)
2681 { // The application declares that it would not sent any more, close this socket
2682 Close();
2683 }
2684 else
2685 { // Need to ack, the application will close later
2687 }
2688 if (m_state == LAST_ACK)
2689 {
2690 m_dataRetrCount = m_dataRetries; // prevent endless FINs
2691 NS_LOG_LOGIC("TcpSocketBase " << this << " scheduling LATO1");
2692 Time lastRto = m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4);
2694 }
2695}
2696
2697/* Kill this socket. This is a callback function configured to m_endpoint in
2698 SetupCallback(), invoked when the endpoint is destroyed. */
2699void
2701{
2702 NS_LOG_FUNCTION(this);
2703 m_endPoint = nullptr;
2704 if (m_tcp)
2705 {
2706 m_tcp->RemoveSocket(this);
2707 }
2708 NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2709 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2711}
2712
2713/* Kill this socket. This is a callback function configured to m_endpoint in
2714 SetupCallback(), invoked when the endpoint is destroyed. */
2715void
2717{
2718 NS_LOG_FUNCTION(this);
2719 m_endPoint6 = nullptr;
2720 if (m_tcp)
2721 {
2722 m_tcp->RemoveSocket(this);
2723 }
2724 NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2725 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2727}
2728
2729/* Send an empty packet with specified TCP flags */
2730void
2732{
2733 NS_LOG_FUNCTION(this << static_cast<uint32_t>(flags));
2734
2735 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
2736 {
2737 NS_LOG_WARN("Failed to send empty packet due to null endpoint");
2738 return;
2739 }
2740
2741 Ptr<Packet> p = Create<Packet>();
2742 TcpHeader header;
2744
2745 if (flags & TcpHeader::FIN)
2746 {
2747 flags |= TcpHeader::ACK;
2748 }
2749 else if (m_state == FIN_WAIT_1 || m_state == LAST_ACK || m_state == CLOSING)
2750 {
2751 ++s;
2752 }
2753
2754 AddSocketTags(p);
2755
2756 header.SetFlags(flags);
2757 header.SetSequenceNumber(s);
2758 header.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
2759 if (m_endPoint != nullptr)
2760 {
2763 }
2764 else
2765 {
2768 }
2769 AddOptions(header);
2770
2771 // RFC 6298, clause 2.4
2772 m_rto =
2773 Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4), m_minRto);
2774
2775 uint16_t windowSize = AdvertisedWindowSize();
2776 bool hasSyn = flags & TcpHeader::SYN;
2777 bool hasFin = flags & TcpHeader::FIN;
2778 bool isAck = flags == TcpHeader::ACK;
2779 if (hasSyn)
2780 {
2782 { // The window scaling option is set only on SYN packets
2783 AddOptionWScale(header);
2784 }
2785
2786 if (m_sackEnabled)
2787 {
2788 AddOptionSackPermitted(header);
2789 }
2790
2791 if (m_synCount == 0)
2792 { // No more connection retries, give up
2793 NS_LOG_LOGIC("Connection failed.");
2794 m_rtt->Reset(); // According to recommendation -> RFC 6298
2796 m_state = CLOSED;
2798 return;
2799 }
2800 else
2801 { // Exponential backoff of connection time out
2802 int backoffCount = 0x1 << (m_synRetries - m_synCount);
2803 m_rto = m_cnTimeout * backoffCount;
2804 m_synCount--;
2805 }
2806
2807 if (m_synRetries - 1 == m_synCount)
2808 {
2809 UpdateRttHistory(s, 0, false);
2810 }
2811 else
2812 { // This is SYN retransmission
2813 UpdateRttHistory(s, 0, true);
2814 }
2815
2816 windowSize = AdvertisedWindowSize(false);
2817 }
2818 header.SetWindowSize(windowSize);
2819
2820 if (flags & TcpHeader::ACK)
2821 { // If sending an ACK, cancel the delay ACK as well
2823 m_delAckCount = 0;
2824 if (m_highTxAck < header.GetAckNumber())
2825 {
2826 m_highTxAck = header.GetAckNumber();
2827 }
2828 if (m_sackEnabled && m_tcb->m_rxBuffer->GetSackListSize() > 0)
2829 {
2830 AddOptionSack(header);
2831 }
2832 NS_LOG_INFO("Sending a pure ACK, acking seq " << m_tcb->m_rxBuffer->NextRxSequence());
2833 }
2834
2835 m_txTrace(p, header, this);
2836
2837 if (m_endPoint != nullptr)
2838 {
2839 m_tcp->SendPacket(p,
2840 header,
2844 }
2845 else
2846 {
2847 m_tcp->SendPacket(p,
2848 header,
2852 }
2853
2854 if (m_retxEvent.IsExpired() && (hasSyn || hasFin) && !isAck)
2855 { // Retransmit SYN / SYN+ACK / FIN / FIN+ACK to guard against lost
2856 NS_LOG_LOGIC("Schedule retransmission timeout at time "
2857 << Simulator::Now().GetSeconds() << " to expire at time "
2858 << (Simulator::Now() + m_rto.Get()).GetSeconds());
2860 }
2861}
2862
2863/* This function closes the endpoint completely. Called upon RST_TX action. */
2864void
2866{
2867 NS_LOG_FUNCTION(this);
2871}
2872
2873/* Deallocate the end point and cancel all the timers */
2874void
2876{
2877 // note: it shouldn't be necessary to invalidate the callback and manually call
2878 // TcpL4Protocol::RemoveSocket. Alas, if one relies on the endpoint destruction
2879 // callback, there's a weird memory access to a free'd area. Harmless, but valgrind
2880 // considers it an error.
2881
2882 if (m_endPoint != nullptr)
2883 {
2885 m_endPoint->SetDestroyCallback(MakeNullCallback<void>());
2886 m_tcp->DeAllocate(m_endPoint);
2887 m_endPoint = nullptr;
2888 m_tcp->RemoveSocket(this);
2889 }
2890 else if (m_endPoint6 != nullptr)
2891 {
2893 m_endPoint6->SetDestroyCallback(MakeNullCallback<void>());
2894 m_tcp->DeAllocate(m_endPoint6);
2895 m_endPoint6 = nullptr;
2896 m_tcp->RemoveSocket(this);
2897 }
2898}
2899
2900/* Configure the endpoint to a local address. Called by Connect() if Bind() didn't specify one. */
2901int
2903{
2904 NS_LOG_FUNCTION(this);
2905 Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4>();
2906 NS_ASSERT(ipv4);
2907 if (!ipv4->GetRoutingProtocol())
2908 {
2909 NS_FATAL_ERROR("No Ipv4RoutingProtocol in the node");
2910 }
2911 // Create a dummy packet, then ask the routing function for the best output
2912 // interface's address
2913 Ipv4Header header;
2915 Socket::SocketErrno errno_;
2916 Ptr<Ipv4Route> route;
2918 route = ipv4->GetRoutingProtocol()->RouteOutput(Ptr<Packet>(), header, oif, errno_);
2919 if (!route)
2920 {
2921 NS_LOG_LOGIC("Route to " << m_endPoint->GetPeerAddress() << " does not exist");
2922 NS_LOG_ERROR(errno_);
2923 m_errno = errno_;
2924 return -1;
2925 }
2926 NS_LOG_LOGIC("Route exists");
2927 m_endPoint->SetLocalAddress(route->GetSource());
2928 return 0;
2929}
2930
2931int
2933{
2934 NS_LOG_FUNCTION(this);
2936 NS_ASSERT(ipv6);
2937 if (!ipv6->GetRoutingProtocol())
2938 {
2939 NS_FATAL_ERROR("No Ipv6RoutingProtocol in the node");
2940 }
2941 // Create a dummy packet, then ask the routing function for the best output
2942 // interface's address
2943 Ipv6Header header;
2945 Socket::SocketErrno errno_;
2946 Ptr<Ipv6Route> route;
2948 route = ipv6->GetRoutingProtocol()->RouteOutput(Ptr<Packet>(), header, oif, errno_);
2949 if (!route)
2950 {
2951 NS_LOG_LOGIC("Route to " << m_endPoint6->GetPeerAddress() << " does not exist");
2952 NS_LOG_ERROR(errno_);
2953 m_errno = errno_;
2954 return -1;
2955 }
2956 NS_LOG_LOGIC("Route exists");
2957 m_endPoint6->SetLocalAddress(route->GetSource());
2958 return 0;
2959}
2960
2961/* This function is called only if a SYN received in LISTEN state. After
2962 TcpSocketBase cloned, allocate a new end point to handle the incoming
2963 connection and send a SYN+ACK to complete the handshake. */
2964void
2966 const TcpHeader& h,
2967 const Address& fromAddress,
2968 const Address& toAddress)
2969{
2970 NS_LOG_FUNCTION(this << p << h << fromAddress << toAddress);
2971 // Get port and address from peer (connecting host)
2972 if (InetSocketAddress::IsMatchingType(toAddress))
2973 {
2974 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(),
2975 InetSocketAddress::ConvertFrom(toAddress).GetIpv4(),
2976 InetSocketAddress::ConvertFrom(toAddress).GetPort(),
2977 InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2978 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2979 m_endPoint6 = nullptr;
2980 }
2981 else if (Inet6SocketAddress::IsMatchingType(toAddress))
2982 {
2983 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(),
2984 Inet6SocketAddress::ConvertFrom(toAddress).GetIpv6(),
2985 Inet6SocketAddress::ConvertFrom(toAddress).GetPort(),
2986 Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2987 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2988 m_endPoint = nullptr;
2989 }
2990 m_tcp->AddSocket(this);
2991
2992 // Change the cloned socket from LISTEN state to SYN_RCVD
2993 NS_LOG_DEBUG("LISTEN -> SYN_RCVD");
2994 m_state = SYN_RCVD;
2997 SetupCallback();
2998 // Set the sequence number and send SYN+ACK
2999 m_tcb->m_rxBuffer->SetNextRxSequence(h.GetSequenceNumber() + SequenceNumber32(1));
3000
3001 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
3002 * sender has sent an ECN SYN packet and the traffic is ECN Capable
3003 */
3006 {
3010 }
3011 else
3012 {
3015 }
3016}
3017
3018void
3020{ // Wrapper to protected function NotifyConnectionSucceeded() so that it can
3021 // be called as a scheduled event
3023 // The if-block below was moved from ProcessSynSent() to here because we need
3024 // to invoke the NotifySend() only after NotifyConnectionSucceeded() to
3025 // reflect the behaviour in the real world.
3026 if (GetTxAvailable() > 0)
3027 {
3029 }
3030}
3031
3032void
3034{
3035 /*
3036 * Add tags for each socket option.
3037 * Note that currently the socket adds both IPv4 tag and IPv6 tag
3038 * if both options are set. Once the packet got to layer three, only
3039 * the corresponding tags will be read.
3040 */
3041 if (GetIpTos())
3042 {
3043 SocketIpTosTag ipTosTag;
3045 {
3047 }
3048 else
3049 {
3050 // Set the last received ipTos
3051 ipTosTag.SetTos(GetIpTos());
3052 }
3053 p->AddPacketTag(ipTosTag);
3054 }
3055 else
3056 {
3057 if ((m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && p->GetSize() > 0) ||
3059 {
3060 SocketIpTosTag ipTosTag;
3062 p->AddPacketTag(ipTosTag);
3063 }
3064 }
3065
3066 if (IsManualIpv6Tclass())
3067 {
3068 SocketIpv6TclassTag ipTclassTag;
3070 {
3072 }
3073 else
3074 {
3075 // Set the last received ipTos
3076 ipTclassTag.SetTclass(GetIpv6Tclass());
3077 }
3078 p->AddPacketTag(ipTclassTag);
3079 }
3080 else
3081 {
3082 if ((m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && p->GetSize() > 0) ||
3084 {
3085 SocketIpv6TclassTag ipTclassTag;
3087 p->AddPacketTag(ipTclassTag);
3088 }
3089 }
3090
3091 if (IsManualIpTtl())
3092 {
3093 SocketIpTtlTag ipTtlTag;
3094 ipTtlTag.SetTtl(GetIpTtl());
3095 p->AddPacketTag(ipTtlTag);
3096 }
3097
3099 {
3100 SocketIpv6HopLimitTag ipHopLimitTag;
3101 ipHopLimitTag.SetHopLimit(GetIpv6HopLimit());
3102 p->AddPacketTag(ipHopLimitTag);
3103 }
3104
3105 uint8_t priority = GetPriority();
3106 if (priority)
3107 {
3108 SocketPriorityTag priorityTag;
3109 priorityTag.SetPriority(priority);
3110 p->ReplacePacketTag(priorityTag);
3111 }
3112}
3113
3114/* Extract at most maxSize bytes from the TxBuffer at sequence seq, add the
3115 TCP header, and send to TcpL4Protocol */
3118{
3119 NS_LOG_FUNCTION(this << seq << maxSize << withAck);
3120
3121 bool isStartOfTransmission = BytesInFlight() == 0U;
3122 TcpTxItem* outItem = m_txBuffer->CopyFromSequence(maxSize, seq);
3123
3124 m_rateOps->SkbSent(outItem, isStartOfTransmission);
3125
3126 bool isRetransmission = outItem->IsRetrans();
3127 Ptr<Packet> p = outItem->GetPacketCopy();
3128 uint32_t sz = p->GetSize(); // Size of packet
3129 uint8_t flags = withAck ? TcpHeader::ACK : 0;
3130 uint32_t remainingData = m_txBuffer->SizeFromSequence(seq + SequenceNumber32(sz));
3131
3132 // TCP sender should not send data out of the window advertised by the
3133 // peer when it is not retransmission.
3134 NS_ASSERT(isRetransmission ||
3135 ((m_highRxAckMark + SequenceNumber32(m_rWnd)) >= (seq + SequenceNumber32(maxSize))));
3136
3137 if (IsPacingEnabled())
3138 {
3139 NS_LOG_INFO("Pacing is enabled");
3141 {
3142 NS_LOG_DEBUG("Current Pacing Rate " << m_tcb->m_pacingRate);
3143 NS_LOG_DEBUG("Timer is in expired state, activate it "
3144 << m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3145 m_pacingTimer.Schedule(m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3146 }
3147 else
3148 {
3149 NS_LOG_INFO("Timer is already in running state");
3150 }
3151 }
3152 else
3153 {
3154 NS_LOG_INFO("Pacing is disabled");
3155 }
3156
3157 if (withAck)
3158 {
3160 m_delAckCount = 0;
3161 }
3162
3164 m_ecnEchoSeq.Get() > m_ecnCWRSeq.Get() && !isRetransmission)
3165 {
3168 m_ecnCWRSeq = seq;
3169 flags |= TcpHeader::CWR;
3170 NS_LOG_INFO("CWR flags set");
3171 }
3172
3173 AddSocketTags(p);
3174
3175 if (m_closeOnEmpty && (remainingData == 0))
3176 {
3177 flags |= TcpHeader::FIN;
3178 if (m_state == ESTABLISHED)
3179 { // On active close: I am the first one to send FIN
3180 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
3182 }
3183 else if (m_state == CLOSE_WAIT)
3184 { // On passive close: Peer sent me FIN already
3185 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
3186 m_state = LAST_ACK;
3187 }
3188 }
3189 TcpHeader header;
3190 header.SetFlags(flags);
3191 header.SetSequenceNumber(seq);
3192 header.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
3193 if (m_endPoint)
3194 {
3197 }
3198 else
3199 {
3202 }
3204 AddOptions(header);
3205
3206 if (m_retxEvent.IsExpired())
3207 {
3208 // Schedules retransmit timeout. m_rto should be already doubled.
3209
3210 NS_LOG_LOGIC(this << " SendDataPacket Schedule ReTxTimeout at time "
3211 << Simulator::Now().GetSeconds() << " to expire at time "
3212 << (Simulator::Now() + m_rto.Get()).GetSeconds());
3214 }
3215
3216 m_txTrace(p, header, this);
3217
3218 if (m_endPoint)
3219 {
3220 m_tcp->SendPacket(p,
3221 header,
3225 NS_LOG_DEBUG("Send segment of size "
3226 << sz << " with remaining data " << remainingData << " via TcpL4Protocol to "
3227 << m_endPoint->GetPeerAddress() << ". Header " << header);
3228 }
3229 else
3230 {
3231 m_tcp->SendPacket(p,
3232 header,
3236 NS_LOG_DEBUG("Send segment of size "
3237 << sz << " with remaining data " << remainingData << " via TcpL4Protocol to "
3238 << m_endPoint6->GetPeerAddress() << ". Header " << header);
3239 }
3240
3241 UpdateRttHistory(seq, sz, isRetransmission);
3242
3243 // Update bytes sent during recovery phase
3246 {
3247 m_recoveryOps->UpdateBytesSent(sz);
3248 }
3249
3250 // Notify the application of the data being sent unless this is a retransmit
3251 if (!isRetransmission)
3252 {
3254 this,
3255 (seq + sz - m_tcb->m_highTxMark.Get()));
3256 }
3257 // Update highTxMark
3258 m_tcb->m_highTxMark = std::max(seq + sz, m_tcb->m_highTxMark.Get());
3259 return sz;
3260}
3261
3262void
3263TcpSocketBase::UpdateRttHistory(const SequenceNumber32& seq, uint32_t sz, bool isRetransmission)
3264{
3265 NS_LOG_FUNCTION(this);
3266
3267 // update the history of sequence numbers used to calculate the RTT
3268 if (!isRetransmission)
3269 { // This is the next expected one, just log at end
3270 m_history.emplace_back(seq, sz, Simulator::Now());
3271 }
3272 else
3273 { // This is a retransmit, find in list and mark as re-tx
3274 for (auto i = m_history.begin(); i != m_history.end(); ++i)
3275 {
3276 if ((seq >= i->seq) && (seq < (i->seq + SequenceNumber32(i->count))))
3277 { // Found it
3278 i->retx = true;
3279 i->count = ((seq + SequenceNumber32(sz)) - i->seq); // And update count in hist
3280 break;
3281 }
3282 }
3283 }
3284}
3285
3286// Note that this function did not implement the PSH flag
3289{
3290 NS_LOG_FUNCTION(this << withAck);
3291 if (m_txBuffer->Size() == 0)
3292 {
3293 return 0; // Nothing to send
3294 }
3295 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
3296 {
3298 "TcpSocketBase::SendPendingData: No endpoint; m_shutdownSend=" << m_shutdownSend);
3299 return 0; // Is this the right way to handle this condition?
3300 }
3301
3302 uint32_t nPacketsSent = 0;
3303 uint32_t availableWindow = AvailableWindow();
3304
3305 // RFC 6675, Section (C)
3306 // If cwnd - pipe >= 1 SMSS, the sender SHOULD transmit one or more
3307 // segments as follows:
3308 // (NOTE: We check > 0, and do the checks for segmentSize in the following
3309 // else branch to control silly window syndrome and Nagle)
3310 while (availableWindow > 0)
3311 {
3312 if (IsPacingEnabled())
3313 {
3314 NS_LOG_INFO("Pacing is enabled");
3316 {
3317 NS_LOG_INFO("Skipping Packet due to pacing" << m_pacingTimer.GetDelayLeft());
3318 break;
3319 }
3320 NS_LOG_INFO("Timer is not running");
3321 }
3322
3324 {
3325 NS_LOG_INFO("FIN_WAIT and OPEN state; no data to transmit");
3326 break;
3327 }
3328 // (C.1) The scoreboard MUST be queried via NextSeg () for the
3329 // sequence number range of the next segment to transmit (if
3330 // any), and the given segment sent. If NextSeg () returns
3331 // failure (no data to send), return without sending anything
3332 // (i.e., terminate steps C.1 -- C.5).
3333 SequenceNumber32 next;
3334 SequenceNumber32 nextHigh;
3336 if (!m_txBuffer->NextSeg(&next, &nextHigh, enableRule3))
3337 {
3338 NS_LOG_INFO("no valid seq to transmit, or no data available");
3339 break;
3340 }
3341 else
3342 {
3343 // It's time to transmit, but before do silly window and Nagle's check
3344 uint32_t availableData = m_txBuffer->SizeFromSequence(next);
3345
3346 // If there's less app data than the full window, ask the app for more
3347 // data before trying to send
3348 if (availableData < availableWindow)
3349 {
3351 }
3352
3353 // Stop sending if we need to wait for a larger Tx window (prevent silly window
3354 // syndrome) but continue if we don't have data
3355 if (availableWindow < m_tcb->m_segmentSize && availableData > availableWindow)
3356 {
3357 NS_LOG_LOGIC("Preventing Silly Window Syndrome. Wait to send.");
3358 break; // No more
3359 }
3360 // Nagle's algorithm (RFC896): Hold off sending if there is unacked data
3361 // in the buffer and the amount of data to send is less than one segment
3362 if (!m_noDelay && UnAckDataCount() > 0 && availableData < m_tcb->m_segmentSize)
3363 {
3364 NS_LOG_DEBUG("Invoking Nagle's algorithm for seq "
3365 << next << ", SFS: " << m_txBuffer->SizeFromSequence(next)
3366 << ". Wait to send.");
3367 break;
3368 }
3369
3370 uint32_t s = std::min(availableWindow, m_tcb->m_segmentSize);
3371 // NextSeg () may have further constrained the segment size
3372 auto maxSizeToSend = static_cast<uint32_t>(nextHigh - next);
3373 s = std::min(s, maxSizeToSend);
3374
3375 // (C.2) If any of the data octets sent in (C.1) are below HighData,
3376 // HighRxt MUST be set to the highest sequence number of the
3377 // retransmitted segment unless NextSeg () rule (4) was
3378 // invoked for this retransmission.
3379 // (C.3) If any of the data octets sent in (C.1) are above HighData,
3380 // HighData must be updated to reflect the transmission of
3381 // previously unsent data.
3382 //
3383 // These steps are done in m_txBuffer with the tags.
3384 if (m_tcb->m_nextTxSequence != next)
3385 {
3386 m_tcb->m_nextTxSequence = next;
3387 }
3388 if (m_tcb->m_bytesInFlight.Get() == 0)
3389 {
3391 }
3392 uint32_t sz = SendDataPacket(m_tcb->m_nextTxSequence, s, withAck);
3393
3394 NS_LOG_LOGIC(" rxwin " << m_rWnd << " segsize " << m_tcb->m_segmentSize
3395 << " highestRxAck " << m_txBuffer->HeadSequence() << " pd->Size "
3396 << m_txBuffer->Size() << " pd->SFS "
3397 << m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence));
3398
3399 NS_LOG_DEBUG("cWnd: " << m_tcb->m_cWnd << " total unAck: " << UnAckDataCount()
3400 << " sent seq " << m_tcb->m_nextTxSequence << " size " << sz);
3401 m_tcb->m_nextTxSequence += sz;
3402 ++nPacketsSent;
3403 if (IsPacingEnabled())
3404 {
3405 NS_LOG_INFO("Pacing is enabled");
3407 {
3408 NS_LOG_DEBUG("Current Pacing Rate " << m_tcb->m_pacingRate);
3409 NS_LOG_DEBUG("Timer is in expired state, activate it "
3410 << m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3411 m_pacingTimer.Schedule(m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3412 break;
3413 }
3414 }
3415 }
3416
3417 // (C.4) The estimate of the amount of data outstanding in the
3418 // network must be updated by incrementing pipe by the number
3419 // of octets transmitted in (C.1).
3420 //
3421 // Done in BytesInFlight, inside AvailableWindow.
3422 availableWindow = AvailableWindow();
3423
3424 // (C.5) If cwnd - pipe >= 1 SMSS, return to (C.1)
3425 // loop again!
3426 }
3427
3428 if (nPacketsSent > 0)
3429 {
3430 if (!m_sackEnabled)
3431 {
3432 if (!m_limitedTx)
3433 {
3434 // We can't transmit in CA_DISORDER without limitedTx active
3436 }
3437 }
3438
3439 NS_LOG_DEBUG("SendPendingData sent " << nPacketsSent << " segments");
3440 }
3441 else
3442 {
3443 NS_LOG_DEBUG("SendPendingData no segments sent");
3444 }
3445 return nPacketsSent;
3446}
3447
3450{
3451 return m_tcb->m_highTxMark - m_txBuffer->HeadSequence();
3452}
3453
3456{
3457 uint32_t bytesInFlight = m_txBuffer->BytesInFlight();
3458 // Ugly, but we are not modifying the state; m_bytesInFlight is used
3459 // only for tracing purpose.
3460 m_tcb->m_bytesInFlight = bytesInFlight;
3461
3462 NS_LOG_DEBUG("Returning calculated bytesInFlight: " << bytesInFlight);
3463 return bytesInFlight;
3464}
3465
3468{
3469 return std::min(m_rWnd.Get(), m_tcb->m_cWnd.Get());
3470}
3471
3474{
3475 uint32_t win = Window(); // Number of bytes allowed to be outstanding
3476 uint32_t inflight = BytesInFlight(); // Number of outstanding bytes
3477 return (inflight > win) ? 0 : win - inflight;
3478}
3479
3480uint16_t
3482{
3483 NS_LOG_FUNCTION(this << scale);
3484 uint32_t w;
3485
3486 // We don't want to advertise 0 after a FIN is received. So, we just use
3487 // the previous value of the advWnd.
3488 if (m_tcb->m_rxBuffer->GotFin())
3489 {
3490 w = m_advWnd;
3491 }
3492 else
3493 {
3494 NS_ASSERT_MSG(m_tcb->m_rxBuffer->MaxRxSequence() - m_tcb->m_rxBuffer->NextRxSequence() >= 0,
3495 "Unexpected sequence number values");
3496 w = static_cast<uint32_t>(m_tcb->m_rxBuffer->MaxRxSequence() -
3497 m_tcb->m_rxBuffer->NextRxSequence());
3498 }
3499
3500 // Ugly, but we are not modifying the state, that variable
3501 // is used only for tracing purpose.
3502 if (w != m_advWnd)
3503 {
3504 const_cast<TcpSocketBase*>(this)->m_advWnd = w;
3505 }
3506 if (scale)
3507 {
3508 w >>= m_rcvWindShift;
3509 }
3510 if (w > m_maxWinSize)
3511 {
3512 w = m_maxWinSize;
3513 NS_LOG_WARN("Adv window size truncated to "
3514 << m_maxWinSize << "; possibly to avoid overflow of the 16-bit integer");
3515 }
3516 NS_LOG_LOGIC("Returning AdvertisedWindowSize of " << static_cast<uint16_t>(w));
3517 return static_cast<uint16_t>(w);
3518}
3519
3520// Receipt of new packet, put into Rx buffer
3521void
3523{
3524 NS_LOG_FUNCTION(this << tcpHeader);
3525 NS_LOG_DEBUG("Data segment, seq=" << tcpHeader.GetSequenceNumber()
3526 << " pkt size=" << p->GetSize());
3527
3528 // Put into Rx buffer
3529 SequenceNumber32 expectedSeq = m_tcb->m_rxBuffer->NextRxSequence();
3530 if (!m_tcb->m_rxBuffer->Add(p, tcpHeader))
3531 { // Insert failed: No data or RX buffer full
3534 {
3536 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
3538 }
3539 else
3540 {
3542 }
3543 return;
3544 }
3545 // Notify app to receive if necessary
3546 if (expectedSeq < m_tcb->m_rxBuffer->NextRxSequence())
3547 { // NextRxSeq advanced, we have something to send to the app
3548 if (!m_shutdownRecv)
3549 {
3551 }
3552 // Handle exceptions
3553 if (m_closeNotified)
3554 {
3555 NS_LOG_WARN("Why TCP " << this << " got data after close notification?");
3556 }
3557 // If we received FIN before and now completed all "holes" in rx buffer,
3558 // invoke peer close procedure
3559 if (m_tcb->m_rxBuffer->Finished() && (tcpHeader.GetFlags() & TcpHeader::FIN) == 0)
3560 {
3561 DoPeerClose();
3562 return;
3563 }
3564 }
3565 // Now send a new ACK packet acknowledging all received and delivered data
3566 if (m_tcb->m_rxBuffer->Size() > m_tcb->m_rxBuffer->Available() ||
3567 m_tcb->m_rxBuffer->NextRxSequence() > expectedSeq + p->GetSize())
3568 { // A gap exists in the buffer, or we filled a gap: Always ACK
3572 {
3574 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
3576 }
3577 else
3578 {
3580 }
3581 }
3582 else
3583 { // In-sequence packet: ACK if delayed ack count allows
3585 {
3587 m_delAckCount = 0;
3591 {
3592 NS_LOG_DEBUG("Congestion algo " << m_congestionControl->GetName());
3595 << " -> ECN_SENDING_ECE");
3597 }
3598 else
3599 {
3601 }
3602 }
3603 else if (!m_delAckEvent.IsExpired())
3604 {
3606 }
3607 else if (m_delAckEvent.IsExpired())
3608 {
3613 this << " scheduled delayed ACK at "
3615 }
3616 }
3617}
3618
3619void
3621{
3622 SequenceNumber32 ackSeq = tcpHeader.GetAckNumber();
3623 Time m = Time(0.0);
3624
3625 // An ack has been received, calculate rtt and log this measurement
3626 // Note we use a linear search (O(n)) for this since for the common
3627 // case the ack'ed packet will be at the head of the list
3628 if (!m_history.empty())
3629 {
3630 RttHistory& h = m_history.front();
3631 if (!h.retx && ackSeq >= (h.seq + SequenceNumber32(h.count)))
3632 { // Ok to use this sample
3633 if (m_timestampEnabled && tcpHeader.HasOption(TcpOption::TS))
3634 {
3636 ts = DynamicCast<const TcpOptionTS>(tcpHeader.GetOption(TcpOption::TS));
3637 m = TcpOptionTS::ElapsedTimeFromTsValue(ts->GetEcho());
3638 if (m.IsZero())
3639 {
3640 NS_LOG_LOGIC("TcpSocketBase::EstimateRtt - RTT calculated from TcpOption::TS "
3641 "is zero, approximating to 1us.");
3642 m = MicroSeconds(1);
3643 }
3644 }
3645 else
3646 {
3647 m = Simulator::Now() - h.time; // Elapsed time
3648 }
3649 }
3650 }
3651
3652 // Now delete all ack history with seq <= ack
3653 while (!m_history.empty())
3654 {
3655 RttHistory& h = m_history.front();
3656 if ((h.seq + SequenceNumber32(h.count)) > ackSeq)
3657 {
3658 break; // Done removing
3659 }
3660 m_history.pop_front(); // Remove
3661 }
3662
3663 if (!m.IsZero())
3664 {
3665 m_rtt->Measurement(m); // Log the measurement
3666 // RFC 6298, clause 2.4
3667 m_rto = Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4),
3668 m_minRto);
3669 m_tcb->m_lastRtt = m_rtt->GetEstimate();
3670 m_tcb->m_minRtt = std::min(m_tcb->m_lastRtt.Get(), m_tcb->m_minRtt);
3672 }
3673}
3674
3675// Called by the ReceivedAck() when new ACK received and by ProcessSynRcvd()
3676// when the three-way handshake completed. This cancels retransmission timer
3677// and advances Tx window
3678void
3679TcpSocketBase::NewAck(const SequenceNumber32& ack, bool resetRTO)
3680{
3681 NS_LOG_FUNCTION(this << ack);
3682
3683 // Reset the data retransmission count. We got a new ACK!
3685
3686 if (m_state != SYN_RCVD && resetRTO)
3687 { // Set RTO unless the ACK is received in SYN_RCVD state
3689 this << " Cancelled ReTxTimeout event which was set to expire at "
3690 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
3692 // On receiving a "New" ack we restart retransmission timer .. RFC 6298
3693 // RFC 6298, clause 2.4
3694 m_rto = Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4),
3695 m_minRto);
3696
3697 NS_LOG_LOGIC(this << " Schedule ReTxTimeout at time " << Simulator::Now().GetSeconds()
3698 << " to expire at time "
3699 << (Simulator::Now() + m_rto.Get()).GetSeconds());
3701 }
3702
3703 // Note the highest ACK and tell app to send more
3704 NS_LOG_LOGIC("TCP " << this << " NewAck " << ack << " numberAck "
3705 << (ack - m_txBuffer->HeadSequence())); // Number bytes ack'ed
3706
3707 if (GetTxAvailable() > 0)
3708 {
3710 }
3711 if (ack > m_tcb->m_nextTxSequence)
3712 {
3713 m_tcb->m_nextTxSequence = ack; // If advanced
3714 }
3715 if (m_txBuffer->Size() == 0 && m_state != FIN_WAIT_1 && m_state != CLOSING)
3716 { // No retransmit timer if no data to retransmit
3718 this << " Cancelled ReTxTimeout event which was set to expire at "
3719 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
3721 }
3722}
3723
3724// Retransmit timeout
3725void
3727{
3728 NS_LOG_FUNCTION(this);
3729 NS_LOG_LOGIC(this << " ReTxTimeout Expired at time " << Simulator::Now().GetSeconds());
3730 // If erroneous timeout in closed/timed-wait state, just return
3731 if (m_state == CLOSED || m_state == TIME_WAIT)
3732 {
3733 return;
3734 }
3735
3736 if (m_state == SYN_SENT)
3737 {
3738 NS_ASSERT(m_synCount > 0);
3740 {
3742 }
3743 else
3744 {
3746 }
3747 return;
3748 }
3749
3750 // Retransmit non-data packet: Only if in FIN_WAIT_1 or CLOSING state
3751 if (m_txBuffer->Size() == 0)
3752 {
3753 if (m_state == FIN_WAIT_1 || m_state == CLOSING)
3754 { // Must have lost FIN, re-send
3756 }
3757 return;
3758 }
3759
3760 NS_LOG_DEBUG("Checking if Connection is Established");
3761 // If all data are received (non-closing socket and nothing to send), just return
3762 if (m_state <= ESTABLISHED && m_txBuffer->HeadSequence() >= m_tcb->m_highTxMark &&
3763 m_txBuffer->Size() == 0)
3764 {
3765 NS_LOG_DEBUG("Already Sent full data" << m_txBuffer->HeadSequence() << " "
3766 << m_tcb->m_highTxMark);
3767 return;
3768 }
3769
3770 if (m_dataRetrCount == 0)
3771 {
3772 NS_LOG_INFO("No more data retries available. Dropping connection");
3775 return;
3776 }
3777 else
3778 {
3780 }
3781
3782 uint32_t inFlightBeforeRto = BytesInFlight();
3783 bool resetSack = !m_sackEnabled; // Reset SACK information if SACK is not enabled.
3784 // The information in the TcpTxBuffer is guessed, in this case.
3785
3786 // Reset dupAckCount
3787 m_dupAckCount = 0;
3788 if (!m_sackEnabled)
3789 {
3790 m_txBuffer->ResetRenoSack();
3791 }
3792
3793 // From RFC 6675, Section 5.1
3794 // [RFC2018] suggests that a TCP sender SHOULD expunge the SACK
3795 // information gathered from a receiver upon a retransmission timeout
3796 // (RTO) "since the timeout might indicate that the data receiver has
3797 // reneged." Additionally, a TCP sender MUST "ignore prior SACK
3798 // information in determining which data to retransmit."
3799 // It has been suggested that, as long as robust tests for
3800 // reneging are present, an implementation can retain and use SACK
3801 // information across a timeout event [Errata1610].
3802 // The head of the sent list will not be marked as sacked, therefore
3803 // will be retransmitted, if the receiver renegotiate the SACK blocks
3804 // that we received.
3805 m_txBuffer->SetSentListLost(resetSack);
3806
3807 // From RFC 6675, Section 5.1
3808 // If an RTO occurs during loss recovery as specified in this document,
3809 // RecoveryPoint MUST be set to HighData. Further, the new value of
3810 // RecoveryPoint MUST be preserved and the loss recovery algorithm
3811 // outlined in this document MUST be terminated.
3813 m_recoverActive = true;
3814
3815 // RFC 6298, clause 2.5, double the timer
3816 Time doubledRto = m_rto + m_rto;
3817 m_rto = Min(doubledRto, Time::FromDouble(60, Time::S));
3818
3819 // Empty RTT history
3820 m_history.clear();
3821
3822 // Please don't reset highTxMark, it is used for retransmission detection
3823
3824 // When a TCP sender detects segment loss using the retransmission timer
3825 // and the given segment has not yet been resent by way of the
3826 // retransmission timer, decrease ssThresh
3827 if (m_tcb->m_congState != TcpSocketState::CA_LOSS || !m_txBuffer->IsHeadRetransmitted())
3828 {
3829 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, inFlightBeforeRto);
3830 }
3831
3832 // Cwnd set to 1 MSS
3838
3840
3841 NS_LOG_DEBUG("RTO. Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to " << m_tcb->m_ssThresh
3842 << ", restart from seqnum " << m_txBuffer->HeadSequence()
3843 << " doubled rto to " << m_rto.Get().GetSeconds() << " s");
3844
3846 "There are some bytes in flight after an RTO: " << BytesInFlight());
3847
3849
3851 "In flight (" << BytesInFlight() << ") there is more than one segment ("
3852 << m_tcb->m_segmentSize << ")");
3853}
3854
3855void
3857{
3858 m_delAckCount = 0;
3862 {
3865 }
3866 else
3867 {
3869 }
3870}
3871
3872void
3874{
3875 NS_LOG_FUNCTION(this);
3876
3878 if (m_state == LAST_ACK)
3879 {
3880 if (m_dataRetrCount == 0)
3881 {
3882 NS_LOG_INFO("LAST-ACK: No more data retries available. Dropping connection");
3885 return;
3886 }
3889 NS_LOG_LOGIC("TcpSocketBase " << this << " rescheduling LATO1");
3890 Time lastRto = m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4);
3892 }
3893}
3894
3895// Send 1-byte data to probe for the window size at the receiver when
3896// the local knowledge tells that the receiver has zero window size
3897// C.f.: RFC793 p.42, RFC1112 sec.4.2.2.17
3898void
3900{
3901 NS_LOG_LOGIC("PersistTimeout expired at " << Simulator::Now().GetSeconds());
3903 std::min(Seconds(60), Time(2 * m_persistTimeout)); // max persist timeout = 60s
3904 Ptr<Packet> p = m_txBuffer->CopyFromSequence(1, m_tcb->m_nextTxSequence)->GetPacketCopy();
3905 m_txBuffer->ResetLastSegmentSent();
3906 TcpHeader tcpHeader;
3908 tcpHeader.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
3910 if (m_endPoint != nullptr)
3911 {
3914 }
3915 else
3916 {
3919 }
3920 AddOptions(tcpHeader);
3921 // Send a packet tag for setting ECT bits in IP header
3923 {
3924 SocketIpTosTag ipTosTag;
3926 p->AddPacketTag(ipTosTag);
3927
3928 SocketIpv6TclassTag ipTclassTag;
3930 p->AddPacketTag(ipTclassTag);
3931 }
3932 m_txTrace(p, tcpHeader, this);
3933
3934 if (m_endPoint != nullptr)
3935 {
3936 m_tcp->SendPacket(p,
3937 tcpHeader,
3941 }
3942 else
3943 {
3944 m_tcp->SendPacket(p,
3945 tcpHeader,
3949 }
3950
3951 NS_LOG_LOGIC("Schedule persist timeout at time "
3952 << Simulator::Now().GetSeconds() << " to expire at time "
3953 << (Simulator::Now() + m_persistTimeout).GetSeconds());
3955}
3956
3957void
3959{
3960 NS_LOG_FUNCTION(this);
3961 bool res;
3962 SequenceNumber32 seq;
3963 SequenceNumber32 seqHigh;
3964 uint32_t maxSizeToSend;
3965
3966 // Find the first segment marked as lost and not retransmitted. With Reno,
3967 // that should be the head
3968 res = m_txBuffer->NextSeg(&seq, &seqHigh, false);
3969 if (!res)
3970 {
3971 // We have already retransmitted the head. However, we still received
3972 // three dupacks, or the RTO expired, but no data to transmit.
3973 // Therefore, re-send again the head.
3974 seq = m_txBuffer->HeadSequence();
3975 maxSizeToSend = m_tcb->m_segmentSize;
3976 }
3977 else
3978 {
3979 // NextSeg() may constrain the segment size when res is true
3980 maxSizeToSend = static_cast<uint32_t>(seqHigh - seq);
3981 }
3982 NS_ASSERT(m_sackEnabled || seq == m_txBuffer->HeadSequence());
3983
3984 NS_LOG_INFO("Retransmitting " << seq);
3985 // Update the trace and retransmit the segment
3986 m_tcb->m_nextTxSequence = seq;
3987 uint32_t sz = SendDataPacket(m_tcb->m_nextTxSequence, maxSizeToSend, true);
3988
3989 NS_ASSERT(sz > 0);
3990}
3991
3992void
3994{
4002}
4003
4004/* Move TCP to Time_Wait state and schedule a transition to Closed state */
4005void
4007{
4008 NS_LOG_DEBUG(TcpStateName[m_state] << " -> TIME_WAIT");
4011 if (!m_closeNotified)
4012 {
4013 // Technically the connection is not fully closed, but we notify now
4014 // because an implementation (real socket) would behave as if closed.
4015 // Notify normal close when entering TIME_WAIT or leaving LAST_ACK.
4017 m_closeNotified = true;
4018 }
4019 // Move from TIME_WAIT to CLOSED after 2*MSL. Max segment lifetime is 2 min
4020 // according to RFC793, p.28
4022}
4023
4024/* Below are the attribute get/set functions */
4025
4026void
4028{
4029 NS_LOG_FUNCTION(this << size);
4030 m_txBuffer->SetMaxBufferSize(size);
4031}
4032
4035{
4036 return m_txBuffer->MaxBufferSize();
4037}
4038
4039void
4041{
4042 NS_LOG_FUNCTION(this << size);
4043 uint32_t oldSize = GetRcvBufSize();
4044
4045 m_tcb->m_rxBuffer->SetMaxBufferSize(size);
4046
4047 /* The size has (manually) increased. Actively inform the other end to prevent
4048 * stale zero-window states.
4049 */
4050 if (oldSize < size && m_connected)
4051 {
4054 {
4056 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
4058 }
4059 else
4060 {
4062 }
4063 }
4064}
4065
4068{
4069 return m_tcb->m_rxBuffer->MaxBufferSize();
4070}
4071
4072void
4074{
4075 NS_LOG_FUNCTION(this << size);
4076 m_tcb->m_segmentSize = size;
4077 m_txBuffer->SetSegmentSize(size);
4078
4079 NS_ABORT_MSG_UNLESS(m_state == CLOSED, "Cannot change segment size dynamically.");
4080}
4081
4084{
4085 return m_tcb->m_segmentSize;
4086}
4087
4088void
4090{
4091 NS_LOG_FUNCTION(this << timeout);
4093}
4094
4095Time
4097{
4098 return m_cnTimeout;
4099}
4100
4101void
4103{
4104 NS_LOG_FUNCTION(this << count);
4105 m_synRetries = count;
4106}
4107
4110{
4111 return m_synRetries;
4112}
4113
4114void
4116{
4117 NS_LOG_FUNCTION(this << retries);
4118 m_dataRetries = retries;
4119}
4120
4123{
4124 NS_LOG_FUNCTION(this);
4125 return m_dataRetries;
4126}
4127
4128void
4130{
4131 NS_LOG_FUNCTION(this << timeout);
4133}
4134
4135Time
4137{
4138 return m_delAckTimeout;
4139}
4140
4141void
4143{
4144 NS_LOG_FUNCTION(this << count);
4145 m_delAckMaxCount = count;
4146}
4147
4150{
4151 return m_delAckMaxCount;
4152}
4153
4154void
4156{
4157 NS_LOG_FUNCTION(this << noDelay);
4158 m_noDelay = noDelay;
4159}
4160
4161bool
4163{
4164 return m_noDelay;
4165}
4166
4167void
4169{
4170 NS_LOG_FUNCTION(this << timeout);
4172}
4173
4174Time
4176{
4177 return m_persistTimeout;
4178}
4179
4180bool
4182{
4183 // Broadcast is not implemented. Return true only if allowBroadcast==false
4184 return (!allowBroadcast);
4185}
4186
4187bool
4189{
4190 return false;
4191}
4192
4193void
4195{
4196 NS_LOG_FUNCTION(this << header);
4197
4199 {
4200 AddOptionTimestamp(header);
4201 }
4202}
4203
4204void
4206{
4207 NS_LOG_FUNCTION(this << option);
4208
4209 Ptr<const TcpOptionWinScale> ws = DynamicCast<const TcpOptionWinScale>(option);
4210
4211 // In naming, we do the contrary of RFC 1323. The received scaling factor
4212 // is Rcv.Wind.Scale (and not Snd.Wind.Scale)
4213 m_sndWindShift = ws->GetScale();
4214
4215 if (m_sndWindShift > 14)
4216 {
4217 NS_LOG_WARN("Possible error; m_sndWindShift exceeds 14: " << m_sndWindShift);
4218 m_sndWindShift = 14;
4219 }
4220
4221 NS_LOG_INFO(m_node->GetId() << " Received a scale factor of "
4222 << static_cast<int>(m_sndWindShift));
4223}
4224
4225uint8_t
4227{
4228 NS_LOG_FUNCTION(this);
4229 uint32_t maxSpace = m_tcb->m_rxBuffer->MaxBufferSize();
4230 uint8_t scale = 0;
4231
4232 while (maxSpace > m_maxWinSize)
4233 {
4234 maxSpace = maxSpace >> 1;
4235 ++scale;
4236 }
4237
4238 if (scale > 14)
4239 {
4240 NS_LOG_WARN("Possible error; scale exceeds 14: " << scale);
4241 scale = 14;
4242 }
4243
4244 NS_LOG_INFO("Node " << m_node->GetId() << " calculated wscale factor of "
4245 << static_cast<int>(scale) << " for buffer size "
4246 << m_tcb->m_rxBuffer->MaxBufferSize());
4247 return scale;
4248}
4249
4250void
4252{
4253 NS_LOG_FUNCTION(this << header);
4254 NS_ASSERT(header.GetFlags() & TcpHeader::SYN);
4255
4256 Ptr<TcpOptionWinScale> option = CreateObject<TcpOptionWinScale>();
4257
4258 // In naming, we do the contrary of RFC 1323. The sended scaling factor
4259 // is Snd.Wind.Scale (and not Rcv.Wind.Scale)
4260
4262 option->SetScale(m_rcvWindShift);
4263
4264 header.AppendOption(option);
4265
4266 NS_LOG_INFO(m_node->GetId() << " Send a scaling factor of "
4267 << static_cast<int>(m_rcvWindShift));
4268}
4269
4272{
4273 NS_LOG_FUNCTION(this << option);
4274
4275 Ptr<const TcpOptionSack> s = DynamicCast<const TcpOptionSack>(option);
4276 return m_txBuffer->Update(s->GetSackList(), MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
4277}
4278
4279void
4281{
4282 NS_LOG_FUNCTION(this << option);
4283
4284 Ptr<const TcpOptionSackPermitted> s = DynamicCast<const TcpOptionSackPermitted>(option);
4285
4286 NS_ASSERT(m_sackEnabled == true);
4287 NS_LOG_INFO(m_node->GetId() << " Received a SACK_PERMITTED option " << s);
4288}
4289
4290void
4292{
4293 NS_LOG_FUNCTION(this << header);
4294 NS_ASSERT(header.GetFlags() & TcpHeader::SYN);
4295
4296 Ptr<TcpOptionSackPermitted> option = CreateObject<TcpOptionSackPermitted>();
4297 header.AppendOption(option);
4298 NS_LOG_INFO(m_node->GetId() << " Add option SACK-PERMITTED");
4299}
4300
4301void
4303{
4304 NS_LOG_FUNCTION(this << header);
4305
4306 // Calculate the number of SACK blocks allowed in this packet
4307 uint8_t optionLenAvail = header.GetMaxOptionLength() - header.GetOptionLength();
4308 uint8_t allowedSackBlocks = (optionLenAvail - 2) / 8;
4309
4310 TcpOptionSack::SackList sackList = m_tcb->m_rxBuffer->GetSackList();
4311 if (allowedSackBlocks == 0 || sackList.empty())
4312 {
4313 NS_LOG_LOGIC("No space available or sack list empty, not adding sack blocks");
4314 return;
4315 }
4316
4317 // Append the allowed number of SACK blocks
4318 Ptr<TcpOptionSack> option = CreateObject<TcpOptionSack>();
4319
4320 for (auto i = sackList.begin(); allowedSackBlocks > 0 && i != sackList.end(); ++i)
4321 {
4322 option->AddSackBlock(*i);
4323 allowedSackBlocks--;
4324 }
4325
4326 header.AppendOption(option);
4327 NS_LOG_INFO(m_node->GetId() << " Add option SACK " << *option);
4328}
4329
4330void
4332 const SequenceNumber32& seq)
4333{
4334 NS_LOG_FUNCTION(this << option);
4335
4336 Ptr<const TcpOptionTS> ts = DynamicCast<const TcpOptionTS>(option);
4337
4338 // This is valid only when no overflow occurs. It happens
4339 // when a connection last longer than 50 days.
4340 if (m_tcb->m_rcvTimestampValue > ts->GetTimestamp())
4341 {
4342 // Do not save a smaller timestamp (probably there is reordering)
4343 return;
4344 }
4345
4346 m_tcb->m_rcvTimestampValue = ts->GetTimestamp();
4347 m_tcb->m_rcvTimestampEchoReply = ts->GetEcho();
4348
4349 if (seq == m_tcb->m_rxBuffer->NextRxSequence() && seq <= m_highTxAck)
4350 {
4351 m_timestampToEcho = ts->GetTimestamp();
4352 }
4353
4354 NS_LOG_INFO(m_node->GetId() << " Got timestamp=" << m_timestampToEcho
4355 << " and Echo=" << ts->GetEcho());
4356}
4357
4358void
4360{
4361 NS_LOG_FUNCTION(this << header);
4362
4363 Ptr<TcpOptionTS> option = CreateObject<TcpOptionTS>();
4364
4365 option->SetTimestamp(TcpOptionTS::NowToTsValue());
4366 option->SetEcho(m_timestampToEcho);
4367
4368 header.AppendOption(option);
4369 NS_LOG_INFO(m_node->GetId() << " Add option TS, ts=" << option->GetTimestamp()
4370 << " echo=" << m_timestampToEcho);
4371}
4372
4373void
4375{
4376 NS_LOG_FUNCTION(this << header);
4377 // If the connection is not established, the window size is always
4378 // updated
4379 uint32_t receivedWindow = header.GetWindowSize();
4380 receivedWindow <<= m_sndWindShift;
4381 NS_LOG_INFO("Received (scaled) window is " << receivedWindow << " bytes");
4382 if (m_state < ESTABLISHED)
4383 {
4384 m_rWnd = receivedWindow;
4385 NS_LOG_LOGIC("State less than ESTABLISHED; updating rWnd to " << m_rWnd);
4386 return;
4387 }
4388
4389 // Test for conditions that allow updating of the window
4390 // 1) segment contains new data (advancing the right edge of the receive
4391 // buffer),
4392 // 2) segment does not contain new data but the segment acks new data
4393 // (highest sequence number acked advances), or
4394 // 3) the advertised window is larger than the current send window
4395 bool update = false;
4396 if (header.GetAckNumber() == m_highRxAckMark && receivedWindow > m_rWnd)
4397 {
4398 // right edge of the send window is increased (window update)
4399 update = true;
4400 }
4401 if (header.GetAckNumber() > m_highRxAckMark)
4402 {
4403 m_highRxAckMark = header.GetAckNumber();
4404 update = true;
4405 }
4406 if (header.GetSequenceNumber() > m_highRxMark)
4407 {
4409 update = true;
4410 }
4411 if (update)
4412 {
4413 m_rWnd = receivedWindow;
4414 NS_LOG_LOGIC("updating rWnd to " << m_rWnd);
4415 }
4416}
4417
4418void
4420{
4421 NS_LOG_FUNCTION(this << minRto);
4422 m_minRto = minRto;
4423}
4424
4425Time
4427{
4428 return m_minRto;
4429}
4430
4431void
4433{
4434 NS_LOG_FUNCTION(this << clockGranularity);
4435 m_clockGranularity = clockGranularity;
4436}
4437
4438Time
4440{
4441 return m_clockGranularity;
4442}
4443
4446{
4447 return m_txBuffer;
4448}
4449
4452{
4453 return m_tcb->m_rxBuffer;
4454}
4455
4456void
4458{
4459 m_retxThresh = retxThresh;
4460 m_txBuffer->SetDupAckThresh(retxThresh);
4461}
4462
4463void
4465{
4466 m_pacingRateTrace(oldValue, newValue);
4467}
4468
4469void
4471{
4472 m_cWndTrace(oldValue, newValue);
4473}
4474
4475void
4477{
4478 m_cWndInflTrace(oldValue, newValue);
4479}
4480
4481void
4483{
4484 m_ssThTrace(oldValue, newValue);
4485}
4486
4487void
4489 TcpSocketState::TcpCongState_t newValue) const
4490{
4491 m_congStateTrace(oldValue, newValue);
4492}
4493
4494void
4496 TcpSocketState::EcnState_t newValue) const
4497{
4498 m_ecnStateTrace(oldValue, newValue);
4499}
4500
4501void
4503
4504{
4505 m_nextTxSequenceTrace(oldValue, newValue);
4506}
4507
4508void
4510{
4511 m_highTxMarkTrace(oldValue, newValue);
4512}
4513
4514void
4516{
4517 m_bytesInFlightTrace(oldValue, newValue);
4518}
4519
4520void
4521TcpSocketBase::UpdateRtt(Time oldValue, Time newValue) const
4522{
4523 m_lastRttTrace(oldValue, newValue);
4524}
4525
4526void
4528{
4529 NS_LOG_FUNCTION(this << algo);
4530 m_congestionControl = algo;
4532}
4533
4534void
4536{
4537 NS_LOG_FUNCTION(this << recovery);
4538 m_recoveryOps = recovery;
4539}
4540
4543{
4544 return CopyObject<TcpSocketBase>(this);
4545}
4546
4549{
4550 if (a > b)
4551 {
4552 return a - b;
4553 }
4554
4555 return 0;
4556}
4557
4558void
4560{
4561 NS_LOG_FUNCTION(this);
4562 NS_LOG_INFO("Performing Pacing");
4564}
4565
4566bool
4568{
4569 if (!m_tcb->m_pacing)
4570 {
4571 return false;
4572 }
4573 else
4574 {
4576 {
4577 return true;
4578 }
4579 SequenceNumber32 highTxMark = m_tcb->m_highTxMark; // cast traced value
4580 if (highTxMark.GetValue() > (GetInitialCwnd() * m_tcb->m_segmentSize))
4581 {
4582 return true;
4583 }
4584 }
4585 return false;
4586}
4587
4588void
4590{
4591 NS_LOG_FUNCTION(this << m_tcb);
4592
4593 // According to Linux, set base pacing rate to (cwnd * mss) / srtt
4594 //
4595 // In (early) slow start, multiply base by the slow start factor.
4596 // In late slow start and congestion avoidance, multiply base by
4597 // the congestion avoidance factor.
4598 // Comment from Linux code regarding early/late slow start:
4599 // Normal Slow Start condition is (tp->snd_cwnd < tp->snd_ssthresh)
4600 // If snd_cwnd >= (tp->snd_ssthresh / 2), we are approaching
4601 // end of slow start and should slow down.
4602
4603 // Similar to Linux, do not update pacing rate here if the
4604 // congestion control implements TcpCongestionOps::CongControl ()
4605 if (m_congestionControl->HasCongControl() || !m_tcb->m_pacing)
4606 {
4607 return;
4608 }
4609
4610 double factor;
4611 if (m_tcb->m_cWnd < m_tcb->m_ssThresh / 2)
4612 {
4613 NS_LOG_DEBUG("Pacing according to slow start factor; " << m_tcb->m_cWnd << " "
4614 << m_tcb->m_ssThresh);
4615 factor = static_cast<double>(m_tcb->m_pacingSsRatio) / 100;
4616 }
4617 else
4618 {
4619 NS_LOG_DEBUG("Pacing according to congestion avoidance factor; " << m_tcb->m_cWnd << " "
4620 << m_tcb->m_ssThresh);
4621 factor = static_cast<double>(m_tcb->m_pacingCaRatio) / 100;
4622 }
4623 Time lastRtt = m_tcb->m_lastRtt.Get(); // Get underlying Time value
4624 NS_LOG_DEBUG("Last RTT is " << lastRtt.GetSeconds());
4625
4626 // Multiply by 8 to convert from bytes per second to bits per second
4627 DataRate pacingRate((std::max(m_tcb->m_cWnd, m_tcb->m_bytesInFlight) * 8 * factor) /
4628 lastRtt.GetSeconds());
4629 if (pacingRate < m_tcb->m_maxPacingRate)
4630 {
4631 NS_LOG_DEBUG("Pacing rate updated to: " << pacingRate);
4632 m_tcb->m_pacingRate = pacingRate;
4633 }
4634 else
4635 {
4636 NS_LOG_DEBUG("Pacing capped by max pacing rate: " << m_tcb->m_maxPacingRate);
4638 }
4639}
4640
4641void
4643{
4644 NS_LOG_FUNCTION(this << pacing);
4645 m_tcb->m_pacing = pacing;
4646}
4647
4648void
4650{
4651 NS_LOG_FUNCTION(this << paceWindow);
4652 m_tcb->m_paceInitialWindow = paceWindow;
4653}
4654
4655void
4657{
4658 NS_LOG_FUNCTION(this << useEcn);
4659 m_tcb->m_useEcn = useEcn;
4660}
4661
4664{
4665 return m_rWnd.Get();
4666}
4667
4670{
4671 return m_highRxAckMark.Get();
4672}
4673
4674// RttHistory methods
4676 : seq(s),
4677 count(c),
4678 time(t),
4679 retx(false)
4680{
4681}
4682
4684 : seq(h.seq),
4685 count(h.count),
4686 time(h.time),
4687 retx(h.retx)
4688{
4689}
4690
4691} // namespace ns3
#define Max(a, b)
#define Min(a, b)
a polymophic address class
Definition: address.h:101
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Callback template class.
Definition: callback.h:438
bool IsNull() const
Check for null implementation.
Definition: callback.h:569
AttributeValue implementation for Callback.
Definition: callback.h:806
Class for representing data rates.
Definition: data-rate.h:89
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
Hold variables of type enum.
Definition: enum.h:62
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition: event-id.cc:69
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
An Inet6 address class.
static Inet6SocketAddress ConvertFrom(const Address &addr)
Convert the address to a InetSocketAddress.
uint16_t GetPort() const
Get the port.
static bool IsMatchingType(const Address &addr)
If the address match.
Ipv6Address GetIpv6() const
Get the IPv6 address.
an Inet address class
static bool IsMatchingType(const Address &address)
Ipv4Address GetIpv4() const
static InetSocketAddress ConvertFrom(const Address &address)
Returns an InetSocketAddress which corresponds to the input Address.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:42
static Ipv4Address GetZero()
static Ipv4Address GetAny()
void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
void SetDestroyCallback(Callback< void > callback)
Set the default destroy callback.
Ipv4Address GetLocalAddress() const
Get the local address.
void SetLocalAddress(Ipv4Address address)
Set the local address.
uint16_t GetPeerPort() const
Get the peer port.
uint16_t GetLocalPort() const
Get the local port.
Ipv4Address GetPeerAddress() const
Get the peer address.
void SetIcmpCallback(Callback< void, Ipv4Address, uint8_t, uint8_t, uint8_t, uint32_t > callback)
Set the ICMP callback.
void SetPeer(Ipv4Address address, uint16_t port)
Set the peer information (address and port).
void SetRxCallback(Callback< void, Ptr< Packet >, Ipv4Header, uint16_t, Ptr< Ipv4Interface > > callback)
Set the reception callback.
Packet header for IPv4.
Definition: ipv4-header.h:34
void SetDestination(Ipv4Address destination)
Definition: ipv4-header.cc:309
Ipv4Address GetSource() const
Definition: ipv4-header.cc:302
EcnType GetEcn() const
Definition: ipv4-header.cc:169
Ipv4Address GetDestination() const
Definition: ipv4-header.cc:316
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:80
Describes an IPv6 address.
Definition: ipv6-address.h:49
static Ipv6Address GetAny()
Get the "any" (::) Ipv6Address.
bool IsIpv4MappedAddress() const
If the address is an IPv4-mapped address.
Ipv4Address GetIpv4MappedAddress() const
Return the Ipv4 address.
uint16_t GetLocalPort() const
Get the local port.
void SetPeer(Ipv6Address addr, uint16_t port)
Set the peer information (address and port).
Ipv6Address GetPeerAddress() const
Get the peer address.
void SetIcmpCallback(Callback< void, Ipv6Address, uint8_t, uint8_t, uint8_t, uint32_t > callback)
Set the ICMP callback.
Ipv6Address GetLocalAddress() const
Get the local address.
void SetLocalAddress(Ipv6Address addr)
Set the local address.
void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
void SetRxCallback(Callback< void, Ptr< Packet >, Ipv6Header, uint16_t, Ptr< Ipv6Interface > > callback)
Set the reception callback.
uint16_t GetPeerPort() const
Get the peer port.
void SetDestroyCallback(Callback< void > callback)
Set the default destroy callback.
Packet header for IPv6.
Definition: ipv6-header.h:35
void SetDestination(Ipv6Address dst)
Set the "Destination address" field.
Definition: ipv6-header.cc:118
Ipv6Address GetDestination() const
Get the "Destination address" field.
Definition: ipv6-header.cc:124
EcnType GetEcn() const
Definition: ipv6-header.cc:284
Ipv6Address GetSource() const
Get the "Source address" field.
Definition: ipv6-header.cc:112
IPv6 layer implementation.
uint32_t GetId() const
Definition: node.cc:117
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:322
friend Ptr< T > CopyObject(Ptr< T > object)
Copy an Object.
Definition: object.h:592
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:522
AttributeValue implementation for Pointer.
Definition: pointer.h:48
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Helper class to store RTT measurements.
uint32_t count
Number of bytes sent.
RttHistory(SequenceNumber32 s, uint32_t c, Time t)
Constructor - builds an RttHistory with the given parameters.
bool retx
True if this has been retransmitted.
Time time
Time this one was sent.
SequenceNumber32 seq
First sequence number in packet sent.
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:605
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition: simulator.cc:217
Ptr< NetDevice > GetBoundNetDevice()
Returns socket's bound NetDevice, if any.
Definition: socket.cc:347
Ptr< Packet > Recv()
Read a single packet from the socket.
Definition: socket.cc:174
void SetConnectCallback(Callback< void, Ptr< Socket > > connectionSucceeded, Callback< void, Ptr< Socket > > connectionFailed)
Specify callbacks to allow the caller to determine if the connection succeeds of fails.
Definition: socket.cc:87
bool IsManualIpTtl() const
Checks if the socket has a specific IPv4 TTL set.
Definition: socket.cc:374
void NotifySend(uint32_t spaceAvailable)
Notify through the callback (if set) that some data have been sent.
Definition: socket.cc:292
void NotifyNewConnectionCreated(Ptr< Socket > socket, const Address &from)
Notify through the callback (if set) that a new connection has been created.
Definition: socket.cc:272
virtual uint8_t GetIpTtl() const
Query the value of IP Time to Live field of this socket.
Definition: socket.cc:517
bool NotifyConnectionRequest(const Address &from)
Notify through the callback (if set) that an incoming connection is being requested by a remote host.
Definition: socket.cc:254
uint8_t GetIpTos() const
Query the value of IP Type of Service of this socket.
Definition: socket.cc:450
SocketType
Enumeration of the possible socket types.
Definition: socket.h:107
@ NS3_SOCK_STREAM
Definition: socket.h:108
void SetDataSentCallback(Callback< void, Ptr< Socket >, uint32_t > dataSent)
Notify application when a packet has been sent from transport protocol (non-standard socket call)
Definition: socket.cc:114
void SetSendCallback(Callback< void, Ptr< Socket >, uint32_t > sendCb)
Notify application when space in transmit buffer is added.
Definition: socket.cc:121
void NotifyErrorClose()
Notify through the callback (if set) that the connection has been closed due to an error.
Definition: socket.cc:244
void NotifyDataRecv()
Notify through the callback (if set) that some data have been received.
Definition: socket.cc:302
Ptr< NetDevice > m_boundnetdevice
the device this socket is bound to (might be null).
Definition: socket.h:1081
virtual void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
Definition: socket.cc:327
void NotifyNormalClose()
Notify through the callback (if set) that the connection has been closed.
Definition: socket.cc:234
virtual uint8_t GetIpv6HopLimit() const
Query the value of IP Hop Limit field of this socket.
Definition: socket.cc:542
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition: socket.cc:128
SocketErrno
Enumeration of the possible errors returned by a socket.
Definition: socket.h:84
@ ERROR_SHUTDOWN
Definition: socket.h:90
@ ERROR_INVAL
Definition: socket.h:93
@ ERROR_ADDRINUSE
Definition: socket.h:98
@ ERROR_ADDRNOTAVAIL
Definition: socket.h:97
@ ERROR_NOTCONN
Definition: socket.h:87
@ ERROR_MSGSIZE
Definition: socket.h:88
void NotifyDataSent(uint32_t size)
Notify through the callback (if set) that some data have been sent.
Definition: socket.cc:282
void NotifyConnectionSucceeded()
Notify through the callback (if set) that the connection has been established.
Definition: socket.cc:214
uint8_t GetPriority() const
Query the priority value of this socket.
Definition: socket.cc:393
uint8_t GetIpv6Tclass() const
Query the value of IPv6 Traffic Class field of this socket.
Definition: socket.cc:492
bool IsManualIpv6HopLimit() const
Checks if the socket has a specific IPv6 Hop Limit set.
Definition: socket.cc:380
bool IsManualIpv6Tclass() const
Checks if the socket has a specific IPv6 Tclass set.
Definition: socket.cc:368
void NotifyConnectionFailed()
Notify through the callback (if set) that the connection has not been established due to an error.
Definition: socket.cc:224
indicates whether the socket has IP_TOS set.
Definition: socket.h:1271
void SetTos(uint8_t tos)
Set the tag's TOS.
Definition: socket.cc:798
This class implements a tag that carries the socket-specific TTL of a packet to the IP layer.
Definition: socket.h:1124
void SetTtl(uint8_t ttl)
Set the tag's TTL.
Definition: socket.cc:604
This class implements a tag that carries the socket-specific HOPLIMIT of a packet to the IPv6 layer.
Definition: socket.h:1172
void SetHopLimit(uint8_t hopLimit)
Set the tag's Hop Limit.
Definition: socket.cc:668
indicates whether the socket has IPV6_TCLASS set.
Definition: socket.h:1366
void SetTclass(uint8_t tclass)
Set the tag's Tclass.
Definition: socket.cc:910
indicates whether the socket has a priority set.
Definition: socket.h:1318
void SetPriority(uint8_t priority)
Set the tag's priority.
Definition: socket.cc:854
Header for the Transmission Control Protocol.
Definition: tcp-header.h:47
void SetDestinationPort(uint16_t port)
Set the destination port.
Definition: tcp-header.cc:70
void SetSequenceNumber(SequenceNumber32 sequenceNumber)
Set the sequence Number.
Definition: tcp-header.cc:76
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:118
uint8_t GetMaxOptionLength() const
Get maximum option length.
Definition: tcp-header.cc:142
uint16_t GetDestinationPort() const
Get the destination port.
Definition: tcp-header.cc:112
Ptr< const TcpOption > GetOption(uint8_t kind) const
Get the option specified.
Definition: tcp-header.cc:464
@ URG
Urgent.
Definition: tcp-header.h:284
void SetFlags(uint8_t flags)
Set flags of the header.
Definition: tcp-header.cc:88
void SetWindowSize(uint16_t windowSize)
Set the window size.
Definition: tcp-header.cc:94
const TcpOptionList & GetOptionList() const
Get the list of option in this header.
Definition: tcp-header.cc:458
uint16_t GetWindowSize() const
Get the window size.
Definition: tcp-header.cc:154
uint8_t GetOptionLength() const
Get the total length of appended options.
Definition: tcp-header.cc:136
bool AppendOption(Ptr< const TcpOption > option)
Append an option to the TCP header.
Definition: tcp-header.cc:432
static std::string FlagsToString(uint8_t flags, const std::string &delimiter="|")
Converts an integer into a human readable list of Tcp flags.
Definition: tcp-header.cc:39
bool HasOption(uint8_t kind) const
Check if the header has the option specified.
Definition: tcp-header.cc:478
uint16_t GetSourcePort() const
Get the source port.
Definition: tcp-header.cc:106
void SetSourcePort(uint16_t port)
Set the source port.
Definition: tcp-header.cc:64
void SetAckNumber(SequenceNumber32 ackNumber)
Set the ACK number.
Definition: tcp-header.cc:82
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:148
SequenceNumber32 GetAckNumber() const
Get the ACK number.
Definition: tcp-header.cc:124
@ SACKPERMITTED
SACKPERMITTED.
Definition: tcp-option.h:62
@ WINSCALE
WINSCALE.
Definition: tcp-option.h:61
std::list< SackBlock > SackList
SACK list definition.
static Time ElapsedTimeFromTsValue(uint32_t echoTime)
Estimate the Time elapsed from a TS echo value.
static uint32_t NowToTsValue()
Return an uint32_t value which represent "now".
virtual const TcpRateSample & GenerateSample(uint32_t delivered, uint32_t lost, bool is_sack_reneg, uint32_t priorInFlight, const Time &minRtt)=0
Generate a TcpRateSample to feed a congestion avoidance algorithm.
virtual void SkbSent(TcpTxItem *skb, bool isStartOfTransmission)=0
Put the rate information inside the sent skb.
virtual void CalculateAppLimited(uint32_t cWnd, uint32_t in_flight, uint32_t segmentSize, const SequenceNumber32 &tailSeq, const SequenceNumber32 &nextTx, const uint32_t lostOut, const uint32_t retransOut)=0
If a gap is detected between sends, it means we are app-limited.
virtual const TcpRateConnection & GetConnectionRate()=0
virtual void SkbDelivered(TcpTxItem *skb)=0
Update the Rate information after an item is received.
A base class for implementation of a stream socket using TCP.
void AddOptionSack(TcpHeader &header)
Add the SACK option to the header.
int GetSockName(Address &address) const override
Get socket address.
Time m_persistTimeout
Time between sending 1-byte probes.
uint16_t m_maxWinSize
Maximum window size to advertise.
uint8_t m_rcvWindShift
Window shift to apply to outgoing segments.
void SetPaceInitialWindow(bool paceWindow)
Enable or disable pacing of the initial window.
int Bind6() override
Allocate a local IPv6 endpoint for this socket.
void TimeWait()
Move from CLOSING or FIN_WAIT_2 to TIME_WAIT state.
Ptr< TcpCongestionOps > m_congestionControl
Congestion control.
Ptr< TcpTxBuffer > GetTxBuffer() const
Get a pointer to the Tx buffer.
int SetupEndpoint()
Configure the endpoint to a local address.
virtual void LastAckTimeout()
Timeout at LAST_ACK, close the connection.
void ProcessEstablished(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon ESTABLISHED state.
Time m_minRto
minimum value of the Retransmit timeout
uint32_t SendPendingData(bool withAck=false)
Send as much pending data as possible according to the Tx window.
TracedValue< uint32_t > m_advWnd
Advertised Window size.
TracedCallback< Ptr< const Packet >, const TcpHeader &, Ptr< const TcpSocketBase > > m_txTrace
Trace of transmitted packets.
SequenceNumber32 m_recover
Previous highest Tx seqnum for fast recovery (set it to initial seq number)
bool m_recoverActive
Whether "m_recover" has been set/activated It is used to avoid comparing with the old m_recover value...
void DoRetransmit()
Retransmit the first segment marked as lost, without considering available window nor pacing.
bool CheckNoEcn(uint8_t tos) const
Checks if TOS has no ECN codepoints.
virtual void SetNode(Ptr< Node > node)
Set the associated node.
int ShutdownRecv() override
uint8_t m_sndWindShift
Window shift to apply to incoming segments.
Ptr< TcpL4Protocol > m_tcp
the associated TCP L4 protocol
Ptr< TcpSocketState > m_tcb
Congestion control information.
bool GetAllowBroadcast() const override
Query whether broadcast datagram transmissions are allowed.
void UpdateSsThresh(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState slow start threshold.
TracedCallback< Ptr< const Packet >, const TcpHeader &, Ptr< const TcpSocketBase > > m_rxTrace
Trace of received packets.
virtual void SetTcp(Ptr< TcpL4Protocol > tcp)
Set the associated TCP L4 protocol.
void EnterRecovery(uint32_t currentDelivered)
Enter the CA_RECOVERY, and retransmit the head.
Time GetMinRto() const
Get the Minimum RTO.
void ProcessSynSent(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon SYN_SENT.
void ForwardUp(Ptr< Packet > packet, Ipv4Header header, uint16_t port, Ptr< Ipv4Interface > incomingInterface)
Called by the L3 protocol when it received a packet to pass on to TCP.
bool SetAllowBroadcast(bool allowBroadcast) override
Configure whether broadcast datagram transmissions are allowed.
void CancelAllTimers()
Cancel all timer when endpoint is deleted.
Time GetDelAckTimeout() const override
Get the time to delay an ACK.
Ptr< TcpRecoveryOps > m_recoveryOps
Recovery Algorithm.
TracedCallback< uint32_t, uint32_t > m_bytesInFlightTrace
Callback pointer for bytesInFlight trace chaining.
uint32_t GetInitialSSThresh() const override
Get the initial Slow Start Threshold.
void NotifyPacingPerformed()
Notify Pacing.
void SetDelAckTimeout(Time timeout) override
Set the time to delay an ACK.
void CloseAndNotify()
Peacefully close the socket by notifying the upper layer and deallocate end point.
Ptr< TcpRateOps > m_rateOps
Rate operations.
void PeerClose(Ptr< Packet > p, const TcpHeader &tcpHeader)
Received a FIN from peer, notify rx buffer.
int Close() override
Close a socket.
bool m_shutdownSend
Send no longer allowed.
bool IsPacingEnabled() const
Return true if packets in the current window should be paced.
void ProcessOptionWScale(const Ptr< const TcpOption > option)
Read and parse the Window scale option.
bool m_closeOnEmpty
Close socket upon tx buffer emptied.
virtual void ReTxTimeout()
An RTO event happened.
void AddOptionSackPermitted(TcpHeader &header)
Add the SACK PERMITTED option to the header.
TracedValue< Time > m_rto
Retransmit timeout.
uint32_t GetSndBufSize() const override
Get the send buffer size.
virtual void ReceivedData(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Recv of a data, put into buffer, call L7 to get it if necessary.
EventId m_timewaitEvent
TIME_WAIT expiration event: Move this socket to CLOSED state.
Ptr< TcpTxBuffer > m_txBuffer
Tx buffer.
static TypeId GetTypeId()
Get the type ID.
uint32_t m_dupAckCount
Dupack counter.
void SetRetxThresh(uint32_t retxThresh)
Set the retransmission threshold (dup ack threshold for a fast retransmit)
int Send(Ptr< Packet > p, uint32_t flags) override
Send data (or dummy data) to the remote host.
TracedCallback< SequenceNumber32, SequenceNumber32 > m_nextTxSequenceTrace
Callback pointer for next tx sequence chaining.
void UpdateBytesInFlight(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState bytes inflight.
EventId m_delAckEvent
Delayed ACK timeout event.
TracedCallback< Time, Time > m_lastRttTrace
Callback pointer for RTT trace chaining.
bool GetTcpNoDelay() const override
Check if Nagle's algorithm is enabled or not.
virtual void SetRtt(Ptr< RttEstimator > rtt)
Set the associated RTT estimator.
TracedCallback< uint32_t, uint32_t > m_cWndTrace
Callback pointer for cWnd trace chaining.
void UpdatePacingRateTrace(DataRate oldValue, DataRate newValue) const
Callback function to hook to TcpSocketState pacing rate.
void SetDataRetries(uint32_t retries) override
Set the number of data transmission retries before giving up.
void AddOptions(TcpHeader &tcpHeader)
Add options to TcpHeader.
TracedCallback< TcpSocketState::EcnState_t, TcpSocketState::EcnState_t > m_ecnStateTrace
Callback pointer for ECN state trace chaining.
void SetSynRetries(uint32_t count) override
Set the number of connection retries before giving up.
void ProcessWait(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon CLOSE_WAIT, FIN_WAIT_1, FIN_WAIT_2.
SequenceNumber32 m_highTxAck
Highest ack sent.
uint32_t GetTxAvailable() const override
Returns the number of bytes which can be sent in a single call to Send.
bool m_timestampEnabled
Timestamp option enabled.
virtual void PersistTimeout()
Send 1 byte probe to get an updated window size.
TracedValue< TcpStates_t > m_state
TCP state.
int SetupCallback()
Common part of the two Bind(), i.e.
Ptr< RttEstimator > m_rtt
Round trip time estimator.
Timer m_pacingTimer
Pacing Event.
EventId m_retxEvent
Retransmission event.
uint32_t m_bytesAckedNotProcessed
Bytes acked, but not processed.
void AddOptionTimestamp(TcpHeader &header)
Add the timestamp option to the header.
virtual uint32_t BytesInFlight() const
Return total bytes in flight.
uint32_t GetSegSize() const override
Get the segment size.
int SendTo(Ptr< Packet > p, uint32_t flags, const Address &toAddress) override
Send data to a specified peer.
uint32_t m_dataRetries
Number of data retransmission attempts.
double m_msl
Max segment lifetime.
void ProcessLastAck(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon LAST_ACK.
bool m_limitedTx
perform limited transmit
virtual uint32_t SendDataPacket(SequenceNumber32 seq, uint32_t maxSize, bool withAck)
Extract at most maxSize bytes from the TxBuffer at sequence seq, add the TCP header,...
TracedCallback< TcpSocketState::TcpCongState_t, TcpSocketState::TcpCongState_t > m_congStateTrace
Callback pointer for congestion state trace chaining.
void ProcessSynRcvd(Ptr< Packet > packet, const TcpHeader &tcpHeader, const Address &fromAddress, const Address &toAddress)
Received a packet upon SYN_RCVD.
virtual void ReceivedAck(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received an ACK packet.
SocketType GetSocketType() const override
int ShutdownSend() override
TracedValue< SequenceNumber32 > m_ecnCWRSeq
Sequence number of the last sent CWR.
Time GetPersistTimeout() const override
Get the timeout for persistent connection.
void UpdateCwnd(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState congestion window.
uint32_t m_delAckCount
Delayed ACK counter.
Ipv4EndPoint * m_endPoint
the IPv4 endpoint
static uint32_t SafeSubtraction(uint32_t a, uint32_t b)
Performs a safe subtraction between a and b (a-b)
virtual void DelAckTimeout()
Action upon delay ACK timeout, i.e.
Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress) override
Read a single packet from the socket and retrieve the sender address.
Time m_cnTimeout
Timeout for connection retry.
Time GetClockGranularity() const
Get the Clock Granularity (used in RTO calcs).
bool m_winScalingEnabled
Window Scale option enabled (RFC 7323)
void UpdateEcnState(TcpSocketState::EcnState_t oldValue, TcpSocketState::EcnState_t newValue) const
Callback function to hook to EcnState state.
EventId m_sendPendingDataEvent
micro-delay event to send pending data
uint32_t m_delAckMaxCount
Number of packet to fire an ACK before delay timeout.
uint8_t CalculateWScale() const
Calculate window scale value based on receive buffer space.
virtual void NewAck(const SequenceNumber32 &seq, bool resetRTO)
Update buffers w.r.t.
bool m_closeNotified
Told app to close socket.
int Listen() override
Listen for incoming connections.
void Destroy6()
Kill this socket by zeroing its attributes (IPv6)
TracedValue< SequenceNumber32 > m_ecnCESeq
Sequence number of the last received Congestion Experienced.
void SetClockGranularity(Time clockGranularity)
Sets the Clock Granularity (used in RTO calcs).
bool IsValidTcpSegment(const SequenceNumber32 seq, const uint32_t tcpHeaderSize, const uint32_t tcpPayloadSize)
Checks whether the given TCP segment is valid or not.
Time m_clockGranularity
Clock Granularity used in RTO calcs.
void DupAck(uint32_t currentDelivered)
Dupack management.
bool m_shutdownRecv
Receive no longer allowed.
void UpdateCongState(TcpSocketState::TcpCongState_t oldValue, TcpSocketState::TcpCongState_t newValue) const
Callback function to hook to TcpSocketState congestion state.
virtual uint32_t Window() const
Return the max possible number of unacked bytes.
Callback< void, Ipv6Address, uint8_t, uint8_t, uint8_t, uint32_t > m_icmpCallback6
ICMPv6 callback.
std::deque< RttHistory > m_history
List of sent packet.
void ProcessOptionSackPermitted(const Ptr< const TcpOption > option)
Read the SACK PERMITTED option.
int Bind() override
Allocate a local IPv4 endpoint for this socket.
virtual uint32_t AvailableWindow() const
Return unfilled portion of window.
TracedValue< SequenceNumber32 > m_highRxMark
Highest seqno received.
void ReadOptions(const TcpHeader &tcpHeader, uint32_t *bytesSacked)
Read TCP options before Ack processing.
virtual uint16_t AdvertisedWindowSize(bool scale=true) const
The amount of Rx window announced to the peer.
void ForwardUp6(Ptr< Packet > packet, Ipv6Header header, uint16_t port, Ptr< Ipv6Interface > incomingInterface)
Called by the L3 protocol when it received a packet to pass on to TCP.
bool m_connected
Connection established.
TracedValue< SequenceNumber32 > m_highRxAckMark
Highest ack received.
void AddOptionWScale(TcpHeader &header)
Add the window scale option to the header.
virtual void SendEmptyPacket(uint8_t flags)
Send a empty packet that carries a flag, e.g., ACK.
void UpdateWindowSize(const TcpHeader &header)
Update the receiver window (RWND) based on the value of the window field in the header.
uint32_t GetRxAvailable() const override
Return number of bytes which can be returned from one or multiple calls to Recv.
uint32_t GetDataRetries() const override
Get the number of data transmission retries before giving up.
int SetupEndpoint6()
Configure the endpoint v6 to a local address.
uint32_t GetRetxThresh() const
Get the retransmission threshold (dup ack threshold for a fast retransmit)
void DeallocateEndPoint()
Deallocate m_endPoint and m_endPoint6.
void Destroy()
Kill this socket by zeroing its attributes (IPv4)
void UpdateHighTxMark(SequenceNumber32 oldValue, SequenceNumber32 newValue) const
Callback function to hook to TcpSocketState high tx mark.
TcpSocketBase()
Create an unbound TCP socket.
void SetInitialSSThresh(uint32_t threshold) override
Set the initial Slow Start Threshold.
TracedCallback< DataRate, DataRate > m_pacingRateTrace
Callback pointer for pacing rate trace chaining.
uint32_t m_timestampToEcho
Timestamp to echo.
Ipv6EndPoint * m_endPoint6
the IPv6 endpoint
void SetSndBufSize(uint32_t size) override
Set the send buffer size.
virtual Ptr< TcpSocketBase > Fork()
Call CopyObject<> to clone me.
TracedCallback< uint32_t, uint32_t > m_ssThTrace
Callback pointer for ssTh trace chaining.
SocketErrno m_errno
Socket error code.
SocketErrno GetErrno() const override
Get last error number.
virtual void CompleteFork(Ptr< Packet > p, const TcpHeader &tcpHeader, const Address &fromAddress, const Address &toAddress)
Complete a connection by forking the socket.
void ProcessClosing(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon CLOSING.
TracedCallback< SequenceNumber32, SequenceNumber32 > m_highTxMarkTrace
Callback pointer for high tx mark chaining.
int Connect(const Address &address) override
Initiate a connection to a remote host.
Ptr< Node > m_node
the associated node
void SetSegSize(uint32_t size) override
Set the segment size.
TypeId GetInstanceTypeId() const override
Get the instance TypeId.
uint32_t m_synRetries
Number of connection attempts.
void SetConnTimeout(Time timeout) override
Set the connection timeout.
void SetDelAckMaxCount(uint32_t count) override
Set the number of packet to fire an ACK before delay timeout.
EventId m_lastAckEvent
Last ACK timeout event.
bool IsTcpOptionEnabled(uint8_t kind) const
Return true if the specified option is enabled.
void UpdatePacingRate()
Dynamically update the pacing rate.
EventId m_persistEvent
Persist event: Send 1 byte to probe for a non-zero Rx window.
void SetPacingStatus(bool pacing)
Enable or disable pacing.
void UpdateRtt(Time oldValue, Time newValue) const
Callback function to hook to TcpSocketState rtt.
void SetCongestionControlAlgorithm(Ptr< TcpCongestionOps > algo)
Install a congestion control algorithm on this socket.
int GetPeerName(Address &address) const override
Get the peer address of a connected socket.
virtual uint32_t UnAckDataCount() const
Return count of number of unacked bytes.
uint32_t m_dataRetrCount
Count of remaining data retransmission attempts.
void UpdateCwndInfl(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState inflated congestion window.
Ptr< TcpRxBuffer > GetRxBuffer() const
Get a pointer to the Rx buffer.
void SetPersistTimeout(Time timeout) override
Set the timeout for persistent connection.
void ConnectionSucceeded()
Schedule-friendly wrapper for Socket::NotifyConnectionSucceeded()
bool m_noDelay
Set to true to disable Nagle's algorithm.
uint32_t GetDelAckMaxCount() const override
Get the number of packet to fire an ACK before delay timeout.
void ForwardIcmp(Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
Called by the L3 protocol when it received an ICMP packet to pass on to TCP.
virtual void ProcessAck(const SequenceNumber32 &ackNumber, bool scoreboardUpdated, uint32_t currentDelivered, const SequenceNumber32 &oldHeadSequence)
Process a received ack.
void ForwardIcmp6(Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
Called by the L3 protocol when it received an ICMPv6 packet to pass on to TCP.
virtual void DoForwardUp(Ptr< Packet > packet, const Address &fromAddress, const Address &toAddress)
Called by TcpSocketBase::ForwardUp{,6}().
bool m_isFirstPartialAck
First partial ACK during RECOVERY.
uint8_t MarkEcnCodePoint(const uint8_t tos, const TcpSocketState::EcnCodePoint_t codePoint) const
mark ECN code point
Time m_delAckTimeout
Time to delay an ACK.
Callback< void, Ipv4Address, uint8_t, uint8_t, uint8_t, uint32_t > m_icmpCallback
ICMP callback.
void SetInitialCwnd(uint32_t cwnd) override
Set the initial Congestion Window.
void SetUseEcn(TcpSocketState::UseEcn_t useEcn)
Set ECN mode of use on the socket.
void ProcessListen(Ptr< Packet > packet, const TcpHeader &tcpHeader, const Address &fromAddress, const Address &toAddress)
Received a packet upon LISTEN state.
uint32_t m_synCount
Count of remaining connection retries.
int DoConnect()
Perform the real connection tasks: Send SYN if allowed, RST if invalid.
uint32_t GetSynRetries() const override
Get the number of connection retries before giving up.
void DoPeerClose()
FIN is in sequence, notify app and respond with a FIN.
void SendRST()
Send reset and tear down this socket.
bool OutOfRange(SequenceNumber32 head, SequenceNumber32 tail) const
Check if a sequence number range is within the rx window.
TracedValue< SequenceNumber32 > m_ecnEchoSeq
Sequence number of the last received ECN Echo.
uint32_t m_retxThresh
Fast Retransmit threshold.
uint32_t GetRWnd() const
Get the current value of the receiver's offered window (RCV.WND)
SequenceNumber32 GetHighRxAck() const
Get the current value of the receiver's highest (in-sequence) sequence number acked.
void BindToNetDevice(Ptr< NetDevice > netdevice) override
Bind a socket to specific device.
void EnterCwr(uint32_t currentDelivered)
Enter CA_CWR state upon receipt of an ECN Echo.
virtual void EstimateRtt(const TcpHeader &tcpHeader)
Take into account the packet for RTT estimation.
uint32_t GetInitialCwnd() const override
Get the initial Congestion Window.
TracedValue< uint32_t > m_rWnd
Receiver window (RCV.WND in RFC793)
void ProcessOptionTimestamp(const Ptr< const TcpOption > option, const SequenceNumber32 &seq)
Process the timestamp option from other side.
void SetRcvBufSize(uint32_t size) override
Set the receive buffer size.
void SetTcpNoDelay(bool noDelay) override
Enable/Disable Nagle's algorithm.
virtual void UpdateRttHistory(const SequenceNumber32 &seq, uint32_t sz, bool isRetransmission)
Update the RTT history, when we send TCP segments.
bool m_sackEnabled
RFC SACK option enabled.
void UpdateNextTxSequence(SequenceNumber32 oldValue, SequenceNumber32 newValue) const
Callback function to hook to TcpSocketState next tx sequence.
void SetMinRto(Time minRto)
Sets the Minimum RTO.
Time GetConnTimeout() const override
Get the connection timeout.
Ptr< Node > GetNode() const override
Return the node this socket is associated with.
uint32_t ProcessOptionSack(const Ptr< const TcpOption > option)
Read the SACK option.
void SetRecoveryAlgorithm(Ptr< TcpRecoveryOps > recovery)
Install a recovery algorithm on this socket.
int DoClose()
Close a socket by sending RST, FIN, or FIN+ACK, depend on the current state.
void AddSocketTags(const Ptr< Packet > &p) const
Add Tags for the Socket.
TracedCallback< uint32_t, uint32_t > m_cWndInflTrace
Callback pointer for cWndInfl trace chaining.
uint32_t GetRcvBufSize() const override
Get the receive buffer size.
(abstract) base class of all TcpSockets
Definition: tcp-socket.h:48
static const char *const TcpStateName[TcpSocket::LAST_STATE]
Literal names of TCP states for use in log messages.
Definition: tcp-socket.h:95
uint32_t m_segmentSize
Segment size.
@ CA_EVENT_ECN_IS_CE
received CE marked IP packet.
@ CA_EVENT_ECN_NO_CE
ECT set, but not CE marked.
@ CA_EVENT_DELAYED_ACK
Delayed ack is sent.
@ CA_EVENT_NON_DELAYED_ACK
Non-delayed ack is sent.
@ CA_EVENT_COMPLETE_CWR
end of congestion recovery
@ CA_EVENT_LOSS
loss timeout
@ CA_EVENT_TX_START
first transmit when no packets in flight
Time m_minRtt
Minimum RTT observed throughout the connection.
TracedValue< SequenceNumber32 > m_highTxMark
Highest seqno ever sent, regardless of ReTx.
uint32_t m_initialSsThresh
Initial Slow Start Threshold value.
EcnMode_t m_ecnMode
ECN mode.
Callback< void, uint8_t > m_sendEmptyPacketCallback
Callback to send an empty packet.
TracedValue< DataRate > m_pacingRate
Current Pacing rate.
UseEcn_t
Parameter value related to ECN enable/disable functionality similar to sysctl for tcp_ecn.
@ AcceptOnly
Enable only when the peer endpoint is ECN capable.
TracedValue< TcpCongState_t > m_congState
State in the Congestion state machine.
bool m_paceInitialWindow
Enable/Disable pacing for the initial window.
DataRate m_maxPacingRate
Max Pacing rate.
UseEcn_t m_useEcn
Socket ECN capability.
bool m_pacing
Pacing status.
bool m_isRetransDataAcked
Retransmitted data is ACKed if true.
static const char *const TcpCongStateName[TcpSocketState::CA_LAST_STATE]
Literal names of TCP states for use in log messages.
TcpCongState_t
Definition of the Congestion state machine.
@ CA_RECOVERY
CWND was reduced, we are fast-retransmitting.
@ CA_DISORDER
In all the respects it is "Open", but requires a bit more attention.
@ CA_CWR
cWnd was reduced due to some congestion notification event, such as ECN, ICMP source quench,...
@ CA_LOSS
CWND was reduced due to RTO timeout or SACK reneging.
@ CA_OPEN
Normal state, no dubious events.
SequenceNumber32 m_lastAckedSeq
Last sequence ACKed.
@ DctcpEcn
ECN functionality as described in RFC 8257.
TracedValue< uint32_t > m_cWnd
Congestion window.
uint32_t m_initialCWnd
Initial cWnd value.
uint32_t m_rcvTimestampEchoReply
Sender Timestamp echoed by the receiver.
TracedValue< Time > m_lastRtt
Last RTT sample collected.
EcnState_t
Definition of the Ecn state machine.
@ ECN_CWR_SENT
Sender has reduced the congestion window, and sent a packet with CWR bit set in TCP header.
@ ECN_DISABLED
ECN disabled traffic.
@ ECN_ECE_RCVD
Last ACK received had ECE bit set in TCP header.
@ ECN_IDLE
ECN is enabled but currently there is no action pertaining to ECE or CWR to be taken.
@ ECN_CE_RCVD
Last packet received had CE bit set in IP header.
@ ECN_SENDING_ECE
Receiver sends an ACK with ECE bit set in TCP header.
TracedValue< uint32_t > m_bytesInFlight
Bytes in flight.
TracedValue< uint32_t > m_cWndInfl
Inflated congestion window trace (used only for backward compatibility purpose)
uint16_t m_pacingCaRatio
CA pacing ratio.
Ptr< TcpRxBuffer > m_rxBuffer
Rx buffer (reordering buffer)
TracedValue< SequenceNumber32 > m_nextTxSequence
Next seqnum to be sent (SND.NXT), ReTx pushes it back.
uint32_t m_lastAckedSackedBytes
The number of bytes acked and sacked as indicated by the current ACK received.
uint16_t m_pacingSsRatio
SS pacing ratio.
static const char *const EcnStateName[TcpSocketState::ECN_CWR_SENT+1]
Literal names of ECN states for use in log messages.
TracedValue< EcnState_t > m_ecnState
Current ECN State, represented as combination of EcnState values.
TracedValue< uint32_t > m_ssThresh
Slow start threshold.
uint32_t m_rcvTimestampValue
Receiver Timestamp value.
EcnCodePoint_t m_ectCodePoint
ECT code point to use.
Item that encloses the application packet and some flags for it.
Definition: tcp-tx-item.h:33
Ptr< Packet > GetPacketCopy() const
Get a copy of the Packet underlying this item.
Definition: tcp-tx-item.cc:79
bool IsRetrans() const
Is the item retransmitted?
Definition: tcp-tx-item.cc:73
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
@ S
second
Definition: nstime.h:116
static Time FromDouble(double value, Unit unit)
Create a Time equal to value in unit unit.
Definition: nstime.h:516
AttributeValue implementation for Time.
Definition: nstime.h:1413
A simple virtual Timer class.
Definition: timer.h:78
void SetFunction(FN fn)
Definition: timer.h:279
bool IsExpired() const
Definition: timer.cc:122
Time GetDelayLeft() const
Definition: timer.cc:90
void Cancel()
Cancel the currently-running event if there is one.
Definition: timer.cc:108
void Schedule()
Schedule a new event using the currently-configured delay, function, and arguments.
Definition: timer.cc:162
bool IsRunning() const
Definition: timer.cc:129
T Get() const
Get the underlying value.
Definition: traced-value.h:249
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
Hold an unsigned integer type.
Definition: uinteger.h:45
uint16_t port
Definition: dsdv-manet.cc:44
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:81
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeCallbackAccessor(T1 a1)
Definition: callback.h:838
Ptr< const AttributeChecker > MakeCallbackChecker()
Definition: callback.cc:88
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Definition: double.h:43
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Definition: pointer.h:259
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1434
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1414
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:254
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:261
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
@ ESTABLISHED
Connection established
Definition: tcp-socket.h:72
@ FIN_WAIT_2
All buffered data sent, waiting for remote to shutdown.
Definition: tcp-socket.h:81
@ LISTEN
Listening for a connection
Definition: tcp-socket.h:68
@ CLOSE_WAIT
Remote side has shutdown and is waiting for us to finish writing our data and to shutdown (we have to...
Definition: tcp-socket.h:73
@ SYN_SENT
Sent a connection request, waiting for ack
Definition: tcp-socket.h:69
@ CLOSED
Socket is finished
Definition: tcp-socket.h:67
@ FIN_WAIT_1
Our side has shutdown, waiting to complete transmission of remaining buffered data
Definition: tcp-socket.h:79
@ TIME_WAIT
Timeout to catch resent junk before entering closed, can only be entered from FIN_WAIT2 or CLOSING.
Definition: tcp-socket.h:84
@ SYN_RCVD
Received a connection request, sent ack, waiting for final ack in three-way handshake.
Definition: tcp-socket.h:70
@ LAST_ACK
Our side has shutdown after remote has shutdown.
Definition: tcp-socket.h:76
@ CLOSING
Both sides have shutdown but we still have data we have to finish sending
Definition: tcp-socket.h:82
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
log2() macro definition; to deal with Bug 1467.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:704
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:189
ns3::Time timeout
uint64_t m_delivered
The total amount of data in bytes delivered so far.
Definition: tcp-rate-ops.h:175