A Discrete-Event Network Simulator
API
tcp-socket-base.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007 Georgia Tech Research Corporation
3  * Copyright (c) 2010 Adrian Sai-wah Tam
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
19  */
20 
21 #define NS_LOG_APPEND_CONTEXT \
22  if (m_node) \
23  { \
24  std::clog << " [node " << m_node->GetId() << "] "; \
25  }
26 
27 #include "tcp-socket-base.h"
28 
29 #include "ipv4-end-point.h"
30 #include "ipv6-end-point.h"
31 #include "ipv6-l3-protocol.h"
32 #include "rtt-estimator.h"
33 #include "tcp-congestion-ops.h"
34 #include "tcp-header.h"
35 #include "tcp-l4-protocol.h"
37 #include "tcp-option-sack.h"
38 #include "tcp-option-ts.h"
39 #include "tcp-option-winscale.h"
40 #include "tcp-recovery-ops.h"
41 #include "tcp-rx-buffer.h"
42 #include "tcp-tx-buffer.h"
43 
44 #include "ns3/abort.h"
45 #include "ns3/data-rate.h"
46 #include "ns3/double.h"
47 #include "ns3/inet-socket-address.h"
48 #include "ns3/inet6-socket-address.h"
49 #include "ns3/ipv4-interface-address.h"
50 #include "ns3/ipv4-route.h"
51 #include "ns3/ipv4-routing-protocol.h"
52 #include "ns3/ipv4.h"
53 #include "ns3/ipv6-route.h"
54 #include "ns3/ipv6-routing-protocol.h"
55 #include "ns3/ipv6.h"
56 #include "ns3/log.h"
57 #include "ns3/node.h"
58 #include "ns3/object.h"
59 #include "ns3/packet.h"
60 #include "ns3/pointer.h"
61 #include "ns3/simulation-singleton.h"
62 #include "ns3/simulator.h"
63 #include "ns3/tcp-rate-ops.h"
64 #include "ns3/trace-source-accessor.h"
65 #include "ns3/uinteger.h"
66 
67 #include <algorithm>
68 #include <math.h>
69 
70 namespace ns3
71 {
72 
73 NS_LOG_COMPONENT_DEFINE("TcpSocketBase");
74 
75 NS_OBJECT_ENSURE_REGISTERED(TcpSocketBase);
76 
77 TypeId
79 {
80  static TypeId tid =
81  TypeId("ns3::TcpSocketBase")
83  .SetGroupName("Internet")
84  .AddConstructor<TcpSocketBase>()
85  // .AddAttribute ("TcpState", "State in TCP state machine",
86  // TypeId::ATTR_GET,
87  // EnumValue (CLOSED),
88  // MakeEnumAccessor (&TcpSocketBase::m_state),
89  // MakeEnumChecker (CLOSED, "Closed"))
90  .AddAttribute("MaxSegLifetime",
91  "Maximum segment lifetime in seconds, use for TIME_WAIT state transition "
92  "to CLOSED state",
93  DoubleValue(120), /* RFC793 says MSL=2 minutes*/
95  MakeDoubleChecker<double>(0))
96  .AddAttribute("MaxWindowSize",
97  "Max size of advertised window",
98  UintegerValue(65535),
100  MakeUintegerChecker<uint16_t>())
101  .AddAttribute("IcmpCallback",
102  "Callback invoked whenever an icmp error is received on this socket.",
103  CallbackValue(),
106  .AddAttribute("IcmpCallback6",
107  "Callback invoked whenever an icmpv6 error is received on this socket.",
108  CallbackValue(),
111  .AddAttribute("WindowScaling",
112  "Enable or disable Window Scaling option",
113  BooleanValue(true),
116  .AddAttribute("Sack",
117  "Enable or disable Sack option",
118  BooleanValue(true),
121  .AddAttribute("Timestamp",
122  "Enable or disable Timestamp option",
123  BooleanValue(true),
126  .AddAttribute(
127  "MinRto",
128  "Minimum retransmit timeout value",
129  TimeValue(Seconds(1.0)), // RFC 6298 says min RTO=1 sec, but Linux uses 200ms.
130  // See http://www.postel.org/pipermail/end2end-interest/2004-November/004402.html
132  MakeTimeChecker())
133  .AddAttribute(
134  "ClockGranularity",
135  "Clock Granularity used in RTO calculations",
136  TimeValue(MilliSeconds(1)), // RFC6298 suggest to use fine clock granularity
139  MakeTimeChecker())
140  .AddAttribute("TxBuffer",
141  "TCP Tx buffer",
142  PointerValue(),
144  MakePointerChecker<TcpTxBuffer>())
145  .AddAttribute("RxBuffer",
146  "TCP Rx buffer",
147  PointerValue(),
149  MakePointerChecker<TcpRxBuffer>())
150  .AddAttribute("CongestionOps",
151  "Pointer to TcpCongestionOps object",
152  PointerValue(),
154  MakePointerChecker<TcpCongestionOps>())
155  .AddAttribute(
156  "ReTxThreshold",
157  "Threshold for fast retransmit",
158  UintegerValue(3),
160  MakeUintegerChecker<uint32_t>())
161  .AddAttribute("LimitedTransmit",
162  "Enable limited transmit",
163  BooleanValue(true),
166  .AddAttribute("UseEcn",
167  "Parameter to set ECN functionality",
171  "Off",
173  "On",
175  "AcceptOnly"))
176  .AddTraceSource("RTO",
177  "Retransmission timeout",
179  "ns3::TracedValueCallback::Time")
180  .AddTraceSource("RTT",
181  "Last RTT sample",
183  "ns3::TracedValueCallback::Time")
184  .AddTraceSource("NextTxSequence",
185  "Next sequence number to send (SND.NXT)",
187  "ns3::SequenceNumber32TracedValueCallback")
188  .AddTraceSource("HighestSequence",
189  "Highest sequence number ever sent in socket's life time",
191  "ns3::TracedValueCallback::SequenceNumber32")
192  .AddTraceSource("State",
193  "TCP state",
195  "ns3::TcpStatesTracedValueCallback")
196  .AddTraceSource("CongState",
197  "TCP Congestion machine state",
199  "ns3::TcpSocketState::TcpCongStatesTracedValueCallback")
200  .AddTraceSource("EcnState",
201  "Trace ECN state change of socket",
203  "ns3::TcpSocketState::EcnStatesTracedValueCallback")
204  .AddTraceSource("AdvWND",
205  "Advertised Window Size",
207  "ns3::TracedValueCallback::Uint32")
208  .AddTraceSource("RWND",
209  "Remote side's flow control window",
211  "ns3::TracedValueCallback::Uint32")
212  .AddTraceSource("BytesInFlight",
213  "Socket estimation of bytes in flight",
215  "ns3::TracedValueCallback::Uint32")
216  .AddTraceSource("HighestRxSequence",
217  "Highest sequence number received from peer",
219  "ns3::TracedValueCallback::SequenceNumber32")
220  .AddTraceSource("HighestRxAck",
221  "Highest ack received from peer",
223  "ns3::TracedValueCallback::SequenceNumber32")
224  .AddTraceSource("PacingRate",
225  "The current TCP pacing rate",
227  "ns3::TracedValueCallback::DataRate")
228  .AddTraceSource("CongestionWindow",
229  "The TCP connection's congestion window",
231  "ns3::TracedValueCallback::Uint32")
232  .AddTraceSource("CongestionWindowInflated",
233  "The TCP connection's congestion window inflates as in older RFC",
235  "ns3::TracedValueCallback::Uint32")
236  .AddTraceSource("SlowStartThreshold",
237  "TCP slow start threshold (bytes)",
239  "ns3::TracedValueCallback::Uint32")
240  .AddTraceSource("Tx",
241  "Send tcp packet to IP protocol",
243  "ns3::TcpSocketBase::TcpTxRxTracedCallback")
244  .AddTraceSource("Rx",
245  "Receive tcp packet from IP protocol",
247  "ns3::TcpSocketBase::TcpTxRxTracedCallback")
248  .AddTraceSource("EcnEchoSeq",
249  "Sequence of last received ECN Echo",
251  "ns3::SequenceNumber32TracedValueCallback")
252  .AddTraceSource("EcnCeSeq",
253  "Sequence of last received CE",
255  "ns3::SequenceNumber32TracedValueCallback")
256  .AddTraceSource("EcnCwrSeq",
257  "Sequence of last received CWR",
259  "ns3::SequenceNumber32TracedValueCallback");
260  return tid;
261 }
262 
263 TypeId
265 {
266  return TcpSocketBase::GetTypeId();
267 }
268 
270  : TcpSocket()
271 {
272  NS_LOG_FUNCTION(this);
273  m_txBuffer = CreateObject<TcpTxBuffer>();
274  m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
275  m_tcb = CreateObject<TcpSocketState>();
276  m_rateOps = CreateObject<TcpRateLinux>();
277 
278  m_tcb->m_rxBuffer = CreateObject<TcpRxBuffer>();
279 
282 
284 
285  bool ok;
286 
288  "PacingRate",
290  NS_ASSERT(ok == true);
291 
292  ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
294  NS_ASSERT(ok == true);
295 
296  ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
298  NS_ASSERT(ok == true);
299 
300  ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
302  NS_ASSERT(ok == true);
303 
304  ok = m_tcb->TraceConnectWithoutContext("CongState",
306  NS_ASSERT(ok == true);
307 
308  ok = m_tcb->TraceConnectWithoutContext("EcnState",
310  NS_ASSERT(ok == true);
311 
312  ok =
313  m_tcb->TraceConnectWithoutContext("NextTxSequence",
315  NS_ASSERT(ok == true);
316 
317  ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
319  NS_ASSERT(ok == true);
320 
321  ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
323  NS_ASSERT(ok == true);
324 
326  NS_ASSERT(ok == true);
327 }
328 
330  : TcpSocket(sock),
331  // copy object::m_tid and socket::callbacks
332  m_dupAckCount(sock.m_dupAckCount),
333  m_delAckCount(0),
334  m_delAckMaxCount(sock.m_delAckMaxCount),
335  m_noDelay(sock.m_noDelay),
336  m_synCount(sock.m_synCount),
337  m_synRetries(sock.m_synRetries),
338  m_dataRetrCount(sock.m_dataRetrCount),
339  m_dataRetries(sock.m_dataRetries),
340  m_rto(sock.m_rto),
341  m_minRto(sock.m_minRto),
342  m_clockGranularity(sock.m_clockGranularity),
343  m_delAckTimeout(sock.m_delAckTimeout),
344  m_persistTimeout(sock.m_persistTimeout),
345  m_cnTimeout(sock.m_cnTimeout),
346  m_endPoint(nullptr),
347  m_endPoint6(nullptr),
348  m_node(sock.m_node),
349  m_tcp(sock.m_tcp),
350  m_state(sock.m_state),
351  m_errno(sock.m_errno),
352  m_closeNotified(sock.m_closeNotified),
353  m_closeOnEmpty(sock.m_closeOnEmpty),
354  m_shutdownSend(sock.m_shutdownSend),
355  m_shutdownRecv(sock.m_shutdownRecv),
356  m_connected(sock.m_connected),
357  m_msl(sock.m_msl),
358  m_maxWinSize(sock.m_maxWinSize),
359  m_bytesAckedNotProcessed(sock.m_bytesAckedNotProcessed),
360  m_rWnd(sock.m_rWnd),
361  m_highRxMark(sock.m_highRxMark),
362  m_highRxAckMark(sock.m_highRxAckMark),
363  m_sackEnabled(sock.m_sackEnabled),
364  m_winScalingEnabled(sock.m_winScalingEnabled),
365  m_rcvWindShift(sock.m_rcvWindShift),
366  m_sndWindShift(sock.m_sndWindShift),
367  m_timestampEnabled(sock.m_timestampEnabled),
368  m_timestampToEcho(sock.m_timestampToEcho),
369  m_recover(sock.m_recover),
370  m_recoverActive(sock.m_recoverActive),
371  m_retxThresh(sock.m_retxThresh),
372  m_limitedTx(sock.m_limitedTx),
373  m_isFirstPartialAck(sock.m_isFirstPartialAck),
374  m_txTrace(sock.m_txTrace),
375  m_rxTrace(sock.m_rxTrace),
376  m_pacingTimer(Timer::CANCEL_ON_DESTROY),
377  m_ecnEchoSeq(sock.m_ecnEchoSeq),
378  m_ecnCESeq(sock.m_ecnCESeq),
379  m_ecnCWRSeq(sock.m_ecnCWRSeq)
380 {
381  NS_LOG_FUNCTION(this);
382  NS_LOG_LOGIC("Invoked the copy constructor");
383  // Copy the rtt estimator if it is set
384  if (sock.m_rtt)
385  {
386  m_rtt = sock.m_rtt->Copy();
387  }
388  // Reset all callbacks to null
389  Callback<void, Ptr<Socket>> vPS = MakeNullCallback<void, Ptr<Socket>>();
390  Callback<void, Ptr<Socket>, const Address&> vPSA =
391  MakeNullCallback<void, Ptr<Socket>, const Address&>();
392  Callback<void, Ptr<Socket>, uint32_t> vPSUI = MakeNullCallback<void, Ptr<Socket>, uint32_t>();
393  SetConnectCallback(vPS, vPS);
394  SetDataSentCallback(vPSUI);
395  SetSendCallback(vPSUI);
396  SetRecvCallback(vPS);
398  m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
399  m_tcb = CopyObject(sock.m_tcb);
401 
404 
405  if (sock.m_congestionControl)
406  {
408  m_congestionControl->Init(m_tcb);
409  }
410 
411  if (sock.m_recoveryOps)
412  {
413  m_recoveryOps = sock.m_recoveryOps->Fork();
414  }
415 
416  m_rateOps = CreateObject<TcpRateLinux>();
418  {
420  }
421 
422  bool ok;
423 
425  "PacingRate",
427 
428  ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
430  NS_ASSERT(ok == true);
431 
432  ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
434  NS_ASSERT(ok == true);
435 
436  ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
438  NS_ASSERT(ok == true);
439 
440  ok = m_tcb->TraceConnectWithoutContext("CongState",
442  NS_ASSERT(ok == true);
443 
444  ok = m_tcb->TraceConnectWithoutContext("EcnState",
446  NS_ASSERT(ok == true);
447 
448  ok =
449  m_tcb->TraceConnectWithoutContext("NextTxSequence",
451  NS_ASSERT(ok == true);
452 
453  ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
455  NS_ASSERT(ok == true);
456 
457  ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
459  NS_ASSERT(ok == true);
460 
462  NS_ASSERT(ok == true);
463 }
464 
466 {
467  NS_LOG_FUNCTION(this);
468  m_node = nullptr;
469  if (m_endPoint != nullptr)
470  {
471  NS_ASSERT(m_tcp);
472  /*
473  * Upon Bind, an Ipv4Endpoint is allocated and set to m_endPoint, and
474  * DestroyCallback is set to TcpSocketBase::Destroy. If we called
475  * m_tcp->DeAllocate, it will destroy its Ipv4EndpointDemux::DeAllocate,
476  * which in turn destroys my m_endPoint, and in turn invokes
477  * TcpSocketBase::Destroy to nullify m_node, m_endPoint, and m_tcp.
478  */
479  NS_ASSERT(m_endPoint != nullptr);
480  m_tcp->DeAllocate(m_endPoint);
481  NS_ASSERT(m_endPoint == nullptr);
482  }
483  if (m_endPoint6 != nullptr)
484  {
485  NS_ASSERT(m_tcp);
486  NS_ASSERT(m_endPoint6 != nullptr);
487  m_tcp->DeAllocate(m_endPoint6);
488  NS_ASSERT(m_endPoint6 == nullptr);
489  }
490  m_tcp = nullptr;
491  CancelAllTimers();
492 }
493 
494 /* Associate a node with this TCP socket */
495 void
497 {
498  m_node = node;
499 }
500 
501 /* Associate the L4 protocol (e.g. mux/demux) with this socket */
502 void
504 {
505  m_tcp = tcp;
506 }
507 
508 /* Set an RTT estimator with this socket */
509 void
511 {
512  m_rtt = rtt;
513 }
514 
515 /* Inherit from Socket class: Returns error code */
518 {
519  return m_errno;
520 }
521 
522 /* Inherit from Socket class: Returns socket type, NS3_SOCK_STREAM */
525 {
526  return NS3_SOCK_STREAM;
527 }
528 
529 /* Inherit from Socket class: Returns associated node */
530 Ptr<Node>
532 {
533  return m_node;
534 }
535 
536 /* Inherit from Socket class: Bind socket to an end-point in TcpL4Protocol */
537 int
539 {
540  NS_LOG_FUNCTION(this);
541  m_endPoint = m_tcp->Allocate();
542  if (nullptr == m_endPoint)
543  {
545  return -1;
546  }
547 
548  m_tcp->AddSocket(this);
549 
550  return SetupCallback();
551 }
552 
553 int
555 {
556  NS_LOG_FUNCTION(this);
557  m_endPoint6 = m_tcp->Allocate6();
558  if (nullptr == m_endPoint6)
559  {
561  return -1;
562  }
563 
564  m_tcp->AddSocket(this);
565 
566  return SetupCallback();
567 }
568 
569 /* Inherit from Socket class: Bind socket (with specific address) to an end-point in TcpL4Protocol
570  */
571 int
573 {
574  NS_LOG_FUNCTION(this << address);
576  {
578  Ipv4Address ipv4 = transport.GetIpv4();
579  uint16_t port = transport.GetPort();
580  SetIpTos(transport.GetTos());
581  if (ipv4 == Ipv4Address::GetAny() && port == 0)
582  {
583  m_endPoint = m_tcp->Allocate();
584  }
585  else if (ipv4 == Ipv4Address::GetAny() && port != 0)
586  {
587  m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), port);
588  }
589  else if (ipv4 != Ipv4Address::GetAny() && port == 0)
590  {
591  m_endPoint = m_tcp->Allocate(ipv4);
592  }
593  else if (ipv4 != Ipv4Address::GetAny() && port != 0)
594  {
595  m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), ipv4, port);
596  }
597  if (nullptr == m_endPoint)
598  {
600  return -1;
601  }
602  }
604  {
606  Ipv6Address ipv6 = transport.GetIpv6();
607  uint16_t port = transport.GetPort();
608  if (ipv6 == Ipv6Address::GetAny() && port == 0)
609  {
610  m_endPoint6 = m_tcp->Allocate6();
611  }
612  else if (ipv6 == Ipv6Address::GetAny() && port != 0)
613  {
614  m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), port);
615  }
616  else if (ipv6 != Ipv6Address::GetAny() && port == 0)
617  {
618  m_endPoint6 = m_tcp->Allocate6(ipv6);
619  }
620  else if (ipv6 != Ipv6Address::GetAny() && port != 0)
621  {
622  m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), ipv6, port);
623  }
624  if (nullptr == m_endPoint6)
625  {
627  return -1;
628  }
629  }
630  else
631  {
633  return -1;
634  }
635 
636  m_tcp->AddSocket(this);
637 
638  NS_LOG_LOGIC("TcpSocketBase " << this << " got an endpoint: " << m_endPoint);
639 
640  return SetupCallback();
641 }
642 
643 void
645 {
647  (m_state == CLOSED) || threshold == m_tcb->m_initialSsThresh,
648  "TcpSocketBase::SetSSThresh() cannot change initial ssThresh after connection started.");
649 
650  m_tcb->m_initialSsThresh = threshold;
651 }
652 
653 uint32_t
655 {
656  return m_tcb->m_initialSsThresh;
657 }
658 
659 void
661 {
663  (m_state == CLOSED) || cwnd == m_tcb->m_initialCWnd,
664  "TcpSocketBase::SetInitialCwnd() cannot change initial cwnd after connection started.");
665 
666  m_tcb->m_initialCWnd = cwnd;
667 }
668 
669 uint32_t
671 {
672  return m_tcb->m_initialCWnd;
673 }
674 
675 /* Inherit from Socket class: Initiate connection to a remote address:port */
676 int
678 {
679  NS_LOG_FUNCTION(this << address);
680 
681  // If haven't do so, Bind() this socket first
683  {
684  if (m_endPoint == nullptr)
685  {
686  if (Bind() == -1)
687  {
688  NS_ASSERT(m_endPoint == nullptr);
689  return -1; // Bind() failed
690  }
691  NS_ASSERT(m_endPoint != nullptr);
692  }
694  m_endPoint->SetPeer(transport.GetIpv4(), transport.GetPort());
695  SetIpTos(transport.GetTos());
696  m_endPoint6 = nullptr;
697 
698  // Get the appropriate local address and port number from the routing protocol and set up
699  // endpoint
700  if (SetupEndpoint() != 0)
701  {
702  NS_LOG_ERROR("Route to destination does not exist ?!");
703  return -1;
704  }
705  }
707  {
708  // If we are operating on a v4-mapped address, translate the address to
709  // a v4 address and re-call this function
711  Ipv6Address v6Addr = transport.GetIpv6();
712  if (v6Addr.IsIpv4MappedAddress() == true)
713  {
714  Ipv4Address v4Addr = v6Addr.GetIpv4MappedAddress();
715  return Connect(InetSocketAddress(v4Addr, transport.GetPort()));
716  }
717 
718  if (m_endPoint6 == nullptr)
719  {
720  if (Bind6() == -1)
721  {
722  NS_ASSERT(m_endPoint6 == nullptr);
723  return -1; // Bind() failed
724  }
725  NS_ASSERT(m_endPoint6 != nullptr);
726  }
727  m_endPoint6->SetPeer(v6Addr, transport.GetPort());
728  m_endPoint = nullptr;
729 
730  // Get the appropriate local address and port number from the routing protocol and set up
731  // endpoint
732  if (SetupEndpoint6() != 0)
733  {
734  NS_LOG_ERROR("Route to destination does not exist ?!");
735  return -1;
736  }
737  }
738  else
739  {
741  return -1;
742  }
743 
744  // Re-initialize parameters in case this socket is being reused after CLOSE
745  m_rtt->Reset();
748 
749  // DoConnect() will do state-checking and send a SYN packet
750  return DoConnect();
751 }
752 
753 /* Inherit from Socket class: Listen on the endpoint for an incoming connection */
754 int
756 {
757  NS_LOG_FUNCTION(this);
758 
759  // Linux quits EINVAL if we're not in CLOSED state, so match what they do
760  if (m_state != CLOSED)
761  {
763  return -1;
764  }
765  // In other cases, set the state to LISTEN and done
766  NS_LOG_DEBUG("CLOSED -> LISTEN");
767  m_state = LISTEN;
768  return 0;
769 }
770 
771 /* Inherit from Socket class: Kill this socket and signal the peer (if any) */
772 int
774 {
775  NS_LOG_FUNCTION(this);
779  if (m_tcb->m_rxBuffer->Size() != 0)
780  {
781  NS_LOG_WARN("Socket " << this << " << unread rx data during close. Sending reset."
782  << "This is probably due to a bad sink application; check its code");
783  SendRST();
784  return 0;
785  }
786 
787  if (m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence) > 0)
788  { // App close with pending data must wait until all data transmitted
789  if (m_closeOnEmpty == false)
790  {
791  m_closeOnEmpty = true;
792  NS_LOG_INFO("Socket " << this << " deferring close, state " << TcpStateName[m_state]);
793  }
794  return 0;
795  }
796  return DoClose();
797 }
798 
799 /* Inherit from Socket class: Signal a termination of send */
800 int
802 {
803  NS_LOG_FUNCTION(this);
804 
805  // this prevents data from being added to the buffer
806  m_shutdownSend = true;
807  m_closeOnEmpty = true;
808  // if buffer is already empty, send a fin now
809  // otherwise fin will go when buffer empties.
810  if (m_txBuffer->Size() == 0)
811  {
812  if (m_state == ESTABLISHED || m_state == CLOSE_WAIT)
813  {
814  NS_LOG_INFO("Empty tx buffer, send fin");
816 
817  if (m_state == ESTABLISHED)
818  { // On active close: I am the first one to send FIN
819  NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
821  }
822  else
823  { // On passive close: Peer sent me FIN already
824  NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
825  m_state = LAST_ACK;
826  }
827  }
828  }
829 
830  return 0;
831 }
832 
833 /* Inherit from Socket class: Signal a termination of receive */
834 int
836 {
837  NS_LOG_FUNCTION(this);
838  m_shutdownRecv = true;
839  return 0;
840 }
841 
842 /* Inherit from Socket class: Send a packet. Parameter flags is not used.
843  Packet has no TCP header. Invoked by upper-layer application */
844 int
846 {
847  NS_LOG_FUNCTION(this << p);
848  NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Send()");
850  {
851  // Store the packet into Tx buffer
852  if (!m_txBuffer->Add(p))
853  { // TxBuffer overflow, send failed
855  return -1;
856  }
857  if (m_shutdownSend)
858  {
860  return -1;
861  }
862 
866  m_txBuffer->TailSequence(),
868  m_txBuffer->GetLost(),
869  m_txBuffer->GetRetransmitsCount());
870 
871  // Submit the data to lower layers
872  NS_LOG_LOGIC("txBufSize=" << m_txBuffer->Size() << " state " << TcpStateName[m_state]);
873  if ((m_state == ESTABLISHED || m_state == CLOSE_WAIT) && AvailableWindow() > 0)
874  { // Try to send the data out: Add a little step to allow the application
875  // to fill the buffer
877  {
880  this,
881  m_connected);
882  }
883  }
884  return p->GetSize();
885  }
886  else
887  { // Connection not established yet
889  return -1; // Send failure
890  }
891 }
892 
893 /* Inherit from Socket class: In TcpSocketBase, it is same as Send() call */
894 int
895 TcpSocketBase::SendTo(Ptr<Packet> p, uint32_t flags, const Address& /* address */)
896 {
897  return Send(p, flags); // SendTo() and Send() are the same
898 }
899 
900 /* Inherit from Socket class: Return data to upper-layer application. Parameter flags
901  is not used. Data is returned as a packet of size no larger than maxSize */
903 TcpSocketBase::Recv(uint32_t maxSize, uint32_t flags)
904 {
905  NS_LOG_FUNCTION(this);
906  NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Recv()");
907  if (m_tcb->m_rxBuffer->Size() == 0 && m_state == CLOSE_WAIT)
908  {
909  return Create<Packet>(); // Send EOF on connection close
910  }
911  Ptr<Packet> outPacket = m_tcb->m_rxBuffer->Extract(maxSize);
912  return outPacket;
913 }
914 
915 /* Inherit from Socket class: Recv and return the remote's address */
917 TcpSocketBase::RecvFrom(uint32_t maxSize, uint32_t flags, Address& fromAddress)
918 {
919  NS_LOG_FUNCTION(this << maxSize << flags);
920  Ptr<Packet> packet = Recv(maxSize, flags);
921  // Null packet means no data to read, and an empty packet indicates EOF
922  if (packet && packet->GetSize() != 0)
923  {
924  if (m_endPoint != nullptr)
925  {
926  fromAddress =
928  }
929  else if (m_endPoint6 != nullptr)
930  {
931  fromAddress =
933  }
934  else
935  {
936  fromAddress = InetSocketAddress(Ipv4Address::GetZero(), 0);
937  }
938  }
939  return packet;
940 }
941 
942 /* Inherit from Socket class: Get the max number of bytes an app can send */
943 uint32_t
945 {
946  NS_LOG_FUNCTION(this);
947  return m_txBuffer->Available();
948 }
949 
950 /* Inherit from Socket class: Get the max number of bytes an app can read */
951 uint32_t
953 {
954  NS_LOG_FUNCTION(this);
955  return m_tcb->m_rxBuffer->Available();
956 }
957 
958 /* Inherit from Socket class: Return local address:port */
959 int
961 {
962  NS_LOG_FUNCTION(this);
963  if (m_endPoint != nullptr)
964  {
966  }
967  else if (m_endPoint6 != nullptr)
968  {
970  }
971  else
972  { // It is possible to call this method on a socket without a name
973  // in which case, behavior is unspecified
974  // Should this return an InetSocketAddress or an Inet6SocketAddress?
976  }
977  return 0;
978 }
979 
980 int
982 {
983  NS_LOG_FUNCTION(this << address);
984 
985  if (!m_endPoint && !m_endPoint6)
986  {
988  return -1;
989  }
990 
991  if (m_endPoint)
992  {
994  }
995  else if (m_endPoint6)
996  {
998  }
999  else
1000  {
1001  NS_ASSERT(false);
1002  }
1003 
1004  return 0;
1005 }
1006 
1007 /* Inherit from Socket class: Bind this socket to the specified NetDevice */
1008 void
1010 {
1011  NS_LOG_FUNCTION(netdevice);
1012  Socket::BindToNetDevice(netdevice); // Includes sanity check
1013  if (m_endPoint != nullptr)
1014  {
1015  m_endPoint->BindToNetDevice(netdevice);
1016  }
1017 
1018  if (m_endPoint6 != nullptr)
1019  {
1020  m_endPoint6->BindToNetDevice(netdevice);
1021  }
1022 }
1023 
1024 /* Clean up after Bind. Set up callback functions in the end-point. */
1025 int
1027 {
1028  NS_LOG_FUNCTION(this);
1029 
1030  if (m_endPoint == nullptr && m_endPoint6 == nullptr)
1031  {
1032  return -1;
1033  }
1034  if (m_endPoint != nullptr)
1035  {
1042  }
1043  if (m_endPoint6 != nullptr)
1044  {
1051  }
1052 
1053  return 0;
1054 }
1055 
1056 /* Perform the real connection tasks: Send SYN if allowed, RST if invalid */
1057 int
1059 {
1060  NS_LOG_FUNCTION(this);
1061 
1062  // A new connection is allowed only if this socket does not have a connection
1063  if (m_state == CLOSED || m_state == LISTEN || m_state == SYN_SENT || m_state == LAST_ACK ||
1064  m_state == CLOSE_WAIT)
1065  { // send a SYN packet and change state into SYN_SENT
1066  // send a SYN packet with ECE and CWR flags set if sender is ECN capable
1068  {
1070  }
1071  else
1072  {
1074  }
1075  NS_LOG_DEBUG(TcpStateName[m_state] << " -> SYN_SENT");
1076  m_state = SYN_SENT;
1077  m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED; // because sender is not yet aware about
1078  // receiver's ECN capability
1079  }
1080  else if (m_state != TIME_WAIT)
1081  { // In states SYN_RCVD, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, and CLOSING, an connection
1082  // exists. We send RST, tear down everything, and close this socket.
1083  SendRST();
1084  CloseAndNotify();
1085  }
1086  return 0;
1087 }
1088 
1089 /* Do the action to close the socket. Usually send a packet with appropriate
1090  flags depended on the current m_state. */
1091 int
1093 {
1094  NS_LOG_FUNCTION(this);
1095  switch (m_state)
1096  {
1097  case SYN_RCVD:
1098  case ESTABLISHED:
1099  // send FIN to close the peer
1101  NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
1102  m_state = FIN_WAIT_1;
1103  break;
1104  case CLOSE_WAIT:
1105  // send FIN+ACK to close the peer
1107  NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
1108  m_state = LAST_ACK;
1109  break;
1110  case SYN_SENT:
1111  case CLOSING:
1112  // Send RST if application closes in SYN_SENT and CLOSING
1113  SendRST();
1114  CloseAndNotify();
1115  break;
1116  case LISTEN:
1117  // In this state, move to CLOSED and tear down the end point
1118  CloseAndNotify();
1119  break;
1120  case LAST_ACK:
1121  case CLOSED:
1122  case FIN_WAIT_1:
1123  case FIN_WAIT_2:
1124  case TIME_WAIT:
1125  default: /* mute compiler */
1126  // Do nothing in these five states
1127  break;
1128  }
1129  return 0;
1130 }
1131 
1132 /* Peacefully close the socket by notifying the upper layer and deallocate end point */
1133 void
1135 {
1136  NS_LOG_FUNCTION(this);
1137 
1138  if (!m_closeNotified)
1139  {
1141  m_closeNotified = true;
1142  }
1143  if (m_lastAckEvent.IsRunning())
1144  {
1146  }
1147  NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSED");
1148  m_state = CLOSED;
1150 }
1151 
1152 /* Tell if a sequence number range is out side the range that my rx buffer can
1153  accept */
1154 bool
1156 {
1157  if (m_state == LISTEN || m_state == SYN_SENT || m_state == SYN_RCVD)
1158  { // Rx buffer in these states are not initialized.
1159  return false;
1160  }
1161  if (m_state == LAST_ACK || m_state == CLOSING || m_state == CLOSE_WAIT)
1162  { // In LAST_ACK and CLOSING states, it only wait for an ACK and the
1163  // sequence number must equals to m_rxBuffer->NextRxSequence ()
1164  return (m_tcb->m_rxBuffer->NextRxSequence() != head);
1165  }
1166 
1167  // In all other cases, check if the sequence number is in range
1168  return (tail < m_tcb->m_rxBuffer->NextRxSequence() ||
1169  m_tcb->m_rxBuffer->MaxRxSequence() <= head);
1170 }
1171 
1172 /* Function called by the L3 protocol when it received a packet to pass on to
1173  the TCP. This function is registered as the "RxCallback" function in
1174  SetupCallback(), which invoked by Bind(), and CompleteFork() */
1175 void
1177  Ipv4Header header,
1178  uint16_t port,
1179  Ptr<Ipv4Interface> incomingInterface)
1180 {
1181  NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint->GetPeerAddress() << ":"
1182  << m_endPoint->GetPeerPort() << " to " << m_endPoint->GetLocalAddress()
1183  << ":" << m_endPoint->GetLocalPort());
1184 
1185  Address fromAddress = InetSocketAddress(header.GetSource(), port);
1187 
1188  TcpHeader tcpHeader;
1189  uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1190 
1191  if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1192  bytesRemoved,
1193  packet->GetSize() - bytesRemoved))
1194  {
1195  return;
1196  }
1197 
1198  if (header.GetEcn() == Ipv4Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1199  {
1200  NS_LOG_INFO("Received CE flag is valid");
1202  m_ecnCESeq = tcpHeader.GetSequenceNumber();
1205  }
1206  else if (header.GetEcn() != Ipv4Header::ECN_NotECT &&
1208  {
1210  }
1211 
1212  DoForwardUp(packet, fromAddress, toAddress);
1213 }
1214 
1215 void
1217  Ipv6Header header,
1218  uint16_t port,
1219  Ptr<Ipv6Interface> incomingInterface)
1220 {
1221  NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint6->GetPeerAddress() << ":"
1222  << m_endPoint6->GetPeerPort() << " to " << m_endPoint6->GetLocalAddress()
1223  << ":" << m_endPoint6->GetLocalPort());
1224 
1225  Address fromAddress = Inet6SocketAddress(header.GetSource(), port);
1227 
1228  TcpHeader tcpHeader;
1229  uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1230 
1231  if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1232  bytesRemoved,
1233  packet->GetSize() - bytesRemoved))
1234  {
1235  return;
1236  }
1237 
1238  if (header.GetEcn() == Ipv6Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1239  {
1240  NS_LOG_INFO("Received CE flag is valid");
1242  m_ecnCESeq = tcpHeader.GetSequenceNumber();
1245  }
1246  else if (header.GetEcn() != Ipv6Header::ECN_NotECT)
1247  {
1249  }
1250 
1251  DoForwardUp(packet, fromAddress, toAddress);
1252 }
1253 
1254 void
1256  uint8_t icmpTtl,
1257  uint8_t icmpType,
1258  uint8_t icmpCode,
1259  uint32_t icmpInfo)
1260 {
1261  NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1262  << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1263  << icmpInfo);
1264  if (!m_icmpCallback.IsNull())
1265  {
1266  m_icmpCallback(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1267  }
1268 }
1269 
1270 void
1272  uint8_t icmpTtl,
1273  uint8_t icmpType,
1274  uint8_t icmpCode,
1275  uint32_t icmpInfo)
1276 {
1277  NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1278  << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1279  << icmpInfo);
1280  if (!m_icmpCallback6.IsNull())
1281  {
1282  m_icmpCallback6(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1283  }
1284 }
1285 
1286 bool
1288  const uint32_t tcpHeaderSize,
1289  const uint32_t tcpPayloadSize)
1290 {
1291  if (tcpHeaderSize == 0 || tcpHeaderSize > 60)
1292  {
1293  NS_LOG_ERROR("Bytes removed: " << tcpHeaderSize << " invalid");
1294  return false; // Discard invalid packet
1295  }
1296  else if (tcpPayloadSize > 0 && OutOfRange(seq, seq + tcpPayloadSize))
1297  {
1298  // Discard fully out of range data packets
1299  NS_LOG_WARN("At state " << TcpStateName[m_state] << " received packet of seq [" << seq
1300  << ":" << seq + tcpPayloadSize << ") out of range ["
1301  << m_tcb->m_rxBuffer->NextRxSequence() << ":"
1302  << m_tcb->m_rxBuffer->MaxRxSequence() << ")");
1303  // Acknowledgement should be sent for all unacceptable packets (RFC793, p.69)
1305  return false;
1306  }
1307  return true;
1308 }
1309 
1310 void
1311 TcpSocketBase::DoForwardUp(Ptr<Packet> packet, const Address& fromAddress, const Address& toAddress)
1312 {
1313  // in case the packet still has a priority tag attached, remove it
1314  SocketPriorityTag priorityTag;
1315  packet->RemovePacketTag(priorityTag);
1316 
1317  // Peel off TCP header
1318  TcpHeader tcpHeader;
1319  packet->RemoveHeader(tcpHeader);
1320  SequenceNumber32 seq = tcpHeader.GetSequenceNumber();
1321 
1322  if (m_state == ESTABLISHED && !(tcpHeader.GetFlags() & TcpHeader::RST))
1323  {
1324  // Check if the sender has responded to ECN echo by reducing the Congestion Window
1325  if (tcpHeader.GetFlags() & TcpHeader::CWR)
1326  {
1327  // Check if a packet with CE bit set is received. If there is no CE bit set, then change
1328  // the state to ECN_IDLE to stop sending ECN Echo messages. If there is CE bit set, the
1329  // packet should continue sending ECN Echo messages
1330  //
1332  {
1335  }
1336  }
1337  }
1338 
1339  m_rxTrace(packet, tcpHeader, this);
1340 
1341  if (tcpHeader.GetFlags() & TcpHeader::SYN)
1342  {
1343  /* The window field in a segment where the SYN bit is set (i.e., a <SYN>
1344  * or <SYN,ACK>) MUST NOT be scaled (from RFC 7323 page 9). But should be
1345  * saved anyway..
1346  */
1347  m_rWnd = tcpHeader.GetWindowSize();
1348 
1350  {
1352  }
1353  else
1354  {
1355  m_winScalingEnabled = false;
1356  }
1357 
1359  {
1361  }
1362  else
1363  {
1364  m_sackEnabled = false;
1365  m_txBuffer->SetSackEnabled(false);
1366  }
1367 
1368  // When receiving a <SYN> or <SYN-ACK> we should adapt TS to the other end
1369  if (tcpHeader.HasOption(TcpOption::TS) && m_timestampEnabled)
1370  {
1372  tcpHeader.GetSequenceNumber());
1373  }
1374  else
1375  {
1376  m_timestampEnabled = false;
1377  }
1378 
1379  // Initialize cWnd and ssThresh
1383 
1384  if (tcpHeader.GetFlags() & TcpHeader::ACK)
1385  {
1386  EstimateRtt(tcpHeader);
1387  m_highRxAckMark = tcpHeader.GetAckNumber();
1388  }
1389  }
1390  else if (tcpHeader.GetFlags() & TcpHeader::ACK)
1391  {
1392  NS_ASSERT(!(tcpHeader.GetFlags() & TcpHeader::SYN));
1393  if (m_timestampEnabled)
1394  {
1395  if (!tcpHeader.HasOption(TcpOption::TS))
1396  {
1397  // Ignoring segment without TS, RFC 7323
1398  NS_LOG_LOGIC("At state " << TcpStateName[m_state] << " received packet of seq ["
1399  << seq << ":" << seq + packet->GetSize()
1400  << ") without TS option. Silently discard it");
1401  return;
1402  }
1403  else
1404  {
1406  tcpHeader.GetSequenceNumber());
1407  }
1408  }
1409 
1410  EstimateRtt(tcpHeader);
1411  UpdateWindowSize(tcpHeader);
1412  }
1413 
1414  if (m_rWnd.Get() == 0 && m_persistEvent.IsExpired())
1415  { // Zero window: Enter persist state to send 1 byte to probe
1416  NS_LOG_LOGIC(this << " Enter zerowindow persist state");
1417  NS_LOG_LOGIC(
1418  this << " Cancelled ReTxTimeout event which was set to expire at "
1419  << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
1420  m_retxEvent.Cancel();
1421  NS_LOG_LOGIC("Schedule persist timeout at time "
1422  << Simulator::Now().GetSeconds() << " to expire at time "
1423  << (Simulator::Now() + m_persistTimeout).GetSeconds());
1424  m_persistEvent =
1427  }
1428 
1429  // TCP state machine code in different process functions
1430  // C.f.: tcp_rcv_state_process() in tcp_input.c in Linux kernel
1431  switch (m_state)
1432  {
1433  case ESTABLISHED:
1434  ProcessEstablished(packet, tcpHeader);
1435  break;
1436  case LISTEN:
1437  ProcessListen(packet, tcpHeader, fromAddress, toAddress);
1438  break;
1439  case TIME_WAIT:
1440  // Do nothing
1441  break;
1442  case CLOSED:
1443  // Send RST if the incoming packet is not a RST
1444  if ((tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG)) != TcpHeader::RST)
1445  { // Since m_endPoint is not configured yet, we cannot use SendRST here
1446  TcpHeader h;
1447  Ptr<Packet> p = Create<Packet>();
1450  h.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
1451  h.SetSourcePort(tcpHeader.GetDestinationPort());
1452  h.SetDestinationPort(tcpHeader.GetSourcePort());
1454  AddOptions(h);
1455  m_txTrace(p, h, this);
1456  m_tcp->SendPacket(p, h, toAddress, fromAddress, m_boundnetdevice);
1457  }
1458  break;
1459  case SYN_SENT:
1460  ProcessSynSent(packet, tcpHeader);
1461  break;
1462  case SYN_RCVD:
1463  ProcessSynRcvd(packet, tcpHeader, fromAddress, toAddress);
1464  break;
1465  case FIN_WAIT_1:
1466  case FIN_WAIT_2:
1467  case CLOSE_WAIT:
1468  ProcessWait(packet, tcpHeader);
1469  break;
1470  case CLOSING:
1471  ProcessClosing(packet, tcpHeader);
1472  break;
1473  case LAST_ACK:
1474  ProcessLastAck(packet, tcpHeader);
1475  break;
1476  default: // mute compiler
1477  break;
1478  }
1479 
1480  if (m_rWnd.Get() != 0 && m_persistEvent.IsRunning())
1481  { // persist probes end, the other end has increased the window
1483  NS_LOG_LOGIC(this << " Leaving zerowindow persist state");
1485 
1487  }
1488 }
1489 
1490 /* Received a packet upon ESTABLISHED state. This function is mimicking the
1491  role of tcp_rcv_established() in tcp_input.c in Linux kernel. */
1492 void
1494 {
1495  NS_LOG_FUNCTION(this << tcpHeader);
1496 
1497  // Extract the flags. PSH, URG, CWR and ECE are disregarded.
1498  uint8_t tcpflags =
1500 
1501  // Different flags are different events
1502  if (tcpflags == TcpHeader::ACK)
1503  {
1504  if (tcpHeader.GetAckNumber() < m_txBuffer->HeadSequence())
1505  {
1506  // Case 1: If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored.
1507  // Pag. 72 RFC 793
1508  NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1509  << " SND.UNA = " << m_txBuffer->HeadSequence());
1510 
1511  // TODO: RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation]
1512  }
1513  else if (tcpHeader.GetAckNumber() > m_tcb->m_highTxMark)
1514  {
1515  // If the ACK acks something not yet sent (SEG.ACK > HighTxMark) then
1516  // send an ACK, drop the segment, and return.
1517  // Pag. 72 RFC 793
1518  NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1519  << " HighTxMark = " << m_tcb->m_highTxMark);
1520 
1521  // Receiver sets ECE flags when it receives a packet with CE bit on or sender hasn’t
1522  // responded to ECN echo sent by receiver
1525  {
1528  << " -> ECN_SENDING_ECE");
1530  }
1531  else
1532  {
1534  }
1535  }
1536  else
1537  {
1538  // SND.UNA < SEG.ACK =< HighTxMark
1539  // Pag. 72 RFC 793
1540  ReceivedAck(packet, tcpHeader);
1541  }
1542  }
1543  else if (tcpflags == TcpHeader::SYN)
1544  { // Received SYN, old NS-3 behaviour is to set state to SYN_RCVD and
1545  // respond with a SYN+ACK. But it is not a legal state transition as of
1546  // RFC793. Thus this is ignored.
1547  }
1548  else if (tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
1549  { // No action for received SYN+ACK, it is probably a duplicated packet
1550  }
1551  else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
1552  { // Received FIN or FIN+ACK, bring down this socket nicely
1553  PeerClose(packet, tcpHeader);
1554  }
1555  else if (tcpflags == 0)
1556  { // No flags means there is only data
1557  ReceivedData(packet, tcpHeader);
1558  if (m_tcb->m_rxBuffer->Finished())
1559  {
1560  PeerClose(packet, tcpHeader);
1561  }
1562  }
1563  else
1564  { // Received RST or the TCP flags is invalid, in either case, terminate this socket
1565  if (tcpflags != TcpHeader::RST)
1566  { // this must be an invalid flag, send reset
1567  NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
1568  << " received. Reset packet is sent.");
1569  SendRST();
1570  }
1571  CloseAndNotify();
1572  }
1573 }
1574 
1575 bool
1577 {
1578  NS_LOG_FUNCTION(this << static_cast<uint32_t>(kind));
1579 
1580  switch (kind)
1581  {
1582  case TcpOption::TS:
1583  return m_timestampEnabled;
1584  case TcpOption::WINSCALE:
1585  return m_winScalingEnabled;
1587  case TcpOption::SACK:
1588  return m_sackEnabled;
1589  default:
1590  break;
1591  }
1592  return false;
1593 }
1594 
1595 void
1596 TcpSocketBase::ReadOptions(const TcpHeader& tcpHeader, uint32_t* bytesSacked)
1597 {
1598  NS_LOG_FUNCTION(this << tcpHeader);
1599  TcpHeader::TcpOptionList::const_iterator it;
1600  const TcpHeader::TcpOptionList options = tcpHeader.GetOptionList();
1601 
1602  for (it = options.begin(); it != options.end(); ++it)
1603  {
1604  const Ptr<const TcpOption> option = (*it);
1605 
1606  // Check only for ACK options here
1607  switch (option->GetKind())
1608  {
1609  case TcpOption::SACK:
1610  *bytesSacked = ProcessOptionSack(option);
1611  break;
1612  default:
1613  continue;
1614  }
1615  }
1616 }
1617 
1618 // Sender should reduce the Congestion Window as a response to receiver's
1619 // ECN Echo notification only once per window
1620 void
1621 TcpSocketBase::EnterCwr(uint32_t currentDelivered)
1622 {
1623  NS_LOG_FUNCTION(this << currentDelivered);
1625  NS_LOG_DEBUG("Reduce ssThresh to " << m_tcb->m_ssThresh);
1626  // Do not update m_cWnd, under assumption that recovery process will
1627  // gradually bring it down to m_ssThresh. Update the 'inflated' value of
1628  // cWnd used for tracing, however.
1633  // CWR state will be exited when the ack exceeds the m_recover variable.
1634  // Do not set m_recoverActive (which applies to a loss-based recovery)
1635  // m_recover corresponds to Linux tp->high_seq
1637  if (!m_congestionControl->HasCongControl())
1638  {
1639  // If there is a recovery algorithm, invoke it.
1640  m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1641  NS_LOG_INFO("Enter CWR recovery mode; set cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1642  << m_tcb->m_ssThresh << ", recover to "
1643  << m_recover);
1644  }
1645 }
1646 
1647 void
1648 TcpSocketBase::EnterRecovery(uint32_t currentDelivered)
1649 {
1650  NS_LOG_FUNCTION(this);
1652 
1654 
1655  if (!m_sackEnabled)
1656  {
1657  // One segment has left the network, PLUS the head is lost
1658  m_txBuffer->AddRenoSack();
1659  m_txBuffer->MarkHeadAsLost();
1660  }
1661  else
1662  {
1663  if (!m_txBuffer->IsLost(m_txBuffer->HeadSequence()))
1664  {
1665  // We received 3 dupacks, but the head is not marked as lost
1666  // (received less than 3 SACK block ahead).
1667  // Manually set it as lost.
1668  m_txBuffer->MarkHeadAsLost();
1669  }
1670  }
1671 
1672  // RFC 6675, point (4):
1673  // (4) Invoke fast retransmit and enter loss recovery as follows:
1674  // (4.1) RecoveryPoint = HighData
1676  m_recoverActive = true;
1677 
1680 
1681  // (4.2) ssthresh = cwnd = (FlightSize / 2)
1682  // If SACK is not enabled, still consider the head as 'in flight' for
1683  // compatibility with old ns-3 versions
1684  uint32_t bytesInFlight =
1686  m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, bytesInFlight);
1687 
1688  if (!m_congestionControl->HasCongControl())
1689  {
1690  m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1691  NS_LOG_INFO(m_dupAckCount << " dupack. Enter fast recovery mode."
1692  << "Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1693  << m_tcb->m_ssThresh << " at fast recovery seqnum " << m_recover
1694  << " calculated in flight: " << bytesInFlight);
1695  }
1696 
1697  // (4.3) Retransmit the first data segment presumed dropped
1698  DoRetransmit();
1699  // (4.4) Run SetPipe ()
1700  // (4.5) Proceed to step (C)
1701  // these steps are done after the ProcessAck function (SendPendingData)
1702 }
1703 
1704 void
1705 TcpSocketBase::DupAck(uint32_t currentDelivered)
1706 {
1707  NS_LOG_FUNCTION(this);
1708  // NOTE: We do not count the DupAcks received in CA_LOSS, because we
1709  // don't know if they are generated by a spurious retransmission or because
1710  // of a real packet loss. With SACK, it is easy to know, but we do not consider
1711  // dupacks. Without SACK, there are some heuristics in the RFC 6582, but
1712  // for now, we do not implement it, leading to ignoring the dupacks.
1714  {
1715  return;
1716  }
1717 
1718  // RFC 6675, Section 5, 3rd paragraph:
1719  // If the incoming ACK is a duplicate acknowledgment per the definition
1720  // in Section 2 (regardless of its status as a cumulative
1721  // acknowledgment), and the TCP is not currently in loss recovery
1722  // the TCP MUST increase DupAcks by one ...
1724  {
1725  ++m_dupAckCount;
1726  }
1727 
1729  {
1730  // From Open we go Disorder
1732  "From OPEN->DISORDER but with " << m_dupAckCount << " dup ACKs");
1733 
1736 
1737  NS_LOG_DEBUG("CA_OPEN -> CA_DISORDER");
1738  }
1739 
1741  {
1742  if (!m_sackEnabled)
1743  {
1744  // If we are in recovery and we receive a dupack, one segment
1745  // has left the network. This is equivalent to a SACK of one block.
1746  m_txBuffer->AddRenoSack();
1747  }
1748  if (!m_congestionControl->HasCongControl())
1749  {
1750  m_recoveryOps->DoRecovery(m_tcb, currentDelivered);
1751  NS_LOG_INFO(m_dupAckCount << " Dupack received in fast recovery mode."
1752  "Increase cwnd to "
1753  << m_tcb->m_cWnd);
1754  }
1755  }
1757  {
1758  // m_dupackCount should not exceed its threshold in CA_DISORDER state
1759  // when m_recoverActive has not been set. When recovery point
1760  // have been set after timeout, the sender could enter into CA_DISORDER
1761  // after receiving new ACK smaller than m_recover. After that, m_dupackCount
1762  // can be equal and larger than m_retxThresh and we should avoid entering
1763  // CA_RECOVERY and reducing sending rate again.
1765 
1766  // RFC 6675, Section 5, continuing:
1767  // ... and take the following steps:
1768  // (1) If DupAcks >= DupThresh, go to step (4).
1769  // Sequence number comparison (m_highRxAckMark >= m_recover) will take
1770  // effect only when m_recover has been set. Hence, we can avoid to use
1771  // m_recover in the last congestion event and fail to enter
1772  // CA_RECOVERY when sequence number is advanced significantly since
1773  // the last congestion event, which could be common for
1774  // bandwidth-greedy application in high speed and reliable network
1775  // (such as datacenter network) whose sending rate is constrained by
1776  // TCP socket buffer size at receiver side.
1777  if ((m_dupAckCount == m_retxThresh) &&
1779  {
1780  EnterRecovery(currentDelivered);
1782  }
1783  // (2) If DupAcks < DupThresh but IsLost (HighACK + 1) returns true
1784  // (indicating at least three segments have arrived above the current
1785  // cumulative acknowledgment point, which is taken to indicate loss)
1786  // go to step (4).
1787  else if (m_txBuffer->IsLost(m_highRxAckMark + m_tcb->m_segmentSize))
1788  {
1789  EnterRecovery(currentDelivered);
1791  }
1792  else
1793  {
1794  // (3) The TCP MAY transmit previously unsent data segments as per
1795  // Limited Transmit [RFC5681] ...except that the number of octets
1796  // which may be sent is governed by pipe and cwnd as follows:
1797  //
1798  // (3.1) Set HighRxt to HighACK.
1799  // Not clear in RFC. We don't do this here, since we still have
1800  // to retransmit the segment.
1801 
1802  if (!m_sackEnabled && m_limitedTx)
1803  {
1804  m_txBuffer->AddRenoSack();
1805 
1806  // In limited transmit, cwnd Infl is not updated.
1807  }
1808  }
1809  }
1810 }
1811 
1812 /* Process the newly received ACK */
1813 void
1815 {
1816  NS_LOG_FUNCTION(this << tcpHeader);
1817 
1818  NS_ASSERT(0 != (tcpHeader.GetFlags() & TcpHeader::ACK));
1820 
1821  uint32_t previousLost = m_txBuffer->GetLost();
1822  uint32_t priorInFlight = m_tcb->m_bytesInFlight.Get();
1823 
1824  // RFC 6675, Section 5, 1st paragraph:
1825  // Upon the receipt of any ACK containing SACK information, the
1826  // scoreboard MUST be updated via the Update () routine (done in ReadOptions)
1827  uint32_t bytesSacked = 0;
1828  uint64_t previousDelivered = m_rateOps->GetConnectionRate().m_delivered;
1829  ReadOptions(tcpHeader, &bytesSacked);
1830 
1831  SequenceNumber32 ackNumber = tcpHeader.GetAckNumber();
1832  SequenceNumber32 oldHeadSequence = m_txBuffer->HeadSequence();
1833 
1834  if (ackNumber < oldHeadSequence)
1835  {
1836  NS_LOG_DEBUG("Possibly received a stale ACK (ack number < head sequence)");
1837  // If there is any data piggybacked, store it into m_rxBuffer
1838  if (packet->GetSize() > 0)
1839  {
1840  ReceivedData(packet, tcpHeader);
1841  }
1842  return;
1843  }
1844  if ((ackNumber > oldHeadSequence) && (ackNumber < m_recover) &&
1846  {
1847  uint32_t segAcked = (ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
1848  for (uint32_t i = 0; i < segAcked; i++)
1849  {
1850  if (m_txBuffer->IsRetransmittedDataAcked(ackNumber - (i * m_tcb->m_segmentSize)))
1851  {
1852  m_tcb->m_isRetransDataAcked = true;
1853  NS_LOG_DEBUG("Ack Number " << ackNumber << "is ACK of retransmitted packet.");
1854  }
1855  }
1856  }
1857 
1858  m_txBuffer->DiscardUpTo(ackNumber, MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
1859 
1860  uint32_t currentDelivered =
1861  static_cast<uint32_t>(m_rateOps->GetConnectionRate().m_delivered - previousDelivered);
1862  m_tcb->m_lastAckedSackedBytes = currentDelivered;
1863 
1864  if (m_tcb->m_congState == TcpSocketState::CA_CWR && (ackNumber > m_recover))
1865  {
1866  // Recovery is over after the window exceeds m_recover
1867  // (although it may be re-entered below if ECE is still set)
1870  if (!m_congestionControl->HasCongControl())
1871  {
1873  m_recoveryOps->ExitRecovery(m_tcb);
1875  }
1876  }
1877 
1878  if (ackNumber > oldHeadSequence && (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED) &&
1879  (tcpHeader.GetFlags() & TcpHeader::ECE))
1880  {
1881  if (m_ecnEchoSeq < ackNumber)
1882  {
1883  NS_LOG_INFO("Received ECN Echo is valid");
1884  m_ecnEchoSeq = ackNumber;
1885  NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_RCVD");
1888  {
1889  EnterCwr(currentDelivered);
1890  }
1891  }
1892  }
1894  !(tcpHeader.GetFlags() & TcpHeader::ECE))
1895  {
1897  }
1898 
1899  // Update bytes in flight before processing the ACK for proper calculation of congestion window
1900  NS_LOG_INFO("Update bytes in flight before processing the ACK.");
1901  BytesInFlight();
1902 
1903  // RFC 6675 Section 5: 2nd, 3rd paragraph and point (A), (B) implementation
1904  // are inside the function ProcessAck
1905  ProcessAck(ackNumber, (bytesSacked > 0), currentDelivered, oldHeadSequence);
1906  m_tcb->m_isRetransDataAcked = false;
1907 
1908  if (m_congestionControl->HasCongControl())
1909  {
1910  uint32_t currentLost = m_txBuffer->GetLost();
1911  uint32_t lost =
1912  (currentLost > previousLost) ? currentLost - previousLost : previousLost - currentLost;
1913  auto rateSample = m_rateOps->GenerateSample(currentDelivered,
1914  lost,
1915  false,
1916  priorInFlight,
1917  m_tcb->m_minRtt);
1918  auto rateConn = m_rateOps->GetConnectionRate();
1919  m_congestionControl->CongControl(m_tcb, rateConn, rateSample);
1920  }
1921 
1922  // If there is any data piggybacked, store it into m_rxBuffer
1923  if (packet->GetSize() > 0)
1924  {
1925  ReceivedData(packet, tcpHeader);
1926  }
1927 
1928  // RFC 6675, Section 5, point (C), try to send more data. NB: (C) is implemented
1929  // inside SendPendingData
1931 }
1932 
1933 void
1935  bool scoreboardUpdated,
1936  uint32_t currentDelivered,
1937  const SequenceNumber32& oldHeadSequence)
1938 {
1939  NS_LOG_FUNCTION(this << ackNumber << scoreboardUpdated);
1940  // RFC 6675, Section 5, 2nd paragraph:
1941  // If the incoming ACK is a cumulative acknowledgment, the TCP MUST
1942  // reset DupAcks to zero.
1943  bool exitedFastRecovery = false;
1944  uint32_t oldDupAckCount = m_dupAckCount; // remember the old value
1945  m_tcb->m_lastAckedSeq = ackNumber; // Update lastAckedSeq
1946  uint32_t bytesAcked = 0;
1947 
1948  /* In RFC 5681 the definition of duplicate acknowledgment was strict:
1949  *
1950  * (a) the receiver of the ACK has outstanding data,
1951  * (b) the incoming acknowledgment carries no data,
1952  * (c) the SYN and FIN bits are both off,
1953  * (d) the acknowledgment number is equal to the greatest acknowledgment
1954  * received on the given connection (TCP.UNA from [RFC793]),
1955  * (e) the advertised window in the incoming acknowledgment equals the
1956  * advertised window in the last incoming acknowledgment.
1957  *
1958  * With RFC 6675, this definition has been reduced:
1959  *
1960  * (a) the ACK is carrying a SACK block that identifies previously
1961  * unacknowledged and un-SACKed octets between HighACK (TCP.UNA) and
1962  * HighData (m_highTxMark)
1963  */
1964 
1965  bool isDupack = m_sackEnabled ? scoreboardUpdated
1966  : ackNumber == oldHeadSequence && ackNumber < m_tcb->m_highTxMark;
1967 
1968  NS_LOG_DEBUG("ACK of " << ackNumber << " SND.UNA=" << oldHeadSequence
1969  << " SND.NXT=" << m_tcb->m_nextTxSequence
1970  << " in state: " << TcpSocketState::TcpCongStateName[m_tcb->m_congState]
1971  << " with m_recover: " << m_recover);
1972 
1973  // RFC 6675, Section 5, 3rd paragraph:
1974  // If the incoming ACK is a duplicate acknowledgment per the definition
1975  // in Section 2 (regardless of its status as a cumulative
1976  // acknowledgment), and the TCP is not currently in loss recovery
1977  if (isDupack)
1978  {
1979  // loss recovery check is done inside this function thanks to
1980  // the congestion state machine
1981  DupAck(currentDelivered);
1982  }
1983 
1984  if (ackNumber == oldHeadSequence && ackNumber == m_tcb->m_highTxMark)
1985  {
1986  // Dupack, but the ACK is precisely equal to the nextTxSequence
1987  return;
1988  }
1989  else if (ackNumber == oldHeadSequence && ackNumber > m_tcb->m_highTxMark)
1990  {
1991  // ACK of the FIN bit ... nextTxSequence is not updated since we
1992  // don't have anything to transmit
1993  NS_LOG_DEBUG("Update nextTxSequence manually to " << ackNumber);
1994  m_tcb->m_nextTxSequence = ackNumber;
1995  }
1996  else if (ackNumber == oldHeadSequence)
1997  {
1998  // DupAck. Artificially call PktsAcked: after all, one segment has been ACKed.
1999  m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_lastRtt);
2000  }
2001  else if (ackNumber > oldHeadSequence)
2002  {
2003  // Please remember that, with SACK, we can enter here even if we
2004  // received a dupack.
2005  bytesAcked = ackNumber - oldHeadSequence;
2006  uint32_t segsAcked = bytesAcked / m_tcb->m_segmentSize;
2007  m_bytesAckedNotProcessed += bytesAcked % m_tcb->m_segmentSize;
2008  bytesAcked -= bytesAcked % m_tcb->m_segmentSize;
2009 
2011  {
2012  segsAcked += 1;
2013  bytesAcked += m_tcb->m_segmentSize;
2015  }
2016 
2017  // Dupack count is reset to eventually fast-retransmit after 3 dupacks.
2018  // Any SACK-ed segment will be cleaned up by DiscardUpTo.
2019  // In the case that we advanced SND.UNA, but the ack contains SACK blocks,
2020  // we do not reset. At the third one we will retransmit.
2021  // If we are already in recovery, this check is useless since dupAcks
2022  // are not considered in this phase. When from Recovery we go back
2023  // to open, then dupAckCount is reset anyway.
2024  if (!isDupack)
2025  {
2026  m_dupAckCount = 0;
2027  }
2028 
2029  // RFC 6675, Section 5, part (B)
2030  // (B) Upon receipt of an ACK that does not cover RecoveryPoint, the
2031  // following actions MUST be taken:
2032  //
2033  // (B.1) Use Update () to record the new SACK information conveyed
2034  // by the incoming ACK.
2035  // (B.2) Use SetPipe () to re-calculate the number of octets still
2036  // in the network.
2037  //
2038  // (B.1) is done at the beginning, while (B.2) is delayed to part (C) while
2039  // trying to transmit with SendPendingData. We are not allowed to exit
2040  // the CA_RECOVERY phase. Just process this partial ack (RFC 5681)
2041  if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
2042  {
2043  if (!m_sackEnabled)
2044  {
2045  // Manually set the head as lost, it will be retransmitted.
2046  NS_LOG_INFO("Partial ACK. Manually setting head as lost");
2047  m_txBuffer->MarkHeadAsLost();
2048  }
2049 
2050  // Before retransmitting the packet perform DoRecovery and check if
2051  // there is available window
2052  if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2053  {
2054  m_recoveryOps->DoRecovery(m_tcb, currentDelivered);
2055  }
2056 
2057  // If the packet is already retransmitted do not retransmit it
2058  if (!m_txBuffer->IsRetransmittedDataAcked(ackNumber + m_tcb->m_segmentSize))
2059  {
2060  DoRetransmit(); // Assume the next seq is lost. Retransmit lost packet
2061  m_tcb->m_cWndInfl = SafeSubtraction(m_tcb->m_cWndInfl, bytesAcked);
2062  }
2063 
2064  // This partial ACK acknowledge the fact that one segment has been
2065  // previously lost and now successfully received. All others have
2066  // been processed when they come under the form of dupACKs
2067  m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_lastRtt);
2068  NewAck(ackNumber, m_isFirstPartialAck);
2069 
2070  if (m_isFirstPartialAck)
2071  {
2072  NS_LOG_DEBUG("Partial ACK of " << ackNumber
2073  << " and this is the first (RTO will be reset);"
2074  " cwnd set to "
2075  << m_tcb->m_cWnd << " recover seq: " << m_recover
2076  << " dupAck count: " << m_dupAckCount);
2077  m_isFirstPartialAck = false;
2078  }
2079  else
2080  {
2081  NS_LOG_DEBUG("Partial ACK of "
2082  << ackNumber
2083  << " and this is NOT the first (RTO will not be reset)"
2084  " cwnd set to "
2085  << m_tcb->m_cWnd << " recover seq: " << m_recover
2086  << " dupAck count: " << m_dupAckCount);
2087  }
2088  }
2089  // From RFC 6675 section 5.1
2090  // In addition, a new recovery phase (as described in Section 5) MUST NOT
2091  // be initiated until HighACK is greater than or equal to the new value
2092  // of RecoveryPoint.
2093  else if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_LOSS)
2094  {
2095  m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_lastRtt);
2096  m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2097 
2098  NS_LOG_DEBUG(" Cong Control Called, cWnd=" << m_tcb->m_cWnd
2099  << " ssTh=" << m_tcb->m_ssThresh);
2100  if (!m_sackEnabled)
2101  {
2102  NS_ASSERT_MSG(
2103  m_txBuffer->GetSacked() == 0,
2104  "Some segment got dup-acked in CA_LOSS state: " << m_txBuffer->GetSacked());
2105  }
2106  NewAck(ackNumber, true);
2107  }
2109  {
2110  m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_lastRtt);
2111  // TODO: need to check behavior if marking is compounded by loss
2112  // and/or packet reordering
2113  if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2114  {
2115  m_recoveryOps->DoRecovery(m_tcb, currentDelivered);
2116  }
2117  NewAck(ackNumber, true);
2118  }
2119  else
2120  {
2122  {
2123  m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_lastRtt);
2124  }
2126  {
2127  if (segsAcked >= oldDupAckCount)
2128  {
2129  m_congestionControl->PktsAcked(m_tcb,
2130  segsAcked - oldDupAckCount,
2131  m_tcb->m_lastRtt);
2132  }
2133 
2134  if (!isDupack)
2135  {
2136  // The network reorder packets. Linux changes the counting lost
2137  // packet algorithm from FACK to NewReno. We simply go back in Open.
2138  m_congestionControl->CongestionStateSet(m_tcb, TcpSocketState::CA_OPEN);
2140  NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2141  << " exiting CA_DISORDER -> CA_OPEN");
2142  }
2143  else
2144  {
2145  NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2146  << " but still in CA_DISORDER");
2147  }
2148  }
2149  // RFC 6675, Section 5:
2150  // Once a TCP is in the loss recovery phase, the following procedure
2151  // MUST be used for each arriving ACK:
2152  // (A) An incoming cumulative ACK for a sequence number greater than
2153  // RecoveryPoint signals the end of loss recovery, and the loss
2154  // recovery phase MUST be terminated. Any information contained in
2155  // the scoreboard for sequence numbers greater than the new value of
2156  // HighACK SHOULD NOT be cleared when leaving the loss recovery
2157  // phase.
2159  {
2160  m_isFirstPartialAck = true;
2161 
2162  // Recalculate the segs acked, that are from m_recover to ackNumber
2163  // (which are the ones we have not passed to PktsAcked and that
2164  // can increase cWnd)
2165  // TODO: check consistency for dynamic segment size
2166  segsAcked =
2167  static_cast<uint32_t>(ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
2168  m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_lastRtt);
2170  m_congestionControl->CongestionStateSet(m_tcb, TcpSocketState::CA_OPEN);
2172  exitedFastRecovery = true;
2173  m_dupAckCount = 0; // From recovery to open, reset dupack
2174 
2175  NS_LOG_DEBUG(segsAcked << " segments acked in CA_RECOVER, ack of " << ackNumber
2176  << ", exiting CA_RECOVERY -> CA_OPEN");
2177  }
2179  {
2180  m_isFirstPartialAck = true;
2181 
2182  // Recalculate the segs acked, that are from m_recover to ackNumber
2183  // (which are the ones we have not passed to PktsAcked and that
2184  // can increase cWnd)
2185  segsAcked = (ackNumber - m_recover) / m_tcb->m_segmentSize;
2186 
2187  m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_lastRtt);
2188 
2189  m_congestionControl->CongestionStateSet(m_tcb, TcpSocketState::CA_OPEN);
2191  NS_LOG_DEBUG(segsAcked << " segments acked in CA_LOSS, ack of" << ackNumber
2192  << ", exiting CA_LOSS -> CA_OPEN");
2193  }
2194 
2195  if (ackNumber >= m_recover)
2196  {
2197  // All lost segments in the congestion event have been
2198  // retransmitted successfully. The recovery point (m_recover)
2199  // should be deactivated.
2200  m_recoverActive = false;
2201  }
2202 
2203  if (exitedFastRecovery)
2204  {
2205  NewAck(ackNumber, true);
2207  m_recoveryOps->ExitRecovery(m_tcb);
2208  NS_LOG_DEBUG("Leaving Fast Recovery; BytesInFlight() = "
2209  << BytesInFlight() << "; cWnd = " << m_tcb->m_cWnd);
2210  }
2212  {
2213  m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2214 
2216 
2217  NS_LOG_LOGIC("Congestion control called: "
2218  << " cWnd: " << m_tcb->m_cWnd << " ssTh: " << m_tcb->m_ssThresh
2219  << " segsAcked: " << segsAcked);
2220 
2221  NewAck(ackNumber, true);
2222  }
2223  }
2224  }
2225  // Update the pacing rate, since m_congestionControl->IncreaseWindow() or
2226  // m_congestionControl->PktsAcked () may change m_tcb->m_cWnd
2227  // Make sure that control reaches the end of this function and there is no
2228  // return in between
2229  UpdatePacingRate();
2230 }
2231 
2232 /* Received a packet upon LISTEN state. */
2233 void
2235  const TcpHeader& tcpHeader,
2236  const Address& fromAddress,
2237  const Address& toAddress)
2238 {
2239  NS_LOG_FUNCTION(this << tcpHeader);
2240 
2241  // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2242  uint8_t tcpflags =
2244 
2245  // Fork a socket if received a SYN. Do nothing otherwise.
2246  // C.f.: the LISTEN part in tcp_v4_do_rcv() in tcp_ipv4.c in Linux kernel
2247  if (tcpflags != TcpHeader::SYN)
2248  {
2249  return;
2250  }
2251 
2252  // Call socket's notify function to let the server app know we got a SYN
2253  // If the server app refuses the connection, do nothing
2254  if (!NotifyConnectionRequest(fromAddress))
2255  {
2256  return;
2257  }
2258  // Clone the socket, simulate fork
2259  Ptr<TcpSocketBase> newSock = Fork();
2260  NS_LOG_LOGIC("Cloned a TcpSocketBase " << newSock);
2262  newSock,
2263  packet,
2264  tcpHeader,
2265  fromAddress,
2266  toAddress);
2267 }
2268 
2269 /* Received a packet upon SYN_SENT */
2270 void
2272 {
2273  NS_LOG_FUNCTION(this << tcpHeader);
2274 
2275  // Extract the flags. PSH and URG are disregarded.
2276  uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2277 
2278  if (tcpflags == 0)
2279  { // Bare data, accept it and move to ESTABLISHED state. This is not a normal behaviour. Remove
2280  // this?
2281  NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2282  m_congestionControl->CongestionStateSet(m_tcb, TcpSocketState::CA_OPEN);
2284  m_state = ESTABLISHED;
2285  m_connected = true;
2286  m_retxEvent.Cancel();
2288  ReceivedData(packet, tcpHeader);
2290  }
2291  else if (tcpflags & TcpHeader::ACK && !(tcpflags & TcpHeader::SYN))
2292  { // Ignore ACK in SYN_SENT
2293  }
2294  else if (tcpflags & TcpHeader::SYN && !(tcpflags & TcpHeader::ACK))
2295  { // Received SYN, move to SYN_RCVD state and respond with SYN+ACK
2296  NS_LOG_DEBUG("SYN_SENT -> SYN_RCVD");
2297  m_state = SYN_RCVD;
2299  m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2300  /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2301  * the traffic is ECN capable and sender has sent ECN SYN packet
2302  */
2303 
2306  {
2307  NS_LOG_INFO("Received ECN SYN packet");
2311  }
2312  else
2313  {
2316  }
2317  }
2318  else if (tcpflags & (TcpHeader::SYN | TcpHeader::ACK) &&
2319  m_tcb->m_nextTxSequence + SequenceNumber32(1) == tcpHeader.GetAckNumber())
2320  { // Handshake completed
2321  NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2322  m_congestionControl->CongestionStateSet(m_tcb, TcpSocketState::CA_OPEN);
2324  m_state = ESTABLISHED;
2325  m_connected = true;
2326  m_retxEvent.Cancel();
2327  m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2329  m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2330  // Before sending packets, update the pacing rate based on RTT measurement so far
2331  UpdatePacingRate();
2333 
2334  /* Check if we received an ECN SYN-ACK packet. Change the ECN state of sender to ECN_IDLE if
2335  * receiver has sent an ECN SYN-ACK packet and the traffic is ECN Capable
2336  */
2338  (tcpflags & (TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::ECE))
2339  {
2340  NS_LOG_INFO("Received ECN SYN-ACK packet.");
2343  }
2344  else
2345  {
2347  }
2350  // Always respond to first data packet to speed up the connection.
2351  // Remove to get the behaviour of old NS-3 code.
2353  }
2354  else
2355  { // Other in-sequence input
2356  if (!(tcpflags & TcpHeader::RST))
2357  { // When (1) rx of FIN+ACK; (2) rx of FIN; (3) rx of bad flags
2358  NS_LOG_LOGIC("Illegal flag combination "
2359  << TcpHeader::FlagsToString(tcpHeader.GetFlags())
2360  << " received in SYN_SENT. Reset packet is sent.");
2361  SendRST();
2362  }
2363  CloseAndNotify();
2364  }
2365 }
2366 
2367 /* Received a packet upon SYN_RCVD */
2368 void
2370  const TcpHeader& tcpHeader,
2371  const Address& fromAddress,
2372  const Address& /* toAddress */)
2373 {
2374  NS_LOG_FUNCTION(this << tcpHeader);
2375 
2376  // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2377  uint8_t tcpflags =
2379 
2380  if (tcpflags == 0 ||
2381  (tcpflags == TcpHeader::ACK &&
2382  m_tcb->m_nextTxSequence + SequenceNumber32(1) == tcpHeader.GetAckNumber()))
2383  { // If it is bare data, accept it and move to ESTABLISHED state. This is
2384  // possibly due to ACK lost in 3WHS. If in-sequence ACK is received, the
2385  // handshake is completed nicely.
2386  NS_LOG_DEBUG("SYN_RCVD -> ESTABLISHED");
2387  m_congestionControl->CongestionStateSet(m_tcb, TcpSocketState::CA_OPEN);
2389  m_state = ESTABLISHED;
2390  m_connected = true;
2391  m_retxEvent.Cancel();
2393  m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2394  if (m_endPoint)
2395  {
2396  m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2397  InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2398  }
2399  else if (m_endPoint6)
2400  {
2401  m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2402  Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2403  }
2404  // Always respond to first data packet to speed up the connection.
2405  // Remove to get the behaviour of old NS-3 code.
2407  NotifyNewConnectionCreated(this, fromAddress);
2408  ReceivedAck(packet, tcpHeader);
2409  // Update the pacing rate based on RTT measurement so far
2410  UpdatePacingRate();
2411  // As this connection is established, the socket is available to send data now
2412  if (GetTxAvailable() > 0)
2413  {
2415  }
2416  }
2417  else if (tcpflags == TcpHeader::SYN)
2418  { // Probably the peer lost my SYN+ACK
2419  m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2420  /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2421  * sender has sent an ECN SYN packet and the traffic is ECN Capable
2422  */
2424  (tcpHeader.GetFlags() & (TcpHeader::CWR | TcpHeader::ECE)) ==
2426  {
2427  NS_LOG_INFO("Received ECN SYN packet");
2431  }
2432  else
2433  {
2436  }
2437  }
2438  else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2439  {
2440  if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2441  { // In-sequence FIN before connection complete. Set up connection and close.
2442  m_connected = true;
2443  m_retxEvent.Cancel();
2445  m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2446  if (m_endPoint)
2447  {
2448  m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2449  InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2450  }
2451  else if (m_endPoint6)
2452  {
2453  m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2454  Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2455  }
2456  NotifyNewConnectionCreated(this, fromAddress);
2457  PeerClose(packet, tcpHeader);
2458  }
2459  }
2460  else
2461  { // Other in-sequence input
2462  if (tcpflags != TcpHeader::RST)
2463  { // When (1) rx of SYN+ACK; (2) rx of FIN; (3) rx of bad flags
2464  NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2465  << " received. Reset packet is sent.");
2466  if (m_endPoint)
2467  {
2468  m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2469  InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2470  }
2471  else if (m_endPoint6)
2472  {
2473  m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2474  Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2475  }
2476  SendRST();
2477  }
2478  CloseAndNotify();
2479  }
2480 }
2481 
2482 /* Received a packet upon CLOSE_WAIT, FIN_WAIT_1, or FIN_WAIT_2 states */
2483 void
2485 {
2486  NS_LOG_FUNCTION(this << tcpHeader);
2487 
2488  // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2489  uint8_t tcpflags =
2491 
2492  if (packet->GetSize() > 0 && !(tcpflags & TcpHeader::ACK))
2493  { // Bare data, accept it
2494  ReceivedData(packet, tcpHeader);
2495  }
2496  else if (tcpflags == TcpHeader::ACK)
2497  { // Process the ACK, and if in FIN_WAIT_1, conditionally move to FIN_WAIT_2
2498  ReceivedAck(packet, tcpHeader);
2499  if (m_state == FIN_WAIT_1 && m_txBuffer->Size() == 0 &&
2500  tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2501  { // This ACK corresponds to the FIN sent
2502  NS_LOG_DEBUG("FIN_WAIT_1 -> FIN_WAIT_2");
2503  m_state = FIN_WAIT_2;
2504  }
2505  }
2506  else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2507  { // Got FIN, respond with ACK and move to next state
2508  if (tcpflags & TcpHeader::ACK)
2509  { // Process the ACK first
2510  ReceivedAck(packet, tcpHeader);
2511  }
2512  m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber());
2513  }
2514  else if (tcpflags == TcpHeader::SYN || tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
2515  { // Duplicated SYN or SYN+ACK, possibly due to spurious retransmission
2516  return;
2517  }
2518  else
2519  { // This is a RST or bad flags
2520  if (tcpflags != TcpHeader::RST)
2521  {
2522  NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2523  << " received. Reset packet is sent.");
2524  SendRST();
2525  }
2526  CloseAndNotify();
2527  return;
2528  }
2529 
2530  // Check if the close responder sent an in-sequence FIN, if so, respond ACK
2531  if ((m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2) && m_tcb->m_rxBuffer->Finished())
2532  {
2533  if (m_state == FIN_WAIT_1)
2534  {
2535  NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2536  m_state = CLOSING;
2537  if (m_txBuffer->Size() == 0 &&
2538  tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2539  { // This ACK corresponds to the FIN sent
2540  TimeWait();
2541  }
2542  }
2543  else if (m_state == FIN_WAIT_2)
2544  {
2545  TimeWait();
2546  }
2548  if (!m_shutdownRecv)
2549  {
2550  NotifyDataRecv();
2551  }
2552  }
2553 }
2554 
2555 /* Received a packet upon CLOSING */
2556 void
2558 {
2559  NS_LOG_FUNCTION(this << tcpHeader);
2560 
2561  // Extract the flags. PSH and URG are disregarded.
2562  uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2563 
2564  if (tcpflags == TcpHeader::ACK)
2565  {
2566  if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2567  { // This ACK corresponds to the FIN sent
2568  TimeWait();
2569  }
2570  }
2571  else
2572  { // CLOSING state means simultaneous close, i.e. no one is sending data to
2573  // anyone. If anything other than ACK is received, respond with a reset.
2574  if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2575  { // FIN from the peer as well. We can close immediately.
2577  }
2578  else if (tcpflags != TcpHeader::RST)
2579  { // Receive of SYN or SYN+ACK or bad flags or pure data
2580  NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2581  << " received. Reset packet is sent.");
2582  SendRST();
2583  }
2584  CloseAndNotify();
2585  }
2586 }
2587 
2588 /* Received a packet upon LAST_ACK */
2589 void
2591 {
2592  NS_LOG_FUNCTION(this << tcpHeader);
2593 
2594  // Extract the flags. PSH and URG are disregarded.
2595  uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2596 
2597  if (tcpflags == 0)
2598  {
2599  ReceivedData(packet, tcpHeader);
2600  }
2601  else if (tcpflags == TcpHeader::ACK)
2602  {
2603  if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2604  { // This ACK corresponds to the FIN sent. This socket closed peacefully.
2605  CloseAndNotify();
2606  }
2607  }
2608  else if (tcpflags == TcpHeader::FIN)
2609  { // Received FIN again, the peer probably lost the FIN+ACK
2611  }
2612  else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK) || tcpflags == TcpHeader::RST)
2613  {
2614  CloseAndNotify();
2615  }
2616  else
2617  { // Received a SYN or SYN+ACK or bad flags
2618  NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2619  << " received. Reset packet is sent.");
2620  SendRST();
2621  CloseAndNotify();
2622  }
2623 }
2624 
2625 /* Peer sent me a FIN. Remember its sequence in rx buffer. */
2626 void
2628 {
2629  NS_LOG_FUNCTION(this << tcpHeader);
2630 
2631  // Ignore all out of range packets
2632  if (tcpHeader.GetSequenceNumber() < m_tcb->m_rxBuffer->NextRxSequence() ||
2633  tcpHeader.GetSequenceNumber() > m_tcb->m_rxBuffer->MaxRxSequence())
2634  {
2635  return;
2636  }
2637  // For any case, remember the FIN position in rx buffer first
2638  m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber() +
2639  SequenceNumber32(p->GetSize()));
2640  NS_LOG_LOGIC("Accepted FIN at seq "
2641  << tcpHeader.GetSequenceNumber() + SequenceNumber32(p->GetSize()));
2642  // If there is any piggybacked data, process it
2643  if (p->GetSize())
2644  {
2645  ReceivedData(p, tcpHeader);
2646  }
2647  // Return if FIN is out of sequence, otherwise move to CLOSE_WAIT state by DoPeerClose
2648  if (!m_tcb->m_rxBuffer->Finished())
2649  {
2650  return;
2651  }
2652 
2653  // Simultaneous close: Application invoked Close() when we are processing this FIN packet
2654  if (m_state == FIN_WAIT_1)
2655  {
2656  NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2657  m_state = CLOSING;
2658  return;
2659  }
2660 
2661  DoPeerClose(); // Change state, respond with ACK
2662 }
2663 
2664 /* Received a in-sequence FIN. Close down this socket. */
2665 void
2667 {
2669  m_state == FIN_WAIT_2);
2670 
2671  // Move the state to CLOSE_WAIT
2672  NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSE_WAIT");
2673  m_state = CLOSE_WAIT;
2674 
2675  if (!m_closeNotified)
2676  {
2677  // The normal behaviour for an application is that, when the peer sent a in-sequence
2678  // FIN, the app should prepare to close. The app has two choices at this point: either
2679  // respond with ShutdownSend() call to declare that it has nothing more to send and
2680  // the socket can be closed immediately; or remember the peer's close request, wait
2681  // until all its existing data are pushed into the TCP socket, then call Close()
2682  // explicitly.
2683  NS_LOG_LOGIC("TCP " << this << " calling NotifyNormalClose");
2685  m_closeNotified = true;
2686  }
2687  if (m_shutdownSend)
2688  { // The application declares that it would not sent any more, close this socket
2689  Close();
2690  }
2691  else
2692  { // Need to ack, the application will close later
2694  }
2695  if (m_state == LAST_ACK)
2696  {
2697  m_dataRetrCount = m_dataRetries; // prevent endless FINs
2698  NS_LOG_LOGIC("TcpSocketBase " << this << " scheduling LATO1");
2699  Time lastRto = m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4);
2701  }
2702 }
2703 
2704 /* Kill this socket. This is a callback function configured to m_endpoint in
2705  SetupCallback(), invoked when the endpoint is destroyed. */
2706 void
2708 {
2709  NS_LOG_FUNCTION(this);
2710  m_endPoint = nullptr;
2711  if (m_tcp)
2712  {
2713  m_tcp->RemoveSocket(this);
2714  }
2715  NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2716  << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2717  CancelAllTimers();
2718 }
2719 
2720 /* Kill this socket. This is a callback function configured to m_endpoint in
2721  SetupCallback(), invoked when the endpoint is destroyed. */
2722 void
2724 {
2725  NS_LOG_FUNCTION(this);
2726  m_endPoint6 = nullptr;
2727  if (m_tcp)
2728  {
2729  m_tcp->RemoveSocket(this);
2730  }
2731  NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2732  << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2733  CancelAllTimers();
2734 }
2735 
2736 /* Send an empty packet with specified TCP flags */
2737 void
2739 {
2740  NS_LOG_FUNCTION(this << static_cast<uint32_t>(flags));
2741 
2742  if (m_endPoint == nullptr && m_endPoint6 == nullptr)
2743  {
2744  NS_LOG_WARN("Failed to send empty packet due to null endpoint");
2745  return;
2746  }
2747 
2748  Ptr<Packet> p = Create<Packet>();
2749  TcpHeader header;
2751 
2752  if (flags & TcpHeader::FIN)
2753  {
2754  flags |= TcpHeader::ACK;
2755  }
2756  else if (m_state == FIN_WAIT_1 || m_state == LAST_ACK || m_state == CLOSING)
2757  {
2758  ++s;
2759  }
2760 
2761  AddSocketTags(p);
2762 
2763  header.SetFlags(flags);
2764  header.SetSequenceNumber(s);
2765  header.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
2766  if (m_endPoint != nullptr)
2767  {
2770  }
2771  else
2772  {
2775  }
2776  AddOptions(header);
2777 
2778  // RFC 6298, clause 2.4
2779  m_rto =
2780  Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4), m_minRto);
2781 
2782  uint16_t windowSize = AdvertisedWindowSize();
2783  bool hasSyn = flags & TcpHeader::SYN;
2784  bool hasFin = flags & TcpHeader::FIN;
2785  bool isAck = flags == TcpHeader::ACK;
2786  if (hasSyn)
2787  {
2788  if (m_winScalingEnabled)
2789  { // The window scaling option is set only on SYN packets
2790  AddOptionWScale(header);
2791  }
2792 
2793  if (m_sackEnabled)
2794  {
2795  AddOptionSackPermitted(header);
2796  }
2797 
2798  if (m_synCount == 0)
2799  { // No more connection retries, give up
2800  NS_LOG_LOGIC("Connection failed.");
2801  m_rtt->Reset(); // According to recommendation -> RFC 6298
2803  m_state = CLOSED;
2805  return;
2806  }
2807  else
2808  { // Exponential backoff of connection time out
2809  int backoffCount = 0x1 << (m_synRetries - m_synCount);
2810  m_rto = m_cnTimeout * backoffCount;
2811  m_synCount--;
2812  }
2813 
2814  if (m_synRetries - 1 == m_synCount)
2815  {
2816  UpdateRttHistory(s, 0, false);
2817  }
2818  else
2819  { // This is SYN retransmission
2820  UpdateRttHistory(s, 0, true);
2821  }
2822 
2823  windowSize = AdvertisedWindowSize(false);
2824  }
2825  header.SetWindowSize(windowSize);
2826 
2827  if (flags & TcpHeader::ACK)
2828  { // If sending an ACK, cancel the delay ACK as well
2830  m_delAckCount = 0;
2831  if (m_highTxAck < header.GetAckNumber())
2832  {
2833  m_highTxAck = header.GetAckNumber();
2834  }
2835  if (m_sackEnabled && m_tcb->m_rxBuffer->GetSackListSize() > 0)
2836  {
2837  AddOptionSack(header);
2838  }
2839  NS_LOG_INFO("Sending a pure ACK, acking seq " << m_tcb->m_rxBuffer->NextRxSequence());
2840  }
2841 
2842  m_txTrace(p, header, this);
2843 
2844  if (m_endPoint != nullptr)
2845  {
2846  m_tcp->SendPacket(p,
2847  header,
2851  }
2852  else
2853  {
2854  m_tcp->SendPacket(p,
2855  header,
2859  }
2860 
2861  if (m_retxEvent.IsExpired() && (hasSyn || hasFin) && !isAck)
2862  { // Retransmit SYN / SYN+ACK / FIN / FIN+ACK to guard against lost
2863  NS_LOG_LOGIC("Schedule retransmission timeout at time "
2864  << Simulator::Now().GetSeconds() << " to expire at time "
2865  << (Simulator::Now() + m_rto.Get()).GetSeconds());
2867  }
2868 }
2869 
2870 /* This function closes the endpoint completely. Called upon RST_TX action. */
2871 void
2873 {
2874  NS_LOG_FUNCTION(this);
2876  NotifyErrorClose();
2878 }
2879 
2880 /* Deallocate the end point and cancel all the timers */
2881 void
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);
2907  Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4>();
2908  NS_ASSERT(ipv4);
2909  if (!ipv4->GetRoutingProtocol())
2910  {
2911  NS_FATAL_ERROR("No Ipv4RoutingProtocol in the node");
2912  }
2913  // Create a dummy packet, then ask the routing function for the best output
2914  // interface's address
2915  Ipv4Header header;
2917  Socket::SocketErrno errno_;
2918  Ptr<Ipv4Route> route;
2920  route = ipv4->GetRoutingProtocol()->RouteOutput(Ptr<Packet>(), header, oif, errno_);
2921  if (!route)
2922  {
2923  NS_LOG_LOGIC("Route to " << m_endPoint->GetPeerAddress() << " does not exist");
2924  NS_LOG_ERROR(errno_);
2925  m_errno = errno_;
2926  return -1;
2927  }
2928  NS_LOG_LOGIC("Route exists");
2929  m_endPoint->SetLocalAddress(route->GetSource());
2930  return 0;
2931 }
2932 
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 == false)
3271  { // This is the next expected one, just log at end
3272  m_history.emplace_back(seq, sz, Simulator::Now());
3273  }
3274  else
3275  { // This is a retransmit, find in list and mark as re-tx
3276  for (std::deque<RttHistory>::iterator i = m_history.begin(); i != m_history.end(); ++i)
3277  {
3278  if ((seq >= i->seq) && (seq < (i->seq + SequenceNumber32(i->count))))
3279  { // Found it
3280  i->retx = true;
3281  i->count = ((seq + SequenceNumber32(sz)) - i->seq); // And update count in hist
3282  break;
3283  }
3284  }
3285  }
3286 }
3287 
3288 // Note that this function did not implement the PSH flag
3289 uint32_t
3291 {
3292  NS_LOG_FUNCTION(this << withAck);
3293  if (m_txBuffer->Size() == 0)
3294  {
3295  return false; // Nothing to send
3296  }
3297  if (m_endPoint == nullptr && m_endPoint6 == nullptr)
3298  {
3299  NS_LOG_INFO(
3300  "TcpSocketBase::SendPendingData: No endpoint; m_shutdownSend=" << m_shutdownSend);
3301  return false; // Is this the right way to handle this condition?
3302  }
3303 
3304  uint32_t nPacketsSent = 0;
3305  uint32_t availableWindow = AvailableWindow();
3306 
3307  // RFC 6675, Section (C)
3308  // If cwnd - pipe >= 1 SMSS, the sender SHOULD transmit one or more
3309  // segments as follows:
3310  // (NOTE: We check > 0, and do the checks for segmentSize in the following
3311  // else branch to control silly window syndrome and Nagle)
3312  while (availableWindow > 0)
3313  {
3314  if (IsPacingEnabled())
3315  {
3316  NS_LOG_INFO("Pacing is enabled");
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  uint32_t maxSizeToSend = static_cast<uint32_t>(nextHigh - next);
3375  s = std::min(s, maxSizeToSend);
3376 
3377  // (C.2) If any of the data octets sent in (C.1) are below HighData,
3378  // HighRxt MUST be set to the highest sequence number of the
3379  // retransmitted segment unless NextSeg () rule (4) was
3380  // invoked for this retransmission.
3381  // (C.3) If any of the data octets sent in (C.1) are above HighData,
3382  // HighData must be updated to reflect the transmission of
3383  // previously unsent data.
3384  //
3385  // These steps are done in m_txBuffer with the tags.
3386  if (m_tcb->m_nextTxSequence != next)
3387  {
3388  m_tcb->m_nextTxSequence = next;
3389  }
3390  if (m_tcb->m_bytesInFlight.Get() == 0)
3391  {
3393  }
3394  uint32_t sz = SendDataPacket(m_tcb->m_nextTxSequence, s, withAck);
3395 
3396  NS_LOG_LOGIC(" rxwin " << m_rWnd << " segsize " << m_tcb->m_segmentSize
3397  << " highestRxAck " << m_txBuffer->HeadSequence() << " pd->Size "
3398  << m_txBuffer->Size() << " pd->SFS "
3399  << m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence));
3400 
3401  NS_LOG_DEBUG("cWnd: " << m_tcb->m_cWnd << " total unAck: " << UnAckDataCount()
3402  << " sent seq " << m_tcb->m_nextTxSequence << " size " << sz);
3403  m_tcb->m_nextTxSequence += sz;
3404  ++nPacketsSent;
3405  if (IsPacingEnabled())
3406  {
3407  NS_LOG_INFO("Pacing is enabled");
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  TcpOptionSack::SackList::iterator i;
4322  for (i = sackList.begin(); allowedSackBlocks > 0 && i != sackList.end(); ++i)
4323  {
4324  option->AddSackBlock(*i);
4325  allowedSackBlocks--;
4326  }
4327 
4328  header.AppendOption(option);
4329  NS_LOG_INFO(m_node->GetId() << " Add option SACK " << *option);
4330 }
4331 
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 == true)
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:42
#define max(a, b)
Definition: 80211b.c:43
a polymophic address class
Definition: address.h:100
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Callback template class.
Definition: callback.h:443
bool IsNull() const
Check for null implementation.
Definition: callback.h:572
AttributeValue implementation for Callback.
Definition: callback.h:809
Class for representing data rates.
Definition: data-rate.h:90
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
Hold variables of type enum.
Definition: enum.h:56
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition: event-id.cc:69
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
An Inet6 address class.
static Inet6SocketAddress ConvertFrom(const Address &addr)
Convert the address to a InetSocketAddress.
uint16_t GetPort() const
Get the port.
static bool IsMatchingType(const Address &addr)
If the address match.
Ipv6Address GetIpv6() const
Get the IPv6 address.
an Inet address class
static bool IsMatchingType(const Address &address)
Ipv4Address GetIpv4() const
static InetSocketAddress ConvertFrom(const Address &address)
Returns an InetSocketAddress which corresponds to the input Address.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:43
static Ipv4Address GetZero()
static Ipv4Address GetAny()
void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
void SetDestroyCallback(Callback< void > callback)
Set the default destroy callback.
void SetLocalAddress(Ipv4Address address)
Set the local address.
Ipv4Address GetPeerAddress()
Get the peer address.
void SetIcmpCallback(Callback< void, Ipv4Address, uint8_t, uint8_t, uint8_t, uint32_t > callback)
Set the ICMP callback.
uint16_t GetPeerPort()
Get the peer port.
uint16_t GetLocalPort()
Get the local port.
void SetPeer(Ipv4Address address, uint16_t port)
Set the peer information (address and port).
Ipv4Address GetLocalAddress()
Get the local address.
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:79
Describes an IPv6 address.
Definition: ipv6-address.h:50
static Ipv6Address GetAny()
Get the "any" (::) Ipv6Address.
bool IsIpv4MappedAddress() const
If the address is an IPv4-mapped address.
Ipv4Address GetIpv4MappedAddress() const
Return the Ipv4 address.
Ipv6Address GetLocalAddress()
Get the local address.
uint16_t GetLocalPort() const
Get the local port.
void SetPeer(Ipv6Address addr, uint16_t port)
Set the peer information (address and port).
void SetIcmpCallback(Callback< void, Ipv6Address, uint8_t, uint8_t, uint8_t, uint32_t > callback)
Set the ICMP callback.
void SetRxCallback(Callback< void, Ptr< Packet >, Ipv6Header, uint16_t, Ptr< Ipv6Interface >> callback)
Set the reception callback.
void SetLocalAddress(Ipv6Address addr)
Set the local address.
Ipv6Address GetPeerAddress()
Get the peer address.
void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
uint16_t GetPeerPort() const
Get the peer port.
void SetDestroyCallback(Callback< void > callback)
Set the default destroy callback.
Packet header for IPv6.
Definition: ipv6-header.h:36
void SetDestination(Ipv6Address dst)
Set the "Destination address" field.
Definition: ipv6-header.cc:118
Ipv6Address GetDestination() const
Get the "Destination address" field.
Definition: ipv6-header.cc:124
EcnType GetEcn() const
Definition: ipv6-header.cc:284
Ipv6Address GetSource() const
Get the "Source address" field.
Definition: ipv6-header.cc:112
IPv6 layer implementation.
uint32_t GetId() const
Definition: node.cc:117
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:311
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:986
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:294
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:863
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:979
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:305
bool ReplacePacketTag(Tag &tag)
Replace the value of a packet tag.
Definition: packet.cc:994
Hold objects of type Ptr<T>.
Definition: pointer.h:37
Helper class to store RTT measurements.
uint32_t count
Number of bytes sent.
RttHistory(SequenceNumber32 s, uint32_t c, Time t)
Constructor - builds an RttHistory with the given parameters.
bool retx
True if this has been retransmitted.
Time time
Time this one was sent.
SequenceNumber32 seq
First sequence number in packet sent.
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:606
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition: simulator.cc:208
Ptr< NetDevice > GetBoundNetDevice()
Returns socket's bound NetDevice, if any.
Definition: socket.cc:345
Ptr< Packet > Recv()
Read a single packet from the socket.
Definition: socket.cc:172
bool IsManualIpTtl() const
Checks if the socket has a specific IPv4 TTL set.
Definition: socket.cc:372
void SetIpTos(uint8_t ipTos)
Manually set IP Type of Service field.
Definition: socket.cc:432
void NotifySend(uint32_t spaceAvailable)
Notify through the callback (if set) that some data have been sent.
Definition: socket.cc:290
void NotifyNewConnectionCreated(Ptr< Socket > socket, const Address &from)
Notify through the callback (if set) that a new connection has been created.
Definition: socket.cc:270
virtual uint8_t GetIpTtl() const
Query the value of IP Time to Live field of this socket.
Definition: socket.cc:515
bool NotifyConnectionRequest(const Address &from)
Notify through the callback (if set) that an incoming connection is being requested by a remote host.
Definition: socket.cc:252
uint8_t GetIpTos() const
Query the value of IP Type of Service of this socket.
Definition: socket.cc:448
void SetRecvCallback(Callback< void, Ptr< Socket >> receivedData)
Notify application when new data is available to be read.
Definition: socket.cc:126
SocketType
Enumeration of the possible socket types.
Definition: socket.h:107
@ NS3_SOCK_STREAM
Definition: socket.h:108
void SetDataSentCallback(Callback< void, Ptr< Socket >, uint32_t > dataSent)
Notify application when a packet has been sent from transport protocol (non-standard socket call)
Definition: socket.cc:112
void SetSendCallback(Callback< void, Ptr< Socket >, uint32_t > sendCb)
Notify application when space in transmit buffer is added.
Definition: socket.cc:119
void NotifyErrorClose()
Notify through the callback (if set) that the connection has been closed due to an error.
Definition: socket.cc:242
void NotifyDataRecv()
Notify through the callback (if set) that some data have been received.
Definition: socket.cc:300
Ptr< NetDevice > m_boundnetdevice
the device this socket is bound to (might be null).
Definition: socket.h:1079
virtual void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
Definition: socket.cc:325
void NotifyNormalClose()
Notify through the callback (if set) that the connection has been closed.
Definition: socket.cc:232
virtual uint8_t GetIpv6HopLimit() const
Query the value of IP Hop Limit field of this socket.
Definition: socket.cc:540
SocketErrno
Enumeration of the possible errors returned by a socket.
Definition: socket.h:84
@ ERROR_SHUTDOWN
Definition: socket.h:90
@ ERROR_INVAL
Definition: socket.h:93
@ ERROR_ADDRINUSE
Definition: socket.h:98
@ ERROR_ADDRNOTAVAIL
Definition: socket.h:97
@ ERROR_NOTCONN
Definition: socket.h:87
@ ERROR_MSGSIZE
Definition: socket.h:88
void NotifyDataSent(uint32_t size)
Notify through the callback (if set) that some data have been sent.
Definition: socket.cc:280
void SetConnectCallback(Callback< void, Ptr< Socket >> connectionSucceeded, Callback< void, Ptr< Socket >> connectionFailed)
Specify callbacks to allow the caller to determine if the connection succeeds of fails.
Definition: socket.cc:85
void NotifyConnectionSucceeded()
Notify through the callback (if set) that the connection has been established.
Definition: socket.cc:212
uint8_t GetPriority() const
Query the priority value of this socket.
Definition: socket.cc:391
uint8_t GetIpv6Tclass() const
Query the value of IPv6 Traffic Class field of this socket.
Definition: socket.cc:490
bool IsManualIpv6HopLimit() const
Checks if the socket has a specific IPv6 Hop Limit set.
Definition: socket.cc:378
bool IsManualIpv6Tclass() const
Checks if the socket has a specific IPv6 Tclass set.
Definition: socket.cc:366
void NotifyConnectionFailed()
Notify through the callback (if set) that the connection has not been established due to an error.
Definition: socket.cc:222
indicates whether the socket has IP_TOS set.
Definition: socket.h:1269
void SetTos(uint8_t tos)
Set the tag's TOS.
Definition: socket.cc:796
This class implements a tag that carries the socket-specific TTL of a packet to the IP layer.
Definition: socket.h:1122
void SetTtl(uint8_t ttl)
Set the tag's TTL.
Definition: socket.cc:602
This class implements a tag that carries the socket-specific HOPLIMIT of a packet to the IPv6 layer.
Definition: socket.h:1170
void SetHopLimit(uint8_t hopLimit)
Set the tag's Hop Limit.
Definition: socket.cc:666
indicates whether the socket has IPV6_TCLASS set.
Definition: socket.h:1364
void SetTclass(uint8_t tclass)
Set the tag's Tclass.
Definition: socket.cc:908
indicates whether the socket has a priority set.
Definition: socket.h:1316
void SetPriority(uint8_t priority)
Set the tag's priority.
Definition: socket.cc:852
Header for the Transmission Control Protocol.
Definition: tcp-header.h:46
void SetDestinationPort(uint16_t port)
Set the destination port.
Definition: tcp-header.cc:89
void SetSequenceNumber(SequenceNumber32 sequenceNumber)
Set the sequence Number.
Definition: tcp-header.cc:95
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:137
uint8_t GetMaxOptionLength() const
Get maximum option length.
Definition: tcp-header.cc:161
uint16_t GetDestinationPort() const
Get the destination port.
Definition: tcp-header.cc:131
std::list< Ptr< const TcpOption > > TcpOptionList
List of TcpOption.
Definition: tcp-header.h:51
Ptr< const TcpOption > GetOption(uint8_t kind) const
Get the option specified.
Definition: tcp-header.cc:486
@ URG
Urgent.
Definition: tcp-header.h:286
void SetFlags(uint8_t flags)
Set flags of the header.
Definition: tcp-header.cc:107
void SetWindowSize(uint16_t windowSize)
Set the window size.
Definition: tcp-header.cc:113
const TcpOptionList & GetOptionList() const
Get the list of option in this header.
Definition: tcp-header.cc:480
uint16_t GetWindowSize() const
Get the window size.
Definition: tcp-header.cc:173
uint8_t GetOptionLength() const
Get the total length of appended options.
Definition: tcp-header.cc:155
bool AppendOption(Ptr< const TcpOption > option)
Append an option to the TCP header.
Definition: tcp-header.cc:454
static std::string FlagsToString(uint8_t flags, const std::string &delimiter="|")
Converts an integer into a human readable list of Tcp flags.
Definition: tcp-header.cc:58
bool HasOption(uint8_t kind) const
Check if the header has the option specified.
Definition: tcp-header.cc:502
uint16_t GetSourcePort() const
Get the source port.
Definition: tcp-header.cc:125
void SetSourcePort(uint16_t port)
Set the source port.
Definition: tcp-header.cc:83
void SetAckNumber(SequenceNumber32 ackNumber)
Set the ACK number.
Definition: tcp-header.cc:101
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:167
SequenceNumber32 GetAckNumber() const
Get the ACK number.
Definition: tcp-header.cc:143
virtual uint8_t GetKind() const =0
Get the ‘kind’ (as in RFC 793) of this option.
@ SACKPERMITTED
SACKPERMITTED.
Definition: tcp-option.h:62
@ WINSCALE
WINSCALE.
Definition: tcp-option.h:61
std::list< SackBlock > SackList
SACK list definition.
static Time ElapsedTimeFromTsValue(uint32_t echoTime)
Estimate the Time elapsed from a TS echo value.
static uint32_t NowToTsValue()
Return an uint32_t value which represent "now".
virtual 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.
SocketErrno GetErrno() const override
Get last error number.
int SetupEndpoint()
Configure the endpoint to a local address.
virtual void LastAckTimeout()
Timeout at LAST_ACK, close the connection.
void ProcessEstablished(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon ESTABLISHED state.
Time m_minRto
minimum value of the Retransmit timeout
uint32_t SendPendingData(bool withAck=false)
Send as much pending data as possible according to the Tx window.
TracedValue< uint32_t > m_advWnd
Advertised Window size.
TracedCallback< Ptr< const Packet >, const TcpHeader &, Ptr< const TcpSocketBase > > m_txTrace
Trace of transmitted packets.
SequenceNumber32 m_recover
Previous highest Tx seqnum for fast recovery (set it to initial seq number)
bool m_recoverActive
Whether "m_recover" has been set/activated It is used to avoid comparing with the old m_recover value...
void DoRetransmit()
Retransmit the first segment marked as lost, without considering available window nor pacing.
bool CheckNoEcn(uint8_t tos) const
Checks if TOS has no ECN codepoints.
virtual void SetNode(Ptr< Node > node)
Set the associated node.
int ShutdownRecv() override
uint8_t m_sndWindShift
Window shift to apply to incoming segments.
Ptr< TcpL4Protocol > m_tcp
the associated TCP L4 protocol
Ptr< TcpSocketState > m_tcb
Congestion control information.
bool GetAllowBroadcast() const override
Query whether broadcast datagram transmissions are allowed.
void UpdateSsThresh(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState slow start threshold.
TracedCallback< Ptr< const Packet >, const TcpHeader &, Ptr< const TcpSocketBase > > m_rxTrace
Trace of received packets.
virtual void SetTcp(Ptr< TcpL4Protocol > tcp)
Set the associated TCP L4 protocol.
void EnterRecovery(uint32_t currentDelivered)
Enter the CA_RECOVERY, and retransmit the head.
Time GetMinRto() const
Get the Minimum RTO.
void ProcessSynSent(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon SYN_SENT.
void ForwardUp(Ptr< Packet > packet, Ipv4Header header, uint16_t port, Ptr< Ipv4Interface > incomingInterface)
Called by the L3 protocol when it received a packet to pass on to TCP.
bool SetAllowBroadcast(bool allowBroadcast) override
Configure whether broadcast datagram transmissions are allowed.
SocketType GetSocketType() const override
void CancelAllTimers()
Cancel all timer when endpoint is deleted.
Time GetDelAckTimeout() const override
Get the time to delay an ACK.
Ptr< TcpRecoveryOps > m_recoveryOps
Recovery Algorithm.
TracedCallback< uint32_t, uint32_t > m_bytesInFlightTrace
Callback pointer for bytesInFlight trace chaining.
uint32_t GetInitialSSThresh() const override
Get the initial Slow Start Threshold.
void NotifyPacingPerformed()
Notify Pacing.
void SetDelAckTimeout(Time timeout) override
Set the time to delay an ACK.
void CloseAndNotify()
Peacefully close the socket by notifying the upper layer and deallocate end point.
Ptr< TcpRateOps > m_rateOps
Rate operations.
void PeerClose(Ptr< Packet > p, const TcpHeader &tcpHeader)
Received a FIN from peer, notify rx buffer.
int Close() override
Close a socket.
bool m_shutdownSend
Send no longer allowed.
bool IsPacingEnabled() const
Return true if packets in the current window should be paced.
void ProcessOptionWScale(const Ptr< const TcpOption > option)
Read and parse the Window scale option.
bool m_closeOnEmpty
Close socket upon tx buffer emptied.
virtual void ReTxTimeout()
An RTO event happened.
void AddOptionSackPermitted(TcpHeader &header)
Add the SACK PERMITTED option to the header.
TracedValue< Time > m_rto
Retransmit timeout.
uint32_t GetSndBufSize() const override
Get the send buffer size.
virtual void ReceivedData(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Recv of a data, put into buffer, call L7 to get it if necessary.
EventId m_timewaitEvent
TIME_WAIT expiration event: Move this socket to CLOSED state.
Ptr< TcpTxBuffer > m_txBuffer
Tx buffer.
static TypeId GetTypeId()
Get the type ID.
uint32_t m_dupAckCount
Dupack counter.
void SetRetxThresh(uint32_t retxThresh)
Set the retransmission threshold (dup ack threshold for a fast retransmit)
int Send(Ptr< Packet > p, uint32_t flags) override
Send data (or dummy data) to the remote host.
TracedCallback< SequenceNumber32, SequenceNumber32 > m_nextTxSequenceTrace
Callback pointer for next tx sequence chaining.
void UpdateBytesInFlight(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState bytes inflight.
EventId m_delAckEvent
Delayed ACK timeout event.
TracedCallback< Time, Time > m_lastRttTrace
Callback pointer for RTT trace chaining.
bool GetTcpNoDelay() const override
Check if Nagle's algorithm is enabled or not.
virtual void SetRtt(Ptr< RttEstimator > rtt)
Set the associated RTT estimator.
TracedCallback< uint32_t, uint32_t > m_cWndTrace
Callback pointer for cWnd trace chaining.
void UpdatePacingRateTrace(DataRate oldValue, DataRate newValue) const
Callback function to hook to TcpSocketState pacing rate.
void SetDataRetries(uint32_t retries) override
Set the number of data transmission retries before giving up.
void AddOptions(TcpHeader &tcpHeader)
Add options to TcpHeader.
TracedCallback< TcpSocketState::EcnState_t, TcpSocketState::EcnState_t > m_ecnStateTrace
Callback pointer for ECN state trace chaining.
void SetSynRetries(uint32_t count) override
Set the number of connection retries before giving up.
void ProcessWait(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon CLOSE_WAIT, FIN_WAIT_1, FIN_WAIT_2.
SequenceNumber32 m_highTxAck
Highest ack sent.
uint32_t GetTxAvailable() const override
Returns the number of bytes which can be sent in a single call to Send.
bool m_timestampEnabled
Timestamp option enabled.
virtual void PersistTimeout()
Send 1 byte probe to get an updated window size.
TracedValue< TcpStates_t > m_state
TCP state.
int SetupCallback()
Common part of the two Bind(), i.e.
Ptr< RttEstimator > m_rtt
Round trip time estimator.
Timer m_pacingTimer
Pacing Event.
EventId m_retxEvent
Retransmission event.
uint32_t m_bytesAckedNotProcessed
Bytes acked, but not processed.
void AddOptionTimestamp(TcpHeader &header)
Add the timestamp option to the header.
virtual uint32_t BytesInFlight() const
Return total bytes in flight.
uint32_t GetSegSize() const override
Get the segment size.
int SendTo(Ptr< Packet > p, uint32_t flags, const Address &toAddress) override
Send data to a specified peer.
uint32_t m_dataRetries
Number of data retransmission attempts.
double m_msl
Max segment lifetime.
void ProcessLastAck(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon LAST_ACK.
bool m_limitedTx
perform limited transmit
virtual uint32_t SendDataPacket(SequenceNumber32 seq, uint32_t maxSize, bool withAck)
Extract at most maxSize bytes from the TxBuffer at sequence seq, add the TCP header,...
TracedCallback< TcpSocketState::TcpCongState_t, TcpSocketState::TcpCongState_t > m_congStateTrace
Callback pointer for congestion state trace chaining.
void ProcessSynRcvd(Ptr< Packet > packet, const TcpHeader &tcpHeader, const Address &fromAddress, const Address &toAddress)
Received a packet upon SYN_RCVD.
virtual void ReceivedAck(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received an ACK packet.
int ShutdownSend() override
TracedValue< SequenceNumber32 > m_ecnCWRSeq
Sequence number of the last sent CWR.
Time GetPersistTimeout() const override
Get the timeout for persistent connection.
void UpdateCwnd(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState congestion window.
uint32_t m_delAckCount
Delayed ACK counter.
Ipv4EndPoint * m_endPoint
the IPv4 endpoint
static uint32_t SafeSubtraction(uint32_t a, uint32_t b)
Performs a safe subtraction between a and b (a-b)
virtual void DelAckTimeout()
Action upon delay ACK timeout, i.e.
Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress) override
Read a single packet from the socket and retrieve the sender address.
Time m_cnTimeout
Timeout for connection retry.
Time GetClockGranularity() const
Get the Clock Granularity (used in RTO calcs).
bool m_winScalingEnabled
Window Scale option enabled (RFC 7323)
void UpdateEcnState(TcpSocketState::EcnState_t oldValue, TcpSocketState::EcnState_t newValue) const
Callback function to hook to EcnState state.
EventId m_sendPendingDataEvent
micro-delay event to send pending data
uint32_t m_delAckMaxCount
Number of packet to fire an ACK before delay timeout.
uint8_t CalculateWScale() const
Calculate window scale value based on receive buffer space.
virtual void NewAck(const SequenceNumber32 &seq, bool resetRTO)
Update buffers w.r.t.
bool m_closeNotified
Told app to close socket.
int Listen() override
Listen for incoming connections.
void Destroy6()
Kill this socket by zeroing its attributes (IPv6)
TracedValue< SequenceNumber32 > m_ecnCESeq
Sequence number of the last received Congestion Experienced.
void SetClockGranularity(Time clockGranularity)
Sets the Clock Granularity (used in RTO calcs).
bool IsValidTcpSegment(const SequenceNumber32 seq, const uint32_t tcpHeaderSize, const uint32_t tcpPayloadSize)
Checks whether the given TCP segment is valid or not.
Time m_clockGranularity
Clock Granularity used in RTO calcs.
void DupAck(uint32_t currentDelivered)
Dupack management.
bool m_shutdownRecv
Receive no longer allowed.
void UpdateCongState(TcpSocketState::TcpCongState_t oldValue, TcpSocketState::TcpCongState_t newValue) const
Callback function to hook to TcpSocketState congestion state.
virtual uint32_t Window() const
Return the max possible number of unacked bytes.
Callback< void, Ipv6Address, uint8_t, uint8_t, uint8_t, uint32_t > m_icmpCallback6
ICMPv6 callback.
std::deque< RttHistory > m_history
List of sent packet.
void ProcessOptionSackPermitted(const Ptr< const TcpOption > option)
Read the SACK PERMITTED option.
int Bind() override
Allocate a local IPv4 endpoint for this socket.
virtual uint32_t AvailableWindow() const
Return unfilled portion of window.
TracedValue< SequenceNumber32 > m_highRxMark
Highest seqno received.
void ReadOptions(const TcpHeader &tcpHeader, uint32_t *bytesSacked)
Read TCP options before Ack processing.
virtual uint16_t AdvertisedWindowSize(bool scale=true) const
The amount of Rx window announced to the peer.
void ForwardUp6(Ptr< Packet > packet, Ipv6Header header, uint16_t port, Ptr< Ipv6Interface > incomingInterface)
Called by the L3 protocol when it received a packet to pass on to TCP.
bool m_connected
Connection established.
TracedValue< SequenceNumber32 > m_highRxAckMark
Highest ack received.
void AddOptionWScale(TcpHeader &header)
Add the window scale option to the header.
virtual void SendEmptyPacket(uint8_t flags)
Send a empty packet that carries a flag, e.g., ACK.
void UpdateWindowSize(const TcpHeader &header)
Update the receiver window (RWND) based on the value of the window field in the header.
uint32_t GetRxAvailable() const override
Return number of bytes which can be returned from one or multiple calls to Recv.
uint32_t GetDataRetries() const override
Get the number of data transmission retries before giving up.
int SetupEndpoint6()
Configure the endpoint v6 to a local address.
uint32_t GetRetxThresh() const
Get the retransmission threshold (dup ack threshold for a fast retransmit)
void DeallocateEndPoint()
Deallocate m_endPoint and m_endPoint6.
void Destroy()
Kill this socket by zeroing its attributes (IPv4)
void UpdateHighTxMark(SequenceNumber32 oldValue, SequenceNumber32 newValue) const
Callback function to hook to TcpSocketState high tx mark.
TcpSocketBase()
Create an unbound TCP socket.
void SetInitialSSThresh(uint32_t threshold) override
Set the initial Slow Start Threshold.
TracedCallback< DataRate, DataRate > m_pacingRateTrace
Callback pointer for pacing rate trace chaining.
uint32_t m_timestampToEcho
Timestamp to echo.
Ipv6EndPoint * m_endPoint6
the IPv6 endpoint
void SetSndBufSize(uint32_t size) override
Set the send buffer size.
virtual Ptr< TcpSocketBase > Fork()
Call CopyObject<> to clone me.
TracedCallback< uint32_t, uint32_t > m_ssThTrace
Callback pointer for ssTh trace chaining.
SocketErrno m_errno
Socket error code.
virtual void CompleteFork(Ptr< Packet > p, const TcpHeader &tcpHeader, const Address &fromAddress, const Address &toAddress)
Complete a connection by forking the socket.
void ProcessClosing(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon CLOSING.
TracedCallback< SequenceNumber32, SequenceNumber32 > m_highTxMarkTrace
Callback pointer for high tx mark chaining.
int Connect(const Address &address) override
Initiate a connection to a remote host.
Ptr< Node > m_node
the associated node
void SetSegSize(uint32_t size) override
Set the segment size.
TypeId GetInstanceTypeId() const override
Get the instance TypeId.
uint32_t m_synRetries
Number of connection attempts.
void SetConnTimeout(Time timeout) override
Set the connection timeout.
void SetDelAckMaxCount(uint32_t count) override
Set the number of packet to fire an ACK before delay timeout.
EventId m_lastAckEvent
Last ACK timeout event.
bool IsTcpOptionEnabled(uint8_t kind) const
Return true if the specified option is enabled.
void UpdatePacingRate()
Dynamically update the pacing rate.
EventId m_persistEvent
Persist event: Send 1 byte to probe for a non-zero Rx window.
void SetPacingStatus(bool pacing)
Enable or disable pacing.
void UpdateRtt(Time oldValue, Time newValue) const
Callback function to hook to TcpSocketState rtt.
void SetCongestionControlAlgorithm(Ptr< TcpCongestionOps > algo)
Install a congestion control algorithm on this socket.
int GetPeerName(Address &address) const override
Get the peer address of a connected socket.
virtual uint32_t UnAckDataCount() const
Return count of number of unacked bytes.
uint32_t m_dataRetrCount
Count of remaining data retransmission attempts.
void UpdateCwndInfl(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState inflated congestion window.
Ptr< TcpRxBuffer > GetRxBuffer() const
Get a pointer to the Rx buffer.
void SetPersistTimeout(Time timeout) override
Set the timeout for persistent connection.
void ConnectionSucceeded()
Schedule-friendly wrapper for Socket::NotifyConnectionSucceeded()
bool m_noDelay
Set to true to disable Nagle's algorithm.
uint32_t GetDelAckMaxCount() const override
Get the number of packet to fire an ACK before delay timeout.
void ForwardIcmp(Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
Called by the L3 protocol when it received an ICMP packet to pass on to TCP.
virtual void ProcessAck(const SequenceNumber32 &ackNumber, bool scoreboardUpdated, uint32_t currentDelivered, const SequenceNumber32 &oldHeadSequence)
Process a received ack.
void ForwardIcmp6(Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
Called by the L3 protocol when it received an ICMPv6 packet to pass on to TCP.
virtual void DoForwardUp(Ptr< Packet > packet, const Address &fromAddress, const Address &toAddress)
Called by TcpSocketBase::ForwardUp{,6}().
bool m_isFirstPartialAck
First partial ACK during RECOVERY.
uint8_t MarkEcnCodePoint(const uint8_t tos, const TcpSocketState::EcnCodePoint_t codePoint) const
mark ECN code point
Time m_delAckTimeout
Time to delay an ACK.
Callback< void, Ipv4Address, uint8_t, uint8_t, uint8_t, uint32_t > m_icmpCallback
ICMP callback.
void SetInitialCwnd(uint32_t cwnd) override
Set the initial Congestion Window.
void SetUseEcn(TcpSocketState::UseEcn_t useEcn)
Set ECN mode of use on the socket.
void ProcessListen(Ptr< Packet > packet, const TcpHeader &tcpHeader, const Address &fromAddress, const Address &toAddress)
Received a packet upon LISTEN state.
uint32_t m_synCount
Count of remaining connection retries.
int DoConnect()
Perform the real connection tasks: Send SYN if allowed, RST if invalid.
uint32_t GetSynRetries() const override
Get the number of connection retries before giving up.
void DoPeerClose()
FIN is in sequence, notify app and respond with a FIN.
void SendRST()
Send reset and tear down this socket.
bool OutOfRange(SequenceNumber32 head, SequenceNumber32 tail) const
Check if a sequence number range is within the rx window.
TracedValue< SequenceNumber32 > m_ecnEchoSeq
Sequence number of the last received ECN Echo.
uint32_t m_retxThresh
Fast Retransmit threshold.
uint32_t GetRWnd() const
Get the current value of the receiver's offered window (RCV.WND)
SequenceNumber32 GetHighRxAck() const
Get the current value of the receiver's highest (in-sequence) sequence number acked.
void BindToNetDevice(Ptr< NetDevice > netdevice) override
Bind a socket to specific device.
void EnterCwr(uint32_t currentDelivered)
Enter CA_CWR state upon receipt of an ECN Echo.
virtual void EstimateRtt(const TcpHeader &tcpHeader)
Take into account the packet for RTT estimation.
uint32_t GetInitialCwnd() const override
Get the initial Congestion Window.
TracedValue< uint32_t > m_rWnd
Receiver window (RCV.WND in RFC793)
void ProcessOptionTimestamp(const Ptr< const TcpOption > option, const SequenceNumber32 &seq)
Process the timestamp option from other side.
void SetRcvBufSize(uint32_t size) override
Set the receive buffer size.
void SetTcpNoDelay(bool noDelay) override
Enable/Disable Nagle's algorithm.
virtual void UpdateRttHistory(const SequenceNumber32 &seq, uint32_t sz, bool isRetransmission)
Update the RTT history, when we send TCP segments.
bool m_sackEnabled
RFC SACK option enabled.
void UpdateNextTxSequence(SequenceNumber32 oldValue, SequenceNumber32 newValue) const
Callback function to hook to TcpSocketState next tx sequence.
void SetMinRto(Time minRto)
Sets the Minimum RTO.
Time GetConnTimeout() const override
Get the connection timeout.
Ptr< Node > GetNode() const override
Return the node this socket is associated with.
uint32_t ProcessOptionSack(const Ptr< const TcpOption > option)
Read the SACK option.
void SetRecoveryAlgorithm(Ptr< TcpRecoveryOps > recovery)
Install a recovery algorithm on this socket.
int DoClose()
Close a socket by sending RST, FIN, or FIN+ACK, depend on the current state.
void AddSocketTags(const Ptr< Packet > &p) const
Add Tags for the Socket.
TracedCallback< uint32_t, uint32_t > m_cWndInflTrace
Callback pointer for cWndInfl trace chaining.
uint32_t GetRcvBufSize() const override
Get the receive buffer size.
(abstract) base class of all TcpSockets
Definition: tcp-socket.h:48
static const char *const TcpStateName[TcpSocket::LAST_STATE]
Literal names of TCP states for use in log messages.
Definition: tcp-socket.h:95
uint32_t m_segmentSize
Segment size.
@ CA_EVENT_ECN_IS_CE
received CE marked IP packet.
@ CA_EVENT_ECN_NO_CE
ECT set, but not CE marked.
@ CA_EVENT_DELAYED_ACK
Delayed ack is sent.
@ CA_EVENT_NON_DELAYED_ACK
Non-delayed ack is sent.
@ CA_EVENT_COMPLETE_CWR
end of congestion recovery
@ CA_EVENT_LOSS
loss timeout
@ CA_EVENT_TX_START
first transmit when no packets in flight
Time m_minRtt
Minimum RTT observed throughout the connection.
TracedValue< SequenceNumber32 > m_highTxMark
Highest seqno ever sent, regardless of ReTx.
uint32_t m_initialSsThresh
Initial Slow Start Threshold value.
EcnMode_t m_ecnMode
ECN mode.
Callback< void, uint8_t > m_sendEmptyPacketCallback
Callback to send an empty packet.
TracedValue< DataRate > m_pacingRate
Current Pacing rate.
UseEcn_t
Parameter value related to ECN enable/disable functionality similar to sysctl for tcp_ecn.
@ AcceptOnly
Enable only when the peer endpoint is ECN capable.
TracedValue< TcpCongState_t > m_congState
State in the Congestion state machine.
bool m_paceInitialWindow
Enable/Disable pacing for the initial window.
DataRate m_maxPacingRate
Max Pacing rate.
UseEcn_t m_useEcn
Socket ECN capability.
bool m_pacing
Pacing status.
bool m_isRetransDataAcked
Retransmitted data is ACKed if true.
static const char *const TcpCongStateName[TcpSocketState::CA_LAST_STATE]
Literal names of TCP states for use in log messages.
TcpCongState_t
Definition of the Congestion state machine.
@ CA_RECOVERY
CWND was reduced, we are fast-retransmitting.
@ CA_DISORDER
In all the respects it is "Open", but requires a bit more attention.
@ CA_CWR
cWnd was reduced due to some congestion notification event, such as ECN, ICMP source quench,...
@ CA_LOSS
CWND was reduced due to RTO timeout or SACK reneging.
@ CA_OPEN
Normal state, no dubious events.
SequenceNumber32 m_lastAckedSeq
Last sequence ACKed.
@ DctcpEcn
ECN functionality as described in RFC 8257.
TracedValue< uint32_t > m_cWnd
Congestion window.
uint32_t m_initialCWnd
Initial cWnd value.
uint32_t m_rcvTimestampEchoReply
Sender Timestamp echoed by the receiver.
TracedValue< Time > m_lastRtt
Last RTT sample collected.
EcnState_t
Definition of the Ecn state machine.
@ ECN_CWR_SENT
Sender has reduced the congestion window, and sent a packet with CWR bit set in TCP header.
@ ECN_DISABLED
ECN disabled traffic.
@ ECN_ECE_RCVD
Last ACK received had ECE bit set in TCP header.
@ ECN_IDLE
ECN is enabled but currently there is no action pertaining to ECE or CWR to be taken.
@ ECN_CE_RCVD
Last packet received had CE bit set in IP header.
@ ECN_SENDING_ECE
Receiver sends an ACK with ECE bit set in TCP header.
TracedValue< uint32_t > m_bytesInFlight
Bytes in flight.
TracedValue< uint32_t > m_cWndInfl
Inflated congestion window trace (used only for backward compatibility purpose)
uint16_t m_pacingCaRatio
CA pacing ratio.
Ptr< TcpRxBuffer > m_rxBuffer
Rx buffer (reordering buffer)
TracedValue< SequenceNumber32 > m_nextTxSequence
Next seqnum to be sent (SND.NXT), ReTx pushes it back.
uint32_t m_lastAckedSackedBytes
The number of bytes acked and sacked as indicated by the current ACK received.
uint16_t m_pacingSsRatio
SS pacing ratio.
static const char *const EcnStateName[TcpSocketState::ECN_CWR_SENT+1]
Literal names of ECN states for use in log messages.
TracedValue< EcnState_t > m_ecnState
Current ECN State, represented as combination of EcnState values.
TracedValue< uint32_t > m_ssThresh
Slow start threshold.
uint32_t m_rcvTimestampValue
Receiver Timestamp value.
EcnCodePoint_t m_ectCodePoint
ECT code point to use.
Item that encloses the application packet and some flags for it.
Definition: tcp-tx-item.h:33
Ptr< Packet > GetPacketCopy() const
Get a copy of the Packet underlying this item.
Definition: tcp-tx-item.cc:79
bool IsRetrans() const
Is the item retransmitted?
Definition: tcp-tx-item.cc:73
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
@ S
second
Definition: nstime.h:116
static Time FromDouble(double value, Unit unit)
Create a Time equal to value in unit unit.
Definition: nstime.h:515
AttributeValue implementation for Time.
Definition: nstime.h:1423
A simple virtual Timer class.
Definition: timer.h:74
void SetFunction(FN fn)
Definition: timer.h:278
bool IsExpired() const
Definition: timer.cc:126
Time GetDelayLeft() const
Definition: timer.cc:90
void Cancel()
Cancel the currently-running event if there is one.
Definition: timer.cc:112
void Schedule()
Schedule a new event using the currently-configured delay, function, and arguments.
Definition: timer.cc:166
bool IsRunning() const
Definition: timer.cc:133
T Get() const
Get the underlying value.
Definition: traced-value.h:249
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
Hold an unsigned integer type.
Definition: uinteger.h:45
uint16_t port
Definition: dsdv-manet.cc:45
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: boolean.h:86
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeCallbackAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: callback.h:847
Ptr< const AttributeChecker > MakeCallbackChecker()
Definition: callback.cc:82
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: double.h:43
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: enum.h:205
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: pointer.h:231
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: nstime.h:1424
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: uinteger.h:46
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:243
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:229
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:254
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:261
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
@ ESTABLISHED
Connection established
Definition: tcp-socket.h:72
@ FIN_WAIT_2
All buffered data sent, waiting for remote to shutdown.
Definition: tcp-socket.h:81
@ LISTEN
Listening for a connection
Definition: tcp-socket.h:68
@ CLOSE_WAIT
Remote side has shutdown and is waiting for us to finish writing our data and to shutdown (we have to...
Definition: tcp-socket.h:73
@ SYN_SENT
Sent a connection request, waiting for ack
Definition: tcp-socket.h:69
@ CLOSED
Socket is finished
Definition: tcp-socket.h:67
@ FIN_WAIT_1
Our side has shutdown, waiting to complete transmission of remaining buffered data
Definition: tcp-socket.h:79
@ TIME_WAIT
Timeout to catch resent junk before entering closed, can only be entered from FIN_WAIT2 or CLOSING.
Definition: tcp-socket.h:84
@ SYN_RCVD
Received a connection request, sent ack, waiting for final ack in three-way handshake.
Definition: tcp-socket.h:70
@ LAST_ACK
Our side has shutdown after remote has shutdown.
Definition: tcp-socket.h:76
@ CLOSING
Both sides have shutdown but we still have data we have to finish sending
Definition: tcp-socket.h:82
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1360
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
log2() macro definition; to deal with Bug 1467.
address
Definition: first.py:40
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:848
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:707
Ptr< const AttributeChecker > MakeEnumChecker(int v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:163
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:535
ns3::Time timeout
uint64_t m_delivered
The total amount of data in bytes delivered so far.
Definition: tcp-rate-ops.h:174