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