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