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 
66 namespace ns3 {
67 
68 NS_LOG_COMPONENT_DEFINE ("TcpSocketBase");
69 
70 NS_OBJECT_ENSURE_REGISTERED (TcpSocketBase);
71 
72 TypeId
74 {
75  static TypeId tid = TypeId ("ns3::TcpSocketBase")
76  .SetParent<TcpSocket> ()
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.",
94  CallbackValue (),
97  .AddAttribute ("IcmpCallback6", "Callback invoked whenever an icmpv6 error is received on this socket.",
98  CallbackValue (),
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
119  MakeTimeChecker ())
120  .AddAttribute ("ClockGranularity",
121  "Clock Granularity used in RTO calculations",
122  TimeValue (MilliSeconds (1)), // RFC6298 suggest to use fine clock granularity
125  MakeTimeChecker ())
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 
244 TypeId
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 
304  ok = m_tcb->TraceConnectWithoutContext ("RTT",
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  {
387  m_congestionControl->Init (m_tcb);
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 
438  ok = m_tcb->TraceConnectWithoutContext ("RTT",
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;
469  CancelAllTimers ();
470 }
471 
472 /* Associate a node with this TCP socket */
473 void
475 {
476  m_node = node;
477 }
478 
479 /* Associate the L4 protocol (e.g. mux/demux) with this socket */
480 void
482 {
483  m_tcp = tcp;
484 }
485 
486 /* Set an RTT estimator with this socket */
487 void
489 {
490  m_rtt = rtt;
491 }
492 
493 /* Inherit from Socket class: Returns error code */
495 TcpSocketBase::GetErrno (void) const
496 {
497  return m_errno;
498 }
499 
500 /* Inherit from Socket class: Returns socket type, NS3_SOCK_STREAM */
502 TcpSocketBase::GetSocketType (void) const
503 {
504  return NS3_SOCK_STREAM;
505 }
506 
507 /* Inherit from Socket class: Returns associated node */
508 Ptr<Node>
510 {
511  return m_node;
512 }
513 
514 /* Inherit from Socket class: Bind socket to an end-point in TcpL4Protocol */
515 int
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 
531 int
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 */
548 int
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 
620 void
622 {
623  NS_ABORT_MSG_UNLESS ( (m_state == CLOSED) || threshold == m_tcb->m_initialSsThresh,
624  "TcpSocketBase::SetSSThresh() cannot change initial ssThresh after connection started.");
625 
626  m_tcb->m_initialSsThresh = threshold;
627 }
628 
629 uint32_t
631 {
632  return m_tcb->m_initialSsThresh;
633 }
634 
635 void
637 {
639  "TcpSocketBase::SetInitialCwnd() cannot change initial cwnd after connection started.");
640 
641  m_tcb->m_initialCWnd = cwnd;
642 }
643 
644 uint32_t
646 {
647  return m_tcb->m_initialCWnd;
648 }
649 
650 /* Inherit from Socket class: Initiate connection to a remote address:port */
651 int
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 */
727 int
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) */
745 int
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 */
773 int
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  {
785  if (m_state == ESTABLISHED || m_state == CLOSE_WAIT)
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");
798  m_state = LAST_ACK;
799  }
800  }
801  }
802 
803  return 0;
804 }
805 
806 /* Inherit from Socket class: Signal a termination of receive */
807 int
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 */
817 int
818 TcpSocketBase::Send (Ptr<Packet> p, uint32_t flags)
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 */
862 int
863 TcpSocketBase::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 */
871 TcpSocketBase::Recv (uint32_t maxSize, uint32_t flags)
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 */
885 TcpSocketBase::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 */
909 uint32_t
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 */
917 uint32_t
919 {
920  NS_LOG_FUNCTION (this);
921  return m_tcb->m_rxBuffer->Available ();
922 }
923 
924 /* Inherit from Socket class: Return local address:port */
925 int
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 
946 int
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  {
960  m_endPoint->GetPeerPort ());
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 */
976 void
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. */
995 int
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 */
1021 int
1023 {
1024  NS_LOG_FUNCTION (this);
1025 
1026  // A new connection is allowed only if this socket does not have a connection
1027  if (m_state == CLOSED || m_state == LISTEN || m_state == SYN_SENT || m_state == LAST_ACK || m_state == CLOSE_WAIT)
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. */
1053 int
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");
1064  m_state = 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 */
1095 void
1097 {
1098  NS_LOG_FUNCTION (this);
1099 
1100  if (!m_closeNotified)
1101  {
1102  NotifyNormalClose ();
1103  m_closeNotified = true;
1104  }
1105  if (m_lastAckEvent.IsRunning ())
1106  {
1108  }
1109  NS_LOG_DEBUG (TcpStateName[m_state] << " -> CLOSED");
1110  m_state = CLOSED;
1111  DeallocateEndPoint ();
1112 }
1113 
1114 
1115 /* Tell if a sequence number range is out side the range that my rx buffer can
1116  accpet */
1117 bool
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() */
1137 void
1139  Ptr<Ipv4Interface> incomingInterface)
1140 {
1141  NS_LOG_LOGIC ("Socket " << this << " forward up " <<
1142  m_endPoint->GetPeerAddress () <<
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 (),
1149  m_endPoint->GetLocalPort ());
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");
1163  NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
1164  m_ecnCESeq = tcpHeader.GetSequenceNumber ();
1167  }
1169  {
1171  }
1172 
1173  DoForwardUp (packet, fromAddress, toAddress);
1174 }
1175 
1176 void
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");
1202  NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
1203  m_ecnCESeq = tcpHeader.GetSequenceNumber ();
1206  }
1207  else if (header.GetEcn() != Ipv6Header::ECN_NotECT)
1208  {
1210  }
1211 
1212  DoForwardUp (packet, fromAddress, toAddress);
1213 }
1214 
1215 void
1216 TcpSocketBase::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 
1229 void
1230 TcpSocketBase::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 
1243 bool
1244 TcpSocketBase::IsValidTcpSegment (const SequenceNumber32 seq, const uint32_t tcpHeaderSize,
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 
1267 void
1268 TcpSocketBase::DoForwardUp (Ptr<Packet> packet, const Address &fromAddress,
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));
1350  if (m_timestampEnabled)
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 ());
1378  m_retxEvent.Cancel ();
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. */
1449 void
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 
1527 bool
1529 {
1530  NS_LOG_FUNCTION (this << static_cast<uint32_t> (kind));
1531 
1532  switch (kind)
1533  {
1534  case TcpOption::TS:
1535  return m_timestampEnabled;
1536  case TcpOption::WINSCALE:
1537  return m_winScalingEnabled;
1539  case TcpOption::SACK:
1540  return m_sackEnabled;
1541  default:
1542  break;
1543  }
1544  return false;
1545 }
1546 
1547 void
1548 TcpSocketBase::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
1572 void
1573 TcpSocketBase::EnterCwr (uint32_t currentDelivered)
1574 {
1575  NS_LOG_FUNCTION (this << currentDelivered);
1576  m_tcb->m_ssThresh = m_congestionControl->GetSsThresh (m_tcb, BytesInFlight ());
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 
1599 void
1600 TcpSocketBase::EnterRecovery (uint32_t currentDelivered)
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 
1631  m_congestionControl->CongestionStateSet (m_tcb, TcpSocketState::CA_RECOVERY);
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
1637  uint32_t bytesInFlight = m_sackEnabled ? BytesInFlight () : BytesInFlight () + m_tcb->m_segmentSize;
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 
1657 void
1658 TcpSocketBase::DupAck (uint32_t currentDelivered)
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 
1687  m_congestionControl->CongestionStateSet (m_tcb, TcpSocketState::CA_DISORDER);
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 */
1764 void
1766 {
1767  NS_LOG_FUNCTION (this << tcpHeader);
1768 
1769  NS_ASSERT (0 != (tcpHeader.GetFlags () & TcpHeader::ACK));
1770  NS_ASSERT (m_tcb->m_segmentSize > 0);
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  {
1803  m_tcb->m_isRetransDataAcked = true;
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  {
1823  m_tcb->m_cWnd = m_tcb->m_ssThresh.Get ();
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;
1835  NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_RCVD");
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 
1880 void
1881 TcpSocketBase::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 <<
1918  " in state: " << TcpSocketState::TcpCongStateName[m_tcb->m_congState] <<
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;
1957  m_bytesAckedNotProcessed += 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
2011  m_tcb->m_cWndInfl = SafeSubtraction (m_tcb->m_cWndInfl, bytesAcked);
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 
2020  if (m_isFirstPartialAck)
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);
2152  m_tcb->m_cWnd = m_tcb->m_ssThresh.Get ();
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
2176  UpdatePacingRate ();
2177 }
2178 
2179 /* Received a packet upon LISTEN state. */
2180 void
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 */
2210 void
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);
2223  m_state = ESTABLISHED;
2224  m_connected = true;
2225  m_retxEvent.Cancel ();
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);
2262  m_state = ESTABLISHED;
2263  m_connected = true;
2264  m_retxEvent.Cancel ();
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
2269  UpdatePacingRate ();
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 */
2304 void
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);
2323  m_state = ESTABLISHED;
2324  m_connected = true;
2325  m_retxEvent.Cancel ();
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
2344  UpdatePacingRate ();
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;
2375  m_retxEvent.Cancel ();
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 */
2415 void
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");
2434  m_state = 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 */
2487 void
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 */
2519 void
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. */
2555 void
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. */
2592 void
2594 {
2597 
2598  // Move the state to CLOSE_WAIT
2599  NS_LOG_DEBUG (TcpStateName[m_state] << " -> CLOSE_WAIT");
2600  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");
2611  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. */
2633 void
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. */
2649 void
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 */
2664 void
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  {
2695  header.SetSourcePort (m_endPoint->GetLocalPort ());
2697  }
2698  else
2699  {
2700  header.SetSourcePort (m_endPoint6->GetLocalPort ());
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  {
2714  if (m_winScalingEnabled)
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;
2730  DeallocateEndPoint ();
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
2755  m_delAckEvent.Cancel ();
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. */
2792 void
2794 {
2795  NS_LOG_FUNCTION (this);
2797  NotifyErrorClose ();
2798  DeallocateEndPoint ();
2799 }
2800 
2801 /* Deallocate the end point and cancel all the timers */
2802 void
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. */
2824 int
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 
2854 int
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. */
2887 void
2888 TcpSocketBase::CompleteFork ([[maybe_unused]] Ptr<Packet> p, const TcpHeader& h,
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 
2939 void
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 
2953 void
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 */
3035 uint32_t
3036 TcpSocketBase::SendDataPacket (SequenceNumber32 seq, uint32_t maxSize, bool withAck)
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  {
3076  m_delAckEvent.Cancel ();
3077  m_delAckCount = 0;
3078  }
3079 
3080  if (m_tcb->m_ecnState == TcpSocketState::ECN_ECE_RCVD && m_ecnEchoSeq.Get() > m_ecnCWRSeq.Get () && !isRetransmission)
3081  {
3082  NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CWR_SENT");
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");
3097  m_state = 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  {
3111  header.SetSourcePort (m_endPoint->GetLocalPort ());
3113  }
3114  else
3115  {
3116  header.SetSourcePort (m_endPoint6->GetLocalPort ());
3118  }
3119  header.SetWindowSize (AdvertisedWindowSize ());
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 
3170 void
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
3196 uint32_t
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;
3244  bool enableRule3 = m_sackEnabled && m_tcb->m_congState == TcpSocketState::CA_RECOVERY;
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 
3359 uint32_t
3361 {
3362  return m_tcb->m_highTxMark - m_txBuffer->HeadSequence ();
3363 }
3364 
3365 uint32_t
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 
3377 uint32_t
3379 {
3380  return std::min (m_rWnd.Get (), m_tcb->m_cWnd.Get ());
3381 }
3382 
3383 uint32_t
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 
3391 uint16_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
3430 void
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  {
3492  m_delAckEvent.Cancel ();
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 " <<
3517  (Simulator::Now () + Simulator::GetDelayLeft (m_delAckEvent)).GetSeconds ());
3518  }
3519  }
3520 }
3521 
3522 void
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
3579 void
3580 TcpSocketBase::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 ());
3591  m_retxEvent.Cancel ();
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 ());
3618  m_retxEvent.Cancel ();
3619  }
3620 }
3621 
3622 // Retransmit timeout
3623 void
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");
3669  NotifyErrorClose ();
3670  DeallocateEndPoint ();
3671  return;
3672  }
3673  else
3674  {
3675  --m_dataRetrCount;
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 
3735  m_pacingTimer.Cancel ();
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 
3752 void
3754 {
3755  m_delAckCount = 0;
3758  {
3761  }
3762  else
3763  {
3765  }
3766 }
3767 
3768 void
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");
3779  NotifyErrorClose ();
3780  DeallocateEndPoint ();
3781  return;
3782  }
3783  m_dataRetrCount--;
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
3794 void
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 ());
3808  tcpHeader.SetDestinationPort (m_endPoint->GetPeerPort ());
3809  }
3810  else
3811  {
3812  tcpHeader.SetSourcePort (m_endPoint6->GetLocalPort ());
3813  tcpHeader.SetDestinationPort (m_endPoint6->GetPeerPort ());
3814  }
3815  AddOptions (tcpHeader);
3816  //Send a packet tag for setting ECT bits in IP header
3818  {
3819  SocketIpTosTag ipTosTag;
3820  ipTosTag.SetTos (MarkEcnCodePoint (0, m_tcb->m_ectCodePoint));
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 
3846 void
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 
3881 void
3883 {
3884  m_retxEvent.Cancel ();
3886  m_delAckEvent.Cancel ();
3890  m_pacingTimer.Cancel ();
3891 }
3892 
3893 /* Move TCP to Time_Wait state and schedule a transition to Closed state */
3894 void
3896 {
3897  NS_LOG_DEBUG (TcpStateName[m_state] << " -> TIME_WAIT");
3898  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.
3905  NotifyNormalClose ();
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 
3916 void
3918 {
3919  NS_LOG_FUNCTION (this << size);
3920  m_txBuffer->SetMaxBufferSize (size);
3921 }
3922 
3923 uint32_t
3925 {
3926  return m_txBuffer->MaxBufferSize ();
3927 }
3928 
3929 void
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 
3955 uint32_t
3957 {
3958  return m_tcb->m_rxBuffer->MaxBufferSize ();
3959 }
3960 
3961 void
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 
3971 uint32_t
3973 {
3974  return m_tcb->m_segmentSize;
3975 }
3976 
3977 void
3979 {
3980  NS_LOG_FUNCTION (this << timeout);
3981  m_cnTimeout = timeout;
3982 }
3983 
3984 Time
3986 {
3987  return m_cnTimeout;
3988 }
3989 
3990 void
3992 {
3993  NS_LOG_FUNCTION (this << count);
3994  m_synRetries = count;
3995 }
3996 
3997 uint32_t
3999 {
4000  return m_synRetries;
4001 }
4002 
4003 void
4005 {
4006  NS_LOG_FUNCTION (this << retries);
4007  m_dataRetries = retries;
4008 }
4009 
4010 uint32_t
4012 {
4013  NS_LOG_FUNCTION (this);
4014  return m_dataRetries;
4015 }
4016 
4017 void
4019 {
4020  NS_LOG_FUNCTION (this << timeout);
4022 }
4023 
4024 Time
4026 {
4027  return m_delAckTimeout;
4028 }
4029 
4030 void
4032 {
4033  NS_LOG_FUNCTION (this << count);
4034  m_delAckMaxCount = count;
4035 }
4036 
4037 uint32_t
4039 {
4040  return m_delAckMaxCount;
4041 }
4042 
4043 void
4045 {
4046  NS_LOG_FUNCTION (this << noDelay);
4047  m_noDelay = noDelay;
4048 }
4049 
4050 bool
4052 {
4053  return m_noDelay;
4054 }
4055 
4056 void
4058 {
4059  NS_LOG_FUNCTION (this << timeout);
4061 }
4062 
4063 Time
4065 {
4066  return m_persistTimeout;
4067 }
4068 
4069 bool
4071 {
4072  // Broadcast is not implemented. Return true only if allowBroadcast==false
4073  return (!allowBroadcast);
4074 }
4075 
4076 bool
4078 {
4079  return false;
4080 }
4081 
4082 void
4084 {
4085  NS_LOG_FUNCTION (this << header);
4086 
4087  if (m_timestampEnabled)
4088  {
4089  AddOptionTimestamp (header);
4090  }
4091 }
4092 
4093 void
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 
4114 uint8_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 
4138 void
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 
4158 uint32_t
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 
4167 void
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 
4178 void
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 
4189 void
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 
4218 void
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 
4246 void
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 
4305 void
4307 {
4308  NS_LOG_FUNCTION (this << minRto);
4309  m_minRto = minRto;
4310 }
4311 
4312 Time
4314 {
4315  return m_minRto;
4316 }
4317 
4318 void
4320 {
4321  NS_LOG_FUNCTION (this << clockGranularity);
4322  m_clockGranularity = clockGranularity;
4323 }
4324 
4325 Time
4327 {
4328  return m_clockGranularity;
4329 }
4330 
4333 {
4334  return m_txBuffer;
4335 }
4336 
4339 {
4340  return m_tcb->m_rxBuffer;
4341 }
4342 
4343 void
4344 TcpSocketBase::SetRetxThresh (uint32_t retxThresh)
4345 {
4346  m_retxThresh = retxThresh;
4347  m_txBuffer->SetDupAckThresh (retxThresh);
4348 }
4349 
4350 void
4352 {
4353  m_pacingRateTrace (oldValue, newValue);
4354 }
4355 
4356 void
4357 TcpSocketBase::UpdateCwnd (uint32_t oldValue, uint32_t newValue)
4358 {
4359  m_cWndTrace (oldValue, newValue);
4360 }
4361 
4362 void
4363 TcpSocketBase::UpdateCwndInfl (uint32_t oldValue, uint32_t newValue)
4364 {
4365  m_cWndInflTrace (oldValue, newValue);
4366 }
4367 
4368 void
4369 TcpSocketBase::UpdateSsThresh (uint32_t oldValue, uint32_t newValue)
4370 {
4371  m_ssThTrace (oldValue, newValue);
4372 }
4373 
4374 void
4377 {
4378  m_congStateTrace (oldValue, newValue);
4379 }
4380 
4381  void
4383  TcpSocketState::EcnState_t newValue)
4384 {
4385  m_ecnStateTrace (oldValue, newValue);
4386 }
4387 
4388 void
4390  SequenceNumber32 newValue)
4391 
4392 {
4393  m_nextTxSequenceTrace (oldValue, newValue);
4394 }
4395 
4396 void
4398 {
4399  m_highTxMarkTrace (oldValue, newValue);
4400 }
4401 
4402 void
4403 TcpSocketBase::UpdateBytesInFlight (uint32_t oldValue, uint32_t newValue)
4404 {
4405  m_bytesInFlightTrace (oldValue, newValue);
4406 }
4407 
4408 void
4409 TcpSocketBase::UpdateRtt (Time oldValue, Time newValue)
4410 {
4411  m_lastRttTrace (oldValue, newValue);
4412 }
4413 
4414 void
4416 {
4417  NS_LOG_FUNCTION (this << algo);
4418  m_congestionControl = algo;
4419  m_congestionControl->Init (m_tcb);
4420 }
4421 
4422 void
4424 {
4425  NS_LOG_FUNCTION (this << recovery);
4426  m_recoveryOps = recovery;
4427 }
4428 
4431 {
4432  return CopyObject<TcpSocketBase> (this);
4433 }
4434 
4435 uint32_t
4436 TcpSocketBase::SafeSubtraction (uint32_t a, uint32_t b)
4437 {
4438  if (a > b)
4439  {
4440  return a-b;
4441  }
4442 
4443  return 0;
4444 }
4445 
4446 void
4448 {
4449  NS_LOG_FUNCTION (this);
4450  NS_LOG_INFO ("Performing Pacing");
4452 }
4453 
4454 bool
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 
4476 void
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 
4523 void
4525 {
4526  NS_LOG_FUNCTION (this << pacing);
4527  m_tcb->m_pacing = pacing;
4528 }
4529 
4530 void
4532 {
4533  NS_LOG_FUNCTION (this << paceWindow);
4534  m_tcb->m_paceInitialWindow = paceWindow;
4535 }
4536 
4537 void
4539 {
4540  NS_LOG_FUNCTION (this << useEcn);
4541  m_tcb->m_useEcn = useEcn;
4542 }
4543 
4544 uint32_t
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
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:470
friend Ptr< T > CopyObject(Ptr< T > object)
Copy an Object.
Definition: object.h:541
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 void SkbSent(TcpTxItem *skb, bool isStartOfTransmission)=0
Put the rate information inside the sent skb.
virtual const TcpRateConnection & GetConnectionRate()=0
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 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 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)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: boolean.h:85
Ptr< const AttributeAccessor > MakeCallbackAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: callback.h:1982
Ptr< const AttributeChecker > MakeCallbackChecker(void)
Definition: callback.cc:74
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: double.h:42
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: enum.h:205
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: pointer.h:227
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: nstime.h:1309
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: uinteger.h: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 > 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
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:522
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
ns3::Time timeout
uint64_t m_delivered
The total amount of data in bytes delivered so far.
Definition: tcp-rate-ops.h:164