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