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