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)), // 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
293 : TcpSocket()
294{
295 NS_LOG_FUNCTION(this);
297 m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
300
301 m_tcb->m_rxBuffer = CreateObject<TcpRxBuffer>();
302
303 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
305
306 m_tcb->m_sendEmptyPacketCallback = MakeCallback(&TcpSocketBase::SendEmptyPacket, this);
307
308 bool ok;
309
310 ok = m_tcb->TraceConnectWithoutContext(
311 "PacingRate",
313 NS_ASSERT(ok == true);
314
315 ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
317 NS_ASSERT(ok == true);
318
319 ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
321 NS_ASSERT(ok == true);
322
323 ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
325 NS_ASSERT(ok == true);
326
327 ok = m_tcb->TraceConnectWithoutContext("CongState",
329 NS_ASSERT(ok == true);
330
331 ok = m_tcb->TraceConnectWithoutContext("EcnState",
333 NS_ASSERT(ok == true);
334
335 ok =
336 m_tcb->TraceConnectWithoutContext("NextTxSequence",
338 NS_ASSERT(ok == true);
339
340 ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
342 NS_ASSERT(ok == true);
343
344 ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
346 NS_ASSERT(ok == true);
347
348 ok = m_tcb->TraceConnectWithoutContext("RTT", MakeCallback(&TcpSocketBase::UpdateRtt, this));
349 NS_ASSERT(ok == true);
350
351 ok = m_tcb->TraceConnectWithoutContext("LastRTT",
353 NS_ASSERT(ok == true);
354}
355
357 : TcpSocket(sock),
358 // copy object::m_tid and socket::callbacks
359 m_dupAckCount(sock.m_dupAckCount),
360 m_delAckCount(0),
361 m_delAckMaxCount(sock.m_delAckMaxCount),
362 m_noDelay(sock.m_noDelay),
363 m_synCount(sock.m_synCount),
364 m_synRetries(sock.m_synRetries),
365 m_dataRetrCount(sock.m_dataRetrCount),
366 m_dataRetries(sock.m_dataRetries),
367 m_rto(sock.m_rto),
368 m_minRto(sock.m_minRto),
369 m_clockGranularity(sock.m_clockGranularity),
370 m_delAckTimeout(sock.m_delAckTimeout),
371 m_persistTimeout(sock.m_persistTimeout),
372 m_cnTimeout(sock.m_cnTimeout),
373 m_endPoint(nullptr),
374 m_endPoint6(nullptr),
375 m_node(sock.m_node),
376 m_tcp(sock.m_tcp),
377 m_state(sock.m_state),
378 m_errno(sock.m_errno),
379 m_closeNotified(sock.m_closeNotified),
380 m_closeOnEmpty(sock.m_closeOnEmpty),
381 m_shutdownSend(sock.m_shutdownSend),
382 m_shutdownRecv(sock.m_shutdownRecv),
383 m_connected(sock.m_connected),
384 m_msl(sock.m_msl),
385 m_maxWinSize(sock.m_maxWinSize),
386 m_bytesAckedNotProcessed(sock.m_bytesAckedNotProcessed),
387 m_rWnd(sock.m_rWnd),
388 m_highRxMark(sock.m_highRxMark),
389 m_highRxAckMark(sock.m_highRxAckMark),
390 m_sackEnabled(sock.m_sackEnabled),
391 m_winScalingEnabled(sock.m_winScalingEnabled),
392 m_rcvWindShift(sock.m_rcvWindShift),
393 m_sndWindShift(sock.m_sndWindShift),
394 m_timestampEnabled(sock.m_timestampEnabled),
395 m_timestampToEcho(sock.m_timestampToEcho),
396 m_recover(sock.m_recover),
397 m_recoverActive(sock.m_recoverActive),
398 m_retxThresh(sock.m_retxThresh),
399 m_limitedTx(sock.m_limitedTx),
400 m_isFirstPartialAck(sock.m_isFirstPartialAck),
401 m_txTrace(sock.m_txTrace),
402 m_rxTrace(sock.m_rxTrace),
403 m_pacingTimer(Timer::CANCEL_ON_DESTROY),
404 m_ecnEchoSeq(sock.m_ecnEchoSeq),
405 m_ecnCESeq(sock.m_ecnCESeq),
406 m_ecnCWRSeq(sock.m_ecnCWRSeq)
407{
408 NS_LOG_FUNCTION(this);
409 NS_LOG_LOGIC("Invoked the copy constructor");
410 // Copy the rtt estimator if it is set
411 if (sock.m_rtt)
412 {
413 m_rtt = sock.m_rtt->Copy();
414 }
415 // Reset all callbacks to null
417 Callback<void, Ptr<Socket>, const Address&> vPSA =
420 SetConnectCallback(vPS, vPS);
421 SetDataSentCallback(vPSUI);
422 SetSendCallback(vPSUI);
423 SetRecvCallback(vPS);
425 m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
426 m_tcb = CopyObject(sock.m_tcb);
427 m_tcb->m_rxBuffer = CopyObject(sock.m_tcb->m_rxBuffer);
428
429 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
431
432 if (sock.m_congestionControl)
433 {
436 }
437
438 if (sock.m_recoveryOps)
439 {
440 m_recoveryOps = sock.m_recoveryOps->Fork();
441 }
442
444 if (m_tcb->m_sendEmptyPacketCallback.IsNull())
445 {
446 m_tcb->m_sendEmptyPacketCallback = MakeCallback(&TcpSocketBase::SendEmptyPacket, this);
447 }
448
449 bool ok;
450
451 ok = m_tcb->TraceConnectWithoutContext(
452 "PacingRate",
454
455 ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
457 NS_ASSERT(ok == true);
458
459 ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
461 NS_ASSERT(ok == true);
462
463 ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
465 NS_ASSERT(ok == true);
466
467 ok = m_tcb->TraceConnectWithoutContext("CongState",
469 NS_ASSERT(ok == true);
470
471 ok = m_tcb->TraceConnectWithoutContext("EcnState",
473 NS_ASSERT(ok == true);
474
475 ok =
476 m_tcb->TraceConnectWithoutContext("NextTxSequence",
478 NS_ASSERT(ok == true);
479
480 ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
482 NS_ASSERT(ok == true);
483
484 ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
486 NS_ASSERT(ok == true);
487
488 ok = m_tcb->TraceConnectWithoutContext("RTT", MakeCallback(&TcpSocketBase::UpdateRtt, this));
489 NS_ASSERT(ok == true);
490
491 ok = m_tcb->TraceConnectWithoutContext("LastRTT",
493 NS_ASSERT(ok == true);
494}
495
497{
498 NS_LOG_FUNCTION(this);
499 m_node = nullptr;
500 if (m_endPoint != nullptr)
501 {
503 /*
504 * Upon Bind, an Ipv4Endpoint is allocated and set to m_endPoint, and
505 * DestroyCallback is set to TcpSocketBase::Destroy. If we called
506 * m_tcp->DeAllocate, it will destroy its Ipv4EndpointDemux::DeAllocate,
507 * which in turn destroys my m_endPoint, and in turn invokes
508 * TcpSocketBase::Destroy to nullify m_node, m_endPoint, and m_tcp.
509 */
510 NS_ASSERT(m_endPoint != nullptr);
511 m_tcp->DeAllocate(m_endPoint);
512 NS_ASSERT(m_endPoint == nullptr);
513 }
514 if (m_endPoint6 != nullptr)
515 {
517 NS_ASSERT(m_endPoint6 != nullptr);
518 m_tcp->DeAllocate(m_endPoint6);
519 NS_ASSERT(m_endPoint6 == nullptr);
520 }
521 m_tcp = nullptr;
523}
524
525/* Associate a node with this TCP socket */
526void
528{
529 m_node = node;
530}
531
532/* Associate the L4 protocol (e.g. mux/demux) with this socket */
533void
538
539/* Set an RTT estimator with this socket */
540void
545
546/* Inherit from Socket class: Returns error code */
549{
550 return m_errno;
551}
552
553/* Inherit from Socket class: Returns socket type, NS3_SOCK_STREAM */
556{
557 return NS3_SOCK_STREAM;
558}
559
560/* Inherit from Socket class: Returns associated node */
563{
564 return m_node;
565}
566
567/* Inherit from Socket class: Bind socket to an end-point in TcpL4Protocol */
568int
570{
571 NS_LOG_FUNCTION(this);
572 m_endPoint = m_tcp->Allocate();
573 if (nullptr == m_endPoint)
574 {
576 return -1;
577 }
578
579 m_tcp->AddSocket(this);
580
581 return SetupCallback();
582}
583
584int
586{
587 NS_LOG_FUNCTION(this);
588 m_endPoint6 = m_tcp->Allocate6();
589 if (nullptr == m_endPoint6)
590 {
592 return -1;
593 }
594
595 m_tcp->AddSocket(this);
596
597 return SetupCallback();
598}
599
600/* Inherit from Socket class: Bind socket (with specific address) to an end-point in TcpL4Protocol
601 */
602int
604{
605 NS_LOG_FUNCTION(this << address);
607 {
609 Ipv4Address ipv4 = transport.GetIpv4();
610 uint16_t port = transport.GetPort();
611 if (ipv4 == Ipv4Address::GetAny() && port == 0)
612 {
613 m_endPoint = m_tcp->Allocate();
614 }
615 else if (ipv4 == Ipv4Address::GetAny() && port != 0)
616 {
617 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), port);
618 }
619 else if (ipv4 != Ipv4Address::GetAny() && port == 0)
620 {
621 m_endPoint = m_tcp->Allocate(ipv4);
622 }
623 else if (ipv4 != Ipv4Address::GetAny() && port != 0)
624 {
625 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), ipv4, port);
626 }
627 if (nullptr == m_endPoint)
628 {
630 return -1;
631 }
632 }
633 else if (Inet6SocketAddress::IsMatchingType(address))
634 {
636 Ipv6Address ipv6 = transport.GetIpv6();
637 uint16_t port = transport.GetPort();
638 if (ipv6 == Ipv6Address::GetAny() && port == 0)
639 {
640 m_endPoint6 = m_tcp->Allocate6();
641 }
642 else if (ipv6 == Ipv6Address::GetAny() && port != 0)
643 {
644 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), port);
645 }
646 else if (ipv6 != Ipv6Address::GetAny() && port == 0)
647 {
648 m_endPoint6 = m_tcp->Allocate6(ipv6);
649 }
650 else if (ipv6 != Ipv6Address::GetAny() && port != 0)
651 {
652 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), ipv6, port);
653 }
654 if (nullptr == m_endPoint6)
655 {
657 return -1;
658 }
659 }
660 else
661 {
663 return -1;
664 }
665
666 m_tcp->AddSocket(this);
667
668 NS_LOG_LOGIC("TcpSocketBase " << this << " got an endpoint: " << m_endPoint);
669
670 return SetupCallback();
671}
672
673void
675{
677 (m_state == CLOSED) || threshold == m_tcb->m_initialSsThresh,
678 "TcpSocketBase::SetSSThresh() cannot change initial ssThresh after connection started.");
679
680 m_tcb->m_initialSsThresh = threshold;
681}
682
685{
686 return m_tcb->m_initialSsThresh;
687}
688
689void
691{
693 (m_state == CLOSED) || cwnd == m_tcb->m_initialCWnd,
694 "TcpSocketBase::SetInitialCwnd() cannot change initial cwnd after connection started.");
695
696 m_tcb->m_initialCWnd = cwnd;
697}
698
701{
702 return m_tcb->m_initialCWnd;
703}
704
705/* Inherit from Socket class: Initiate connection to a remote address:port */
706int
708{
709 NS_LOG_FUNCTION(this << address);
710
711 // If haven't do so, Bind() this socket first
713 {
714 if (m_endPoint == nullptr)
715 {
716 if (Bind() == -1)
717 {
718 NS_ASSERT(m_endPoint == nullptr);
719 return -1; // Bind() failed
720 }
721 NS_ASSERT(m_endPoint != nullptr);
722 }
724 m_endPoint->SetPeer(transport.GetIpv4(), transport.GetPort());
725 m_endPoint6 = nullptr;
726
727 // Get the appropriate local address and port number from the routing protocol and set up
728 // endpoint
729 if (SetupEndpoint() != 0)
730 {
731 NS_LOG_ERROR("Route to destination does not exist ?!");
732 return -1;
733 }
734 }
735 else if (Inet6SocketAddress::IsMatchingType(address))
736 {
737 // If we are operating on a v4-mapped address, translate the address to
738 // a v4 address and re-call this function
740 Ipv6Address v6Addr = transport.GetIpv6();
741 if (v6Addr.IsIpv4MappedAddress())
742 {
743 Ipv4Address v4Addr = v6Addr.GetIpv4MappedAddress();
744 return Connect(InetSocketAddress(v4Addr, transport.GetPort()));
745 }
746
747 if (m_endPoint6 == nullptr)
748 {
749 if (Bind6() == -1)
750 {
751 NS_ASSERT(m_endPoint6 == nullptr);
752 return -1; // Bind() failed
753 }
754 NS_ASSERT(m_endPoint6 != nullptr);
755 }
756 m_endPoint6->SetPeer(v6Addr, transport.GetPort());
757 m_endPoint = nullptr;
758
759 // Get the appropriate local address and port number from the routing protocol and set up
760 // endpoint
761 if (SetupEndpoint6() != 0)
762 {
763 NS_LOG_ERROR("Route to destination does not exist ?!");
764 return -1;
765 }
766 }
767 else
768 {
770 return -1;
771 }
772
773 // Re-initialize parameters in case this socket is being reused after CLOSE
774 m_rtt->Reset();
777
778 // DoConnect() will do state-checking and send a SYN packet
779 return DoConnect();
780}
781
782/* Inherit from Socket class: Listen on the endpoint for an incoming connection */
783int
785{
786 NS_LOG_FUNCTION(this);
787
788 // Linux quits EINVAL if we're not in CLOSED state, so match what they do
789 if (m_state != CLOSED)
790 {
792 return -1;
793 }
794 // In other cases, set the state to LISTEN and done
795 NS_LOG_DEBUG("CLOSED -> LISTEN");
796 m_state = LISTEN;
797 return 0;
798}
799
800/* Inherit from Socket class: Kill this socket and signal the peer (if any) */
801int
803{
804 NS_LOG_FUNCTION(this);
805 /// @internal
806 /// First we check to see if there is any unread rx data.
807 /// \bugid{426} claims we should send reset in this case.
808 if (m_tcb->m_rxBuffer->Size() != 0)
809 {
810 NS_LOG_WARN("Socket " << this << " << unread rx data during close. Sending reset."
811 << "This is probably due to a bad sink application; check its code");
812 SendRST();
813 return 0;
814 }
815
816 if (m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence) > 0)
817 { // App close with pending data must wait until all data transmitted
818 if (!m_closeOnEmpty)
819 {
820 m_closeOnEmpty = true;
821 NS_LOG_INFO("Socket " << this << " deferring close, state " << TcpStateName[m_state]);
822 }
823 return 0;
824 }
825 return DoClose();
826}
827
828/* Inherit from Socket class: Signal a termination of send */
829int
831{
832 NS_LOG_FUNCTION(this);
833
834 // this prevents data from being added to the buffer
835 m_shutdownSend = true;
836 m_closeOnEmpty = true;
837 // if buffer is already empty, send a fin now
838 // otherwise fin will go when buffer empties.
839 if (m_txBuffer->Size() == 0)
840 {
842 {
843 NS_LOG_INFO("Empty tx buffer, send fin");
845
846 if (m_state == ESTABLISHED)
847 { // On active close: I am the first one to send FIN
848 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
850 }
851 else
852 { // On passive close: Peer sent me FIN already
853 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
855 }
856 }
857 }
858
859 return 0;
860}
861
862/* Inherit from Socket class: Signal a termination of receive */
863int
865{
866 NS_LOG_FUNCTION(this);
867 m_shutdownRecv = true;
868 return 0;
869}
870
871/* Inherit from Socket class: Send a packet. Parameter flags is not used.
872 Packet has no TCP header. Invoked by upper-layer application */
873int
875{
876 NS_LOG_FUNCTION(this << p);
877 NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Send()");
879 {
880 // Store the packet into Tx buffer
881 if (!m_txBuffer->Add(p))
882 { // TxBuffer overflow, send failed
884 return -1;
885 }
886 if (m_shutdownSend)
887 {
889 return -1;
890 }
891
892 m_rateOps->CalculateAppLimited(m_tcb->m_cWnd,
893 m_tcb->m_bytesInFlight,
894 m_tcb->m_segmentSize,
895 m_txBuffer->TailSequence(),
896 m_tcb->m_nextTxSequence,
897 m_txBuffer->GetLost(),
898 m_txBuffer->GetRetransmitsCount());
899
900 // Submit the data to lower layers
901 NS_LOG_LOGIC("txBufSize=" << m_txBuffer->Size() << " state " << TcpStateName[m_state]);
902 if ((m_state == ESTABLISHED || m_state == CLOSE_WAIT) && AvailableWindow() > 0)
903 { // Try to send the data out: Add a little step to allow the application
904 // to fill the buffer
906 {
909 this,
911 }
912 }
913 return p->GetSize();
914 }
915 else
916 { // Connection not established yet
918 return -1; // Send failure
919 }
920}
921
922/* Inherit from Socket class: In TcpSocketBase, it is same as Send() call */
923int
924TcpSocketBase::SendTo(Ptr<Packet> p, uint32_t flags, const Address& /* address */)
925{
926 return Send(p, flags); // SendTo() and Send() are the same
927}
928
929/* Inherit from Socket class: Return data to upper-layer application. Parameter flags
930 is not used. Data is returned as a packet of size no larger than maxSize */
933{
934 NS_LOG_FUNCTION(this);
935 NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Recv()");
936 if (m_tcb->m_rxBuffer->Size() == 0 && m_state == CLOSE_WAIT)
937 {
938 return Create<Packet>(); // Send EOF on connection close
939 }
940 Ptr<Packet> outPacket = m_tcb->m_rxBuffer->Extract(maxSize);
941 return outPacket;
942}
943
944/* Inherit from Socket class: Recv and return the remote's address */
947{
948 NS_LOG_FUNCTION(this << maxSize << flags);
949 Ptr<Packet> packet = Recv(maxSize, flags);
950 // Null packet means no data to read, and an empty packet indicates EOF
951 if (packet && packet->GetSize() != 0)
952 {
953 if (m_endPoint != nullptr)
954 {
955 fromAddress =
957 }
958 else if (m_endPoint6 != nullptr)
959 {
960 fromAddress =
962 }
963 else
964 {
965 fromAddress = InetSocketAddress(Ipv4Address::GetZero(), 0);
966 }
967 }
968 return packet;
969}
970
971/* Inherit from Socket class: Get the max number of bytes an app can send */
974{
975 NS_LOG_FUNCTION(this);
976 return m_txBuffer->Available();
977}
978
979/* Inherit from Socket class: Get the max number of bytes an app can read */
982{
983 NS_LOG_FUNCTION(this);
984 return m_tcb->m_rxBuffer->Available();
985}
986
987/* Inherit from Socket class: Return local address:port */
988int
990{
991 NS_LOG_FUNCTION(this);
992 if (m_endPoint != nullptr)
993 {
995 }
996 else if (m_endPoint6 != nullptr)
997 {
999 }
1000 else
1001 { // It is possible to call this method on a socket without a name
1002 // in which case, behavior is unspecified
1003 // Should this return an InetSocketAddress or an Inet6SocketAddress?
1005 }
1006 return 0;
1007}
1008
1009int
1011{
1012 NS_LOG_FUNCTION(this << address);
1013
1014 if (!m_endPoint && !m_endPoint6)
1015 {
1017 return -1;
1018 }
1019
1020 if (m_endPoint)
1021 {
1023 }
1024 else if (m_endPoint6)
1025 {
1027 }
1028 else
1029 {
1030 NS_ASSERT(false);
1031 }
1032
1033 return 0;
1034}
1035
1036/* Inherit from Socket class: Bind this socket to the specified NetDevice */
1037void
1039{
1040 NS_LOG_FUNCTION(netdevice);
1041 Socket::BindToNetDevice(netdevice); // Includes sanity check
1042 if (m_endPoint != nullptr)
1043 {
1044 m_endPoint->BindToNetDevice(netdevice);
1045 }
1046
1047 if (m_endPoint6 != nullptr)
1048 {
1049 m_endPoint6->BindToNetDevice(netdevice);
1050 }
1051}
1052
1053/* Clean up after Bind. Set up callback functions in the end-point. */
1054int
1084
1085/* Perform the real connection tasks: Send SYN if allowed, RST if invalid */
1086int
1088{
1089 NS_LOG_FUNCTION(this);
1090
1091 // A new connection is allowed only if this socket does not have a connection
1092 if (m_state == CLOSED || m_state == LISTEN || m_state == SYN_SENT || m_state == LAST_ACK ||
1094 { // send a SYN packet and change state into SYN_SENT
1095 // send a SYN packet with ECE and CWR flags set if sender is ECN capable
1096 if (m_tcb->m_useEcn == TcpSocketState::On)
1097 {
1099 }
1100 else
1101 {
1103 }
1104 NS_LOG_DEBUG(TcpStateName[m_state] << " -> SYN_SENT");
1105 m_state = SYN_SENT;
1106 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED; // because sender is not yet aware about
1107 // receiver's ECN capability
1108 }
1109 else if (m_state != TIME_WAIT)
1110 { // In states SYN_RCVD, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, and CLOSING, an connection
1111 // exists. We send RST, tear down everything, and close this socket.
1112 SendRST();
1114 }
1115 return 0;
1116}
1117
1118/* Do the action to close the socket. Usually send a packet with appropriate
1119 flags depended on the current m_state. */
1120int
1122{
1123 NS_LOG_FUNCTION(this);
1124 switch (m_state)
1125 {
1126 case SYN_RCVD:
1127 case ESTABLISHED:
1128 // send FIN to close the peer
1130 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
1132 break;
1133 case CLOSE_WAIT:
1134 // send FIN+ACK to close the peer
1136 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
1137 m_state = LAST_ACK;
1138 break;
1139 case SYN_SENT:
1140 case CLOSING:
1141 // Send RST if application closes in SYN_SENT and CLOSING
1142 SendRST();
1144 break;
1145 case LISTEN:
1146 // In this state, move to CLOSED and tear down the end point
1148 break;
1149 case LAST_ACK:
1150 case CLOSED:
1151 case FIN_WAIT_1:
1152 case FIN_WAIT_2:
1153 case TIME_WAIT:
1154 default: /* mute compiler */
1155 // Do nothing in these five states
1156 break;
1157 }
1158 return 0;
1159}
1160
1161/* Peacefully close the socket by notifying the upper layer and deallocate end point */
1162void
1164{
1165 NS_LOG_FUNCTION(this);
1166
1167 if (!m_closeNotified)
1168 {
1170 m_closeNotified = true;
1171 }
1173 {
1175 }
1176 NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSED");
1177 m_state = CLOSED;
1179}
1180
1181/* Tell if a sequence number range is out side the range that my rx buffer can
1182 accept */
1183bool
1185{
1186 if (m_state == LISTEN || m_state == SYN_SENT || m_state == SYN_RCVD)
1187 { // Rx buffer in these states are not initialized.
1188 return false;
1189 }
1190 if (m_state == LAST_ACK || m_state == CLOSING || m_state == CLOSE_WAIT)
1191 { // In LAST_ACK and CLOSING states, it only wait for an ACK and the
1192 // sequence number must equals to m_rxBuffer->NextRxSequence ()
1193 return (m_tcb->m_rxBuffer->NextRxSequence() != head);
1194 }
1195
1196 // In all other cases, check if the sequence number is in range
1197 return (tail < m_tcb->m_rxBuffer->NextRxSequence() ||
1198 m_tcb->m_rxBuffer->MaxRxSequence() <= head);
1199}
1200
1201/* Function called by the L3 protocol when it received a packet to pass on to
1202 the TCP. This function is registered as the "RxCallback" function in
1203 SetupCallback(), which invoked by Bind(), and CompleteFork() */
1204void
1206 Ipv4Header header,
1207 uint16_t port,
1208 Ptr<Ipv4Interface> incomingInterface)
1209{
1210 NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint->GetPeerAddress() << ":"
1211 << m_endPoint->GetPeerPort() << " to " << m_endPoint->GetLocalAddress()
1212 << ":" << m_endPoint->GetLocalPort());
1213
1214 Address fromAddress = InetSocketAddress(header.GetSource(), port);
1216
1217 TcpHeader tcpHeader;
1218 uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1219
1220 if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1221 bytesRemoved,
1222 packet->GetSize() - bytesRemoved))
1223 {
1224 return;
1225 }
1226
1227 if (header.GetEcn() == Ipv4Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1228 {
1229 NS_LOG_INFO("Received CE flag is valid");
1230 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
1231 m_ecnCESeq = tcpHeader.GetSequenceNumber();
1232 m_tcb->m_ecnState = TcpSocketState::ECN_CE_RCVD;
1234 }
1235 else if (header.GetEcn() != Ipv4Header::ECN_NotECT &&
1236 m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED)
1237 {
1239 }
1240
1241 DoForwardUp(packet, fromAddress, toAddress);
1242}
1243
1244void
1246 Ipv6Header header,
1247 uint16_t port,
1248 Ptr<Ipv6Interface> incomingInterface)
1249{
1250 NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint6->GetPeerAddress() << ":"
1252 << ":" << m_endPoint6->GetLocalPort());
1253
1254 Address fromAddress = Inet6SocketAddress(header.GetSource(), port);
1256
1257 TcpHeader tcpHeader;
1258 uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1259
1260 if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1261 bytesRemoved,
1262 packet->GetSize() - bytesRemoved))
1263 {
1264 return;
1265 }
1266
1267 if (header.GetEcn() == Ipv6Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1268 {
1269 NS_LOG_INFO("Received CE flag is valid");
1270 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
1271 m_ecnCESeq = tcpHeader.GetSequenceNumber();
1272 m_tcb->m_ecnState = TcpSocketState::ECN_CE_RCVD;
1274 }
1275 else if (header.GetEcn() != Ipv6Header::ECN_NotECT)
1276 {
1278 }
1279
1280 DoForwardUp(packet, fromAddress, toAddress);
1281}
1282
1283void
1285 uint8_t icmpTtl,
1286 uint8_t icmpType,
1287 uint8_t icmpCode,
1288 uint32_t icmpInfo)
1289{
1290 NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1291 << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1292 << icmpInfo);
1293 if (!m_icmpCallback.IsNull())
1294 {
1295 m_icmpCallback(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1296 }
1297}
1298
1299void
1301 uint8_t icmpTtl,
1302 uint8_t icmpType,
1303 uint8_t icmpCode,
1304 uint32_t icmpInfo)
1305{
1306 NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1307 << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1308 << icmpInfo);
1309 if (!m_icmpCallback6.IsNull())
1310 {
1311 m_icmpCallback6(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1312 }
1313}
1314
1315bool
1317 const uint32_t tcpHeaderSize,
1318 const uint32_t tcpPayloadSize)
1319{
1320 if (tcpHeaderSize == 0 || tcpHeaderSize > 60)
1321 {
1322 NS_LOG_ERROR("Bytes removed: " << tcpHeaderSize << " invalid");
1323 return false; // Discard invalid packet
1324 }
1325 else if (tcpPayloadSize > 0 && OutOfRange(seq, seq + tcpPayloadSize))
1326 {
1327 // Discard fully out of range data packets
1328 NS_LOG_WARN("At state " << TcpStateName[m_state] << " received packet of seq [" << seq
1329 << ":" << seq + tcpPayloadSize << ") out of range ["
1330 << m_tcb->m_rxBuffer->NextRxSequence() << ":"
1331 << m_tcb->m_rxBuffer->MaxRxSequence() << ")");
1332 // Acknowledgement should be sent for all unacceptable packets (RFC793, p.69)
1334 return false;
1335 }
1336 return true;
1337}
1338
1339void
1340TcpSocketBase::DoForwardUp(Ptr<Packet> packet, const Address& fromAddress, const Address& toAddress)
1341{
1342 // in case the packet still has a priority tag attached, remove it
1343 SocketPriorityTag priorityTag;
1344 packet->RemovePacketTag(priorityTag);
1345
1346 // Peel off TCP header
1347 TcpHeader tcpHeader;
1348 packet->RemoveHeader(tcpHeader);
1349 SequenceNumber32 seq = tcpHeader.GetSequenceNumber();
1350
1351 if (m_state == ESTABLISHED && !(tcpHeader.GetFlags() & TcpHeader::RST))
1352 {
1353 // Check if the sender has responded to ECN echo by reducing the Congestion Window
1354 if (tcpHeader.GetFlags() & TcpHeader::CWR)
1355 {
1356 // Check if a packet with CE bit set is received. If there is no CE bit set, then change
1357 // the state to ECN_IDLE to stop sending ECN Echo messages. If there is CE bit set, the
1358 // packet should continue sending ECN Echo messages
1359 //
1360 if (m_tcb->m_ecnState != TcpSocketState::ECN_CE_RCVD)
1361 {
1362 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
1363 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
1364 }
1365 }
1366 }
1367
1368 m_rxTrace(packet, tcpHeader, this);
1369
1370 if (tcpHeader.GetFlags() & TcpHeader::SYN)
1371 {
1372 /* The window field in a segment where the SYN bit is set (i.e., a <SYN>
1373 * or <SYN,ACK>) MUST NOT be scaled (from RFC 7323 page 9). But should be
1374 * saved anyway..
1375 */
1376 m_rWnd = tcpHeader.GetWindowSize();
1377
1379 {
1381 }
1382 else
1383 {
1384 m_winScalingEnabled = false;
1385 }
1386
1388 {
1390 }
1391 else
1392 {
1393 m_sackEnabled = false;
1394 m_txBuffer->SetSackEnabled(false);
1395 }
1396
1397 // When receiving a <SYN> or <SYN-ACK> we should adapt TS to the other end
1398 if (tcpHeader.HasOption(TcpOption::TS) && m_timestampEnabled)
1399 {
1401 tcpHeader.GetSequenceNumber());
1402 }
1403 else
1404 {
1405 m_timestampEnabled = false;
1406 }
1407
1408 // Initialize cWnd and ssThresh
1409 m_tcb->m_cWnd = GetInitialCwnd() * GetSegSize();
1410 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
1411 m_tcb->m_ssThresh = GetInitialSSThresh();
1412
1413 if (tcpHeader.GetFlags() & TcpHeader::ACK)
1414 {
1415 EstimateRtt(tcpHeader);
1416 m_highRxAckMark = tcpHeader.GetAckNumber();
1417 }
1418 }
1419 else if (tcpHeader.GetFlags() & TcpHeader::ACK)
1420 {
1421 NS_ASSERT(!(tcpHeader.GetFlags() & TcpHeader::SYN));
1423 {
1424 if (!tcpHeader.HasOption(TcpOption::TS))
1425 {
1426 // Ignoring segment without TS, RFC 7323
1427 NS_LOG_LOGIC("At state " << TcpStateName[m_state] << " received packet of seq ["
1428 << seq << ":" << seq + packet->GetSize()
1429 << ") without TS option. Silently discard it");
1430 return;
1431 }
1432 else
1433 {
1435 tcpHeader.GetSequenceNumber());
1436 }
1437 }
1438
1439 EstimateRtt(tcpHeader);
1440 UpdateWindowSize(tcpHeader);
1441 }
1442
1443 if (m_rWnd.Get() == 0 && m_persistEvent.IsExpired())
1444 { // Zero window: Enter persist state to send 1 byte to probe
1445 NS_LOG_LOGIC(this << " Enter zerowindow persist state");
1447 this << " Cancelled ReTxTimeout event which was set to expire at "
1448 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
1450 NS_LOG_LOGIC("Schedule persist timeout at time "
1451 << Simulator::Now().GetSeconds() << " to expire at time "
1452 << (Simulator::Now() + m_persistTimeout).GetSeconds());
1456 }
1457
1458 // TCP state machine code in different process functions
1459 // C.f.: tcp_rcv_state_process() in tcp_input.c in Linux kernel
1460 switch (m_state)
1461 {
1462 case ESTABLISHED:
1463 ProcessEstablished(packet, tcpHeader);
1464 break;
1465 case LISTEN:
1466 ProcessListen(packet, tcpHeader, fromAddress, toAddress);
1467 break;
1468 case TIME_WAIT:
1469 // Do nothing
1470 break;
1471 case CLOSED:
1472 // Send RST if the incoming packet is not a RST
1473 if ((tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG)) != TcpHeader::RST)
1474 { // Since m_endPoint is not configured yet, we cannot use SendRST here
1475 TcpHeader h;
1478 h.SetSequenceNumber(m_tcb->m_nextTxSequence);
1479 h.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
1480 h.SetSourcePort(tcpHeader.GetDestinationPort());
1481 h.SetDestinationPort(tcpHeader.GetSourcePort());
1483 AddOptions(h);
1484 m_txTrace(p, h, this);
1485 m_tcp->SendPacket(p, h, toAddress, fromAddress, m_boundnetdevice);
1486 }
1487 break;
1488 case SYN_SENT:
1489 ProcessSynSent(packet, tcpHeader);
1490 break;
1491 case SYN_RCVD:
1492 ProcessSynRcvd(packet, tcpHeader, fromAddress, toAddress);
1493 break;
1494 case FIN_WAIT_1:
1495 case FIN_WAIT_2:
1496 case CLOSE_WAIT:
1497 ProcessWait(packet, tcpHeader);
1498 break;
1499 case CLOSING:
1500 ProcessClosing(packet, tcpHeader);
1501 break;
1502 case LAST_ACK:
1503 ProcessLastAck(packet, tcpHeader);
1504 break;
1505 default: // mute compiler
1506 break;
1507 }
1508
1509 if (m_rWnd.Get() != 0 && m_persistEvent.IsPending())
1510 { // persist probes end, the other end has increased the window
1512 NS_LOG_LOGIC(this << " Leaving zerowindow persist state");
1514
1516 }
1517}
1518
1519/* Received a packet upon ESTABLISHED state. This function is mimicking the
1520 role of tcp_rcv_established() in tcp_input.c in Linux kernel. */
1521void
1523{
1524 NS_LOG_FUNCTION(this << tcpHeader);
1525
1526 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
1527 uint8_t tcpflags =
1529
1530 // Different flags are different events
1531 if (tcpflags == TcpHeader::ACK)
1532 {
1533 if (tcpHeader.GetAckNumber() < m_txBuffer->HeadSequence())
1534 {
1535 // Case 1: If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored.
1536 // Pag. 72 RFC 793
1537 NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1538 << " SND.UNA = " << m_txBuffer->HeadSequence());
1539
1540 // TODO: RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation]
1541 }
1542 else if (tcpHeader.GetAckNumber() > m_tcb->m_highTxMark)
1543 {
1544 // If the ACK acks something not yet sent (SEG.ACK > HighTxMark) then
1545 // send an ACK, drop the segment, and return.
1546 // Pag. 72 RFC 793
1547 NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1548 << " HighTxMark = " << m_tcb->m_highTxMark);
1549
1550 // Receiver sets ECE flags when it receives a packet with CE bit on or sender hasn't
1551 // responded to ECN echo sent by receiver
1552 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
1554 {
1557 << " -> ECN_SENDING_ECE");
1559 }
1560 else
1561 {
1563 }
1564 }
1565 else
1566 {
1567 // SND.UNA < SEG.ACK =< HighTxMark
1568 // Pag. 72 RFC 793
1569 ReceivedAck(packet, tcpHeader);
1570 }
1571 }
1572 else if (tcpflags == TcpHeader::SYN || tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
1573 {
1574 // (a) Received SYN, old NS-3 behaviour is to set state to SYN_RCVD and
1575 // respond with a SYN+ACK. But it is not a legal state transition as of
1576 // RFC793. Thus this is ignored.
1577
1578 // (b) No action for received SYN+ACK, it is probably a duplicated packet
1579 }
1580 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
1581 { // Received FIN or FIN+ACK, bring down this socket nicely
1582 PeerClose(packet, tcpHeader);
1583 }
1584 else if (tcpflags == 0)
1585 { // No flags means there is only data
1586 ReceivedData(packet, tcpHeader);
1587 if (m_tcb->m_rxBuffer->Finished())
1588 {
1589 PeerClose(packet, tcpHeader);
1590 }
1591 }
1592 else
1593 { // Received RST or the TCP flags is invalid, in either case, terminate this socket
1594 if (tcpflags != TcpHeader::RST)
1595 { // this must be an invalid flag, send reset
1596 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
1597 << " received. Reset packet is sent.");
1598 SendRST();
1599 }
1601 }
1602}
1603
1604bool
1606{
1607 NS_LOG_FUNCTION(this << static_cast<uint32_t>(kind));
1608
1609 switch (kind)
1610 {
1611 case TcpOption::TS:
1612 return m_timestampEnabled;
1614 return m_winScalingEnabled;
1616 case TcpOption::SACK:
1617 return m_sackEnabled;
1618 default:
1619 break;
1620 }
1621 return false;
1622}
1623
1624void
1625TcpSocketBase::ReadOptions(const TcpHeader& tcpHeader, uint32_t* bytesSacked)
1626{
1627 NS_LOG_FUNCTION(this << tcpHeader);
1628
1629 for (const auto& option : tcpHeader.GetOptionList())
1630 {
1631 // Check only for ACK options here
1632 switch (option->GetKind())
1633 {
1634 case TcpOption::SACK:
1635 *bytesSacked = ProcessOptionSack(option);
1636 break;
1637 default:
1638 continue;
1639 }
1640 }
1641}
1642
1643// Sender should reduce the Congestion Window as a response to receiver's
1644// ECN Echo notification only once per window
1645void
1647{
1648 NS_LOG_FUNCTION(this << currentDelivered);
1649 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, BytesInFlight());
1650 NS_LOG_DEBUG("Reduce ssThresh to " << m_tcb->m_ssThresh);
1651 // Do not update m_cWnd, under assumption that recovery process will
1652 // gradually bring it down to m_ssThresh. Update the 'inflated' value of
1653 // cWnd used for tracing, however.
1654 m_tcb->m_cWndInfl = m_tcb->m_ssThresh;
1655 NS_ASSERT(m_tcb->m_congState != TcpSocketState::CA_CWR);
1656 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_CWR");
1657 m_tcb->m_congState = TcpSocketState::CA_CWR;
1658 // CWR state will be exited when the ack exceeds the m_recover variable.
1659 // Do not set m_recoverActive (which applies to a loss-based recovery)
1660 // m_recover corresponds to Linux tp->high_seq
1661 m_recover = m_tcb->m_highTxMark;
1662 if (!m_congestionControl->HasCongControl())
1663 {
1664 // If there is a recovery algorithm, invoke it.
1665 m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1666 NS_LOG_INFO("Enter CWR recovery mode; set cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1667 << m_tcb->m_ssThresh << ", recover to "
1668 << m_recover);
1669 }
1670}
1671
1672void
1674{
1675 NS_LOG_FUNCTION(this);
1677
1678 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_RECOVERY");
1679
1680 if (!m_sackEnabled)
1681 {
1682 // One segment has left the network, PLUS the head is lost
1683 m_txBuffer->AddRenoSack();
1684 m_txBuffer->MarkHeadAsLost();
1685 }
1686 else
1687 {
1688 if (!m_txBuffer->IsLost(m_txBuffer->HeadSequence()))
1689 {
1690 // We received 3 dupacks, but the head is not marked as lost
1691 // (received less than 3 SACK block ahead).
1692 // Manually set it as lost.
1693 m_txBuffer->MarkHeadAsLost();
1694 }
1695 }
1696
1697 // RFC 6675, point (4):
1698 // (4) Invoke fast retransmit and enter loss recovery as follows:
1699 // (4.1) RecoveryPoint = HighData
1700 m_recover = m_tcb->m_highTxMark;
1701 m_recoverActive = true;
1702
1704 m_tcb->m_congState = TcpSocketState::CA_RECOVERY;
1705
1706 // (4.2) ssthresh = cwnd = (FlightSize / 2)
1707 // If SACK is not enabled, still consider the head as 'in flight' for
1708 // compatibility with old ns-3 versions
1709 uint32_t bytesInFlight =
1710 m_sackEnabled ? BytesInFlight() : BytesInFlight() + m_tcb->m_segmentSize;
1711 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, bytesInFlight);
1712
1713 if (!m_congestionControl->HasCongControl())
1714 {
1715 m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1716 NS_LOG_INFO(m_dupAckCount << " dupack. Enter fast recovery mode."
1717 << "Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1718 << m_tcb->m_ssThresh << " at fast recovery seqnum " << m_recover
1719 << " calculated in flight: " << bytesInFlight);
1720 }
1721
1722 // (4.3) Retransmit the first data segment presumed dropped
1723 uint32_t sz = SendDataPacket(m_highRxAckMark, m_tcb->m_segmentSize, true);
1724 NS_ASSERT_MSG(sz > 0, "SendDataPacket returned zero, indicating zero bytes were sent");
1725 // (4.4) Run SetPipe ()
1726 // (4.5) Proceed to step (C)
1727 // these steps are done after the ProcessAck function (SendPendingData)
1728}
1729
1730void
1732{
1733 NS_LOG_FUNCTION(this);
1734 // NOTE: We do not count the DupAcks received in CA_LOSS, because we
1735 // don't know if they are generated by a spurious retransmission or because
1736 // of a real packet loss. With SACK, it is easy to know, but we do not consider
1737 // dupacks. Without SACK, there are some heuristics in the RFC 6582, but
1738 // for now, we do not implement it, leading to ignoring the dupacks.
1739 if (m_tcb->m_congState == TcpSocketState::CA_LOSS)
1740 {
1741 return;
1742 }
1743
1744 // RFC 6675, Section 5, 3rd paragraph:
1745 // If the incoming ACK is a duplicate acknowledgment per the definition
1746 // in Section 2 (regardless of its status as a cumulative
1747 // acknowledgment), and the TCP is not currently in loss recovery
1748 // the TCP MUST increase DupAcks by one ...
1749 if (m_tcb->m_congState != TcpSocketState::CA_RECOVERY)
1750 {
1751 ++m_dupAckCount;
1752 }
1753
1754 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
1755 {
1756 // From Open we go Disorder
1758 "From OPEN->DISORDER but with " << m_dupAckCount << " dup ACKs");
1759
1761 m_tcb->m_congState = TcpSocketState::CA_DISORDER;
1762
1763 NS_LOG_DEBUG("CA_OPEN -> CA_DISORDER");
1764 }
1765
1766 if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
1767 {
1768 if (!m_sackEnabled)
1769 {
1770 // If we are in recovery and we receive a dupack, one segment
1771 // has left the network. This is equivalent to a SACK of one block.
1772 m_txBuffer->AddRenoSack();
1773 }
1774 if (!m_congestionControl->HasCongControl())
1775 {
1776 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, true);
1777 NS_LOG_INFO(m_dupAckCount << " Dupack received in fast recovery mode."
1778 "Increase cwnd to "
1779 << m_tcb->m_cWnd);
1780 }
1781 }
1782 else if (m_tcb->m_congState == TcpSocketState::CA_DISORDER)
1783 {
1784 // m_dupackCount should not exceed its threshold in CA_DISORDER state
1785 // when m_recoverActive has not been set. When recovery point
1786 // have been set after timeout, the sender could enter into CA_DISORDER
1787 // after receiving new ACK smaller than m_recover. After that, m_dupackCount
1788 // can be equal and larger than m_retxThresh and we should avoid entering
1789 // CA_RECOVERY and reducing sending rate again.
1791
1792 // RFC 6675, Section 5, continuing:
1793 // ... and take the following steps:
1794 // (1) If DupAcks >= DupThresh, go to step (4).
1795 // Sequence number comparison (m_highRxAckMark >= m_recover) will take
1796 // effect only when m_recover has been set. Hence, we can avoid to use
1797 // m_recover in the last congestion event and fail to enter
1798 // CA_RECOVERY when sequence number is advanced significantly since
1799 // the last congestion event, which could be common for
1800 // bandwidth-greedy application in high speed and reliable network
1801 // (such as datacenter network) whose sending rate is constrained by
1802 // TCP socket buffer size at receiver side.
1803 if ((m_dupAckCount == m_retxThresh) &&
1805 {
1806 EnterRecovery(currentDelivered);
1808 }
1809 // (2) If DupAcks < DupThresh but IsLost (HighACK + 1) returns true
1810 // (indicating at least three segments have arrived above the current
1811 // cumulative acknowledgment point, which is taken to indicate loss)
1812 // go to step (4). Note that m_highRxAckMark is (HighACK + 1)
1813 else if (m_txBuffer->IsLost(m_highRxAckMark))
1814 {
1815 EnterRecovery(currentDelivered);
1817 }
1818 else
1819 {
1820 // (3) The TCP MAY transmit previously unsent data segments as per
1821 // Limited Transmit [RFC5681] ...except that the number of octets
1822 // which may be sent is governed by pipe and cwnd as follows:
1823 //
1824 // (3.1) Set HighRxt to HighACK.
1825 // Not clear in RFC. We don't do this here, since we still have
1826 // to retransmit the segment.
1827
1828 if (!m_sackEnabled && m_limitedTx)
1829 {
1830 m_txBuffer->AddRenoSack();
1831
1832 // In limited transmit, cwnd Infl is not updated.
1833 }
1834 }
1835 }
1836}
1837
1838/* Process the newly received ACK */
1839void
1841{
1842 NS_LOG_FUNCTION(this << tcpHeader);
1843
1844 NS_ASSERT(0 != (tcpHeader.GetFlags() & TcpHeader::ACK));
1845 NS_ASSERT(m_tcb->m_segmentSize > 0);
1846
1847 uint32_t previousLost = m_txBuffer->GetLost();
1848 uint32_t priorInFlight = m_tcb->m_bytesInFlight.Get();
1849
1850 // RFC 6675, Section 5, 1st paragraph:
1851 // Upon the receipt of any ACK containing SACK information, the
1852 // scoreboard MUST be updated via the Update () routine (done in ReadOptions)
1853 uint32_t bytesSacked = 0;
1854 uint64_t previousDelivered = m_rateOps->GetConnectionRate().m_delivered;
1855 ReadOptions(tcpHeader, &bytesSacked);
1856
1857 SequenceNumber32 ackNumber = tcpHeader.GetAckNumber();
1858 SequenceNumber32 oldHeadSequence = m_txBuffer->HeadSequence();
1859
1860 if (ackNumber < oldHeadSequence)
1861 {
1862 NS_LOG_DEBUG("Possibly received a stale ACK (ack number < head sequence)");
1863 // If there is any data piggybacked, store it into m_rxBuffer
1864 if (packet->GetSize() > 0)
1865 {
1866 ReceivedData(packet, tcpHeader);
1867 }
1868 return;
1869 }
1870 if ((ackNumber > oldHeadSequence) && (ackNumber < m_recover) &&
1871 (m_tcb->m_congState == TcpSocketState::CA_RECOVERY))
1872 {
1873 uint32_t segAcked = (ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
1874 for (uint32_t i = 0; i < segAcked; i++)
1875 {
1876 if (m_txBuffer->IsRetransmittedDataAcked(ackNumber - (i * m_tcb->m_segmentSize)))
1877 {
1878 m_tcb->m_isRetransDataAcked = true;
1879 NS_LOG_DEBUG("Ack Number " << ackNumber << "is ACK of retransmitted packet.");
1880 }
1881 }
1882 }
1883
1884 m_txBuffer->DiscardUpTo(ackNumber, MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
1885
1886 auto currentDelivered =
1887 static_cast<uint32_t>(m_rateOps->GetConnectionRate().m_delivered - previousDelivered);
1888 m_tcb->m_lastAckedSackedBytes = currentDelivered;
1889
1890 if (m_tcb->m_congState == TcpSocketState::CA_CWR && (ackNumber > m_recover))
1891 {
1892 // Recovery is over after the window exceeds m_recover
1893 // (although it may be re-entered below if ECE is still set)
1894 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_OPEN");
1895 m_tcb->m_congState = TcpSocketState::CA_OPEN;
1896 if (!m_congestionControl->HasCongControl())
1897 {
1898 m_tcb->m_cWnd = m_tcb->m_ssThresh.Get();
1899 m_recoveryOps->ExitRecovery(m_tcb);
1901 }
1902 }
1903
1904 if (ackNumber > oldHeadSequence && (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED) &&
1905 (tcpHeader.GetFlags() & TcpHeader::ECE))
1906 {
1907 if (m_ecnEchoSeq < ackNumber)
1908 {
1909 NS_LOG_INFO("Received ECN Echo is valid");
1910 m_ecnEchoSeq = ackNumber;
1911 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_RCVD");
1912 m_tcb->m_ecnState = TcpSocketState::ECN_ECE_RCVD;
1913 if (m_tcb->m_congState != TcpSocketState::CA_CWR)
1914 {
1915 EnterCwr(currentDelivered);
1916 }
1917 }
1918 }
1919 else if (m_tcb->m_ecnState == TcpSocketState::ECN_ECE_RCVD &&
1920 !(tcpHeader.GetFlags() & TcpHeader::ECE))
1921 {
1922 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
1923 }
1924
1925 // Update bytes in flight before processing the ACK for proper calculation of congestion window
1926 NS_LOG_INFO("Update bytes in flight before processing the ACK.");
1927 BytesInFlight();
1928
1929 bool receivedData = packet->GetSize() > 0;
1930
1931 // RFC 6675 Section 5: 2nd, 3rd paragraph and point (A), (B) implementation
1932 // are inside the function ProcessAck
1933 ProcessAck(ackNumber, (bytesSacked > 0), currentDelivered, oldHeadSequence, receivedData);
1934 m_tcb->m_isRetransDataAcked = false;
1935
1936 if (m_congestionControl->HasCongControl())
1937 {
1938 uint32_t currentLost = m_txBuffer->GetLost();
1939 uint32_t lost =
1940 (currentLost > previousLost) ? currentLost - previousLost : previousLost - currentLost;
1941 auto rateSample = m_rateOps->GenerateSample(currentDelivered,
1942 lost,
1943 false,
1944 priorInFlight,
1945 m_tcb->m_minRtt);
1946 auto rateConn = m_rateOps->GetConnectionRate();
1947 m_congestionControl->CongControl(m_tcb, rateConn, rateSample);
1948 }
1949
1950 // If there is any data piggybacked, store it into m_rxBuffer
1951 if (receivedData)
1952 {
1953 ReceivedData(packet, tcpHeader);
1954 }
1955
1956 // RFC 6675, Section 5, point (C), try to send more data. NB: (C) is implemented
1957 // inside SendPendingData
1959}
1960
1961void
1963 bool scoreboardUpdated,
1964 uint32_t currentDelivered,
1965 const SequenceNumber32& oldHeadSequence,
1966 bool receivedData)
1967{
1968 NS_LOG_FUNCTION(this << ackNumber << scoreboardUpdated << currentDelivered << oldHeadSequence);
1969 // RFC 6675, Section 5, 2nd paragraph:
1970 // If the incoming ACK is a cumulative acknowledgment, the TCP MUST
1971 // reset DupAcks to zero.
1972 bool exitedFastRecovery = false;
1973 uint32_t oldDupAckCount = m_dupAckCount; // remember the old value
1974 m_tcb->m_lastAckedSeq = ackNumber; // Update lastAckedSeq
1975 uint32_t bytesAcked = 0;
1976
1977 /* In RFC 5681 the definition of duplicate acknowledgment was strict:
1978 *
1979 * (a) the receiver of the ACK has outstanding data,
1980 * (b) the incoming acknowledgment carries no data,
1981 * (c) the SYN and FIN bits are both off,
1982 * (d) the acknowledgment number is equal to the greatest acknowledgment
1983 * received on the given connection (TCP.UNA from [RFC793]),
1984 * (e) the advertised window in the incoming acknowledgment equals the
1985 * advertised window in the last incoming acknowledgment.
1986 *
1987 * With RFC 6675, this definition has been reduced:
1988 *
1989 * (a) the ACK is carrying a SACK block that identifies previously
1990 * unacknowledged and un-SACKed octets between HighACK (TCP.UNA) and
1991 * HighData (m_highTxMark)
1992 *
1993 * The check below implements conditions a), b), and d), and c) is prevented by virtue of not
1994 * reaching this code if SYN or FIN is set, and e) is not supported.
1995 */
1996
1997 bool isDupack = m_sackEnabled ? scoreboardUpdated
1998 : (ackNumber == oldHeadSequence &&
1999 ackNumber < m_tcb->m_highTxMark && !receivedData);
2000
2001 NS_LOG_DEBUG("ACK of " << ackNumber << " SND.UNA=" << oldHeadSequence
2002 << " SND.NXT=" << m_tcb->m_nextTxSequence
2003 << " in state: " << TcpSocketState::TcpCongStateName[m_tcb->m_congState]
2004 << " with m_recover: " << m_recover);
2005
2006 // RFC 6675, Section 5, 3rd paragraph:
2007 // If the incoming ACK is a duplicate acknowledgment per the definition
2008 // in Section 2 (regardless of its status as a cumulative
2009 // acknowledgment), and the TCP is not currently in loss recovery
2010 if (isDupack)
2011 {
2012 // loss recovery check is done inside this function thanks to
2013 // the congestion state machine
2014 DupAck(currentDelivered);
2015 }
2016
2017 if (ackNumber == oldHeadSequence && ackNumber == m_tcb->m_highTxMark)
2018 {
2019 // Dupack, but the ACK is precisely equal to the nextTxSequence
2020 return;
2021 }
2022 else if (ackNumber == oldHeadSequence && ackNumber > m_tcb->m_highTxMark)
2023 {
2024 // ACK of the FIN bit ... nextTxSequence is not updated since we
2025 // don't have anything to transmit
2026 NS_LOG_DEBUG("Update nextTxSequence manually to " << ackNumber);
2027 m_tcb->m_nextTxSequence = ackNumber;
2028 }
2029 else if (ackNumber == oldHeadSequence)
2030 {
2031 // DupAck. Artificially call PktsAcked: after all, one segment has been ACKed.
2032 m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_srtt);
2033 }
2034 else if (ackNumber > oldHeadSequence)
2035 {
2036 // Please remember that, with SACK, we can enter here even if we
2037 // received a dupack.
2038 bytesAcked = currentDelivered;
2039 uint32_t segsAcked = bytesAcked / m_tcb->m_segmentSize;
2040 m_bytesAckedNotProcessed += bytesAcked % m_tcb->m_segmentSize;
2041 bytesAcked -= bytesAcked % m_tcb->m_segmentSize;
2042
2043 if (m_bytesAckedNotProcessed >= m_tcb->m_segmentSize)
2044 {
2045 segsAcked += 1;
2046 bytesAcked += m_tcb->m_segmentSize;
2047 m_bytesAckedNotProcessed -= m_tcb->m_segmentSize;
2048 }
2049 NS_LOG_DEBUG("Set segsAcked: " << segsAcked
2050 << " based on currentDelivered: " << currentDelivered);
2051
2052 // Dupack count is reset to eventually fast-retransmit after 3 dupacks.
2053 // Any SACK-ed segment will be cleaned up by DiscardUpTo.
2054 // In the case that we advanced SND.UNA, but the ack contains SACK blocks,
2055 // we do not reset. At the third one we will retransmit.
2056 // If we are already in recovery, this check is useless since dupAcks
2057 // are not considered in this phase. When from Recovery we go back
2058 // to open, then dupAckCount is reset anyway.
2059 if (!isDupack)
2060 {
2061 m_dupAckCount = 0;
2062 }
2063
2064 // RFC 6675, Section 5, part (B)
2065 // (B) Upon receipt of an ACK that does not cover RecoveryPoint, the
2066 // following actions MUST be taken:
2067 //
2068 // (B.1) Use Update () to record the new SACK information conveyed
2069 // by the incoming ACK.
2070 // (B.2) Use SetPipe () to re-calculate the number of octets still
2071 // in the network.
2072 //
2073 // (B.1) is done at the beginning, while (B.2) is delayed to part (C) while
2074 // trying to transmit with SendPendingData. We are not allowed to exit
2075 // the CA_RECOVERY phase. Just process this partial ack (RFC 5681)
2076 if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
2077 {
2078 if (!m_sackEnabled)
2079 {
2080 // Manually set the head as lost, it will be retransmitted.
2081 NS_LOG_INFO("Partial ACK. Manually setting head as lost");
2082 m_txBuffer->MarkHeadAsLost();
2083 }
2084
2085 // Before retransmitting the packet perform DoRecovery and check if
2086 // there is available window
2087 if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2088 {
2089 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, false);
2090 }
2091
2092 // If the packet is already retransmitted do not retransmit it
2093 if (!m_txBuffer->IsRetransmittedDataAcked(ackNumber + m_tcb->m_segmentSize))
2094 {
2095 DoRetransmit(); // Assume the next seq is lost. Retransmit lost packet
2096 m_tcb->m_cWndInfl = SafeSubtraction(m_tcb->m_cWndInfl, bytesAcked);
2097 }
2098
2099 // This partial ACK acknowledge the fact that one segment has been
2100 // previously lost and now successfully received. All others have
2101 // been processed when they come under the form of dupACKs
2102 m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_srtt);
2103 NewAck(ackNumber, m_isFirstPartialAck);
2104
2106 {
2107 NS_LOG_DEBUG("Partial ACK of " << ackNumber
2108 << " and this is the first (RTO will be reset);"
2109 " cwnd set to "
2110 << m_tcb->m_cWnd << " recover seq: " << m_recover
2111 << " dupAck count: " << m_dupAckCount);
2112 m_isFirstPartialAck = false;
2113 }
2114 else
2115 {
2116 NS_LOG_DEBUG("Partial ACK of "
2117 << ackNumber
2118 << " and this is NOT the first (RTO will not be reset)"
2119 " cwnd set to "
2120 << m_tcb->m_cWnd << " recover seq: " << m_recover
2121 << " dupAck count: " << m_dupAckCount);
2122 }
2123 }
2124 // From RFC 6675 section 5.1
2125 // In addition, a new recovery phase (as described in Section 5) MUST NOT
2126 // be initiated until HighACK is greater than or equal to the new value
2127 // of RecoveryPoint.
2128 else if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_LOSS)
2129 {
2130 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2131 m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2132
2133 NS_LOG_DEBUG(" Cong Control Called, cWnd=" << m_tcb->m_cWnd
2134 << " ssTh=" << m_tcb->m_ssThresh);
2135 if (!m_sackEnabled)
2136 {
2138 m_txBuffer->GetSacked() == 0,
2139 "Some segment got dup-acked in CA_LOSS state: " << m_txBuffer->GetSacked());
2140 }
2141 NewAck(ackNumber, true);
2142 }
2143 else if (m_tcb->m_congState == TcpSocketState::CA_CWR)
2144 {
2145 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2146 // TODO: need to check behavior if marking is compounded by loss
2147 // and/or packet reordering
2148 if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2149 {
2150 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, false);
2151 }
2152 NewAck(ackNumber, true);
2153 }
2154 else
2155 {
2156 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
2157 {
2158 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2159 }
2160 else if (m_tcb->m_congState == TcpSocketState::CA_DISORDER)
2161 {
2162 if (segsAcked >= oldDupAckCount)
2163 {
2164 m_congestionControl->PktsAcked(m_tcb,
2165 segsAcked - oldDupAckCount,
2166 m_tcb->m_srtt);
2167 }
2168
2169 if (!isDupack)
2170 {
2171 // The network reorder packets. Linux changes the counting lost
2172 // packet algorithm from FACK to NewReno. We simply go back in Open.
2174 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2175 NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2176 << " exiting CA_DISORDER -> CA_OPEN");
2177 }
2178 else
2179 {
2180 NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2181 << " but still in CA_DISORDER");
2182 }
2183 }
2184 // RFC 6675, Section 5:
2185 // Once a TCP is in the loss recovery phase, the following procedure
2186 // MUST be used for each arriving ACK:
2187 // (A) An incoming cumulative ACK for a sequence number greater than
2188 // RecoveryPoint signals the end of loss recovery, and the loss
2189 // recovery phase MUST be terminated. Any information contained in
2190 // the scoreboard for sequence numbers greater than the new value of
2191 // HighACK SHOULD NOT be cleared when leaving the loss recovery
2192 // phase.
2193 else if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
2194 {
2195 m_isFirstPartialAck = true;
2196
2197 // Recalculate the segs acked, that are from m_recover to ackNumber
2198 // (which are the ones we have not passed to PktsAcked and that
2199 // can increase cWnd)
2200 // TODO: check consistency for dynamic segment size
2201 segsAcked =
2202 static_cast<uint32_t>(ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
2203 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2206 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2207 exitedFastRecovery = true;
2208 m_dupAckCount = 0; // From recovery to open, reset dupack
2209
2210 NS_LOG_DEBUG(segsAcked << " segments acked in CA_RECOVER, ack of " << ackNumber
2211 << ", exiting CA_RECOVERY -> CA_OPEN");
2212 }
2213 else if (m_tcb->m_congState == TcpSocketState::CA_LOSS)
2214 {
2215 m_isFirstPartialAck = true;
2216
2217 // Recalculate the segs acked, that are from m_recover to ackNumber
2218 // (which are the ones we have not passed to PktsAcked and that
2219 // can increase cWnd)
2220 segsAcked = (ackNumber - m_recover) / m_tcb->m_segmentSize;
2221
2222 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2223
2225 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2226 NS_LOG_DEBUG(segsAcked << " segments acked in CA_LOSS, ack of" << ackNumber
2227 << ", exiting CA_LOSS -> CA_OPEN");
2228 }
2229
2230 if (ackNumber >= m_recover)
2231 {
2232 // All lost segments in the congestion event have been
2233 // retransmitted successfully. The recovery point (m_recover)
2234 // should be deactivated.
2235 m_recoverActive = false;
2236 }
2237
2238 if (exitedFastRecovery)
2239 {
2240 NewAck(ackNumber, true);
2241 m_tcb->m_cWnd = m_tcb->m_ssThresh.Get();
2242 m_recoveryOps->ExitRecovery(m_tcb);
2243 NS_LOG_DEBUG("Leaving Fast Recovery; BytesInFlight() = "
2244 << BytesInFlight() << "; cWnd = " << m_tcb->m_cWnd);
2245 }
2246 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
2247 {
2248 m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2249
2250 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
2251
2252 NS_LOG_LOGIC("Congestion control called: cWnd: " << m_tcb->m_cWnd
2253 << " ssTh: " << m_tcb->m_ssThresh
2254 << " segsAcked: " << segsAcked);
2255
2256 NewAck(ackNumber, true);
2257 }
2258 }
2259 }
2260 // Update the pacing rate, since m_congestionControl->IncreaseWindow() or
2261 // m_congestionControl->PktsAcked () may change m_tcb->m_cWnd
2262 // Make sure that control reaches the end of this function and there is no
2263 // return in between
2265}
2266
2267/* Received a packet upon LISTEN state. */
2268void
2270 const TcpHeader& tcpHeader,
2271 const Address& fromAddress,
2272 const Address& toAddress)
2273{
2274 NS_LOG_FUNCTION(this << tcpHeader);
2275
2276 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2277 uint8_t tcpflags =
2279
2280 // Fork a socket if received a SYN. Do nothing otherwise.
2281 // C.f.: the LISTEN part in tcp_v4_do_rcv() in tcp_ipv4.c in Linux kernel
2282 if (tcpflags != TcpHeader::SYN)
2283 {
2284 return;
2285 }
2286
2287 // Call socket's notify function to let the server app know we got a SYN
2288 // If the server app refuses the connection, do nothing
2289 if (!NotifyConnectionRequest(fromAddress))
2290 {
2291 return;
2292 }
2293 // Clone the socket, simulate fork
2294 Ptr<TcpSocketBase> newSock = Fork();
2295 NS_LOG_LOGIC("Cloned a TcpSocketBase " << newSock);
2297 newSock,
2298 packet,
2299 tcpHeader,
2300 fromAddress,
2301 toAddress);
2302}
2303
2304/* Received a packet upon SYN_SENT */
2305void
2307{
2308 NS_LOG_FUNCTION(this << tcpHeader);
2309
2310 // Extract the flags. PSH and URG are disregarded.
2311 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2312
2313 if (tcpflags == 0)
2314 { // Bare data, accept it and move to ESTABLISHED state. This is not a normal behaviour. Remove
2315 // this?
2316 NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2318 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2320 m_connected = true;
2323 ReceivedData(packet, tcpHeader);
2325 }
2326 else if (tcpflags & TcpHeader::ACK && !(tcpflags & TcpHeader::SYN))
2327 { // Ignore ACK in SYN_SENT
2328 }
2329 else if (tcpflags & TcpHeader::SYN && !(tcpflags & TcpHeader::ACK))
2330 { // Received SYN, move to SYN_RCVD state and respond with SYN+ACK
2331 NS_LOG_DEBUG("SYN_SENT -> SYN_RCVD");
2332 m_state = SYN_RCVD;
2334 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2335 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2336 * the traffic is ECN capable and sender has sent ECN SYN packet
2337 */
2338
2339 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2341 {
2342 NS_LOG_INFO("Received ECN SYN packet");
2344 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2345 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2346 }
2347 else
2348 {
2349 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2351 }
2352 }
2353 else if (tcpflags & (TcpHeader::SYN | TcpHeader::ACK) &&
2354 m_tcb->m_nextTxSequence + SequenceNumber32(1) == tcpHeader.GetAckNumber())
2355 { // Handshake completed
2356 NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2358 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2360 m_connected = true;
2362 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2363 m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
2364 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2365 // Before sending packets, update the pacing rate based on RTT measurement so far
2368
2369 /* Check if we received an ECN SYN-ACK packet. Change the ECN state of sender to ECN_IDLE if
2370 * receiver has sent an ECN SYN-ACK packet and the traffic is ECN Capable
2371 */
2372 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2373 (tcpflags & (TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::ECE))
2374 {
2375 NS_LOG_INFO("Received ECN SYN-ACK packet.");
2376 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2377 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2378 }
2379 else
2380 {
2381 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2382 }
2385 // Always respond to first data packet to speed up the connection.
2386 // Remove to get the behaviour of old NS-3 code.
2388 }
2389 else
2390 { // Other in-sequence input
2391 if (!(tcpflags & TcpHeader::RST))
2392 { // When (1) rx of FIN+ACK; (2) rx of FIN; (3) rx of bad flags
2393 NS_LOG_LOGIC("Illegal flag combination "
2394 << TcpHeader::FlagsToString(tcpHeader.GetFlags())
2395 << " received in SYN_SENT. Reset packet is sent.");
2396 SendRST();
2397 }
2399 }
2400}
2401
2402/* Received a packet upon SYN_RCVD */
2403void
2405 const TcpHeader& tcpHeader,
2406 const Address& fromAddress,
2407 const Address& /* toAddress */)
2408{
2409 NS_LOG_FUNCTION(this << tcpHeader);
2410
2411 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2412 uint8_t tcpflags =
2414
2415 if (tcpflags == 0 ||
2416 (tcpflags == TcpHeader::ACK &&
2417 m_tcb->m_nextTxSequence + SequenceNumber32(1) == tcpHeader.GetAckNumber()))
2418 { // If it is bare data, accept it and move to ESTABLISHED state. This is
2419 // possibly due to ACK lost in 3WHS. If in-sequence ACK is received, the
2420 // handshake is completed nicely.
2421 NS_LOG_DEBUG("SYN_RCVD -> ESTABLISHED");
2423 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2425 m_connected = true;
2427 m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
2428 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2429 if (m_endPoint)
2430 {
2431 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2432 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2433 }
2434 else if (m_endPoint6)
2435 {
2436 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2437 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2438 }
2439 // Always respond to first data packet to speed up the connection.
2440 // Remove to get the behaviour of old NS-3 code.
2442 NotifyNewConnectionCreated(this, fromAddress);
2443 ReceivedAck(packet, tcpHeader);
2444 // Update the pacing rate based on RTT measurement so far
2446 // As this connection is established, the socket is available to send data now
2447 if (GetTxAvailable() > 0)
2448 {
2450 }
2451 }
2452 else if (tcpflags == TcpHeader::SYN)
2453 { // Probably the peer lost my SYN+ACK
2454 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2455 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2456 * sender has sent an ECN SYN packet and the traffic is ECN Capable
2457 */
2458 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2459 (tcpHeader.GetFlags() & (TcpHeader::CWR | TcpHeader::ECE)) ==
2461 {
2462 NS_LOG_INFO("Received ECN SYN packet");
2464 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2465 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2466 }
2467 else
2468 {
2469 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2471 }
2472 }
2473 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2474 {
2475 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2476 { // In-sequence FIN before connection complete. Set up connection and close.
2477 m_connected = true;
2479 m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
2480 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2481 if (m_endPoint)
2482 {
2483 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2484 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2485 }
2486 else if (m_endPoint6)
2487 {
2488 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2489 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2490 }
2491 NotifyNewConnectionCreated(this, fromAddress);
2492 PeerClose(packet, tcpHeader);
2493 }
2494 }
2495 else
2496 { // Other in-sequence input
2497 if (tcpflags != TcpHeader::RST)
2498 { // When (1) rx of SYN+ACK; (2) rx of FIN; (3) rx of bad flags
2499 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2500 << " received. Reset packet is sent.");
2501 if (m_endPoint)
2502 {
2503 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2504 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2505 }
2506 else if (m_endPoint6)
2507 {
2508 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2509 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2510 }
2511 SendRST();
2512 }
2514 }
2515}
2516
2517/* Received a packet upon CLOSE_WAIT, FIN_WAIT_1, or FIN_WAIT_2 states */
2518void
2520{
2521 NS_LOG_FUNCTION(this << tcpHeader);
2522
2523 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2524 uint8_t tcpflags =
2526
2527 if (packet->GetSize() > 0 && !(tcpflags & TcpHeader::ACK))
2528 { // Bare data, accept it
2529 ReceivedData(packet, tcpHeader);
2530 }
2531 else if (tcpflags == TcpHeader::ACK)
2532 { // Process the ACK, and if in FIN_WAIT_1, conditionally move to FIN_WAIT_2
2533 ReceivedAck(packet, tcpHeader);
2534 if (m_state == FIN_WAIT_1 && m_txBuffer->Size() == 0 &&
2535 tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2536 { // This ACK corresponds to the FIN sent
2537 NS_LOG_DEBUG("FIN_WAIT_1 -> FIN_WAIT_2");
2539 }
2540 }
2541 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2542 { // Got FIN, respond with ACK and move to next state
2543 if (tcpflags & TcpHeader::ACK)
2544 { // Process the ACK first
2545 ReceivedAck(packet, tcpHeader);
2546 }
2547 m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber());
2548 }
2549 else if (tcpflags == TcpHeader::SYN || tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
2550 { // Duplicated SYN or SYN+ACK, possibly due to spurious retransmission
2551 return;
2552 }
2553 else
2554 { // This is a RST or bad flags
2555 if (tcpflags != TcpHeader::RST)
2556 {
2557 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2558 << " received. Reset packet is sent.");
2559 SendRST();
2560 }
2562 return;
2563 }
2564
2565 // Check if the close responder sent an in-sequence FIN, if so, respond ACK
2566 if ((m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2) && m_tcb->m_rxBuffer->Finished())
2567 {
2568 if (m_state == FIN_WAIT_1)
2569 {
2570 NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2571 m_state = CLOSING;
2572 if (m_txBuffer->Size() == 0 &&
2573 tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2574 { // This ACK corresponds to the FIN sent
2575 TimeWait();
2576 }
2577 }
2578 else if (m_state == FIN_WAIT_2)
2579 {
2580 TimeWait();
2581 }
2583 if (!m_shutdownRecv)
2584 {
2586 }
2587 }
2588}
2589
2590/* Received a packet upon CLOSING */
2591void
2593{
2594 NS_LOG_FUNCTION(this << tcpHeader);
2595
2596 // Extract the flags. PSH and URG are disregarded.
2597 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2598
2599 if (tcpflags == TcpHeader::ACK)
2600 {
2601 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2602 { // This ACK corresponds to the FIN sent
2603 TimeWait();
2604 }
2605 }
2606 else
2607 { // CLOSING state means simultaneous close, i.e. no one is sending data to
2608 // anyone. If anything other than ACK is received, respond with a reset.
2609 if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2610 { // FIN from the peer as well. We can close immediately.
2612 }
2613 else if (tcpflags != TcpHeader::RST)
2614 { // Receive of SYN or SYN+ACK or bad flags or pure data
2615 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2616 << " received. Reset packet is sent.");
2617 SendRST();
2618 }
2620 }
2621}
2622
2623/* Received a packet upon LAST_ACK */
2624void
2626{
2627 NS_LOG_FUNCTION(this << tcpHeader);
2628
2629 // Extract the flags. PSH and URG are disregarded.
2630 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2631
2632 if (tcpflags == 0)
2633 {
2634 ReceivedData(packet, tcpHeader);
2635 }
2636 else if (tcpflags == TcpHeader::ACK)
2637 {
2638 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2639 { // This ACK corresponds to the FIN sent. This socket closed peacefully.
2641 }
2642 }
2643 else if (tcpflags == TcpHeader::FIN)
2644 { // Received FIN again, the peer probably lost the FIN+ACK
2646 }
2647 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK) || tcpflags == TcpHeader::RST)
2648 {
2650 }
2651 else
2652 { // Received a SYN or SYN+ACK or bad flags
2653 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2654 << " received. Reset packet is sent.");
2655 SendRST();
2657 }
2658}
2659
2660/* Peer sent me a FIN. Remember its sequence in rx buffer. */
2661void
2663{
2664 NS_LOG_FUNCTION(this << tcpHeader);
2665
2666 // Ignore all out of range packets
2667 if (tcpHeader.GetSequenceNumber() < m_tcb->m_rxBuffer->NextRxSequence() ||
2668 tcpHeader.GetSequenceNumber() > m_tcb->m_rxBuffer->MaxRxSequence())
2669 {
2670 return;
2671 }
2672 // For any case, remember the FIN position in rx buffer first
2673 m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber() +
2674 SequenceNumber32(p->GetSize()));
2675 NS_LOG_LOGIC("Accepted FIN at seq "
2676 << tcpHeader.GetSequenceNumber() + SequenceNumber32(p->GetSize()));
2677 // If there is any piggybacked data, process it
2678 if (p->GetSize())
2679 {
2680 ReceivedData(p, tcpHeader);
2681 }
2682 // Return if FIN is out of sequence, otherwise move to CLOSE_WAIT state by DoPeerClose
2683 if (!m_tcb->m_rxBuffer->Finished())
2684 {
2685 return;
2686 }
2687
2688 // Simultaneous close: Application invoked Close() when we are processing this FIN packet
2689 if (m_state == FIN_WAIT_1)
2690 {
2691 NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2692 m_state = CLOSING;
2693 return;
2694 }
2695
2696 DoPeerClose(); // Change state, respond with ACK
2697}
2698
2699/* Received a in-sequence FIN. Close down this socket. */
2700void
2702{
2704 m_state == FIN_WAIT_2);
2705
2706 // Move the state to CLOSE_WAIT
2707 NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSE_WAIT");
2709
2710 if (!m_closeNotified)
2711 {
2712 // The normal behaviour for an application is that, when the peer sent a in-sequence
2713 // FIN, the app should prepare to close. The app has two choices at this point: either
2714 // respond with ShutdownSend() call to declare that it has nothing more to send and
2715 // the socket can be closed immediately; or remember the peer's close request, wait
2716 // until all its existing data are pushed into the TCP socket, then call Close()
2717 // explicitly.
2718 NS_LOG_LOGIC("TCP " << this << " calling NotifyNormalClose");
2720 m_closeNotified = true;
2721 }
2722 if (m_shutdownSend)
2723 { // The application declares that it would not sent any more, close this socket
2724 Close();
2725 }
2726 else
2727 { // Need to ack, the application will close later
2729 }
2730 if (m_state == LAST_ACK)
2731 {
2732 m_dataRetrCount = m_dataRetries; // prevent endless FINs
2733 NS_LOG_LOGIC("TcpSocketBase " << this << " scheduling LATO1");
2734 Time lastRto = m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4);
2736 }
2737}
2738
2739/* Kill this socket. This is a callback function configured to m_endpoint in
2740 SetupCallback(), invoked when the endpoint is destroyed. */
2741void
2743{
2744 NS_LOG_FUNCTION(this);
2745 m_endPoint = nullptr;
2746 if (m_tcp)
2747 {
2748 m_tcp->RemoveSocket(this);
2749 }
2750 NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2751 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2753}
2754
2755/* Kill this socket. This is a callback function configured to m_endpoint in
2756 SetupCallback(), invoked when the endpoint is destroyed. */
2757void
2759{
2760 NS_LOG_FUNCTION(this);
2761 m_endPoint6 = nullptr;
2762 if (m_tcp)
2763 {
2764 m_tcp->RemoveSocket(this);
2765 }
2766 NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2767 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2769}
2770
2771/* Send an empty packet with specified TCP flags */
2772void
2774{
2775 NS_LOG_FUNCTION(this << static_cast<uint32_t>(flags));
2776
2777 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
2778 {
2779 NS_LOG_WARN("Failed to send empty packet due to null endpoint");
2780 return;
2781 }
2782
2784 TcpHeader header;
2785 SequenceNumber32 s = m_tcb->m_nextTxSequence;
2786 TcpPacketType_t packetType = INVALID;
2787
2788 if (flags & TcpHeader::FIN)
2789 {
2790 packetType = TcpPacketType_t::FIN;
2791 flags |= TcpHeader::ACK;
2792 }
2793 else if (m_state == FIN_WAIT_1 || m_state == LAST_ACK || m_state == CLOSING)
2794 {
2795 ++s;
2796 }
2797
2798 if (flags & TcpHeader::SYN)
2799 {
2800 packetType = TcpPacketType_t::SYN;
2801 if (flags & TcpHeader::ACK)
2802 {
2803 packetType = TcpPacketType_t::SYN_ACK;
2804 }
2805 }
2806 else if (flags & TcpHeader::ACK)
2807 {
2808 packetType = TcpPacketType_t::PURE_ACK;
2809 }
2810
2811 if (flags & TcpHeader::RST)
2812 {
2813 packetType = TcpPacketType_t::RST;
2814 }
2815
2816 NS_ASSERT_MSG(packetType != TcpPacketType_t::INVALID, "Invalid TCP packet type");
2817 AddSocketTags(p, IsEct(packetType));
2818
2819 header.SetFlags(flags);
2820 header.SetSequenceNumber(s);
2821 header.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
2822 if (m_endPoint != nullptr)
2823 {
2826 }
2827 else
2828 {
2831 }
2832 AddOptions(header);
2833
2834 // RFC 6298, clause 2.4
2835 m_rto =
2836 Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4), m_minRto);
2837
2838 uint16_t windowSize = AdvertisedWindowSize();
2839 bool hasSyn = flags & TcpHeader::SYN;
2840 bool hasFin = flags & TcpHeader::FIN;
2841 bool isAck = flags == TcpHeader::ACK;
2842 if (hasSyn)
2843 {
2845 { // The window scaling option is set only on SYN packets
2846 AddOptionWScale(header);
2847 }
2848
2849 if (m_sackEnabled)
2850 {
2851 AddOptionSackPermitted(header);
2852 }
2853
2854 if (m_synCount == 0)
2855 { // No more connection retries, give up
2856 NS_LOG_LOGIC("Connection failed.");
2857 m_rtt->Reset(); // According to recommendation -> RFC 6298
2859 m_state = CLOSED;
2861 return;
2862 }
2863 else
2864 { // Exponential backoff of connection time out
2865 int backoffCount = 0x1 << (m_synRetries - m_synCount);
2866 m_rto = m_cnTimeout * backoffCount;
2867 m_synCount--;
2868 }
2869
2870 if (m_synRetries - 1 == m_synCount)
2871 {
2872 UpdateRttHistory(s, 0, false);
2873 }
2874 else
2875 { // This is SYN retransmission
2876 UpdateRttHistory(s, 0, true);
2877 }
2878
2879 windowSize = AdvertisedWindowSize(false);
2880 }
2881 header.SetWindowSize(windowSize);
2882
2883 if (flags & TcpHeader::ACK)
2884 { // If sending an ACK, cancel the delay ACK as well
2886 m_delAckCount = 0;
2887 if (m_highTxAck < header.GetAckNumber())
2888 {
2889 m_highTxAck = header.GetAckNumber();
2890 }
2891 if (m_sackEnabled && m_tcb->m_rxBuffer->GetSackListSize() > 0)
2892 {
2893 AddOptionSack(header);
2894 }
2895 NS_LOG_INFO("Sending a pure ACK, acking seq " << m_tcb->m_rxBuffer->NextRxSequence());
2896 }
2897
2898 m_txTrace(p, header, this);
2899
2900 if (m_endPoint != nullptr)
2901 {
2902 m_tcp->SendPacket(p,
2903 header,
2907 }
2908 else
2909 {
2910 m_tcp->SendPacket(p,
2911 header,
2915 }
2916
2917 if (m_retxEvent.IsExpired() && (hasSyn || hasFin) && !isAck)
2918 { // Retransmit SYN / SYN+ACK / FIN / FIN+ACK to guard against lost
2919 NS_LOG_LOGIC("Schedule retransmission timeout at time "
2920 << Simulator::Now().GetSeconds() << " to expire at time "
2921 << (Simulator::Now() + m_rto.Get()).GetSeconds());
2923 }
2924}
2925
2926/* This function closes the endpoint completely. Called upon RST_TX action. */
2927void
2935
2936/* Deallocate the end point and cancel all the timers */
2937void
2939{
2940 // note: it shouldn't be necessary to invalidate the callback and manually call
2941 // TcpL4Protocol::RemoveSocket. Alas, if one relies on the endpoint destruction
2942 // callback, there's a weird memory access to a free'd area. Harmless, but valgrind
2943 // considers it an error.
2944
2945 if (m_endPoint != nullptr)
2946 {
2949 m_tcp->DeAllocate(m_endPoint);
2950 m_endPoint = nullptr;
2951 m_tcp->RemoveSocket(this);
2952 }
2953 else if (m_endPoint6 != nullptr)
2954 {
2957 m_tcp->DeAllocate(m_endPoint6);
2958 m_endPoint6 = nullptr;
2959 m_tcp->RemoveSocket(this);
2960 }
2961}
2962
2963/* Configure the endpoint to a local address. Called by Connect() if Bind() didn't specify one. */
2964int
2966{
2967 NS_LOG_FUNCTION(this);
2968 Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4>();
2969 NS_ASSERT(ipv4);
2970 if (!ipv4->GetRoutingProtocol())
2971 {
2972 NS_FATAL_ERROR("No Ipv4RoutingProtocol in the node");
2973 }
2974 // Create a dummy packet, then ask the routing function for the best output
2975 // interface's address
2976 Ipv4Header header;
2978 Socket::SocketErrno errno_;
2979 Ptr<Ipv4Route> route;
2981 route = ipv4->GetRoutingProtocol()->RouteOutput(Ptr<Packet>(), header, oif, errno_);
2982 if (!route)
2983 {
2984 NS_LOG_LOGIC("Route to " << m_endPoint->GetPeerAddress() << " does not exist");
2985 NS_LOG_ERROR(errno_);
2986 m_errno = errno_;
2987 return -1;
2988 }
2989 NS_LOG_LOGIC("Route exists");
2990 m_endPoint->SetLocalAddress(route->GetSource());
2991 return 0;
2992}
2993
2994int
2996{
2997 NS_LOG_FUNCTION(this);
2999 NS_ASSERT(ipv6);
3000 if (!ipv6->GetRoutingProtocol())
3001 {
3002 NS_FATAL_ERROR("No Ipv6RoutingProtocol in the node");
3003 }
3004 // Create a dummy packet, then ask the routing function for the best output
3005 // interface's address
3006 Ipv6Header header;
3008 Socket::SocketErrno errno_;
3009 Ptr<Ipv6Route> route;
3011 route = ipv6->GetRoutingProtocol()->RouteOutput(Ptr<Packet>(), header, oif, errno_);
3012 if (!route)
3013 {
3014 NS_LOG_LOGIC("Route to " << m_endPoint6->GetPeerAddress() << " does not exist");
3015 NS_LOG_ERROR(errno_);
3016 m_errno = errno_;
3017 return -1;
3018 }
3019 NS_LOG_LOGIC("Route exists");
3020 m_endPoint6->SetLocalAddress(route->GetSource());
3021 return 0;
3022}
3023
3024/* This function is called only if a SYN received in LISTEN state. After
3025 TcpSocketBase cloned, allocate a new end point to handle the incoming
3026 connection and send a SYN+ACK to complete the handshake. */
3027void
3029 const TcpHeader& h,
3030 const Address& fromAddress,
3031 const Address& toAddress)
3032{
3033 NS_LOG_FUNCTION(this << p << h << fromAddress << toAddress);
3034 // Get port and address from peer (connecting host)
3035 if (InetSocketAddress::IsMatchingType(toAddress))
3036 {
3037 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(),
3038 InetSocketAddress::ConvertFrom(toAddress).GetIpv4(),
3039 InetSocketAddress::ConvertFrom(toAddress).GetPort(),
3040 InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
3041 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
3042 m_endPoint6 = nullptr;
3043 }
3044 else if (Inet6SocketAddress::IsMatchingType(toAddress))
3045 {
3046 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(),
3047 Inet6SocketAddress::ConvertFrom(toAddress).GetIpv6(),
3048 Inet6SocketAddress::ConvertFrom(toAddress).GetPort(),
3049 Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
3050 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
3051 m_endPoint = nullptr;
3052 }
3053 m_tcp->AddSocket(this);
3054
3055 // Change the cloned socket from LISTEN state to SYN_RCVD
3056 NS_LOG_DEBUG("LISTEN -> SYN_RCVD");
3057 m_state = SYN_RCVD;
3060 SetupCallback();
3061 // Set the sequence number and send SYN+ACK
3062 m_tcb->m_rxBuffer->SetNextRxSequence(h.GetSequenceNumber() + SequenceNumber32(1));
3063
3064 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
3065 * sender has sent an ECN SYN packet and the traffic is ECN Capable
3066 */
3067 if (m_tcb->m_useEcn != TcpSocketState::Off &&
3069 {
3071 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
3072 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
3073 }
3074 else
3075 {
3077 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
3078 }
3079}
3080
3081void
3083{ // Wrapper to protected function NotifyConnectionSucceeded() so that it can
3084 // be called as a scheduled event
3086 // The if-block below was moved from ProcessSynSent() to here because we need
3087 // to invoke the NotifySend() only after NotifyConnectionSucceeded() to
3088 // reflect the behaviour in the real world.
3089 if (GetTxAvailable() > 0)
3090 {
3092 }
3093}
3094
3095void
3097{
3098 /*
3099 * Add tags for each socket option.
3100 * Note that currently the socket adds both IPv4 tag and IPv6 tag
3101 * if both options are set. Once the packet got to layer three, only
3102 * the corresponding tags will be read.
3103 */
3104 if (GetIpTos())
3105 {
3106 SocketIpTosTag ipTosTag;
3107 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !CheckNoEcn(GetIpTos()) && isEct)
3108 {
3109 ipTosTag.SetTos(MarkEcnCodePoint(GetIpTos(), m_tcb->m_ectCodePoint));
3110 }
3111 else
3112 {
3113 // Set the last received ipTos
3114 ipTosTag.SetTos(GetIpTos());
3115 }
3116 p->AddPacketTag(ipTosTag);
3117 }
3118 else
3119 {
3120 if ((m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && p->GetSize() > 0 && isEct) ||
3121 m_tcb->m_ecnMode == TcpSocketState::DctcpEcn)
3122 {
3123 SocketIpTosTag ipTosTag;
3124 ipTosTag.SetTos(MarkEcnCodePoint(GetIpTos(), m_tcb->m_ectCodePoint));
3125 p->AddPacketTag(ipTosTag);
3126 }
3127 }
3128
3129 if (IsManualIpv6Tclass())
3130 {
3131 SocketIpv6TclassTag ipTclassTag;
3132 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !CheckNoEcn(GetIpv6Tclass()) &&
3133 isEct)
3134 {
3135 ipTclassTag.SetTclass(MarkEcnCodePoint(GetIpv6Tclass(), m_tcb->m_ectCodePoint));
3136 }
3137 else
3138 {
3139 // Set the last received ipTos
3140 ipTclassTag.SetTclass(GetIpv6Tclass());
3141 }
3142 p->AddPacketTag(ipTclassTag);
3143 }
3144 else
3145 {
3146 if ((m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && p->GetSize() > 0 && isEct) ||
3147 m_tcb->m_ecnMode == TcpSocketState::DctcpEcn)
3148 {
3149 SocketIpv6TclassTag ipTclassTag;
3150 ipTclassTag.SetTclass(MarkEcnCodePoint(GetIpv6Tclass(), m_tcb->m_ectCodePoint));
3151 p->AddPacketTag(ipTclassTag);
3152 }
3153 }
3154
3155 if (IsManualIpTtl())
3156 {
3157 SocketIpTtlTag ipTtlTag;
3158 ipTtlTag.SetTtl(GetIpTtl());
3159 p->AddPacketTag(ipTtlTag);
3160 }
3161
3163 {
3164 SocketIpv6HopLimitTag ipHopLimitTag;
3165 ipHopLimitTag.SetHopLimit(GetIpv6HopLimit());
3166 p->AddPacketTag(ipHopLimitTag);
3167 }
3168
3169 uint8_t priority = GetPriority();
3170 if (priority)
3171 {
3172 SocketPriorityTag priorityTag;
3173 priorityTag.SetPriority(priority);
3174 p->ReplacePacketTag(priorityTag);
3175 }
3176}
3177
3178/* Extract at most maxSize bytes from the TxBuffer at sequence seq, add the
3179 TCP header, and send to TcpL4Protocol */
3182{
3183 NS_LOG_FUNCTION(this << seq << maxSize << withAck);
3184
3185 bool isStartOfTransmission = BytesInFlight() == 0U;
3186 TcpTxItem* outItem = m_txBuffer->CopyFromSequence(maxSize, seq);
3187
3188 m_rateOps->SkbSent(outItem, isStartOfTransmission);
3189
3190 bool isRetransmission = outItem->IsRetrans();
3191 Ptr<Packet> p = outItem->GetPacketCopy();
3192 uint32_t sz = p->GetSize(); // Size of packet
3193 uint8_t flags = withAck ? TcpHeader::ACK : 0;
3194 uint32_t remainingData = m_txBuffer->SizeFromSequence(seq + SequenceNumber32(sz));
3195
3196 // TCP sender should not send data out of the window advertised by the
3197 // peer when it is not retransmission.
3198 NS_ASSERT(isRetransmission ||
3199 ((m_highRxAckMark + SequenceNumber32(m_rWnd)) >= (seq + SequenceNumber32(maxSize))));
3200
3201 if (IsPacingEnabled())
3202 {
3203 NS_LOG_INFO("Pacing is enabled");
3205 {
3206 NS_LOG_DEBUG("Current Pacing Rate " << m_tcb->m_pacingRate);
3207 NS_LOG_DEBUG("Timer is in expired state, activate it "
3208 << m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3209 m_pacingTimer.Schedule(m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3210 }
3211 else
3212 {
3213 NS_LOG_INFO("Timer is already in running state");
3214 }
3215 }
3216 else
3217 {
3218 NS_LOG_INFO("Pacing is disabled");
3219 }
3220
3221 if (withAck)
3222 {
3224 m_delAckCount = 0;
3225 }
3226
3227 if (m_tcb->m_ecnState == TcpSocketState::ECN_ECE_RCVD &&
3228 m_ecnEchoSeq.Get() > m_ecnCWRSeq.Get() && !isRetransmission)
3229 {
3230 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CWR_SENT");
3231 m_tcb->m_ecnState = TcpSocketState::ECN_CWR_SENT;
3232 m_ecnCWRSeq = seq;
3233 flags |= TcpHeader::CWR;
3234 NS_LOG_INFO("CWR flags set");
3235 }
3236
3237 bool isEct = IsEct(isRetransmission ? TcpPacketType_t::RE_XMT : TcpPacketType_t::DATA);
3238 AddSocketTags(p, isEct);
3239
3240 if (m_closeOnEmpty && (remainingData == 0))
3241 {
3242 flags |= TcpHeader::FIN;
3243 if (m_state == ESTABLISHED)
3244 { // On active close: I am the first one to send FIN
3245 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
3247 }
3248 else if (m_state == CLOSE_WAIT)
3249 { // On passive close: Peer sent me FIN already
3250 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
3251 m_state = LAST_ACK;
3252 }
3253 }
3254 TcpHeader header;
3255 header.SetFlags(flags);
3256 header.SetSequenceNumber(seq);
3257 header.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
3258 if (m_endPoint)
3259 {
3262 }
3263 else
3264 {
3267 }
3269 AddOptions(header);
3270
3271 if (m_retxEvent.IsExpired())
3272 {
3273 // Schedules retransmit timeout. m_rto should be already doubled.
3274
3275 NS_LOG_LOGIC(this << " SendDataPacket Schedule ReTxTimeout at time "
3276 << Simulator::Now().GetSeconds() << " to expire at time "
3277 << (Simulator::Now() + m_rto.Get()).GetSeconds());
3279 }
3280
3281 m_txTrace(p, header, this);
3282 if (isRetransmission)
3283 {
3284 if (m_endPoint)
3285 {
3287 header,
3290 this);
3291 }
3292 else
3293 {
3295 header,
3298 this);
3299 }
3300 }
3301
3302 if (m_endPoint)
3303 {
3304 m_tcp->SendPacket(p,
3305 header,
3309 NS_LOG_DEBUG("Send segment of size "
3310 << sz << " with remaining data " << remainingData << " via TcpL4Protocol to "
3311 << m_endPoint->GetPeerAddress() << ". Header " << header);
3312 }
3313 else
3314 {
3315 m_tcp->SendPacket(p,
3316 header,
3320 NS_LOG_DEBUG("Send segment of size "
3321 << sz << " with remaining data " << remainingData << " via TcpL4Protocol to "
3322 << m_endPoint6->GetPeerAddress() << ". Header " << header);
3323 }
3324
3325 // Signal to congestion control whether the cwnd is fully used
3326 // This is a simple version of Linux tcp_cwnd_validate() but following
3327 // the principle implemented in Linux that limits the updating of cwnd
3328 // (in the congestion controls) when flight size is >= cwnd
3329 // send will also be cwnd limited if less then one segment of cwnd is available
3330 m_tcb->m_isCwndLimited = (m_tcb->m_cWnd < BytesInFlight() + m_tcb->m_segmentSize);
3331
3332 UpdateRttHistory(seq, sz, isRetransmission);
3333
3334 // Update bytes sent during recovery phase
3335 if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY ||
3336 m_tcb->m_congState == TcpSocketState::CA_CWR)
3337 {
3338 m_recoveryOps->UpdateBytesSent(sz);
3339 }
3340
3341 // Notify the application of the data being sent unless this is a retransmit
3342 if (!isRetransmission)
3343 {
3345 this,
3346 (seq + sz - m_tcb->m_highTxMark.Get()));
3347 }
3348 // Update highTxMark
3349 m_tcb->m_highTxMark = std::max(seq + sz, m_tcb->m_highTxMark.Get());
3350 return sz;
3351}
3352
3353void
3354TcpSocketBase::UpdateRttHistory(const SequenceNumber32& seq, uint32_t sz, bool isRetransmission)
3355{
3356 NS_LOG_FUNCTION(this);
3357
3358 // update the history of sequence numbers used to calculate the RTT
3359 if (!isRetransmission)
3360 { // This is the next expected one, just log at end
3361 m_history.emplace_back(seq, sz, Simulator::Now());
3362 }
3363 else
3364 { // This is a retransmit, find in list and mark as re-tx
3365 for (auto i = m_history.begin(); i != m_history.end(); ++i)
3366 {
3367 if ((seq >= i->seq) && (seq < (i->seq + SequenceNumber32(i->count))))
3368 { // Found it
3369 i->retx = true;
3370 i->count = ((seq + SequenceNumber32(sz)) - i->seq); // And update count in hist
3371 break;
3372 }
3373 }
3374 }
3375}
3376
3377// Note that this function did not implement the PSH flag
3380{
3381 NS_LOG_FUNCTION(this << withAck);
3382 if (m_txBuffer->Size() == 0)
3383 {
3384 return 0; // Nothing to send
3385 }
3386 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
3387 {
3389 "TcpSocketBase::SendPendingData: No endpoint; m_shutdownSend=" << m_shutdownSend);
3390 return 0; // Is this the right way to handle this condition?
3391 }
3392
3393 uint32_t nPacketsSent = 0;
3394 uint32_t availableWindow = AvailableWindow();
3395
3396 // RFC 6675, Section (C)
3397 // If cwnd - pipe >= 1 SMSS, the sender SHOULD transmit one or more
3398 // segments as follows:
3399 // (NOTE: We check > 0, and do the checks for segmentSize in the following
3400 // else branch to control silly window syndrome and Nagle)
3401 while (availableWindow > 0)
3402 {
3403 if (IsPacingEnabled())
3404 {
3405 NS_LOG_INFO("Pacing is enabled");
3407 {
3408 NS_LOG_INFO("Skipping Packet due to pacing" << m_pacingTimer.GetDelayLeft());
3409 break;
3410 }
3411 NS_LOG_INFO("Timer is not running");
3412 }
3413
3415 {
3416 NS_LOG_INFO("FIN_WAIT and OPEN state; no data to transmit");
3417 break;
3418 }
3419 // (C.1) The scoreboard MUST be queried via NextSeg () for the
3420 // sequence number range of the next segment to transmit (if
3421 // any), and the given segment sent. If NextSeg () returns
3422 // failure (no data to send), return without sending anything
3423 // (i.e., terminate steps C.1 -- C.5).
3424 SequenceNumber32 next;
3425 SequenceNumber32 nextHigh;
3426 bool enableRule3 = m_sackEnabled && m_tcb->m_congState == TcpSocketState::CA_RECOVERY;
3427 if (!m_txBuffer->NextSeg(&next, &nextHigh, enableRule3))
3428 {
3429 NS_LOG_INFO("no valid seq to transmit, or no data available");
3430 break;
3431 }
3432 else
3433 {
3434 // It's time to transmit, but before do silly window and Nagle's check
3435 uint32_t availableData = m_txBuffer->SizeFromSequence(next);
3436
3437 // If there's less app data than the full window, ask the app for more
3438 // data before trying to send
3439 if (availableData < availableWindow)
3440 {
3442 }
3443
3444 // Stop sending if we need to wait for a larger Tx window (prevent silly window
3445 // syndrome) but continue if we don't have data
3446 if (availableWindow < m_tcb->m_segmentSize && availableData > availableWindow)
3447 {
3448 NS_LOG_LOGIC("Preventing Silly Window Syndrome. Wait to send.");
3449 break; // No more
3450 }
3451 // Nagle's algorithm (RFC896): Hold off sending if there is unacked data
3452 // in the buffer and the amount of data to send is less than one segment
3453 if (!m_noDelay && UnAckDataCount() > 0 && availableData < m_tcb->m_segmentSize)
3454 {
3455 NS_LOG_DEBUG("Invoking Nagle's algorithm for seq "
3456 << next << ", SFS: " << m_txBuffer->SizeFromSequence(next)
3457 << ". Wait to send.");
3458 break;
3459 }
3460
3461 uint32_t s = std::min(availableWindow, m_tcb->m_segmentSize);
3462 // NextSeg () may have further constrained the segment size
3463 auto maxSizeToSend = static_cast<uint32_t>(nextHigh - next);
3464 s = std::min(s, maxSizeToSend);
3465
3466 // (C.2) If any of the data octets sent in (C.1) are below HighData,
3467 // HighRxt MUST be set to the highest sequence number of the
3468 // retransmitted segment unless NextSeg () rule (4) was
3469 // invoked for this retransmission.
3470 // (C.3) If any of the data octets sent in (C.1) are above HighData,
3471 // HighData must be updated to reflect the transmission of
3472 // previously unsent data.
3473 //
3474 // These steps are done in m_txBuffer with the tags.
3475 if (m_tcb->m_nextTxSequence != next)
3476 {
3477 m_tcb->m_nextTxSequence = next;
3478 }
3479 if (m_tcb->m_bytesInFlight.Get() == 0)
3480 {
3482 }
3483 uint32_t sz = SendDataPacket(m_tcb->m_nextTxSequence, s, withAck);
3484
3485 NS_LOG_LOGIC(" rxwin " << m_rWnd << " segsize " << m_tcb->m_segmentSize
3486 << " highestRxAck " << m_txBuffer->HeadSequence() << " pd->Size "
3487 << m_txBuffer->Size() << " pd->SFS "
3488 << m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence));
3489
3490 NS_LOG_DEBUG("cWnd: " << m_tcb->m_cWnd << " total unAck: " << UnAckDataCount()
3491 << " sent seq " << m_tcb->m_nextTxSequence << " size " << sz);
3492 m_tcb->m_nextTxSequence += sz;
3493 ++nPacketsSent;
3494 if (IsPacingEnabled())
3495 {
3496 NS_LOG_INFO("Pacing is enabled");
3498 {
3499 NS_LOG_DEBUG("Current Pacing Rate " << m_tcb->m_pacingRate);
3500 NS_LOG_DEBUG("Timer is in expired state, activate it "
3501 << m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3502 m_pacingTimer.Schedule(m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3503 break;
3504 }
3505 }
3506 }
3507
3508 // (C.4) The estimate of the amount of data outstanding in the
3509 // network must be updated by incrementing pipe by the number
3510 // of octets transmitted in (C.1).
3511 //
3512 // Done in BytesInFlight, inside AvailableWindow.
3513 availableWindow = AvailableWindow();
3514
3515 // (C.5) If cwnd - pipe >= 1 SMSS, return to (C.1)
3516 // loop again!
3517 }
3518
3519 if (nPacketsSent > 0)
3520 {
3521 if (!m_sackEnabled)
3522 {
3523 if (!m_limitedTx)
3524 {
3525 // We can't transmit in CA_DISORDER without limitedTx active
3527 }
3528 }
3529
3530 NS_LOG_DEBUG("SendPendingData sent " << nPacketsSent << " segments");
3531 }
3532 else
3533 {
3534 NS_LOG_DEBUG("SendPendingData no segments sent");
3535 }
3536 return nPacketsSent;
3537}
3538
3541{
3542 return m_tcb->m_highTxMark - m_txBuffer->HeadSequence();
3543}
3544
3547{
3548 uint32_t bytesInFlight = m_txBuffer->BytesInFlight();
3549 // Ugly, but we are not modifying the state; m_bytesInFlight is used
3550 // only for tracing purpose.
3551 m_tcb->m_bytesInFlight = bytesInFlight;
3552
3553 NS_LOG_DEBUG("Returning calculated bytesInFlight: " << bytesInFlight);
3554 return bytesInFlight;
3555}
3556
3559{
3560 return std::min(m_rWnd.Get(), m_tcb->m_cWnd.Get());
3561}
3562
3565{
3566 uint32_t win = Window(); // Number of bytes allowed to be outstanding
3567 uint32_t inflight = BytesInFlight(); // Number of outstanding bytes
3568 return (inflight > win) ? 0 : win - inflight;
3569}
3570
3571uint16_t
3573{
3574 NS_LOG_FUNCTION(this << scale);
3575 uint32_t w;
3576
3577 // We don't want to advertise 0 after a FIN is received. So, we just use
3578 // the previous value of the advWnd.
3579 if (m_tcb->m_rxBuffer->GotFin())
3580 {
3581 w = m_advWnd;
3582 }
3583 else
3584 {
3585 NS_ASSERT_MSG(m_tcb->m_rxBuffer->MaxRxSequence() - m_tcb->m_rxBuffer->NextRxSequence() >= 0,
3586 "Unexpected sequence number values");
3587 w = static_cast<uint32_t>(m_tcb->m_rxBuffer->MaxRxSequence() -
3588 m_tcb->m_rxBuffer->NextRxSequence());
3589 }
3590
3591 // Ugly, but we are not modifying the state, that variable
3592 // is used only for tracing purpose.
3593 if (w != m_advWnd)
3594 {
3595 const_cast<TcpSocketBase*>(this)->m_advWnd = w;
3596 }
3597 if (scale)
3598 {
3599 w >>= m_rcvWindShift;
3600 }
3601 if (w > m_maxWinSize)
3602 {
3603 w = m_maxWinSize;
3604 NS_LOG_WARN("Adv window size truncated to "
3605 << m_maxWinSize << "; possibly to avoid overflow of the 16-bit integer");
3606 }
3607 NS_LOG_LOGIC("Returning AdvertisedWindowSize of " << static_cast<uint16_t>(w));
3608 return static_cast<uint16_t>(w);
3609}
3610
3611// Receipt of new packet, put into Rx buffer
3612void
3614{
3615 NS_LOG_FUNCTION(this << tcpHeader);
3616 NS_LOG_DEBUG("Data segment, seq=" << tcpHeader.GetSequenceNumber()
3617 << " pkt size=" << p->GetSize());
3618
3619 // Put into Rx buffer
3620 SequenceNumber32 expectedSeq = m_tcb->m_rxBuffer->NextRxSequence();
3621 if (!m_tcb->m_rxBuffer->Add(p, tcpHeader))
3622 { // Insert failed: No data or RX buffer full
3623 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3625 {
3627 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
3629 }
3630 else
3631 {
3633 }
3634 return;
3635 }
3636 // Notify app to receive if necessary
3637 if (expectedSeq < m_tcb->m_rxBuffer->NextRxSequence())
3638 { // NextRxSeq advanced, we have something to send to the app
3639 if (!m_shutdownRecv)
3640 {
3642 }
3643 // Handle exceptions
3644 if (m_closeNotified)
3645 {
3646 NS_LOG_WARN("Why TCP " << this << " got data after close notification?");
3647 }
3648 // If we received FIN before and now completed all "holes" in rx buffer,
3649 // invoke peer close procedure
3650 if (m_tcb->m_rxBuffer->Finished() && (tcpHeader.GetFlags() & TcpHeader::FIN) == 0)
3651 {
3652 DoPeerClose();
3653 return;
3654 }
3655 }
3656 // Now send a new ACK packet acknowledging all received and delivered data
3657 if (m_tcb->m_rxBuffer->Size() > m_tcb->m_rxBuffer->Available() ||
3658 m_tcb->m_rxBuffer->NextRxSequence() > expectedSeq + p->GetSize())
3659 { // A gap exists in the buffer, or we filled a gap: Always ACK
3661 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3663 {
3665 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
3667 }
3668 else
3669 {
3671 }
3672 }
3673 else
3674 { // In-sequence packet: ACK if delayed ack count allows
3676 {
3678 m_delAckCount = 0;
3680 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3682 {
3683 NS_LOG_DEBUG("Congestion algo " << m_congestionControl->GetName());
3686 << " -> ECN_SENDING_ECE");
3688 }
3689 else
3690 {
3692 }
3693 }
3694 else if (!m_delAckEvent.IsExpired())
3695 {
3697 }
3698 else if (m_delAckEvent.IsExpired())
3699 {
3704 this << " scheduled delayed ACK at "
3706 }
3707 }
3708}
3709
3710Time
3711TcpSocketBase::CalculateRttSample(const TcpHeader& tcpHeader, const RttHistory& rttHistory)
3712{
3713 NS_LOG_FUNCTION(this);
3714 SequenceNumber32 ackSeq = tcpHeader.GetAckNumber();
3715 Time rtt;
3716
3717 if (ackSeq >= (rttHistory.seq + SequenceNumber32(rttHistory.count)))
3718 {
3719 // As per RFC 6298 (Section 3)
3720 // RTT samples MUST NOT be made using segments that were
3721 // retransmitted (and thus for which it is ambiguous whether the reply
3722 // was for the first instance of the packet or a later instance). The
3723 // only case when TCP can safely take RTT samples from retransmitted
3724 // segments is when the TCP timestamp option is employed, since
3725 // the timestamp option removes the ambiguity regarding which instance
3726 // of the data segment triggered the acknowledgment.
3727 if (m_timestampEnabled && tcpHeader.HasOption(TcpOption::TS))
3728 {
3731 rtt = TcpOptionTS::ElapsedTimeFromTsValue(ts->GetEcho());
3732 if (rtt.IsZero())
3733 {
3734 NS_LOG_LOGIC("TcpSocketBase::EstimateRtt - RTT calculated from TcpOption::TS "
3735 "is zero, approximating to 1us.");
3736 NS_LOG_DEBUG("RTT calculated from TcpOption::TS is zero, updating rtt to 1us.");
3737 rtt = MicroSeconds(1);
3738 }
3739 }
3740 else if (!rttHistory.retx)
3741 {
3742 // Elapsed time since the packet was transmitted
3743 rtt = Simulator::Now() - rttHistory.time;
3744 }
3745 }
3746 return rtt;
3747}
3748
3749void
3751{
3752 NS_LOG_FUNCTION(this);
3753 SequenceNumber32 ackSeq = tcpHeader.GetAckNumber();
3754 Time rtt;
3755
3756 // An ack has been received, calculate rtt and log this measurement
3757 // Note we use a linear search (O(n)) for this since for the common
3758 // case the ack'ed packet will be at the head of the list
3759 if (!m_history.empty())
3760 {
3761 RttHistory& earliestTransmittedPktHistory = m_history.front();
3762 rtt = CalculateRttSample(tcpHeader, earliestTransmittedPktHistory);
3763
3764 // Store ACKed packet that has the latest transmission time to update `lastRtt`
3765 RttHistory latestTransmittedPktHistory = earliestTransmittedPktHistory;
3766
3767 // Delete all ACK history with seq <= ack
3768 while (!m_history.empty())
3769 {
3770 RttHistory& rttHistory = m_history.front();
3771 if ((rttHistory.seq + SequenceNumber32(rttHistory.count)) > ackSeq)
3772 {
3773 break; // Done removing
3774 }
3775
3776 latestTransmittedPktHistory = rttHistory;
3777 m_history.pop_front(); // Remove
3778 }
3779
3780 // In case of multiple packets being ACKed in a single acknowledgement, `m_lastRtt` is
3781 // RTT of the last (S)ACKed packet calculated using the data packet with the latest
3782 // transmission time
3783 Time lastRtt = CalculateRttSample(tcpHeader, latestTransmittedPktHistory);
3784 if (!lastRtt.IsZero())
3785 {
3786 NS_LOG_DEBUG("Last RTT sample updated to: " << lastRtt);
3787 m_tcb->m_lastRtt = lastRtt;
3788 }
3789 }
3790
3791 if (!rtt.IsZero())
3792 {
3793 m_rtt->Measurement(rtt); // Log the measurement
3794 // RFC 6298, clause 2.4
3795 m_rto = Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4),
3796 m_minRto);
3797 m_tcb->m_srtt = m_rtt->GetEstimate();
3798 m_tcb->m_minRtt = std::min(m_tcb->m_srtt.Get(), m_tcb->m_minRtt);
3799 NS_LOG_INFO(this << m_tcb->m_srtt << m_tcb->m_minRtt);
3800 }
3801}
3802
3803// Called by the ReceivedAck() when new ACK received and by ProcessSynRcvd()
3804// when the three-way handshake completed. This cancels retransmission timer
3805// and advances Tx window
3806void
3807TcpSocketBase::NewAck(const SequenceNumber32& ack, bool resetRTO)
3808{
3809 NS_LOG_FUNCTION(this << ack);
3810
3811 // Reset the data retransmission count. We got a new ACK!
3813
3814 if (m_state != SYN_RCVD && resetRTO)
3815 { // Set RTO unless the ACK is received in SYN_RCVD state
3817 this << " Cancelled ReTxTimeout event which was set to expire at "
3818 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
3820 // On receiving a "New" ack we restart retransmission timer .. RFC 6298
3821 // RFC 6298, clause 2.4
3822 m_rto = Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4),
3823 m_minRto);
3824
3825 NS_LOG_LOGIC(this << " Schedule ReTxTimeout at time " << Simulator::Now().GetSeconds()
3826 << " to expire at time "
3827 << (Simulator::Now() + m_rto.Get()).GetSeconds());
3829 }
3830
3831 // Note the highest ACK and tell app to send more
3832 NS_LOG_LOGIC("TCP " << this << " NewAck " << ack << " numberAck "
3833 << (ack - m_txBuffer->HeadSequence())); // Number bytes ack'ed
3834
3835 if (GetTxAvailable() > 0)
3836 {
3838 }
3839 if (ack > m_tcb->m_nextTxSequence)
3840 {
3841 m_tcb->m_nextTxSequence = ack; // If advanced
3842 }
3843 if (m_txBuffer->Size() == 0 && m_state != FIN_WAIT_1 && m_state != CLOSING)
3844 { // No retransmit timer if no data to retransmit
3846 this << " Cancelled ReTxTimeout event which was set to expire at "
3847 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
3849 }
3850}
3851
3852// Retransmit timeout
3853void
3855{
3856 NS_LOG_FUNCTION(this);
3857 NS_LOG_LOGIC(this << " ReTxTimeout Expired at time " << Simulator::Now().GetSeconds());
3858 // If erroneous timeout in closed/timed-wait state, just return
3859 if (m_state == CLOSED || m_state == TIME_WAIT)
3860 {
3861 return;
3862 }
3863
3864 if (m_state == SYN_SENT)
3865 {
3866 NS_ASSERT(m_synCount > 0);
3867 if (m_tcb->m_useEcn == TcpSocketState::On)
3868 {
3870 }
3871 else
3872 {
3874 }
3875 return;
3876 }
3877
3878 // Retransmit non-data packet: Only if in FIN_WAIT_1 or CLOSING state
3879 if (m_txBuffer->Size() == 0)
3880 {
3881 if (m_state == FIN_WAIT_1 || m_state == CLOSING)
3882 { // Must have lost FIN, re-send
3884 }
3885 return;
3886 }
3887
3888 NS_LOG_DEBUG("Checking if Connection is Established");
3889 // If all data are received (non-closing socket and nothing to send), just return
3890 if (m_state <= ESTABLISHED && m_txBuffer->HeadSequence() >= m_tcb->m_highTxMark &&
3891 m_txBuffer->Size() == 0)
3892 {
3893 NS_LOG_DEBUG("Already Sent full data" << m_txBuffer->HeadSequence() << " "
3894 << m_tcb->m_highTxMark);
3895 return;
3896 }
3897
3898 if (m_dataRetrCount == 0)
3899 {
3900 NS_LOG_INFO("No more data retries available. Dropping connection");
3903 return;
3904 }
3905 else
3906 {
3908 }
3909
3910 uint32_t inFlightBeforeRto = BytesInFlight();
3911 bool resetSack = !m_sackEnabled; // Reset SACK information if SACK is not enabled.
3912 // The information in the TcpTxBuffer is guessed, in this case.
3913
3914 // Reset dupAckCount
3915 m_dupAckCount = 0;
3916 if (!m_sackEnabled)
3917 {
3918 m_txBuffer->ResetRenoSack();
3919 }
3920
3921 // From RFC 6675, Section 5.1
3922 // [RFC2018] suggests that a TCP sender SHOULD expunge the SACK
3923 // information gathered from a receiver upon a retransmission timeout
3924 // (RTO) "since the timeout might indicate that the data receiver has
3925 // reneged." Additionally, a TCP sender MUST "ignore prior SACK
3926 // information in determining which data to retransmit."
3927 // It has been suggested that, as long as robust tests for
3928 // reneging are present, an implementation can retain and use SACK
3929 // information across a timeout event [Errata1610].
3930 // The head of the sent list will not be marked as sacked, therefore
3931 // will be retransmitted, if the receiver renegotiate the SACK blocks
3932 // that we received.
3933 m_txBuffer->SetSentListLost(resetSack);
3934
3935 // From RFC 6675, Section 5.1
3936 // If an RTO occurs during loss recovery as specified in this document,
3937 // RecoveryPoint MUST be set to HighData. Further, the new value of
3938 // RecoveryPoint MUST be preserved and the loss recovery algorithm
3939 // outlined in this document MUST be terminated.
3940 m_recover = m_tcb->m_highTxMark;
3941 m_recoverActive = true;
3942
3943 // RFC 6298, clause 2.5, double the timer
3944 Time doubledRto = m_rto + m_rto;
3945 m_rto = Min(doubledRto, Time::FromDouble(60, Time::S));
3946
3947 // Empty RTT history
3948 m_history.clear();
3949
3950 // Please don't reset highTxMark, it is used for retransmission detection
3951
3952 // When a TCP sender detects segment loss using the retransmission timer
3953 // and the given segment has not yet been resent by way of the
3954 // retransmission timer, decrease ssThresh
3955 if (m_tcb->m_congState != TcpSocketState::CA_LOSS || !m_txBuffer->IsHeadRetransmitted())
3956 {
3957 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, inFlightBeforeRto);
3958 }
3959
3960 // Cwnd set to 1 MSS
3963 m_tcb->m_congState = TcpSocketState::CA_LOSS;
3964 m_tcb->m_cWnd = m_tcb->m_segmentSize;
3965 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
3966
3968
3969 NS_LOG_DEBUG("RTO. Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to " << m_tcb->m_ssThresh
3970 << ", restart from seqnum " << m_txBuffer->HeadSequence()
3971 << " doubled rto to " << m_rto.Get().GetSeconds() << " s");
3972
3974 "There are some bytes in flight after an RTO: " << BytesInFlight());
3975
3977
3978 NS_ASSERT_MSG(BytesInFlight() <= m_tcb->m_segmentSize,
3979 "In flight (" << BytesInFlight() << ") there is more than one segment ("
3980 << m_tcb->m_segmentSize << ")");
3981}
3982
3983void
3999
4000void
4002{
4003 NS_LOG_FUNCTION(this);
4004
4006 if (m_state == LAST_ACK)
4007 {
4008 if (m_dataRetrCount == 0)
4009 {
4010 NS_LOG_INFO("LAST-ACK: No more data retries available. Dropping connection");
4013 return;
4014 }
4017 NS_LOG_LOGIC("TcpSocketBase " << this << " rescheduling LATO1");
4018 Time lastRto = m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4);
4020 }
4021}
4022
4023// Send 1-byte data to probe for the window size at the receiver when
4024// the local knowledge tells that the receiver has zero window size
4025// C.f.: RFC793 p.42, RFC1112 sec.4.2.2.17
4026void
4028{
4029 NS_LOG_LOGIC("PersistTimeout expired at " << Simulator::Now().GetSeconds());
4031 std::min(Seconds(60), Time(2 * m_persistTimeout)); // max persist timeout = 60s
4032 Ptr<Packet> p = m_txBuffer->CopyFromSequence(1, m_tcb->m_nextTxSequence)->GetPacketCopy();
4033 m_txBuffer->ResetLastSegmentSent();
4034 TcpHeader tcpHeader;
4035 tcpHeader.SetSequenceNumber(m_tcb->m_nextTxSequence);
4036 tcpHeader.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
4038 if (m_endPoint != nullptr)
4039 {
4042 }
4043 else
4044 {
4047 }
4048 AddOptions(tcpHeader);
4049 // Send a packet tag for setting ECT bits in IP header
4050 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED)
4051 {
4053 }
4054 m_txTrace(p, tcpHeader, this);
4055
4056 if (m_endPoint != nullptr)
4057 {
4058 m_tcp->SendPacket(p,
4059 tcpHeader,
4063 }
4064 else
4065 {
4066 m_tcp->SendPacket(p,
4067 tcpHeader,
4071 }
4072
4073 NS_LOG_LOGIC("Schedule persist timeout at time "
4074 << Simulator::Now().GetSeconds() << " to expire at time "
4075 << (Simulator::Now() + m_persistTimeout).GetSeconds());
4077}
4078
4079void
4081{
4082 NS_LOG_FUNCTION(this);
4083 bool res;
4084 SequenceNumber32 seq;
4085 SequenceNumber32 seqHigh;
4086 uint32_t maxSizeToSend;
4087
4088 // Find the first segment marked as lost and not retransmitted. With Reno,
4089 // that should be the head
4090 res = m_txBuffer->NextSeg(&seq, &seqHigh, false);
4091 if (!res)
4092 {
4093 // We have already retransmitted the head. However, we still received
4094 // three dupacks, or the RTO expired, but no data to transmit.
4095 // Therefore, re-send again the head.
4096 seq = m_txBuffer->HeadSequence();
4097 maxSizeToSend = m_tcb->m_segmentSize;
4098 }
4099 else
4100 {
4101 // NextSeg() may constrain the segment size when res is true
4102 maxSizeToSend = static_cast<uint32_t>(seqHigh - seq);
4103 }
4104 NS_ASSERT(m_sackEnabled || seq == m_txBuffer->HeadSequence());
4105
4106 NS_LOG_INFO("Retransmitting " << seq);
4107 // Update the trace and retransmit the segment
4108 m_tcb->m_nextTxSequence = seq;
4109 uint32_t sz = SendDataPacket(m_tcb->m_nextTxSequence, maxSizeToSend, true);
4110
4111 NS_ASSERT(sz > 0);
4112}
4113
4114void
4125
4126/* Move TCP to Time_Wait state and schedule a transition to Closed state */
4127void
4129{
4130 NS_LOG_DEBUG(TcpStateName[m_state] << " -> TIME_WAIT");
4133 if (!m_closeNotified)
4134 {
4135 // Technically the connection is not fully closed, but we notify now
4136 // because an implementation (real socket) would behave as if closed.
4137 // Notify normal close when entering TIME_WAIT or leaving LAST_ACK.
4139 m_closeNotified = true;
4140 }
4141 // Move from TIME_WAIT to CLOSED after 2*MSL. Max segment lifetime is 2 min
4142 // according to RFC793, p.28
4144}
4145
4146/* Below are the attribute get/set functions */
4147
4148void
4150{
4151 NS_LOG_FUNCTION(this << size);
4152 m_txBuffer->SetMaxBufferSize(size);
4153}
4154
4157{
4158 return m_txBuffer->MaxBufferSize();
4159}
4160
4161void
4163{
4164 NS_LOG_FUNCTION(this << size);
4165 uint32_t oldSize = GetRcvBufSize();
4166
4167 m_tcb->m_rxBuffer->SetMaxBufferSize(size);
4168
4169 /* The size has (manually) increased. Actively inform the other end to prevent
4170 * stale zero-window states.
4171 */
4172 if (oldSize < size && m_connected)
4173 {
4174 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
4176 {
4178 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
4180 }
4181 else
4182 {
4184 }
4185 }
4186}
4187
4190{
4191 return m_tcb->m_rxBuffer->MaxBufferSize();
4192}
4193
4194void
4196{
4197 NS_LOG_FUNCTION(this << size);
4198 m_tcb->m_segmentSize = size;
4199 m_txBuffer->SetSegmentSize(size);
4200
4201 NS_ABORT_MSG_UNLESS(m_state == CLOSED, "Cannot change segment size dynamically.");
4202}
4203
4206{
4207 return m_tcb->m_segmentSize;
4208}
4209
4210void
4216
4217Time
4219{
4220 return m_cnTimeout;
4221}
4222
4223void
4225{
4226 NS_LOG_FUNCTION(this << count);
4227 m_synRetries = count;
4228}
4229
4232{
4233 return m_synRetries;
4234}
4235
4236void
4238{
4239 NS_LOG_FUNCTION(this << retries);
4240 m_dataRetries = retries;
4241}
4242
4245{
4246 NS_LOG_FUNCTION(this);
4247 return m_dataRetries;
4248}
4249
4250void
4256
4257Time
4259{
4260 return m_delAckTimeout;
4261}
4262
4263void
4265{
4266 NS_LOG_FUNCTION(this << count);
4267 m_delAckMaxCount = count;
4268}
4269
4275
4276void
4278{
4279 NS_LOG_FUNCTION(this << noDelay);
4280 m_noDelay = noDelay;
4281}
4282
4283bool
4285{
4286 return m_noDelay;
4287}
4288
4289void
4295
4296Time
4301
4302bool
4304{
4305 // Broadcast is not implemented. Return true only if allowBroadcast==false
4306 return (!allowBroadcast);
4307}
4308
4309bool
4311{
4312 return false;
4313}
4314
4315void
4317{
4318 NS_LOG_FUNCTION(this << header);
4319
4321 {
4322 AddOptionTimestamp(header);
4323 }
4324}
4325
4326void
4328{
4329 NS_LOG_FUNCTION(this << option);
4330
4332
4333 // In naming, we do the contrary of RFC 1323. The received scaling factor
4334 // is Rcv.Wind.Scale (and not Snd.Wind.Scale)
4335 m_sndWindShift = ws->GetScale();
4336
4337 if (m_sndWindShift > 14)
4338 {
4339 NS_LOG_WARN("Possible error; m_sndWindShift exceeds 14: " << m_sndWindShift);
4340 m_sndWindShift = 14;
4341 }
4342
4343 NS_LOG_INFO(m_node->GetId() << " Received a scale factor of "
4344 << static_cast<int>(m_sndWindShift));
4345}
4346
4347uint8_t
4349{
4350 NS_LOG_FUNCTION(this);
4351 uint32_t maxSpace = m_tcb->m_rxBuffer->MaxBufferSize();
4352 uint8_t scale = 0;
4353
4354 while (maxSpace > m_maxWinSize)
4355 {
4356 maxSpace = maxSpace >> 1;
4357 ++scale;
4358 }
4359
4360 if (scale > 14)
4361 {
4362 NS_LOG_WARN("Possible error; scale exceeds 14: " << scale);
4363 scale = 14;
4364 }
4365
4366 NS_LOG_INFO("Node " << m_node->GetId() << " calculated wscale factor of "
4367 << static_cast<int>(scale) << " for buffer size "
4368 << m_tcb->m_rxBuffer->MaxBufferSize());
4369 return scale;
4370}
4371
4372void
4374{
4375 NS_LOG_FUNCTION(this << header);
4376 NS_ASSERT(header.GetFlags() & TcpHeader::SYN);
4377
4379
4380 // In naming, we do the contrary of RFC 1323. The sended scaling factor
4381 // is Snd.Wind.Scale (and not Rcv.Wind.Scale)
4382
4384 option->SetScale(m_rcvWindShift);
4385
4386 header.AppendOption(option);
4387
4388 NS_LOG_INFO(m_node->GetId() << " Send a scaling factor of "
4389 << static_cast<int>(m_rcvWindShift));
4390}
4391
4394{
4395 NS_LOG_FUNCTION(this << option);
4396
4398 return m_txBuffer->Update(s->GetSackList(), MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
4399}
4400
4401void
4403{
4404 NS_LOG_FUNCTION(this << option);
4405
4407
4408 NS_ASSERT(m_sackEnabled == true);
4409 NS_LOG_INFO(m_node->GetId() << " Received a SACK_PERMITTED option " << s);
4410}
4411
4412void
4414{
4415 NS_LOG_FUNCTION(this << header);
4416 NS_ASSERT(header.GetFlags() & TcpHeader::SYN);
4417
4419 header.AppendOption(option);
4420 NS_LOG_INFO(m_node->GetId() << " Add option SACK-PERMITTED");
4421}
4422
4423void
4425{
4426 NS_LOG_FUNCTION(this << header);
4427
4428 // Calculate the number of SACK blocks allowed in this packet
4429 uint8_t optionLenAvail = header.GetMaxOptionLength() - header.GetOptionLength();
4430 uint8_t allowedSackBlocks = (optionLenAvail - 2) / 8;
4431
4432 TcpOptionSack::SackList sackList = m_tcb->m_rxBuffer->GetSackList();
4433 if (allowedSackBlocks == 0 || sackList.empty())
4434 {
4435 NS_LOG_LOGIC("No space available or sack list empty, not adding sack blocks");
4436 return;
4437 }
4438
4439 // Append the allowed number of SACK blocks
4441
4442 for (auto i = sackList.begin(); allowedSackBlocks > 0 && i != sackList.end(); ++i)
4443 {
4444 option->AddSackBlock(*i);
4445 allowedSackBlocks--;
4446 }
4447
4448 header.AppendOption(option);
4449 NS_LOG_INFO(m_node->GetId() << " Add option SACK " << *option);
4450}
4451
4452void
4454 const SequenceNumber32& seq)
4455{
4456 NS_LOG_FUNCTION(this << option);
4457
4459
4460 // This is valid only when no overflow occurs. It happens
4461 // when a connection last longer than 50 days.
4462 if (m_tcb->m_rcvTimestampValue > ts->GetTimestamp())
4463 {
4464 // Do not save a smaller timestamp (probably there is reordering)
4465 return;
4466 }
4467
4468 m_tcb->m_rcvTimestampValue = ts->GetTimestamp();
4469 m_tcb->m_rcvTimestampEchoReply = ts->GetEcho();
4470
4471 if (seq == m_tcb->m_rxBuffer->NextRxSequence() && seq <= m_highTxAck)
4472 {
4473 m_timestampToEcho = ts->GetTimestamp();
4474 }
4475
4476 NS_LOG_INFO(m_node->GetId() << " Got timestamp=" << m_timestampToEcho
4477 << " and Echo=" << ts->GetEcho());
4478}
4479
4480void
4482{
4483 NS_LOG_FUNCTION(this << header);
4484
4486
4487 option->SetTimestamp(TcpOptionTS::NowToTsValue());
4488 option->SetEcho(m_timestampToEcho);
4489
4490 header.AppendOption(option);
4491 NS_LOG_INFO(m_node->GetId() << " Add option TS, ts=" << option->GetTimestamp()
4492 << " echo=" << m_timestampToEcho);
4493}
4494
4495void
4497{
4498 NS_LOG_FUNCTION(this << header);
4499 // If the connection is not established, the window size is always
4500 // updated
4501 uint32_t receivedWindow = header.GetWindowSize();
4502 receivedWindow <<= m_sndWindShift;
4503 NS_LOG_INFO("Received (scaled) window is " << receivedWindow << " bytes");
4504 if (m_state < ESTABLISHED)
4505 {
4506 m_rWnd = receivedWindow;
4507 NS_LOG_LOGIC("State less than ESTABLISHED; updating rWnd to " << m_rWnd);
4508 return;
4509 }
4510
4511 // Test for conditions that allow updating of the window
4512 // 1) segment contains new data (advancing the right edge of the receive
4513 // buffer),
4514 // 2) segment does not contain new data but the segment acks new data
4515 // (highest sequence number acked advances), or
4516 // 3) the advertised window is larger than the current send window
4517 bool update = false;
4518 if (header.GetAckNumber() == m_highRxAckMark && receivedWindow > m_rWnd)
4519 {
4520 // right edge of the send window is increased (window update)
4521 update = true;
4522 }
4523 if (header.GetAckNumber() > m_highRxAckMark)
4524 {
4525 m_highRxAckMark = header.GetAckNumber();
4526 update = true;
4527 }
4528 if (header.GetSequenceNumber() > m_highRxMark)
4529 {
4531 update = true;
4532 }
4533 if (update)
4534 {
4535 m_rWnd = receivedWindow;
4536 NS_LOG_LOGIC("updating rWnd to " << m_rWnd);
4537 }
4538}
4539
4540void
4542{
4543 NS_LOG_FUNCTION(this << minRto);
4544 m_minRto = minRto;
4545}
4546
4547Time
4549{
4550 return m_minRto;
4551}
4552
4553void
4555{
4556 NS_LOG_FUNCTION(this << clockGranularity);
4557 m_clockGranularity = clockGranularity;
4558}
4559
4560Time
4565
4568{
4569 return m_txBuffer;
4570}
4571
4574{
4575 return m_tcb->m_rxBuffer;
4576}
4577
4578void
4580{
4581 m_retxThresh = retxThresh;
4582 m_txBuffer->SetDupAckThresh(retxThresh);
4583}
4584
4585void
4587{
4588 m_pacingRateTrace(oldValue, newValue);
4589}
4590
4591void
4593{
4594 m_cWndTrace(oldValue, newValue);
4595}
4596
4597void
4599{
4600 m_cWndInflTrace(oldValue, newValue);
4601}
4602
4603void
4605{
4606 m_ssThTrace(oldValue, newValue);
4607}
4608
4609void
4615
4616void
4618 TcpSocketState::EcnState_t newValue) const
4619{
4620 m_ecnStateTrace(oldValue, newValue);
4621}
4622
4623void
4625
4626{
4627 m_nextTxSequenceTrace(oldValue, newValue);
4628}
4629
4630void
4632{
4633 m_highTxMarkTrace(oldValue, newValue);
4634}
4635
4636void
4638{
4639 m_bytesInFlightTrace(oldValue, newValue);
4640}
4641
4642void
4643TcpSocketBase::UpdateRtt(Time oldValue, Time newValue) const
4644{
4645 m_srttTrace(oldValue, newValue);
4646}
4647
4648void
4649TcpSocketBase::UpdateLastRtt(Time oldValue, Time newValue) const
4650{
4651 m_lastRttTrace(oldValue, newValue);
4652}
4653
4654void
4661
4662void
4664{
4665 NS_LOG_FUNCTION(this << recovery);
4666 m_recoveryOps = recovery;
4667}
4668
4671{
4672 return CopyObject<TcpSocketBase>(this);
4673}
4674
4677{
4678 if (a > b)
4679 {
4680 return a - b;
4681 }
4682
4683 return 0;
4684}
4685
4686void
4688{
4689 NS_LOG_FUNCTION(this);
4690 NS_LOG_INFO("Performing Pacing");
4692}
4693
4694bool
4696{
4697 if (!m_tcb->m_pacing)
4698 {
4699 return false;
4700 }
4701 else
4702 {
4703 if (m_tcb->m_paceInitialWindow)
4704 {
4705 return true;
4706 }
4707 SequenceNumber32 highTxMark = m_tcb->m_highTxMark; // cast traced value
4708 if (highTxMark.GetValue() > (GetInitialCwnd() * m_tcb->m_segmentSize))
4709 {
4710 return true;
4711 }
4712 }
4713 return false;
4714}
4715
4716void
4718{
4719 NS_LOG_FUNCTION(this << m_tcb);
4720
4721 // According to Linux, set base pacing rate to (cwnd * mss) / srtt
4722 //
4723 // In (early) slow start, multiply base by the slow start factor.
4724 // In late slow start and congestion avoidance, multiply base by
4725 // the congestion avoidance factor.
4726 // Comment from Linux code regarding early/late slow start:
4727 // Normal Slow Start condition is (tp->snd_cwnd < tp->snd_ssthresh)
4728 // If snd_cwnd >= (tp->snd_ssthresh / 2), we are approaching
4729 // end of slow start and should slow down.
4730
4731 // Similar to Linux, do not update pacing rate here if the
4732 // congestion control implements TcpCongestionOps::CongControl ()
4733 if (m_congestionControl->HasCongControl() || !m_tcb->m_pacing)
4734 {
4735 return;
4736 }
4737
4738 double factor;
4739 if (m_tcb->m_cWnd < m_tcb->m_ssThresh / 2)
4740 {
4741 NS_LOG_DEBUG("Pacing according to slow start factor; " << m_tcb->m_cWnd << " "
4742 << m_tcb->m_ssThresh);
4743 factor = static_cast<double>(m_tcb->m_pacingSsRatio) / 100;
4744 }
4745 else
4746 {
4747 NS_LOG_DEBUG("Pacing according to congestion avoidance factor; " << m_tcb->m_cWnd << " "
4748 << m_tcb->m_ssThresh);
4749 factor = static_cast<double>(m_tcb->m_pacingCaRatio) / 100;
4750 }
4751 Time srtt = m_tcb->m_srtt.Get(); // Get underlying Time value
4752 NS_LOG_DEBUG("Smoothed RTT is " << srtt.GetSeconds());
4753
4754 // Multiply by 8 to convert from bytes per second to bits per second
4755 DataRate pacingRate((std::max(m_tcb->m_cWnd, m_tcb->m_bytesInFlight) * 8 * factor) /
4756 srtt.GetSeconds());
4757 if (pacingRate < m_tcb->m_maxPacingRate)
4758 {
4759 NS_LOG_DEBUG("Pacing rate updated to: " << pacingRate);
4760 m_tcb->m_pacingRate = pacingRate;
4761 }
4762 else
4763 {
4764 NS_LOG_DEBUG("Pacing capped by max pacing rate: " << m_tcb->m_maxPacingRate);
4765 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
4766 }
4767}
4768
4769void
4771{
4772 NS_LOG_FUNCTION(this << pacing);
4773 m_tcb->m_pacing = pacing;
4774}
4775
4776void
4778{
4779 NS_LOG_FUNCTION(this << paceWindow);
4780 m_tcb->m_paceInitialWindow = paceWindow;
4781}
4782
4783bool
4785{
4786 NS_LOG_FUNCTION(this << packetType);
4787 NS_ASSERT_MSG(packetType != TcpPacketType_t::INVALID, "Invalid TCP packet type");
4788 if (m_tcb->m_ecnState == TcpSocketState::ECN_DISABLED)
4789 {
4790 return false;
4791 }
4792
4793 NS_ABORT_MSG_IF(!ECN_RESTRICTION_MAP.contains(std::make_pair(packetType, m_tcb->m_ecnMode)),
4794 "Invalid packetType and ecnMode");
4795
4796 return ECN_RESTRICTION_MAP.at(std::make_pair(packetType, m_tcb->m_ecnMode));
4797}
4798
4799void
4801{
4802 NS_LOG_FUNCTION(this << useEcn);
4803 m_tcb->m_useEcn = useEcn;
4804}
4805
4808{
4809 return m_rWnd.Get();
4810}
4811
4814{
4815 return m_highRxAckMark.Get();
4816}
4817
4818// RttHistory methods
4820 : seq(s),
4821 count(c),
4822 time(t),
4823 retx(false)
4824{
4825}
4826
4828 : seq(h.seq),
4829 count(h.count),
4830 time(h.time),
4831 retx(h.retx)
4832{
4833}
4834
4835} // namespace ns3
#define Max(a, b)
#define Min(a, b)
a polymophic address class
Definition address.h:90
AttributeValue implementation for Boolean.
Definition boolean.h:26
Callback template class.
Definition callback.h:422
AttributeValue implementation for Callback.
Definition callback.h:786
Class for representing data rates.
Definition data-rate.h:78
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
Hold variables of type enum.
Definition enum.h:52
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:561
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:595
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:206
Ptr< NetDevice > GetBoundNetDevice()
Returns socket's bound NetDevice, if any.
Definition socket.cc:336
Ptr< Packet > Recv()
Read a single packet from the socket.
Definition socket.cc:163
void SetConnectCallback(Callback< void, Ptr< Socket > > connectionSucceeded, Callback< void, Ptr< Socket > > connectionFailed)
Specify callbacks to allow the caller to determine if the connection succeeds of fails.
Definition socket.cc:76
bool IsManualIpTtl() const
Checks if the socket has a specific IPv4 TTL set.
Definition socket.cc:363
void NotifySend(uint32_t spaceAvailable)
Notify through the callback (if set) that some data have been sent.
Definition socket.cc:281
void NotifyNewConnectionCreated(Ptr< Socket > socket, const Address &from)
Notify through the callback (if set) that a new connection has been created.
Definition socket.cc:261
virtual uint8_t GetIpTtl() const
Query the value of IP Time to Live field of this socket.
Definition socket.cc:506
bool NotifyConnectionRequest(const Address &from)
Notify through the callback (if set) that an incoming connection is being requested by a remote host.
Definition socket.cc:243
uint8_t GetIpTos() const
Query the value of IP Type of Service of this socket.
Definition socket.cc:439
SocketType
Enumeration of the possible socket types.
Definition socket.h:96
@ NS3_SOCK_STREAM
Definition socket.h:97
void SetDataSentCallback(Callback< void, Ptr< Socket >, uint32_t > dataSent)
Notify application when a packet has been sent from transport protocol (non-standard socket call)
Definition socket.cc:103
void SetSendCallback(Callback< void, Ptr< Socket >, uint32_t > sendCb)
Notify application when space in transmit buffer is added.
Definition socket.cc:110
void NotifyErrorClose()
Notify through the callback (if set) that the connection has been closed due to an error.
Definition socket.cc:233
void NotifyDataRecv()
Notify through the callback (if set) that some data have been received.
Definition socket.cc:291
Ptr< NetDevice > m_boundnetdevice
the device this socket is bound to (might be null).
Definition socket.h:1070
virtual void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
Definition socket.cc:316
void NotifyNormalClose()
Notify through the callback (if set) that the connection has been closed.
Definition socket.cc:223
virtual uint8_t GetIpv6HopLimit() const
Query the value of IP Hop Limit field of this socket.
Definition socket.cc:531
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition socket.cc:117
SocketErrno
Enumeration of the possible errors returned by a socket.
Definition socket.h:73
@ ERROR_SHUTDOWN
Definition socket.h:79
@ ERROR_INVAL
Definition socket.h:82
@ ERROR_ADDRINUSE
Definition socket.h:87
@ ERROR_ADDRNOTAVAIL
Definition socket.h:86
@ ERROR_NOTCONN
Definition socket.h:76
@ ERROR_MSGSIZE
Definition socket.h:77
void NotifyDataSent(uint32_t size)
Notify through the callback (if set) that some data have been sent.
Definition socket.cc:271
void NotifyConnectionSucceeded()
Notify through the callback (if set) that the connection has been established.
Definition socket.cc:203
uint8_t GetPriority() const
Query the priority value of this socket.
Definition socket.cc:382
uint8_t GetIpv6Tclass() const
Query the value of IPv6 Traffic Class field of this socket.
Definition socket.cc:481
bool IsManualIpv6HopLimit() const
Checks if the socket has a specific IPv6 Hop Limit set.
Definition socket.cc:369
bool IsManualIpv6Tclass() const
Checks if the socket has a specific IPv6 Tclass set.
Definition socket.cc:357
void NotifyConnectionFailed()
Notify through the callback (if set) that the connection has not been established due to an error.
Definition socket.cc:213
indicates whether the socket has IP_TOS set.
Definition socket.h:1260
void SetTos(uint8_t tos)
Set the tag's TOS.
Definition socket.cc:787
This class implements a tag that carries the socket-specific TTL of a packet to the IP layer.
Definition socket.h:1113
void SetTtl(uint8_t ttl)
Set the tag's TTL.
Definition socket.cc:593
This class implements a tag that carries the socket-specific HOPLIMIT of a packet to the IPv6 layer.
Definition socket.h:1161
void SetHopLimit(uint8_t hopLimit)
Set the tag's Hop Limit.
Definition socket.cc:657
indicates whether the socket has IPV6_TCLASS set.
Definition socket.h:1355
void SetTclass(uint8_t tclass)
Set the tag's Tclass.
Definition socket.cc:899
indicates whether the socket has a priority set.
Definition socket.h:1307
void SetPriority(uint8_t priority)
Set the tag's priority.
Definition socket.cc:843
Header for the Transmission Control Protocol.
Definition tcp-header.h:36
void SetDestinationPort(uint16_t port)
Set the destination port.
Definition tcp-header.cc:59
void SetSequenceNumber(SequenceNumber32 sequenceNumber)
Set the sequence Number.
Definition tcp-header.cc:65
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
uint8_t GetMaxOptionLength() const
Get maximum option length.
uint16_t GetDestinationPort() const
Get the destination port.
Ptr< const TcpOption > GetOption(uint8_t kind) const
Get the option specified.
void SetFlags(uint8_t flags)
Set flags of the header.
Definition tcp-header.cc:77
void SetWindowSize(uint16_t windowSize)
Set the window size.
Definition tcp-header.cc:83
const TcpOptionList & GetOptionList() const
Get the list of option in this header.
uint16_t GetWindowSize() const
Get the window size.
uint8_t GetOptionLength() const
Get the total length of appended options.
bool AppendOption(Ptr< const TcpOption > option)
Append an option to the TCP header.
static std::string FlagsToString(uint8_t flags, const std::string &delimiter="|")
Converts an integer into a human readable list of Tcp flags.
Definition tcp-header.cc:28
bool HasOption(uint8_t kind) const
Check if the header has the option specified.
uint16_t GetSourcePort() const
Get the source port.
Definition tcp-header.cc:95
void SetSourcePort(uint16_t port)
Set the source port.
Definition tcp-header.cc:53
void SetAckNumber(SequenceNumber32 ackNumber)
Set the ACK number.
Definition tcp-header.cc:71
uint8_t GetFlags() const
Get the flags.
SequenceNumber32 GetAckNumber() const
Get the ACK number.
@ SACKPERMITTED
SACKPERMITTED.
Definition tcp-option.h:49
@ WINSCALE
WINSCALE.
Definition tcp-option.h:48
std::list< SackBlock > SackList
SACK list definition.
static Time ElapsedTimeFromTsValue(uint32_t echoTime)
Estimate the Time elapsed from a TS echo value.
static uint32_t NowToTsValue()
Return an uint32_t value which represent "now".
virtual void SkbDelivered(TcpTxItem *skb)=0
Update the Rate information after an item is received.
A base class for implementation of a stream socket using TCP.
void AddOptionSack(TcpHeader &header)
Add the SACK option to the header.
int GetSockName(Address &address) const override
Get socket address.
Time m_persistTimeout
Time between sending 1-byte probes.
uint16_t m_maxWinSize
Maximum window size to advertise.
uint8_t m_rcvWindShift
Window shift to apply to outgoing segments.
void SetPaceInitialWindow(bool paceWindow)
Enable or disable pacing of the initial window.
int Bind6() override
Allocate a local IPv6 endpoint for this socket.
void TimeWait()
Move from CLOSING or FIN_WAIT_2 to TIME_WAIT state.
Ptr< TcpCongestionOps > m_congestionControl
Congestion control.
void AddSocketTags(const Ptr< Packet > &p, bool isEct) const
Add Tags for the Socket.
Ptr< TcpTxBuffer > GetTxBuffer() const
Get a pointer to the Tx buffer.
int SetupEndpoint()
Configure the endpoint to a local address.
virtual void LastAckTimeout()
Timeout at LAST_ACK, close the connection.
void ProcessEstablished(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon ESTABLISHED state.
Time m_minRto
minimum value of the Retransmit timeout
uint32_t SendPendingData(bool withAck=false)
Send as much pending data as possible according to the Tx window.
TracedValue< uint32_t > m_advWnd
Advertised Window size.
TracedCallback< Ptr< const Packet >, const TcpHeader &, Ptr< const TcpSocketBase > > m_txTrace
Trace of transmitted packets.
SequenceNumber32 m_recover
Previous highest Tx seqnum for fast recovery (set it to initial seq number)
bool m_recoverActive
Whether "m_recover" has been set/activated It is used to avoid comparing with the old m_recover value...
void DoRetransmit()
Retransmit the first segment marked as lost, without considering available window nor pacing.
bool CheckNoEcn(uint8_t tos) const
Checks if TOS has no ECN codepoints.
virtual void SetNode(Ptr< Node > node)
Set the associated node.
int ShutdownRecv() override
uint8_t m_sndWindShift
Window shift to apply to incoming segments.
Ptr< TcpL4Protocol > m_tcp
the associated TCP L4 protocol
Ptr< TcpSocketState > m_tcb
Congestion control information.
bool GetAllowBroadcast() const override
Query whether broadcast datagram transmissions are allowed.
void UpdateSsThresh(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState slow start threshold.
TracedCallback< Ptr< const Packet >, const TcpHeader &, Ptr< const TcpSocketBase > > m_rxTrace
Trace of received packets.
virtual void SetTcp(Ptr< TcpL4Protocol > tcp)
Set the associated TCP L4 protocol.
void EnterRecovery(uint32_t currentDelivered)
Enter the CA_RECOVERY, and retransmit the head.
Time GetMinRto() const
Get the Minimum RTO.
void ProcessSynSent(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon SYN_SENT.
void ForwardUp(Ptr< Packet > packet, Ipv4Header header, uint16_t port, Ptr< Ipv4Interface > incomingInterface)
Called by the L3 protocol when it received a packet to pass on to TCP.
bool SetAllowBroadcast(bool allowBroadcast) override
Configure whether broadcast datagram transmissions are allowed.
void CancelAllTimers()
Cancel all timer when endpoint is deleted.
Time GetDelAckTimeout() const override
Get the time to delay an ACK.
Ptr< TcpRecoveryOps > m_recoveryOps
Recovery Algorithm.
TracedCallback< uint32_t, uint32_t > m_bytesInFlightTrace
Callback pointer for bytesInFlight trace chaining.
uint32_t GetInitialSSThresh() const override
Get the initial Slow Start Threshold.
void NotifyPacingPerformed()
Notify Pacing.
void SetDelAckTimeout(Time timeout) override
Set the time to delay an ACK.
void CloseAndNotify()
Peacefully close the socket by notifying the upper layer and deallocate end point.
Ptr< TcpRateOps > m_rateOps
Rate operations.
void PeerClose(Ptr< Packet > p, const TcpHeader &tcpHeader)
Received a FIN from peer, notify rx buffer.
int Close() override
Close a socket.
bool m_shutdownSend
Send no longer allowed.
bool IsPacingEnabled() const
Return true if packets in the current window should be paced.
void ProcessOptionWScale(const Ptr< const TcpOption > option)
Read and parse the Window scale option.
bool m_closeOnEmpty
Close socket upon tx buffer emptied.
virtual void ReTxTimeout()
An RTO event happened.
void AddOptionSackPermitted(TcpHeader &header)
Add the SACK PERMITTED option to the header.
TracedValue< Time > m_rto
Retransmit timeout.
uint32_t GetSndBufSize() const override
Get the send buffer size.
virtual void ReceivedData(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Recv of a data, put into buffer, call L7 to get it if necessary.
EventId m_timewaitEvent
TIME_WAIT expiration event: Move this socket to CLOSED state.
Ptr< TcpTxBuffer > m_txBuffer
Tx buffer.
static TypeId GetTypeId()
Get the type ID.
uint32_t m_dupAckCount
Dupack counter.
void SetRetxThresh(uint32_t retxThresh)
Set the retransmission threshold (dup ack threshold for a fast retransmit)
int Send(Ptr< Packet > p, uint32_t flags) override
Send data (or dummy data) to the remote host.
TracedCallback< SequenceNumber32, SequenceNumber32 > m_nextTxSequenceTrace
Callback pointer for next tx sequence chaining.
void UpdateBytesInFlight(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState bytes inflight.
EventId m_delAckEvent
Delayed ACK timeout event.
TracedCallback< Time, Time > m_lastRttTrace
Callback pointer for Last RTT trace chaining.
bool GetTcpNoDelay() const override
Check if Nagle's algorithm is enabled or not.
virtual void SetRtt(Ptr< RttEstimator > rtt)
Set the associated RTT estimator.
TracedCallback< uint32_t, uint32_t > m_cWndTrace
Callback pointer for cWnd trace chaining.
void UpdatePacingRateTrace(DataRate oldValue, DataRate newValue) const
Callback function to hook to TcpSocketState pacing rate.
void SetDataRetries(uint32_t retries) override
Set the number of data transmission retries before giving up.
void AddOptions(TcpHeader &tcpHeader)
Add options to TcpHeader.
TracedCallback< TcpSocketState::EcnState_t, TcpSocketState::EcnState_t > m_ecnStateTrace
Callback pointer for ECN state trace chaining.
void SetSynRetries(uint32_t count) override
Set the number of connection retries before giving up.
void ProcessWait(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon CLOSE_WAIT, FIN_WAIT_1, FIN_WAIT_2.
SequenceNumber32 m_highTxAck
Highest ack sent.
uint32_t GetTxAvailable() const override
Returns the number of bytes which can be sent in a single call to Send.
bool m_timestampEnabled
Timestamp option enabled.
virtual void PersistTimeout()
Send 1 byte probe to get an updated window size.
TracedValue< TcpStates_t > m_state
TCP state.
int SetupCallback()
Common part of the two Bind(), i.e.
Ptr< RttEstimator > m_rtt
Round trip time estimator.
Timer m_pacingTimer
Pacing Event.
EventId m_retxEvent
Retransmission event.
uint32_t m_bytesAckedNotProcessed
Bytes acked, but not processed.
void AddOptionTimestamp(TcpHeader &header)
Add the timestamp option to the header.
virtual uint32_t BytesInFlight() const
Return total bytes in flight.
uint32_t GetSegSize() const override
Get the segment size.
virtual void ProcessAck(const SequenceNumber32 &ackNumber, bool scoreboardUpdated, uint32_t currentDelivered, const SequenceNumber32 &oldHeadSequence, bool receivedData)
Process a received ack.
int SendTo(Ptr< Packet > p, uint32_t flags, const Address &toAddress) override
Send data to a specified peer.
uint32_t m_dataRetries
Number of data retransmission attempts.
double m_msl
Max segment lifetime.
void ProcessLastAck(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon LAST_ACK.
bool m_limitedTx
perform limited transmit
virtual uint32_t SendDataPacket(SequenceNumber32 seq, uint32_t maxSize, bool withAck)
Extract at most maxSize bytes from the TxBuffer at sequence seq, add the TCP header,...
TracedCallback< TcpSocketState::TcpCongState_t, TcpSocketState::TcpCongState_t > m_congStateTrace
Callback pointer for congestion state trace chaining.
void ProcessSynRcvd(Ptr< Packet > packet, const TcpHeader &tcpHeader, const Address &fromAddress, const Address &toAddress)
Received a packet upon SYN_RCVD.
virtual void ReceivedAck(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received an ACK packet.
SocketType GetSocketType() const override
int ShutdownSend() override
TracedValue< SequenceNumber32 > m_ecnCWRSeq
Sequence number of the last sent CWR.
Time GetPersistTimeout() const override
Get the timeout for persistent connection.
void UpdateCwnd(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState congestion window.
void UpdateLastRtt(Time oldValue, Time newValue) const
Callback function to hook to TcpSocketState lastRtt.
TracedCallback< Ptr< const Packet >, const TcpHeader &, const Address &, const Address &, Ptr< const TcpSocketBase > > m_retransmissionTrace
Trace of retransmitted packets.
uint32_t m_delAckCount
Delayed ACK counter.
Ipv4EndPoint * m_endPoint
the IPv4 endpoint
TcpPacketType_t
Tcp Packet Types.
static uint32_t SafeSubtraction(uint32_t a, uint32_t b)
Performs a safe subtraction between a and b (a-b)
virtual void DelAckTimeout()
Action upon delay ACK timeout, i.e.
Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress) override
Read a single packet from the socket and retrieve the sender address.
Time m_cnTimeout
Timeout for connection retry.
Time GetClockGranularity() const
Get the Clock Granularity (used in RTO calcs).
bool m_winScalingEnabled
Window Scale option enabled (RFC 7323)
void UpdateEcnState(TcpSocketState::EcnState_t oldValue, TcpSocketState::EcnState_t newValue) const
Callback function to hook to EcnState state.
EventId m_sendPendingDataEvent
micro-delay event to send pending data
uint32_t m_delAckMaxCount
Number of packet to fire an ACK before delay timeout.
uint8_t CalculateWScale() const
Calculate window scale value based on receive buffer space.
virtual void NewAck(const SequenceNumber32 &seq, bool resetRTO)
Update buffers w.r.t.
bool m_closeNotified
Told app to close socket.
int Listen() override
Listen for incoming connections.
void Destroy6()
Kill this socket by zeroing its attributes (IPv6)
bool IsEct(TcpPacketType_t packetType) const
Checks if a TCP packet should be ECN-capable (ECT) according to the TcpPacketType and ECN mode.
TracedValue< SequenceNumber32 > m_ecnCESeq
Sequence number of the last received Congestion Experienced.
void SetClockGranularity(Time clockGranularity)
Sets the Clock Granularity (used in RTO calcs).
bool IsValidTcpSegment(const SequenceNumber32 seq, const uint32_t tcpHeaderSize, const uint32_t tcpPayloadSize)
Checks whether the given TCP segment is valid or not.
Time m_clockGranularity
Clock Granularity used in RTO calcs.
void DupAck(uint32_t currentDelivered)
Dupack management.
bool m_shutdownRecv
Receive no longer allowed.
void UpdateCongState(TcpSocketState::TcpCongState_t oldValue, TcpSocketState::TcpCongState_t newValue) const
Callback function to hook to TcpSocketState congestion state.
virtual uint32_t Window() const
Return the max possible number of unacked bytes.
Callback< void, Ipv6Address, uint8_t, uint8_t, uint8_t, uint32_t > m_icmpCallback6
ICMPv6 callback.
std::deque< RttHistory > m_history
List of sent packet.
void ProcessOptionSackPermitted(const Ptr< const TcpOption > option)
Read the SACK PERMITTED option.
int Bind() override
Allocate a local IPv4 endpoint for this socket.
virtual uint32_t AvailableWindow() const
Return unfilled portion of window.
TracedValue< SequenceNumber32 > m_highRxMark
Highest seqno received.
void ReadOptions(const TcpHeader &tcpHeader, uint32_t *bytesSacked)
Read TCP options before Ack processing.
virtual uint16_t AdvertisedWindowSize(bool scale=true) const
The amount of Rx window announced to the peer.
void ForwardUp6(Ptr< Packet > packet, Ipv6Header header, uint16_t port, Ptr< Ipv6Interface > incomingInterface)
Called by the L3 protocol when it received a packet to pass on to TCP.
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.
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 INTERNET_EXPORT const char *const TcpCongStateName[TcpSocketState::CA_LAST_STATE]
Literal names of TCP states for use in log messages.
TcpCongState_t
Definition of the Congestion state machine.
@ CA_RECOVERY
CWND was reduced, we are fast-retransmitting.
@ CA_DISORDER
In all the respects it is "Open", but requires a bit more attention.
@ CA_CWR
cWnd was reduced due to some congestion notification event, such as ECN, ICMP source quench,...
@ CA_LOSS
CWND was reduced due to RTO timeout or SACK reneging.
@ CA_OPEN
Normal state, no dubious events.
@ DctcpEcn
ECN functionality as described in RFC 8257.
@ ClassicEcn
ECN functionality as described in RFC 3168.
EcnState_t
Definition of the Ecn state machine.
@ ECN_CWR_SENT
Sender has reduced the congestion window, and sent a packet with CWR bit set in TCP header.
@ ECN_DISABLED
ECN disabled traffic.
@ ECN_ECE_RCVD
Last ACK received had ECE bit set in TCP header.
@ ECN_IDLE
ECN is enabled but currently there is no action pertaining to ECE or CWR to be taken.
@ ECN_CE_RCVD
Last packet received had CE bit set in IP header.
@ ECN_SENDING_ECE
Receiver sends an ACK with ECE bit set in TCP header.
static INTERNET_EXPORT const char *const EcnStateName[TcpSocketState::ECN_CWR_SENT+1]
Literal names of ECN states for use in log messages.
Item that encloses the application packet and some flags for it.
Definition tcp-tx-item.h:22
Ptr< Packet > GetPacketCopy() const
Get a copy of the Packet underlying this item.
bool IsRetrans() const
Is the item retransmitted?
Simulation virtual time values and global simulation resolution.
Definition nstime.h: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:511
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
AttributeValue implementation for Time.
Definition nstime.h:1432
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:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
uint16_t port
Definition dsdv-manet.cc:33
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeAccessor > MakeCallbackAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition callback.h:818
Ptr< const AttributeChecker > MakeCallbackChecker()
Definition callback.cc:77
Ptr< const AttributeChecker > MakeDoubleChecker()
Definition double.h:82
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition double.h:32
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition enum.h:221
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition pointer.h:248
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:269
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1433
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1453
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
Callback< R, Args... > MakeNullCallback()
Definition callback.h:727
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition abort.h:133
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#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:1369
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
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.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition enum.h:179
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
ns3::Time timeout