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(
143 "MinRto",
144 "Minimum retransmit timeout value",
145 TimeValue(Seconds(1)), // RFC 6298 says min RTO=1 sec, but Linux uses 200ms.
146 // See http://www.postel.org/pipermail/end2end-interest/2004-November/004402.html
149 .AddAttribute(
150 "ClockGranularity",
151 "Clock Granularity used in RTO calculations",
152 TimeValue(MilliSeconds(1)), // RFC6298 suggest to use fine clock granularity
156 .AddAttribute("TxBuffer",
157 "TCP Tx buffer",
158 PointerValue(),
161 .AddAttribute("RxBuffer",
162 "TCP Rx buffer",
163 PointerValue(),
166 .AddAttribute("CongestionOps",
167 "Pointer to TcpCongestionOps object",
168 PointerValue(),
171 .AddAttribute("RecoveryOps",
172 "Pointer to TcpRecoveryOps object",
173 PointerValue(),
176 .AddAttribute(
177 "ReTxThreshold",
178 "Threshold for fast retransmit",
179 UintegerValue(3),
182 .AddAttribute("LimitedTransmit",
183 "Enable limited transmit",
184 BooleanValue(true),
187 .AddAttribute("UseEcn",
188 "Parameter to set ECN functionality",
192 "Off",
194 "On",
196 "AcceptOnly"))
197 .AddAttribute("UseAbe",
198 "Parameter to set ABE functionality",
199 BooleanValue(false),
202 .AddTraceSource("RTO",
203 "Retransmission timeout",
205 "ns3::TracedValueCallback::Time")
206 .AddTraceSource("RTT",
207 "Smoothed RTT",
209 "ns3::TracedValueCallback::Time")
210 .AddTraceSource("LastRTT",
211 "RTT of the last (S)ACKed packet",
213 "ns3::TracedValueCallback::Time")
214 .AddTraceSource("NextTxSequence",
215 "Next sequence number to send (SND.NXT)",
217 "ns3::SequenceNumber32TracedValueCallback")
218 .AddTraceSource("HighestSequence",
219 "Highest sequence number ever sent in socket's life time",
221 "ns3::TracedValueCallback::SequenceNumber32")
222 .AddTraceSource("State",
223 "TCP state",
225 "ns3::TcpStatesTracedValueCallback")
226 .AddTraceSource("CongState",
227 "TCP Congestion machine state",
229 "ns3::TcpSocketState::TcpCongStatesTracedValueCallback")
230 .AddTraceSource("EcnState",
231 "Trace ECN state change of socket",
233 "ns3::TcpSocketState::EcnStatesTracedValueCallback")
234 .AddTraceSource("AdvWND",
235 "Advertised Window Size",
237 "ns3::TracedValueCallback::Uint32")
238 .AddTraceSource("RWND",
239 "Remote side's flow control window",
241 "ns3::TracedValueCallback::Uint32")
242 .AddTraceSource("BytesInFlight",
243 "Socket estimation of bytes in flight",
245 "ns3::TracedValueCallback::Uint32")
246 .AddTraceSource("HighestRxSequence",
247 "Highest sequence number received from peer",
249 "ns3::TracedValueCallback::SequenceNumber32")
250 .AddTraceSource("HighestRxAck",
251 "Highest ack received from peer",
253 "ns3::TracedValueCallback::SequenceNumber32")
254 .AddTraceSource("PacingRate",
255 "The current TCP pacing rate",
257 "ns3::TracedValueCallback::DataRate")
258 .AddTraceSource("CongestionWindow",
259 "The TCP connection's congestion window",
261 "ns3::TracedValueCallback::Uint32")
262 .AddTraceSource("CongestionWindowInflated",
263 "The TCP connection's congestion window inflates as in older RFC",
265 "ns3::TracedValueCallback::Uint32")
266 .AddTraceSource("SlowStartThreshold",
267 "TCP slow start threshold (bytes)",
269 "ns3::TracedValueCallback::Uint32")
270 .AddTraceSource("Tx",
271 "Send tcp packet to IP protocol",
273 "ns3::TcpSocketBase::TcpTxRxTracedCallback")
274 .AddTraceSource("Retransmission",
275 "Notification of a TCP retransmission",
277 "ns3::TcpSocketBase::RetransmissionCallback")
278 .AddTraceSource("Rx",
279 "Receive tcp packet from IP protocol",
281 "ns3::TcpSocketBase::TcpTxRxTracedCallback")
282 .AddTraceSource("EcnEchoSeq",
283 "Sequence of last received ECN Echo",
285 "ns3::SequenceNumber32TracedValueCallback")
286 .AddTraceSource("EcnCeSeq",
287 "Sequence of last received CE",
289 "ns3::SequenceNumber32TracedValueCallback")
290 .AddTraceSource("EcnCwrSeq",
291 "Sequence of last received CWR",
293 "ns3::SequenceNumber32TracedValueCallback");
294 return tid;
295}
296
298 : TcpSocket()
299{
300 NS_LOG_FUNCTION(this);
301
303 m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
306
307 m_tcb->m_rxBuffer = CreateObject<TcpRxBuffer>();
308
309 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
311
312 m_tcb->m_sendEmptyPacketCallback = MakeCallback(&TcpSocketBase::SendEmptyPacket, this);
313
314 bool ok;
315
316 ok = m_tcb->TraceConnectWithoutContext(
317 "PacingRate",
319 NS_ASSERT(ok == true);
320
321 ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
323 NS_ASSERT(ok == true);
324
325 ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
327 NS_ASSERT(ok == true);
328
329 ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
331 NS_ASSERT(ok == true);
332
333 ok = m_tcb->TraceConnectWithoutContext("CongState",
335 NS_ASSERT(ok == true);
336
337 ok = m_tcb->TraceConnectWithoutContext("EcnState",
339 NS_ASSERT(ok == true);
340
341 ok =
342 m_tcb->TraceConnectWithoutContext("NextTxSequence",
344 NS_ASSERT(ok == true);
345
346 ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
348 NS_ASSERT(ok == true);
349
350 ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
352 NS_ASSERT(ok == true);
353
354 ok = m_tcb->TraceConnectWithoutContext("RTT", MakeCallback(&TcpSocketBase::UpdateRtt, this));
355 NS_ASSERT(ok == true);
356
357 ok = m_tcb->TraceConnectWithoutContext("LastRTT",
359 NS_ASSERT(ok == true);
360}
361
362void
369
371 : TcpSocket(sock),
372 // copy object::m_tid and socket::callbacks
374 m_delAckCount(0),
376 m_noDelay(sock.m_noDelay),
381 m_rto(sock.m_rto),
382 m_minRto(sock.m_minRto),
387 m_endPoint(nullptr),
388 m_endPoint6(nullptr),
389 m_node(sock.m_node),
390 m_tcp(sock.m_tcp),
391 m_state(sock.m_state),
392 m_errno(sock.m_errno),
398 m_msl(sock.m_msl),
401 m_rWnd(sock.m_rWnd),
410 m_recover(sock.m_recover),
415 m_txTrace(sock.m_txTrace),
416 m_rxTrace(sock.m_rxTrace),
417 m_pacingTimer(Timer::CANCEL_ON_DESTROY),
421{
422 NS_LOG_FUNCTION(this);
423 NS_LOG_LOGIC("Invoked the copy constructor");
424 // Copy the rtt estimator if it is set
425 if (sock.m_rtt)
426 {
427 m_rtt = sock.m_rtt->Copy();
428 }
429 // Reset all callbacks to null
431 Callback<void, Ptr<Socket>, const Address&> vPSA =
434 SetConnectCallback(vPS, vPS);
435 SetDataSentCallback(vPSUI);
436 SetSendCallback(vPSUI);
437 SetRecvCallback(vPS);
439 m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
440 m_tcb = CopyObject(sock.m_tcb);
441 m_tcb->m_rxBuffer = CopyObject(sock.m_tcb->m_rxBuffer);
442
443 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
445
447
448 if (sock.m_congestionControl)
449 {
452 m_congestionControl->SetRateOps(m_rateOps);
453 }
454
455 if (sock.m_recoveryOps)
456 {
457 m_recoveryOps = sock.m_recoveryOps->Fork();
458 }
459
460 if (m_tcb->m_sendEmptyPacketCallback.IsNull())
461 {
462 m_tcb->m_sendEmptyPacketCallback = MakeCallback(&TcpSocketBase::SendEmptyPacket, this);
463 }
464
465 bool ok;
466
467 ok = m_tcb->TraceConnectWithoutContext(
468 "PacingRate",
470
471 ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
473 NS_ASSERT(ok == true);
474
475 ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
477 NS_ASSERT(ok == true);
478
479 ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
481 NS_ASSERT(ok == true);
482
483 ok = m_tcb->TraceConnectWithoutContext("CongState",
485 NS_ASSERT(ok == true);
486
487 ok = m_tcb->TraceConnectWithoutContext("EcnState",
489 NS_ASSERT(ok == true);
490
491 ok =
492 m_tcb->TraceConnectWithoutContext("NextTxSequence",
494 NS_ASSERT(ok == true);
495
496 ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
498 NS_ASSERT(ok == true);
499
500 ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
502 NS_ASSERT(ok == true);
503
504 ok = m_tcb->TraceConnectWithoutContext("RTT", MakeCallback(&TcpSocketBase::UpdateRtt, this));
505 NS_ASSERT(ok == true);
506
507 ok = m_tcb->TraceConnectWithoutContext("LastRTT",
509 NS_ASSERT(ok == true);
510}
511
513{
514 NS_LOG_FUNCTION(this);
515 m_node = nullptr;
516 if (m_endPoint != nullptr)
517 {
519 /*
520 * Upon Bind, an Ipv4Endpoint is allocated and set to m_endPoint, and
521 * DestroyCallback is set to TcpSocketBase::Destroy. If we called
522 * m_tcp->DeAllocate, it will destroy its Ipv4EndpointDemux::DeAllocate,
523 * which in turn destroys my m_endPoint, and in turn invokes
524 * TcpSocketBase::Destroy to nullify m_node, m_endPoint, and m_tcp.
525 */
526 NS_ASSERT(m_endPoint != nullptr);
527 m_tcp->DeAllocate(m_endPoint);
528 NS_ASSERT(m_endPoint == nullptr);
529 }
530 if (m_endPoint6 != nullptr)
531 {
533 NS_ASSERT(m_endPoint6 != nullptr);
534 m_tcp->DeAllocate(m_endPoint6);
535 NS_ASSERT(m_endPoint6 == nullptr);
536 }
537 m_tcp = nullptr;
539}
540
541/* Associate a node with this TCP socket */
542void
544{
545 m_node = node;
546}
547
548/* Associate the L4 protocol (e.g. mux/demux) with this socket */
549void
554
555/* Set an RTT estimator with this socket */
556void
561
562/* Inherit from Socket class: Returns error code */
565{
566 return m_errno;
567}
568
569/* Inherit from Socket class: Returns socket type, NS3_SOCK_STREAM */
572{
573 return NS3_SOCK_STREAM;
574}
575
576/* Inherit from Socket class: Returns associated node */
579{
580 return m_node;
581}
582
583/* Inherit from Socket class: Bind socket to an end-point in TcpL4Protocol */
584int
586{
587 NS_LOG_FUNCTION(this);
588 m_endPoint = m_tcp->Allocate();
589 if (nullptr == m_endPoint)
590 {
592 return -1;
593 }
594
595 m_tcp->AddSocket(this);
596
597 return SetupCallback();
598}
599
600int
602{
603 NS_LOG_FUNCTION(this);
604 m_endPoint6 = m_tcp->Allocate6();
605 if (nullptr == m_endPoint6)
606 {
608 return -1;
609 }
610
611 m_tcp->AddSocket(this);
612
613 return SetupCallback();
614}
615
616/* Inherit from Socket class: Bind socket (with specific address) to an end-point in TcpL4Protocol
617 */
618int
620{
621 NS_LOG_FUNCTION(this << address);
623 {
625 Ipv4Address ipv4 = transport.GetIpv4();
626 uint16_t port = transport.GetPort();
627 if (ipv4 == Ipv4Address::GetAny() && port == 0)
628 {
629 m_endPoint = m_tcp->Allocate();
630 }
631 else if (ipv4 == Ipv4Address::GetAny() && port != 0)
632 {
633 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), port);
634 }
635 else if (ipv4 != Ipv4Address::GetAny() && port == 0)
636 {
637 m_endPoint = m_tcp->Allocate(ipv4);
638 }
639 else if (ipv4 != Ipv4Address::GetAny() && port != 0)
640 {
641 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), ipv4, port);
642 }
643 if (nullptr == m_endPoint)
644 {
646 return -1;
647 }
648 }
649 else if (Inet6SocketAddress::IsMatchingType(address))
650 {
652 Ipv6Address ipv6 = transport.GetIpv6();
653 uint16_t port = transport.GetPort();
654 if (ipv6 == Ipv6Address::GetAny() && port == 0)
655 {
656 m_endPoint6 = m_tcp->Allocate6();
657 }
658 else if (ipv6 == Ipv6Address::GetAny() && port != 0)
659 {
660 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), port);
661 }
662 else if (ipv6 != Ipv6Address::GetAny() && port == 0)
663 {
664 m_endPoint6 = m_tcp->Allocate6(ipv6);
665 }
666 else if (ipv6 != Ipv6Address::GetAny() && port != 0)
667 {
668 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), ipv6, port);
669 }
670 if (nullptr == m_endPoint6)
671 {
673 return -1;
674 }
675 }
676 else
677 {
679 return -1;
680 }
681
682 m_tcp->AddSocket(this);
683
684 NS_LOG_LOGIC("TcpSocketBase " << this << " got an endpoint: " << m_endPoint);
685
686 return SetupCallback();
687}
688
689void
691{
693 (m_state == CLOSED) || threshold == m_tcb->m_initialSsThresh,
694 "TcpSocketBase::SetSSThresh() cannot change initial ssThresh after connection started.");
695
696 m_tcb->m_initialSsThresh = threshold;
697}
698
701{
702 return m_tcb->m_initialSsThresh;
703}
704
705void
707{
709 (m_state == CLOSED) || cwnd == m_tcb->m_initialCWnd,
710 "TcpSocketBase::SetInitialCwnd() cannot change initial cwnd after connection started.");
711
712 m_tcb->m_initialCWnd = cwnd;
713}
714
717{
718 return m_tcb->m_initialCWnd;
719}
720
721/* Inherit from Socket class: Initiate connection to a remote address:port */
722int
724{
725 NS_LOG_FUNCTION(this << address);
726
727 // If haven't do so, Bind() this socket first
729 {
730 if (m_endPoint == nullptr)
731 {
732 if (Bind() == -1)
733 {
734 NS_ASSERT(m_endPoint == nullptr);
735 return -1; // Bind() failed
736 }
737 NS_ASSERT(m_endPoint != nullptr);
738 }
740 m_endPoint->SetPeer(transport.GetIpv4(), transport.GetPort());
741 m_endPoint6 = nullptr;
742
743 // Get the appropriate local address and port number from the routing protocol and set up
744 // endpoint
745 if (SetupEndpoint() != 0)
746 {
747 NS_LOG_ERROR("Route to destination does not exist ?!");
748 return -1;
749 }
750 }
751 else if (Inet6SocketAddress::IsMatchingType(address))
752 {
753 // If we are operating on a v4-mapped address, translate the address to
754 // a v4 address and re-call this function
756 Ipv6Address v6Addr = transport.GetIpv6();
757 if (v6Addr.IsIpv4MappedAddress())
758 {
759 Ipv4Address v4Addr = v6Addr.GetIpv4MappedAddress();
760 return Connect(InetSocketAddress(v4Addr, transport.GetPort()));
761 }
762
763 if (m_endPoint6 == nullptr)
764 {
765 if (Bind6() == -1)
766 {
767 NS_ASSERT(m_endPoint6 == nullptr);
768 return -1; // Bind() failed
769 }
770 NS_ASSERT(m_endPoint6 != nullptr);
771 }
772 m_endPoint6->SetPeer(v6Addr, transport.GetPort());
773 m_endPoint = nullptr;
774
775 // Get the appropriate local address and port number from the routing protocol and set up
776 // endpoint
777 if (SetupEndpoint6() != 0)
778 {
779 NS_LOG_ERROR("Route to destination does not exist ?!");
780 return -1;
781 }
782 }
783 else
784 {
786 return -1;
787 }
788
789 // Re-initialize parameters in case this socket is being reused after CLOSE
790 m_rtt->Reset();
793
794 // DoConnect() will do state-checking and send a SYN packet
795 return DoConnect();
796}
797
798/* Inherit from Socket class: Listen on the endpoint for an incoming connection */
799int
801{
802 NS_LOG_FUNCTION(this);
803
804 // Linux quits EINVAL if we're not in CLOSED state, so match what they do
805 if (m_state != CLOSED)
806 {
808 return -1;
809 }
810 // In other cases, set the state to LISTEN and done
811 NS_LOG_DEBUG("CLOSED -> LISTEN");
812 m_state = LISTEN;
813 return 0;
814}
815
816/* Inherit from Socket class: Kill this socket and signal the peer (if any) */
817int
819{
820 NS_LOG_FUNCTION(this);
821 /// @internal
822 /// First we check to see if there is any unread rx data.
823 /// \bugid{426} claims we should send reset in this case.
824 if (m_tcb->m_rxBuffer->Size() != 0)
825 {
826 NS_LOG_WARN("Socket " << this << " << unread rx data during close. Sending reset."
827 << "This is probably due to a bad sink application; check its code");
828 SendRST();
829 return 0;
830 }
831
832 if (m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence) > 0)
833 { // App close with pending data must wait until all data transmitted
834 if (!m_closeOnEmpty)
835 {
836 m_closeOnEmpty = true;
837 NS_LOG_INFO("Socket " << this << " deferring close, state " << TcpStateName[m_state]);
838 }
839 return 0;
840 }
841 return DoClose();
842}
843
844/* Inherit from Socket class: Signal a termination of send */
845int
847{
848 NS_LOG_FUNCTION(this);
849
850 // this prevents data from being added to the buffer
851 m_shutdownSend = true;
852 m_closeOnEmpty = true;
853 // if buffer is already empty, send a fin now
854 // otherwise fin will go when buffer empties.
855 if (m_txBuffer->Size() == 0)
856 {
858 {
859 NS_LOG_INFO("Empty tx buffer, send fin");
861
862 if (m_state == ESTABLISHED)
863 { // On active close: I am the first one to send FIN
864 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
866 }
867 else
868 { // On passive close: Peer sent me FIN already
869 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
871 }
872 }
873 }
874
875 return 0;
876}
877
878/* Inherit from Socket class: Signal a termination of receive */
879int
881{
882 NS_LOG_FUNCTION(this);
883 m_shutdownRecv = true;
884 return 0;
885}
886
887/* Inherit from Socket class: Send a packet. Parameter flags is not used.
888 Packet has no TCP header. Invoked by upper-layer application */
889int
891{
892 NS_LOG_FUNCTION(this << p);
893 NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Send()");
895 {
896 // Store the packet into Tx buffer
897 if (!m_txBuffer->Add(p))
898 { // TxBuffer overflow, send failed
900 return -1;
901 }
902 if (m_shutdownSend)
903 {
905 return -1;
906 }
907
908 m_rateOps->CalculateAppLimited(m_tcb->m_cWnd,
909 m_tcb->m_bytesInFlight,
910 m_tcb->m_segmentSize,
911 m_txBuffer->TailSequence(),
912 m_tcb->m_nextTxSequence,
913 m_txBuffer->GetLost(),
914 m_txBuffer->GetRetransmitsCount());
915
916 // Submit the data to lower layers
917 NS_LOG_LOGIC("txBufSize=" << m_txBuffer->Size() << " state " << TcpStateName[m_state]);
918 if ((m_state == ESTABLISHED || m_state == CLOSE_WAIT) && AvailableWindow() > 0)
919 { // Try to send the data out: Add a little step to allow the application
920 // to fill the buffer
921 if (!m_sendPendingDataEvent.IsPending())
922 {
925 this,
927 }
928 }
929 return p->GetSize();
930 }
931 else
932 { // Connection not established yet
934 return -1; // Send failure
935 }
936}
937
938/* Inherit from Socket class: In TcpSocketBase, it is same as Send() call */
939int
940TcpSocketBase::SendTo(Ptr<Packet> p, uint32_t flags, const Address& /* address */)
941{
942 return Send(p, flags); // SendTo() and Send() are the same
943}
944
945/* Inherit from Socket class: Return data to upper-layer application. Parameter flags
946 is not used. Data is returned as a packet of size no larger than maxSize */
949{
950 NS_LOG_FUNCTION(this);
951 NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Recv()");
952 if (m_tcb->m_rxBuffer->Size() == 0 && m_state == CLOSE_WAIT)
953 {
954 return Create<Packet>(); // Send EOF on connection close
955 }
956 Ptr<Packet> outPacket = m_tcb->m_rxBuffer->Extract(maxSize);
957 return outPacket;
958}
959
960/* Inherit from Socket class: Recv and return the remote's address */
963{
964 NS_LOG_FUNCTION(this << maxSize << flags);
965 Ptr<Packet> packet = Recv(maxSize, flags);
966 // Null packet means no data to read, and an empty packet indicates EOF
967 if (packet && packet->GetSize() != 0)
968 {
969 if (m_endPoint != nullptr)
970 {
971 fromAddress =
972 InetSocketAddress(m_endPoint->GetPeerAddress(), m_endPoint->GetPeerPort());
973 }
974 else if (m_endPoint6 != nullptr)
975 {
976 fromAddress =
977 Inet6SocketAddress(m_endPoint6->GetPeerAddress(), m_endPoint6->GetPeerPort());
978 }
979 else
980 {
981 fromAddress = InetSocketAddress(Ipv4Address::GetZero(), 0);
982 }
983 }
984 return packet;
985}
986
987/* Inherit from Socket class: Get the max number of bytes an app can send */
990{
991 NS_LOG_FUNCTION(this);
992 return m_txBuffer->Available();
993}
994
995/* Inherit from Socket class: Get the max number of bytes an app can read */
998{
999 NS_LOG_FUNCTION(this);
1000 return m_tcb->m_rxBuffer->Available();
1001}
1002
1003/* Inherit from Socket class: Return local address:port */
1004int
1006{
1007 NS_LOG_FUNCTION(this);
1008 if (m_endPoint != nullptr)
1009 {
1010 address = InetSocketAddress(m_endPoint->GetLocalAddress(), m_endPoint->GetLocalPort());
1011 }
1012 else if (m_endPoint6 != nullptr)
1013 {
1014 address = Inet6SocketAddress(m_endPoint6->GetLocalAddress(), m_endPoint6->GetLocalPort());
1015 }
1016 else
1017 { // It is possible to call this method on a socket without a name
1018 // in which case, behavior is unspecified
1019 // Should this return an InetSocketAddress or an Inet6SocketAddress?
1021 }
1022 return 0;
1023}
1024
1025int
1027{
1028 NS_LOG_FUNCTION(this << address);
1029
1030 if (!m_endPoint && !m_endPoint6)
1031 {
1033 return -1;
1034 }
1035
1036 if (m_endPoint)
1037 {
1038 address = InetSocketAddress(m_endPoint->GetPeerAddress(), m_endPoint->GetPeerPort());
1039 }
1040 else if (m_endPoint6)
1041 {
1042 address = Inet6SocketAddress(m_endPoint6->GetPeerAddress(), m_endPoint6->GetPeerPort());
1043 }
1044 else
1045 {
1046 NS_ASSERT(false);
1047 }
1048
1049 return 0;
1050}
1051
1052/* Inherit from Socket class: Bind this socket to the specified NetDevice */
1053void
1055{
1056 NS_LOG_FUNCTION(netdevice);
1057 Socket::BindToNetDevice(netdevice); // Includes sanity check
1058 if (m_endPoint != nullptr)
1059 {
1060 m_endPoint->BindToNetDevice(netdevice);
1061 }
1062
1063 if (m_endPoint6 != nullptr)
1064 {
1065 m_endPoint6->BindToNetDevice(netdevice);
1066 }
1067}
1068
1069/* Clean up after Bind. Set up callback functions in the end-point. */
1070int
1072{
1073 NS_LOG_FUNCTION(this);
1074
1075 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
1076 {
1077 return -1;
1078 }
1079 if (m_endPoint != nullptr)
1080 {
1081 m_endPoint->SetRxCallback(
1083 m_endPoint->SetIcmpCallback(
1085 m_endPoint->SetDestroyCallback(
1087 }
1088 if (m_endPoint6 != nullptr)
1089 {
1090 m_endPoint6->SetRxCallback(
1092 m_endPoint6->SetIcmpCallback(
1094 m_endPoint6->SetDestroyCallback(
1096 }
1097
1098 return 0;
1099}
1100
1101/* Perform the real connection tasks: Send SYN if allowed, RST if invalid */
1102int
1104{
1105 NS_LOG_FUNCTION(this);
1106
1107 // A new connection is allowed only if this socket does not have a connection
1108 if (m_state == CLOSED || m_state == LISTEN || m_state == SYN_SENT || m_state == LAST_ACK ||
1110 { // send a SYN packet and change state into SYN_SENT
1111 // send a SYN packet with ECE and CWR flags set if sender is ECN capable
1112 if (m_tcb->m_useEcn == TcpSocketState::On)
1113 {
1115 }
1116 else
1117 {
1119 }
1120 NS_LOG_DEBUG(TcpStateName[m_state] << " -> SYN_SENT");
1121 m_state = SYN_SENT;
1122 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED; // because sender is not yet aware about
1123 // receiver's ECN capability
1124 }
1125 else if (m_state != TIME_WAIT)
1126 { // In states SYN_RCVD, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, and CLOSING, an connection
1127 // exists. We send RST, tear down everything, and close this socket.
1128 SendRST();
1130 }
1131 return 0;
1132}
1133
1134/* Do the action to close the socket. Usually send a packet with appropriate
1135 flags depended on the current m_state. */
1136int
1138{
1139 NS_LOG_FUNCTION(this);
1140 switch (m_state)
1141 {
1142 case SYN_RCVD:
1143 case ESTABLISHED:
1144 // send FIN to close the peer
1146 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
1148 break;
1149 case CLOSE_WAIT:
1150 // send FIN+ACK to close the peer
1152 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
1153 m_state = LAST_ACK;
1154 break;
1155 case SYN_SENT:
1156 case CLOSING:
1157 // Send RST if application closes in SYN_SENT and CLOSING
1158 SendRST();
1160 break;
1161 case LISTEN:
1162 // In this state, move to CLOSED and tear down the end point
1164 break;
1165 case LAST_ACK:
1166 case CLOSED:
1167 case FIN_WAIT_1:
1168 case FIN_WAIT_2:
1169 case TIME_WAIT:
1170 default: /* mute compiler */
1171 // Do nothing in these five states
1172 break;
1173 }
1174 return 0;
1175}
1176
1177/* Peacefully close the socket by notifying the upper layer and deallocate end point */
1178void
1180{
1181 NS_LOG_FUNCTION(this);
1182
1183 if (!m_closeNotified)
1184 {
1186 m_closeNotified = true;
1187 }
1188 if (m_lastAckEvent.IsPending())
1189 {
1190 m_lastAckEvent.Cancel();
1191 }
1192 NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSED");
1193 m_state = CLOSED;
1195}
1196
1197/* Tell if a sequence number range is out side the range that my rx buffer can
1198 accept */
1199bool
1201{
1202 if (m_state == LISTEN || m_state == SYN_SENT || m_state == SYN_RCVD)
1203 { // Rx buffer in these states are not initialized.
1204 return false;
1205 }
1206 if (m_state == LAST_ACK || m_state == CLOSING || m_state == CLOSE_WAIT)
1207 { // In LAST_ACK and CLOSING states, it only wait for an ACK and the
1208 // sequence number must equals to m_rxBuffer->NextRxSequence ()
1209 return (m_tcb->m_rxBuffer->NextRxSequence() != head);
1210 }
1211
1212 // In all other cases, check if the sequence number is in range
1213 return (tail < m_tcb->m_rxBuffer->NextRxSequence() ||
1214 m_tcb->m_rxBuffer->MaxRxSequence() <= head);
1215}
1216
1217/* Function called by the L3 protocol when it received a packet to pass on to
1218 the TCP. This function is registered as the "RxCallback" function in
1219 SetupCallback(), which invoked by Bind(), and CompleteFork() */
1220void
1222 Ipv4Header header,
1223 uint16_t port,
1224 Ptr<Ipv4Interface> incomingInterface)
1225{
1226 NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint->GetPeerAddress() << ":"
1227 << m_endPoint->GetPeerPort() << " to " << m_endPoint->GetLocalAddress()
1228 << ":" << m_endPoint->GetLocalPort());
1229
1230 Address fromAddress = InetSocketAddress(header.GetSource(), port);
1231 Address toAddress = InetSocketAddress(header.GetDestination(), m_endPoint->GetLocalPort());
1232
1233 TcpHeader tcpHeader;
1234 uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1235
1236 if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1237 bytesRemoved,
1238 packet->GetSize() - bytesRemoved))
1239 {
1240 return;
1241 }
1242
1243 if (header.GetEcn() == Ipv4Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1244 {
1245 NS_LOG_INFO("Received CE flag is valid");
1246 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
1247 m_ecnCESeq = tcpHeader.GetSequenceNumber();
1248 m_tcb->m_ecnState = TcpSocketState::ECN_CE_RCVD;
1250 }
1251 else if (header.GetEcn() != Ipv4Header::ECN_NotECT &&
1252 m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED)
1253 {
1255 }
1256
1257 DoForwardUp(packet, fromAddress, toAddress);
1258}
1259
1260void
1262 Ipv6Header header,
1263 uint16_t port,
1264 Ptr<Ipv6Interface> incomingInterface)
1265{
1266 NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint6->GetPeerAddress() << ":"
1267 << m_endPoint6->GetPeerPort() << " to " << m_endPoint6->GetLocalAddress()
1268 << ":" << m_endPoint6->GetLocalPort());
1269
1270 Address fromAddress = Inet6SocketAddress(header.GetSource(), port);
1271 Address toAddress = Inet6SocketAddress(header.GetDestination(), m_endPoint6->GetLocalPort());
1272
1273 TcpHeader tcpHeader;
1274 uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1275
1276 if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1277 bytesRemoved,
1278 packet->GetSize() - bytesRemoved))
1279 {
1280 return;
1281 }
1282
1283 if (header.GetEcn() == Ipv6Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1284 {
1285 NS_LOG_INFO("Received CE flag is valid");
1286 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
1287 m_ecnCESeq = tcpHeader.GetSequenceNumber();
1288 m_tcb->m_ecnState = TcpSocketState::ECN_CE_RCVD;
1290 }
1291 else if (header.GetEcn() != Ipv6Header::ECN_NotECT)
1292 {
1294 }
1295
1296 DoForwardUp(packet, fromAddress, toAddress);
1297}
1298
1299void
1301 uint8_t icmpTtl,
1302 uint8_t icmpType,
1303 uint8_t icmpCode,
1304 uint32_t icmpInfo)
1305{
1306 NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1307 << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1308 << icmpInfo);
1309 if (!m_icmpCallback.IsNull())
1310 {
1311 m_icmpCallback(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1312 }
1313}
1314
1315void
1317 uint8_t icmpTtl,
1318 uint8_t icmpType,
1319 uint8_t icmpCode,
1320 uint32_t icmpInfo)
1321{
1322 NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1323 << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1324 << icmpInfo);
1325 if (!m_icmpCallback6.IsNull())
1326 {
1327 m_icmpCallback6(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1328 }
1329}
1330
1331bool
1333 const uint32_t tcpHeaderSize,
1334 const uint32_t tcpPayloadSize)
1335{
1336 if (tcpHeaderSize == 0 || tcpHeaderSize > 60)
1337 {
1338 NS_LOG_ERROR("Bytes removed: " << tcpHeaderSize << " invalid");
1339 return false; // Discard invalid packet
1340 }
1341 else if (tcpPayloadSize > 0 && OutOfRange(seq, seq + tcpPayloadSize))
1342 {
1343 // Discard fully out of range data packets
1344 NS_LOG_WARN("At state " << TcpStateName[m_state] << " received packet of seq [" << seq
1345 << ":" << seq + tcpPayloadSize << ") out of range ["
1346 << m_tcb->m_rxBuffer->NextRxSequence() << ":"
1347 << m_tcb->m_rxBuffer->MaxRxSequence() << ")");
1348 // Acknowledgement should be sent for all unacceptable packets (RFC793, p.69)
1350 return false;
1351 }
1352 return true;
1353}
1354
1355void
1356TcpSocketBase::DoForwardUp(Ptr<Packet> packet, const Address& fromAddress, const Address& toAddress)
1357{
1358 // in case the packet still has a priority tag attached, remove it
1359 SocketPriorityTag priorityTag;
1360 packet->RemovePacketTag(priorityTag);
1361
1362 // Peel off TCP header
1363 TcpHeader tcpHeader;
1364 packet->RemoveHeader(tcpHeader);
1365 SequenceNumber32 seq = tcpHeader.GetSequenceNumber();
1366
1367 if (m_state == ESTABLISHED && !(tcpHeader.GetFlags() & TcpHeader::RST))
1368 {
1369 // Check if the sender has responded to ECN echo by reducing the Congestion Window
1370 if (tcpHeader.GetFlags() & TcpHeader::CWR)
1371 {
1372 // Check if a packet with CE bit set is received. If there is no CE bit set, then change
1373 // the state to ECN_IDLE to stop sending ECN Echo messages. If there is CE bit set, the
1374 // packet should continue sending ECN Echo messages
1375 //
1376 if (m_tcb->m_ecnState != TcpSocketState::ECN_CE_RCVD)
1377 {
1378 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
1379 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
1380 }
1381 }
1382 }
1383
1384 m_rxTrace(packet, tcpHeader, this);
1385
1386 if (tcpHeader.GetFlags() & TcpHeader::SYN)
1387 {
1388 /* The window field in a segment where the SYN bit is set (i.e., a <SYN>
1389 * or <SYN,ACK>) MUST NOT be scaled (from RFC 7323 page 9). But should be
1390 * saved anyway..
1391 */
1392 m_rWnd = tcpHeader.GetWindowSize();
1393
1395 {
1397 }
1398 else
1399 {
1400 m_winScalingEnabled = false;
1401 }
1402
1404 {
1406 }
1407 else
1408 {
1409 m_sackEnabled = false;
1410 m_txBuffer->SetSackEnabled(false);
1411 }
1412
1413 // When receiving a <SYN> or <SYN-ACK> we should adapt TS to the other end
1414 if (tcpHeader.HasOption(TcpOption::TS) && m_timestampEnabled)
1415 {
1417 tcpHeader.GetSequenceNumber());
1418 }
1419 else
1420 {
1421 m_timestampEnabled = false;
1422 }
1423
1424 // Initialize cWnd and ssThresh
1425 m_tcb->m_cWnd = GetInitialCwnd() * GetSegSize();
1426 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
1427 m_tcb->m_ssThresh = GetInitialSSThresh();
1428
1429 if (tcpHeader.GetFlags() & TcpHeader::ACK)
1430 {
1431 EstimateRtt(tcpHeader);
1432 m_highRxAckMark = tcpHeader.GetAckNumber();
1433 }
1434 }
1435 else if (tcpHeader.GetFlags() & TcpHeader::ACK)
1436 {
1437 NS_ASSERT(!(tcpHeader.GetFlags() & TcpHeader::SYN));
1439 {
1440 if (!tcpHeader.HasOption(TcpOption::TS))
1441 {
1442 // Ignoring segment without TS, RFC 7323
1443 NS_LOG_LOGIC("At state " << TcpStateName[m_state] << " received packet of seq ["
1444 << seq << ":" << seq + packet->GetSize()
1445 << ") without TS option. Silently discard it");
1446 return;
1447 }
1448 else
1449 {
1451 tcpHeader.GetSequenceNumber());
1452 }
1453 }
1454
1455 EstimateRtt(tcpHeader);
1456 UpdateWindowSize(tcpHeader);
1457 }
1458
1459 if (m_rWnd.Get() == 0 && m_persistEvent.IsExpired())
1460 { // Zero window: Enter persist state to send 1 byte to probe
1461 NS_LOG_LOGIC(this << " Enter zerowindow persist state");
1463 this << " Cancelled ReTxTimeout event which was set to expire at "
1464 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
1465 m_retxEvent.Cancel();
1466 NS_LOG_LOGIC("Schedule persist timeout at time "
1467 << Simulator::Now().GetSeconds() << " to expire at time "
1468 << (Simulator::Now() + m_persistTimeout).GetSeconds());
1472 }
1473
1474 // TCP state machine code in different process functions
1475 // C.f.: tcp_rcv_state_process() in tcp_input.c in Linux kernel
1476 switch (m_state)
1477 {
1478 case ESTABLISHED:
1479 ProcessEstablished(packet, tcpHeader);
1480 break;
1481 case LISTEN:
1482 ProcessListen(packet, tcpHeader, fromAddress, toAddress);
1483 break;
1484 case TIME_WAIT:
1485 // Do nothing
1486 break;
1487 case CLOSED:
1488 // Send RST if the incoming packet is not a RST
1489 if ((tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG)) != TcpHeader::RST)
1490 { // Since m_endPoint is not configured yet, we cannot use SendRST here
1491 TcpHeader h;
1494 h.SetSequenceNumber(m_tcb->m_nextTxSequence);
1495 h.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
1496 h.SetSourcePort(tcpHeader.GetDestinationPort());
1497 h.SetDestinationPort(tcpHeader.GetSourcePort());
1499 AddOptions(h);
1500 m_txTrace(p, h, this);
1501 m_tcp->SendPacket(p, h, toAddress, fromAddress, m_boundnetdevice);
1502 }
1503 break;
1504 case SYN_SENT:
1505 ProcessSynSent(packet, tcpHeader);
1506 break;
1507 case SYN_RCVD:
1508 ProcessSynRcvd(packet, tcpHeader, fromAddress, toAddress);
1509 break;
1510 case FIN_WAIT_1:
1511 case FIN_WAIT_2:
1512 case CLOSE_WAIT:
1513 ProcessWait(packet, tcpHeader);
1514 break;
1515 case CLOSING:
1516 ProcessClosing(packet, tcpHeader);
1517 break;
1518 case LAST_ACK:
1519 ProcessLastAck(packet, tcpHeader);
1520 break;
1521 default: // mute compiler
1522 break;
1523 }
1524
1525 if (m_rWnd.Get() != 0 && m_persistEvent.IsPending())
1526 { // persist probes end, the other end has increased the window
1528 NS_LOG_LOGIC(this << " Leaving zerowindow persist state");
1529 m_persistEvent.Cancel();
1530
1532 }
1533}
1534
1535/* Received a packet upon ESTABLISHED state. This function is mimicking the
1536 role of tcp_rcv_established() in tcp_input.c in Linux kernel. */
1537void
1539{
1540 NS_LOG_FUNCTION(this << tcpHeader);
1541
1542 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
1543 uint8_t tcpflags =
1545
1546 // Different flags are different events
1547 if (tcpflags == TcpHeader::ACK)
1548 {
1549 if (tcpHeader.GetAckNumber() < m_txBuffer->HeadSequence())
1550 {
1551 // Case 1: If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored.
1552 // Pag. 72 RFC 793
1553 NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1554 << " SND.UNA = " << m_txBuffer->HeadSequence());
1555
1556 // TODO: RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation]
1557 }
1558 else if (tcpHeader.GetAckNumber() > m_tcb->m_highTxMark)
1559 {
1560 // If the ACK acks something not yet sent (SEG.ACK > HighTxMark) then
1561 // send an ACK, drop the segment, and return.
1562 // Pag. 72 RFC 793
1563 NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1564 << " HighTxMark = " << m_tcb->m_highTxMark);
1565
1566 // Receiver sets ECE flags when it receives a packet with CE bit on or sender hasn't
1567 // responded to ECN echo sent by receiver
1568 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
1570 {
1573 << " -> ECN_SENDING_ECE");
1575 }
1576 else
1577 {
1579 }
1580 }
1581 else
1582 {
1583 // SND.UNA < SEG.ACK =< HighTxMark
1584 // Pag. 72 RFC 793
1585 ReceivedAck(packet, tcpHeader);
1586 }
1587 }
1588 else if (tcpflags == TcpHeader::SYN || tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
1589 {
1590 // (a) Received SYN, old NS-3 behaviour is to set state to SYN_RCVD and
1591 // respond with a SYN+ACK. But it is not a legal state transition as of
1592 // RFC793. Thus this is ignored.
1593
1594 // (b) No action for received SYN+ACK, it is probably a duplicated packet
1595 }
1596 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
1597 { // Received FIN or FIN+ACK, bring down this socket nicely
1598 PeerClose(packet, tcpHeader);
1599 }
1600 else if (tcpflags == 0)
1601 { // No flags means there is only data
1602 ReceivedData(packet, tcpHeader);
1603 if (m_tcb->m_rxBuffer->Finished())
1604 {
1605 PeerClose(packet, tcpHeader);
1606 }
1607 }
1608 else
1609 { // Received RST or the TCP flags is invalid, in either case, terminate this socket
1610 if (tcpflags != TcpHeader::RST)
1611 { // this must be an invalid flag, send reset
1612 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
1613 << " received. Reset packet is sent.");
1614 SendRST();
1615 }
1617 }
1618}
1619
1620bool
1622{
1623 NS_LOG_FUNCTION(this << static_cast<uint32_t>(kind));
1624
1625 switch (kind)
1626 {
1627 case TcpOption::TS:
1628 return m_timestampEnabled;
1630 return m_winScalingEnabled;
1632 case TcpOption::SACK:
1633 return m_sackEnabled;
1634 default:
1635 break;
1636 }
1637 return false;
1638}
1639
1640void
1641TcpSocketBase::ReadOptions(const TcpHeader& tcpHeader, uint32_t* bytesSacked)
1642{
1643 NS_LOG_FUNCTION(this << tcpHeader);
1644
1645 for (const auto& option : tcpHeader.GetOptionList())
1646 {
1647 // Check only for ACK options here
1648 switch (option->GetKind())
1649 {
1650 case TcpOption::SACK:
1651 *bytesSacked = ProcessOptionSack(option);
1652 break;
1653 default:
1654 continue;
1655 }
1656 }
1657}
1658
1659// Sender should reduce the Congestion Window as a response to receiver's
1660// ECN Echo notification only once per window
1661void
1663{
1664 NS_LOG_FUNCTION(this << currentDelivered);
1665 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, BytesInFlight());
1666 NS_LOG_DEBUG("Reduce ssThresh to " << m_tcb->m_ssThresh);
1667 // Do not update m_cWnd, under assumption that recovery process will
1668 // gradually bring it down to m_ssThresh. Update the 'inflated' value of
1669 // cWnd used for tracing, however.
1670 m_tcb->m_cWndInfl = m_tcb->m_ssThresh;
1671 NS_ASSERT(m_tcb->m_congState != TcpSocketState::CA_CWR);
1672 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_CWR");
1673 m_tcb->m_congState = TcpSocketState::CA_CWR;
1674 // CWR state will be exited when the ack exceeds the m_recover variable.
1675 // Do not set m_recoverActive (which applies to a loss-based recovery)
1676 // m_recover corresponds to Linux tp->high_seq
1677 m_recover = m_tcb->m_highTxMark;
1678 if (!m_congestionControl->HasCongControl())
1679 {
1680 // If there is a recovery algorithm, invoke it.
1681 m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1682 NS_LOG_INFO("Enter CWR recovery mode; set cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1683 << m_tcb->m_ssThresh << ", recover to "
1684 << m_recover);
1685 }
1686}
1687
1688void
1690{
1691 NS_LOG_FUNCTION(this);
1693
1694 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_RECOVERY");
1695
1696 if (!m_sackEnabled)
1697 {
1698 // One segment has left the network, PLUS the head is lost
1699 m_txBuffer->AddRenoSack();
1700 m_txBuffer->MarkHeadAsLost();
1701 }
1702 else
1703 {
1704 if (!m_txBuffer->IsLost(m_txBuffer->HeadSequence()))
1705 {
1706 // We received 3 dupacks, but the head is not marked as lost
1707 // (received less than 3 SACK block ahead).
1708 // Manually set it as lost.
1709 m_txBuffer->MarkHeadAsLost();
1710 }
1711 }
1712
1713 // RFC 6675, point (4):
1714 // (4) Invoke fast retransmit and enter loss recovery as follows:
1715 // (4.1) RecoveryPoint = HighData
1716 m_recover = m_tcb->m_highTxMark;
1717 m_recoverActive = true;
1718
1720 m_tcb->m_congState = TcpSocketState::CA_RECOVERY;
1721
1722 // (4.2) ssthresh = cwnd = (FlightSize / 2)
1723 // If SACK is not enabled, still consider the head as 'in flight' for
1724 // compatibility with old ns-3 versions
1725 uint32_t bytesInFlight =
1726 m_sackEnabled ? BytesInFlight() : BytesInFlight() + m_tcb->m_segmentSize;
1727 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, bytesInFlight);
1728
1729 if (!m_congestionControl->HasCongControl())
1730 {
1731 m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1732 NS_LOG_INFO(m_dupAckCount << " dupack. Enter fast recovery mode."
1733 << "Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1734 << m_tcb->m_ssThresh << " at fast recovery seqnum " << m_recover
1735 << " calculated in flight: " << bytesInFlight);
1736 }
1737
1738 // (4.3) Retransmit the first data segment presumed dropped
1739 uint32_t sz = SendDataPacket(m_highRxAckMark, m_tcb->m_segmentSize, true);
1740 NS_ASSERT_MSG(sz > 0, "SendDataPacket returned zero, indicating zero bytes were sent");
1741 // (4.4) Run SetPipe ()
1742 // (4.5) Proceed to step (C)
1743 // these steps are done after the ProcessAck function (SendPendingData)
1744}
1745
1746void
1748{
1749 NS_LOG_FUNCTION(this);
1750 // NOTE: We do not count the DupAcks received in CA_LOSS, because we
1751 // don't know if they are generated by a spurious retransmission or because
1752 // of a real packet loss. With SACK, it is easy to know, but we do not consider
1753 // dupacks. Without SACK, there are some heuristics in the RFC 6582, but
1754 // for now, we do not implement it, leading to ignoring the dupacks.
1755 if (m_tcb->m_congState == TcpSocketState::CA_LOSS)
1756 {
1757 return;
1758 }
1759
1760 // RFC 6675, Section 5, 3rd paragraph:
1761 // If the incoming ACK is a duplicate acknowledgment per the definition
1762 // in Section 2 (regardless of its status as a cumulative
1763 // acknowledgment), and the TCP is not currently in loss recovery
1764 // the TCP MUST increase DupAcks by one ...
1765 if (m_tcb->m_congState != TcpSocketState::CA_RECOVERY)
1766 {
1767 ++m_dupAckCount;
1768 }
1769
1770 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
1771 {
1772 // From Open we go Disorder
1774 "From OPEN->DISORDER but with " << m_dupAckCount << " dup ACKs");
1775
1777 m_tcb->m_congState = TcpSocketState::CA_DISORDER;
1778
1779 NS_LOG_DEBUG("CA_OPEN -> CA_DISORDER");
1780 }
1781
1782 if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
1783 {
1784 if (!m_sackEnabled)
1785 {
1786 // If we are in recovery and we receive a dupack, one segment
1787 // has left the network. This is equivalent to a SACK of one block.
1788 m_txBuffer->AddRenoSack();
1789 }
1790 if (!m_congestionControl->HasCongControl())
1791 {
1792 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, true);
1793 NS_LOG_INFO(m_dupAckCount << " Dupack received in fast recovery mode."
1794 "Increase cwnd to "
1795 << m_tcb->m_cWnd);
1796 }
1797 }
1798 else if (m_tcb->m_congState == TcpSocketState::CA_DISORDER)
1799 {
1800 // m_dupackCount should not exceed its threshold in CA_DISORDER state
1801 // when m_recoverActive has not been set. When recovery point
1802 // have been set after timeout, the sender could enter into CA_DISORDER
1803 // after receiving new ACK smaller than m_recover. After that, m_dupackCount
1804 // can be equal and larger than m_retxThresh and we should avoid entering
1805 // CA_RECOVERY and reducing sending rate again.
1807
1808 // RFC 6675, Section 5, continuing:
1809 // ... and take the following steps:
1810 // (1) If DupAcks >= DupThresh, go to step (4).
1811 // Sequence number comparison (m_highRxAckMark >= m_recover) will take
1812 // effect only when m_recover has been set. Hence, we can avoid to use
1813 // m_recover in the last congestion event and fail to enter
1814 // CA_RECOVERY when sequence number is advanced significantly since
1815 // the last congestion event, which could be common for
1816 // bandwidth-greedy application in high speed and reliable network
1817 // (such as datacenter network) whose sending rate is constrained by
1818 // TCP socket buffer size at receiver side.
1819 if ((m_dupAckCount == m_retxThresh) &&
1821 {
1822 EnterRecovery(currentDelivered);
1824 }
1825 // (2) If DupAcks < DupThresh but IsLost (HighACK + 1) returns true
1826 // (indicating at least three segments have arrived above the current
1827 // cumulative acknowledgment point, which is taken to indicate loss)
1828 // go to step (4). Note that m_highRxAckMark is (HighACK + 1)
1829 else if (m_txBuffer->IsLost(m_highRxAckMark))
1830 {
1831 EnterRecovery(currentDelivered);
1833 }
1834 else
1835 {
1836 // (3) The TCP MAY transmit previously unsent data segments as per
1837 // Limited Transmit [RFC5681] ...except that the number of octets
1838 // which may be sent is governed by pipe and cwnd as follows:
1839 //
1840 // (3.1) Set HighRxt to HighACK.
1841 // Not clear in RFC. We don't do this here, since we still have
1842 // to retransmit the segment.
1843
1844 if (!m_sackEnabled && m_limitedTx)
1845 {
1846 m_txBuffer->AddRenoSack();
1847
1848 // In limited transmit, cwnd Infl is not updated.
1849 }
1850 }
1851 }
1852}
1853
1854/* Process the newly received ACK */
1855void
1857{
1858 NS_LOG_FUNCTION(this << tcpHeader);
1859
1860 NS_ASSERT(0 != (tcpHeader.GetFlags() & TcpHeader::ACK));
1861 NS_ASSERT(m_tcb->m_segmentSize > 0);
1862
1863 uint32_t previousLost = m_txBuffer->GetLost();
1864 uint32_t priorInFlight = m_tcb->m_bytesInFlight.Get();
1865
1866 // RFC 6675, Section 5, 1st paragraph:
1867 // Upon the receipt of any ACK containing SACK information, the
1868 // scoreboard MUST be updated via the Update () routine (done in ReadOptions)
1869 uint32_t bytesSacked = 0;
1870 uint64_t previousDelivered = m_rateOps->GetConnectionRate().m_delivered;
1871 ReadOptions(tcpHeader, &bytesSacked);
1872
1873 SequenceNumber32 ackNumber = tcpHeader.GetAckNumber();
1874 SequenceNumber32 oldHeadSequence = m_txBuffer->HeadSequence();
1875
1876 if (ackNumber < oldHeadSequence)
1877 {
1878 NS_LOG_DEBUG("Possibly received a stale ACK (ack number < head sequence)");
1879 // If there is any data piggybacked, store it into m_rxBuffer
1880 if (packet->GetSize() > 0)
1881 {
1882 ReceivedData(packet, tcpHeader);
1883 }
1884 return;
1885 }
1886 if ((ackNumber > oldHeadSequence) && (ackNumber < m_recover) &&
1887 (m_tcb->m_congState == TcpSocketState::CA_RECOVERY))
1888 {
1889 uint32_t segAcked = (ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
1890 for (uint32_t i = 0; i < segAcked; i++)
1891 {
1892 if (m_txBuffer->IsRetransmittedDataAcked(ackNumber - (i * m_tcb->m_segmentSize)))
1893 {
1894 m_tcb->m_isRetransDataAcked = true;
1895 NS_LOG_DEBUG("Ack Number " << ackNumber << "is ACK of retransmitted packet.");
1896 }
1897 }
1898 }
1899
1900 m_txBuffer->DiscardUpTo(ackNumber, MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
1901
1902 auto currentDelivered =
1903 static_cast<uint32_t>(m_rateOps->GetConnectionRate().m_delivered - previousDelivered);
1904 m_tcb->m_lastAckedSackedBytes = currentDelivered;
1905
1906 if (m_tcb->m_congState == TcpSocketState::CA_CWR && (ackNumber > m_recover))
1907 {
1908 // Recovery is over after the window exceeds m_recover
1909 // (although it may be re-entered below if ECE is still set)
1910 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_OPEN");
1911 m_tcb->m_congState = TcpSocketState::CA_OPEN;
1912 if (!m_congestionControl->HasCongControl())
1913 {
1914 m_tcb->m_cWnd = m_tcb->m_ssThresh.Get();
1915 m_recoveryOps->ExitRecovery(m_tcb);
1917 }
1918 }
1919
1920 if (ackNumber > oldHeadSequence && (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED) &&
1921 (tcpHeader.GetFlags() & TcpHeader::ECE))
1922 {
1923 if (m_ecnEchoSeq < ackNumber)
1924 {
1925 NS_LOG_INFO("Received ECN Echo is valid");
1926 m_ecnEchoSeq = ackNumber;
1927 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_RCVD");
1928 m_tcb->m_ecnState = TcpSocketState::ECN_ECE_RCVD;
1929 if (m_tcb->m_congState != TcpSocketState::CA_CWR)
1930 {
1931 EnterCwr(currentDelivered);
1932 }
1933 }
1934 }
1935 else if (m_tcb->m_ecnState == TcpSocketState::ECN_ECE_RCVD &&
1936 !(tcpHeader.GetFlags() & TcpHeader::ECE))
1937 {
1938 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
1939 }
1940
1941 // Update bytes in flight before processing the ACK for proper calculation of congestion window
1942 NS_LOG_INFO("Update bytes in flight before processing the ACK.");
1943 BytesInFlight();
1944
1945 bool receivedData = packet->GetSize() > 0;
1946
1947 // RFC 6675 Section 5: 2nd, 3rd paragraph and point (A), (B) implementation
1948 // are inside the function ProcessAck
1949 ProcessAck(ackNumber, (bytesSacked > 0), currentDelivered, oldHeadSequence, receivedData);
1950 m_tcb->m_isRetransDataAcked = false;
1951
1952 if (m_congestionControl->HasCongControl())
1953 {
1954 uint32_t currentLost = m_txBuffer->GetLost();
1955 uint32_t lost =
1956 (currentLost > previousLost) ? currentLost - previousLost : previousLost - currentLost;
1957 auto rateSample = m_rateOps->GenerateSample(currentDelivered,
1958 lost,
1959 false,
1960 priorInFlight,
1961 m_tcb->m_minRtt);
1962 auto rateConn = m_rateOps->GetConnectionRate();
1963 m_congestionControl->CongControl(m_tcb, rateConn, rateSample);
1964 }
1965
1966 // If there is any data piggybacked, store it into m_rxBuffer
1967 if (receivedData)
1968 {
1969 ReceivedData(packet, tcpHeader);
1970 }
1971
1972 // RFC 6675, Section 5, point (C), try to send more data. NB: (C) is implemented
1973 // inside SendPendingData
1975}
1976
1977void
1979 bool scoreboardUpdated,
1980 uint32_t currentDelivered,
1981 const SequenceNumber32& oldHeadSequence,
1982 bool receivedData)
1983{
1984 NS_LOG_FUNCTION(this << ackNumber << scoreboardUpdated << currentDelivered << oldHeadSequence);
1985 // RFC 6675, Section 5, 2nd paragraph:
1986 // If the incoming ACK is a cumulative acknowledgment, the TCP MUST
1987 // reset DupAcks to zero.
1988 bool exitedFastRecovery = false;
1989 uint32_t oldDupAckCount = m_dupAckCount; // remember the old value
1990 m_tcb->m_lastAckedSeq = ackNumber; // Update lastAckedSeq
1991 uint32_t bytesAcked = 0;
1992
1993 /* In RFC 5681 the definition of duplicate acknowledgment was strict:
1994 *
1995 * (a) the receiver of the ACK has outstanding data,
1996 * (b) the incoming acknowledgment carries no data,
1997 * (c) the SYN and FIN bits are both off,
1998 * (d) the acknowledgment number is equal to the greatest acknowledgment
1999 * received on the given connection (TCP.UNA from [RFC793]),
2000 * (e) the advertised window in the incoming acknowledgment equals the
2001 * advertised window in the last incoming acknowledgment.
2002 *
2003 * With RFC 6675, this definition has been reduced:
2004 *
2005 * (a) the ACK is carrying a SACK block that identifies previously
2006 * unacknowledged and un-SACKed octets between HighACK (TCP.UNA) and
2007 * HighData (m_highTxMark)
2008 *
2009 * The check below implements conditions a), b), and d), and c) is prevented by virtue of not
2010 * reaching this code if SYN or FIN is set, and e) is not supported.
2011 */
2012
2013 bool isDupack = m_sackEnabled ? scoreboardUpdated
2014 : (ackNumber == oldHeadSequence &&
2015 ackNumber < m_tcb->m_highTxMark && !receivedData);
2016
2017 NS_LOG_DEBUG("ACK of " << ackNumber << " SND.UNA=" << oldHeadSequence
2018 << " SND.NXT=" << m_tcb->m_nextTxSequence
2019 << " in state: " << TcpSocketState::TcpCongStateName[m_tcb->m_congState]
2020 << " with m_recover: " << m_recover);
2021
2022 // RFC 6675, Section 5, 3rd paragraph:
2023 // If the incoming ACK is a duplicate acknowledgment per the definition
2024 // in Section 2 (regardless of its status as a cumulative
2025 // acknowledgment), and the TCP is not currently in loss recovery
2026 if (isDupack)
2027 {
2028 // loss recovery check is done inside this function thanks to
2029 // the congestion state machine
2030 DupAck(currentDelivered);
2031 }
2032
2033 if (ackNumber == oldHeadSequence && ackNumber == m_tcb->m_highTxMark)
2034 {
2035 // Dupack, but the ACK is precisely equal to the nextTxSequence
2036 return;
2037 }
2038 else if (ackNumber == oldHeadSequence && ackNumber > m_tcb->m_highTxMark)
2039 {
2040 // ACK of the FIN bit ... nextTxSequence is not updated since we
2041 // don't have anything to transmit
2042 NS_LOG_DEBUG("Update nextTxSequence manually to " << ackNumber);
2043 m_tcb->m_nextTxSequence = ackNumber;
2044 }
2045 else if (ackNumber == oldHeadSequence)
2046 {
2047 // DupAck. Artificially call PktsAcked: after all, one segment has been ACKed.
2048 m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_srtt);
2049 }
2050 else if (ackNumber > oldHeadSequence)
2051 {
2052 // Please remember that, with SACK, we can enter here even if we
2053 // received a dupack.
2054 bytesAcked = currentDelivered;
2055 uint32_t segsAcked = bytesAcked / m_tcb->m_segmentSize;
2056 m_bytesAckedNotProcessed += bytesAcked % m_tcb->m_segmentSize;
2057 bytesAcked -= bytesAcked % m_tcb->m_segmentSize;
2058
2059 if (m_bytesAckedNotProcessed >= m_tcb->m_segmentSize)
2060 {
2061 segsAcked += 1;
2062 bytesAcked += m_tcb->m_segmentSize;
2063 m_bytesAckedNotProcessed -= m_tcb->m_segmentSize;
2064 }
2065 NS_LOG_DEBUG("Set segsAcked: " << segsAcked
2066 << " based on currentDelivered: " << currentDelivered);
2067
2068 // Dupack count is reset to eventually fast-retransmit after 3 dupacks.
2069 // Any SACK-ed segment will be cleaned up by DiscardUpTo.
2070 // In the case that we advanced SND.UNA, but the ack contains SACK blocks,
2071 // we do not reset. At the third one we will retransmit.
2072 // If we are already in recovery, this check is useless since dupAcks
2073 // are not considered in this phase. When from Recovery we go back
2074 // to open, then dupAckCount is reset anyway.
2075 if (!isDupack)
2076 {
2077 m_dupAckCount = 0;
2078 }
2079
2080 // RFC 6675, Section 5, part (B)
2081 // (B) Upon receipt of an ACK that does not cover RecoveryPoint, the
2082 // following actions MUST be taken:
2083 //
2084 // (B.1) Use Update () to record the new SACK information conveyed
2085 // by the incoming ACK.
2086 // (B.2) Use SetPipe () to re-calculate the number of octets still
2087 // in the network.
2088 //
2089 // (B.1) is done at the beginning, while (B.2) is delayed to part (C) while
2090 // trying to transmit with SendPendingData. We are not allowed to exit
2091 // the CA_RECOVERY phase. Just process this partial ack (RFC 5681)
2092 if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
2093 {
2094 if (!m_sackEnabled)
2095 {
2096 // Manually set the head as lost, it will be retransmitted.
2097 NS_LOG_INFO("Partial ACK. Manually setting head as lost");
2098 m_txBuffer->MarkHeadAsLost();
2099 }
2100
2101 // Before retransmitting the packet perform DoRecovery and check if
2102 // there is available window
2103 if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2104 {
2105 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, false);
2106 }
2107
2108 // If the packet is already retransmitted do not retransmit it
2109 if (!m_txBuffer->IsRetransmittedDataAcked(ackNumber + m_tcb->m_segmentSize))
2110 {
2111 DoRetransmit(); // Assume the next seq is lost. Retransmit lost packet
2112 m_tcb->m_cWndInfl = SafeSubtraction(m_tcb->m_cWndInfl, bytesAcked);
2113 }
2114
2115 // This partial ACK acknowledge the fact that one segment has been
2116 // previously lost and now successfully received. All others have
2117 // been processed when they come under the form of dupACKs
2118 m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_srtt);
2119 NewAck(ackNumber, m_isFirstPartialAck);
2120
2122 {
2123 NS_LOG_DEBUG("Partial ACK of " << ackNumber
2124 << " and this is the first (RTO will be reset);"
2125 " cwnd set to "
2126 << m_tcb->m_cWnd << " recover seq: " << m_recover
2127 << " dupAck count: " << m_dupAckCount);
2128 m_isFirstPartialAck = false;
2129 }
2130 else
2131 {
2132 NS_LOG_DEBUG("Partial ACK of "
2133 << ackNumber
2134 << " and this is NOT the first (RTO will not be reset)"
2135 " cwnd set to "
2136 << m_tcb->m_cWnd << " recover seq: " << m_recover
2137 << " dupAck count: " << m_dupAckCount);
2138 }
2139 }
2140 // From RFC 6675 section 5.1
2141 // In addition, a new recovery phase (as described in Section 5) MUST NOT
2142 // be initiated until HighACK is greater than or equal to the new value
2143 // of RecoveryPoint.
2144 else if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_LOSS)
2145 {
2146 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2147 m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2148
2149 NS_LOG_DEBUG(" Cong Control Called, cWnd=" << m_tcb->m_cWnd
2150 << " ssTh=" << m_tcb->m_ssThresh);
2151 if (!m_sackEnabled)
2152 {
2154 m_txBuffer->GetSacked() == 0,
2155 "Some segment got dup-acked in CA_LOSS state: " << m_txBuffer->GetSacked());
2156 }
2157 NewAck(ackNumber, true);
2158 }
2159 else if (m_tcb->m_congState == TcpSocketState::CA_CWR)
2160 {
2161 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2162 // TODO: need to check behavior if marking is compounded by loss
2163 // and/or packet reordering
2164 if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2165 {
2166 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, false);
2167 }
2168 NewAck(ackNumber, true);
2169 }
2170 else
2171 {
2172 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
2173 {
2174 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2175 }
2176 else if (m_tcb->m_congState == TcpSocketState::CA_DISORDER)
2177 {
2178 if (segsAcked >= oldDupAckCount)
2179 {
2180 m_congestionControl->PktsAcked(m_tcb,
2181 segsAcked - oldDupAckCount,
2182 m_tcb->m_srtt);
2183 }
2184
2185 if (!isDupack)
2186 {
2187 // The network reorder packets. Linux changes the counting lost
2188 // packet algorithm from FACK to NewReno. We simply go back in Open.
2190 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2191 NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2192 << " exiting CA_DISORDER -> CA_OPEN");
2193 }
2194 else
2195 {
2196 NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2197 << " but still in CA_DISORDER");
2198 }
2199 }
2200 // RFC 6675, Section 5:
2201 // Once a TCP is in the loss recovery phase, the following procedure
2202 // MUST be used for each arriving ACK:
2203 // (A) An incoming cumulative ACK for a sequence number greater than
2204 // RecoveryPoint signals the end of loss recovery, and the loss
2205 // recovery phase MUST be terminated. Any information contained in
2206 // the scoreboard for sequence numbers greater than the new value of
2207 // HighACK SHOULD NOT be cleared when leaving the loss recovery
2208 // phase.
2209 else if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
2210 {
2211 m_isFirstPartialAck = true;
2212
2213 // Recalculate the segs acked, that are from m_recover to ackNumber
2214 // (which are the ones we have not passed to PktsAcked and that
2215 // can increase cWnd)
2216 // TODO: check consistency for dynamic segment size
2217 segsAcked =
2218 static_cast<uint32_t>(ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
2219 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2222 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2223 exitedFastRecovery = true;
2224 m_dupAckCount = 0; // From recovery to open, reset dupack
2225
2226 NS_LOG_DEBUG(segsAcked << " segments acked in CA_RECOVER, ack of " << ackNumber
2227 << ", exiting CA_RECOVERY -> CA_OPEN");
2228 }
2229 else if (m_tcb->m_congState == TcpSocketState::CA_LOSS)
2230 {
2231 m_isFirstPartialAck = true;
2232
2233 // Recalculate the segs acked, that are from m_recover to ackNumber
2234 // (which are the ones we have not passed to PktsAcked and that
2235 // can increase cWnd)
2236 segsAcked = (ackNumber - m_recover) / m_tcb->m_segmentSize;
2237
2238 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2239
2241 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2242 NS_LOG_DEBUG(segsAcked << " segments acked in CA_LOSS, ack of" << ackNumber
2243 << ", exiting CA_LOSS -> CA_OPEN");
2244 }
2245
2246 if (ackNumber >= m_recover)
2247 {
2248 // All lost segments in the congestion event have been
2249 // retransmitted successfully. The recovery point (m_recover)
2250 // should be deactivated.
2251 m_recoverActive = false;
2252 }
2253
2254 if (exitedFastRecovery)
2255 {
2256 NewAck(ackNumber, true);
2257 m_tcb->m_cWnd = m_tcb->m_ssThresh.Get();
2258 m_recoveryOps->ExitRecovery(m_tcb);
2259 NS_LOG_DEBUG("Leaving Fast Recovery; BytesInFlight() = "
2260 << BytesInFlight() << "; cWnd = " << m_tcb->m_cWnd);
2261 }
2262 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
2263 {
2264 m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2265
2266 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
2267
2268 NS_LOG_LOGIC("Congestion control called: cWnd: " << m_tcb->m_cWnd
2269 << " ssTh: " << m_tcb->m_ssThresh
2270 << " segsAcked: " << segsAcked);
2271
2272 NewAck(ackNumber, true);
2273 }
2274 }
2275 }
2276 // Update the pacing rate, since m_congestionControl->IncreaseWindow() or
2277 // m_congestionControl->PktsAcked () may change m_tcb->m_cWnd
2278 // Make sure that control reaches the end of this function and there is no
2279 // return in between
2281}
2282
2283/* Received a packet upon LISTEN state. */
2284void
2286 const TcpHeader& tcpHeader,
2287 const Address& fromAddress,
2288 const Address& toAddress)
2289{
2290 NS_LOG_FUNCTION(this << tcpHeader);
2291
2292 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2293 uint8_t tcpflags =
2295
2296 // Fork a socket if received a SYN. Do nothing otherwise.
2297 // C.f.: the LISTEN part in tcp_v4_do_rcv() in tcp_ipv4.c in Linux kernel
2298 if (tcpflags != TcpHeader::SYN)
2299 {
2300 return;
2301 }
2302
2303 // Call socket's notify function to let the server app know we got a SYN
2304 // If the server app refuses the connection, do nothing
2305 if (!NotifyConnectionRequest(fromAddress))
2306 {
2307 return;
2308 }
2309 // Clone the socket, simulate fork
2310 Ptr<TcpSocketBase> newSock = Fork();
2311 NS_LOG_LOGIC("Cloned a TcpSocketBase " << newSock);
2313 newSock,
2314 packet,
2315 tcpHeader,
2316 fromAddress,
2317 toAddress);
2318}
2319
2320/* Received a packet upon SYN_SENT */
2321void
2323{
2324 NS_LOG_FUNCTION(this << tcpHeader);
2325
2326 // Extract the flags. PSH and URG are disregarded.
2327 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2328
2329 if (tcpflags == 0)
2330 { // Bare data, accept it and move to ESTABLISHED state. This is not a normal behaviour. Remove
2331 // this?
2332 NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2334 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2336 m_connected = true;
2337 m_retxEvent.Cancel();
2339 ReceivedData(packet, tcpHeader);
2341 }
2342 else if (tcpflags & TcpHeader::ACK && !(tcpflags & TcpHeader::SYN))
2343 { // Ignore ACK in SYN_SENT
2344 }
2345 else if (tcpflags & TcpHeader::SYN && !(tcpflags & TcpHeader::ACK))
2346 { // Received SYN, move to SYN_RCVD state and respond with SYN+ACK
2347 NS_LOG_DEBUG("SYN_SENT -> SYN_RCVD");
2348 m_state = SYN_RCVD;
2350 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2351 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2352 * the traffic is ECN capable and sender has sent ECN SYN packet
2353 */
2354
2355 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2357 {
2358 NS_LOG_INFO("Received ECN SYN packet");
2360 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2361 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2362 }
2363 else
2364 {
2365 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2367 }
2368 }
2369 else if (tcpflags & (TcpHeader::SYN | TcpHeader::ACK) &&
2370 m_tcb->m_nextTxSequence + SequenceNumber32(1) == tcpHeader.GetAckNumber())
2371 { // Handshake completed
2372 NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2374 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2376 m_connected = true;
2377 m_retxEvent.Cancel();
2378 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2379 m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
2380 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2381 // Before sending packets, update the pacing rate based on RTT measurement so far
2384
2385 /* Check if we received an ECN SYN-ACK packet. Change the ECN state of sender to ECN_IDLE if
2386 * receiver has sent an ECN SYN-ACK packet and the traffic is ECN Capable
2387 */
2388 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2389 (tcpflags & (TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::ECE))
2390 {
2391 NS_LOG_INFO("Received ECN SYN-ACK packet.");
2392 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2393 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2394 }
2395 else
2396 {
2397 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2398 }
2401 // Always respond to first data packet to speed up the connection.
2402 // Remove to get the behaviour of old NS-3 code.
2404 }
2405 else
2406 { // Other in-sequence input
2407 if (!(tcpflags & TcpHeader::RST))
2408 { // When (1) rx of FIN+ACK; (2) rx of FIN; (3) rx of bad flags
2409 NS_LOG_LOGIC("Illegal flag combination "
2410 << TcpHeader::FlagsToString(tcpHeader.GetFlags())
2411 << " received in SYN_SENT. Reset packet is sent.");
2412 SendRST();
2413 }
2415 }
2416}
2417
2418/* Received a packet upon SYN_RCVD */
2419void
2421 const TcpHeader& tcpHeader,
2422 const Address& fromAddress,
2423 const Address& /* toAddress */)
2424{
2425 NS_LOG_FUNCTION(this << tcpHeader);
2426
2427 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2428 uint8_t tcpflags =
2430
2431 if (tcpflags == 0 ||
2432 (tcpflags == TcpHeader::ACK &&
2433 m_tcb->m_nextTxSequence + SequenceNumber32(1) == tcpHeader.GetAckNumber()))
2434 { // If it is bare data, accept it and move to ESTABLISHED state. This is
2435 // possibly due to ACK lost in 3WHS. If in-sequence ACK is received, the
2436 // handshake is completed nicely.
2437 NS_LOG_DEBUG("SYN_RCVD -> ESTABLISHED");
2439 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2441 m_connected = true;
2442 m_retxEvent.Cancel();
2443 m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
2444 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2445 if (m_endPoint)
2446 {
2447 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2448 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2449 }
2450 else if (m_endPoint6)
2451 {
2452 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2453 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2454 }
2455 // Always respond to first data packet to speed up the connection.
2456 // Remove to get the behaviour of old NS-3 code.
2458 NotifyNewConnectionCreated(this, fromAddress);
2459 ReceivedAck(packet, tcpHeader);
2460 // Update the pacing rate based on RTT measurement so far
2462 // As this connection is established, the socket is available to send data now
2463 if (GetTxAvailable() > 0)
2464 {
2466 }
2467 }
2468 else if (tcpflags == TcpHeader::SYN)
2469 { // Probably the peer lost my SYN+ACK
2470 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2471 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2472 * sender has sent an ECN SYN packet and the traffic is ECN Capable
2473 */
2474 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2475 (tcpHeader.GetFlags() & (TcpHeader::CWR | TcpHeader::ECE)) ==
2477 {
2478 NS_LOG_INFO("Received ECN SYN packet");
2480 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2481 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2482 }
2483 else
2484 {
2485 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2487 }
2488 }
2489 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2490 {
2491 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2492 { // In-sequence FIN before connection complete. Set up connection and close.
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 NotifyNewConnectionCreated(this, fromAddress);
2508 PeerClose(packet, tcpHeader);
2509 }
2510 }
2511 else
2512 { // Other in-sequence input
2513 if (tcpflags != TcpHeader::RST)
2514 { // When (1) rx of SYN+ACK; (2) rx of FIN; (3) rx of bad flags
2515 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2516 << " received. Reset packet is sent.");
2517 if (m_endPoint)
2518 {
2519 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2520 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2521 }
2522 else if (m_endPoint6)
2523 {
2524 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2525 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2526 }
2527 SendRST();
2528 }
2530 }
2531}
2532
2533/* Received a packet upon CLOSE_WAIT, FIN_WAIT_1, or FIN_WAIT_2 states */
2534void
2536{
2537 NS_LOG_FUNCTION(this << tcpHeader);
2538
2539 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2540 uint8_t tcpflags =
2542
2543 if (packet->GetSize() > 0 && !(tcpflags & TcpHeader::ACK))
2544 { // Bare data, accept it
2545 ReceivedData(packet, tcpHeader);
2546 }
2547 else if (tcpflags == TcpHeader::ACK)
2548 { // Process the ACK, and if in FIN_WAIT_1, conditionally move to FIN_WAIT_2
2549 ReceivedAck(packet, tcpHeader);
2550 if (m_state == FIN_WAIT_1 && m_txBuffer->Size() == 0 &&
2551 tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2552 { // This ACK corresponds to the FIN sent
2553 NS_LOG_DEBUG("FIN_WAIT_1 -> FIN_WAIT_2");
2555 }
2556 }
2557 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2558 { // Got FIN, respond with ACK and move to next state
2559 if (tcpflags & TcpHeader::ACK)
2560 { // Process the ACK first
2561 ReceivedAck(packet, tcpHeader);
2562 }
2563 m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber());
2564 }
2565 else if (tcpflags == TcpHeader::SYN || tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
2566 { // Duplicated SYN or SYN+ACK, possibly due to spurious retransmission
2567 return;
2568 }
2569 else
2570 { // This is a RST or bad flags
2571 if (tcpflags != TcpHeader::RST)
2572 {
2573 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2574 << " received. Reset packet is sent.");
2575 SendRST();
2576 }
2578 return;
2579 }
2580
2581 // Check if the close responder sent an in-sequence FIN, if so, respond ACK
2582 if ((m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2) && m_tcb->m_rxBuffer->Finished())
2583 {
2584 if (m_state == FIN_WAIT_1)
2585 {
2586 NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2587 m_state = CLOSING;
2588 if (m_txBuffer->Size() == 0 &&
2589 tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2590 { // This ACK corresponds to the FIN sent
2591 TimeWait();
2592 }
2593 }
2594 else if (m_state == FIN_WAIT_2)
2595 {
2596 TimeWait();
2597 }
2599 if (!m_shutdownRecv)
2600 {
2602 }
2603 }
2604}
2605
2606/* Received a packet upon CLOSING */
2607void
2609{
2610 NS_LOG_FUNCTION(this << tcpHeader);
2611
2612 // Extract the flags. PSH and URG are disregarded.
2613 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2614
2615 if (tcpflags == TcpHeader::ACK)
2616 {
2617 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2618 { // This ACK corresponds to the FIN sent
2619 TimeWait();
2620 }
2621 }
2622 else
2623 { // CLOSING state means simultaneous close, i.e. no one is sending data to
2624 // anyone. If anything other than ACK is received, respond with a reset.
2625 if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2626 { // FIN from the peer as well. We can close immediately.
2628 }
2629 else if (tcpflags != TcpHeader::RST)
2630 { // Receive of SYN or SYN+ACK or bad flags or pure data
2631 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2632 << " received. Reset packet is sent.");
2633 SendRST();
2634 }
2636 }
2637}
2638
2639/* Received a packet upon LAST_ACK */
2640void
2642{
2643 NS_LOG_FUNCTION(this << tcpHeader);
2644
2645 // Extract the flags. PSH and URG are disregarded.
2646 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2647
2648 if (tcpflags == 0)
2649 {
2650 ReceivedData(packet, tcpHeader);
2651 }
2652 else if (tcpflags == TcpHeader::ACK)
2653 {
2654 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2655 { // This ACK corresponds to the FIN sent. This socket closed peacefully.
2657 }
2658 }
2659 else if (tcpflags == TcpHeader::FIN)
2660 { // Received FIN again, the peer probably lost the FIN+ACK
2662 }
2663 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK) || tcpflags == TcpHeader::RST)
2664 {
2666 }
2667 else
2668 { // Received a SYN or SYN+ACK or bad flags
2669 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2670 << " received. Reset packet is sent.");
2671 SendRST();
2673 }
2674}
2675
2676/* Peer sent me a FIN. Remember its sequence in rx buffer. */
2677void
2679{
2680 NS_LOG_FUNCTION(this << tcpHeader);
2681
2682 // Ignore all out of range packets
2683 if (tcpHeader.GetSequenceNumber() < m_tcb->m_rxBuffer->NextRxSequence() ||
2684 tcpHeader.GetSequenceNumber() > m_tcb->m_rxBuffer->MaxRxSequence())
2685 {
2686 return;
2687 }
2688 // For any case, remember the FIN position in rx buffer first
2689 m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber() +
2690 SequenceNumber32(p->GetSize()));
2691 NS_LOG_LOGIC("Accepted FIN at seq "
2692 << tcpHeader.GetSequenceNumber() + SequenceNumber32(p->GetSize()));
2693 // If there is any piggybacked data, process it
2694 if (p->GetSize())
2695 {
2696 ReceivedData(p, tcpHeader);
2697 }
2698 // Return if FIN is out of sequence, otherwise move to CLOSE_WAIT state by DoPeerClose
2699 if (!m_tcb->m_rxBuffer->Finished())
2700 {
2701 return;
2702 }
2703
2704 // Simultaneous close: Application invoked Close() when we are processing this FIN packet
2705 if (m_state == FIN_WAIT_1)
2706 {
2707 NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2708 m_state = CLOSING;
2709 return;
2710 }
2711
2712 DoPeerClose(); // Change state, respond with ACK
2713}
2714
2715/* Received a in-sequence FIN. Close down this socket. */
2716void
2718{
2720 m_state == FIN_WAIT_2);
2721
2722 // Move the state to CLOSE_WAIT
2723 NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSE_WAIT");
2725
2726 if (!m_closeNotified)
2727 {
2728 // The normal behaviour for an application is that, when the peer sent a in-sequence
2729 // FIN, the app should prepare to close. The app has two choices at this point: either
2730 // respond with ShutdownSend() call to declare that it has nothing more to send and
2731 // the socket can be closed immediately; or remember the peer's close request, wait
2732 // until all its existing data are pushed into the TCP socket, then call Close()
2733 // explicitly.
2734 NS_LOG_LOGIC("TCP " << this << " calling NotifyNormalClose");
2736 m_closeNotified = true;
2737 }
2738 if (m_shutdownSend)
2739 { // The application declares that it would not sent any more, close this socket
2740 Close();
2741 }
2742 else
2743 { // Need to ack, the application will close later
2745 }
2746 if (m_state == LAST_ACK)
2747 {
2748 m_dataRetrCount = m_dataRetries; // prevent endless FINs
2749 NS_LOG_LOGIC("TcpSocketBase " << this << " scheduling LATO1");
2750 Time lastRto = m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4);
2752 }
2753}
2754
2755/* Kill this socket. This is a callback function configured to m_endpoint in
2756 SetupCallback(), invoked when the endpoint is destroyed. */
2757void
2759{
2760 NS_LOG_FUNCTION(this);
2761 m_endPoint = nullptr;
2762 if (m_tcp)
2763 {
2764 m_tcp->RemoveSocket(this);
2765 }
2766 NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2767 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2769}
2770
2771/* Kill this socket. This is a callback function configured to m_endpoint in
2772 SetupCallback(), invoked when the endpoint is destroyed. */
2773void
2775{
2776 NS_LOG_FUNCTION(this);
2777 m_endPoint6 = nullptr;
2778 if (m_tcp)
2779 {
2780 m_tcp->RemoveSocket(this);
2781 }
2782 NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2783 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2785}
2786
2787/* Send an empty packet with specified TCP flags */
2788void
2790{
2791 NS_LOG_FUNCTION(this << static_cast<uint32_t>(flags));
2792
2793 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
2794 {
2795 NS_LOG_WARN("Failed to send empty packet due to null endpoint");
2796 return;
2797 }
2798
2800 TcpHeader header;
2801 SequenceNumber32 s = m_tcb->m_nextTxSequence;
2802 TcpPacketType_t packetType = INVALID;
2803
2804 if (flags & TcpHeader::FIN)
2805 {
2806 packetType = TcpPacketType_t::FIN;
2807 flags |= TcpHeader::ACK;
2808 }
2809 else if (m_state == FIN_WAIT_1 || m_state == LAST_ACK || m_state == CLOSING)
2810 {
2811 ++s;
2812 }
2813
2814 if (flags & TcpHeader::SYN)
2815 {
2816 packetType = TcpPacketType_t::SYN;
2817 if (flags & TcpHeader::ACK)
2818 {
2819 packetType = TcpPacketType_t::SYN_ACK;
2820 }
2821 }
2822 else if (flags & TcpHeader::ACK)
2823 {
2824 packetType = TcpPacketType_t::PURE_ACK;
2825 }
2826
2827 if (flags & TcpHeader::RST)
2828 {
2829 packetType = TcpPacketType_t::RST;
2830 }
2831
2832 NS_ASSERT_MSG(packetType != TcpPacketType_t::INVALID, "Invalid TCP packet type");
2833 AddSocketTags(p, IsEct(packetType));
2834
2835 header.SetFlags(flags);
2836 header.SetSequenceNumber(s);
2837 header.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
2838 if (m_endPoint != nullptr)
2839 {
2840 header.SetSourcePort(m_endPoint->GetLocalPort());
2841 header.SetDestinationPort(m_endPoint->GetPeerPort());
2842 }
2843 else
2844 {
2845 header.SetSourcePort(m_endPoint6->GetLocalPort());
2846 header.SetDestinationPort(m_endPoint6->GetPeerPort());
2847 }
2848 AddOptions(header);
2849
2850 // RFC 6298, clause 2.4
2851 m_rto =
2852 Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4), m_minRto);
2853
2854 uint16_t windowSize = AdvertisedWindowSize();
2855 bool hasSyn = flags & TcpHeader::SYN;
2856 bool hasFin = flags & TcpHeader::FIN;
2857 bool isAck = flags == TcpHeader::ACK;
2858 if (hasSyn)
2859 {
2861 { // The window scaling option is set only on SYN packets
2862 AddOptionWScale(header);
2863 }
2864
2865 if (m_sackEnabled)
2866 {
2867 AddOptionSackPermitted(header);
2868 }
2869
2870 if (m_synCount == 0)
2871 { // No more connection retries, give up
2872 NS_LOG_LOGIC("Connection failed.");
2873 m_rtt->Reset(); // According to recommendation -> RFC 6298
2875 m_state = CLOSED;
2877 return;
2878 }
2879 else
2880 { // Exponential backoff of connection time out
2881 int backoffCount = 0x1 << (m_synRetries - m_synCount);
2882 m_rto = m_cnTimeout * backoffCount;
2883 m_synCount--;
2884 }
2885
2886 if (m_synRetries - 1 == m_synCount)
2887 {
2888 UpdateRttHistory(s, 0, false);
2889 }
2890 else
2891 { // This is SYN retransmission
2892 UpdateRttHistory(s, 0, true);
2893 }
2894
2895 windowSize = AdvertisedWindowSize(false);
2896 }
2897 header.SetWindowSize(windowSize);
2898
2899 if (flags & TcpHeader::ACK)
2900 { // If sending an ACK, cancel the delay ACK as well
2901 m_delAckEvent.Cancel();
2902 m_delAckCount = 0;
2903 if (m_highTxAck < header.GetAckNumber())
2904 {
2905 m_highTxAck = header.GetAckNumber();
2906 }
2907 if (m_sackEnabled && m_tcb->m_rxBuffer->GetSackListSize() > 0)
2908 {
2909 AddOptionSack(header);
2910 }
2911 NS_LOG_INFO("Sending a pure ACK, acking seq " << m_tcb->m_rxBuffer->NextRxSequence());
2912 }
2913
2914 m_txTrace(p, header, this);
2915
2916 if (m_endPoint != nullptr)
2917 {
2918 m_tcp->SendPacket(p,
2919 header,
2920 m_endPoint->GetLocalAddress(),
2921 m_endPoint->GetPeerAddress(),
2923 }
2924 else
2925 {
2926 m_tcp->SendPacket(p,
2927 header,
2928 m_endPoint6->GetLocalAddress(),
2929 m_endPoint6->GetPeerAddress(),
2931 }
2932
2933 if (m_retxEvent.IsExpired() && (hasSyn || hasFin) && !isAck)
2934 { // Retransmit SYN / SYN+ACK / FIN / FIN+ACK to guard against lost
2935 NS_LOG_LOGIC("Schedule retransmission timeout at time "
2936 << Simulator::Now().GetSeconds() << " to expire at time "
2937 << (Simulator::Now() + m_rto.Get()).GetSeconds());
2939 }
2940}
2941
2942/* This function closes the endpoint completely. Called upon RST_TX action. */
2943void
2951
2952/* Deallocate the end point and cancel all the timers */
2953void
2955{
2956 // note: it shouldn't be necessary to invalidate the callback and manually call
2957 // TcpL4Protocol::RemoveSocket. Alas, if one relies on the endpoint destruction
2958 // callback, there's a weird memory access to a free'd area. Harmless, but valgrind
2959 // considers it an error.
2960
2961 if (m_endPoint != nullptr)
2962 {
2964 m_endPoint->SetDestroyCallback(MakeNullCallback<void>());
2965 m_tcp->DeAllocate(m_endPoint);
2966 m_endPoint = nullptr;
2967 m_tcp->RemoveSocket(this);
2968 }
2969 else if (m_endPoint6 != nullptr)
2970 {
2972 m_endPoint6->SetDestroyCallback(MakeNullCallback<void>());
2973 m_tcp->DeAllocate(m_endPoint6);
2974 m_endPoint6 = nullptr;
2975 m_tcp->RemoveSocket(this);
2976 }
2977}
2978
2979/* Configure the endpoint to a local address. Called by Connect() if Bind() didn't specify one. */
2980int
2982{
2983 NS_LOG_FUNCTION(this);
2984 Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4>();
2985 NS_ASSERT(ipv4);
2986 if (!ipv4->GetRoutingProtocol())
2987 {
2988 NS_FATAL_ERROR("No Ipv4RoutingProtocol in the node");
2989 }
2990 // Create a dummy packet, then ask the routing function for the best output
2991 // interface's address
2992 Ipv4Header header;
2993 header.SetDestination(m_endPoint->GetPeerAddress());
2994 Socket::SocketErrno errno_;
2995 Ptr<Ipv4Route> route;
2997 route = ipv4->GetRoutingProtocol()->RouteOutput(Ptr<Packet>(), header, oif, errno_);
2998 if (!route)
2999 {
3000 NS_LOG_LOGIC("Route to " << m_endPoint->GetPeerAddress() << " does not exist");
3001 NS_LOG_ERROR(errno_);
3002 m_errno = errno_;
3003 return -1;
3004 }
3005 NS_LOG_LOGIC("Route exists");
3006 m_endPoint->SetLocalAddress(route->GetSource());
3007 return 0;
3008}
3009
3010int
3012{
3013 NS_LOG_FUNCTION(this);
3014 Ptr<Ipv6L3Protocol> ipv6 = m_node->GetObject<Ipv6L3Protocol>();
3015 NS_ASSERT(ipv6);
3016 if (!ipv6->GetRoutingProtocol())
3017 {
3018 NS_FATAL_ERROR("No Ipv6RoutingProtocol in the node");
3019 }
3020 // Create a dummy packet, then ask the routing function for the best output
3021 // interface's address
3022 Ipv6Header header;
3023 header.SetDestination(m_endPoint6->GetPeerAddress());
3024 Socket::SocketErrno errno_;
3025 Ptr<Ipv6Route> route;
3027 route = ipv6->GetRoutingProtocol()->RouteOutput(Ptr<Packet>(), header, oif, errno_);
3028 if (!route)
3029 {
3030 NS_LOG_LOGIC("Route to " << m_endPoint6->GetPeerAddress() << " does not exist");
3031 NS_LOG_ERROR(errno_);
3032 m_errno = errno_;
3033 return -1;
3034 }
3035 NS_LOG_LOGIC("Route exists");
3036 m_endPoint6->SetLocalAddress(route->GetSource());
3037 return 0;
3038}
3039
3040/* This function is called only if a SYN received in LISTEN state. After
3041 TcpSocketBase cloned, allocate a new end point to handle the incoming
3042 connection and send a SYN+ACK to complete the handshake. */
3043void
3045 const TcpHeader& h,
3046 const Address& fromAddress,
3047 const Address& toAddress)
3048{
3049 NS_LOG_FUNCTION(this << p << h << fromAddress << toAddress);
3050 // Get port and address from peer (connecting host)
3051 if (InetSocketAddress::IsMatchingType(toAddress))
3052 {
3053 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(),
3054 InetSocketAddress::ConvertFrom(toAddress).GetIpv4(),
3055 InetSocketAddress::ConvertFrom(toAddress).GetPort(),
3056 InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
3057 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
3058 m_endPoint6 = nullptr;
3059 }
3060 else if (Inet6SocketAddress::IsMatchingType(toAddress))
3061 {
3062 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(),
3063 Inet6SocketAddress::ConvertFrom(toAddress).GetIpv6(),
3064 Inet6SocketAddress::ConvertFrom(toAddress).GetPort(),
3065 Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
3066 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
3067 m_endPoint = nullptr;
3068 }
3069 m_tcp->AddSocket(this);
3070
3071 // Change the cloned socket from LISTEN state to SYN_RCVD
3072 NS_LOG_DEBUG("LISTEN -> SYN_RCVD");
3073 m_state = SYN_RCVD;
3076 SetupCallback();
3077 // Set the sequence number and send SYN+ACK
3078 m_tcb->m_rxBuffer->SetNextRxSequence(h.GetSequenceNumber() + SequenceNumber32(1));
3079
3080 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
3081 * sender has sent an ECN SYN packet and the traffic is ECN Capable
3082 */
3083 if (m_tcb->m_useEcn != TcpSocketState::Off &&
3085 {
3087 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
3088 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
3089 }
3090 else
3091 {
3093 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
3094 }
3095}
3096
3097void
3099{ // Wrapper to protected function NotifyConnectionSucceeded() so that it can
3100 // be called as a scheduled event
3102 // The if-block below was moved from ProcessSynSent() to here because we need
3103 // to invoke the NotifySend() only after NotifyConnectionSucceeded() to
3104 // reflect the behaviour in the real world.
3105 if (GetTxAvailable() > 0)
3106 {
3108 }
3109}
3110
3111void
3113{
3114 /*
3115 * Add tags for each socket option.
3116 * Note that currently the socket adds both IPv4 tag and IPv6 tag
3117 * if both options are set. Once the packet got to layer three, only
3118 * the corresponding tags will be read.
3119 */
3120 if (GetIpTos())
3121 {
3122 SocketIpTosTag ipTosTag;
3123 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !CheckNoEcn(GetIpTos()) && isEct)
3124 {
3125 ipTosTag.SetTos(MarkEcnCodePoint(GetIpTos(), m_tcb->m_ectCodePoint));
3126 }
3127 else
3128 {
3129 // Set the last received ipTos
3130 ipTosTag.SetTos(GetIpTos());
3131 }
3132 p->AddPacketTag(ipTosTag);
3133 }
3134 else
3135 {
3136 if ((m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && p->GetSize() > 0 && isEct) ||
3137 m_tcb->m_ecnMode == TcpSocketState::DctcpEcn)
3138 {
3139 SocketIpTosTag ipTosTag;
3140 ipTosTag.SetTos(MarkEcnCodePoint(GetIpTos(), m_tcb->m_ectCodePoint));
3141 p->AddPacketTag(ipTosTag);
3142 }
3143 }
3144
3145 if (IsManualIpv6Tclass())
3146 {
3147 SocketIpv6TclassTag ipTclassTag;
3148 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !CheckNoEcn(GetIpv6Tclass()) &&
3149 isEct)
3150 {
3151 ipTclassTag.SetTclass(MarkEcnCodePoint(GetIpv6Tclass(), m_tcb->m_ectCodePoint));
3152 }
3153 else
3154 {
3155 // Set the last received ipTos
3156 ipTclassTag.SetTclass(GetIpv6Tclass());
3157 }
3158 p->AddPacketTag(ipTclassTag);
3159 }
3160 else
3161 {
3162 if ((m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && p->GetSize() > 0 && isEct) ||
3163 m_tcb->m_ecnMode == TcpSocketState::DctcpEcn)
3164 {
3165 SocketIpv6TclassTag ipTclassTag;
3166 ipTclassTag.SetTclass(MarkEcnCodePoint(GetIpv6Tclass(), m_tcb->m_ectCodePoint));
3167 p->AddPacketTag(ipTclassTag);
3168 }
3169 }
3170
3171 if (IsManualIpTtl())
3172 {
3173 SocketIpTtlTag ipTtlTag;
3174 ipTtlTag.SetTtl(GetIpTtl());
3175 p->AddPacketTag(ipTtlTag);
3176 }
3177
3179 {
3180 SocketIpv6HopLimitTag ipHopLimitTag;
3181 ipHopLimitTag.SetHopLimit(GetIpv6HopLimit());
3182 p->AddPacketTag(ipHopLimitTag);
3183 }
3184
3185 uint8_t priority = GetPriority();
3186 if (priority)
3187 {
3188 SocketPriorityTag priorityTag;
3189 priorityTag.SetPriority(priority);
3190 p->ReplacePacketTag(priorityTag);
3191 }
3192}
3193
3194/* Extract at most maxSize bytes from the TxBuffer at sequence seq, add the
3195 TCP header, and send to TcpL4Protocol */
3198{
3199 NS_LOG_FUNCTION(this << seq << maxSize << withAck);
3200
3201 bool isStartOfTransmission = BytesInFlight() == 0U;
3202 TcpTxItem* outItem = m_txBuffer->CopyFromSequence(maxSize, seq);
3203
3204 m_rateOps->SkbSent(outItem, isStartOfTransmission);
3205
3206 bool isRetransmission = outItem->IsRetrans();
3207 Ptr<Packet> p = outItem->GetPacketCopy();
3208 uint32_t sz = p->GetSize(); // Size of packet
3209 uint8_t flags = withAck ? TcpHeader::ACK : 0;
3210 uint32_t remainingData = m_txBuffer->SizeFromSequence(seq + SequenceNumber32(sz));
3211
3212 // TCP sender should not send data out of the window advertised by the
3213 // peer when it is not retransmission.
3214 NS_ASSERT(isRetransmission ||
3215 ((m_highRxAckMark + SequenceNumber32(m_rWnd)) >= (seq + SequenceNumber32(maxSize))));
3216
3217 if (IsPacingEnabled())
3218 {
3219 NS_LOG_INFO("Pacing is enabled");
3220 if (m_pacingTimer.IsExpired())
3221 {
3222 NS_LOG_DEBUG("Current Pacing Rate " << m_tcb->m_pacingRate);
3223 NS_LOG_DEBUG("Timer is in expired state, activate it "
3224 << m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3225 m_pacingTimer.Schedule(m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3226 }
3227 else
3228 {
3229 NS_LOG_INFO("Timer is already in running state");
3230 }
3231 }
3232 else
3233 {
3234 NS_LOG_INFO("Pacing is disabled");
3235 }
3236
3237 if (withAck)
3238 {
3239 m_delAckEvent.Cancel();
3240 m_delAckCount = 0;
3241 }
3242
3243 if (m_tcb->m_ecnState == TcpSocketState::ECN_ECE_RCVD &&
3244 m_ecnEchoSeq.Get() > m_ecnCWRSeq.Get() && !isRetransmission)
3245 {
3246 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CWR_SENT");
3247 m_tcb->m_ecnState = TcpSocketState::ECN_CWR_SENT;
3248 m_ecnCWRSeq = seq;
3249 flags |= TcpHeader::CWR;
3250 NS_LOG_INFO("CWR flags set");
3251 }
3252
3253 bool isEct = IsEct(isRetransmission ? TcpPacketType_t::RE_XMT : TcpPacketType_t::DATA);
3254 AddSocketTags(p, isEct);
3255
3256 if (m_closeOnEmpty && (remainingData == 0))
3257 {
3258 flags |= TcpHeader::FIN;
3259 if (m_state == ESTABLISHED)
3260 { // On active close: I am the first one to send FIN
3261 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
3263 }
3264 else if (m_state == CLOSE_WAIT)
3265 { // On passive close: Peer sent me FIN already
3266 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
3267 m_state = LAST_ACK;
3268 }
3269 }
3270 TcpHeader header;
3271 header.SetFlags(flags);
3272 header.SetSequenceNumber(seq);
3273 header.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
3274 if (m_endPoint)
3275 {
3276 header.SetSourcePort(m_endPoint->GetLocalPort());
3277 header.SetDestinationPort(m_endPoint->GetPeerPort());
3278 }
3279 else
3280 {
3281 header.SetSourcePort(m_endPoint6->GetLocalPort());
3282 header.SetDestinationPort(m_endPoint6->GetPeerPort());
3283 }
3285 AddOptions(header);
3286
3287 if (m_retxEvent.IsExpired())
3288 {
3289 // Schedules retransmit timeout. m_rto should be already doubled.
3290
3291 NS_LOG_LOGIC(this << " SendDataPacket Schedule ReTxTimeout at time "
3292 << Simulator::Now().GetSeconds() << " to expire at time "
3293 << (Simulator::Now() + m_rto.Get()).GetSeconds());
3295 }
3296
3297 m_txTrace(p, header, this);
3298 if (isRetransmission)
3299 {
3300 if (m_endPoint)
3301 {
3303 header,
3304 m_endPoint->GetLocalAddress(),
3305 m_endPoint->GetPeerAddress(),
3306 this);
3307 }
3308 else
3309 {
3311 header,
3312 m_endPoint6->GetLocalAddress(),
3313 m_endPoint6->GetPeerAddress(),
3314 this);
3315 }
3316 }
3317
3318 if (m_endPoint)
3319 {
3320 m_tcp->SendPacket(p,
3321 header,
3322 m_endPoint->GetLocalAddress(),
3323 m_endPoint->GetPeerAddress(),
3325 NS_LOG_DEBUG("Send segment of size "
3326 << sz << " with remaining data " << remainingData << " via TcpL4Protocol to "
3327 << m_endPoint->GetPeerAddress() << ". Header " << header);
3328 }
3329 else
3330 {
3331 m_tcp->SendPacket(p,
3332 header,
3333 m_endPoint6->GetLocalAddress(),
3334 m_endPoint6->GetPeerAddress(),
3336 NS_LOG_DEBUG("Send segment of size "
3337 << sz << " with remaining data " << remainingData << " via TcpL4Protocol to "
3338 << m_endPoint6->GetPeerAddress() << ". Header " << header);
3339 }
3340
3341 // Signal to congestion control whether the cwnd is fully used
3342 // This is a simple version of Linux tcp_cwnd_validate() but following
3343 // the principle implemented in Linux that limits the updating of cwnd
3344 // (in the congestion controls) when flight size is >= cwnd
3345 // send will also be cwnd limited if less then one segment of cwnd is available
3346 m_tcb->m_isCwndLimited = (m_tcb->m_cWnd < BytesInFlight() + m_tcb->m_segmentSize);
3347
3348 UpdateRttHistory(seq, sz, isRetransmission);
3349
3350 // Update bytes sent during recovery phase
3351 if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY ||
3352 m_tcb->m_congState == TcpSocketState::CA_CWR)
3353 {
3354 m_recoveryOps->UpdateBytesSent(sz);
3355 }
3356
3357 // Notify the application of the data being sent unless this is a retransmit
3358 if (!isRetransmission)
3359 {
3361 this,
3362 (seq + sz - m_tcb->m_highTxMark.Get()));
3363 }
3364 // Update highTxMark
3365 m_tcb->m_highTxMark = std::max(seq + sz, m_tcb->m_highTxMark.Get());
3366 return sz;
3367}
3368
3369void
3370TcpSocketBase::UpdateRttHistory(const SequenceNumber32& seq, uint32_t sz, bool isRetransmission)
3371{
3372 NS_LOG_FUNCTION(this);
3373
3374 // update the history of sequence numbers used to calculate the RTT
3375 if (!isRetransmission)
3376 { // This is the next expected one, just log at end
3377 m_history.emplace_back(seq, sz, Simulator::Now());
3378 }
3379 else
3380 { // This is a retransmit, find in list and mark as re-tx
3381 for (auto i = m_history.begin(); i != m_history.end(); ++i)
3382 {
3383 if ((seq >= i->seq) && (seq < (i->seq + SequenceNumber32(i->count))))
3384 { // Found it
3385 i->retx = true;
3386 i->count = ((seq + SequenceNumber32(sz)) - i->seq); // And update count in hist
3387 break;
3388 }
3389 }
3390 }
3391}
3392
3393// Note that this function did not implement the PSH flag
3396{
3397 NS_LOG_FUNCTION(this << withAck);
3398 if (m_txBuffer->Size() == 0)
3399 {
3400 return 0; // Nothing to send
3401 }
3402 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
3403 {
3405 "TcpSocketBase::SendPendingData: No endpoint; m_shutdownSend=" << m_shutdownSend);
3406 return 0; // Is this the right way to handle this condition?
3407 }
3408
3409 uint32_t nPacketsSent = 0;
3410 uint32_t availableWindow = AvailableWindow();
3411
3412 // RFC 6675, Section (C)
3413 // If cwnd - pipe >= 1 SMSS, the sender SHOULD transmit one or more
3414 // segments as follows:
3415 // (NOTE: We check > 0, and do the checks for segmentSize in the following
3416 // else branch to control silly window syndrome and Nagle)
3417 while (availableWindow > 0)
3418 {
3419 if (IsPacingEnabled())
3420 {
3421 NS_LOG_INFO("Pacing is enabled");
3422 if (m_pacingTimer.IsRunning())
3423 {
3424 NS_LOG_INFO("Skipping Packet due to pacing" << m_pacingTimer.GetDelayLeft());
3425 break;
3426 }
3427 NS_LOG_INFO("Timer is not running");
3428 }
3429
3431 {
3432 NS_LOG_INFO("FIN_WAIT and OPEN state; no data to transmit");
3433 break;
3434 }
3435 // (C.1) The scoreboard MUST be queried via NextSeg () for the
3436 // sequence number range of the next segment to transmit (if
3437 // any), and the given segment sent. If NextSeg () returns
3438 // failure (no data to send), return without sending anything
3439 // (i.e., terminate steps C.1 -- C.5).
3440 SequenceNumber32 next;
3441 SequenceNumber32 nextHigh;
3442 bool enableRule3 = m_sackEnabled && m_tcb->m_congState == TcpSocketState::CA_RECOVERY;
3443 if (!m_txBuffer->NextSeg(&next, &nextHigh, enableRule3))
3444 {
3445 NS_LOG_INFO("no valid seq to transmit, or no data available");
3446 break;
3447 }
3448 else
3449 {
3450 // It's time to transmit, but before do silly window and Nagle's check
3451 uint32_t availableData = m_txBuffer->SizeFromSequence(next);
3452
3453 // If there's less app data than the full window, ask the app for more
3454 // data before trying to send
3455 if (availableData < availableWindow)
3456 {
3458 }
3459
3460 // Stop sending if we need to wait for a larger Tx window (prevent silly window
3461 // syndrome) but continue if we don't have data
3462 if (availableWindow < m_tcb->m_segmentSize && availableData > availableWindow)
3463 {
3464 NS_LOG_LOGIC("Preventing Silly Window Syndrome. Wait to send.");
3465 break; // No more
3466 }
3467 // Nagle's algorithm (RFC896): Hold off sending if there is unacked data
3468 // in the buffer and the amount of data to send is less than one segment
3469 if (!m_noDelay && UnAckDataCount() > 0 && availableData < m_tcb->m_segmentSize)
3470 {
3471 NS_LOG_DEBUG("Invoking Nagle's algorithm for seq "
3472 << next << ", SFS: " << m_txBuffer->SizeFromSequence(next)
3473 << ". Wait to send.");
3474 break;
3475 }
3476
3477 uint32_t s = std::min(availableWindow, m_tcb->m_segmentSize);
3478 // NextSeg () may have further constrained the segment size
3479 auto maxSizeToSend = static_cast<uint32_t>(nextHigh - next);
3480 s = std::min(s, maxSizeToSend);
3481
3482 // (C.2) If any of the data octets sent in (C.1) are below HighData,
3483 // HighRxt MUST be set to the highest sequence number of the
3484 // retransmitted segment unless NextSeg () rule (4) was
3485 // invoked for this retransmission.
3486 // (C.3) If any of the data octets sent in (C.1) are above HighData,
3487 // HighData must be updated to reflect the transmission of
3488 // previously unsent data.
3489 //
3490 // These steps are done in m_txBuffer with the tags.
3491 if (m_tcb->m_nextTxSequence != next)
3492 {
3493 m_tcb->m_nextTxSequence = next;
3494 }
3495 if (m_tcb->m_bytesInFlight.Get() == 0)
3496 {
3498 }
3499 uint32_t sz = SendDataPacket(m_tcb->m_nextTxSequence, s, withAck);
3500
3501 NS_LOG_LOGIC(" rxwin " << m_rWnd << " segsize " << m_tcb->m_segmentSize
3502 << " highestRxAck " << m_txBuffer->HeadSequence() << " pd->Size "
3503 << m_txBuffer->Size() << " pd->SFS "
3504 << m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence));
3505
3506 NS_LOG_DEBUG("cWnd: " << m_tcb->m_cWnd << " total unAck: " << UnAckDataCount()
3507 << " sent seq " << m_tcb->m_nextTxSequence << " size " << sz);
3508 m_tcb->m_nextTxSequence += sz;
3509 ++nPacketsSent;
3510 if (IsPacingEnabled())
3511 {
3512 NS_LOG_INFO("Pacing is enabled");
3513 if (m_pacingTimer.IsExpired())
3514 {
3515 NS_LOG_DEBUG("Current Pacing Rate " << m_tcb->m_pacingRate);
3516 NS_LOG_DEBUG("Timer is in expired state, activate it "
3517 << m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3518 m_pacingTimer.Schedule(m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3519 break;
3520 }
3521 }
3522 }
3523
3524 // (C.4) The estimate of the amount of data outstanding in the
3525 // network must be updated by incrementing pipe by the number
3526 // of octets transmitted in (C.1).
3527 //
3528 // Done in BytesInFlight, inside AvailableWindow.
3529 availableWindow = AvailableWindow();
3530
3531 // (C.5) If cwnd - pipe >= 1 SMSS, return to (C.1)
3532 // loop again!
3533 }
3534
3535 if (nPacketsSent > 0)
3536 {
3537 if (!m_sackEnabled)
3538 {
3539 if (!m_limitedTx)
3540 {
3541 // We can't transmit in CA_DISORDER without limitedTx active
3543 }
3544 }
3545
3546 NS_LOG_DEBUG("SendPendingData sent " << nPacketsSent << " segments");
3547 }
3548 else
3549 {
3550 NS_LOG_DEBUG("SendPendingData no segments sent");
3551 }
3552 return nPacketsSent;
3553}
3554
3557{
3558 return m_tcb->m_highTxMark - m_txBuffer->HeadSequence();
3559}
3560
3563{
3564 uint32_t bytesInFlight = m_txBuffer->BytesInFlight();
3565 // Ugly, but we are not modifying the state; m_bytesInFlight is used
3566 // only for tracing purpose.
3567 m_tcb->m_bytesInFlight = bytesInFlight;
3568
3569 NS_LOG_DEBUG("Returning calculated bytesInFlight: " << bytesInFlight);
3570 return bytesInFlight;
3571}
3572
3575{
3576 return std::min(m_rWnd.Get(), m_tcb->m_cWnd.Get());
3577}
3578
3581{
3582 uint32_t win = Window(); // Number of bytes allowed to be outstanding
3583 uint32_t inflight = BytesInFlight(); // Number of outstanding bytes
3584 return (inflight > win) ? 0 : win - inflight;
3585}
3586
3587uint16_t
3589{
3590 NS_LOG_FUNCTION(this << scale);
3591 uint32_t w;
3592
3593 // We don't want to advertise 0 after a FIN is received. So, we just use
3594 // the previous value of the advWnd.
3595 if (m_tcb->m_rxBuffer->GotFin())
3596 {
3597 w = m_advWnd;
3598 }
3599 else
3600 {
3601 NS_ASSERT_MSG(m_tcb->m_rxBuffer->MaxRxSequence() - m_tcb->m_rxBuffer->NextRxSequence() >= 0,
3602 "Unexpected sequence number values");
3603 w = static_cast<uint32_t>(m_tcb->m_rxBuffer->MaxRxSequence() -
3604 m_tcb->m_rxBuffer->NextRxSequence());
3605 }
3606
3607 // Ugly, but we are not modifying the state, that variable
3608 // is used only for tracing purpose.
3609 if (w != m_advWnd)
3610 {
3611 const_cast<TcpSocketBase*>(this)->m_advWnd = w;
3612 }
3613 if (scale)
3614 {
3615 w >>= m_rcvWindShift;
3616 }
3617 if (w > m_maxWinSize)
3618 {
3619 w = m_maxWinSize;
3620 NS_LOG_WARN("Adv window size truncated to "
3621 << m_maxWinSize << "; possibly to avoid overflow of the 16-bit integer");
3622 }
3623 NS_LOG_LOGIC("Returning AdvertisedWindowSize of " << static_cast<uint16_t>(w));
3624 return static_cast<uint16_t>(w);
3625}
3626
3627// Receipt of new packet, put into Rx buffer
3628void
3630{
3631 NS_LOG_FUNCTION(this << tcpHeader);
3632 NS_LOG_DEBUG("Data segment, seq=" << tcpHeader.GetSequenceNumber()
3633 << " pkt size=" << p->GetSize());
3634
3635 // Put into Rx buffer
3636 SequenceNumber32 expectedSeq = m_tcb->m_rxBuffer->NextRxSequence();
3637 if (!m_tcb->m_rxBuffer->Add(p, tcpHeader))
3638 { // Insert failed: No data or RX buffer full
3639 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3641 {
3643 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
3645 }
3646 else
3647 {
3649 }
3650 return;
3651 }
3652 // Notify app to receive if necessary
3653 if (expectedSeq < m_tcb->m_rxBuffer->NextRxSequence())
3654 { // NextRxSeq advanced, we have something to send to the app
3655 if (!m_shutdownRecv)
3656 {
3658 }
3659 // Handle exceptions
3660 if (m_closeNotified)
3661 {
3662 NS_LOG_WARN("Why TCP " << this << " got data after close notification?");
3663 }
3664 // If we received FIN before and now completed all "holes" in rx buffer,
3665 // invoke peer close procedure
3666 if (m_tcb->m_rxBuffer->Finished() && (tcpHeader.GetFlags() & TcpHeader::FIN) == 0)
3667 {
3668 DoPeerClose();
3669 return;
3670 }
3671 }
3672 // Now send a new ACK packet acknowledging all received and delivered data
3673 if (m_tcb->m_rxBuffer->Size() > m_tcb->m_rxBuffer->Available() ||
3674 m_tcb->m_rxBuffer->NextRxSequence() > expectedSeq + p->GetSize())
3675 { // A gap exists in the buffer, or we filled a gap: Always ACK
3677 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3679 {
3681 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
3683 }
3684 else
3685 {
3687 }
3688 }
3689 else
3690 { // In-sequence packet: ACK if delayed ack count allows
3692 {
3693 m_delAckEvent.Cancel();
3694 m_delAckCount = 0;
3696 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3698 {
3699 NS_LOG_DEBUG("Congestion algo " << m_congestionControl->GetName());
3702 << " -> ECN_SENDING_ECE");
3704 }
3705 else
3706 {
3708 }
3709 }
3710 else if (!m_delAckEvent.IsExpired())
3711 {
3713 }
3714 else if (m_delAckEvent.IsExpired())
3715 {
3720 this << " scheduled delayed ACK at "
3722 }
3723 }
3724}
3725
3726Time
3727TcpSocketBase::CalculateRttSample(const TcpHeader& tcpHeader, const RttHistory& rttHistory)
3728{
3729 NS_LOG_FUNCTION(this);
3730 SequenceNumber32 ackSeq = tcpHeader.GetAckNumber();
3731 Time rtt;
3732
3733 if (ackSeq >= (rttHistory.seq + SequenceNumber32(rttHistory.count)))
3734 {
3735 // As per RFC 6298 (Section 3)
3736 // RTT samples MUST NOT be made using segments that were
3737 // retransmitted (and thus for which it is ambiguous whether the reply
3738 // was for the first instance of the packet or a later instance). The
3739 // only case when TCP can safely take RTT samples from retransmitted
3740 // segments is when the TCP timestamp option is employed, since
3741 // the timestamp option removes the ambiguity regarding which instance
3742 // of the data segment triggered the acknowledgment.
3743 if (m_timestampEnabled && tcpHeader.HasOption(TcpOption::TS))
3744 {
3747 rtt = TcpOptionTS::ElapsedTimeFromTsValue(ts->GetEcho());
3748 if (rtt.IsZero())
3749 {
3750 NS_LOG_LOGIC("TcpSocketBase::EstimateRtt - RTT calculated from TcpOption::TS "
3751 "is zero, approximating to 1us.");
3752 NS_LOG_DEBUG("RTT calculated from TcpOption::TS is zero, updating rtt to 1us.");
3753 rtt = MicroSeconds(1);
3754 }
3755 }
3756 else if (!rttHistory.retx)
3757 {
3758 // Elapsed time since the packet was transmitted
3759 rtt = Simulator::Now() - rttHistory.time;
3760 }
3761 }
3762 return rtt;
3763}
3764
3765void
3767{
3768 NS_LOG_FUNCTION(this);
3769 SequenceNumber32 ackSeq = tcpHeader.GetAckNumber();
3770 Time rtt;
3771
3772 // An ack has been received, calculate rtt and log this measurement
3773 // Note we use a linear search (O(n)) for this since for the common
3774 // case the ack'ed packet will be at the head of the list
3775 if (!m_history.empty())
3776 {
3777 RttHistory& earliestTransmittedPktHistory = m_history.front();
3778 rtt = CalculateRttSample(tcpHeader, earliestTransmittedPktHistory);
3779
3780 // Store ACKed packet that has the latest transmission time to update `lastRtt`
3781 RttHistory latestTransmittedPktHistory = earliestTransmittedPktHistory;
3782
3783 // Delete all ACK history with seq <= ack
3784 while (!m_history.empty())
3785 {
3786 RttHistory& rttHistory = m_history.front();
3787 if ((rttHistory.seq + SequenceNumber32(rttHistory.count)) > ackSeq)
3788 {
3789 break; // Done removing
3790 }
3791
3792 latestTransmittedPktHistory = rttHistory;
3793 m_history.pop_front(); // Remove
3794 }
3795
3796 // In case of multiple packets being ACKed in a single acknowledgement, `m_lastRtt` is
3797 // RTT of the last (S)ACKed packet calculated using the data packet with the latest
3798 // transmission time
3799 Time lastRtt = CalculateRttSample(tcpHeader, latestTransmittedPktHistory);
3800 if (!lastRtt.IsZero())
3801 {
3802 NS_LOG_DEBUG("Last RTT sample updated to: " << lastRtt);
3803 m_tcb->m_lastRtt = lastRtt;
3804 }
3805 }
3806
3807 if (!rtt.IsZero())
3808 {
3809 m_rtt->Measurement(rtt); // Log the measurement
3810 // RFC 6298, clause 2.4
3811 m_rto = Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4),
3812 m_minRto);
3813 m_tcb->m_srtt = m_rtt->GetEstimate();
3814 m_tcb->m_minRtt = std::min(m_tcb->m_srtt.Get(), m_tcb->m_minRtt);
3815 NS_LOG_INFO(this << m_tcb->m_srtt << m_tcb->m_minRtt);
3816 }
3817}
3818
3819// Called by the ReceivedAck() when new ACK received and by ProcessSynRcvd()
3820// when the three-way handshake completed. This cancels retransmission timer
3821// and advances Tx window
3822void
3823TcpSocketBase::NewAck(const SequenceNumber32& ack, bool resetRTO)
3824{
3825 NS_LOG_FUNCTION(this << ack);
3826
3827 // Reset the data retransmission count. We got a new ACK!
3829
3830 if (m_state != SYN_RCVD && resetRTO)
3831 { // Set RTO unless the ACK is received in SYN_RCVD state
3833 this << " Cancelled ReTxTimeout event which was set to expire at "
3834 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
3835 m_retxEvent.Cancel();
3836 // On receiving a "New" ack we restart retransmission timer .. RFC 6298
3837 // RFC 6298, clause 2.4
3838 m_rto = Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4),
3839 m_minRto);
3840
3841 NS_LOG_LOGIC(this << " Schedule ReTxTimeout at time " << Simulator::Now().GetSeconds()
3842 << " to expire at time "
3843 << (Simulator::Now() + m_rto.Get()).GetSeconds());
3845 }
3846
3847 // Note the highest ACK and tell app to send more
3848 NS_LOG_LOGIC("TCP " << this << " NewAck " << ack << " numberAck "
3849 << (ack - m_txBuffer->HeadSequence())); // Number bytes ack'ed
3850
3851 if (GetTxAvailable() > 0)
3852 {
3854 }
3855 if (ack > m_tcb->m_nextTxSequence)
3856 {
3857 m_tcb->m_nextTxSequence = ack; // If advanced
3858 }
3859 if (m_txBuffer->Size() == 0 && m_state != FIN_WAIT_1 && m_state != CLOSING)
3860 { // No retransmit timer if no data to retransmit
3862 this << " Cancelled ReTxTimeout event which was set to expire at "
3863 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
3864 m_retxEvent.Cancel();
3865 }
3866}
3867
3868// Retransmit timeout
3869void
3871{
3872 NS_LOG_FUNCTION(this);
3873 NS_LOG_LOGIC(this << " ReTxTimeout Expired at time " << Simulator::Now().GetSeconds());
3874 // If erroneous timeout in closed/timed-wait state, just return
3875 if (m_state == CLOSED || m_state == TIME_WAIT)
3876 {
3877 return;
3878 }
3879
3880 if (m_state == SYN_SENT)
3881 {
3882 NS_ASSERT(m_synCount > 0);
3883 if (m_tcb->m_useEcn == TcpSocketState::On)
3884 {
3886 }
3887 else
3888 {
3890 }
3891 return;
3892 }
3893
3894 // Retransmit non-data packet: Only if in FIN_WAIT_1 or CLOSING state
3895 if (m_txBuffer->Size() == 0)
3896 {
3897 if (m_state == FIN_WAIT_1 || m_state == CLOSING)
3898 { // Must have lost FIN, re-send
3900 }
3901 return;
3902 }
3903
3904 NS_LOG_DEBUG("Checking if Connection is Established");
3905 // If all data are received (non-closing socket and nothing to send), just return
3906 if (m_state <= ESTABLISHED && m_txBuffer->HeadSequence() >= m_tcb->m_highTxMark &&
3907 m_txBuffer->Size() == 0)
3908 {
3909 NS_LOG_DEBUG("Already Sent full data" << m_txBuffer->HeadSequence() << " "
3910 << m_tcb->m_highTxMark);
3911 return;
3912 }
3913
3914 if (m_dataRetrCount == 0)
3915 {
3916 NS_LOG_INFO("No more data retries available. Dropping connection");
3919 return;
3920 }
3921 else
3922 {
3924 }
3925
3926 uint32_t inFlightBeforeRto = BytesInFlight();
3927 bool resetSack = !m_sackEnabled; // Reset SACK information if SACK is not enabled.
3928 // The information in the TcpTxBuffer is guessed, in this case.
3929
3930 // Reset dupAckCount
3931 m_dupAckCount = 0;
3932 if (!m_sackEnabled)
3933 {
3934 m_txBuffer->ResetRenoSack();
3935 }
3936
3937 // From RFC 6675, Section 5.1
3938 // [RFC2018] suggests that a TCP sender SHOULD expunge the SACK
3939 // information gathered from a receiver upon a retransmission timeout
3940 // (RTO) "since the timeout might indicate that the data receiver has
3941 // reneged." Additionally, a TCP sender MUST "ignore prior SACK
3942 // information in determining which data to retransmit."
3943 // It has been suggested that, as long as robust tests for
3944 // reneging are present, an implementation can retain and use SACK
3945 // information across a timeout event [Errata1610].
3946 // The head of the sent list will not be marked as sacked, therefore
3947 // will be retransmitted, if the receiver renegotiate the SACK blocks
3948 // that we received.
3949 m_txBuffer->SetSentListLost(resetSack);
3950
3951 // From RFC 6675, Section 5.1
3952 // If an RTO occurs during loss recovery as specified in this document,
3953 // RecoveryPoint MUST be set to HighData. Further, the new value of
3954 // RecoveryPoint MUST be preserved and the loss recovery algorithm
3955 // outlined in this document MUST be terminated.
3956 m_recover = m_tcb->m_highTxMark;
3957 m_recoverActive = true;
3958
3959 // RFC 6298, clause 2.5, double the timer
3960 Time doubledRto = m_rto + m_rto;
3961 m_rto = Min(doubledRto, Time::FromDouble(60, Time::S));
3962
3963 // Empty RTT history
3964 m_history.clear();
3965
3966 // Please don't reset highTxMark, it is used for retransmission detection
3967
3968 // When a TCP sender detects segment loss using the retransmission timer
3969 // and the given segment has not yet been resent by way of the
3970 // retransmission timer, decrease ssThresh
3971 if (m_tcb->m_congState != TcpSocketState::CA_LOSS || !m_txBuffer->IsHeadRetransmitted())
3972 {
3973 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, inFlightBeforeRto);
3974 }
3975
3976 // Cwnd set to 1 MSS
3979 m_tcb->m_congState = TcpSocketState::CA_LOSS;
3980 m_tcb->m_cWnd = m_tcb->m_segmentSize;
3981 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
3982
3983 m_pacingTimer.Cancel();
3984
3985 NS_LOG_DEBUG("RTO. Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to " << m_tcb->m_ssThresh
3986 << ", restart from seqnum " << m_txBuffer->HeadSequence()
3987 << " doubled rto to " << m_rto.Get().GetSeconds() << " s");
3988
3990 "There are some bytes in flight after an RTO: " << BytesInFlight());
3991
3993
3994 NS_ASSERT_MSG(BytesInFlight() <= m_tcb->m_segmentSize,
3995 "In flight (" << BytesInFlight() << ") there is more than one segment ("
3996 << m_tcb->m_segmentSize << ")");
3997}
3998
3999void
4015
4016void
4018{
4019 NS_LOG_FUNCTION(this);
4020
4021 m_lastAckEvent.Cancel();
4022 if (m_state == LAST_ACK)
4023 {
4024 if (m_dataRetrCount == 0)
4025 {
4026 NS_LOG_INFO("LAST-ACK: No more data retries available. Dropping connection");
4029 return;
4030 }
4033 NS_LOG_LOGIC("TcpSocketBase " << this << " rescheduling LATO1");
4034 Time lastRto = m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4);
4036 }
4037}
4038
4039// Send 1-byte data to probe for the window size at the receiver when
4040// the local knowledge tells that the receiver has zero window size
4041// C.f.: RFC793 p.42, RFC1112 sec.4.2.2.17
4042void
4044{
4045 NS_LOG_LOGIC("PersistTimeout expired at " << Simulator::Now().GetSeconds());
4047 std::min(Seconds(60), Time(2 * m_persistTimeout)); // max persist timeout = 60s
4048 Ptr<Packet> p = m_txBuffer->CopyFromSequence(1, m_tcb->m_nextTxSequence)->GetPacketCopy();
4049 m_txBuffer->ResetLastSegmentSent();
4050 TcpHeader tcpHeader;
4051 tcpHeader.SetSequenceNumber(m_tcb->m_nextTxSequence);
4052 tcpHeader.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
4054 if (m_endPoint != nullptr)
4055 {
4056 tcpHeader.SetSourcePort(m_endPoint->GetLocalPort());
4057 tcpHeader.SetDestinationPort(m_endPoint->GetPeerPort());
4058 }
4059 else
4060 {
4061 tcpHeader.SetSourcePort(m_endPoint6->GetLocalPort());
4062 tcpHeader.SetDestinationPort(m_endPoint6->GetPeerPort());
4063 }
4064 AddOptions(tcpHeader);
4065 // Send a packet tag for setting ECT bits in IP header
4066 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED)
4067 {
4069 }
4070 m_txTrace(p, tcpHeader, this);
4071
4072 if (m_endPoint != nullptr)
4073 {
4074 m_tcp->SendPacket(p,
4075 tcpHeader,
4076 m_endPoint->GetLocalAddress(),
4077 m_endPoint->GetPeerAddress(),
4079 }
4080 else
4081 {
4082 m_tcp->SendPacket(p,
4083 tcpHeader,
4084 m_endPoint6->GetLocalAddress(),
4085 m_endPoint6->GetPeerAddress(),
4087 }
4088
4089 NS_LOG_LOGIC("Schedule persist timeout at time "
4090 << Simulator::Now().GetSeconds() << " to expire at time "
4091 << (Simulator::Now() + m_persistTimeout).GetSeconds());
4093}
4094
4095void
4097{
4098 NS_LOG_FUNCTION(this);
4099 bool res;
4100 SequenceNumber32 seq;
4101 SequenceNumber32 seqHigh;
4102 uint32_t maxSizeToSend;
4103
4104 // Find the first segment marked as lost and not retransmitted. With Reno,
4105 // that should be the head
4106 res = m_txBuffer->NextSeg(&seq, &seqHigh, false);
4107 if (!res)
4108 {
4109 // We have already retransmitted the head. However, we still received
4110 // three dupacks, or the RTO expired, but no data to transmit.
4111 // Therefore, re-send again the head.
4112 seq = m_txBuffer->HeadSequence();
4113 maxSizeToSend = m_tcb->m_segmentSize;
4114 }
4115 else
4116 {
4117 // NextSeg() may constrain the segment size when res is true
4118 maxSizeToSend = static_cast<uint32_t>(seqHigh - seq);
4119 }
4120 NS_ASSERT(m_sackEnabled || seq == m_txBuffer->HeadSequence());
4121
4122 NS_LOG_INFO("Retransmitting " << seq);
4123 // Update the trace and retransmit the segment
4124 m_tcb->m_nextTxSequence = seq;
4125 uint32_t sz = SendDataPacket(m_tcb->m_nextTxSequence, maxSizeToSend, true);
4126
4127 NS_ASSERT(sz > 0);
4128}
4129
4130void
4132{
4133 m_retxEvent.Cancel();
4134 m_persistEvent.Cancel();
4135 m_delAckEvent.Cancel();
4136 m_lastAckEvent.Cancel();
4137 m_timewaitEvent.Cancel();
4138 m_sendPendingDataEvent.Cancel();
4139 m_pacingTimer.Cancel();
4140}
4141
4142/* Move TCP to Time_Wait state and schedule a transition to Closed state */
4143void
4145{
4146 NS_LOG_DEBUG(TcpStateName[m_state] << " -> TIME_WAIT");
4149 if (!m_closeNotified)
4150 {
4151 // Technically the connection is not fully closed, but we notify now
4152 // because an implementation (real socket) would behave as if closed.
4153 // Notify normal close when entering TIME_WAIT or leaving LAST_ACK.
4155 m_closeNotified = true;
4156 }
4157 // Move from TIME_WAIT to CLOSED after 2*MSL. Max segment lifetime is 2 min
4158 // according to RFC793, p.28
4160}
4161
4162/* Below are the attribute get/set functions */
4163
4164void
4166{
4167 NS_LOG_FUNCTION(this << size);
4168 m_txBuffer->SetMaxBufferSize(size);
4169}
4170
4173{
4174 return m_txBuffer->MaxBufferSize();
4175}
4176
4177void
4179{
4180 NS_LOG_FUNCTION(this << size);
4181 uint32_t oldSize = GetRcvBufSize();
4182
4183 m_tcb->m_rxBuffer->SetMaxBufferSize(size);
4184
4185 /* The size has (manually) increased. Actively inform the other end to prevent
4186 * stale zero-window states.
4187 */
4188 if (oldSize < size && m_connected)
4189 {
4190 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
4192 {
4194 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
4196 }
4197 else
4198 {
4200 }
4201 }
4202}
4203
4206{
4207 return m_tcb->m_rxBuffer->MaxBufferSize();
4208}
4209
4210void
4212{
4213 NS_LOG_FUNCTION(this << size);
4214 m_tcb->m_segmentSize = size;
4215 m_txBuffer->SetSegmentSize(size);
4216
4217 NS_ABORT_MSG_UNLESS(m_state == CLOSED, "Cannot change segment size dynamically.");
4218}
4219
4222{
4223 return m_tcb->m_segmentSize;
4224}
4225
4226void
4232
4233Time
4235{
4236 return m_cnTimeout;
4237}
4238
4239void
4241{
4242 NS_LOG_FUNCTION(this << count);
4243 m_synRetries = count;
4244}
4245
4248{
4249 return m_synRetries;
4250}
4251
4252void
4254{
4255 NS_LOG_FUNCTION(this << retries);
4256 m_dataRetries = retries;
4257}
4258
4261{
4262 NS_LOG_FUNCTION(this);
4263 return m_dataRetries;
4264}
4265
4266void
4272
4273Time
4275{
4276 return m_delAckTimeout;
4277}
4278
4279void
4281{
4282 NS_LOG_FUNCTION(this << count);
4283 m_delAckMaxCount = count;
4284}
4285
4291
4292void
4294{
4295 NS_LOG_FUNCTION(this << noDelay);
4296 m_noDelay = noDelay;
4297}
4298
4299bool
4301{
4302 return m_noDelay;
4303}
4304
4305void
4311
4312Time
4317
4318bool
4320{
4321 // Broadcast is not implemented. Return true only if allowBroadcast==false
4322 return (!allowBroadcast);
4323}
4324
4325bool
4327{
4328 return false;
4329}
4330
4331void
4333{
4334 NS_LOG_FUNCTION(this << header);
4335
4337 {
4338 AddOptionTimestamp(header);
4339 }
4340}
4341
4342void
4344{
4345 NS_LOG_FUNCTION(this << option);
4346
4348
4349 // In naming, we do the contrary of RFC 1323. The received scaling factor
4350 // is Rcv.Wind.Scale (and not Snd.Wind.Scale)
4351 m_sndWindShift = ws->GetScale();
4352
4353 if (m_sndWindShift > 14)
4354 {
4355 NS_LOG_WARN("Possible error; m_sndWindShift exceeds 14: " << m_sndWindShift);
4356 m_sndWindShift = 14;
4357 }
4358
4359 NS_LOG_INFO(m_node->GetId() << " Received a scale factor of "
4360 << static_cast<int>(m_sndWindShift));
4361}
4362
4363uint8_t
4365{
4366 NS_LOG_FUNCTION(this);
4367 uint32_t maxSpace = m_tcb->m_rxBuffer->MaxBufferSize();
4368 uint8_t scale = 0;
4369
4370 while (maxSpace > m_maxWinSize)
4371 {
4372 maxSpace = maxSpace >> 1;
4373 ++scale;
4374 }
4375
4376 if (scale > 14)
4377 {
4378 NS_LOG_WARN("Possible error; scale exceeds 14: " << scale);
4379 scale = 14;
4380 }
4381
4382 NS_LOG_INFO("Node " << m_node->GetId() << " calculated wscale factor of "
4383 << static_cast<int>(scale) << " for buffer size "
4384 << m_tcb->m_rxBuffer->MaxBufferSize());
4385 return scale;
4386}
4387
4388void
4390{
4391 NS_LOG_FUNCTION(this << header);
4392 NS_ASSERT(header.GetFlags() & TcpHeader::SYN);
4393
4395
4396 // In naming, we do the contrary of RFC 1323. The sended scaling factor
4397 // is Snd.Wind.Scale (and not Rcv.Wind.Scale)
4398
4400 option->SetScale(m_rcvWindShift);
4401
4402 header.AppendOption(option);
4403
4404 NS_LOG_INFO(m_node->GetId() << " Send a scaling factor of "
4405 << static_cast<int>(m_rcvWindShift));
4406}
4407
4410{
4411 NS_LOG_FUNCTION(this << option);
4412
4414 return m_txBuffer->Update(s->GetSackList(), MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
4415}
4416
4417void
4419{
4420 NS_LOG_FUNCTION(this << option);
4421
4423
4424 NS_ASSERT(m_sackEnabled == true);
4425 NS_LOG_INFO(m_node->GetId() << " Received a SACK_PERMITTED option " << s);
4426}
4427
4428void
4430{
4431 NS_LOG_FUNCTION(this << header);
4432 NS_ASSERT(header.GetFlags() & TcpHeader::SYN);
4433
4435 header.AppendOption(option);
4436 NS_LOG_INFO(m_node->GetId() << " Add option SACK-PERMITTED");
4437}
4438
4439void
4441{
4442 NS_LOG_FUNCTION(this << header);
4443
4444 // Calculate the number of SACK blocks allowed in this packet
4445 uint8_t optionLenAvail = header.GetMaxOptionLength() - header.GetOptionLength();
4446 uint8_t allowedSackBlocks = (optionLenAvail - 2) / 8;
4447
4448 TcpOptionSack::SackList sackList = m_tcb->m_rxBuffer->GetSackList();
4449 if (allowedSackBlocks == 0 || sackList.empty())
4450 {
4451 NS_LOG_LOGIC("No space available or sack list empty, not adding sack blocks");
4452 return;
4453 }
4454
4455 // Append the allowed number of SACK blocks
4457
4458 for (auto i = sackList.begin(); allowedSackBlocks > 0 && i != sackList.end(); ++i)
4459 {
4460 option->AddSackBlock(*i);
4461 allowedSackBlocks--;
4462 }
4463
4464 header.AppendOption(option);
4465 NS_LOG_INFO(m_node->GetId() << " Add option SACK " << *option);
4466}
4467
4468void
4470 const SequenceNumber32& seq)
4471{
4472 NS_LOG_FUNCTION(this << option);
4473
4475
4476 // This is valid only when no overflow occurs. It happens
4477 // when a connection last longer than 50 days.
4478 if (m_tcb->m_rcvTimestampValue > ts->GetTimestamp())
4479 {
4480 // Do not save a smaller timestamp (probably there is reordering)
4481 return;
4482 }
4483
4484 m_tcb->m_rcvTimestampValue = ts->GetTimestamp();
4485 m_tcb->m_rcvTimestampEchoReply = ts->GetEcho();
4486
4487 if (seq == m_tcb->m_rxBuffer->NextRxSequence() && seq <= m_highTxAck)
4488 {
4489 m_timestampToEcho = ts->GetTimestamp();
4490 }
4491
4492 NS_LOG_INFO(m_node->GetId() << " Got timestamp=" << m_timestampToEcho
4493 << " and Echo=" << ts->GetEcho());
4494}
4495
4496void
4498{
4499 NS_LOG_FUNCTION(this << header);
4500
4502
4503 option->SetTimestamp(TcpOptionTS::NowToTsValue());
4504 option->SetEcho(m_timestampToEcho);
4505
4506 header.AppendOption(option);
4507 NS_LOG_INFO(m_node->GetId() << " Add option TS, ts=" << option->GetTimestamp()
4508 << " echo=" << m_timestampToEcho);
4509}
4510
4511void
4513{
4514 NS_LOG_FUNCTION(this << header);
4515 // If the connection is not established, the window size is always
4516 // updated
4517 uint32_t receivedWindow = header.GetWindowSize();
4518 receivedWindow <<= m_sndWindShift;
4519 NS_LOG_INFO("Received (scaled) window is " << receivedWindow << " bytes");
4520 if (m_state < ESTABLISHED)
4521 {
4522 m_rWnd = receivedWindow;
4523 NS_LOG_LOGIC("State less than ESTABLISHED; updating rWnd to " << m_rWnd);
4524 return;
4525 }
4526
4527 // Test for conditions that allow updating of the window
4528 // 1) segment contains new data (advancing the right edge of the receive
4529 // buffer),
4530 // 2) segment does not contain new data but the segment acks new data
4531 // (highest sequence number acked advances), or
4532 // 3) the advertised window is larger than the current send window
4533 bool update = false;
4534 if (header.GetAckNumber() == m_highRxAckMark && receivedWindow > m_rWnd)
4535 {
4536 // right edge of the send window is increased (window update)
4537 update = true;
4538 }
4539 if (header.GetAckNumber() > m_highRxAckMark)
4540 {
4541 m_highRxAckMark = header.GetAckNumber();
4542 update = true;
4543 }
4544 if (header.GetSequenceNumber() > m_highRxMark)
4545 {
4547 update = true;
4548 }
4549 if (update)
4550 {
4551 m_rWnd = receivedWindow;
4552 NS_LOG_LOGIC("updating rWnd to " << m_rWnd);
4553 }
4554}
4555
4556void
4558{
4559 NS_LOG_FUNCTION(this << minRto);
4560 m_minRto = minRto;
4561}
4562
4563Time
4565{
4566 return m_minRto;
4567}
4568
4569void
4571{
4572 NS_LOG_FUNCTION(this << clockGranularity);
4573 m_clockGranularity = clockGranularity;
4574}
4575
4576Time
4581
4584{
4585 return m_txBuffer;
4586}
4587
4590{
4591 return m_tcb->m_rxBuffer;
4592}
4593
4594void
4596{
4597 m_retxThresh = retxThresh;
4598 m_txBuffer->SetDupAckThresh(retxThresh);
4599}
4600
4601void
4603{
4604 m_pacingRateTrace(oldValue, newValue);
4605}
4606
4607void
4609{
4610 m_cWndTrace(oldValue, newValue);
4611}
4612
4613void
4615{
4616 m_cWndInflTrace(oldValue, newValue);
4617}
4618
4619void
4621{
4622 m_ssThTrace(oldValue, newValue);
4623}
4624
4625void
4631
4632void
4634 TcpSocketState::EcnState_t newValue) const
4635{
4636 m_ecnStateTrace(oldValue, newValue);
4637}
4638
4639void
4641
4642{
4643 m_nextTxSequenceTrace(oldValue, newValue);
4644}
4645
4646void
4648{
4649 m_highTxMarkTrace(oldValue, newValue);
4650}
4651
4652void
4654{
4655 m_bytesInFlightTrace(oldValue, newValue);
4656}
4657
4658void
4659TcpSocketBase::UpdateRtt(Time oldValue, Time newValue) const
4660{
4661 m_srttTrace(oldValue, newValue);
4662}
4663
4664void
4665TcpSocketBase::UpdateLastRtt(Time oldValue, Time newValue) const
4666{
4667 m_lastRttTrace(oldValue, newValue);
4668}
4669
4670void
4678
4679void
4681{
4682 NS_LOG_FUNCTION(this << recovery);
4683 m_recoveryOps = recovery;
4684}
4685
4688{
4689 return CopyObject<TcpSocketBase>(this);
4690}
4691
4694{
4695 if (a > b)
4696 {
4697 return a - b;
4698 }
4699
4700 return 0;
4701}
4702
4703void
4705{
4706 NS_LOG_FUNCTION(this);
4707 NS_LOG_INFO("Performing Pacing");
4709}
4710
4711bool
4713{
4714 if (!m_tcb->m_pacing)
4715 {
4716 return false;
4717 }
4718 else
4719 {
4720 if (m_tcb->m_paceInitialWindow)
4721 {
4722 return true;
4723 }
4724 SequenceNumber32 highTxMark = m_tcb->m_highTxMark; // cast traced value
4725 if (highTxMark.GetValue() > (GetInitialCwnd() * m_tcb->m_segmentSize))
4726 {
4727 return true;
4728 }
4729 }
4730 return false;
4731}
4732
4733void
4735{
4736 NS_LOG_FUNCTION(this << m_tcb);
4737
4738 // According to Linux, set base pacing rate to (cwnd * mss) / srtt
4739 //
4740 // In (early) slow start, multiply base by the slow start factor.
4741 // In late slow start and congestion avoidance, multiply base by
4742 // the congestion avoidance factor.
4743 // Comment from Linux code regarding early/late slow start:
4744 // Normal Slow Start condition is (tp->snd_cwnd < tp->snd_ssthresh)
4745 // If snd_cwnd >= (tp->snd_ssthresh / 2), we are approaching
4746 // end of slow start and should slow down.
4747
4748 // Similar to Linux, do not update pacing rate here if the
4749 // congestion control implements TcpCongestionOps::CongControl ()
4750 if (m_congestionControl->HasCongControl() || !m_tcb->m_pacing)
4751 {
4752 return;
4753 }
4754
4755 double factor;
4756 if (m_tcb->m_cWnd < m_tcb->m_ssThresh / 2)
4757 {
4758 NS_LOG_DEBUG("Pacing according to slow start factor; " << m_tcb->m_cWnd << " "
4759 << m_tcb->m_ssThresh);
4760 factor = static_cast<double>(m_tcb->m_pacingSsRatio) / 100;
4761 }
4762 else
4763 {
4764 NS_LOG_DEBUG("Pacing according to congestion avoidance factor; " << m_tcb->m_cWnd << " "
4765 << m_tcb->m_ssThresh);
4766 factor = static_cast<double>(m_tcb->m_pacingCaRatio) / 100;
4767 }
4768 Time srtt = m_tcb->m_srtt.Get(); // Get underlying Time value
4769 NS_LOG_DEBUG("Smoothed RTT is " << srtt.GetSeconds());
4770
4771 // Multiply by 8 to convert from bytes per second to bits per second
4772 DataRate pacingRate((std::max(m_tcb->m_cWnd, m_tcb->m_bytesInFlight) * 8 * factor) /
4773 srtt.GetSeconds());
4774 if (pacingRate < m_tcb->m_maxPacingRate)
4775 {
4776 NS_LOG_DEBUG("Pacing rate updated to: " << pacingRate);
4777 m_tcb->m_pacingRate = pacingRate;
4778 }
4779 else
4780 {
4781 NS_LOG_DEBUG("Pacing capped by max pacing rate: " << m_tcb->m_maxPacingRate);
4782 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
4783 }
4784}
4785
4786void
4788{
4789 NS_LOG_FUNCTION(this << pacing);
4790 m_tcb->m_pacing = pacing;
4791}
4792
4793void
4795{
4796 NS_LOG_FUNCTION(this << paceWindow);
4797 m_tcb->m_paceInitialWindow = paceWindow;
4798}
4799
4800bool
4802{
4803 NS_LOG_FUNCTION(this << packetType);
4804 NS_ASSERT_MSG(packetType != TcpPacketType_t::INVALID, "Invalid TCP packet type");
4805 if (m_tcb->m_ecnState == TcpSocketState::ECN_DISABLED)
4806 {
4807 return false;
4808 }
4809
4810 NS_ABORT_MSG_IF(!ECN_RESTRICTION_MAP.contains(std::make_pair(packetType, m_tcb->m_ecnMode)),
4811 "Invalid packetType and ecnMode");
4812
4813 return ECN_RESTRICTION_MAP.at(std::make_pair(packetType, m_tcb->m_ecnMode));
4814}
4815
4816void
4818{
4819 NS_LOG_FUNCTION(this << useEcn);
4820 m_tcb->m_useEcn = useEcn;
4821}
4822
4823void
4825{
4826 NS_LOG_FUNCTION(this << useAbe);
4827 if (m_tcb->m_useEcn == TcpSocketState::Off && useAbe)
4828 {
4829 NS_LOG_INFO("Enabling ECN along with ABE");
4830 m_tcb->m_useEcn = TcpSocketState::On;
4831 }
4832 m_tcb->m_abeEnabled = useAbe;
4833}
4834
4835bool
4837{
4838 return m_tcb->m_abeEnabled;
4839}
4840
4843{
4844 return m_rWnd.Get();
4845}
4846
4849{
4850 return m_highRxAckMark.Get();
4851}
4852
4853// RttHistory methods
4855 : seq(s),
4856 count(c),
4857 time(t),
4858 retx(false)
4859{
4860}
4861
4863 : seq(h.seq),
4864 count(h.count),
4865 time(h.time),
4866 retx(h.retx)
4867{
4868}
4869
4870} // namespace ns3
#define Max(a, b)
#define Min(a, b)
a polymophic address class
Definition address.h:90
AttributeValue implementation for Boolean.
Definition boolean.h:26
Callback template class.
Definition callback.h:422
AttributeValue implementation for Callback.
Definition callback.h:786
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:67
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:561
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:595
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:206
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:1070
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:1260
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:1113
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:1161
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:1355
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:1307
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.
Time GetDelAckTimeout() const override
Get the time to delay an ACK.
Ptr< TcpRecoveryOps > m_recoveryOps
Recovery Algorithm.
TracedCallback< uint32_t, uint32_t > m_bytesInFlightTrace
Callback pointer for bytesInFlight trace chaining.
uint32_t GetInitialSSThresh() const override
Get the initial Slow Start Threshold.
void NotifyPacingPerformed()
Notify Pacing.
void SetDelAckTimeout(Time timeout) override
Set the time to delay an ACK.
void CloseAndNotify()
Peacefully close the socket by notifying the upper layer and deallocate end point.
Ptr< TcpRateOps > m_rateOps
Rate operations.
void PeerClose(Ptr< Packet > p, const TcpHeader &tcpHeader)
Received a FIN from peer, notify rx buffer.
int Close() override
Close a socket.
bool m_shutdownSend
Send no longer allowed.
bool IsPacingEnabled() const
Return true if packets in the current window should be paced.
void ProcessOptionWScale(const Ptr< const TcpOption > option)
Read and parse the Window scale option.
bool m_closeOnEmpty
Close socket upon tx buffer emptied.
virtual void ReTxTimeout()
An RTO event happened.
void AddOptionSackPermitted(TcpHeader &header)
Add the SACK PERMITTED option to the header.
TracedValue< Time > m_rto
Retransmit timeout.
uint32_t GetSndBufSize() const override
Get the send buffer size.
virtual void ReceivedData(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Recv of a data, put into buffer, call L7 to get it if necessary.
EventId m_timewaitEvent
TIME_WAIT expiration event: Move this socket to CLOSED state.
Ptr< TcpTxBuffer > m_txBuffer
Tx buffer.
static TypeId GetTypeId()
Get the type ID.
uint32_t m_dupAckCount
Dupack counter.
void SetRetxThresh(uint32_t retxThresh)
Set the retransmission threshold (dup ack threshold for a fast retransmit)
int Send(Ptr< Packet > p, uint32_t flags) override
Send data (or dummy data) to the remote host.
TracedCallback< SequenceNumber32, SequenceNumber32 > m_nextTxSequenceTrace
Callback pointer for next tx sequence chaining.
void UpdateBytesInFlight(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState bytes inflight.
EventId m_delAckEvent
Delayed ACK timeout event.
TracedCallback< Time, Time > m_lastRttTrace
Callback pointer for 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.
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
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.
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.
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:96
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:394
Time TimeStep(uint64_t ts)
Scheduler interface.
Definition nstime.h:1451
@ S
second
Definition nstime.h:107
static Time FromDouble(double value, Unit unit)
Create a Time equal to value in unit unit.
Definition nstime.h:513
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:306
AttributeValue implementation for Time.
Definition nstime.h:1456
A simple virtual Timer class.
Definition timer.h:67
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
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:114
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:818
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:221
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:249
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:270
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:1457
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1477
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... > MakeNullCallback()
Definition callback.h:727
#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:243
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#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:250
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#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:439
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:1393
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
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.
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:684
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:179
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:585
Ptr< T > CopyObject(Ptr< const T > object)
Definition object.h:581
ns3::Time timeout