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 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 * Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
8 */
9
10#define NS_LOG_APPEND_CONTEXT \
11 if (m_node) \
12 { \
13 std::clog << " [node " << m_node->GetId() << "] "; \
14 }
15
16#include "tcp-socket-base.h"
17
18#include "ipv4-end-point.h"
19#include "ipv4-route.h"
21#include "ipv4.h"
22#include "ipv6-end-point.h"
23#include "ipv6-l3-protocol.h"
24#include "ipv6-route.h"
26#include "rtt-estimator.h"
27#include "tcp-congestion-ops.h"
28#include "tcp-header.h"
29#include "tcp-l4-protocol.h"
31#include "tcp-option-sack.h"
32#include "tcp-option-ts.h"
33#include "tcp-option-winscale.h"
34#include "tcp-rate-ops.h"
35#include "tcp-recovery-ops.h"
36#include "tcp-rx-buffer.h"
37#include "tcp-tx-buffer.h"
38
39#include "ns3/abort.h"
40#include "ns3/data-rate.h"
41#include "ns3/double.h"
42#include "ns3/inet-socket-address.h"
43#include "ns3/inet6-socket-address.h"
44#include "ns3/log.h"
45#include "ns3/node.h"
46#include "ns3/object.h"
47#include "ns3/packet.h"
48#include "ns3/pointer.h"
49#include "ns3/simulation-singleton.h"
50#include "ns3/simulator.h"
51#include "ns3/trace-source-accessor.h"
52#include "ns3/uinteger.h"
53
54#include <algorithm>
55#include <cmath>
56
85
86namespace ns3
87{
88
89NS_LOG_COMPONENT_DEFINE("TcpSocketBase");
90
92
95{
96 static TypeId tid =
97 TypeId("ns3::TcpSocketBase")
99 .SetGroupName("Internet")
100 .AddConstructor<TcpSocketBase>()
101 // .AddAttribute ("TcpState", "State in TCP state machine",
102 // TypeId::ATTR_GET,
103 // EnumValue (CLOSED),
104 // MakeEnumAccessor (&TcpSocketBase::m_state),
105 // MakeEnumChecker (CLOSED, "Closed"))
106 .AddAttribute("MaxSegLifetime",
107 "Maximum segment lifetime in seconds, use for TIME_WAIT state transition "
108 "to CLOSED state",
109 DoubleValue(120), /* RFC793 says MSL=2 minutes*/
112 .AddAttribute("MaxWindowSize",
113 "Max size of advertised window",
114 UintegerValue(65535),
117 .AddAttribute("IcmpCallback",
118 "Callback invoked whenever an icmp error is received on this socket.",
122 .AddAttribute("IcmpCallback6",
123 "Callback invoked whenever an icmpv6 error is received on this socket.",
127 .AddAttribute("WindowScaling",
128 "Enable or disable Window Scaling option",
129 BooleanValue(true),
132 .AddAttribute("Sack",
133 "Enable or disable Sack option",
134 BooleanValue(true),
137 .AddAttribute("Timestamp",
138 "Enable or disable Timestamp option",
139 BooleanValue(true),
142 .AddAttribute("Fack",
143 "Enable or disable FACK option",
144 BooleanValue(false),
147 .AddAttribute(
148 "MinRto",
149 "Minimum retransmit timeout value",
150 TimeValue(Seconds(1)), // RFC 6298 says min RTO=1 sec, but Linux uses 200ms.
151 // See http://www.postel.org/pipermail/end2end-interest/2004-November/004402.html
154 .AddAttribute(
155 "ClockGranularity",
156 "Clock Granularity used in RTO calculations",
157 TimeValue(MilliSeconds(1)), // RFC6298 suggest to use fine clock granularity
161 .AddAttribute("TxBuffer",
162 "TCP Tx buffer",
163 PointerValue(),
166 .AddAttribute("RxBuffer",
167 "TCP Rx buffer",
168 PointerValue(),
171 .AddAttribute("CongestionOps",
172 "Pointer to TcpCongestionOps object",
173 PointerValue(),
176 .AddAttribute("RecoveryOps",
177 "Pointer to TcpRecoveryOps object",
178 PointerValue(),
181 .AddAttribute(
182 "ReTxThreshold",
183 "Threshold for fast retransmit",
184 UintegerValue(3),
187 .AddAttribute("LimitedTransmit",
188 "Enable limited transmit",
189 BooleanValue(true),
192 .AddAttribute("UseEcn",
193 "Parameter to set ECN functionality",
197 "Off",
199 "On",
201 "AcceptOnly"))
202 .AddAttribute("UseAbe",
203 "Parameter to set ABE functionality",
204 BooleanValue(false),
207 .AddTraceSource("RTO",
208 "Retransmission timeout",
210 "ns3::TracedValueCallback::Time")
211 .AddTraceSource("RTT",
212 "Smoothed RTT",
214 "ns3::TracedValueCallback::Time")
215 .AddTraceSource("LastRTT",
216 "RTT of the last (S)ACKed packet",
218 "ns3::TracedValueCallback::Time")
219 .AddTraceSource("NextTxSequence",
220 "Next sequence number to send (SND.NXT)",
222 "ns3::SequenceNumber32TracedValueCallback")
223 .AddTraceSource("HighestSequence",
224 "Highest sequence number ever sent in socket's life time",
226 "ns3::TracedValueCallback::SequenceNumber32")
227 .AddTraceSource("State",
228 "TCP state",
230 "ns3::TcpStatesTracedValueCallback")
231 .AddTraceSource("CongState",
232 "TCP Congestion machine state",
234 "ns3::TcpSocketState::TcpCongStatesTracedValueCallback")
235 .AddTraceSource("EcnState",
236 "Trace ECN state change of socket",
238 "ns3::TcpSocketState::EcnStatesTracedValueCallback")
239 .AddTraceSource("AdvWND",
240 "Advertised Window Size",
242 "ns3::TracedValueCallback::Uint32")
243 .AddTraceSource("RWND",
244 "Remote side's flow control window",
246 "ns3::TracedValueCallback::Uint32")
247 .AddTraceSource("BytesInFlight",
248 "Socket estimation of bytes in flight",
250 "ns3::TracedValueCallback::Uint32")
251 .AddTraceSource("FackAwnd",
252 "Socket estimation of bytes in flight by FACK",
254 "ns3::TracedValueCallback::Uint32")
255 .AddTraceSource("HighestRxSequence",
256 "Highest sequence number received from peer",
258 "ns3::TracedValueCallback::SequenceNumber32")
259 .AddTraceSource("HighestRxAck",
260 "Highest ack received from peer",
262 "ns3::TracedValueCallback::SequenceNumber32")
263 .AddTraceSource("PacingRate",
264 "The current TCP pacing rate",
266 "ns3::TracedValueCallback::DataRate")
267 .AddTraceSource("CongestionWindow",
268 "The TCP connection's congestion window",
270 "ns3::TracedValueCallback::Uint32")
271 .AddTraceSource("CongestionWindowInflated",
272 "The TCP connection's congestion window inflates as in older RFC",
274 "ns3::TracedValueCallback::Uint32")
275 .AddTraceSource("SlowStartThreshold",
276 "TCP slow start threshold (bytes)",
278 "ns3::TracedValueCallback::Uint32")
279 .AddTraceSource("Tx",
280 "Send tcp packet to IP protocol",
282 "ns3::TcpSocketBase::TcpTxRxTracedCallback")
283 .AddTraceSource("Retransmission",
284 "Notification of a TCP retransmission",
286 "ns3::TcpSocketBase::RetransmissionCallback")
287 .AddTraceSource("Rx",
288 "Receive tcp packet from IP protocol",
290 "ns3::TcpSocketBase::TcpTxRxTracedCallback")
291 .AddTraceSource("EcnEchoSeq",
292 "Sequence of last received ECN Echo",
294 "ns3::SequenceNumber32TracedValueCallback")
295 .AddTraceSource("EcnCeSeq",
296 "Sequence of last received CE",
298 "ns3::SequenceNumber32TracedValueCallback")
299 .AddTraceSource("EcnCwrSeq",
300 "Sequence of last received CWR",
302 "ns3::SequenceNumber32TracedValueCallback");
303 return tid;
304}
305
307 : TcpSocket()
308{
309 NS_LOG_FUNCTION(this);
310
312 m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
315
316 m_sndFack = 0;
318
319 m_tcb->m_rxBuffer = CreateObject<TcpRxBuffer>();
320
321 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
323
324 m_tcb->m_sendEmptyPacketCallback = MakeCallback(&TcpSocketBase::SendEmptyPacket, this);
325
326 bool ok;
327
328 ok = m_tcb->TraceConnectWithoutContext(
329 "PacingRate",
331 NS_ASSERT_MSG(ok, "Could not connect trace source PacingRate");
332
333 ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
335 NS_ASSERT_MSG(ok, "Could not connect trace source CongestionWindow");
336
337 ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
339 NS_ASSERT_MSG(ok, "Could not connect trace source CongestionWindowInflated");
340
341 ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
343 NS_ASSERT_MSG(ok, "Could not connect trace source SlowStartThreshold");
344
345 ok = m_tcb->TraceConnectWithoutContext("CongState",
347 NS_ASSERT_MSG(ok, "Could not connect trace source CongState");
348
349 ok = m_tcb->TraceConnectWithoutContext("EcnState",
351 NS_ASSERT_MSG(ok, "Could not connect trace source EcnState");
352
353 ok =
354 m_tcb->TraceConnectWithoutContext("NextTxSequence",
356 NS_ASSERT_MSG(ok, "Could not connect trace source NextTxSequence");
357
358 ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
360 NS_ASSERT_MSG(ok, "Could not connect trace source HighestSequence");
361
362 ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
364 NS_ASSERT_MSG(ok, "Could not connect trace source BytesInFlight");
365
366 ok = m_tcb->TraceConnectWithoutContext("FackAwnd",
368 NS_ASSERT_MSG(ok, "Could not connect trace source FackAwnd");
369
370 ok = m_tcb->TraceConnectWithoutContext("RTT", MakeCallback(&TcpSocketBase::UpdateRtt, this));
371 NS_ASSERT_MSG(ok, "Could not connect trace source RTT");
372
373 ok = m_tcb->TraceConnectWithoutContext("LastRTT",
375 NS_ASSERT_MSG(ok, "Could not connect trace source LastRTT");
376}
377
378void
385
387 : TcpSocket(sock),
388 // copy object::m_tid and socket::callbacks
390 m_delAckCount(0),
392 m_noDelay(sock.m_noDelay),
397 m_rto(sock.m_rto),
398 m_minRto(sock.m_minRto),
403 m_endPoint(nullptr),
404 m_endPoint6(nullptr),
405 m_node(sock.m_node),
406 m_tcp(sock.m_tcp),
407 m_state(sock.m_state),
408 m_errno(sock.m_errno),
414 m_msl(sock.m_msl),
417 m_rWnd(sock.m_rWnd),
427 m_recover(sock.m_recover),
432 m_txTrace(sock.m_txTrace),
433 m_rxTrace(sock.m_rxTrace),
434 m_pacingTimer(Timer::CANCEL_ON_DESTROY),
438{
439 NS_LOG_FUNCTION(this);
440 NS_LOG_LOGIC("Invoked the copy constructor");
441 // Copy the rtt estimator if it is set
442 if (sock.m_rtt)
443 {
444 m_rtt = sock.m_rtt->Copy();
445 }
446 // Reset all callbacks to null
448 Callback<void, Ptr<Socket>, const Address&> vPSA =
451 SetConnectCallback(vPS, vPS);
452 SetDataSentCallback(vPSUI);
453 SetSendCallback(vPSUI);
454 SetRecvCallback(vPS);
456 m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
457 m_tcb = CopyObject(sock.m_tcb);
458 m_tcb->m_rxBuffer = CopyObject(sock.m_tcb->m_rxBuffer);
459
460 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
462
464
465 if (sock.m_congestionControl)
466 {
469 m_congestionControl->SetRateOps(m_rateOps);
470 }
471
472 if (sock.m_recoveryOps)
473 {
474 m_recoveryOps = sock.m_recoveryOps->Fork();
475 }
476
477 if (m_tcb->m_sendEmptyPacketCallback.IsNull())
478 {
479 m_tcb->m_sendEmptyPacketCallback = MakeCallback(&TcpSocketBase::SendEmptyPacket, this);
480 }
481
482 m_sndFack = sock.m_sndFack;
484
485 bool ok;
486
487 ok = m_tcb->TraceConnectWithoutContext(
488 "PacingRate",
490 NS_ASSERT_MSG(ok, "Could not connect trace source PacingRate");
491
492 ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
494 NS_ASSERT_MSG(ok, "Could not connect trace source CongestionWindow");
495
496 ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
498 NS_ASSERT_MSG(ok, "Could not connect trace source CongestionWindowInflated");
499
500 ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
502 NS_ASSERT_MSG(ok, "Could not connect trace source SlowStartThreshold");
503
504 ok = m_tcb->TraceConnectWithoutContext("CongState",
506 NS_ASSERT_MSG(ok, "Could not connect trace source CongState");
507
508 ok = m_tcb->TraceConnectWithoutContext("EcnState",
510 NS_ASSERT_MSG(ok, "Could not connect trace source EcnState");
511
512 ok =
513 m_tcb->TraceConnectWithoutContext("NextTxSequence",
515 NS_ASSERT_MSG(ok, "Could not connect trace source NextTxSequence");
516
517 ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
519 NS_ASSERT_MSG(ok, "Could not connect trace source HighestSequence");
520 ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
522 NS_ASSERT_MSG(ok, "Could not connect trace source BytesInFlight");
523
524 ok = m_tcb->TraceConnectWithoutContext("FackAwnd",
526
527 ok = m_tcb->TraceConnectWithoutContext("RTT", MakeCallback(&TcpSocketBase::UpdateRtt, this));
528 NS_ASSERT_MSG(ok, "Could not connect trace source RTT");
529
530 ok = m_tcb->TraceConnectWithoutContext("LastRTT",
532 NS_ASSERT_MSG(ok, "Could not connect trace source LastRTT");
533}
534
536{
537 NS_LOG_FUNCTION(this);
538 m_node = nullptr;
539 if (m_endPoint != nullptr)
540 {
542 /*
543 * Upon Bind, an Ipv4Endpoint is allocated and set to m_endPoint, and
544 * DestroyCallback is set to TcpSocketBase::Destroy. If we called
545 * m_tcp->DeAllocate, it will destroy its Ipv4EndpointDemux::DeAllocate,
546 * which in turn destroys my m_endPoint, and in turn invokes
547 * TcpSocketBase::Destroy to nullify m_node, m_endPoint, and m_tcp.
548 */
549 NS_ASSERT(m_endPoint != nullptr);
550 m_tcp->DeAllocate(m_endPoint);
551 NS_ASSERT(m_endPoint == nullptr);
552 }
553 if (m_endPoint6 != nullptr)
554 {
556 NS_ASSERT(m_endPoint6 != nullptr);
557 m_tcp->DeAllocate(m_endPoint6);
558 NS_ASSERT(m_endPoint6 == nullptr);
559 }
560 m_tcp = nullptr;
562}
563
564/* Associate a node with this TCP socket */
565void
567{
568 m_node = node;
569}
570
571/* Associate the L4 protocol (e.g. mux/demux) with this socket */
572void
577
578/* Set an RTT estimator with this socket */
579void
584
585/* Inherit from Socket class: Returns error code */
588{
589 return m_errno;
590}
591
592/* Inherit from Socket class: Returns socket type, NS3_SOCK_STREAM */
595{
596 return NS3_SOCK_STREAM;
597}
598
599/* Inherit from Socket class: Returns associated node */
602{
603 return m_node;
604}
605
606/* Inherit from Socket class: Bind socket to an end-point in TcpL4Protocol */
607int
609{
610 NS_LOG_FUNCTION(this);
611 m_endPoint = m_tcp->Allocate();
612 if (nullptr == m_endPoint)
613 {
615 return -1;
616 }
617
618 m_tcp->AddSocket(this);
619
620 return SetupCallback();
621}
622
623int
625{
626 NS_LOG_FUNCTION(this);
627 m_endPoint6 = m_tcp->Allocate6();
628 if (nullptr == m_endPoint6)
629 {
631 return -1;
632 }
633
634 m_tcp->AddSocket(this);
635
636 return SetupCallback();
637}
638
639/* Inherit from Socket class: Bind socket (with specific address) to an end-point in TcpL4Protocol
640 */
641int
643{
644 NS_LOG_FUNCTION(this << address);
646 {
648 Ipv4Address ipv4 = transport.GetIpv4();
649 uint16_t port = transport.GetPort();
650 if (ipv4 == Ipv4Address::GetAny() && port == 0)
651 {
652 m_endPoint = m_tcp->Allocate();
653 }
654 else if (ipv4 == Ipv4Address::GetAny() && port != 0)
655 {
656 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), port);
657 }
658 else if (ipv4 != Ipv4Address::GetAny() && port == 0)
659 {
660 m_endPoint = m_tcp->Allocate(ipv4);
661 }
662 else if (ipv4 != Ipv4Address::GetAny() && port != 0)
663 {
664 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), ipv4, port);
665 }
666 if (nullptr == m_endPoint)
667 {
669 return -1;
670 }
671 }
672 else if (Inet6SocketAddress::IsMatchingType(address))
673 {
675 Ipv6Address ipv6 = transport.GetIpv6();
676 uint16_t port = transport.GetPort();
677 if (ipv6 == Ipv6Address::GetAny() && port == 0)
678 {
679 m_endPoint6 = m_tcp->Allocate6();
680 }
681 else if (ipv6 == Ipv6Address::GetAny() && port != 0)
682 {
683 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), port);
684 }
685 else if (ipv6 != Ipv6Address::GetAny() && port == 0)
686 {
687 m_endPoint6 = m_tcp->Allocate6(ipv6);
688 }
689 else if (ipv6 != Ipv6Address::GetAny() && port != 0)
690 {
691 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), ipv6, port);
692 }
693 if (nullptr == m_endPoint6)
694 {
696 return -1;
697 }
698 }
699 else
700 {
702 return -1;
703 }
704
705 m_tcp->AddSocket(this);
706
707 NS_LOG_LOGIC("TcpSocketBase " << this << " got an endpoint: " << m_endPoint);
708
709 return SetupCallback();
710}
711
712void
714{
716 (m_state == CLOSED) || threshold == m_tcb->m_initialSsThresh,
717 "TcpSocketBase::SetSSThresh() cannot change initial ssThresh after connection started.");
718
719 m_tcb->m_initialSsThresh = threshold;
720}
721
724{
725 return m_tcb->m_initialSsThresh;
726}
727
728void
730{
732 (m_state == CLOSED) || cwnd == m_tcb->m_initialCWnd,
733 "TcpSocketBase::SetInitialCwnd() cannot change initial cwnd after connection started.");
734
735 m_tcb->m_initialCWnd = cwnd;
736}
737
740{
741 return m_tcb->m_initialCWnd;
742}
743
744/* Inherit from Socket class: Initiate connection to a remote address:port */
745int
747{
748 NS_LOG_FUNCTION(this << address);
749
750 // If haven't do so, Bind() this socket first
752 {
753 if (m_endPoint == nullptr)
754 {
755 if (Bind() == -1)
756 {
757 NS_ASSERT(m_endPoint == nullptr);
758 return -1; // Bind() failed
759 }
760 NS_ASSERT(m_endPoint != nullptr);
761 }
763 m_endPoint->SetPeer(transport.GetIpv4(), transport.GetPort());
764 m_endPoint6 = nullptr;
765
766 // Get the appropriate local address and port number from the routing protocol and set up
767 // endpoint
768 if (SetupEndpoint() != 0)
769 {
770 NS_LOG_ERROR("Route to destination does not exist ?!");
771 return -1;
772 }
773 }
774 else if (Inet6SocketAddress::IsMatchingType(address))
775 {
776 // If we are operating on a v4-mapped address, translate the address to
777 // a v4 address and re-call this function
779 Ipv6Address v6Addr = transport.GetIpv6();
780 if (v6Addr.IsIpv4MappedAddress())
781 {
782 Ipv4Address v4Addr = v6Addr.GetIpv4MappedAddress();
783 return Connect(InetSocketAddress(v4Addr, transport.GetPort()));
784 }
785
786 if (m_endPoint6 == nullptr)
787 {
788 if (Bind6() == -1)
789 {
790 NS_ASSERT(m_endPoint6 == nullptr);
791 return -1; // Bind() failed
792 }
793 NS_ASSERT(m_endPoint6 != nullptr);
794 }
795 m_endPoint6->SetPeer(v6Addr, transport.GetPort());
796 m_endPoint = nullptr;
797
798 // Get the appropriate local address and port number from the routing protocol and set up
799 // endpoint
800 if (SetupEndpoint6() != 0)
801 {
802 NS_LOG_ERROR("Route to destination does not exist ?!");
803 return -1;
804 }
805 }
806 else
807 {
809 return -1;
810 }
811
812 // Re-initialize parameters in case this socket is being reused after CLOSE
813 m_rtt->Reset();
816
817 // DoConnect() will do state-checking and send a SYN packet
818 return DoConnect();
819}
820
821/* Inherit from Socket class: Listen on the endpoint for an incoming connection */
822int
824{
825 NS_LOG_FUNCTION(this);
826
827 // Linux quits EINVAL if we're not in CLOSED state, so match what they do
828 if (m_state != CLOSED)
829 {
831 return -1;
832 }
833 // In other cases, set the state to LISTEN and done
834 NS_LOG_DEBUG("CLOSED -> LISTEN");
835 m_state = LISTEN;
836 return 0;
837}
838
839/* Inherit from Socket class: Kill this socket and signal the peer (if any) */
840int
842{
843 NS_LOG_FUNCTION(this);
844 /// @internal
845 /// First we check to see if there is any unread rx data.
846 /// \bugid{426} claims we should send reset in this case.
847 if (m_tcb->m_rxBuffer->Size() != 0)
848 {
849 NS_LOG_WARN("Socket " << this << " << unread rx data during close. Sending reset."
850 << "This is probably due to a bad sink application; check its code");
851 SendRST();
852 return 0;
853 }
854
855 if (m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence) > 0)
856 { // App close with pending data must wait until all data transmitted
857 if (!m_closeOnEmpty)
858 {
859 m_closeOnEmpty = true;
860 NS_LOG_INFO("Socket " << this << " deferring close, state " << TcpStateName[m_state]);
861 }
862 return 0;
863 }
864 return DoClose();
865}
866
867/* Inherit from Socket class: Signal a termination of send */
868int
870{
871 NS_LOG_FUNCTION(this);
872
873 // this prevents data from being added to the buffer
874 m_shutdownSend = true;
875 m_closeOnEmpty = true;
876 // if buffer is already empty, send a fin now
877 // otherwise fin will go when buffer empties.
878 if (m_txBuffer->Size() == 0)
879 {
881 {
882 NS_LOG_INFO("Empty tx buffer, send fin");
884
885 if (m_state == ESTABLISHED)
886 { // On active close: I am the first one to send FIN
887 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
889 }
890 else
891 { // On passive close: Peer sent me FIN already
892 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
894 }
895 }
896 }
897
898 return 0;
899}
900
901/* Inherit from Socket class: Signal a termination of receive */
902int
904{
905 NS_LOG_FUNCTION(this);
906 m_shutdownRecv = true;
907 return 0;
908}
909
910/* Inherit from Socket class: Send a packet. Parameter flags is not used.
911 Packet has no TCP header. Invoked by upper-layer application */
912int
914{
915 NS_LOG_FUNCTION(this << p);
916 NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Send()");
918 {
919 // Store the packet into Tx buffer
920 if (!m_txBuffer->Add(p))
921 { // TxBuffer overflow, send failed
923 return -1;
924 }
925 if (m_shutdownSend)
926 {
928 return -1;
929 }
930
931 m_rateOps->CalculateAppLimited(m_tcb->m_cWnd,
932 m_tcb->m_bytesInFlight,
933 m_tcb->m_segmentSize,
934 m_txBuffer->TailSequence(),
935 m_tcb->m_nextTxSequence,
936 m_txBuffer->GetLost(),
937 m_txBuffer->GetRetransmitsCount());
938
939 // Submit the data to lower layers
940 NS_LOG_LOGIC("txBufSize=" << m_txBuffer->Size() << " state " << TcpStateName[m_state]);
941 if ((m_state == ESTABLISHED || m_state == CLOSE_WAIT) && AvailableWindow() > 0)
942 { // Try to send the data out: Add a little step to allow the application
943 // to fill the buffer
944 if (!m_sendPendingDataEvent.IsPending())
945 {
948 this,
950 }
951 }
952 return p->GetSize();
953 }
954 else
955 { // Connection not established yet
957 return -1; // Send failure
958 }
959}
960
961/* Inherit from Socket class: In TcpSocketBase, it is same as Send() call */
962int
963TcpSocketBase::SendTo(Ptr<Packet> p, uint32_t flags, const Address& /* address */)
964{
965 return Send(p, flags); // SendTo() and Send() are the same
966}
967
968/* Inherit from Socket class: Return data to upper-layer application. Parameter flags
969 is not used. Data is returned as a packet of size no larger than maxSize */
972{
973 NS_LOG_FUNCTION(this);
974 NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Recv()");
975 if (m_tcb->m_rxBuffer->Size() == 0 && m_state == CLOSE_WAIT)
976 {
977 return Create<Packet>(); // Send EOF on connection close
978 }
979 Ptr<Packet> outPacket = m_tcb->m_rxBuffer->Extract(maxSize);
980 return outPacket;
981}
982
983/* Inherit from Socket class: Recv and return the remote's address */
986{
987 NS_LOG_FUNCTION(this << maxSize << flags);
988 Ptr<Packet> packet = Recv(maxSize, flags);
989 // Null packet means no data to read, and an empty packet indicates EOF
990 if (packet && packet->GetSize() != 0)
991 {
992 if (m_endPoint != nullptr)
993 {
994 fromAddress =
995 InetSocketAddress(m_endPoint->GetPeerAddress(), m_endPoint->GetPeerPort());
996 }
997 else if (m_endPoint6 != nullptr)
998 {
999 fromAddress =
1000 Inet6SocketAddress(m_endPoint6->GetPeerAddress(), m_endPoint6->GetPeerPort());
1001 }
1002 else
1003 {
1004 fromAddress = InetSocketAddress(Ipv4Address::GetZero(), 0);
1005 }
1006 }
1007 return packet;
1008}
1009
1010/* Inherit from Socket class: Get the max number of bytes an app can send */
1013{
1014 NS_LOG_FUNCTION(this);
1015 return m_txBuffer->Available();
1016}
1017
1018/* Inherit from Socket class: Get the max number of bytes an app can read */
1021{
1022 NS_LOG_FUNCTION(this);
1023 return m_tcb->m_rxBuffer->Available();
1024}
1025
1026/* Inherit from Socket class: Return local address:port */
1027int
1029{
1030 NS_LOG_FUNCTION(this);
1031 if (m_endPoint != nullptr)
1032 {
1033 address = InetSocketAddress(m_endPoint->GetLocalAddress(), m_endPoint->GetLocalPort());
1034 }
1035 else if (m_endPoint6 != nullptr)
1036 {
1037 address = Inet6SocketAddress(m_endPoint6->GetLocalAddress(), m_endPoint6->GetLocalPort());
1038 }
1039 else
1040 { // It is possible to call this method on a socket without a name
1041 // in which case, behavior is unspecified
1042 // Should this return an InetSocketAddress or an Inet6SocketAddress?
1044 }
1045 return 0;
1046}
1047
1048int
1050{
1051 NS_LOG_FUNCTION(this << address);
1052
1053 if (!m_endPoint && !m_endPoint6)
1054 {
1056 return -1;
1057 }
1058
1059 if (m_endPoint)
1060 {
1061 address = InetSocketAddress(m_endPoint->GetPeerAddress(), m_endPoint->GetPeerPort());
1062 }
1063 else if (m_endPoint6)
1064 {
1065 address = Inet6SocketAddress(m_endPoint6->GetPeerAddress(), m_endPoint6->GetPeerPort());
1066 }
1067 else
1068 {
1069 NS_ASSERT(false);
1070 }
1071
1072 return 0;
1073}
1074
1075/* Inherit from Socket class: Bind this socket to the specified NetDevice */
1076void
1078{
1079 NS_LOG_FUNCTION(netdevice);
1080 Socket::BindToNetDevice(netdevice); // Includes sanity check
1081 if (m_endPoint != nullptr)
1082 {
1083 m_endPoint->BindToNetDevice(netdevice);
1084 }
1085
1086 if (m_endPoint6 != nullptr)
1087 {
1088 m_endPoint6->BindToNetDevice(netdevice);
1089 }
1090}
1091
1092/* Clean up after Bind. Set up callback functions in the end-point. */
1093int
1095{
1096 NS_LOG_FUNCTION(this);
1097
1098 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
1099 {
1100 return -1;
1101 }
1102 if (m_endPoint != nullptr)
1103 {
1104 m_endPoint->SetRxCallback(
1106 m_endPoint->SetIcmpCallback(
1108 m_endPoint->SetDestroyCallback(
1110 }
1111 if (m_endPoint6 != nullptr)
1112 {
1113 m_endPoint6->SetRxCallback(
1115 m_endPoint6->SetIcmpCallback(
1117 m_endPoint6->SetDestroyCallback(
1119 }
1120
1121 return 0;
1122}
1123
1124/* Perform the real connection tasks: Send SYN if allowed, RST if invalid */
1125int
1127{
1128 NS_LOG_FUNCTION(this);
1129
1130 // A new connection is allowed only if this socket does not have a connection
1131 if (m_state == CLOSED || m_state == LISTEN || m_state == SYN_SENT || m_state == LAST_ACK ||
1133 { // send a SYN packet and change state into SYN_SENT
1134 // send a SYN packet with ECE and CWR flags set if sender is ECN capable
1135 if (m_tcb->m_useEcn == TcpSocketState::On)
1136 {
1138 }
1139 else
1140 {
1142 }
1143 NS_LOG_DEBUG(TcpStateName[m_state] << " -> SYN_SENT");
1144 m_state = SYN_SENT;
1145 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED; // because sender is not yet aware about
1146 // receiver's ECN capability
1147 }
1148 else if (m_state != TIME_WAIT)
1149 { // In states SYN_RCVD, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, and CLOSING, an connection
1150 // exists. We send RST, tear down everything, and close this socket.
1151 SendRST();
1153 }
1154 return 0;
1155}
1156
1157/* Do the action to close the socket. Usually send a packet with appropriate
1158 flags depended on the current m_state. */
1159int
1161{
1162 NS_LOG_FUNCTION(this);
1163 switch (m_state)
1164 {
1165 case SYN_RCVD:
1166 case ESTABLISHED:
1167 // send FIN to close the peer
1169 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
1171 break;
1172 case CLOSE_WAIT:
1173 // send FIN+ACK to close the peer
1175 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
1176 m_state = LAST_ACK;
1177 break;
1178 case SYN_SENT:
1179 case CLOSING:
1180 // Send RST if application closes in SYN_SENT and CLOSING
1181 SendRST();
1183 break;
1184 case LISTEN:
1185 // In this state, move to CLOSED and tear down the end point
1187 break;
1188 case LAST_ACK:
1189 case CLOSED:
1190 case FIN_WAIT_1:
1191 case FIN_WAIT_2:
1192 case TIME_WAIT:
1193 default: /* mute compiler */
1194 // Do nothing in these five states
1195 break;
1196 }
1197 return 0;
1198}
1199
1200/* Peacefully close the socket by notifying the upper layer and deallocate end point */
1201void
1203{
1204 NS_LOG_FUNCTION(this);
1205
1206 if (!m_closeNotified)
1207 {
1209 m_closeNotified = true;
1210 }
1211 if (m_lastAckEvent.IsPending())
1212 {
1213 m_lastAckEvent.Cancel();
1214 }
1215 NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSED");
1216 m_state = CLOSED;
1218}
1219
1220/* Tell if a sequence number range is out side the range that my rx buffer can
1221 accept */
1222bool
1224{
1225 if (m_state == LISTEN || m_state == SYN_SENT || m_state == SYN_RCVD)
1226 { // Rx buffer in these states are not initialized.
1227 return false;
1228 }
1229 if (m_state == LAST_ACK || m_state == CLOSING || m_state == CLOSE_WAIT)
1230 { // In LAST_ACK and CLOSING states, it only wait for an ACK and the
1231 // sequence number must equals to m_rxBuffer->NextRxSequence ()
1232 return (m_tcb->m_rxBuffer->NextRxSequence() != head);
1233 }
1234
1235 // In all other cases, check if the sequence number is in range
1236 return (tail < m_tcb->m_rxBuffer->NextRxSequence() ||
1237 m_tcb->m_rxBuffer->MaxRxSequence() <= head);
1238}
1239
1240/* Function called by the L3 protocol when it received a packet to pass on to
1241 the TCP. This function is registered as the "RxCallback" function in
1242 SetupCallback(), which invoked by Bind(), and CompleteFork() */
1243void
1245 Ipv4Header header,
1246 uint16_t port,
1247 Ptr<Ipv4Interface> incomingInterface)
1248{
1249 NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint->GetPeerAddress() << ":"
1250 << m_endPoint->GetPeerPort() << " to " << m_endPoint->GetLocalAddress()
1251 << ":" << m_endPoint->GetLocalPort());
1252
1253 Address fromAddress = InetSocketAddress(header.GetSource(), port);
1254 Address toAddress = InetSocketAddress(header.GetDestination(), m_endPoint->GetLocalPort());
1255
1256 TcpHeader tcpHeader;
1257 uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1258
1259 if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1260 bytesRemoved,
1261 packet->GetSize() - bytesRemoved))
1262 {
1263 return;
1264 }
1265
1266 if (header.GetEcn() == Ipv4Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1267 {
1268 NS_LOG_INFO("Received CE flag is valid");
1269 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
1270 m_ecnCESeq = tcpHeader.GetSequenceNumber();
1271 m_tcb->m_ecnState = TcpSocketState::ECN_CE_RCVD;
1273 }
1274 else if (header.GetEcn() != Ipv4Header::ECN_NotECT &&
1275 m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED)
1276 {
1278 }
1279
1280 DoForwardUp(packet, fromAddress, toAddress);
1281}
1282
1283void
1285 Ipv6Header header,
1286 uint16_t port,
1287 Ptr<Ipv6Interface> incomingInterface)
1288{
1289 NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint6->GetPeerAddress() << ":"
1290 << m_endPoint6->GetPeerPort() << " to " << m_endPoint6->GetLocalAddress()
1291 << ":" << m_endPoint6->GetLocalPort());
1292
1293 Address fromAddress = Inet6SocketAddress(header.GetSource(), port);
1294 Address toAddress = Inet6SocketAddress(header.GetDestination(), m_endPoint6->GetLocalPort());
1295
1296 TcpHeader tcpHeader;
1297 uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1298
1299 if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1300 bytesRemoved,
1301 packet->GetSize() - bytesRemoved))
1302 {
1303 return;
1304 }
1305
1306 if (header.GetEcn() == Ipv6Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1307 {
1308 NS_LOG_INFO("Received CE flag is valid");
1309 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
1310 m_ecnCESeq = tcpHeader.GetSequenceNumber();
1311 m_tcb->m_ecnState = TcpSocketState::ECN_CE_RCVD;
1313 }
1314 else if (header.GetEcn() != Ipv6Header::ECN_NotECT)
1315 {
1317 }
1318
1319 DoForwardUp(packet, fromAddress, toAddress);
1320}
1321
1322void
1324 uint8_t icmpTtl,
1325 uint8_t icmpType,
1326 uint8_t icmpCode,
1327 uint32_t icmpInfo)
1328{
1329 NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1330 << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1331 << icmpInfo);
1332 if (!m_icmpCallback.IsNull())
1333 {
1334 m_icmpCallback(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1335 }
1336}
1337
1338void
1340 uint8_t icmpTtl,
1341 uint8_t icmpType,
1342 uint8_t icmpCode,
1343 uint32_t icmpInfo)
1344{
1345 NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1346 << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1347 << icmpInfo);
1348 if (!m_icmpCallback6.IsNull())
1349 {
1350 m_icmpCallback6(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1351 }
1352}
1353
1354bool
1356 const uint32_t tcpHeaderSize,
1357 const uint32_t tcpPayloadSize)
1358{
1359 if (tcpHeaderSize == 0 || tcpHeaderSize > 60)
1360 {
1361 NS_LOG_ERROR("Bytes removed: " << tcpHeaderSize << " invalid");
1362 return false; // Discard invalid packet
1363 }
1364 else if (tcpPayloadSize > 0 && OutOfRange(seq, seq + tcpPayloadSize))
1365 {
1366 // Discard fully out of range data packets
1367 NS_LOG_WARN("At state " << TcpStateName[m_state] << " received packet of seq [" << seq
1368 << ":" << seq + tcpPayloadSize << ") out of range ["
1369 << m_tcb->m_rxBuffer->NextRxSequence() << ":"
1370 << m_tcb->m_rxBuffer->MaxRxSequence() << ")");
1371 // Acknowledgement should be sent for all unacceptable packets (RFC793, p.69)
1373 return false;
1374 }
1375 return true;
1376}
1377
1378void
1379TcpSocketBase::DoForwardUp(Ptr<Packet> packet, const Address& fromAddress, const Address& toAddress)
1380{
1381 // in case the packet still has a priority tag attached, remove it
1382 SocketPriorityTag priorityTag;
1383 packet->RemovePacketTag(priorityTag);
1384
1385 // Peel off TCP header
1386 TcpHeader tcpHeader;
1387 packet->RemoveHeader(tcpHeader);
1388 SequenceNumber32 seq = tcpHeader.GetSequenceNumber();
1389
1390 if (m_state == ESTABLISHED && !(tcpHeader.GetFlags() & TcpHeader::RST))
1391 {
1392 // Check if the sender has responded to ECN echo by reducing the Congestion Window
1393 if (tcpHeader.GetFlags() & TcpHeader::CWR)
1394 {
1395 // Check if a packet with CE bit set is received. If there is no CE bit set, then change
1396 // the state to ECN_IDLE to stop sending ECN Echo messages. If there is CE bit set, the
1397 // packet should continue sending ECN Echo messages
1398 //
1399 if (m_tcb->m_ecnState != TcpSocketState::ECN_CE_RCVD)
1400 {
1401 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
1402 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
1403 }
1404 }
1405 }
1406
1407 m_rxTrace(packet, tcpHeader, this);
1408
1409 if (tcpHeader.GetFlags() & TcpHeader::SYN)
1410 {
1411 /* The window field in a segment where the SYN bit is set (i.e., a <SYN>
1412 * or <SYN,ACK>) MUST NOT be scaled (from RFC 7323 page 9). But should be
1413 * saved anyway..
1414 */
1415 m_rWnd = tcpHeader.GetWindowSize();
1416
1418 {
1420 }
1421 else
1422 {
1423 m_winScalingEnabled = false;
1424 }
1425
1427 {
1429 }
1430 else
1431 {
1432 m_sackEnabled = false;
1433 m_txBuffer->SetSackEnabled(false);
1434 }
1435
1436 // When receiving a <SYN> or <SYN-ACK> we should adapt TS to the other end
1437 if (tcpHeader.HasOption(TcpOption::TS) && m_timestampEnabled)
1438 {
1440 tcpHeader.GetSequenceNumber());
1441 }
1442 else
1443 {
1444 m_timestampEnabled = false;
1445 }
1446
1447 // Initialize cWnd and ssThresh
1448 m_tcb->m_cWnd = GetInitialCwnd() * GetSegSize();
1449 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
1450 m_tcb->m_ssThresh = GetInitialSSThresh();
1451
1452 if (tcpHeader.GetFlags() & TcpHeader::ACK)
1453 {
1454 EstimateRtt(tcpHeader);
1455 m_highRxAckMark = tcpHeader.GetAckNumber();
1456 }
1457 }
1458 else if (tcpHeader.GetFlags() & TcpHeader::ACK)
1459 {
1460 NS_ASSERT(!(tcpHeader.GetFlags() & TcpHeader::SYN));
1462 {
1463 if (!tcpHeader.HasOption(TcpOption::TS))
1464 {
1465 // Ignoring segment without TS, RFC 7323
1466 NS_LOG_LOGIC("At state " << TcpStateName[m_state] << " received packet of seq ["
1467 << seq << ":" << seq + packet->GetSize()
1468 << ") without TS option. Silently discard it");
1469 return;
1470 }
1471 else
1472 {
1474 tcpHeader.GetSequenceNumber());
1475 }
1476 }
1477
1478 EstimateRtt(tcpHeader);
1479 UpdateWindowSize(tcpHeader);
1480 }
1481
1482 if (m_rWnd.Get() == 0 && m_persistEvent.IsExpired())
1483 { // Zero window: Enter persist state to send 1 byte to probe
1484 NS_LOG_LOGIC(this << " Enter zerowindow persist state");
1486 this << " Cancelled ReTxTimeout event which was set to expire at "
1487 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
1488 m_retxEvent.Cancel();
1489 NS_LOG_LOGIC("Schedule persist timeout at time "
1490 << Simulator::Now().GetSeconds() << " to expire at time "
1491 << (Simulator::Now() + m_persistTimeout).GetSeconds());
1495 }
1496
1497 // TCP state machine code in different process functions
1498 // C.f.: tcp_rcv_state_process() in tcp_input.c in Linux kernel
1499 switch (m_state)
1500 {
1501 case ESTABLISHED:
1502 ProcessEstablished(packet, tcpHeader);
1503 break;
1504 case LISTEN:
1505 ProcessListen(packet, tcpHeader, fromAddress, toAddress);
1506 break;
1507 case TIME_WAIT:
1508 // Do nothing
1509 break;
1510 case CLOSED:
1511 // Send RST if the incoming packet is not a RST
1512 if ((tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG)) != TcpHeader::RST)
1513 { // Since m_endPoint is not configured yet, we cannot use SendRST here
1514 TcpHeader h;
1517 h.SetSequenceNumber(m_tcb->m_nextTxSequence);
1518 h.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
1519 h.SetSourcePort(tcpHeader.GetDestinationPort());
1520 h.SetDestinationPort(tcpHeader.GetSourcePort());
1522 AddOptions(h);
1523 m_txTrace(p, h, this);
1524 m_tcp->SendPacket(p, h, toAddress, fromAddress, m_boundnetdevice);
1525 }
1526 break;
1527 case SYN_SENT:
1528 ProcessSynSent(packet, tcpHeader);
1529 break;
1530 case SYN_RCVD:
1531 ProcessSynRcvd(packet, tcpHeader, fromAddress, toAddress);
1532 break;
1533 case FIN_WAIT_1:
1534 case FIN_WAIT_2:
1535 case CLOSE_WAIT:
1536 ProcessWait(packet, tcpHeader);
1537 break;
1538 case CLOSING:
1539 ProcessClosing(packet, tcpHeader);
1540 break;
1541 case LAST_ACK:
1542 ProcessLastAck(packet, tcpHeader);
1543 break;
1544 default: // mute compiler
1545 break;
1546 }
1547
1548 if (m_rWnd.Get() != 0 && m_persistEvent.IsPending())
1549 { // persist probes end, the other end has increased the window
1551 NS_LOG_LOGIC(this << " Leaving zerowindow persist state");
1552 m_persistEvent.Cancel();
1553
1555 }
1556}
1557
1558/* Received a packet upon ESTABLISHED state. This function is mimicking the
1559 role of tcp_rcv_established() in tcp_input.c in Linux kernel. */
1560void
1562{
1563 NS_LOG_FUNCTION(this << tcpHeader);
1564
1565 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
1566 uint8_t tcpflags =
1568
1569 // Different flags are different events
1570 if (tcpflags == TcpHeader::ACK)
1571 {
1572 if (tcpHeader.GetAckNumber() < m_txBuffer->HeadSequence())
1573 {
1574 // Case 1: If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored.
1575 // Pag. 72 RFC 793
1576 NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1577 << " SND.UNA = " << m_txBuffer->HeadSequence());
1578
1579 // TODO: RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation]
1580 }
1581 else if (tcpHeader.GetAckNumber() > m_tcb->m_highTxMark)
1582 {
1583 // If the ACK acks something not yet sent (SEG.ACK > HighTxMark) then
1584 // send an ACK, drop the segment, and return.
1585 // Pag. 72 RFC 793
1586 NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1587 << " HighTxMark = " << m_tcb->m_highTxMark);
1588
1589 // Receiver sets ECE flags when it receives a packet with CE bit on or sender hasn't
1590 // responded to ECN echo sent by receiver
1591 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
1593 {
1596 << " -> ECN_SENDING_ECE");
1598 }
1599 else
1600 {
1602 }
1603 }
1604 else
1605 {
1606 // SND.UNA < SEG.ACK =< HighTxMark
1607 // Pag. 72 RFC 793
1608 ReceivedAck(packet, tcpHeader);
1609 }
1610 }
1611 else if (tcpflags == TcpHeader::SYN || tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
1612 {
1613 // (a) Received SYN, old NS-3 behaviour is to set state to SYN_RCVD and
1614 // respond with a SYN+ACK. But it is not a legal state transition as of
1615 // RFC793. Thus this is ignored.
1616
1617 // (b) No action for received SYN+ACK, it is probably a duplicated packet
1618 }
1619 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
1620 { // Received FIN or FIN+ACK, bring down this socket nicely
1621 PeerClose(packet, tcpHeader);
1622 }
1623 else if (tcpflags == 0)
1624 { // No flags means there is only data
1625 ReceivedData(packet, tcpHeader);
1626 if (m_tcb->m_rxBuffer->Finished())
1627 {
1628 PeerClose(packet, tcpHeader);
1629 }
1630 }
1631 else
1632 { // Received RST or the TCP flags is invalid, in either case, terminate this socket
1633 if (tcpflags != TcpHeader::RST)
1634 { // this must be an invalid flag, send reset
1635 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
1636 << " received. Reset packet is sent.");
1637 SendRST();
1638 }
1640 }
1641}
1642
1643bool
1645{
1646 NS_LOG_FUNCTION(this << static_cast<uint32_t>(kind));
1647
1648 switch (kind)
1649 {
1650 case TcpOption::TS:
1651 return m_timestampEnabled;
1653 return m_winScalingEnabled;
1655 case TcpOption::SACK:
1656 return m_sackEnabled;
1657 default:
1658 break;
1659 }
1660 return false;
1661}
1662
1663void
1664TcpSocketBase::ReadOptions(const TcpHeader& tcpHeader, uint32_t* bytesSacked)
1665{
1666 NS_LOG_FUNCTION(this << tcpHeader);
1667
1668 for (const auto& option : tcpHeader.GetOptionList())
1669 {
1670 // Check only for ACK options here
1671 switch (option->GetKind())
1672 {
1673 case TcpOption::SACK:
1674 *bytesSacked = ProcessOptionSack(option);
1675 break;
1676 default:
1677 continue;
1678 }
1679 }
1680}
1681
1682// Sender should reduce the Congestion Window as a response to receiver's
1683// ECN Echo notification only once per window
1684void
1686{
1687 NS_LOG_FUNCTION(this << currentDelivered);
1688 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, BytesInFlight());
1689 NS_LOG_DEBUG("Reduce ssThresh to " << m_tcb->m_ssThresh);
1690 // Do not update m_cWnd, under assumption that recovery process will
1691 // gradually bring it down to m_ssThresh. Update the 'inflated' value of
1692 // cWnd used for tracing, however.
1693 m_tcb->m_cWndInfl = m_tcb->m_ssThresh;
1694 NS_ASSERT(m_tcb->m_congState != TcpSocketState::CA_CWR);
1695 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_CWR");
1696 m_congestionControl->CongestionStateSet(m_tcb, TcpSocketState::CA_CWR);
1697 m_tcb->m_congState = TcpSocketState::CA_CWR;
1698 // CWR state will be exited when the ack exceeds the m_recover variable.
1699 // Do not set m_recoverActive (which applies to a loss-based recovery)
1700 // m_recover corresponds to Linux tp->high_seq
1701 m_recover = m_tcb->m_highTxMark;
1702 if (!m_congestionControl->HasCongControl())
1703 {
1704 // If there is a recovery algorithm, invoke it.
1705 m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1706 NS_LOG_INFO("Enter CWR recovery mode; set cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1707 << m_tcb->m_ssThresh << ", recover to "
1708 << m_recover);
1709 }
1710}
1711
1712void
1714{
1715 NS_LOG_FUNCTION(this);
1717
1718 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_RECOVERY");
1719
1720 if (!m_sackEnabled)
1721 {
1722 // One segment has left the network, PLUS the head is lost
1723 m_txBuffer->AddRenoSack();
1724 m_txBuffer->MarkHeadAsLost();
1725 }
1726 else
1727 {
1728 if (!m_txBuffer->IsLost(m_txBuffer->HeadSequence()))
1729 {
1730 // We received 3 dupacks, but the head is not marked as lost
1731 // (received less than 3 SACK block ahead).
1732 // Manually set it as lost.
1733 m_txBuffer->MarkHeadAsLost();
1734 }
1735 }
1736
1737 // RFC 6675, point (4):
1738 // (4) Invoke fast retransmit and enter loss recovery as follows:
1739 // (4.1) RecoveryPoint = HighData
1740 m_recover = m_tcb->m_highTxMark;
1741 m_recoverActive = true;
1742
1744 m_tcb->m_congState = TcpSocketState::CA_RECOVERY;
1745
1746 // (4.2) ssthresh = cwnd = (FlightSize / 2)
1747 // If SACK is not enabled, still consider the head as 'in flight' for
1748 // compatibility with old ns-3 versions
1749 uint32_t bytesInFlight =
1750 m_sackEnabled ? BytesInFlight() : BytesInFlight() + m_tcb->m_segmentSize;
1751 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, bytesInFlight);
1752
1753 if (!m_congestionControl->HasCongControl())
1754 {
1755 m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1756 NS_LOG_INFO(m_dupAckCount << " dupack. Enter fast recovery mode."
1757 << "Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1758 << m_tcb->m_ssThresh << " at fast recovery seqnum " << m_recover
1759 << " calculated in flight: " << bytesInFlight);
1760 }
1761
1762 // (4.3) Retransmit the first data segment presumed dropped
1763 uint32_t sz = SendDataPacket(m_highRxAckMark, m_tcb->m_segmentSize, true);
1764 NS_ASSERT_MSG(sz > 0, "SendDataPacket returned zero, indicating zero bytes were sent");
1765 // (4.4) Run SetPipe ()
1766 // (4.5) Proceed to step (C)
1767 // these steps are done after the ProcessAck function (SendPendingData)
1768}
1769
1770void
1772{
1773 NS_LOG_FUNCTION(this);
1774 // NOTE: We do not count the DupAcks received in CA_LOSS, because we
1775 // don't know if they are generated by a spurious retransmission or because
1776 // of a real packet loss. With SACK, it is easy to know, but we do not consider
1777 // dupacks. Without SACK, there are some heuristics in the RFC 6582, but
1778 // for now, we do not implement it, leading to ignoring the dupacks.
1779 if (m_tcb->m_congState == TcpSocketState::CA_LOSS)
1780 {
1781 return;
1782 }
1783
1784 // RFC 6675, Section 5, 3rd paragraph:
1785 // If the incoming ACK is a duplicate acknowledgment per the definition
1786 // in Section 2 (regardless of its status as a cumulative
1787 // acknowledgment), and the TCP is not currently in loss recovery
1788 // the TCP MUST increase DupAcks by one ...
1789 if (m_tcb->m_congState != TcpSocketState::CA_RECOVERY)
1790 {
1791 ++m_dupAckCount;
1792 }
1793
1794 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
1795 {
1796 // From Open we go Disorder
1798 "From OPEN->DISORDER but with " << m_dupAckCount << " dup ACKs");
1799
1801 m_tcb->m_congState = TcpSocketState::CA_DISORDER;
1802
1803 NS_LOG_DEBUG("CA_OPEN -> CA_DISORDER");
1804 }
1805
1806 if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
1807 {
1808 if (!m_sackEnabled)
1809 {
1810 // If we are in recovery and we receive a dupack, one segment
1811 // has left the network. This is equivalent to a SACK of one block.
1812 m_txBuffer->AddRenoSack();
1813 }
1814 if (!m_congestionControl->HasCongControl())
1815 {
1816 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, true);
1817 NS_LOG_INFO(m_dupAckCount << " Dupack received in fast recovery mode."
1818 "Increase cwnd to "
1819 << m_tcb->m_cWnd);
1820 }
1821 }
1822 else if (m_tcb->m_congState == TcpSocketState::CA_DISORDER)
1823 {
1824 // m_dupackCount should not exceed its threshold in CA_DISORDER state
1825 // when m_recoverActive has not been set. When recovery point
1826 // have been set after timeout, the sender could enter into CA_DISORDER
1827 // after receiving new ACK smaller than m_recover. After that, m_dupackCount
1828 // can be equal and larger than m_retxThresh and we should avoid entering
1829 // CA_RECOVERY and reducing sending rate again.
1831
1832 uint32_t fackDiff = 0;
1833 if (m_fackEnabled)
1834 {
1835 uint32_t headSeq = m_txBuffer->HeadSequence().GetValue();
1836 if (m_sndFack > headSeq)
1837 {
1838 fackDiff = m_sndFack - headSeq;
1839 }
1840 }
1841
1842 // RFC 6675, Section 5, continuing:
1843 // ... and take the following steps:
1844 // (1) If DupAcks >= DupThresh, go to step (4).
1845 // Sequence number comparison (m_highRxAckMark >= m_recover) will take
1846 // effect only when m_recover has been set. Hence, we can avoid to use
1847 // m_recover in the last congestion event and fail to enter
1848 // CA_RECOVERY when sequence number is advanced significantly since
1849 // the last congestion event, which could be common for
1850 // bandwidth-greedy application in high speed and reliable network
1851 // (such as datacenter network) whose sending rate is constrained by
1852 // TCP socket buffer size at receiver side.
1853
1854 // Check FACK recovery condition
1855
1856 if ((m_fackEnabled && fackDiff > m_tcb->m_segmentSize * 3) ||
1859 {
1860 EnterRecovery(currentDelivered);
1862 }
1863 // (2) If DupAcks < DupThresh but IsLost (HighACK + 1) returns true
1864 // (indicating at least three segments have arrived above the current
1865 // cumulative acknowledgment point, which is taken to indicate loss)
1866 // go to step (4). Note that m_highRxAckMark is (HighACK + 1)
1867 else if (m_txBuffer->IsLost(m_highRxAckMark))
1868 {
1869 EnterRecovery(currentDelivered);
1871 }
1872 else
1873 {
1874 // (3) The TCP MAY transmit previously unsent data segments as per
1875 // Limited Transmit [RFC5681] ...except that the number of octets
1876 // which may be sent is governed by pipe and cwnd as follows:
1877 //
1878 // (3.1) Set HighRxt to HighACK.
1879 // Not clear in RFC. We don't do this here, since we still have
1880 // to retransmit the segment.
1881
1882 if (!m_sackEnabled && m_limitedTx)
1883 {
1884 m_txBuffer->AddRenoSack();
1885
1886 // In limited transmit, cwnd Infl is not updated.
1887 }
1888 }
1889 }
1890}
1891
1892/* Process the newly received ACK */
1893void
1895{
1896 NS_LOG_FUNCTION(this << tcpHeader);
1897
1898 NS_ASSERT(0 != (tcpHeader.GetFlags() & TcpHeader::ACK));
1899 NS_ASSERT(m_tcb->m_segmentSize > 0);
1900
1901 uint32_t previousLost = m_txBuffer->GetLost();
1902 uint32_t priorInFlight = m_tcb->m_bytesInFlight.Get();
1903
1904 // RFC 6675, Section 5, 1st paragraph:
1905 // Upon the receipt of any ACK containing SACK information, the
1906 // scoreboard MUST be updated via the Update () routine (done in ReadOptions)
1907 uint32_t bytesSacked = 0;
1908 uint64_t previousDelivered = m_rateOps->GetConnectionRate().m_delivered;
1909 ReadOptions(tcpHeader, &bytesSacked);
1910
1911 SequenceNumber32 ackNumber = tcpHeader.GetAckNumber();
1912 SequenceNumber32 oldHeadSequence = m_txBuffer->HeadSequence();
1913
1914 if (ackNumber < oldHeadSequence)
1915 {
1916 NS_LOG_DEBUG("Possibly received a stale ACK (ack number < head sequence)");
1917 // If there is any data piggybacked, store it into m_rxBuffer
1918 if (packet->GetSize() > 0)
1919 {
1920 ReceivedData(packet, tcpHeader);
1921 }
1922 return;
1923 }
1924 if ((ackNumber > oldHeadSequence) && (ackNumber < m_recover) &&
1925 (m_tcb->m_congState == TcpSocketState::CA_RECOVERY))
1926 {
1927 uint32_t segAcked = (ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
1928 for (uint32_t i = 0; i < segAcked; i++)
1929 {
1930 if (m_txBuffer->IsRetransmittedDataAcked(ackNumber - (i * m_tcb->m_segmentSize)))
1931 {
1932 m_tcb->m_isRetransDataAcked = true;
1933 NS_LOG_DEBUG("Ack Number " << ackNumber << "is ACK of retransmitted packet.");
1934 }
1935 }
1936 }
1937
1938 m_txBuffer->DiscardUpTo(ackNumber, MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
1939
1940 auto currentDelivered =
1941 static_cast<uint32_t>(m_rateOps->GetConnectionRate().m_delivered - previousDelivered);
1942 m_tcb->m_lastAckedSackedBytes = currentDelivered;
1943
1944 if (m_tcb->m_congState == TcpSocketState::CA_CWR && (ackNumber > m_recover))
1945 {
1946 // Recovery is over after the window exceeds m_recover
1947 // (although it may be re-entered below if ECE is still set)
1948 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_OPEN");
1950 m_tcb->m_congState = TcpSocketState::CA_OPEN;
1951 if (!m_congestionControl->HasCongControl())
1952 {
1953 m_tcb->m_cWnd = m_tcb->m_ssThresh.Get();
1954 m_recoveryOps->ExitRecovery(m_tcb);
1956 }
1957 }
1958
1959 if (ackNumber > oldHeadSequence && (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED) &&
1960 (tcpHeader.GetFlags() & TcpHeader::ECE))
1961 {
1962 if (m_ecnEchoSeq < ackNumber)
1963 {
1964 NS_LOG_INFO("Received ECN Echo is valid");
1965 m_ecnEchoSeq = ackNumber;
1966 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_RCVD");
1967 m_tcb->m_ecnState = TcpSocketState::ECN_ECE_RCVD;
1968 if (m_tcb->m_congState != TcpSocketState::CA_CWR)
1969 {
1970 EnterCwr(currentDelivered);
1971 }
1972 }
1973 }
1974 else if (m_tcb->m_ecnState == TcpSocketState::ECN_ECE_RCVD &&
1975 !(tcpHeader.GetFlags() & TcpHeader::ECE))
1976 {
1977 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
1978 }
1979
1980 // Update bytes in flight before processing the ACK for proper calculation of congestion window
1981 NS_LOG_INFO("Update bytes in flight before processing the ACK.");
1982 BytesInFlight();
1983
1984 bool receivedData = packet->GetSize() > 0;
1985
1986 // RFC 6675 Section 5: 2nd, 3rd paragraph and point (A), (B) implementation
1987 // are inside the function ProcessAck
1988 ProcessAck(ackNumber, (bytesSacked > 0), currentDelivered, oldHeadSequence, receivedData);
1989 m_tcb->m_isRetransDataAcked = false;
1990
1991 if (m_congestionControl->HasCongControl())
1992 {
1993 uint32_t currentLost = m_txBuffer->GetLost();
1994 uint32_t lost =
1995 (currentLost > previousLost) ? currentLost - previousLost : previousLost - currentLost;
1996 auto rateSample = m_rateOps->GenerateSample(currentDelivered,
1997 lost,
1998 false,
1999 priorInFlight,
2000 m_tcb->m_minRtt);
2001 auto rateConn = m_rateOps->GetConnectionRate();
2002 m_congestionControl->CongControl(m_tcb, rateConn, rateSample);
2003 }
2004
2005 // If there is any data piggybacked, store it into m_rxBuffer
2006 if (receivedData)
2007 {
2008 ReceivedData(packet, tcpHeader);
2009 }
2010
2011 // RFC 6675, Section 5, point (C), try to send more data. NB: (C) is implemented
2012 // inside SendPendingData
2014}
2015
2016void
2018 bool scoreboardUpdated,
2019 uint32_t currentDelivered,
2020 const SequenceNumber32& oldHeadSequence,
2021 bool receivedData)
2022{
2023 NS_LOG_FUNCTION(this << ackNumber << scoreboardUpdated << currentDelivered << oldHeadSequence);
2024 // RFC 6675, Section 5, 2nd paragraph:
2025 // If the incoming ACK is a cumulative acknowledgment, the TCP MUST
2026 // reset DupAcks to zero.
2027 bool exitedFastRecovery = false;
2028 uint32_t oldDupAckCount = m_dupAckCount; // remember the old value
2029 m_tcb->m_lastAckedSeq = ackNumber; // Update lastAckedSeq
2030 uint32_t bytesAcked = 0;
2031
2032 /* In RFC 5681 the definition of duplicate acknowledgment was strict:
2033 *
2034 * (a) the receiver of the ACK has outstanding data,
2035 * (b) the incoming acknowledgment carries no data,
2036 * (c) the SYN and FIN bits are both off,
2037 * (d) the acknowledgment number is equal to the greatest acknowledgment
2038 * received on the given connection (TCP.UNA from [RFC793]),
2039 * (e) the advertised window in the incoming acknowledgment equals the
2040 * advertised window in the last incoming acknowledgment.
2041 *
2042 * With RFC 6675, this definition has been reduced:
2043 *
2044 * (a) the ACK is carrying a SACK block that identifies previously
2045 * unacknowledged and un-SACKed octets between HighACK (TCP.UNA) and
2046 * HighData (m_highTxMark)
2047 *
2048 * The check below implements conditions a), b), and d), and c) is prevented by virtue of not
2049 * reaching this code if SYN or FIN is set, and e) is not supported.
2050 */
2051
2052 if (m_fackEnabled && ackNumber == m_txBuffer->HeadSequence() &&
2053 m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
2054 {
2055 if (m_outstandingRetransBytes > m_tcb->m_segmentSize)
2056 {
2057 m_outstandingRetransBytes -= m_tcb->m_segmentSize;
2058 }
2059 else
2060 {
2062 }
2063 }
2064
2065 bool isDupack = m_sackEnabled ? scoreboardUpdated
2066 : (ackNumber == oldHeadSequence &&
2067 ackNumber < m_tcb->m_highTxMark && !receivedData);
2068
2069 NS_LOG_DEBUG("ACK of " << ackNumber << " SND.UNA=" << oldHeadSequence
2070 << " SND.NXT=" << m_tcb->m_nextTxSequence
2071 << " in state: " << TcpSocketState::TcpCongStateName[m_tcb->m_congState]
2072 << " with m_recover: " << m_recover);
2073
2074 // RFC 6675, Section 5, 3rd paragraph:
2075 // If the incoming ACK is a duplicate acknowledgment per the definition
2076 // in Section 2 (regardless of its status as a cumulative
2077 // acknowledgment), and the TCP is not currently in loss recovery
2078 if (isDupack)
2079 {
2080 // loss recovery check is done inside this function thanks to
2081 // the congestion state machine
2082 DupAck(currentDelivered);
2083 }
2084
2085 if (ackNumber == oldHeadSequence && ackNumber == m_tcb->m_highTxMark)
2086 {
2087 // Dupack, but the ACK is precisely equal to the nextTxSequence
2088 return;
2089 }
2090 else if (ackNumber == oldHeadSequence && ackNumber > m_tcb->m_highTxMark)
2091 {
2092 // ACK of the FIN bit ... nextTxSequence is not updated since we
2093 // don't have anything to transmit
2094 NS_LOG_DEBUG("Update nextTxSequence manually to " << ackNumber);
2095 m_tcb->m_nextTxSequence = ackNumber;
2096 }
2097 else if (ackNumber == oldHeadSequence)
2098 {
2099 // DupAck. Artificially call PktsAcked: after all, one segment has been ACKed.
2100 m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_srtt);
2101 }
2102 else if (ackNumber > oldHeadSequence)
2103 {
2104 // Please remember that, with SACK, we can enter here even if we
2105 // received a dupack.
2106 bytesAcked = currentDelivered;
2107 uint32_t segsAcked = bytesAcked / m_tcb->m_segmentSize;
2108 m_bytesAckedNotProcessed += bytesAcked % m_tcb->m_segmentSize;
2109 bytesAcked -= bytesAcked % m_tcb->m_segmentSize;
2110
2111 if (m_bytesAckedNotProcessed >= m_tcb->m_segmentSize)
2112 {
2113 segsAcked += 1;
2114 bytesAcked += m_tcb->m_segmentSize;
2115 m_bytesAckedNotProcessed -= m_tcb->m_segmentSize;
2116 }
2117 NS_LOG_DEBUG("Set segsAcked: " << segsAcked
2118 << " based on currentDelivered: " << currentDelivered);
2119
2120 // Dupack count is reset to eventually fast-retransmit after 3 dupacks.
2121 // Any SACK-ed segment will be cleaned up by DiscardUpTo.
2122 // In the case that we advanced SND.UNA, but the ack contains SACK blocks,
2123 // we do not reset. At the third one we will retransmit.
2124 // If we are already in recovery, this check is useless since dupAcks
2125 // are not considered in this phase. When from Recovery we go back
2126 // to open, then dupAckCount is reset anyway.
2127 if (!isDupack)
2128 {
2129 m_dupAckCount = 0;
2130 }
2131
2132 // RFC 6675, Section 5, part (B)
2133 // (B) Upon receipt of an ACK that does not cover RecoveryPoint, the
2134 // following actions MUST be taken:
2135 //
2136 // (B.1) Use Update () to record the new SACK information conveyed
2137 // by the incoming ACK.
2138 // (B.2) Use SetPipe () to re-calculate the number of octets still
2139 // in the network.
2140 //
2141 // (B.1) is done at the beginning, while (B.2) is delayed to part (C) while
2142 // trying to transmit with SendPendingData. We are not allowed to exit
2143 // the CA_RECOVERY phase. Just process this partial ack (RFC 5681)
2144 if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
2145 {
2146 if (!m_sackEnabled)
2147 {
2148 // Manually set the head as lost, it will be retransmitted.
2149 NS_LOG_INFO("Partial ACK. Manually setting head as lost");
2150 m_txBuffer->MarkHeadAsLost();
2151 }
2152
2153 // Before retransmitting the packet perform DoRecovery and check if
2154 // there is available window
2155 if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2156 {
2157 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, false);
2158 }
2159
2160 // If the packet is already retransmitted do not retransmit it
2161 if (!m_txBuffer->IsRetransmittedDataAcked(ackNumber + m_tcb->m_segmentSize))
2162 {
2163 DoRetransmit(); // Assume the next seq is lost. Retransmit lost packet
2164 m_tcb->m_cWndInfl = SafeSubtraction(m_tcb->m_cWndInfl, bytesAcked);
2165 }
2166
2167 // This partial ACK acknowledge the fact that one segment has been
2168 // previously lost and now successfully received. All others have
2169 // been processed when they come under the form of dupACKs
2170 m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_srtt);
2171 NewAck(ackNumber, m_isFirstPartialAck);
2172
2174 {
2175 NS_LOG_DEBUG("Partial ACK of " << ackNumber
2176 << " and this is the first (RTO will be reset);"
2177 " cwnd set to "
2178 << m_tcb->m_cWnd << " recover seq: " << m_recover
2179 << " dupAck count: " << m_dupAckCount);
2180 m_isFirstPartialAck = false;
2181 }
2182 else
2183 {
2184 NS_LOG_DEBUG("Partial ACK of "
2185 << ackNumber
2186 << " and this is NOT the first (RTO will not be reset)"
2187 " cwnd set to "
2188 << m_tcb->m_cWnd << " recover seq: " << m_recover
2189 << " dupAck count: " << m_dupAckCount);
2190 }
2191 }
2192 // From RFC 6675 section 5.1
2193 // In addition, a new recovery phase (as described in Section 5) MUST NOT
2194 // be initiated until HighACK is greater than or equal to the new value
2195 // of RecoveryPoint.
2196 else if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_LOSS)
2197 {
2198 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2199 m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2200
2201 NS_LOG_DEBUG(" Cong Control Called, cWnd=" << m_tcb->m_cWnd
2202 << " ssTh=" << m_tcb->m_ssThresh);
2203 if (!m_sackEnabled)
2204 {
2206 m_txBuffer->GetSacked() == 0,
2207 "Some segment got dup-acked in CA_LOSS state: " << m_txBuffer->GetSacked());
2208 }
2209 NewAck(ackNumber, true);
2210 }
2211 else if (m_tcb->m_congState == TcpSocketState::CA_CWR)
2212 {
2213 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2214 // TODO: need to check behavior if marking is compounded by loss
2215 // and/or packet reordering
2216 if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2217 {
2218 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, false);
2219 }
2220 NewAck(ackNumber, true);
2221 }
2222 else
2223 {
2224 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
2225 {
2226 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2227 }
2228 else if (m_tcb->m_congState == TcpSocketState::CA_DISORDER)
2229 {
2230 if (segsAcked >= oldDupAckCount)
2231 {
2232 m_congestionControl->PktsAcked(m_tcb,
2233 segsAcked - oldDupAckCount,
2234 m_tcb->m_srtt);
2235 }
2236
2237 if (!isDupack)
2238 {
2239 // The network reorder packets. Linux changes the counting lost
2240 // packet algorithm from FACK to NewReno. We simply go back in Open.
2242 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2243 NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2244 << " exiting CA_DISORDER -> CA_OPEN");
2245 }
2246 else
2247 {
2248 NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2249 << " but still in CA_DISORDER");
2250 }
2251 }
2252 // RFC 6675, Section 5:
2253 // Once a TCP is in the loss recovery phase, the following procedure
2254 // MUST be used for each arriving ACK:
2255 // (A) An incoming cumulative ACK for a sequence number greater than
2256 // RecoveryPoint signals the end of loss recovery, and the loss
2257 // recovery phase MUST be terminated. Any information contained in
2258 // the scoreboard for sequence numbers greater than the new value of
2259 // HighACK SHOULD NOT be cleared when leaving the loss recovery
2260 // phase.
2261 else if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
2262 {
2263 m_isFirstPartialAck = true;
2264
2265 // Recalculate the segs acked, that are from m_recover to ackNumber
2266 // (which are the ones we have not passed to PktsAcked and that
2267 // can increase cWnd)
2268 // TODO: check consistency for dynamic segment size
2269 segsAcked =
2270 static_cast<uint32_t>(ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
2271 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2274 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2275 exitedFastRecovery = true;
2276 m_dupAckCount = 0; // From recovery to open, reset dupack
2277
2278 NS_LOG_DEBUG(segsAcked << " segments acked in CA_RECOVER, ack of " << ackNumber
2279 << ", exiting CA_RECOVERY -> CA_OPEN");
2280 }
2281 else if (m_tcb->m_congState == TcpSocketState::CA_LOSS)
2282 {
2283 m_isFirstPartialAck = true;
2284
2285 // Recalculate the segs acked, that are from m_recover to ackNumber
2286 // (which are the ones we have not passed to PktsAcked and that
2287 // can increase cWnd)
2288 segsAcked = (ackNumber - m_recover) / m_tcb->m_segmentSize;
2289
2290 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2291
2293 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2294 NS_LOG_DEBUG(segsAcked << " segments acked in CA_LOSS, ack of" << ackNumber
2295 << ", exiting CA_LOSS -> CA_OPEN");
2296 }
2297
2298 if (ackNumber >= m_recover)
2299 {
2300 // All lost segments in the congestion event have been
2301 // retransmitted successfully. The recovery point (m_recover)
2302 // should be deactivated.
2303 m_recoverActive = false;
2304 }
2305
2306 if (exitedFastRecovery)
2307 {
2308 NewAck(ackNumber, true);
2309 m_tcb->m_cWnd = m_tcb->m_ssThresh.Get();
2310 m_recoveryOps->ExitRecovery(m_tcb);
2311 NS_LOG_DEBUG("Leaving Fast Recovery; BytesInFlight() = "
2312 << BytesInFlight() << "; cWnd = " << m_tcb->m_cWnd);
2313 }
2314 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
2315 {
2316 m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2317
2318 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
2319
2320 NS_LOG_LOGIC("Congestion control called: cWnd: " << m_tcb->m_cWnd
2321 << " ssTh: " << m_tcb->m_ssThresh
2322 << " segsAcked: " << segsAcked);
2323
2324 NewAck(ackNumber, true);
2325 }
2326 }
2327 }
2328 // Update the pacing rate, since m_congestionControl->IncreaseWindow() or
2329 // m_congestionControl->PktsAcked () may change m_tcb->m_cWnd
2330 // Make sure that control reaches the end of this function and there is no
2331 // return in between
2333}
2334
2335/* Received a packet upon LISTEN state. */
2336void
2338 const TcpHeader& tcpHeader,
2339 const Address& fromAddress,
2340 const Address& toAddress)
2341{
2342 NS_LOG_FUNCTION(this << tcpHeader);
2343
2344 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2345 uint8_t tcpflags =
2347
2348 // Fork a socket if received a SYN. Do nothing otherwise.
2349 // C.f.: the LISTEN part in tcp_v4_do_rcv() in tcp_ipv4.c in Linux kernel
2350 if (tcpflags != TcpHeader::SYN)
2351 {
2352 return;
2353 }
2354
2355 // Call socket's notify function to let the server app know we got a SYN
2356 // If the server app refuses the connection, do nothing
2357 if (!NotifyConnectionRequest(fromAddress))
2358 {
2359 return;
2360 }
2361 // Clone the socket, simulate fork
2362 Ptr<TcpSocketBase> newSock = Fork();
2363 NS_LOG_LOGIC("Cloned a TcpSocketBase " << newSock);
2365 newSock,
2366 packet,
2367 tcpHeader,
2368 fromAddress,
2369 toAddress);
2370}
2371
2372/* Received a packet upon SYN_SENT */
2373void
2375{
2376 NS_LOG_FUNCTION(this << tcpHeader);
2377
2378 // Extract the flags. PSH and URG are disregarded.
2379 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2380
2381 if (tcpflags == 0)
2382 { // Bare data, accept it and move to ESTABLISHED state. This is not a normal behaviour. Remove
2383 // this?
2384 NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2386 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2388 m_connected = true;
2389 m_retxEvent.Cancel();
2391 ReceivedData(packet, tcpHeader);
2393 }
2394 else if (tcpflags & TcpHeader::ACK && !(tcpflags & TcpHeader::SYN))
2395 { // Ignore ACK in SYN_SENT
2396 }
2397 else if (tcpflags & TcpHeader::SYN && !(tcpflags & TcpHeader::ACK))
2398 { // Received SYN, move to SYN_RCVD state and respond with SYN+ACK
2399 NS_LOG_DEBUG("SYN_SENT -> SYN_RCVD");
2400 m_state = SYN_RCVD;
2402 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2403 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2404 * the traffic is ECN capable and sender has sent ECN SYN packet
2405 */
2406
2407 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2409 {
2410 NS_LOG_INFO("Received ECN SYN packet");
2412 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2413 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2414 }
2415 else
2416 {
2417 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2419 }
2420 }
2421 else if (tcpflags & (TcpHeader::SYN | TcpHeader::ACK) &&
2422 m_tcb->m_nextTxSequence + SequenceNumber32(1) == tcpHeader.GetAckNumber())
2423 { // Handshake completed
2424 NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2426 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2428 m_connected = true;
2429 m_retxEvent.Cancel();
2430 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2431 m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
2432 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2433 // Before sending packets, update the pacing rate based on RTT measurement so far
2436
2437 /* Check if we received an ECN SYN-ACK packet. Change the ECN state of sender to ECN_IDLE if
2438 * receiver has sent an ECN SYN-ACK packet and the traffic is ECN Capable
2439 */
2440 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2441 (tcpflags & (TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::ECE))
2442 {
2443 NS_LOG_INFO("Received ECN SYN-ACK packet.");
2444 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2445 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2446 }
2447 else
2448 {
2449 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2450 }
2453 // Always respond to first data packet to speed up the connection.
2454 // Remove to get the behaviour of old NS-3 code.
2456 }
2457 else
2458 { // Other in-sequence input
2459 if (!(tcpflags & TcpHeader::RST))
2460 { // When (1) rx of FIN+ACK; (2) rx of FIN; (3) rx of bad flags
2461 NS_LOG_LOGIC("Illegal flag combination "
2462 << TcpHeader::FlagsToString(tcpHeader.GetFlags())
2463 << " received in SYN_SENT. Reset packet is sent.");
2464 SendRST();
2465 }
2467 }
2468}
2469
2470/* Received a packet upon SYN_RCVD */
2471void
2473 const TcpHeader& tcpHeader,
2474 const Address& fromAddress,
2475 const Address& /* toAddress */)
2476{
2477 NS_LOG_FUNCTION(this << tcpHeader);
2478
2479 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2480 uint8_t tcpflags =
2482
2483 if (tcpflags == 0 ||
2484 (tcpflags == TcpHeader::ACK &&
2485 m_tcb->m_nextTxSequence + SequenceNumber32(1) == tcpHeader.GetAckNumber()))
2486 { // If it is bare data, accept it and move to ESTABLISHED state. This is
2487 // possibly due to ACK lost in 3WHS. If in-sequence ACK is received, the
2488 // handshake is completed nicely.
2489 NS_LOG_DEBUG("SYN_RCVD -> ESTABLISHED");
2491 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2493 m_connected = true;
2494 m_retxEvent.Cancel();
2495 m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
2496 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2497 if (m_endPoint)
2498 {
2499 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2500 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2501 }
2502 else if (m_endPoint6)
2503 {
2504 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2505 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2506 }
2507 // Always respond to first data packet to speed up the connection.
2508 // Remove to get the behaviour of old NS-3 code.
2510 NotifyNewConnectionCreated(this, fromAddress);
2511 ReceivedAck(packet, tcpHeader);
2512 // Update the pacing rate based on RTT measurement so far
2514 // As this connection is established, the socket is available to send data now
2515 if (GetTxAvailable() > 0)
2516 {
2518 }
2519 }
2520 else if (tcpflags == TcpHeader::SYN)
2521 { // Probably the peer lost my SYN+ACK
2522 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2523 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2524 * sender has sent an ECN SYN packet and the traffic is ECN Capable
2525 */
2526 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2527 (tcpHeader.GetFlags() & (TcpHeader::CWR | TcpHeader::ECE)) ==
2529 {
2530 NS_LOG_INFO("Received ECN SYN packet");
2532 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2533 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2534 }
2535 else
2536 {
2537 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2539 }
2540 }
2541 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2542 {
2543 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2544 { // In-sequence FIN before connection complete. Set up connection and close.
2545 m_connected = true;
2546 m_retxEvent.Cancel();
2547 m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
2548 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2549 if (m_endPoint)
2550 {
2551 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2552 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2553 }
2554 else if (m_endPoint6)
2555 {
2556 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2557 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2558 }
2559 NotifyNewConnectionCreated(this, fromAddress);
2560 PeerClose(packet, tcpHeader);
2561 }
2562 }
2563 else
2564 { // Other in-sequence input
2565 if (tcpflags != TcpHeader::RST)
2566 { // When (1) rx of SYN+ACK; (2) rx of FIN; (3) rx of bad flags
2567 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2568 << " received. Reset packet is sent.");
2569 if (m_endPoint)
2570 {
2571 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2572 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2573 }
2574 else if (m_endPoint6)
2575 {
2576 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2577 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2578 }
2579 SendRST();
2580 }
2582 }
2583}
2584
2585/* Received a packet upon CLOSE_WAIT, FIN_WAIT_1, or FIN_WAIT_2 states */
2586void
2588{
2589 NS_LOG_FUNCTION(this << tcpHeader);
2590
2591 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2592 uint8_t tcpflags =
2594
2595 if (packet->GetSize() > 0 && !(tcpflags & TcpHeader::ACK))
2596 { // Bare data, accept it
2597 ReceivedData(packet, tcpHeader);
2598 }
2599 else if (tcpflags == TcpHeader::ACK)
2600 { // Process the ACK, and if in FIN_WAIT_1, conditionally move to FIN_WAIT_2
2601 ReceivedAck(packet, tcpHeader);
2602 if (m_state == FIN_WAIT_1 && m_txBuffer->Size() == 0 &&
2603 tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2604 { // This ACK corresponds to the FIN sent
2605 NS_LOG_DEBUG("FIN_WAIT_1 -> FIN_WAIT_2");
2607 }
2608 }
2609 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2610 { // Got FIN, respond with ACK and move to next state
2611 if (tcpflags & TcpHeader::ACK)
2612 { // Process the ACK first
2613 ReceivedAck(packet, tcpHeader);
2614 }
2615 m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber());
2616 }
2617 else if (tcpflags == TcpHeader::SYN || tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
2618 { // Duplicated SYN or SYN+ACK, possibly due to spurious retransmission
2619 return;
2620 }
2621 else
2622 { // This is a RST or bad flags
2623 if (tcpflags != TcpHeader::RST)
2624 {
2625 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2626 << " received. Reset packet is sent.");
2627 SendRST();
2628 }
2630 return;
2631 }
2632
2633 // Check if the close responder sent an in-sequence FIN, if so, respond ACK
2634 if ((m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2) && m_tcb->m_rxBuffer->Finished())
2635 {
2636 if (m_state == FIN_WAIT_1)
2637 {
2638 NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2639 m_state = CLOSING;
2640 if (m_txBuffer->Size() == 0 &&
2641 tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2642 { // This ACK corresponds to the FIN sent
2643 TimeWait();
2644 }
2645 }
2646 else if (m_state == FIN_WAIT_2)
2647 {
2648 TimeWait();
2649 }
2651 if (!m_shutdownRecv)
2652 {
2654 }
2655 }
2656}
2657
2658/* Received a packet upon CLOSING */
2659void
2661{
2662 NS_LOG_FUNCTION(this << tcpHeader);
2663
2664 // Extract the flags. PSH and URG are disregarded.
2665 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2666
2667 if (tcpflags == TcpHeader::ACK)
2668 {
2669 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2670 { // This ACK corresponds to the FIN sent
2671 TimeWait();
2672 }
2673 }
2674 else
2675 { // CLOSING state means simultaneous close, i.e. no one is sending data to
2676 // anyone. If anything other than ACK is received, respond with a reset.
2677 if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2678 { // FIN from the peer as well. We can close immediately.
2680 }
2681 else if (tcpflags != TcpHeader::RST)
2682 { // Receive of SYN or SYN+ACK or bad flags or pure data
2683 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2684 << " received. Reset packet is sent.");
2685 SendRST();
2686 }
2688 }
2689}
2690
2691/* Received a packet upon LAST_ACK */
2692void
2694{
2695 NS_LOG_FUNCTION(this << tcpHeader);
2696
2697 // Extract the flags. PSH and URG are disregarded.
2698 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2699
2700 if (tcpflags == 0)
2701 {
2702 ReceivedData(packet, tcpHeader);
2703 }
2704 else if (tcpflags == TcpHeader::ACK)
2705 {
2706 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2707 { // This ACK corresponds to the FIN sent. This socket closed peacefully.
2709 }
2710 }
2711 else if (tcpflags == TcpHeader::FIN)
2712 { // Received FIN again, the peer probably lost the FIN+ACK
2714 }
2715 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK) || tcpflags == TcpHeader::RST)
2716 {
2718 }
2719 else
2720 { // Received a SYN or SYN+ACK or bad flags
2721 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2722 << " received. Reset packet is sent.");
2723 SendRST();
2725 }
2726}
2727
2728/* Peer sent me a FIN. Remember its sequence in rx buffer. */
2729void
2731{
2732 NS_LOG_FUNCTION(this << tcpHeader);
2733
2734 // Ignore all out of range packets
2735 if (tcpHeader.GetSequenceNumber() < m_tcb->m_rxBuffer->NextRxSequence() ||
2736 tcpHeader.GetSequenceNumber() > m_tcb->m_rxBuffer->MaxRxSequence())
2737 {
2738 return;
2739 }
2740 // For any case, remember the FIN position in rx buffer first
2741 m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber() +
2742 SequenceNumber32(p->GetSize()));
2743 NS_LOG_LOGIC("Accepted FIN at seq "
2744 << tcpHeader.GetSequenceNumber() + SequenceNumber32(p->GetSize()));
2745 // If there is any piggybacked data, process it
2746 if (p->GetSize())
2747 {
2748 ReceivedData(p, tcpHeader);
2749 }
2750 // Return if FIN is out of sequence, otherwise move to CLOSE_WAIT state by DoPeerClose
2751 if (!m_tcb->m_rxBuffer->Finished())
2752 {
2753 return;
2754 }
2755
2756 // Simultaneous close: Application invoked Close() when we are processing this FIN packet
2757 if (m_state == FIN_WAIT_1)
2758 {
2759 NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2760 m_state = CLOSING;
2761 return;
2762 }
2763
2764 DoPeerClose(); // Change state, respond with ACK
2765}
2766
2767/* Received a in-sequence FIN. Close down this socket. */
2768void
2770{
2772 m_state == FIN_WAIT_2);
2773
2774 // Move the state to CLOSE_WAIT
2775 NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSE_WAIT");
2777
2778 if (!m_closeNotified)
2779 {
2780 // The normal behaviour for an application is that, when the peer sent a in-sequence
2781 // FIN, the app should prepare to close. The app has two choices at this point: either
2782 // respond with ShutdownSend() call to declare that it has nothing more to send and
2783 // the socket can be closed immediately; or remember the peer's close request, wait
2784 // until all its existing data are pushed into the TCP socket, then call Close()
2785 // explicitly.
2786 NS_LOG_LOGIC("TCP " << this << " calling NotifyNormalClose");
2788 m_closeNotified = true;
2789 }
2790 if (m_shutdownSend)
2791 { // The application declares that it would not sent any more, close this socket
2792 Close();
2793 }
2794 else
2795 { // Need to ack, the application will close later
2797 }
2798 if (m_state == LAST_ACK)
2799 {
2800 m_dataRetrCount = m_dataRetries; // prevent endless FINs
2801 NS_LOG_LOGIC("TcpSocketBase " << this << " scheduling LATO1");
2802 Time lastRto = m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4);
2804 }
2805}
2806
2807/* Kill this socket. This is a callback function configured to m_endpoint in
2808 SetupCallback(), invoked when the endpoint is destroyed. */
2809void
2811{
2812 NS_LOG_FUNCTION(this);
2813 m_endPoint = nullptr;
2814 if (m_tcp)
2815 {
2816 m_tcp->RemoveSocket(this);
2817 }
2818 NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2819 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2821}
2822
2823/* Kill this socket. This is a callback function configured to m_endpoint in
2824 SetupCallback(), invoked when the endpoint is destroyed. */
2825void
2827{
2828 NS_LOG_FUNCTION(this);
2829 m_endPoint6 = nullptr;
2830 if (m_tcp)
2831 {
2832 m_tcp->RemoveSocket(this);
2833 }
2834 NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2835 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2837}
2838
2839/* Send an empty packet with specified TCP flags */
2840void
2842{
2843 NS_LOG_FUNCTION(this << static_cast<uint32_t>(flags));
2844
2845 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
2846 {
2847 NS_LOG_WARN("Failed to send empty packet due to null endpoint");
2848 return;
2849 }
2850
2852 TcpHeader header;
2853 SequenceNumber32 s = m_tcb->m_nextTxSequence;
2854 TcpPacketType_t packetType = INVALID;
2855
2856 if (flags & TcpHeader::FIN)
2857 {
2858 packetType = TcpPacketType_t::FIN;
2859 flags |= TcpHeader::ACK;
2860 }
2861 else if (m_state == FIN_WAIT_1 || m_state == LAST_ACK || m_state == CLOSING)
2862 {
2863 ++s;
2864 }
2865
2866 if (flags & TcpHeader::SYN)
2867 {
2868 packetType = TcpPacketType_t::SYN;
2869 if (flags & TcpHeader::ACK)
2870 {
2871 packetType = TcpPacketType_t::SYN_ACK;
2872 }
2873 }
2874 else if (flags & TcpHeader::ACK)
2875 {
2876 packetType = TcpPacketType_t::PURE_ACK;
2877 }
2878
2879 if (flags & TcpHeader::RST)
2880 {
2881 packetType = TcpPacketType_t::RST;
2882 }
2883
2884 NS_ASSERT_MSG(packetType != TcpPacketType_t::INVALID, "Invalid TCP packet type");
2885 AddSocketTags(p, IsEct(packetType));
2886
2887 header.SetFlags(flags);
2888 header.SetSequenceNumber(s);
2889 header.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
2890 if (m_endPoint != nullptr)
2891 {
2892 header.SetSourcePort(m_endPoint->GetLocalPort());
2893 header.SetDestinationPort(m_endPoint->GetPeerPort());
2894 }
2895 else
2896 {
2897 header.SetSourcePort(m_endPoint6->GetLocalPort());
2898 header.SetDestinationPort(m_endPoint6->GetPeerPort());
2899 }
2900 AddOptions(header);
2901
2902 // RFC 6298, clause 2.4
2903 m_rto =
2904 Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4), m_minRto);
2905
2906 uint16_t windowSize = AdvertisedWindowSize();
2907 bool hasSyn = flags & TcpHeader::SYN;
2908 bool hasFin = flags & TcpHeader::FIN;
2909 bool isAck = flags == TcpHeader::ACK;
2910 if (hasSyn)
2911 {
2913 { // The window scaling option is set only on SYN packets
2914 AddOptionWScale(header);
2915 }
2916
2917 if (m_sackEnabled)
2918 {
2919 AddOptionSackPermitted(header);
2920 }
2921
2922 if (m_synCount == 0)
2923 { // No more connection retries, give up
2924 NS_LOG_LOGIC("Connection failed.");
2925 m_rtt->Reset(); // According to recommendation -> RFC 6298
2927 m_state = CLOSED;
2929 return;
2930 }
2931 else
2932 { // Exponential backoff of connection time out
2933 int backoffCount = 0x1 << (m_synRetries - m_synCount);
2934 m_rto = m_cnTimeout * backoffCount;
2935 m_synCount--;
2936 }
2937
2938 if (m_synRetries - 1 == m_synCount)
2939 {
2940 UpdateRttHistory(s, 0, false);
2941 }
2942 else
2943 { // This is SYN retransmission
2944 UpdateRttHistory(s, 0, true);
2945 }
2946
2947 windowSize = AdvertisedWindowSize(false);
2948 }
2949 header.SetWindowSize(windowSize);
2950
2951 if (flags & TcpHeader::ACK)
2952 { // If sending an ACK, cancel the delay ACK as well
2953 m_delAckEvent.Cancel();
2954 m_delAckCount = 0;
2955 if (m_highTxAck < header.GetAckNumber())
2956 {
2957 m_highTxAck = header.GetAckNumber();
2958 }
2959 if (m_sackEnabled && m_tcb->m_rxBuffer->GetSackListSize() > 0)
2960 {
2961 AddOptionSack(header);
2962 }
2963 NS_LOG_INFO("Sending a pure ACK, acking seq " << m_tcb->m_rxBuffer->NextRxSequence());
2964 }
2965
2966 m_txTrace(p, header, this);
2967
2968 if (m_endPoint != nullptr)
2969 {
2970 m_tcp->SendPacket(p,
2971 header,
2972 m_endPoint->GetLocalAddress(),
2973 m_endPoint->GetPeerAddress(),
2975 }
2976 else
2977 {
2978 m_tcp->SendPacket(p,
2979 header,
2980 m_endPoint6->GetLocalAddress(),
2981 m_endPoint6->GetPeerAddress(),
2983 }
2984
2985 if (m_retxEvent.IsExpired() && (hasSyn || hasFin) && !isAck)
2986 { // Retransmit SYN / SYN+ACK / FIN / FIN+ACK to guard against lost
2987 NS_LOG_LOGIC("Schedule retransmission timeout at time "
2988 << Simulator::Now().GetSeconds() << " to expire at time "
2989 << (Simulator::Now() + m_rto.Get()).GetSeconds());
2991 }
2992}
2993
2994/* This function closes the endpoint completely. Called upon RST_TX action. */
2995void
3003
3004/* Deallocate the end point and cancel all the timers */
3005void
3007{
3008 // note: it shouldn't be necessary to invalidate the callback and manually call
3009 // TcpL4Protocol::RemoveSocket. Alas, if one relies on the endpoint destruction
3010 // callback, there's a weird memory access to a free'd area. Harmless, but valgrind
3011 // considers it an error.
3012
3013 if (m_endPoint != nullptr)
3014 {
3016 m_endPoint->SetDestroyCallback(MakeNullCallback<void>());
3017 m_tcp->DeAllocate(m_endPoint);
3018 m_endPoint = nullptr;
3019 m_tcp->RemoveSocket(this);
3020 }
3021 else if (m_endPoint6 != nullptr)
3022 {
3024 m_endPoint6->SetDestroyCallback(MakeNullCallback<void>());
3025 m_tcp->DeAllocate(m_endPoint6);
3026 m_endPoint6 = nullptr;
3027 m_tcp->RemoveSocket(this);
3028 }
3029}
3030
3031/* Configure the endpoint to a local address. Called by Connect() if Bind() didn't specify one. */
3032int
3034{
3035 NS_LOG_FUNCTION(this);
3036 Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4>();
3037 NS_ASSERT(ipv4);
3038 if (!ipv4->GetRoutingProtocol())
3039 {
3040 NS_FATAL_ERROR("No Ipv4RoutingProtocol in the node");
3041 }
3042 // Create a dummy packet, then ask the routing function for the best output
3043 // interface's address
3044 Ipv4Header header;
3045 header.SetDestination(m_endPoint->GetPeerAddress());
3046 Socket::SocketErrno errno_;
3047 Ptr<Ipv4Route> route;
3049 route = ipv4->GetRoutingProtocol()->RouteOutput(Ptr<Packet>(), header, oif, errno_);
3050 if (!route)
3051 {
3052 NS_LOG_LOGIC("Route to " << m_endPoint->GetPeerAddress() << " does not exist");
3053 NS_LOG_ERROR(errno_);
3054 m_errno = errno_;
3055 return -1;
3056 }
3057 NS_LOG_LOGIC("Route exists");
3058 m_endPoint->SetLocalAddress(route->GetSource());
3059 return 0;
3060}
3061
3062int
3064{
3065 NS_LOG_FUNCTION(this);
3066 Ptr<Ipv6L3Protocol> ipv6 = m_node->GetObject<Ipv6L3Protocol>();
3067 NS_ASSERT(ipv6);
3068 if (!ipv6->GetRoutingProtocol())
3069 {
3070 NS_FATAL_ERROR("No Ipv6RoutingProtocol in the node");
3071 }
3072 // Create a dummy packet, then ask the routing function for the best output
3073 // interface's address
3074 Ipv6Header header;
3075 header.SetDestination(m_endPoint6->GetPeerAddress());
3076 Socket::SocketErrno errno_;
3077 Ptr<Ipv6Route> route;
3079 route = ipv6->GetRoutingProtocol()->RouteOutput(Ptr<Packet>(), header, oif, errno_);
3080 if (!route)
3081 {
3082 NS_LOG_LOGIC("Route to " << m_endPoint6->GetPeerAddress() << " does not exist");
3083 NS_LOG_ERROR(errno_);
3084 m_errno = errno_;
3085 return -1;
3086 }
3087 NS_LOG_LOGIC("Route exists");
3088 m_endPoint6->SetLocalAddress(route->GetSource());
3089 return 0;
3090}
3091
3092/* This function is called only if a SYN received in LISTEN state. After
3093 TcpSocketBase cloned, allocate a new end point to handle the incoming
3094 connection and send a SYN+ACK to complete the handshake. */
3095void
3097 const TcpHeader& h,
3098 const Address& fromAddress,
3099 const Address& toAddress)
3100{
3101 NS_LOG_FUNCTION(this << p << h << fromAddress << toAddress);
3102 // Get port and address from peer (connecting host)
3103 if (InetSocketAddress::IsMatchingType(toAddress))
3104 {
3105 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(),
3106 InetSocketAddress::ConvertFrom(toAddress).GetIpv4(),
3107 InetSocketAddress::ConvertFrom(toAddress).GetPort(),
3108 InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
3109 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
3110 m_endPoint6 = nullptr;
3111 }
3112 else if (Inet6SocketAddress::IsMatchingType(toAddress))
3113 {
3114 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(),
3115 Inet6SocketAddress::ConvertFrom(toAddress).GetIpv6(),
3116 Inet6SocketAddress::ConvertFrom(toAddress).GetPort(),
3117 Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
3118 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
3119 m_endPoint = nullptr;
3120 }
3121 m_tcp->AddSocket(this);
3122
3123 // Change the cloned socket from LISTEN state to SYN_RCVD
3124 NS_LOG_DEBUG("LISTEN -> SYN_RCVD");
3125 m_state = SYN_RCVD;
3128 SetupCallback();
3129 // Set the sequence number and send SYN+ACK
3130 m_tcb->m_rxBuffer->SetNextRxSequence(h.GetSequenceNumber() + SequenceNumber32(1));
3131
3132 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
3133 * sender has sent an ECN SYN packet and the traffic is ECN Capable
3134 */
3135 if (m_tcb->m_useEcn != TcpSocketState::Off &&
3137 {
3139 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
3140 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
3141 }
3142 else
3143 {
3145 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
3146 }
3147}
3148
3149void
3151{ // Wrapper to protected function NotifyConnectionSucceeded() so that it can
3152 // be called as a scheduled event
3154 // The if-block below was moved from ProcessSynSent() to here because we need
3155 // to invoke the NotifySend() only after NotifyConnectionSucceeded() to
3156 // reflect the behaviour in the real world.
3157 if (GetTxAvailable() > 0)
3158 {
3160 }
3161}
3162
3163void
3165{
3166 /*
3167 * Add tags for each socket option.
3168 * Note that currently the socket adds both IPv4 tag and IPv6 tag
3169 * if both options are set. Once the packet got to layer three, only
3170 * the corresponding tags will be read.
3171 */
3172 if (GetIpTos())
3173 {
3174 SocketIpTosTag ipTosTag;
3175 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !CheckNoEcn(GetIpTos()) && isEct)
3176 {
3177 ipTosTag.SetTos(MarkEcnCodePoint(GetIpTos(), m_tcb->m_ectCodePoint));
3178 }
3179 else
3180 {
3181 // Set the last received ipTos
3182 ipTosTag.SetTos(GetIpTos());
3183 }
3184 p->AddPacketTag(ipTosTag);
3185 }
3186 else
3187 {
3188 if ((m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && p->GetSize() > 0 && isEct) ||
3189 m_tcb->m_ecnMode == TcpSocketState::DctcpEcn)
3190 {
3191 SocketIpTosTag ipTosTag;
3192 ipTosTag.SetTos(MarkEcnCodePoint(GetIpTos(), m_tcb->m_ectCodePoint));
3193 p->AddPacketTag(ipTosTag);
3194 }
3195 }
3196
3197 if (IsManualIpv6Tclass())
3198 {
3199 SocketIpv6TclassTag ipTclassTag;
3200 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !CheckNoEcn(GetIpv6Tclass()) &&
3201 isEct)
3202 {
3203 ipTclassTag.SetTclass(MarkEcnCodePoint(GetIpv6Tclass(), m_tcb->m_ectCodePoint));
3204 }
3205 else
3206 {
3207 // Set the last received ipTos
3208 ipTclassTag.SetTclass(GetIpv6Tclass());
3209 }
3210 p->AddPacketTag(ipTclassTag);
3211 }
3212 else
3213 {
3214 if ((m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && p->GetSize() > 0 && isEct) ||
3215 m_tcb->m_ecnMode == TcpSocketState::DctcpEcn)
3216 {
3217 SocketIpv6TclassTag ipTclassTag;
3218 ipTclassTag.SetTclass(MarkEcnCodePoint(GetIpv6Tclass(), m_tcb->m_ectCodePoint));
3219 p->AddPacketTag(ipTclassTag);
3220 }
3221 }
3222
3223 if (IsManualIpTtl())
3224 {
3225 SocketIpTtlTag ipTtlTag;
3226 ipTtlTag.SetTtl(GetIpTtl());
3227 p->AddPacketTag(ipTtlTag);
3228 }
3229
3231 {
3232 SocketIpv6HopLimitTag ipHopLimitTag;
3233 ipHopLimitTag.SetHopLimit(GetIpv6HopLimit());
3234 p->AddPacketTag(ipHopLimitTag);
3235 }
3236
3237 uint8_t priority = GetPriority();
3238 if (priority)
3239 {
3240 SocketPriorityTag priorityTag;
3241 priorityTag.SetPriority(priority);
3242 p->ReplacePacketTag(priorityTag);
3243 }
3244}
3245
3246/* Extract at most maxSize bytes from the TxBuffer at sequence seq, add the
3247 TCP header, and send to TcpL4Protocol */
3250{
3251 NS_LOG_FUNCTION(this << seq << maxSize << withAck);
3252
3253 bool isStartOfTransmission = BytesInFlight() == 0U;
3254 TcpTxItem* outItem = m_txBuffer->CopyFromSequence(maxSize, seq);
3255
3256 m_rateOps->SkbSent(outItem, isStartOfTransmission);
3257
3258 bool isRetransmission = outItem->IsRetrans();
3259 Ptr<Packet> p = outItem->GetPacketCopy();
3260 uint32_t sz = p->GetSize(); // Size of packet
3261 uint8_t flags = withAck ? TcpHeader::ACK : 0;
3262 uint32_t remainingData = m_txBuffer->SizeFromSequence(seq + SequenceNumber32(sz));
3263
3264 // TCP sender should not send data out of the window advertised by the
3265 // peer when it is not retransmission.
3266 NS_ASSERT(isRetransmission ||
3267 ((m_highRxAckMark + SequenceNumber32(m_rWnd)) >= (seq + SequenceNumber32(maxSize))));
3268
3269 if (IsPacingEnabled())
3270 {
3271 NS_LOG_INFO("Pacing is enabled");
3272 if (m_pacingTimer.IsExpired())
3273 {
3274 NS_LOG_DEBUG("Current Pacing Rate " << m_tcb->m_pacingRate);
3275 NS_LOG_DEBUG("Timer is in expired state, activate it "
3276 << m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3277 m_pacingTimer.Schedule(m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3278 }
3279 else
3280 {
3281 NS_LOG_INFO("Timer is already in running state");
3282 }
3283 }
3284 else
3285 {
3286 NS_LOG_INFO("Pacing is disabled");
3287 }
3288
3289 if (withAck)
3290 {
3291 m_delAckEvent.Cancel();
3292 m_delAckCount = 0;
3293 }
3294
3295 if (m_tcb->m_ecnState == TcpSocketState::ECN_ECE_RCVD &&
3296 m_ecnEchoSeq.Get() > m_ecnCWRSeq.Get() && !isRetransmission)
3297 {
3298 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CWR_SENT");
3299 m_tcb->m_ecnState = TcpSocketState::ECN_CWR_SENT;
3300 m_ecnCWRSeq = seq;
3301 flags |= TcpHeader::CWR;
3302 NS_LOG_INFO("CWR flags set");
3303 }
3304
3305 bool isEct = IsEct(isRetransmission ? TcpPacketType_t::RE_XMT : TcpPacketType_t::DATA);
3306 AddSocketTags(p, isEct);
3307
3308 if (m_closeOnEmpty && (remainingData == 0))
3309 {
3310 flags |= TcpHeader::FIN;
3311 if (m_state == ESTABLISHED)
3312 { // On active close: I am the first one to send FIN
3313 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
3315 }
3316 else if (m_state == CLOSE_WAIT)
3317 { // On passive close: Peer sent me FIN already
3318 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
3319 m_state = LAST_ACK;
3320 }
3321 }
3322 TcpHeader header;
3323 header.SetFlags(flags);
3324 header.SetSequenceNumber(seq);
3325 header.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
3326 if (m_endPoint)
3327 {
3328 header.SetSourcePort(m_endPoint->GetLocalPort());
3329 header.SetDestinationPort(m_endPoint->GetPeerPort());
3330 }
3331 else
3332 {
3333 header.SetSourcePort(m_endPoint6->GetLocalPort());
3334 header.SetDestinationPort(m_endPoint6->GetPeerPort());
3335 }
3337 AddOptions(header);
3338
3339 if (m_retxEvent.IsExpired())
3340 {
3341 // Schedules retransmit timeout. m_rto should be already doubled.
3342
3343 NS_LOG_LOGIC(this << " SendDataPacket Schedule ReTxTimeout at time "
3344 << Simulator::Now().GetSeconds() << " to expire at time "
3345 << (Simulator::Now() + m_rto.Get()).GetSeconds());
3347 }
3348
3349 m_txTrace(p, header, this);
3350 if (isRetransmission)
3351 {
3352 if (m_endPoint)
3353 {
3355 header,
3356 m_endPoint->GetLocalAddress(),
3357 m_endPoint->GetPeerAddress(),
3358 this);
3359 }
3360 else
3361 {
3363 header,
3364 m_endPoint6->GetLocalAddress(),
3365 m_endPoint6->GetPeerAddress(),
3366 this);
3367 }
3368 }
3369
3370 if (m_endPoint)
3371 {
3372 m_tcp->SendPacket(p,
3373 header,
3374 m_endPoint->GetLocalAddress(),
3375 m_endPoint->GetPeerAddress(),
3377 NS_LOG_DEBUG("Send segment of size "
3378 << sz << " with remaining data " << remainingData << " via TcpL4Protocol to "
3379 << m_endPoint->GetPeerAddress() << ". Header " << header);
3380 }
3381 else
3382 {
3383 m_tcp->SendPacket(p,
3384 header,
3385 m_endPoint6->GetLocalAddress(),
3386 m_endPoint6->GetPeerAddress(),
3388 NS_LOG_DEBUG("Send segment of size "
3389 << sz << " with remaining data " << remainingData << " via TcpL4Protocol to "
3390 << m_endPoint6->GetPeerAddress() << ". Header " << header);
3391 }
3392
3393 // Signal to congestion control whether the cwnd is fully used
3394 // This is a simple version of Linux tcp_cwnd_validate() but following
3395 // the principle implemented in Linux that limits the updating of cwnd
3396 // (in the congestion controls) when flight size is >= cwnd
3397 // send will also be cwnd limited if less then one segment of cwnd is available
3398 m_tcb->m_isCwndLimited = (m_tcb->m_cWnd < BytesInFlight() + m_tcb->m_segmentSize);
3399
3400 UpdateRttHistory(seq, sz, isRetransmission);
3401
3402 // Update bytes sent during recovery phase
3403 if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY ||
3404 m_tcb->m_congState == TcpSocketState::CA_CWR)
3405 {
3406 m_recoveryOps->UpdateBytesSent(sz);
3407 }
3408
3409 // Notify the application of the data being sent unless this is a retransmit
3410 if (!isRetransmission)
3411 {
3413 this,
3414 (seq + sz - m_tcb->m_highTxMark.Get()));
3415 }
3416 // Update highTxMark
3417 m_tcb->m_highTxMark = std::max(seq + sz, m_tcb->m_highTxMark.Get());
3418 return sz;
3419}
3420
3421void
3422TcpSocketBase::UpdateRttHistory(const SequenceNumber32& seq, uint32_t sz, bool isRetransmission)
3423{
3424 NS_LOG_FUNCTION(this);
3425
3426 // update the history of sequence numbers used to calculate the RTT
3427 if (!isRetransmission)
3428 { // This is the next expected one, just log at end
3429 m_history.emplace_back(seq, sz, Simulator::Now());
3430 }
3431 else
3432 { // This is a retransmit, find in list and mark as re-tx
3433 for (auto i = m_history.begin(); i != m_history.end(); ++i)
3434 {
3435 if ((seq >= i->seq) && (seq < (i->seq + SequenceNumber32(i->count))))
3436 { // Found it
3437 i->retx = true;
3438 i->count = ((seq + SequenceNumber32(sz)) - i->seq); // And update count in hist
3439 break;
3440 }
3441 }
3442 }
3443}
3444
3445// Note that this function did not implement the PSH flag
3448{
3449 NS_LOG_FUNCTION(this << withAck);
3450 if (m_txBuffer->Size() == 0)
3451 {
3452 return 0; // Nothing to send
3453 }
3454 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
3455 {
3457 "TcpSocketBase::SendPendingData: No endpoint; m_shutdownSend=" << m_shutdownSend);
3458 return 0; // Is this the right way to handle this condition?
3459 }
3460
3461 uint32_t nPacketsSent = 0;
3462 uint32_t availableWindow = AvailableWindow();
3463
3464 // RFC 6675, Section (C)
3465 // If cwnd - pipe >= 1 SMSS, the sender SHOULD transmit one or more
3466 // segments as follows:
3467 // (NOTE: We check > 0, and do the checks for segmentSize in the following
3468 // else branch to control silly window syndrome and Nagle)
3469 while (availableWindow > 0)
3470 {
3471 if (IsPacingEnabled())
3472 {
3473 NS_LOG_INFO("Pacing is enabled");
3474 if (m_pacingTimer.IsRunning())
3475 {
3476 NS_LOG_INFO("Skipping Packet due to pacing" << m_pacingTimer.GetDelayLeft());
3477 break;
3478 }
3479 NS_LOG_INFO("Timer is not running");
3480 }
3481
3483 {
3484 NS_LOG_INFO("FIN_WAIT and OPEN state; no data to transmit");
3485 break;
3486 }
3487 // (C.1) The scoreboard MUST be queried via NextSeg () for the
3488 // sequence number range of the next segment to transmit (if
3489 // any), and the given segment sent. If NextSeg () returns
3490 // failure (no data to send), return without sending anything
3491 // (i.e., terminate steps C.1 -- C.5).
3492 SequenceNumber32 next;
3493 SequenceNumber32 nextHigh;
3494 bool enableRule3 = m_sackEnabled && m_tcb->m_congState == TcpSocketState::CA_RECOVERY;
3495 if (!m_txBuffer->NextSeg(&next, &nextHigh, enableRule3))
3496 {
3497 NS_LOG_INFO("no valid seq to transmit, or no data available");
3498 break;
3499 }
3500 else
3501 {
3502 // It's time to transmit, but before do silly window and Nagle's check
3503 uint32_t availableData = m_txBuffer->SizeFromSequence(next);
3504
3505 // If there's less app data than the full window, ask the app for more
3506 // data before trying to send
3507 if (availableData < availableWindow)
3508 {
3510 }
3511
3512 // Stop sending if we need to wait for a larger Tx window (prevent silly window
3513 // syndrome) but continue if we don't have data
3514 if (availableWindow < m_tcb->m_segmentSize && availableData > availableWindow)
3515 {
3516 NS_LOG_LOGIC("Preventing Silly Window Syndrome. Wait to send.");
3517 break; // No more
3518 }
3519 // Nagle's algorithm (RFC896): Hold off sending if there is unacked data
3520 // in the buffer and the amount of data to send is less than one segment
3521 if (!m_noDelay && UnAckDataCount() > 0 && availableData < m_tcb->m_segmentSize)
3522 {
3523 NS_LOG_DEBUG("Invoking Nagle's algorithm for seq "
3524 << next << ", SFS: " << m_txBuffer->SizeFromSequence(next)
3525 << ". Wait to send.");
3526 break;
3527 }
3528
3529 uint32_t s = std::min(availableWindow, m_tcb->m_segmentSize);
3530 // NextSeg () may have further constrained the segment size
3531 auto maxSizeToSend = static_cast<uint32_t>(nextHigh - next);
3532 s = std::min(s, maxSizeToSend);
3533
3534 // (C.2) If any of the data octets sent in (C.1) are below HighData,
3535 // HighRxt MUST be set to the highest sequence number of the
3536 // retransmitted segment unless NextSeg () rule (4) was
3537 // invoked for this retransmission.
3538 // (C.3) If any of the data octets sent in (C.1) are above HighData,
3539 // HighData must be updated to reflect the transmission of
3540 // previously unsent data.
3541 //
3542 // These steps are done in m_txBuffer with the tags.
3543 if (m_tcb->m_nextTxSequence != next)
3544 {
3545 m_tcb->m_nextTxSequence = next;
3546 }
3547 if (m_tcb->m_bytesInFlight.Get() == 0)
3548 {
3550 }
3551 uint32_t sz = SendDataPacket(m_tcb->m_nextTxSequence, s, withAck);
3552
3553 NS_LOG_LOGIC(" rxwin " << m_rWnd << " segsize " << m_tcb->m_segmentSize
3554 << " highestRxAck " << m_txBuffer->HeadSequence() << " pd->Size "
3555 << m_txBuffer->Size() << " pd->SFS "
3556 << m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence));
3557
3558 NS_LOG_DEBUG("cWnd: " << m_tcb->m_cWnd << " total unAck: " << UnAckDataCount()
3559 << " sent seq " << m_tcb->m_nextTxSequence << " size " << sz);
3560 m_tcb->m_nextTxSequence += sz;
3561 ++nPacketsSent;
3562 if (IsPacingEnabled())
3563 {
3564 NS_LOG_INFO("Pacing is enabled");
3565 if (m_pacingTimer.IsExpired())
3566 {
3567 NS_LOG_DEBUG("Current Pacing Rate " << m_tcb->m_pacingRate);
3568 NS_LOG_DEBUG("Timer is in expired state, activate it "
3569 << m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3570 m_pacingTimer.Schedule(m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3571 break;
3572 }
3573 }
3574 }
3575
3576 // (C.4) The estimate of the amount of data outstanding in the
3577 // network must be updated by incrementing pipe by the number
3578 // of octets transmitted in (C.1).
3579 //
3580 // Done in BytesInFlight, inside AvailableWindow.
3581 availableWindow = AvailableWindow();
3582
3583 // (C.5) If cwnd - pipe >= 1 SMSS, return to (C.1)
3584 // loop again!
3585 }
3586
3587 if (nPacketsSent > 0)
3588 {
3589 if (!m_sackEnabled)
3590 {
3591 if (!m_limitedTx)
3592 {
3593 // We can't transmit in CA_DISORDER without limitedTx active
3595 }
3596 }
3597
3598 NS_LOG_DEBUG("SendPendingData sent " << nPacketsSent << " segments");
3599 }
3600 else
3601 {
3602 NS_LOG_DEBUG("SendPendingData no segments sent");
3603 }
3604 return nPacketsSent;
3605}
3606
3609{
3610 return m_tcb->m_highTxMark - m_txBuffer->HeadSequence();
3611}
3612
3615{
3616 uint32_t bytesInFlight = m_txBuffer->BytesInFlight();
3617 // Ugly, but we are not modifying the state; m_bytesInFlight is used
3618 // only for tracing purpose.
3619 m_tcb->m_bytesInFlight = bytesInFlight;
3620
3621 NS_LOG_DEBUG("Returning calculated bytesInFlight: " << bytesInFlight);
3622 return bytesInFlight;
3623}
3624
3627{
3628 return std::min(m_rWnd.Get(), m_tcb->m_cWnd.Get());
3629}
3630
3633{
3634 uint32_t win = Window(); // Number of bytes allowed to be outstanding
3635
3636 if (m_sackEnabled && m_fackEnabled && win >= m_tcb->m_ssThresh)
3637 {
3638 // Update awnd (Data sender's estimate of the actual quantity of data outstanding in the
3639 // network)
3640 NS_LOG_DEBUG("FACK is enabled and win >= ssthresh (" << m_tcb->m_ssThresh << ")");
3641
3642 uint32_t sndNxt = (m_tcb->m_highTxMark.Get().GetValue());
3643 uint32_t retranData = m_txBuffer->GetRetransmitsCount();
3644 uint32_t awnd = sndNxt - m_sndFack + retranData;
3645 m_tcb->m_fackAwnd = awnd;
3646
3647 NS_LOG_DEBUG("SndNxt: " << sndNxt << ", SndFack: " << m_sndFack << ", AWND: " << awnd
3648 << ", RetranData :" << retranData);
3649
3650 uint32_t awndDiff = (win > awnd) ? (win - awnd) : 0;
3651 NS_LOG_DEBUG("AWND: " << awnd << ", win: " << win << ", AWND_DIFF: " << awndDiff);
3652 return awndDiff;
3653 }
3654
3655 uint32_t inflight = BytesInFlight();
3656
3657 if (inflight >= win)
3658 {
3659 return 0;
3660 }
3661
3662 return win - inflight;
3663}
3664
3665uint16_t
3667{
3668 NS_LOG_FUNCTION(this << scale);
3669 uint32_t w;
3670
3671 // We don't want to advertise 0 after a FIN is received. So, we just use
3672 // the previous value of the advWnd.
3673 if (m_tcb->m_rxBuffer->GotFin())
3674 {
3675 w = m_advWnd;
3676 }
3677 else
3678 {
3679 NS_ASSERT_MSG(m_tcb->m_rxBuffer->MaxRxSequence() - m_tcb->m_rxBuffer->NextRxSequence() >= 0,
3680 "Unexpected sequence number values");
3681 w = static_cast<uint32_t>(m_tcb->m_rxBuffer->MaxRxSequence() -
3682 m_tcb->m_rxBuffer->NextRxSequence());
3683 }
3684
3685 // Ugly, but we are not modifying the state, that variable
3686 // is used only for tracing purpose.
3687 if (w != m_advWnd)
3688 {
3689 const_cast<TcpSocketBase*>(this)->m_advWnd = w;
3690 }
3691 if (scale)
3692 {
3693 w >>= m_rcvWindShift;
3694 }
3695 if (w > m_maxWinSize)
3696 {
3697 w = m_maxWinSize;
3698 NS_LOG_WARN("Adv window size truncated to "
3699 << m_maxWinSize << "; possibly to avoid overflow of the 16-bit integer");
3700 }
3701 NS_LOG_LOGIC("Returning AdvertisedWindowSize of " << static_cast<uint16_t>(w));
3702 return static_cast<uint16_t>(w);
3703}
3704
3705// Receipt of new packet, put into Rx buffer
3706void
3708{
3709 NS_LOG_FUNCTION(this << tcpHeader);
3710 NS_LOG_DEBUG("Data segment, seq=" << tcpHeader.GetSequenceNumber()
3711 << " pkt size=" << p->GetSize());
3712
3713 // Put into Rx buffer
3714 SequenceNumber32 expectedSeq = m_tcb->m_rxBuffer->NextRxSequence();
3715 if (!m_tcb->m_rxBuffer->Add(p, tcpHeader))
3716 { // Insert failed: No data or RX buffer full
3717 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3719 {
3721 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
3723 }
3724 else
3725 {
3727 }
3728 return;
3729 }
3730 // Notify app to receive if necessary
3731 if (expectedSeq < m_tcb->m_rxBuffer->NextRxSequence())
3732 { // NextRxSeq advanced, we have something to send to the app
3733 if (!m_shutdownRecv)
3734 {
3736 }
3737 // Handle exceptions
3738 if (m_closeNotified)
3739 {
3740 NS_LOG_WARN("Why TCP " << this << " got data after close notification?");
3741 }
3742 // If we received FIN before and now completed all "holes" in rx buffer,
3743 // invoke peer close procedure
3744 if (m_tcb->m_rxBuffer->Finished() && (tcpHeader.GetFlags() & TcpHeader::FIN) == 0)
3745 {
3746 DoPeerClose();
3747 return;
3748 }
3749 }
3750 // Now send a new ACK packet acknowledging all received and delivered data
3751 if (m_tcb->m_rxBuffer->Size() > m_tcb->m_rxBuffer->Available() ||
3752 m_tcb->m_rxBuffer->NextRxSequence() > expectedSeq + p->GetSize())
3753 { // A gap exists in the buffer, or we filled a gap: Always ACK
3755 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3757 {
3759 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
3761 }
3762 else
3763 {
3765 }
3766 }
3767 else
3768 { // In-sequence packet: ACK if delayed ack count allows
3770 {
3771 m_delAckEvent.Cancel();
3772 m_delAckCount = 0;
3774 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3776 {
3777 NS_LOG_DEBUG("Congestion algo " << m_congestionControl->GetName());
3780 << " -> ECN_SENDING_ECE");
3782 }
3783 else
3784 {
3786 }
3787 }
3788 else if (!m_delAckEvent.IsExpired())
3789 {
3791 }
3792 else if (m_delAckEvent.IsExpired())
3793 {
3798 this << " scheduled delayed ACK at "
3800 }
3801 }
3802}
3803
3804Time
3805TcpSocketBase::CalculateRttSample(const TcpHeader& tcpHeader, const RttHistory& rttHistory)
3806{
3807 NS_LOG_FUNCTION(this);
3808 SequenceNumber32 ackSeq = tcpHeader.GetAckNumber();
3809 Time rtt;
3810
3811 if (ackSeq >= (rttHistory.seq + SequenceNumber32(rttHistory.count)))
3812 {
3813 // As per RFC 6298 (Section 3)
3814 // RTT samples MUST NOT be made using segments that were
3815 // retransmitted (and thus for which it is ambiguous whether the reply
3816 // was for the first instance of the packet or a later instance). The
3817 // only case when TCP can safely take RTT samples from retransmitted
3818 // segments is when the TCP timestamp option is employed, since
3819 // the timestamp option removes the ambiguity regarding which instance
3820 // of the data segment triggered the acknowledgment.
3821 if (m_timestampEnabled && tcpHeader.HasOption(TcpOption::TS))
3822 {
3825 rtt = TcpOptionTS::ElapsedTimeFromTsValue(ts->GetEcho());
3826 if (rtt.IsZero())
3827 {
3828 NS_LOG_LOGIC("TcpSocketBase::EstimateRtt - RTT calculated from TcpOption::TS "
3829 "is zero, approximating to 1us.");
3830 NS_LOG_DEBUG("RTT calculated from TcpOption::TS is zero, updating rtt to 1us.");
3831 rtt = MicroSeconds(1);
3832 }
3833 }
3834 else if (!rttHistory.retx)
3835 {
3836 // Elapsed time since the packet was transmitted
3837 rtt = Simulator::Now() - rttHistory.time;
3838 }
3839 }
3840 return rtt;
3841}
3842
3843void
3845{
3846 NS_LOG_FUNCTION(this);
3847 SequenceNumber32 ackSeq = tcpHeader.GetAckNumber();
3848 Time rtt;
3849
3850 // An ack has been received, calculate rtt and log this measurement
3851 // Note we use a linear search (O(n)) for this since for the common
3852 // case the ack'ed packet will be at the head of the list
3853 if (!m_history.empty())
3854 {
3855 RttHistory& earliestTransmittedPktHistory = m_history.front();
3856 rtt = CalculateRttSample(tcpHeader, earliestTransmittedPktHistory);
3857
3858 // Store ACKed packet that has the latest transmission time to update `lastRtt`
3859 RttHistory latestTransmittedPktHistory = earliestTransmittedPktHistory;
3860
3861 // Delete all ACK history with seq <= ack
3862 while (!m_history.empty())
3863 {
3864 RttHistory& rttHistory = m_history.front();
3865 if ((rttHistory.seq + SequenceNumber32(rttHistory.count)) > ackSeq)
3866 {
3867 break; // Done removing
3868 }
3869
3870 latestTransmittedPktHistory = rttHistory;
3871 m_history.pop_front(); // Remove
3872 }
3873
3874 // In case of multiple packets being ACKed in a single acknowledgement, `m_lastRtt` is
3875 // RTT of the last (S)ACKed packet calculated using the data packet with the latest
3876 // transmission time
3877 Time lastRtt = CalculateRttSample(tcpHeader, latestTransmittedPktHistory);
3878 if (!lastRtt.IsZero())
3879 {
3880 NS_LOG_DEBUG("Last RTT sample updated to: " << lastRtt);
3881 m_tcb->m_lastRtt = lastRtt;
3882 }
3883 }
3884
3885 if (!rtt.IsZero())
3886 {
3887 m_rtt->Measurement(rtt); // Log the measurement
3888 // RFC 6298, clause 2.4
3889 m_rto = Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4),
3890 m_minRto);
3891 m_tcb->m_srtt = m_rtt->GetEstimate();
3892 m_tcb->m_minRtt = std::min(m_tcb->m_srtt.Get(), m_tcb->m_minRtt);
3893 NS_LOG_INFO(this << m_tcb->m_srtt << m_tcb->m_minRtt);
3894 }
3895}
3896
3897// Called by the ReceivedAck() when new ACK received and by ProcessSynRcvd()
3898// when the three-way handshake completed. This cancels retransmission timer
3899// and advances Tx window
3900void
3901TcpSocketBase::NewAck(const SequenceNumber32& ack, bool resetRTO)
3902{
3903 NS_LOG_FUNCTION(this << ack);
3904
3905 // Reset the data retransmission count. We got a new ACK!
3907
3908 // Update m_sndFack if possible
3909 if (m_fackEnabled && ack.GetValue() > m_sndFack)
3910 {
3911 NS_LOG_INFO(" m_sndFack " << m_sndFack << " updated by normal ack to " << ack.GetValue());
3912 m_sndFack = ack.GetValue();
3913 }
3914
3915 if (m_state != SYN_RCVD && resetRTO)
3916 { // Set RTO unless the ACK is received in SYN_RCVD state
3918 this << " Cancelled ReTxTimeout event which was set to expire at "
3919 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
3920 m_retxEvent.Cancel();
3921 // On receiving a "New" ack we restart retransmission timer .. RFC 6298
3922 // RFC 6298, clause 2.4
3923 m_rto = Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4),
3924 m_minRto);
3925
3926 NS_LOG_LOGIC(this << " Schedule ReTxTimeout at time " << Simulator::Now().GetSeconds()
3927 << " to expire at time "
3928 << (Simulator::Now() + m_rto.Get()).GetSeconds());
3930 }
3931
3932 // Note the highest ACK and tell app to send more
3933 NS_LOG_LOGIC("TCP " << this << " NewAck " << ack << " numberAck "
3934 << (ack - m_txBuffer->HeadSequence())); // Number bytes ack'ed
3935
3936 if (GetTxAvailable() > 0)
3937 {
3939 }
3940 if (ack > m_tcb->m_nextTxSequence)
3941 {
3942 m_tcb->m_nextTxSequence = ack; // If advanced
3943 }
3944 if (m_txBuffer->Size() == 0 && m_state != FIN_WAIT_1 && m_state != CLOSING)
3945 { // No retransmit timer if no data to retransmit
3947 this << " Cancelled ReTxTimeout event which was set to expire at "
3948 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
3949 m_retxEvent.Cancel();
3950 }
3951}
3952
3953// Retransmit timeout
3954void
3956{
3957 NS_LOG_FUNCTION(this);
3958 NS_LOG_LOGIC(this << " ReTxTimeout Expired at time " << Simulator::Now().GetSeconds());
3959 // If erroneous timeout in closed/timed-wait state, just return
3960 if (m_state == CLOSED || m_state == TIME_WAIT)
3961 {
3962 return;
3963 }
3964
3965 if (m_state == SYN_SENT)
3966 {
3967 NS_ASSERT(m_synCount > 0);
3968 if (m_tcb->m_useEcn == TcpSocketState::On)
3969 {
3971 }
3972 else
3973 {
3975 }
3976 return;
3977 }
3978
3979 // Retransmit non-data packet: Only if in FIN_WAIT_1 or CLOSING state
3980 if (m_txBuffer->Size() == 0)
3981 {
3982 if (m_state == FIN_WAIT_1 || m_state == CLOSING)
3983 { // Must have lost FIN, re-send
3985 }
3986 return;
3987 }
3988
3989 NS_LOG_DEBUG("Checking if Connection is Established");
3990 // If all data are received (non-closing socket and nothing to send), just return
3991 if (m_state <= ESTABLISHED && m_txBuffer->HeadSequence() >= m_tcb->m_highTxMark &&
3992 m_txBuffer->Size() == 0)
3993 {
3994 NS_LOG_DEBUG("Already Sent full data" << m_txBuffer->HeadSequence() << " "
3995 << m_tcb->m_highTxMark);
3996 return;
3997 }
3998
3999 if (m_dataRetrCount == 0)
4000 {
4001 NS_LOG_INFO("No more data retries available. Dropping connection");
4004 return;
4005 }
4006 else
4007 {
4009 }
4010
4011 uint32_t inFlightBeforeRto = BytesInFlight();
4012 bool resetSack = !m_sackEnabled; // Reset SACK information if SACK is not enabled.
4013 // The information in the TcpTxBuffer is guessed, in this case.
4014
4015 // Reset dupAckCount
4016 m_dupAckCount = 0;
4017 if (!m_sackEnabled)
4018 {
4019 m_txBuffer->ResetRenoSack();
4020 }
4021
4022 // From RFC 6675, Section 5.1
4023 // [RFC2018] suggests that a TCP sender SHOULD expunge the SACK
4024 // information gathered from a receiver upon a retransmission timeout
4025 // (RTO) "since the timeout might indicate that the data receiver has
4026 // reneged." Additionally, a TCP sender MUST "ignore prior SACK
4027 // information in determining which data to retransmit."
4028 // It has been suggested that, as long as robust tests for
4029 // reneging are present, an implementation can retain and use SACK
4030 // information across a timeout event [Errata1610].
4031 // The head of the sent list will not be marked as sacked, therefore
4032 // will be retransmitted, if the receiver renegotiate the SACK blocks
4033 // that we received.
4034 m_txBuffer->SetSentListLost(resetSack);
4035
4036 // From RFC 6675, Section 5.1
4037 // If an RTO occurs during loss recovery as specified in this document,
4038 // RecoveryPoint MUST be set to HighData. Further, the new value of
4039 // RecoveryPoint MUST be preserved and the loss recovery algorithm
4040 // outlined in this document MUST be terminated.
4041 m_recover = m_tcb->m_highTxMark;
4042 m_recoverActive = true;
4043
4044 // RFC 6298, clause 2.5, double the timer
4045 Time doubledRto = m_rto + m_rto;
4046 m_rto = Min(doubledRto, Time::FromDouble(60, Time::S));
4047
4048 // Empty RTT history
4049 m_history.clear();
4050
4051 // Please don't reset highTxMark, it is used for retransmission detection
4052
4053 // When a TCP sender detects segment loss using the retransmission timer
4054 // and the given segment has not yet been resent by way of the
4055 // retransmission timer, decrease ssThresh
4056 if (m_tcb->m_congState != TcpSocketState::CA_LOSS || !m_txBuffer->IsHeadRetransmitted())
4057 {
4058 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, inFlightBeforeRto);
4059 }
4060
4061 // Cwnd set to 1 MSS
4064 m_tcb->m_congState = TcpSocketState::CA_LOSS;
4065 m_tcb->m_cWnd = m_tcb->m_segmentSize;
4066 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
4067
4068 m_pacingTimer.Cancel();
4069
4070 NS_LOG_DEBUG("RTO. Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to " << m_tcb->m_ssThresh
4071 << ", restart from seqnum " << m_txBuffer->HeadSequence()
4072 << " doubled rto to " << m_rto.Get().GetSeconds() << " s");
4073
4075 "There are some bytes in flight after an RTO: " << BytesInFlight());
4076
4078
4079 NS_ASSERT_MSG(BytesInFlight() <= m_tcb->m_segmentSize,
4080 "In flight (" << BytesInFlight() << ") there is more than one segment ("
4081 << m_tcb->m_segmentSize << ")");
4082}
4083
4084void
4100
4101void
4103{
4104 NS_LOG_FUNCTION(this);
4105
4106 m_lastAckEvent.Cancel();
4107 if (m_state == LAST_ACK)
4108 {
4109 if (m_dataRetrCount == 0)
4110 {
4111 NS_LOG_INFO("LAST-ACK: No more data retries available. Dropping connection");
4114 return;
4115 }
4118 NS_LOG_LOGIC("TcpSocketBase " << this << " rescheduling LATO1");
4119 Time lastRto = m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4);
4121 }
4122}
4123
4124// Send 1-byte data to probe for the window size at the receiver when
4125// the local knowledge tells that the receiver has zero window size
4126// C.f.: RFC793 p.42, RFC1112 sec.4.2.2.17
4127void
4129{
4130 NS_LOG_LOGIC("PersistTimeout expired at " << Simulator::Now().GetSeconds());
4132 std::min(Seconds(60), Time(2 * m_persistTimeout)); // max persist timeout = 60s
4133 Ptr<Packet> p = m_txBuffer->CopyFromSequence(1, m_tcb->m_nextTxSequence)->GetPacketCopy();
4134 m_txBuffer->ResetLastSegmentSent();
4135 TcpHeader tcpHeader;
4136 tcpHeader.SetSequenceNumber(m_tcb->m_nextTxSequence);
4137 tcpHeader.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
4139 if (m_endPoint != nullptr)
4140 {
4141 tcpHeader.SetSourcePort(m_endPoint->GetLocalPort());
4142 tcpHeader.SetDestinationPort(m_endPoint->GetPeerPort());
4143 }
4144 else
4145 {
4146 tcpHeader.SetSourcePort(m_endPoint6->GetLocalPort());
4147 tcpHeader.SetDestinationPort(m_endPoint6->GetPeerPort());
4148 }
4149 AddOptions(tcpHeader);
4150 // Send a packet tag for setting ECT bits in IP header
4151 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED)
4152 {
4154 }
4155 m_txTrace(p, tcpHeader, this);
4156
4157 if (m_endPoint != nullptr)
4158 {
4159 m_tcp->SendPacket(p,
4160 tcpHeader,
4161 m_endPoint->GetLocalAddress(),
4162 m_endPoint->GetPeerAddress(),
4164 }
4165 else
4166 {
4167 m_tcp->SendPacket(p,
4168 tcpHeader,
4169 m_endPoint6->GetLocalAddress(),
4170 m_endPoint6->GetPeerAddress(),
4172 }
4173
4174 NS_LOG_LOGIC("Schedule persist timeout at time "
4175 << Simulator::Now().GetSeconds() << " to expire at time "
4176 << (Simulator::Now() + m_persistTimeout).GetSeconds());
4178}
4179
4180void
4182{
4183 NS_LOG_FUNCTION(this);
4184 bool res;
4185 SequenceNumber32 seq;
4186 SequenceNumber32 seqHigh;
4187 uint32_t maxSizeToSend;
4188
4189 // Find the first segment marked as lost and not retransmitted. With Reno,
4190 // that should be the head
4191 res = m_txBuffer->NextSeg(&seq, &seqHigh, false);
4192 if (!res)
4193 {
4194 // We have already retransmitted the head. However, we still received
4195 // three dupacks, or the RTO expired, but no data to transmit.
4196 // Therefore, re-send again the head.
4197 seq = m_txBuffer->HeadSequence();
4198 maxSizeToSend = m_tcb->m_segmentSize;
4199 }
4200 else
4201 {
4202 // NextSeg() may constrain the segment size when res is true
4203 maxSizeToSend = static_cast<uint32_t>(seqHigh - seq);
4204 }
4205 NS_ASSERT(m_sackEnabled || seq == m_txBuffer->HeadSequence());
4206
4207 NS_LOG_INFO("Retransmitting " << seq);
4208 // Update the trace and retransmit the segment
4209 m_tcb->m_nextTxSequence = seq;
4210 uint32_t sz = SendDataPacket(m_tcb->m_nextTxSequence, maxSizeToSend, true);
4211
4212 NS_ASSERT(sz > 0);
4213}
4214
4215void
4217{
4218 m_retxEvent.Cancel();
4219 m_persistEvent.Cancel();
4220 m_delAckEvent.Cancel();
4221 m_lastAckEvent.Cancel();
4222 m_timewaitEvent.Cancel();
4223 m_sendPendingDataEvent.Cancel();
4224 m_pacingTimer.Cancel();
4225}
4226
4227/* Move TCP to Time_Wait state and schedule a transition to Closed state */
4228void
4230{
4231 NS_LOG_DEBUG(TcpStateName[m_state] << " -> TIME_WAIT");
4234 if (!m_closeNotified)
4235 {
4236 // Technically the connection is not fully closed, but we notify now
4237 // because an implementation (real socket) would behave as if closed.
4238 // Notify normal close when entering TIME_WAIT or leaving LAST_ACK.
4240 m_closeNotified = true;
4241 }
4242 // Move from TIME_WAIT to CLOSED after 2*MSL. Max segment lifetime is 2 min
4243 // according to RFC793, p.28
4245}
4246
4247/* Below are the attribute get/set functions */
4248
4249void
4251{
4252 NS_LOG_FUNCTION(this << size);
4253 m_txBuffer->SetMaxBufferSize(size);
4254}
4255
4258{
4259 return m_txBuffer->MaxBufferSize();
4260}
4261
4264{
4265 return m_sndFack;
4266}
4267
4268bool
4270{
4271 return m_fackEnabled;
4272}
4273
4274void
4276{
4277 NS_LOG_FUNCTION(this << size);
4278 uint32_t oldSize = GetRcvBufSize();
4279
4280 m_tcb->m_rxBuffer->SetMaxBufferSize(size);
4281
4282 /* The size has (manually) increased. Actively inform the other end to prevent
4283 * stale zero-window states.
4284 */
4285 if (oldSize < size && m_connected)
4286 {
4287 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
4289 {
4291 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
4293 }
4294 else
4295 {
4297 }
4298 }
4299}
4300
4303{
4304 return m_tcb->m_rxBuffer->MaxBufferSize();
4305}
4306
4307void
4309{
4310 NS_LOG_FUNCTION(this << size);
4311 m_tcb->m_segmentSize = size;
4312 m_txBuffer->SetSegmentSize(size);
4313
4314 NS_ABORT_MSG_UNLESS(m_state == CLOSED, "Cannot change segment size dynamically.");
4315}
4316
4319{
4320 return m_tcb->m_segmentSize;
4321}
4322
4323void
4329
4330Time
4332{
4333 return m_cnTimeout;
4334}
4335
4336void
4338{
4339 NS_LOG_FUNCTION(this << count);
4340 m_synRetries = count;
4341}
4342
4345{
4346 return m_synRetries;
4347}
4348
4349void
4351{
4352 NS_LOG_FUNCTION(this << retries);
4353 m_dataRetries = retries;
4354}
4355
4358{
4359 NS_LOG_FUNCTION(this);
4360 return m_dataRetries;
4361}
4362
4363void
4369
4370Time
4372{
4373 return m_delAckTimeout;
4374}
4375
4376void
4378{
4379 NS_LOG_FUNCTION(this << count);
4380 m_delAckMaxCount = count;
4381}
4382
4388
4389void
4391{
4392 NS_LOG_FUNCTION(this << noDelay);
4393 m_noDelay = noDelay;
4394}
4395
4396bool
4398{
4399 return m_noDelay;
4400}
4401
4402void
4408
4409Time
4414
4415bool
4417{
4418 // Broadcast is not implemented. Return true only if allowBroadcast==false
4419 return (!allowBroadcast);
4420}
4421
4422bool
4424{
4425 return false;
4426}
4427
4428void
4430{
4431 NS_LOG_FUNCTION(this << header);
4432
4434 {
4435 AddOptionTimestamp(header);
4436 }
4437}
4438
4439void
4441{
4442 NS_LOG_FUNCTION(this << option);
4443
4445
4446 // In naming, we do the contrary of RFC 1323. The received scaling factor
4447 // is Rcv.Wind.Scale (and not Snd.Wind.Scale)
4448 m_sndWindShift = ws->GetScale();
4449
4450 if (m_sndWindShift > 14)
4451 {
4452 NS_LOG_WARN("Possible error; m_sndWindShift exceeds 14: " << m_sndWindShift);
4453 m_sndWindShift = 14;
4454 }
4455
4456 NS_LOG_INFO(m_node->GetId() << " Received a scale factor of "
4457 << static_cast<int>(m_sndWindShift));
4458}
4459
4460uint8_t
4462{
4463 NS_LOG_FUNCTION(this);
4464 uint32_t maxSpace = m_tcb->m_rxBuffer->MaxBufferSize();
4465 uint8_t scale = 0;
4466
4467 while (maxSpace > m_maxWinSize)
4468 {
4469 maxSpace = maxSpace >> 1;
4470 ++scale;
4471 }
4472
4473 if (scale > 14)
4474 {
4475 NS_LOG_WARN("Possible error; scale exceeds 14: " << scale);
4476 scale = 14;
4477 }
4478
4479 NS_LOG_INFO("Node " << m_node->GetId() << " calculated wscale factor of "
4480 << static_cast<int>(scale) << " for buffer size "
4481 << m_tcb->m_rxBuffer->MaxBufferSize());
4482 return scale;
4483}
4484
4485void
4487{
4488 NS_LOG_FUNCTION(this << header);
4489 NS_ASSERT(header.GetFlags() & TcpHeader::SYN);
4490
4492
4493 // In naming, we do the contrary of RFC 1323. The sended scaling factor
4494 // is Snd.Wind.Scale (and not Rcv.Wind.Scale)
4495
4497 option->SetScale(m_rcvWindShift);
4498
4499 header.AppendOption(option);
4500
4501 NS_LOG_INFO(m_node->GetId() << " Send a scaling factor of "
4502 << static_cast<int>(m_rcvWindShift));
4503}
4504
4507{
4508 NS_LOG_FUNCTION(this << option);
4509
4511
4512 // Update m_sndFack with the highest sequence number acknowledged from the SACK blocks
4513 if (m_fackEnabled)
4514 {
4515 for (const auto& [leftEdge, rightEdge] : s->GetSackList())
4516 {
4517 if (rightEdge.GetValue() > m_sndFack)
4518 {
4519 NS_LOG_INFO(" m_sndFack updated from " << m_sndFack << " to "
4520 << rightEdge.GetValue());
4521 m_sndFack = rightEdge.GetValue();
4522 }
4523 }
4524 }
4525
4526 return m_txBuffer->Update(s->GetSackList(), MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
4527}
4528
4529void
4531{
4532 NS_LOG_FUNCTION(this << option);
4533
4535
4536 NS_ASSERT(m_sackEnabled == true);
4537 NS_LOG_INFO(m_node->GetId() << " Received a SACK_PERMITTED option " << s);
4538}
4539
4540void
4542{
4543 NS_LOG_FUNCTION(this << header);
4544 NS_ASSERT(header.GetFlags() & TcpHeader::SYN);
4545
4547 header.AppendOption(option);
4548 NS_LOG_INFO(m_node->GetId() << " Add option SACK-PERMITTED");
4549}
4550
4551void
4553{
4554 NS_LOG_FUNCTION(this << header);
4555
4556 // Calculate the number of SACK blocks allowed in this packet
4557 uint8_t optionLenAvail = header.GetMaxOptionLength() - header.GetOptionLength();
4558 uint8_t allowedSackBlocks = (optionLenAvail - 2) / 8;
4559
4560 TcpOptionSack::SackList sackList = m_tcb->m_rxBuffer->GetSackList();
4561 if (allowedSackBlocks == 0 || sackList.empty())
4562 {
4563 NS_LOG_LOGIC("No space available or sack list empty, not adding sack blocks");
4564 return;
4565 }
4566
4567 // Append the allowed number of SACK blocks
4569
4570 for (auto i = sackList.begin(); allowedSackBlocks > 0 && i != sackList.end(); ++i)
4571 {
4572 option->AddSackBlock(*i);
4573 allowedSackBlocks--;
4574 }
4575
4576 header.AppendOption(option);
4577 NS_LOG_INFO(m_node->GetId() << " Add option SACK " << *option);
4578}
4579
4580void
4582 const SequenceNumber32& seq)
4583{
4584 NS_LOG_FUNCTION(this << option);
4585
4587
4588 // This is valid only when no overflow occurs. It happens
4589 // when a connection last longer than 50 days.
4590 if (m_tcb->m_rcvTimestampValue > ts->GetTimestamp())
4591 {
4592 // Do not save a smaller timestamp (probably there is reordering)
4593 return;
4594 }
4595
4596 m_tcb->m_rcvTimestampValue = ts->GetTimestamp();
4597 m_tcb->m_rcvTimestampEchoReply = ts->GetEcho();
4598
4599 if (seq == m_tcb->m_rxBuffer->NextRxSequence() && seq <= m_highTxAck)
4600 {
4601 m_timestampToEcho = ts->GetTimestamp();
4602 }
4603
4604 NS_LOG_INFO(m_node->GetId() << " Got timestamp=" << m_timestampToEcho
4605 << " and Echo=" << ts->GetEcho());
4606}
4607
4608void
4610{
4611 NS_LOG_FUNCTION(this << header);
4612
4614
4615 option->SetTimestamp(TcpOptionTS::NowToTsValue());
4616 option->SetEcho(m_timestampToEcho);
4617
4618 header.AppendOption(option);
4619 NS_LOG_INFO(m_node->GetId() << " Add option TS, ts=" << option->GetTimestamp()
4620 << " echo=" << m_timestampToEcho);
4621}
4622
4623void
4625{
4626 NS_LOG_FUNCTION(this << header);
4627 // If the connection is not established, the window size is always
4628 // updated
4629 uint32_t receivedWindow = header.GetWindowSize();
4630 receivedWindow <<= m_sndWindShift;
4631 NS_LOG_INFO("Received (scaled) window is " << receivedWindow << " bytes");
4632 if (m_state < ESTABLISHED)
4633 {
4634 m_rWnd = receivedWindow;
4635 NS_LOG_LOGIC("State less than ESTABLISHED; updating rWnd to " << m_rWnd);
4636 return;
4637 }
4638
4639 // Test for conditions that allow updating of the window
4640 // 1) segment contains new data (advancing the right edge of the receive
4641 // buffer),
4642 // 2) segment does not contain new data but the segment acks new data
4643 // (highest sequence number acked advances), or
4644 // 3) the advertised window is larger than the current send window
4645 bool update = false;
4646 if (header.GetAckNumber() == m_highRxAckMark && receivedWindow > m_rWnd)
4647 {
4648 // right edge of the send window is increased (window update)
4649 update = true;
4650 }
4651 if (header.GetAckNumber() > m_highRxAckMark)
4652 {
4653 m_highRxAckMark = header.GetAckNumber();
4654 update = true;
4655 }
4656 if (header.GetSequenceNumber() > m_highRxMark)
4657 {
4659 update = true;
4660 }
4661 if (update)
4662 {
4663 m_rWnd = receivedWindow;
4664 NS_LOG_LOGIC("updating rWnd to " << m_rWnd);
4665 }
4666}
4667
4668void
4670{
4671 NS_LOG_FUNCTION(this << minRto);
4672 m_minRto = minRto;
4673}
4674
4675Time
4677{
4678 return m_minRto;
4679}
4680
4681void
4683{
4684 NS_LOG_FUNCTION(this << clockGranularity);
4685 m_clockGranularity = clockGranularity;
4686}
4687
4688Time
4693
4696{
4697 return m_txBuffer;
4698}
4699
4702{
4703 return m_tcb->m_rxBuffer;
4704}
4705
4706void
4708{
4709 m_retxThresh = retxThresh;
4710 m_txBuffer->SetDupAckThresh(retxThresh);
4711}
4712
4713void
4715{
4716 m_pacingRateTrace(oldValue, newValue);
4717}
4718
4719void
4721{
4722 m_cWndTrace(oldValue, newValue);
4723}
4724
4725void
4727{
4728 m_cWndInflTrace(oldValue, newValue);
4729}
4730
4731void
4733{
4734 m_ssThTrace(oldValue, newValue);
4735}
4736
4737void
4743
4744void
4746 TcpSocketState::EcnState_t newValue) const
4747{
4748 m_ecnStateTrace(oldValue, newValue);
4749}
4750
4751void
4753
4754{
4755 m_nextTxSequenceTrace(oldValue, newValue);
4756}
4757
4758void
4760{
4761 m_highTxMarkTrace(oldValue, newValue);
4762}
4763
4764void
4766{
4767 m_bytesInFlightTrace(oldValue, newValue);
4768}
4769
4770void
4772{
4773 m_fackAwndTrace(oldValue, newValue);
4774}
4775
4776void
4777TcpSocketBase::UpdateRtt(Time oldValue, Time newValue) const
4778{
4779 m_srttTrace(oldValue, newValue);
4780}
4781
4782void
4783TcpSocketBase::UpdateLastRtt(Time oldValue, Time newValue) const
4784{
4785 m_lastRttTrace(oldValue, newValue);
4786}
4787
4788void
4796
4797void
4799{
4800 NS_LOG_FUNCTION(this << recovery);
4801 m_recoveryOps = recovery;
4802}
4803
4806{
4807 return CopyObject<TcpSocketBase>(this);
4808}
4809
4812{
4813 if (a > b)
4814 {
4815 return a - b;
4816 }
4817
4818 return 0;
4819}
4820
4821void
4823{
4824 NS_LOG_FUNCTION(this);
4825 NS_LOG_INFO("Performing Pacing");
4827}
4828
4829bool
4831{
4832 if (!m_tcb->m_pacing)
4833 {
4834 return false;
4835 }
4836 else
4837 {
4838 if (m_tcb->m_paceInitialWindow)
4839 {
4840 return true;
4841 }
4842 SequenceNumber32 highTxMark = m_tcb->m_highTxMark; // cast traced value
4843 if (highTxMark.GetValue() > (GetInitialCwnd() * m_tcb->m_segmentSize))
4844 {
4845 return true;
4846 }
4847 }
4848 return false;
4849}
4850
4851void
4853{
4854 NS_LOG_FUNCTION(this << m_tcb);
4855
4856 // According to Linux, set base pacing rate to (cwnd * mss) / srtt
4857 //
4858 // In (early) slow start, multiply base by the slow start factor.
4859 // In late slow start and congestion avoidance, multiply base by
4860 // the congestion avoidance factor.
4861 // Comment from Linux code regarding early/late slow start:
4862 // Normal Slow Start condition is (tp->snd_cwnd < tp->snd_ssthresh)
4863 // If snd_cwnd >= (tp->snd_ssthresh / 2), we are approaching
4864 // end of slow start and should slow down.
4865
4866 // Similar to Linux, do not update pacing rate here if the
4867 // congestion control implements TcpCongestionOps::CongControl ()
4868 if (m_congestionControl->HasCongControl() || !m_tcb->m_pacing)
4869 {
4870 return;
4871 }
4872
4873 double factor;
4874 if (m_tcb->m_cWnd < m_tcb->m_ssThresh / 2)
4875 {
4876 NS_LOG_DEBUG("Pacing according to slow start factor; " << m_tcb->m_cWnd << " "
4877 << m_tcb->m_ssThresh);
4878 factor = static_cast<double>(m_tcb->m_pacingSsRatio) / 100;
4879 }
4880 else
4881 {
4882 NS_LOG_DEBUG("Pacing according to congestion avoidance factor; " << m_tcb->m_cWnd << " "
4883 << m_tcb->m_ssThresh);
4884 factor = static_cast<double>(m_tcb->m_pacingCaRatio) / 100;
4885 }
4886 Time srtt = m_tcb->m_srtt.Get(); // Get underlying Time value
4887 NS_LOG_DEBUG("Smoothed RTT is " << srtt.GetSeconds());
4888
4889 // Multiply by 8 to convert from bytes per second to bits per second
4890 DataRate pacingRate((std::max(m_tcb->m_cWnd, m_tcb->m_bytesInFlight) * 8 * factor) /
4891 srtt.GetSeconds());
4892 if (pacingRate < m_tcb->m_maxPacingRate)
4893 {
4894 NS_LOG_DEBUG("Pacing rate updated to: " << pacingRate);
4895 m_tcb->m_pacingRate = pacingRate;
4896 }
4897 else
4898 {
4899 NS_LOG_DEBUG("Pacing capped by max pacing rate: " << m_tcb->m_maxPacingRate);
4900 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
4901 }
4902}
4903
4904void
4906{
4907 NS_LOG_FUNCTION(this << pacing);
4908 m_tcb->m_pacing = pacing;
4909}
4910
4911void
4913{
4914 NS_LOG_FUNCTION(this << paceWindow);
4915 m_tcb->m_paceInitialWindow = paceWindow;
4916}
4917
4918bool
4920{
4921 NS_LOG_FUNCTION(this << packetType);
4922 NS_ASSERT_MSG(packetType != TcpPacketType_t::INVALID, "Invalid TCP packet type");
4923 if (m_tcb->m_ecnState == TcpSocketState::ECN_DISABLED)
4924 {
4925 return false;
4926 }
4927
4928 NS_ABORT_MSG_IF(!ECN_RESTRICTION_MAP.contains(std::make_pair(packetType, m_tcb->m_ecnMode)),
4929 "Invalid packetType and ecnMode");
4930
4931 return ECN_RESTRICTION_MAP.at(std::make_pair(packetType, m_tcb->m_ecnMode));
4932}
4933
4934void
4936{
4937 NS_LOG_FUNCTION(this << useEcn);
4938 m_tcb->m_useEcn = useEcn;
4939}
4940
4941void
4943{
4944 NS_LOG_FUNCTION(this << useAbe);
4945 if (m_tcb->m_useEcn == TcpSocketState::Off && useAbe)
4946 {
4947 NS_LOG_INFO("Enabling ECN along with ABE");
4948 m_tcb->m_useEcn = TcpSocketState::On;
4949 }
4950 m_tcb->m_abeEnabled = useAbe;
4951}
4952
4953bool
4955{
4956 return m_tcb->m_abeEnabled;
4957}
4958
4961{
4962 return m_rWnd.Get();
4963}
4964
4967{
4968 return m_highRxAckMark.Get();
4969}
4970
4971// RttHistory methods
4973 : seq(s),
4974 count(c),
4975 time(t),
4976 retx(false)
4977{
4978}
4979
4981 : seq(h.seq),
4982 count(h.count),
4983 time(h.time),
4984 retx(h.retx)
4985{
4986}
4987
4988} // namespace ns3
#define Max(a, b)
#define Min(a, b)
a polymophic address class
Definition address.h:114
AttributeValue implementation for Boolean.
Definition boolean.h:26
Callback template class.
Definition callback.h:428
AttributeValue implementation for Callback.
Definition callback.h:794
Class for representing data rates.
Definition data-rate.h:78
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
Hold variables of type enum.
Definition enum.h:52
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.
static Ipv4Address GetZero()
static Ipv4Address GetAny()
Packet header for IPv4.
Definition ipv4-header.h:23
void SetDestination(Ipv4Address destination)
Ipv4Address GetSource() const
EcnType GetEcn() const
Ipv4Address GetDestination() const
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition ipv4.h:69
Describes an IPv6 address.
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.
Packet header for IPv6.
Definition ipv6-header.h:24
void SetDestination(Ipv6Address dst)
Set the "Destination address" field.
Ipv6Address GetDestination() const
Get the "Destination address" field.
EcnType GetEcn() const
Ipv6Address GetSource() const
Get the "Source address" field.
IPv6 layer implementation.
AttributeValue implementation for Pointer.
Definition pointer.h:37
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
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:580
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:614
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:200
Ptr< NetDevice > GetBoundNetDevice()
Returns socket's bound NetDevice, if any.
Definition socket.cc:336
Ptr< Packet > Recv()
Read a single packet from the socket.
Definition socket.cc:163
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:76
bool IsManualIpTtl() const
Checks if the socket has a specific IPv4 TTL set.
Definition socket.cc:363
void NotifySend(uint32_t spaceAvailable)
Notify through the callback (if set) that some data have been sent.
Definition socket.cc:281
void NotifyNewConnectionCreated(Ptr< Socket > socket, const Address &from)
Notify through the callback (if set) that a new connection has been created.
Definition socket.cc:261
virtual uint8_t GetIpTtl() const
Query the value of IP Time to Live field of this socket.
Definition socket.cc:506
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:243
uint8_t GetIpTos() const
Query the value of IP Type of Service of this socket.
Definition socket.cc:439
SocketType
Enumeration of the possible socket types.
Definition socket.h:96
@ NS3_SOCK_STREAM
Definition socket.h:97
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:103
void SetSendCallback(Callback< void, Ptr< Socket >, uint32_t > sendCb)
Notify application when space in transmit buffer is added.
Definition socket.cc:110
void NotifyErrorClose()
Notify through the callback (if set) that the connection has been closed due to an error.
Definition socket.cc:233
void NotifyDataRecv()
Notify through the callback (if set) that some data have been received.
Definition socket.cc:291
Ptr< NetDevice > m_boundnetdevice
the device this socket is bound to (might be null).
Definition socket.h:1071
virtual void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
Definition socket.cc:316
void NotifyNormalClose()
Notify through the callback (if set) that the connection has been closed.
Definition socket.cc:223
virtual uint8_t GetIpv6HopLimit() const
Query the value of IP Hop Limit field of this socket.
Definition socket.cc:531
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition socket.cc:117
SocketErrno
Enumeration of the possible errors returned by a socket.
Definition socket.h:73
@ ERROR_SHUTDOWN
Definition socket.h:79
@ ERROR_INVAL
Definition socket.h:82
@ ERROR_ADDRINUSE
Definition socket.h:87
@ ERROR_ADDRNOTAVAIL
Definition socket.h:86
@ ERROR_NOTCONN
Definition socket.h:76
@ ERROR_MSGSIZE
Definition socket.h:77
void NotifyDataSent(uint32_t size)
Notify through the callback (if set) that some data have been sent.
Definition socket.cc:271
void NotifyConnectionSucceeded()
Notify through the callback (if set) that the connection has been established.
Definition socket.cc:203
uint8_t GetPriority() const
Query the priority value of this socket.
Definition socket.cc:382
uint8_t GetIpv6Tclass() const
Query the value of IPv6 Traffic Class field of this socket.
Definition socket.cc:481
bool IsManualIpv6HopLimit() const
Checks if the socket has a specific IPv6 Hop Limit set.
Definition socket.cc:369
bool IsManualIpv6Tclass() const
Checks if the socket has a specific IPv6 Tclass set.
Definition socket.cc:357
void NotifyConnectionFailed()
Notify through the callback (if set) that the connection has not been established due to an error.
Definition socket.cc:213
indicates whether the socket has IP_TOS set.
Definition socket.h:1261
void SetTos(uint8_t tos)
Set the tag's TOS.
Definition socket.cc:787
This class implements a tag that carries the socket-specific TTL of a packet to the IP layer.
Definition socket.h:1114
void SetTtl(uint8_t ttl)
Set the tag's TTL.
Definition socket.cc:593
This class implements a tag that carries the socket-specific HOPLIMIT of a packet to the IPv6 layer.
Definition socket.h:1162
void SetHopLimit(uint8_t hopLimit)
Set the tag's Hop Limit.
Definition socket.cc:657
indicates whether the socket has IPV6_TCLASS set.
Definition socket.h:1356
void SetTclass(uint8_t tclass)
Set the tag's Tclass.
Definition socket.cc:899
indicates whether the socket has a priority set.
Definition socket.h:1308
void SetPriority(uint8_t priority)
Set the tag's priority.
Definition socket.cc:843
Header for the Transmission Control Protocol.
Definition tcp-header.h:36
void SetDestinationPort(uint16_t port)
Set the destination port.
Definition tcp-header.cc:59
void SetSequenceNumber(SequenceNumber32 sequenceNumber)
Set the sequence Number.
Definition tcp-header.cc:65
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
uint8_t GetMaxOptionLength() const
Get maximum option length.
uint16_t GetDestinationPort() const
Get the destination port.
Ptr< const TcpOption > GetOption(uint8_t kind) const
Get the option specified.
void SetFlags(uint8_t flags)
Set flags of the header.
Definition tcp-header.cc:77
void SetWindowSize(uint16_t windowSize)
Set the window size.
Definition tcp-header.cc:83
const TcpOptionList & GetOptionList() const
Get the list of option in this header.
uint16_t GetWindowSize() const
Get the window size.
uint8_t GetOptionLength() const
Get the total length of appended options.
bool AppendOption(Ptr< const TcpOption > option)
Append an option to the TCP header.
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:28
bool HasOption(uint8_t kind) const
Check if the header has the option specified.
uint16_t GetSourcePort() const
Get the source port.
Definition tcp-header.cc:95
void SetSourcePort(uint16_t port)
Set the source port.
Definition tcp-header.cc:53
void SetAckNumber(SequenceNumber32 ackNumber)
Set the ACK number.
Definition tcp-header.cc:71
uint8_t GetFlags() const
Get the flags.
SequenceNumber32 GetAckNumber() const
Get the ACK number.
@ SACKPERMITTED
SACKPERMITTED.
Definition tcp-option.h:49
@ WINSCALE
WINSCALE.
Definition tcp-option.h:48
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 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.
void AddSocketTags(const Ptr< Packet > &p, bool isEct) const
Add Tags for the Socket.
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.
bool GetFackEnabled() const
Check whether Forward Acknowledgment (FACK) is enabled.
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.
uint32_t m_sndFack
Sequence number of the forward most acknowledgement.
void SetDelAckTimeout(Time timeout) override
Set the time to delay an ACK.
uint32_t m_outstandingRetransBytes
Number of outstanding retransmitted bytes.
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 Last 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.
TracedCallback< uint32_t, uint32_t > m_fackAwndTrace
Callback pointer for fackAwnd trace chaining.
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.
virtual void ProcessAck(const SequenceNumber32 &ackNumber, bool scoreboardUpdated, uint32_t currentDelivered, const SequenceNumber32 &oldHeadSequence, bool receivedData)
Process a received ack.
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
uint32_t GetSndFack() const
Get the current FACK sequence number.
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.
void UpdateLastRtt(Time oldValue, Time newValue) const
Callback function to hook to TcpSocketState lastRtt.
TracedCallback< Ptr< const Packet >, const TcpHeader &, const Address &, const Address &, Ptr< const TcpSocketBase > > m_retransmissionTrace
Trace of retransmitted packets.
uint32_t m_delAckCount
Delayed ACK counter.
Ipv4EndPoint * m_endPoint
the IPv4 endpoint
TcpPacketType_t
Tcp Packet Types.
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).
bool IsEct(TcpPacketType_t packetType) const
Checks if a TCP packet should be ECN-capable (ECT) according to the TcpPacketType and ECN mode.
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.
void SetUseAbe(bool useAbe)
Set ABE mode of use on the socket.
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.
bool m_useAbe
ABE mode It will override the UseEcn attribute if it is 'Off' and set it to 'On', but will leave it u...
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.
bool GetUseAbe() const
Get ABE mode of use on the socket.
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.
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.
TracedCallback< Time, Time > m_srttTrace
Callback pointer for RTT trace chaining.
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.
bool m_fackEnabled
flag for enabling FACK
int DoConnect()
Perform the real connection tasks: Send SYN if allowed, RST if invalid.
virtual Time CalculateRttSample(const TcpHeader &tcpHeader, const RttHistory &rttHistory)
Calculate RTT sample for the ACKed packet.
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 NotifyConstructionCompleted() override
Notifier called once the ObjectBase is fully constructed.
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.
void UpdateFackAwnd(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState awnd(FACK's inflight).
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.
TracedCallback< uint32_t, uint32_t > m_cWndInflTrace
Callback pointer for cWndInfl trace chaining.
uint32_t GetRcvBufSize() const override
Get the receive buffer size.
static const char *const TcpStateName[TcpSocket::LAST_STATE]
Literal names of TCP states for use in log messages.
Definition tcp-socket.h:84
@ 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
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.
static INTERNET_EXPORT 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.
@ DctcpEcn
ECN functionality as described in RFC 8257.
@ ClassicEcn
ECN functionality as described in RFC 3168.
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.
static INTERNET_EXPORT const char *const EcnStateName[TcpSocketState::ECN_CWR_SENT+1]
Literal names of ECN states for use in log messages.
Item that encloses the application packet and some flags for it.
Definition tcp-tx-item.h:22
Ptr< Packet > GetPacketCopy() const
Get a copy of the Packet underlying this item.
bool IsRetrans() const
Is the item retransmitted?
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:398
Time TimeStep(uint64_t ts)
Scheduler interface.
Definition nstime.h:1370
@ S
second
Definition nstime.h:106
static Time FromDouble(double value, Unit unit)
Create a Time equal to value in unit unit.
Definition nstime.h:517
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:305
AttributeValue implementation for Time.
Definition nstime.h:1375
A simple virtual Timer class.
Definition timer.h:67
a unique identifier for an interface.
Definition type-id.h:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
Hold an unsigned integer type.
Definition uinteger.h:34
uint16_t port
Definition dsdv-manet.cc:33
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeAccessor > MakeCallbackAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition callback.h:826
Ptr< const AttributeChecker > MakeCallbackChecker()
Definition callback.cc:77
Ptr< const AttributeChecker > MakeDoubleChecker()
Definition double.h:82
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition double.h:32
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition enum.h:223
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition pointer.h:250
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:273
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1376
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1396
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
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:690
Callback< R, Args... > MakeNullCallback()
Build null Callbacks which take no arguments, for varying number of template arguments,...
Definition callback.h:734
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition abort.h:133
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition int64x64.h:231
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:246
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:274
#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:253
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:267
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:454
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
@ ESTABLISHED
Connection established.
Definition tcp-socket.h:61
@ FIN_WAIT_2
All buffered data sent, waiting for remote to shutdown.
Definition tcp-socket.h:70
@ LISTEN
Listening for a connection.
Definition tcp-socket.h:57
@ 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:62
@ SYN_SENT
Sent a connection request, waiting for ack.
Definition tcp-socket.h:58
@ CLOSED
Socket is finished.
Definition tcp-socket.h:56
@ FIN_WAIT_1
Our side has shutdown, waiting to complete transmission of remaining buffered data.
Definition tcp-socket.h:68
@ TIME_WAIT
Timeout to catch resent junk before entering closed, can only be entered from FIN_WAIT2 or CLOSING.
Definition tcp-socket.h:73
@ SYN_RCVD
Received a connection request, sent ack, waiting for final ack in three-way handshake.
Definition tcp-socket.h:59
@ LAST_ACK
Our side has shutdown after remote has shutdown.
Definition tcp-socket.h:65
@ CLOSING
Both sides have shutdown but we still have data we have to finish sending.
Definition tcp-socket.h:71
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1307
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1290
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
const std::map< std::pair< ns3::TcpSocketBase::TcpPacketType_t, ns3::TcpSocketState::EcnMode_t >, bool > ECN_RESTRICTION_MAP
map TcpPacketType and EcnMode to boolean value to check whether ECN-marking is allowed or not
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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:181
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605
Ptr< T > CopyObject(Ptr< const T > object)
Definition object.h:597
-bbr-example
ns3::Time timeout