A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 * Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
8 */
9
10#define NS_LOG_APPEND_CONTEXT \
11 if (m_node) \
12 { \
13 std::clog << " [node " << m_node->GetId() << "] "; \
14 }
15
16#include "tcp-socket-base.h"
17
18#include "ipv4-end-point.h"
19#include "ipv4-route.h"
21#include "ipv4.h"
22#include "ipv6-end-point.h"
23#include "ipv6-l3-protocol.h"
24#include "ipv6-route.h"
26#include "rtt-estimator.h"
27#include "tcp-congestion-ops.h"
28#include "tcp-header.h"
29#include "tcp-l4-protocol.h"
31#include "tcp-option-sack.h"
32#include "tcp-option-ts.h"
33#include "tcp-option-winscale.h"
34#include "tcp-rate-ops.h"
35#include "tcp-recovery-ops.h"
36#include "tcp-rx-buffer.h"
37#include "tcp-tx-buffer.h"
38
39#include "ns3/abort.h"
40#include "ns3/data-rate.h"
41#include "ns3/double.h"
42#include "ns3/inet-socket-address.h"
43#include "ns3/inet6-socket-address.h"
44#include "ns3/log.h"
45#include "ns3/node.h"
46#include "ns3/object.h"
47#include "ns3/packet.h"
48#include "ns3/pointer.h"
49#include "ns3/simulation-singleton.h"
50#include "ns3/simulator.h"
51#include "ns3/trace-source-accessor.h"
52#include "ns3/uinteger.h"
53
54#include <algorithm>
55#include <math.h>
56
85
86namespace ns3
87{
88
89NS_LOG_COMPONENT_DEFINE("TcpSocketBase");
90
91NS_OBJECT_ENSURE_REGISTERED(TcpSocketBase);
92
93TypeId
95{
96 static TypeId tid =
97 TypeId("ns3::TcpSocketBase")
99 .SetGroupName("Internet")
100 .AddConstructor<TcpSocketBase>()
101 // .AddAttribute ("TcpState", "State in TCP state machine",
102 // TypeId::ATTR_GET,
103 // EnumValue (CLOSED),
104 // MakeEnumAccessor (&TcpSocketBase::m_state),
105 // MakeEnumChecker (CLOSED, "Closed"))
106 .AddAttribute("MaxSegLifetime",
107 "Maximum segment lifetime in seconds, use for TIME_WAIT state transition "
108 "to CLOSED state",
109 DoubleValue(120), /* RFC793 says MSL=2 minutes*/
112 .AddAttribute("MaxWindowSize",
113 "Max size of advertised window",
114 UintegerValue(65535),
117 .AddAttribute("IcmpCallback",
118 "Callback invoked whenever an icmp error is received on this socket.",
122 .AddAttribute("IcmpCallback6",
123 "Callback invoked whenever an icmpv6 error is received on this socket.",
127 .AddAttribute("WindowScaling",
128 "Enable or disable Window Scaling option",
129 BooleanValue(true),
132 .AddAttribute("Sack",
133 "Enable or disable Sack option",
134 BooleanValue(true),
137 .AddAttribute("Timestamp",
138 "Enable or disable Timestamp option",
139 BooleanValue(true),
142 .AddAttribute(
143 "MinRto",
144 "Minimum retransmit timeout value",
145 TimeValue(Seconds(1)), // RFC 6298 says min RTO=1 sec, but Linux uses 200ms.
146 // See http://www.postel.org/pipermail/end2end-interest/2004-November/004402.html
149 .AddAttribute(
150 "ClockGranularity",
151 "Clock Granularity used in RTO calculations",
152 TimeValue(MilliSeconds(1)), // RFC6298 suggest to use fine clock granularity
156 .AddAttribute("TxBuffer",
157 "TCP Tx buffer",
158 PointerValue(),
161 .AddAttribute("RxBuffer",
162 "TCP Rx buffer",
163 PointerValue(),
166 .AddAttribute("CongestionOps",
167 "Pointer to TcpCongestionOps object",
168 PointerValue(),
171 .AddAttribute("RecoveryOps",
172 "Pointer to TcpRecoveryOps object",
173 PointerValue(),
176 .AddAttribute(
177 "ReTxThreshold",
178 "Threshold for fast retransmit",
179 UintegerValue(3),
182 .AddAttribute("LimitedTransmit",
183 "Enable limited transmit",
184 BooleanValue(true),
187 .AddAttribute("UseEcn",
188 "Parameter to set ECN functionality",
192 "Off",
194 "On",
196 "AcceptOnly"))
197 .AddTraceSource("RTO",
198 "Retransmission timeout",
200 "ns3::TracedValueCallback::Time")
201 .AddTraceSource("RTT",
202 "Smoothed RTT",
204 "ns3::TracedValueCallback::Time")
205 .AddTraceSource("LastRTT",
206 "RTT of the last (S)ACKed packet",
208 "ns3::TracedValueCallback::Time")
209 .AddTraceSource("NextTxSequence",
210 "Next sequence number to send (SND.NXT)",
212 "ns3::SequenceNumber32TracedValueCallback")
213 .AddTraceSource("HighestSequence",
214 "Highest sequence number ever sent in socket's life time",
216 "ns3::TracedValueCallback::SequenceNumber32")
217 .AddTraceSource("State",
218 "TCP state",
220 "ns3::TcpStatesTracedValueCallback")
221 .AddTraceSource("CongState",
222 "TCP Congestion machine state",
224 "ns3::TcpSocketState::TcpCongStatesTracedValueCallback")
225 .AddTraceSource("EcnState",
226 "Trace ECN state change of socket",
228 "ns3::TcpSocketState::EcnStatesTracedValueCallback")
229 .AddTraceSource("AdvWND",
230 "Advertised Window Size",
232 "ns3::TracedValueCallback::Uint32")
233 .AddTraceSource("RWND",
234 "Remote side's flow control window",
236 "ns3::TracedValueCallback::Uint32")
237 .AddTraceSource("BytesInFlight",
238 "Socket estimation of bytes in flight",
240 "ns3::TracedValueCallback::Uint32")
241 .AddTraceSource("HighestRxSequence",
242 "Highest sequence number received from peer",
244 "ns3::TracedValueCallback::SequenceNumber32")
245 .AddTraceSource("HighestRxAck",
246 "Highest ack received from peer",
248 "ns3::TracedValueCallback::SequenceNumber32")
249 .AddTraceSource("PacingRate",
250 "The current TCP pacing rate",
252 "ns3::TracedValueCallback::DataRate")
253 .AddTraceSource("CongestionWindow",
254 "The TCP connection's congestion window",
256 "ns3::TracedValueCallback::Uint32")
257 .AddTraceSource("CongestionWindowInflated",
258 "The TCP connection's congestion window inflates as in older RFC",
260 "ns3::TracedValueCallback::Uint32")
261 .AddTraceSource("SlowStartThreshold",
262 "TCP slow start threshold (bytes)",
264 "ns3::TracedValueCallback::Uint32")
265 .AddTraceSource("Tx",
266 "Send tcp packet to IP protocol",
268 "ns3::TcpSocketBase::TcpTxRxTracedCallback")
269 .AddTraceSource("Retransmission",
270 "Notification of a TCP retransmission",
272 "ns3::TcpSocketBase::RetransmissionCallback")
273 .AddTraceSource("Rx",
274 "Receive tcp packet from IP protocol",
276 "ns3::TcpSocketBase::TcpTxRxTracedCallback")
277 .AddTraceSource("EcnEchoSeq",
278 "Sequence of last received ECN Echo",
280 "ns3::SequenceNumber32TracedValueCallback")
281 .AddTraceSource("EcnCeSeq",
282 "Sequence of last received CE",
284 "ns3::SequenceNumber32TracedValueCallback")
285 .AddTraceSource("EcnCwrSeq",
286 "Sequence of last received CWR",
288 "ns3::SequenceNumber32TracedValueCallback");
289 return tid;
290}
291
293 : TcpSocket()
294{
295 NS_LOG_FUNCTION(this);
297 m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
300
301 m_tcb->m_rxBuffer = CreateObject<TcpRxBuffer>();
302
303 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
305
306 m_tcb->m_sendEmptyPacketCallback = MakeCallback(&TcpSocketBase::SendEmptyPacket, this);
307
308 bool ok;
309
310 ok = m_tcb->TraceConnectWithoutContext(
311 "PacingRate",
313 NS_ASSERT(ok == true);
314
315 ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
317 NS_ASSERT(ok == true);
318
319 ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
321 NS_ASSERT(ok == true);
322
323 ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
325 NS_ASSERT(ok == true);
326
327 ok = m_tcb->TraceConnectWithoutContext("CongState",
329 NS_ASSERT(ok == true);
330
331 ok = m_tcb->TraceConnectWithoutContext("EcnState",
333 NS_ASSERT(ok == true);
334
335 ok =
336 m_tcb->TraceConnectWithoutContext("NextTxSequence",
338 NS_ASSERT(ok == true);
339
340 ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
342 NS_ASSERT(ok == true);
343
344 ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
346 NS_ASSERT(ok == true);
347
348 ok = m_tcb->TraceConnectWithoutContext("RTT", MakeCallback(&TcpSocketBase::UpdateRtt, this));
349 NS_ASSERT(ok == true);
350
351 ok = m_tcb->TraceConnectWithoutContext("LastRTT",
353 NS_ASSERT(ok == true);
354}
355
357 : TcpSocket(sock),
358 // copy object::m_tid and socket::callbacks
359 m_dupAckCount(sock.m_dupAckCount),
360 m_delAckCount(0),
361 m_delAckMaxCount(sock.m_delAckMaxCount),
362 m_noDelay(sock.m_noDelay),
363 m_synCount(sock.m_synCount),
364 m_synRetries(sock.m_synRetries),
365 m_dataRetrCount(sock.m_dataRetrCount),
366 m_dataRetries(sock.m_dataRetries),
367 m_rto(sock.m_rto),
368 m_minRto(sock.m_minRto),
369 m_clockGranularity(sock.m_clockGranularity),
370 m_delAckTimeout(sock.m_delAckTimeout),
371 m_persistTimeout(sock.m_persistTimeout),
372 m_cnTimeout(sock.m_cnTimeout),
373 m_endPoint(nullptr),
374 m_endPoint6(nullptr),
375 m_node(sock.m_node),
376 m_tcp(sock.m_tcp),
377 m_state(sock.m_state),
378 m_errno(sock.m_errno),
379 m_closeNotified(sock.m_closeNotified),
380 m_closeOnEmpty(sock.m_closeOnEmpty),
381 m_shutdownSend(sock.m_shutdownSend),
382 m_shutdownRecv(sock.m_shutdownRecv),
383 m_connected(sock.m_connected),
384 m_msl(sock.m_msl),
385 m_maxWinSize(sock.m_maxWinSize),
386 m_bytesAckedNotProcessed(sock.m_bytesAckedNotProcessed),
387 m_rWnd(sock.m_rWnd),
388 m_highRxMark(sock.m_highRxMark),
389 m_highRxAckMark(sock.m_highRxAckMark),
390 m_sackEnabled(sock.m_sackEnabled),
391 m_winScalingEnabled(sock.m_winScalingEnabled),
392 m_rcvWindShift(sock.m_rcvWindShift),
393 m_sndWindShift(sock.m_sndWindShift),
394 m_timestampEnabled(sock.m_timestampEnabled),
395 m_timestampToEcho(sock.m_timestampToEcho),
396 m_recover(sock.m_recover),
397 m_recoverActive(sock.m_recoverActive),
398 m_retxThresh(sock.m_retxThresh),
399 m_limitedTx(sock.m_limitedTx),
400 m_isFirstPartialAck(sock.m_isFirstPartialAck),
401 m_txTrace(sock.m_txTrace),
402 m_rxTrace(sock.m_rxTrace),
403 m_pacingTimer(Timer::CANCEL_ON_DESTROY),
404 m_ecnEchoSeq(sock.m_ecnEchoSeq),
405 m_ecnCESeq(sock.m_ecnCESeq),
406 m_ecnCWRSeq(sock.m_ecnCWRSeq)
407{
408 NS_LOG_FUNCTION(this);
409 NS_LOG_LOGIC("Invoked the copy constructor");
410 // Copy the rtt estimator if it is set
411 if (sock.m_rtt)
412 {
413 m_rtt = sock.m_rtt->Copy();
414 }
415 // Reset all callbacks to null
417 Callback<void, Ptr<Socket>, const Address&> vPSA =
420 SetConnectCallback(vPS, vPS);
421 SetDataSentCallback(vPSUI);
422 SetSendCallback(vPSUI);
423 SetRecvCallback(vPS);
425 m_txBuffer->SetRWndCallback(MakeCallback(&TcpSocketBase::GetRWnd, this));
426 m_tcb = CopyObject(sock.m_tcb);
427 m_tcb->m_rxBuffer = CopyObject(sock.m_tcb->m_rxBuffer);
428
429 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
431
433
434 if (sock.m_congestionControl)
435 {
438 m_congestionControl->SetRateOps(m_rateOps);
439 }
440
441 if (sock.m_recoveryOps)
442 {
443 m_recoveryOps = sock.m_recoveryOps->Fork();
444 }
445
446 if (m_tcb->m_sendEmptyPacketCallback.IsNull())
447 {
448 m_tcb->m_sendEmptyPacketCallback = MakeCallback(&TcpSocketBase::SendEmptyPacket, this);
449 }
450
451 bool ok;
452
453 ok = m_tcb->TraceConnectWithoutContext(
454 "PacingRate",
456
457 ok = m_tcb->TraceConnectWithoutContext("CongestionWindow",
459 NS_ASSERT(ok == true);
460
461 ok = m_tcb->TraceConnectWithoutContext("CongestionWindowInflated",
463 NS_ASSERT(ok == true);
464
465 ok = m_tcb->TraceConnectWithoutContext("SlowStartThreshold",
467 NS_ASSERT(ok == true);
468
469 ok = m_tcb->TraceConnectWithoutContext("CongState",
471 NS_ASSERT(ok == true);
472
473 ok = m_tcb->TraceConnectWithoutContext("EcnState",
475 NS_ASSERT(ok == true);
476
477 ok =
478 m_tcb->TraceConnectWithoutContext("NextTxSequence",
480 NS_ASSERT(ok == true);
481
482 ok = m_tcb->TraceConnectWithoutContext("HighestSequence",
484 NS_ASSERT(ok == true);
485
486 ok = m_tcb->TraceConnectWithoutContext("BytesInFlight",
488 NS_ASSERT(ok == true);
489
490 ok = m_tcb->TraceConnectWithoutContext("RTT", MakeCallback(&TcpSocketBase::UpdateRtt, this));
491 NS_ASSERT(ok == true);
492
493 ok = m_tcb->TraceConnectWithoutContext("LastRTT",
495 NS_ASSERT(ok == true);
496}
497
499{
500 NS_LOG_FUNCTION(this);
501 m_node = nullptr;
502 if (m_endPoint != nullptr)
503 {
505 /*
506 * Upon Bind, an Ipv4Endpoint is allocated and set to m_endPoint, and
507 * DestroyCallback is set to TcpSocketBase::Destroy. If we called
508 * m_tcp->DeAllocate, it will destroy its Ipv4EndpointDemux::DeAllocate,
509 * which in turn destroys my m_endPoint, and in turn invokes
510 * TcpSocketBase::Destroy to nullify m_node, m_endPoint, and m_tcp.
511 */
512 NS_ASSERT(m_endPoint != nullptr);
513 m_tcp->DeAllocate(m_endPoint);
514 NS_ASSERT(m_endPoint == nullptr);
515 }
516 if (m_endPoint6 != nullptr)
517 {
519 NS_ASSERT(m_endPoint6 != nullptr);
520 m_tcp->DeAllocate(m_endPoint6);
521 NS_ASSERT(m_endPoint6 == nullptr);
522 }
523 m_tcp = nullptr;
525}
526
527/* Associate a node with this TCP socket */
528void
530{
531 m_node = node;
532}
533
534/* Associate the L4 protocol (e.g. mux/demux) with this socket */
535void
540
541/* Set an RTT estimator with this socket */
542void
547
548/* Inherit from Socket class: Returns error code */
551{
552 return m_errno;
553}
554
555/* Inherit from Socket class: Returns socket type, NS3_SOCK_STREAM */
558{
559 return NS3_SOCK_STREAM;
560}
561
562/* Inherit from Socket class: Returns associated node */
565{
566 return m_node;
567}
568
569/* Inherit from Socket class: Bind socket to an end-point in TcpL4Protocol */
570int
572{
573 NS_LOG_FUNCTION(this);
574 m_endPoint = m_tcp->Allocate();
575 if (nullptr == m_endPoint)
576 {
578 return -1;
579 }
580
581 m_tcp->AddSocket(this);
582
583 return SetupCallback();
584}
585
586int
588{
589 NS_LOG_FUNCTION(this);
590 m_endPoint6 = m_tcp->Allocate6();
591 if (nullptr == m_endPoint6)
592 {
594 return -1;
595 }
596
597 m_tcp->AddSocket(this);
598
599 return SetupCallback();
600}
601
602/* Inherit from Socket class: Bind socket (with specific address) to an end-point in TcpL4Protocol
603 */
604int
606{
607 NS_LOG_FUNCTION(this << address);
609 {
611 Ipv4Address ipv4 = transport.GetIpv4();
612 uint16_t port = transport.GetPort();
613 if (ipv4 == Ipv4Address::GetAny() && port == 0)
614 {
615 m_endPoint = m_tcp->Allocate();
616 }
617 else if (ipv4 == Ipv4Address::GetAny() && port != 0)
618 {
619 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), port);
620 }
621 else if (ipv4 != Ipv4Address::GetAny() && port == 0)
622 {
623 m_endPoint = m_tcp->Allocate(ipv4);
624 }
625 else if (ipv4 != Ipv4Address::GetAny() && port != 0)
626 {
627 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(), ipv4, port);
628 }
629 if (nullptr == m_endPoint)
630 {
632 return -1;
633 }
634 }
635 else if (Inet6SocketAddress::IsMatchingType(address))
636 {
638 Ipv6Address ipv6 = transport.GetIpv6();
639 uint16_t port = transport.GetPort();
640 if (ipv6 == Ipv6Address::GetAny() && port == 0)
641 {
642 m_endPoint6 = m_tcp->Allocate6();
643 }
644 else if (ipv6 == Ipv6Address::GetAny() && port != 0)
645 {
646 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), port);
647 }
648 else if (ipv6 != Ipv6Address::GetAny() && port == 0)
649 {
650 m_endPoint6 = m_tcp->Allocate6(ipv6);
651 }
652 else if (ipv6 != Ipv6Address::GetAny() && port != 0)
653 {
654 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(), ipv6, port);
655 }
656 if (nullptr == m_endPoint6)
657 {
659 return -1;
660 }
661 }
662 else
663 {
665 return -1;
666 }
667
668 m_tcp->AddSocket(this);
669
670 NS_LOG_LOGIC("TcpSocketBase " << this << " got an endpoint: " << m_endPoint);
671
672 return SetupCallback();
673}
674
675void
677{
679 (m_state == CLOSED) || threshold == m_tcb->m_initialSsThresh,
680 "TcpSocketBase::SetSSThresh() cannot change initial ssThresh after connection started.");
681
682 m_tcb->m_initialSsThresh = threshold;
683}
684
687{
688 return m_tcb->m_initialSsThresh;
689}
690
691void
693{
695 (m_state == CLOSED) || cwnd == m_tcb->m_initialCWnd,
696 "TcpSocketBase::SetInitialCwnd() cannot change initial cwnd after connection started.");
697
698 m_tcb->m_initialCWnd = cwnd;
699}
700
703{
704 return m_tcb->m_initialCWnd;
705}
706
707/* Inherit from Socket class: Initiate connection to a remote address:port */
708int
710{
711 NS_LOG_FUNCTION(this << address);
712
713 // If haven't do so, Bind() this socket first
715 {
716 if (m_endPoint == nullptr)
717 {
718 if (Bind() == -1)
719 {
720 NS_ASSERT(m_endPoint == nullptr);
721 return -1; // Bind() failed
722 }
723 NS_ASSERT(m_endPoint != nullptr);
724 }
726 m_endPoint->SetPeer(transport.GetIpv4(), transport.GetPort());
727 m_endPoint6 = nullptr;
728
729 // Get the appropriate local address and port number from the routing protocol and set up
730 // endpoint
731 if (SetupEndpoint() != 0)
732 {
733 NS_LOG_ERROR("Route to destination does not exist ?!");
734 return -1;
735 }
736 }
737 else if (Inet6SocketAddress::IsMatchingType(address))
738 {
739 // If we are operating on a v4-mapped address, translate the address to
740 // a v4 address and re-call this function
742 Ipv6Address v6Addr = transport.GetIpv6();
743 if (v6Addr.IsIpv4MappedAddress())
744 {
745 Ipv4Address v4Addr = v6Addr.GetIpv4MappedAddress();
746 return Connect(InetSocketAddress(v4Addr, transport.GetPort()));
747 }
748
749 if (m_endPoint6 == nullptr)
750 {
751 if (Bind6() == -1)
752 {
753 NS_ASSERT(m_endPoint6 == nullptr);
754 return -1; // Bind() failed
755 }
756 NS_ASSERT(m_endPoint6 != nullptr);
757 }
758 m_endPoint6->SetPeer(v6Addr, transport.GetPort());
759 m_endPoint = nullptr;
760
761 // Get the appropriate local address and port number from the routing protocol and set up
762 // endpoint
763 if (SetupEndpoint6() != 0)
764 {
765 NS_LOG_ERROR("Route to destination does not exist ?!");
766 return -1;
767 }
768 }
769 else
770 {
772 return -1;
773 }
774
775 // Re-initialize parameters in case this socket is being reused after CLOSE
776 m_rtt->Reset();
779
780 // DoConnect() will do state-checking and send a SYN packet
781 return DoConnect();
782}
783
784/* Inherit from Socket class: Listen on the endpoint for an incoming connection */
785int
787{
788 NS_LOG_FUNCTION(this);
789
790 // Linux quits EINVAL if we're not in CLOSED state, so match what they do
791 if (m_state != CLOSED)
792 {
794 return -1;
795 }
796 // In other cases, set the state to LISTEN and done
797 NS_LOG_DEBUG("CLOSED -> LISTEN");
798 m_state = LISTEN;
799 return 0;
800}
801
802/* Inherit from Socket class: Kill this socket and signal the peer (if any) */
803int
805{
806 NS_LOG_FUNCTION(this);
807 /// @internal
808 /// First we check to see if there is any unread rx data.
809 /// \bugid{426} claims we should send reset in this case.
810 if (m_tcb->m_rxBuffer->Size() != 0)
811 {
812 NS_LOG_WARN("Socket " << this << " << unread rx data during close. Sending reset."
813 << "This is probably due to a bad sink application; check its code");
814 SendRST();
815 return 0;
816 }
817
818 if (m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence) > 0)
819 { // App close with pending data must wait until all data transmitted
820 if (!m_closeOnEmpty)
821 {
822 m_closeOnEmpty = true;
823 NS_LOG_INFO("Socket " << this << " deferring close, state " << TcpStateName[m_state]);
824 }
825 return 0;
826 }
827 return DoClose();
828}
829
830/* Inherit from Socket class: Signal a termination of send */
831int
833{
834 NS_LOG_FUNCTION(this);
835
836 // this prevents data from being added to the buffer
837 m_shutdownSend = true;
838 m_closeOnEmpty = true;
839 // if buffer is already empty, send a fin now
840 // otherwise fin will go when buffer empties.
841 if (m_txBuffer->Size() == 0)
842 {
844 {
845 NS_LOG_INFO("Empty tx buffer, send fin");
847
848 if (m_state == ESTABLISHED)
849 { // On active close: I am the first one to send FIN
850 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
852 }
853 else
854 { // On passive close: Peer sent me FIN already
855 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
857 }
858 }
859 }
860
861 return 0;
862}
863
864/* Inherit from Socket class: Signal a termination of receive */
865int
867{
868 NS_LOG_FUNCTION(this);
869 m_shutdownRecv = true;
870 return 0;
871}
872
873/* Inherit from Socket class: Send a packet. Parameter flags is not used.
874 Packet has no TCP header. Invoked by upper-layer application */
875int
877{
878 NS_LOG_FUNCTION(this << p);
879 NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Send()");
881 {
882 // Store the packet into Tx buffer
883 if (!m_txBuffer->Add(p))
884 { // TxBuffer overflow, send failed
886 return -1;
887 }
888 if (m_shutdownSend)
889 {
891 return -1;
892 }
893
894 m_rateOps->CalculateAppLimited(m_tcb->m_cWnd,
895 m_tcb->m_bytesInFlight,
896 m_tcb->m_segmentSize,
897 m_txBuffer->TailSequence(),
898 m_tcb->m_nextTxSequence,
899 m_txBuffer->GetLost(),
900 m_txBuffer->GetRetransmitsCount());
901
902 // Submit the data to lower layers
903 NS_LOG_LOGIC("txBufSize=" << m_txBuffer->Size() << " state " << TcpStateName[m_state]);
904 if ((m_state == ESTABLISHED || m_state == CLOSE_WAIT) && AvailableWindow() > 0)
905 { // Try to send the data out: Add a little step to allow the application
906 // to fill the buffer
908 {
911 this,
913 }
914 }
915 return p->GetSize();
916 }
917 else
918 { // Connection not established yet
920 return -1; // Send failure
921 }
922}
923
924/* Inherit from Socket class: In TcpSocketBase, it is same as Send() call */
925int
926TcpSocketBase::SendTo(Ptr<Packet> p, uint32_t flags, const Address& /* address */)
927{
928 return Send(p, flags); // SendTo() and Send() are the same
929}
930
931/* Inherit from Socket class: Return data to upper-layer application. Parameter flags
932 is not used. Data is returned as a packet of size no larger than maxSize */
935{
936 NS_LOG_FUNCTION(this);
937 NS_ABORT_MSG_IF(flags, "use of flags is not supported in TcpSocketBase::Recv()");
938 if (m_tcb->m_rxBuffer->Size() == 0 && m_state == CLOSE_WAIT)
939 {
940 return Create<Packet>(); // Send EOF on connection close
941 }
942 Ptr<Packet> outPacket = m_tcb->m_rxBuffer->Extract(maxSize);
943 return outPacket;
944}
945
946/* Inherit from Socket class: Recv and return the remote's address */
949{
950 NS_LOG_FUNCTION(this << maxSize << flags);
951 Ptr<Packet> packet = Recv(maxSize, flags);
952 // Null packet means no data to read, and an empty packet indicates EOF
953 if (packet && packet->GetSize() != 0)
954 {
955 if (m_endPoint != nullptr)
956 {
957 fromAddress =
959 }
960 else if (m_endPoint6 != nullptr)
961 {
962 fromAddress =
964 }
965 else
966 {
967 fromAddress = InetSocketAddress(Ipv4Address::GetZero(), 0);
968 }
969 }
970 return packet;
971}
972
973/* Inherit from Socket class: Get the max number of bytes an app can send */
976{
977 NS_LOG_FUNCTION(this);
978 return m_txBuffer->Available();
979}
980
981/* Inherit from Socket class: Get the max number of bytes an app can read */
984{
985 NS_LOG_FUNCTION(this);
986 return m_tcb->m_rxBuffer->Available();
987}
988
989/* Inherit from Socket class: Return local address:port */
990int
992{
993 NS_LOG_FUNCTION(this);
994 if (m_endPoint != nullptr)
995 {
997 }
998 else if (m_endPoint6 != nullptr)
999 {
1001 }
1002 else
1003 { // It is possible to call this method on a socket without a name
1004 // in which case, behavior is unspecified
1005 // Should this return an InetSocketAddress or an Inet6SocketAddress?
1007 }
1008 return 0;
1009}
1010
1011int
1013{
1014 NS_LOG_FUNCTION(this << address);
1015
1016 if (!m_endPoint && !m_endPoint6)
1017 {
1019 return -1;
1020 }
1021
1022 if (m_endPoint)
1023 {
1025 }
1026 else if (m_endPoint6)
1027 {
1029 }
1030 else
1031 {
1032 NS_ASSERT(false);
1033 }
1034
1035 return 0;
1036}
1037
1038/* Inherit from Socket class: Bind this socket to the specified NetDevice */
1039void
1041{
1042 NS_LOG_FUNCTION(netdevice);
1043 Socket::BindToNetDevice(netdevice); // Includes sanity check
1044 if (m_endPoint != nullptr)
1045 {
1046 m_endPoint->BindToNetDevice(netdevice);
1047 }
1048
1049 if (m_endPoint6 != nullptr)
1050 {
1051 m_endPoint6->BindToNetDevice(netdevice);
1052 }
1053}
1054
1055/* Clean up after Bind. Set up callback functions in the end-point. */
1056int
1086
1087/* Perform the real connection tasks: Send SYN if allowed, RST if invalid */
1088int
1090{
1091 NS_LOG_FUNCTION(this);
1092
1093 // A new connection is allowed only if this socket does not have a connection
1094 if (m_state == CLOSED || m_state == LISTEN || m_state == SYN_SENT || m_state == LAST_ACK ||
1096 { // send a SYN packet and change state into SYN_SENT
1097 // send a SYN packet with ECE and CWR flags set if sender is ECN capable
1098 if (m_tcb->m_useEcn == TcpSocketState::On)
1099 {
1101 }
1102 else
1103 {
1105 }
1106 NS_LOG_DEBUG(TcpStateName[m_state] << " -> SYN_SENT");
1107 m_state = SYN_SENT;
1108 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED; // because sender is not yet aware about
1109 // receiver's ECN capability
1110 }
1111 else if (m_state != TIME_WAIT)
1112 { // In states SYN_RCVD, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, and CLOSING, an connection
1113 // exists. We send RST, tear down everything, and close this socket.
1114 SendRST();
1116 }
1117 return 0;
1118}
1119
1120/* Do the action to close the socket. Usually send a packet with appropriate
1121 flags depended on the current m_state. */
1122int
1124{
1125 NS_LOG_FUNCTION(this);
1126 switch (m_state)
1127 {
1128 case SYN_RCVD:
1129 case ESTABLISHED:
1130 // send FIN to close the peer
1132 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
1134 break;
1135 case CLOSE_WAIT:
1136 // send FIN+ACK to close the peer
1138 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
1139 m_state = LAST_ACK;
1140 break;
1141 case SYN_SENT:
1142 case CLOSING:
1143 // Send RST if application closes in SYN_SENT and CLOSING
1144 SendRST();
1146 break;
1147 case LISTEN:
1148 // In this state, move to CLOSED and tear down the end point
1150 break;
1151 case LAST_ACK:
1152 case CLOSED:
1153 case FIN_WAIT_1:
1154 case FIN_WAIT_2:
1155 case TIME_WAIT:
1156 default: /* mute compiler */
1157 // Do nothing in these five states
1158 break;
1159 }
1160 return 0;
1161}
1162
1163/* Peacefully close the socket by notifying the upper layer and deallocate end point */
1164void
1166{
1167 NS_LOG_FUNCTION(this);
1168
1169 if (!m_closeNotified)
1170 {
1172 m_closeNotified = true;
1173 }
1175 {
1177 }
1178 NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSED");
1179 m_state = CLOSED;
1181}
1182
1183/* Tell if a sequence number range is out side the range that my rx buffer can
1184 accept */
1185bool
1187{
1188 if (m_state == LISTEN || m_state == SYN_SENT || m_state == SYN_RCVD)
1189 { // Rx buffer in these states are not initialized.
1190 return false;
1191 }
1192 if (m_state == LAST_ACK || m_state == CLOSING || m_state == CLOSE_WAIT)
1193 { // In LAST_ACK and CLOSING states, it only wait for an ACK and the
1194 // sequence number must equals to m_rxBuffer->NextRxSequence ()
1195 return (m_tcb->m_rxBuffer->NextRxSequence() != head);
1196 }
1197
1198 // In all other cases, check if the sequence number is in range
1199 return (tail < m_tcb->m_rxBuffer->NextRxSequence() ||
1200 m_tcb->m_rxBuffer->MaxRxSequence() <= head);
1201}
1202
1203/* Function called by the L3 protocol when it received a packet to pass on to
1204 the TCP. This function is registered as the "RxCallback" function in
1205 SetupCallback(), which invoked by Bind(), and CompleteFork() */
1206void
1208 Ipv4Header header,
1209 uint16_t port,
1210 Ptr<Ipv4Interface> incomingInterface)
1211{
1212 NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint->GetPeerAddress() << ":"
1213 << m_endPoint->GetPeerPort() << " to " << m_endPoint->GetLocalAddress()
1214 << ":" << m_endPoint->GetLocalPort());
1215
1216 Address fromAddress = InetSocketAddress(header.GetSource(), port);
1218
1219 TcpHeader tcpHeader;
1220 uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1221
1222 if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1223 bytesRemoved,
1224 packet->GetSize() - bytesRemoved))
1225 {
1226 return;
1227 }
1228
1229 if (header.GetEcn() == Ipv4Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1230 {
1231 NS_LOG_INFO("Received CE flag is valid");
1232 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
1233 m_ecnCESeq = tcpHeader.GetSequenceNumber();
1234 m_tcb->m_ecnState = TcpSocketState::ECN_CE_RCVD;
1236 }
1237 else if (header.GetEcn() != Ipv4Header::ECN_NotECT &&
1238 m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED)
1239 {
1241 }
1242
1243 DoForwardUp(packet, fromAddress, toAddress);
1244}
1245
1246void
1248 Ipv6Header header,
1249 uint16_t port,
1250 Ptr<Ipv6Interface> incomingInterface)
1251{
1252 NS_LOG_LOGIC("Socket " << this << " forward up " << m_endPoint6->GetPeerAddress() << ":"
1254 << ":" << m_endPoint6->GetLocalPort());
1255
1256 Address fromAddress = Inet6SocketAddress(header.GetSource(), port);
1258
1259 TcpHeader tcpHeader;
1260 uint32_t bytesRemoved = packet->PeekHeader(tcpHeader);
1261
1262 if (!IsValidTcpSegment(tcpHeader.GetSequenceNumber(),
1263 bytesRemoved,
1264 packet->GetSize() - bytesRemoved))
1265 {
1266 return;
1267 }
1268
1269 if (header.GetEcn() == Ipv6Header::ECN_CE && m_ecnCESeq < tcpHeader.GetSequenceNumber())
1270 {
1271 NS_LOG_INFO("Received CE flag is valid");
1272 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CE_RCVD");
1273 m_ecnCESeq = tcpHeader.GetSequenceNumber();
1274 m_tcb->m_ecnState = TcpSocketState::ECN_CE_RCVD;
1276 }
1277 else if (header.GetEcn() != Ipv6Header::ECN_NotECT)
1278 {
1280 }
1281
1282 DoForwardUp(packet, fromAddress, toAddress);
1283}
1284
1285void
1287 uint8_t icmpTtl,
1288 uint8_t icmpType,
1289 uint8_t icmpCode,
1290 uint32_t icmpInfo)
1291{
1292 NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1293 << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1294 << icmpInfo);
1295 if (!m_icmpCallback.IsNull())
1296 {
1297 m_icmpCallback(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1298 }
1299}
1300
1301void
1303 uint8_t icmpTtl,
1304 uint8_t icmpType,
1305 uint8_t icmpCode,
1306 uint32_t icmpInfo)
1307{
1308 NS_LOG_FUNCTION(this << icmpSource << static_cast<uint32_t>(icmpTtl)
1309 << static_cast<uint32_t>(icmpType) << static_cast<uint32_t>(icmpCode)
1310 << icmpInfo);
1311 if (!m_icmpCallback6.IsNull())
1312 {
1313 m_icmpCallback6(icmpSource, icmpTtl, icmpType, icmpCode, icmpInfo);
1314 }
1315}
1316
1317bool
1319 const uint32_t tcpHeaderSize,
1320 const uint32_t tcpPayloadSize)
1321{
1322 if (tcpHeaderSize == 0 || tcpHeaderSize > 60)
1323 {
1324 NS_LOG_ERROR("Bytes removed: " << tcpHeaderSize << " invalid");
1325 return false; // Discard invalid packet
1326 }
1327 else if (tcpPayloadSize > 0 && OutOfRange(seq, seq + tcpPayloadSize))
1328 {
1329 // Discard fully out of range data packets
1330 NS_LOG_WARN("At state " << TcpStateName[m_state] << " received packet of seq [" << seq
1331 << ":" << seq + tcpPayloadSize << ") out of range ["
1332 << m_tcb->m_rxBuffer->NextRxSequence() << ":"
1333 << m_tcb->m_rxBuffer->MaxRxSequence() << ")");
1334 // Acknowledgement should be sent for all unacceptable packets (RFC793, p.69)
1336 return false;
1337 }
1338 return true;
1339}
1340
1341void
1342TcpSocketBase::DoForwardUp(Ptr<Packet> packet, const Address& fromAddress, const Address& toAddress)
1343{
1344 // in case the packet still has a priority tag attached, remove it
1345 SocketPriorityTag priorityTag;
1346 packet->RemovePacketTag(priorityTag);
1347
1348 // Peel off TCP header
1349 TcpHeader tcpHeader;
1350 packet->RemoveHeader(tcpHeader);
1351 SequenceNumber32 seq = tcpHeader.GetSequenceNumber();
1352
1353 if (m_state == ESTABLISHED && !(tcpHeader.GetFlags() & TcpHeader::RST))
1354 {
1355 // Check if the sender has responded to ECN echo by reducing the Congestion Window
1356 if (tcpHeader.GetFlags() & TcpHeader::CWR)
1357 {
1358 // Check if a packet with CE bit set is received. If there is no CE bit set, then change
1359 // the state to ECN_IDLE to stop sending ECN Echo messages. If there is CE bit set, the
1360 // packet should continue sending ECN Echo messages
1361 //
1362 if (m_tcb->m_ecnState != TcpSocketState::ECN_CE_RCVD)
1363 {
1364 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
1365 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
1366 }
1367 }
1368 }
1369
1370 m_rxTrace(packet, tcpHeader, this);
1371
1372 if (tcpHeader.GetFlags() & TcpHeader::SYN)
1373 {
1374 /* The window field in a segment where the SYN bit is set (i.e., a <SYN>
1375 * or <SYN,ACK>) MUST NOT be scaled (from RFC 7323 page 9). But should be
1376 * saved anyway..
1377 */
1378 m_rWnd = tcpHeader.GetWindowSize();
1379
1381 {
1383 }
1384 else
1385 {
1386 m_winScalingEnabled = false;
1387 }
1388
1390 {
1392 }
1393 else
1394 {
1395 m_sackEnabled = false;
1396 m_txBuffer->SetSackEnabled(false);
1397 }
1398
1399 // When receiving a <SYN> or <SYN-ACK> we should adapt TS to the other end
1400 if (tcpHeader.HasOption(TcpOption::TS) && m_timestampEnabled)
1401 {
1403 tcpHeader.GetSequenceNumber());
1404 }
1405 else
1406 {
1407 m_timestampEnabled = false;
1408 }
1409
1410 // Initialize cWnd and ssThresh
1411 m_tcb->m_cWnd = GetInitialCwnd() * GetSegSize();
1412 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
1413 m_tcb->m_ssThresh = GetInitialSSThresh();
1414
1415 if (tcpHeader.GetFlags() & TcpHeader::ACK)
1416 {
1417 EstimateRtt(tcpHeader);
1418 m_highRxAckMark = tcpHeader.GetAckNumber();
1419 }
1420 }
1421 else if (tcpHeader.GetFlags() & TcpHeader::ACK)
1422 {
1423 NS_ASSERT(!(tcpHeader.GetFlags() & TcpHeader::SYN));
1425 {
1426 if (!tcpHeader.HasOption(TcpOption::TS))
1427 {
1428 // Ignoring segment without TS, RFC 7323
1429 NS_LOG_LOGIC("At state " << TcpStateName[m_state] << " received packet of seq ["
1430 << seq << ":" << seq + packet->GetSize()
1431 << ") without TS option. Silently discard it");
1432 return;
1433 }
1434 else
1435 {
1437 tcpHeader.GetSequenceNumber());
1438 }
1439 }
1440
1441 EstimateRtt(tcpHeader);
1442 UpdateWindowSize(tcpHeader);
1443 }
1444
1445 if (m_rWnd.Get() == 0 && m_persistEvent.IsExpired())
1446 { // Zero window: Enter persist state to send 1 byte to probe
1447 NS_LOG_LOGIC(this << " Enter zerowindow persist state");
1449 this << " Cancelled ReTxTimeout event which was set to expire at "
1450 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
1452 NS_LOG_LOGIC("Schedule persist timeout at time "
1453 << Simulator::Now().GetSeconds() << " to expire at time "
1454 << (Simulator::Now() + m_persistTimeout).GetSeconds());
1458 }
1459
1460 // TCP state machine code in different process functions
1461 // C.f.: tcp_rcv_state_process() in tcp_input.c in Linux kernel
1462 switch (m_state)
1463 {
1464 case ESTABLISHED:
1465 ProcessEstablished(packet, tcpHeader);
1466 break;
1467 case LISTEN:
1468 ProcessListen(packet, tcpHeader, fromAddress, toAddress);
1469 break;
1470 case TIME_WAIT:
1471 // Do nothing
1472 break;
1473 case CLOSED:
1474 // Send RST if the incoming packet is not a RST
1475 if ((tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG)) != TcpHeader::RST)
1476 { // Since m_endPoint is not configured yet, we cannot use SendRST here
1477 TcpHeader h;
1480 h.SetSequenceNumber(m_tcb->m_nextTxSequence);
1481 h.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
1482 h.SetSourcePort(tcpHeader.GetDestinationPort());
1483 h.SetDestinationPort(tcpHeader.GetSourcePort());
1485 AddOptions(h);
1486 m_txTrace(p, h, this);
1487 m_tcp->SendPacket(p, h, toAddress, fromAddress, m_boundnetdevice);
1488 }
1489 break;
1490 case SYN_SENT:
1491 ProcessSynSent(packet, tcpHeader);
1492 break;
1493 case SYN_RCVD:
1494 ProcessSynRcvd(packet, tcpHeader, fromAddress, toAddress);
1495 break;
1496 case FIN_WAIT_1:
1497 case FIN_WAIT_2:
1498 case CLOSE_WAIT:
1499 ProcessWait(packet, tcpHeader);
1500 break;
1501 case CLOSING:
1502 ProcessClosing(packet, tcpHeader);
1503 break;
1504 case LAST_ACK:
1505 ProcessLastAck(packet, tcpHeader);
1506 break;
1507 default: // mute compiler
1508 break;
1509 }
1510
1511 if (m_rWnd.Get() != 0 && m_persistEvent.IsPending())
1512 { // persist probes end, the other end has increased the window
1514 NS_LOG_LOGIC(this << " Leaving zerowindow persist state");
1516
1518 }
1519}
1520
1521/* Received a packet upon ESTABLISHED state. This function is mimicking the
1522 role of tcp_rcv_established() in tcp_input.c in Linux kernel. */
1523void
1525{
1526 NS_LOG_FUNCTION(this << tcpHeader);
1527
1528 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
1529 uint8_t tcpflags =
1531
1532 // Different flags are different events
1533 if (tcpflags == TcpHeader::ACK)
1534 {
1535 if (tcpHeader.GetAckNumber() < m_txBuffer->HeadSequence())
1536 {
1537 // Case 1: If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored.
1538 // Pag. 72 RFC 793
1539 NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1540 << " SND.UNA = " << m_txBuffer->HeadSequence());
1541
1542 // TODO: RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation]
1543 }
1544 else if (tcpHeader.GetAckNumber() > m_tcb->m_highTxMark)
1545 {
1546 // If the ACK acks something not yet sent (SEG.ACK > HighTxMark) then
1547 // send an ACK, drop the segment, and return.
1548 // Pag. 72 RFC 793
1549 NS_LOG_WARN("Ignored ack of " << tcpHeader.GetAckNumber()
1550 << " HighTxMark = " << m_tcb->m_highTxMark);
1551
1552 // Receiver sets ECE flags when it receives a packet with CE bit on or sender hasn't
1553 // responded to ECN echo sent by receiver
1554 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
1556 {
1559 << " -> ECN_SENDING_ECE");
1561 }
1562 else
1563 {
1565 }
1566 }
1567 else
1568 {
1569 // SND.UNA < SEG.ACK =< HighTxMark
1570 // Pag. 72 RFC 793
1571 ReceivedAck(packet, tcpHeader);
1572 }
1573 }
1574 else if (tcpflags == TcpHeader::SYN || tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
1575 {
1576 // (a) Received SYN, old NS-3 behaviour is to set state to SYN_RCVD and
1577 // respond with a SYN+ACK. But it is not a legal state transition as of
1578 // RFC793. Thus this is ignored.
1579
1580 // (b) No action for received SYN+ACK, it is probably a duplicated packet
1581 }
1582 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
1583 { // Received FIN or FIN+ACK, bring down this socket nicely
1584 PeerClose(packet, tcpHeader);
1585 }
1586 else if (tcpflags == 0)
1587 { // No flags means there is only data
1588 ReceivedData(packet, tcpHeader);
1589 if (m_tcb->m_rxBuffer->Finished())
1590 {
1591 PeerClose(packet, tcpHeader);
1592 }
1593 }
1594 else
1595 { // Received RST or the TCP flags is invalid, in either case, terminate this socket
1596 if (tcpflags != TcpHeader::RST)
1597 { // this must be an invalid flag, send reset
1598 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
1599 << " received. Reset packet is sent.");
1600 SendRST();
1601 }
1603 }
1604}
1605
1606bool
1608{
1609 NS_LOG_FUNCTION(this << static_cast<uint32_t>(kind));
1610
1611 switch (kind)
1612 {
1613 case TcpOption::TS:
1614 return m_timestampEnabled;
1616 return m_winScalingEnabled;
1618 case TcpOption::SACK:
1619 return m_sackEnabled;
1620 default:
1621 break;
1622 }
1623 return false;
1624}
1625
1626void
1627TcpSocketBase::ReadOptions(const TcpHeader& tcpHeader, uint32_t* bytesSacked)
1628{
1629 NS_LOG_FUNCTION(this << tcpHeader);
1630
1631 for (const auto& option : tcpHeader.GetOptionList())
1632 {
1633 // Check only for ACK options here
1634 switch (option->GetKind())
1635 {
1636 case TcpOption::SACK:
1637 *bytesSacked = ProcessOptionSack(option);
1638 break;
1639 default:
1640 continue;
1641 }
1642 }
1643}
1644
1645// Sender should reduce the Congestion Window as a response to receiver's
1646// ECN Echo notification only once per window
1647void
1649{
1650 NS_LOG_FUNCTION(this << currentDelivered);
1651 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, BytesInFlight());
1652 NS_LOG_DEBUG("Reduce ssThresh to " << m_tcb->m_ssThresh);
1653 // Do not update m_cWnd, under assumption that recovery process will
1654 // gradually bring it down to m_ssThresh. Update the 'inflated' value of
1655 // cWnd used for tracing, however.
1656 m_tcb->m_cWndInfl = m_tcb->m_ssThresh;
1657 NS_ASSERT(m_tcb->m_congState != TcpSocketState::CA_CWR);
1658 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_CWR");
1659 m_tcb->m_congState = TcpSocketState::CA_CWR;
1660 // CWR state will be exited when the ack exceeds the m_recover variable.
1661 // Do not set m_recoverActive (which applies to a loss-based recovery)
1662 // m_recover corresponds to Linux tp->high_seq
1663 m_recover = m_tcb->m_highTxMark;
1664 if (!m_congestionControl->HasCongControl())
1665 {
1666 // If there is a recovery algorithm, invoke it.
1667 m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1668 NS_LOG_INFO("Enter CWR recovery mode; set cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1669 << m_tcb->m_ssThresh << ", recover to "
1670 << m_recover);
1671 }
1672}
1673
1674void
1676{
1677 NS_LOG_FUNCTION(this);
1679
1680 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_RECOVERY");
1681
1682 if (!m_sackEnabled)
1683 {
1684 // One segment has left the network, PLUS the head is lost
1685 m_txBuffer->AddRenoSack();
1686 m_txBuffer->MarkHeadAsLost();
1687 }
1688 else
1689 {
1690 if (!m_txBuffer->IsLost(m_txBuffer->HeadSequence()))
1691 {
1692 // We received 3 dupacks, but the head is not marked as lost
1693 // (received less than 3 SACK block ahead).
1694 // Manually set it as lost.
1695 m_txBuffer->MarkHeadAsLost();
1696 }
1697 }
1698
1699 // RFC 6675, point (4):
1700 // (4) Invoke fast retransmit and enter loss recovery as follows:
1701 // (4.1) RecoveryPoint = HighData
1702 m_recover = m_tcb->m_highTxMark;
1703 m_recoverActive = true;
1704
1706 m_tcb->m_congState = TcpSocketState::CA_RECOVERY;
1707
1708 // (4.2) ssthresh = cwnd = (FlightSize / 2)
1709 // If SACK is not enabled, still consider the head as 'in flight' for
1710 // compatibility with old ns-3 versions
1711 uint32_t bytesInFlight =
1712 m_sackEnabled ? BytesInFlight() : BytesInFlight() + m_tcb->m_segmentSize;
1713 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, bytesInFlight);
1714
1715 if (!m_congestionControl->HasCongControl())
1716 {
1717 m_recoveryOps->EnterRecovery(m_tcb, m_dupAckCount, UnAckDataCount(), currentDelivered);
1718 NS_LOG_INFO(m_dupAckCount << " dupack. Enter fast recovery mode."
1719 << "Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to "
1720 << m_tcb->m_ssThresh << " at fast recovery seqnum " << m_recover
1721 << " calculated in flight: " << bytesInFlight);
1722 }
1723
1724 // (4.3) Retransmit the first data segment presumed dropped
1725 uint32_t sz = SendDataPacket(m_highRxAckMark, m_tcb->m_segmentSize, true);
1726 NS_ASSERT_MSG(sz > 0, "SendDataPacket returned zero, indicating zero bytes were sent");
1727 // (4.4) Run SetPipe ()
1728 // (4.5) Proceed to step (C)
1729 // these steps are done after the ProcessAck function (SendPendingData)
1730}
1731
1732void
1734{
1735 NS_LOG_FUNCTION(this);
1736 // NOTE: We do not count the DupAcks received in CA_LOSS, because we
1737 // don't know if they are generated by a spurious retransmission or because
1738 // of a real packet loss. With SACK, it is easy to know, but we do not consider
1739 // dupacks. Without SACK, there are some heuristics in the RFC 6582, but
1740 // for now, we do not implement it, leading to ignoring the dupacks.
1741 if (m_tcb->m_congState == TcpSocketState::CA_LOSS)
1742 {
1743 return;
1744 }
1745
1746 // RFC 6675, Section 5, 3rd paragraph:
1747 // If the incoming ACK is a duplicate acknowledgment per the definition
1748 // in Section 2 (regardless of its status as a cumulative
1749 // acknowledgment), and the TCP is not currently in loss recovery
1750 // the TCP MUST increase DupAcks by one ...
1751 if (m_tcb->m_congState != TcpSocketState::CA_RECOVERY)
1752 {
1753 ++m_dupAckCount;
1754 }
1755
1756 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
1757 {
1758 // From Open we go Disorder
1760 "From OPEN->DISORDER but with " << m_dupAckCount << " dup ACKs");
1761
1763 m_tcb->m_congState = TcpSocketState::CA_DISORDER;
1764
1765 NS_LOG_DEBUG("CA_OPEN -> CA_DISORDER");
1766 }
1767
1768 if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
1769 {
1770 if (!m_sackEnabled)
1771 {
1772 // If we are in recovery and we receive a dupack, one segment
1773 // has left the network. This is equivalent to a SACK of one block.
1774 m_txBuffer->AddRenoSack();
1775 }
1776 if (!m_congestionControl->HasCongControl())
1777 {
1778 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, true);
1779 NS_LOG_INFO(m_dupAckCount << " Dupack received in fast recovery mode."
1780 "Increase cwnd to "
1781 << m_tcb->m_cWnd);
1782 }
1783 }
1784 else if (m_tcb->m_congState == TcpSocketState::CA_DISORDER)
1785 {
1786 // m_dupackCount should not exceed its threshold in CA_DISORDER state
1787 // when m_recoverActive has not been set. When recovery point
1788 // have been set after timeout, the sender could enter into CA_DISORDER
1789 // after receiving new ACK smaller than m_recover. After that, m_dupackCount
1790 // can be equal and larger than m_retxThresh and we should avoid entering
1791 // CA_RECOVERY and reducing sending rate again.
1793
1794 // RFC 6675, Section 5, continuing:
1795 // ... and take the following steps:
1796 // (1) If DupAcks >= DupThresh, go to step (4).
1797 // Sequence number comparison (m_highRxAckMark >= m_recover) will take
1798 // effect only when m_recover has been set. Hence, we can avoid to use
1799 // m_recover in the last congestion event and fail to enter
1800 // CA_RECOVERY when sequence number is advanced significantly since
1801 // the last congestion event, which could be common for
1802 // bandwidth-greedy application in high speed and reliable network
1803 // (such as datacenter network) whose sending rate is constrained by
1804 // TCP socket buffer size at receiver side.
1805 if ((m_dupAckCount == m_retxThresh) &&
1807 {
1808 EnterRecovery(currentDelivered);
1810 }
1811 // (2) If DupAcks < DupThresh but IsLost (HighACK + 1) returns true
1812 // (indicating at least three segments have arrived above the current
1813 // cumulative acknowledgment point, which is taken to indicate loss)
1814 // go to step (4). Note that m_highRxAckMark is (HighACK + 1)
1815 else if (m_txBuffer->IsLost(m_highRxAckMark))
1816 {
1817 EnterRecovery(currentDelivered);
1819 }
1820 else
1821 {
1822 // (3) The TCP MAY transmit previously unsent data segments as per
1823 // Limited Transmit [RFC5681] ...except that the number of octets
1824 // which may be sent is governed by pipe and cwnd as follows:
1825 //
1826 // (3.1) Set HighRxt to HighACK.
1827 // Not clear in RFC. We don't do this here, since we still have
1828 // to retransmit the segment.
1829
1830 if (!m_sackEnabled && m_limitedTx)
1831 {
1832 m_txBuffer->AddRenoSack();
1833
1834 // In limited transmit, cwnd Infl is not updated.
1835 }
1836 }
1837 }
1838}
1839
1840/* Process the newly received ACK */
1841void
1843{
1844 NS_LOG_FUNCTION(this << tcpHeader);
1845
1846 NS_ASSERT(0 != (tcpHeader.GetFlags() & TcpHeader::ACK));
1847 NS_ASSERT(m_tcb->m_segmentSize > 0);
1848
1849 uint32_t previousLost = m_txBuffer->GetLost();
1850 uint32_t priorInFlight = m_tcb->m_bytesInFlight.Get();
1851
1852 // RFC 6675, Section 5, 1st paragraph:
1853 // Upon the receipt of any ACK containing SACK information, the
1854 // scoreboard MUST be updated via the Update () routine (done in ReadOptions)
1855 uint32_t bytesSacked = 0;
1856 uint64_t previousDelivered = m_rateOps->GetConnectionRate().m_delivered;
1857 ReadOptions(tcpHeader, &bytesSacked);
1858
1859 SequenceNumber32 ackNumber = tcpHeader.GetAckNumber();
1860 SequenceNumber32 oldHeadSequence = m_txBuffer->HeadSequence();
1861
1862 if (ackNumber < oldHeadSequence)
1863 {
1864 NS_LOG_DEBUG("Possibly received a stale ACK (ack number < head sequence)");
1865 // If there is any data piggybacked, store it into m_rxBuffer
1866 if (packet->GetSize() > 0)
1867 {
1868 ReceivedData(packet, tcpHeader);
1869 }
1870 return;
1871 }
1872 if ((ackNumber > oldHeadSequence) && (ackNumber < m_recover) &&
1873 (m_tcb->m_congState == TcpSocketState::CA_RECOVERY))
1874 {
1875 uint32_t segAcked = (ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
1876 for (uint32_t i = 0; i < segAcked; i++)
1877 {
1878 if (m_txBuffer->IsRetransmittedDataAcked(ackNumber - (i * m_tcb->m_segmentSize)))
1879 {
1880 m_tcb->m_isRetransDataAcked = true;
1881 NS_LOG_DEBUG("Ack Number " << ackNumber << "is ACK of retransmitted packet.");
1882 }
1883 }
1884 }
1885
1886 m_txBuffer->DiscardUpTo(ackNumber, MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
1887
1888 auto currentDelivered =
1889 static_cast<uint32_t>(m_rateOps->GetConnectionRate().m_delivered - previousDelivered);
1890 m_tcb->m_lastAckedSackedBytes = currentDelivered;
1891
1892 if (m_tcb->m_congState == TcpSocketState::CA_CWR && (ackNumber > m_recover))
1893 {
1894 // Recovery is over after the window exceeds m_recover
1895 // (although it may be re-entered below if ECE is still set)
1896 NS_LOG_DEBUG(TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_OPEN");
1897 m_tcb->m_congState = TcpSocketState::CA_OPEN;
1898 if (!m_congestionControl->HasCongControl())
1899 {
1900 m_tcb->m_cWnd = m_tcb->m_ssThresh.Get();
1901 m_recoveryOps->ExitRecovery(m_tcb);
1903 }
1904 }
1905
1906 if (ackNumber > oldHeadSequence && (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED) &&
1907 (tcpHeader.GetFlags() & TcpHeader::ECE))
1908 {
1909 if (m_ecnEchoSeq < ackNumber)
1910 {
1911 NS_LOG_INFO("Received ECN Echo is valid");
1912 m_ecnEchoSeq = ackNumber;
1913 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_ECE_RCVD");
1914 m_tcb->m_ecnState = TcpSocketState::ECN_ECE_RCVD;
1915 if (m_tcb->m_congState != TcpSocketState::CA_CWR)
1916 {
1917 EnterCwr(currentDelivered);
1918 }
1919 }
1920 }
1921 else if (m_tcb->m_ecnState == TcpSocketState::ECN_ECE_RCVD &&
1922 !(tcpHeader.GetFlags() & TcpHeader::ECE))
1923 {
1924 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
1925 }
1926
1927 // Update bytes in flight before processing the ACK for proper calculation of congestion window
1928 NS_LOG_INFO("Update bytes in flight before processing the ACK.");
1929 BytesInFlight();
1930
1931 bool receivedData = packet->GetSize() > 0;
1932
1933 // RFC 6675 Section 5: 2nd, 3rd paragraph and point (A), (B) implementation
1934 // are inside the function ProcessAck
1935 ProcessAck(ackNumber, (bytesSacked > 0), currentDelivered, oldHeadSequence, receivedData);
1936 m_tcb->m_isRetransDataAcked = false;
1937
1938 if (m_congestionControl->HasCongControl())
1939 {
1940 uint32_t currentLost = m_txBuffer->GetLost();
1941 uint32_t lost =
1942 (currentLost > previousLost) ? currentLost - previousLost : previousLost - currentLost;
1943 auto rateSample = m_rateOps->GenerateSample(currentDelivered,
1944 lost,
1945 false,
1946 priorInFlight,
1947 m_tcb->m_minRtt);
1948 auto rateConn = m_rateOps->GetConnectionRate();
1949 m_congestionControl->CongControl(m_tcb, rateConn, rateSample);
1950 }
1951
1952 // If there is any data piggybacked, store it into m_rxBuffer
1953 if (receivedData)
1954 {
1955 ReceivedData(packet, tcpHeader);
1956 }
1957
1958 // RFC 6675, Section 5, point (C), try to send more data. NB: (C) is implemented
1959 // inside SendPendingData
1961}
1962
1963void
1965 bool scoreboardUpdated,
1966 uint32_t currentDelivered,
1967 const SequenceNumber32& oldHeadSequence,
1968 bool receivedData)
1969{
1970 NS_LOG_FUNCTION(this << ackNumber << scoreboardUpdated << currentDelivered << oldHeadSequence);
1971 // RFC 6675, Section 5, 2nd paragraph:
1972 // If the incoming ACK is a cumulative acknowledgment, the TCP MUST
1973 // reset DupAcks to zero.
1974 bool exitedFastRecovery = false;
1975 uint32_t oldDupAckCount = m_dupAckCount; // remember the old value
1976 m_tcb->m_lastAckedSeq = ackNumber; // Update lastAckedSeq
1977 uint32_t bytesAcked = 0;
1978
1979 /* In RFC 5681 the definition of duplicate acknowledgment was strict:
1980 *
1981 * (a) the receiver of the ACK has outstanding data,
1982 * (b) the incoming acknowledgment carries no data,
1983 * (c) the SYN and FIN bits are both off,
1984 * (d) the acknowledgment number is equal to the greatest acknowledgment
1985 * received on the given connection (TCP.UNA from [RFC793]),
1986 * (e) the advertised window in the incoming acknowledgment equals the
1987 * advertised window in the last incoming acknowledgment.
1988 *
1989 * With RFC 6675, this definition has been reduced:
1990 *
1991 * (a) the ACK is carrying a SACK block that identifies previously
1992 * unacknowledged and un-SACKed octets between HighACK (TCP.UNA) and
1993 * HighData (m_highTxMark)
1994 *
1995 * The check below implements conditions a), b), and d), and c) is prevented by virtue of not
1996 * reaching this code if SYN or FIN is set, and e) is not supported.
1997 */
1998
1999 bool isDupack = m_sackEnabled ? scoreboardUpdated
2000 : (ackNumber == oldHeadSequence &&
2001 ackNumber < m_tcb->m_highTxMark && !receivedData);
2002
2003 NS_LOG_DEBUG("ACK of " << ackNumber << " SND.UNA=" << oldHeadSequence
2004 << " SND.NXT=" << m_tcb->m_nextTxSequence
2005 << " in state: " << TcpSocketState::TcpCongStateName[m_tcb->m_congState]
2006 << " with m_recover: " << m_recover);
2007
2008 // RFC 6675, Section 5, 3rd paragraph:
2009 // If the incoming ACK is a duplicate acknowledgment per the definition
2010 // in Section 2 (regardless of its status as a cumulative
2011 // acknowledgment), and the TCP is not currently in loss recovery
2012 if (isDupack)
2013 {
2014 // loss recovery check is done inside this function thanks to
2015 // the congestion state machine
2016 DupAck(currentDelivered);
2017 }
2018
2019 if (ackNumber == oldHeadSequence && ackNumber == m_tcb->m_highTxMark)
2020 {
2021 // Dupack, but the ACK is precisely equal to the nextTxSequence
2022 return;
2023 }
2024 else if (ackNumber == oldHeadSequence && ackNumber > m_tcb->m_highTxMark)
2025 {
2026 // ACK of the FIN bit ... nextTxSequence is not updated since we
2027 // don't have anything to transmit
2028 NS_LOG_DEBUG("Update nextTxSequence manually to " << ackNumber);
2029 m_tcb->m_nextTxSequence = ackNumber;
2030 }
2031 else if (ackNumber == oldHeadSequence)
2032 {
2033 // DupAck. Artificially call PktsAcked: after all, one segment has been ACKed.
2034 m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_srtt);
2035 }
2036 else if (ackNumber > oldHeadSequence)
2037 {
2038 // Please remember that, with SACK, we can enter here even if we
2039 // received a dupack.
2040 bytesAcked = currentDelivered;
2041 uint32_t segsAcked = bytesAcked / m_tcb->m_segmentSize;
2042 m_bytesAckedNotProcessed += bytesAcked % m_tcb->m_segmentSize;
2043 bytesAcked -= bytesAcked % m_tcb->m_segmentSize;
2044
2045 if (m_bytesAckedNotProcessed >= m_tcb->m_segmentSize)
2046 {
2047 segsAcked += 1;
2048 bytesAcked += m_tcb->m_segmentSize;
2049 m_bytesAckedNotProcessed -= m_tcb->m_segmentSize;
2050 }
2051 NS_LOG_DEBUG("Set segsAcked: " << segsAcked
2052 << " based on currentDelivered: " << currentDelivered);
2053
2054 // Dupack count is reset to eventually fast-retransmit after 3 dupacks.
2055 // Any SACK-ed segment will be cleaned up by DiscardUpTo.
2056 // In the case that we advanced SND.UNA, but the ack contains SACK blocks,
2057 // we do not reset. At the third one we will retransmit.
2058 // If we are already in recovery, this check is useless since dupAcks
2059 // are not considered in this phase. When from Recovery we go back
2060 // to open, then dupAckCount is reset anyway.
2061 if (!isDupack)
2062 {
2063 m_dupAckCount = 0;
2064 }
2065
2066 // RFC 6675, Section 5, part (B)
2067 // (B) Upon receipt of an ACK that does not cover RecoveryPoint, the
2068 // following actions MUST be taken:
2069 //
2070 // (B.1) Use Update () to record the new SACK information conveyed
2071 // by the incoming ACK.
2072 // (B.2) Use SetPipe () to re-calculate the number of octets still
2073 // in the network.
2074 //
2075 // (B.1) is done at the beginning, while (B.2) is delayed to part (C) while
2076 // trying to transmit with SendPendingData. We are not allowed to exit
2077 // the CA_RECOVERY phase. Just process this partial ack (RFC 5681)
2078 if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
2079 {
2080 if (!m_sackEnabled)
2081 {
2082 // Manually set the head as lost, it will be retransmitted.
2083 NS_LOG_INFO("Partial ACK. Manually setting head as lost");
2084 m_txBuffer->MarkHeadAsLost();
2085 }
2086
2087 // Before retransmitting the packet perform DoRecovery and check if
2088 // there is available window
2089 if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2090 {
2091 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, false);
2092 }
2093
2094 // If the packet is already retransmitted do not retransmit it
2095 if (!m_txBuffer->IsRetransmittedDataAcked(ackNumber + m_tcb->m_segmentSize))
2096 {
2097 DoRetransmit(); // Assume the next seq is lost. Retransmit lost packet
2098 m_tcb->m_cWndInfl = SafeSubtraction(m_tcb->m_cWndInfl, bytesAcked);
2099 }
2100
2101 // This partial ACK acknowledge the fact that one segment has been
2102 // previously lost and now successfully received. All others have
2103 // been processed when they come under the form of dupACKs
2104 m_congestionControl->PktsAcked(m_tcb, 1, m_tcb->m_srtt);
2105 NewAck(ackNumber, m_isFirstPartialAck);
2106
2108 {
2109 NS_LOG_DEBUG("Partial ACK of " << ackNumber
2110 << " and this is the first (RTO will be reset);"
2111 " cwnd set to "
2112 << m_tcb->m_cWnd << " recover seq: " << m_recover
2113 << " dupAck count: " << m_dupAckCount);
2114 m_isFirstPartialAck = false;
2115 }
2116 else
2117 {
2118 NS_LOG_DEBUG("Partial ACK of "
2119 << ackNumber
2120 << " and this is NOT the first (RTO will not be reset)"
2121 " cwnd set to "
2122 << m_tcb->m_cWnd << " recover seq: " << m_recover
2123 << " dupAck count: " << m_dupAckCount);
2124 }
2125 }
2126 // From RFC 6675 section 5.1
2127 // In addition, a new recovery phase (as described in Section 5) MUST NOT
2128 // be initiated until HighACK is greater than or equal to the new value
2129 // of RecoveryPoint.
2130 else if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_LOSS)
2131 {
2132 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2133 m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2134
2135 NS_LOG_DEBUG(" Cong Control Called, cWnd=" << m_tcb->m_cWnd
2136 << " ssTh=" << m_tcb->m_ssThresh);
2137 if (!m_sackEnabled)
2138 {
2140 m_txBuffer->GetSacked() == 0,
2141 "Some segment got dup-acked in CA_LOSS state: " << m_txBuffer->GetSacked());
2142 }
2143 NewAck(ackNumber, true);
2144 }
2145 else if (m_tcb->m_congState == TcpSocketState::CA_CWR)
2146 {
2147 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2148 // TODO: need to check behavior if marking is compounded by loss
2149 // and/or packet reordering
2150 if (!m_congestionControl->HasCongControl() && segsAcked >= 1)
2151 {
2152 m_recoveryOps->DoRecovery(m_tcb, currentDelivered, false);
2153 }
2154 NewAck(ackNumber, true);
2155 }
2156 else
2157 {
2158 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
2159 {
2160 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2161 }
2162 else if (m_tcb->m_congState == TcpSocketState::CA_DISORDER)
2163 {
2164 if (segsAcked >= oldDupAckCount)
2165 {
2166 m_congestionControl->PktsAcked(m_tcb,
2167 segsAcked - oldDupAckCount,
2168 m_tcb->m_srtt);
2169 }
2170
2171 if (!isDupack)
2172 {
2173 // The network reorder packets. Linux changes the counting lost
2174 // packet algorithm from FACK to NewReno. We simply go back in Open.
2176 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2177 NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2178 << " exiting CA_DISORDER -> CA_OPEN");
2179 }
2180 else
2181 {
2182 NS_LOG_DEBUG(segsAcked << " segments acked in CA_DISORDER, ack of " << ackNumber
2183 << " but still in CA_DISORDER");
2184 }
2185 }
2186 // RFC 6675, Section 5:
2187 // Once a TCP is in the loss recovery phase, the following procedure
2188 // MUST be used for each arriving ACK:
2189 // (A) An incoming cumulative ACK for a sequence number greater than
2190 // RecoveryPoint signals the end of loss recovery, and the loss
2191 // recovery phase MUST be terminated. Any information contained in
2192 // the scoreboard for sequence numbers greater than the new value of
2193 // HighACK SHOULD NOT be cleared when leaving the loss recovery
2194 // phase.
2195 else if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
2196 {
2197 m_isFirstPartialAck = true;
2198
2199 // Recalculate the segs acked, that are from m_recover to ackNumber
2200 // (which are the ones we have not passed to PktsAcked and that
2201 // can increase cWnd)
2202 // TODO: check consistency for dynamic segment size
2203 segsAcked =
2204 static_cast<uint32_t>(ackNumber - oldHeadSequence) / m_tcb->m_segmentSize;
2205 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2208 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2209 exitedFastRecovery = true;
2210 m_dupAckCount = 0; // From recovery to open, reset dupack
2211
2212 NS_LOG_DEBUG(segsAcked << " segments acked in CA_RECOVER, ack of " << ackNumber
2213 << ", exiting CA_RECOVERY -> CA_OPEN");
2214 }
2215 else if (m_tcb->m_congState == TcpSocketState::CA_LOSS)
2216 {
2217 m_isFirstPartialAck = true;
2218
2219 // Recalculate the segs acked, that are from m_recover to ackNumber
2220 // (which are the ones we have not passed to PktsAcked and that
2221 // can increase cWnd)
2222 segsAcked = (ackNumber - m_recover) / m_tcb->m_segmentSize;
2223
2224 m_congestionControl->PktsAcked(m_tcb, segsAcked, m_tcb->m_srtt);
2225
2227 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2228 NS_LOG_DEBUG(segsAcked << " segments acked in CA_LOSS, ack of" << ackNumber
2229 << ", exiting CA_LOSS -> CA_OPEN");
2230 }
2231
2232 if (ackNumber >= m_recover)
2233 {
2234 // All lost segments in the congestion event have been
2235 // retransmitted successfully. The recovery point (m_recover)
2236 // should be deactivated.
2237 m_recoverActive = false;
2238 }
2239
2240 if (exitedFastRecovery)
2241 {
2242 NewAck(ackNumber, true);
2243 m_tcb->m_cWnd = m_tcb->m_ssThresh.Get();
2244 m_recoveryOps->ExitRecovery(m_tcb);
2245 NS_LOG_DEBUG("Leaving Fast Recovery; BytesInFlight() = "
2246 << BytesInFlight() << "; cWnd = " << m_tcb->m_cWnd);
2247 }
2248 if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
2249 {
2250 m_congestionControl->IncreaseWindow(m_tcb, segsAcked);
2251
2252 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
2253
2254 NS_LOG_LOGIC("Congestion control called: cWnd: " << m_tcb->m_cWnd
2255 << " ssTh: " << m_tcb->m_ssThresh
2256 << " segsAcked: " << segsAcked);
2257
2258 NewAck(ackNumber, true);
2259 }
2260 }
2261 }
2262 // Update the pacing rate, since m_congestionControl->IncreaseWindow() or
2263 // m_congestionControl->PktsAcked () may change m_tcb->m_cWnd
2264 // Make sure that control reaches the end of this function and there is no
2265 // return in between
2267}
2268
2269/* Received a packet upon LISTEN state. */
2270void
2272 const TcpHeader& tcpHeader,
2273 const Address& fromAddress,
2274 const Address& toAddress)
2275{
2276 NS_LOG_FUNCTION(this << tcpHeader);
2277
2278 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2279 uint8_t tcpflags =
2281
2282 // Fork a socket if received a SYN. Do nothing otherwise.
2283 // C.f.: the LISTEN part in tcp_v4_do_rcv() in tcp_ipv4.c in Linux kernel
2284 if (tcpflags != TcpHeader::SYN)
2285 {
2286 return;
2287 }
2288
2289 // Call socket's notify function to let the server app know we got a SYN
2290 // If the server app refuses the connection, do nothing
2291 if (!NotifyConnectionRequest(fromAddress))
2292 {
2293 return;
2294 }
2295 // Clone the socket, simulate fork
2296 Ptr<TcpSocketBase> newSock = Fork();
2297 NS_LOG_LOGIC("Cloned a TcpSocketBase " << newSock);
2299 newSock,
2300 packet,
2301 tcpHeader,
2302 fromAddress,
2303 toAddress);
2304}
2305
2306/* Received a packet upon SYN_SENT */
2307void
2309{
2310 NS_LOG_FUNCTION(this << tcpHeader);
2311
2312 // Extract the flags. PSH and URG are disregarded.
2313 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2314
2315 if (tcpflags == 0)
2316 { // Bare data, accept it and move to ESTABLISHED state. This is not a normal behaviour. Remove
2317 // this?
2318 NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2320 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2322 m_connected = true;
2325 ReceivedData(packet, tcpHeader);
2327 }
2328 else if (tcpflags & TcpHeader::ACK && !(tcpflags & TcpHeader::SYN))
2329 { // Ignore ACK in SYN_SENT
2330 }
2331 else if (tcpflags & TcpHeader::SYN && !(tcpflags & TcpHeader::ACK))
2332 { // Received SYN, move to SYN_RCVD state and respond with SYN+ACK
2333 NS_LOG_DEBUG("SYN_SENT -> SYN_RCVD");
2334 m_state = SYN_RCVD;
2336 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2337 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2338 * the traffic is ECN capable and sender has sent ECN SYN packet
2339 */
2340
2341 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2343 {
2344 NS_LOG_INFO("Received ECN SYN packet");
2346 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2347 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2348 }
2349 else
2350 {
2351 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2353 }
2354 }
2355 else if (tcpflags & (TcpHeader::SYN | TcpHeader::ACK) &&
2356 m_tcb->m_nextTxSequence + SequenceNumber32(1) == tcpHeader.GetAckNumber())
2357 { // Handshake completed
2358 NS_LOG_DEBUG("SYN_SENT -> ESTABLISHED");
2360 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2362 m_connected = true;
2364 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2365 m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
2366 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2367 // Before sending packets, update the pacing rate based on RTT measurement so far
2370
2371 /* Check if we received an ECN SYN-ACK packet. Change the ECN state of sender to ECN_IDLE if
2372 * receiver has sent an ECN SYN-ACK packet and the traffic is ECN Capable
2373 */
2374 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2375 (tcpflags & (TcpHeader::CWR | TcpHeader::ECE)) == (TcpHeader::ECE))
2376 {
2377 NS_LOG_INFO("Received ECN SYN-ACK packet.");
2378 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2379 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2380 }
2381 else
2382 {
2383 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2384 }
2387 // Always respond to first data packet to speed up the connection.
2388 // Remove to get the behaviour of old NS-3 code.
2390 }
2391 else
2392 { // Other in-sequence input
2393 if (!(tcpflags & TcpHeader::RST))
2394 { // When (1) rx of FIN+ACK; (2) rx of FIN; (3) rx of bad flags
2395 NS_LOG_LOGIC("Illegal flag combination "
2396 << TcpHeader::FlagsToString(tcpHeader.GetFlags())
2397 << " received in SYN_SENT. Reset packet is sent.");
2398 SendRST();
2399 }
2401 }
2402}
2403
2404/* Received a packet upon SYN_RCVD */
2405void
2407 const TcpHeader& tcpHeader,
2408 const Address& fromAddress,
2409 const Address& /* toAddress */)
2410{
2411 NS_LOG_FUNCTION(this << tcpHeader);
2412
2413 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2414 uint8_t tcpflags =
2416
2417 if (tcpflags == 0 ||
2418 (tcpflags == TcpHeader::ACK &&
2419 m_tcb->m_nextTxSequence + SequenceNumber32(1) == tcpHeader.GetAckNumber()))
2420 { // If it is bare data, accept it and move to ESTABLISHED state. This is
2421 // possibly due to ACK lost in 3WHS. If in-sequence ACK is received, the
2422 // handshake is completed nicely.
2423 NS_LOG_DEBUG("SYN_RCVD -> ESTABLISHED");
2425 m_tcb->m_congState = TcpSocketState::CA_OPEN;
2427 m_connected = true;
2429 m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
2430 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2431 if (m_endPoint)
2432 {
2433 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2434 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2435 }
2436 else if (m_endPoint6)
2437 {
2438 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2439 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2440 }
2441 // Always respond to first data packet to speed up the connection.
2442 // Remove to get the behaviour of old NS-3 code.
2444 NotifyNewConnectionCreated(this, fromAddress);
2445 ReceivedAck(packet, tcpHeader);
2446 // Update the pacing rate based on RTT measurement so far
2448 // As this connection is established, the socket is available to send data now
2449 if (GetTxAvailable() > 0)
2450 {
2452 }
2453 }
2454 else if (tcpflags == TcpHeader::SYN)
2455 { // Probably the peer lost my SYN+ACK
2456 m_tcb->m_rxBuffer->SetNextRxSequence(tcpHeader.GetSequenceNumber() + SequenceNumber32(1));
2457 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
2458 * sender has sent an ECN SYN packet and the traffic is ECN Capable
2459 */
2460 if (m_tcb->m_useEcn != TcpSocketState::Off &&
2461 (tcpHeader.GetFlags() & (TcpHeader::CWR | TcpHeader::ECE)) ==
2463 {
2464 NS_LOG_INFO("Received ECN SYN packet");
2466 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
2467 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
2468 }
2469 else
2470 {
2471 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
2473 }
2474 }
2475 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2476 {
2477 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2478 { // In-sequence FIN before connection complete. Set up connection and close.
2479 m_connected = true;
2481 m_tcb->m_highTxMark = ++m_tcb->m_nextTxSequence;
2482 m_txBuffer->SetHeadSequence(m_tcb->m_nextTxSequence);
2483 if (m_endPoint)
2484 {
2485 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2486 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2487 }
2488 else if (m_endPoint6)
2489 {
2490 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2491 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2492 }
2493 NotifyNewConnectionCreated(this, fromAddress);
2494 PeerClose(packet, tcpHeader);
2495 }
2496 }
2497 else
2498 { // Other in-sequence input
2499 if (tcpflags != TcpHeader::RST)
2500 { // When (1) rx of SYN+ACK; (2) rx of FIN; (3) rx of bad flags
2501 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2502 << " received. Reset packet is sent.");
2503 if (m_endPoint)
2504 {
2505 m_endPoint->SetPeer(InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
2506 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
2507 }
2508 else if (m_endPoint6)
2509 {
2510 m_endPoint6->SetPeer(Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
2511 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
2512 }
2513 SendRST();
2514 }
2516 }
2517}
2518
2519/* Received a packet upon CLOSE_WAIT, FIN_WAIT_1, or FIN_WAIT_2 states */
2520void
2522{
2523 NS_LOG_FUNCTION(this << tcpHeader);
2524
2525 // Extract the flags. PSH, URG, CWR and ECE are disregarded.
2526 uint8_t tcpflags =
2528
2529 if (packet->GetSize() > 0 && !(tcpflags & TcpHeader::ACK))
2530 { // Bare data, accept it
2531 ReceivedData(packet, tcpHeader);
2532 }
2533 else if (tcpflags == TcpHeader::ACK)
2534 { // Process the ACK, and if in FIN_WAIT_1, conditionally move to FIN_WAIT_2
2535 ReceivedAck(packet, tcpHeader);
2536 if (m_state == FIN_WAIT_1 && m_txBuffer->Size() == 0 &&
2537 tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2538 { // This ACK corresponds to the FIN sent
2539 NS_LOG_DEBUG("FIN_WAIT_1 -> FIN_WAIT_2");
2541 }
2542 }
2543 else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2544 { // Got FIN, respond with ACK and move to next state
2545 if (tcpflags & TcpHeader::ACK)
2546 { // Process the ACK first
2547 ReceivedAck(packet, tcpHeader);
2548 }
2549 m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber());
2550 }
2551 else if (tcpflags == TcpHeader::SYN || tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
2552 { // Duplicated SYN or SYN+ACK, possibly due to spurious retransmission
2553 return;
2554 }
2555 else
2556 { // This is a RST or bad flags
2557 if (tcpflags != TcpHeader::RST)
2558 {
2559 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2560 << " received. Reset packet is sent.");
2561 SendRST();
2562 }
2564 return;
2565 }
2566
2567 // Check if the close responder sent an in-sequence FIN, if so, respond ACK
2568 if ((m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2) && m_tcb->m_rxBuffer->Finished())
2569 {
2570 if (m_state == FIN_WAIT_1)
2571 {
2572 NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2573 m_state = CLOSING;
2574 if (m_txBuffer->Size() == 0 &&
2575 tcpHeader.GetAckNumber() == m_tcb->m_highTxMark + SequenceNumber32(1))
2576 { // This ACK corresponds to the FIN sent
2577 TimeWait();
2578 }
2579 }
2580 else if (m_state == FIN_WAIT_2)
2581 {
2582 TimeWait();
2583 }
2585 if (!m_shutdownRecv)
2586 {
2588 }
2589 }
2590}
2591
2592/* Received a packet upon CLOSING */
2593void
2595{
2596 NS_LOG_FUNCTION(this << tcpHeader);
2597
2598 // Extract the flags. PSH and URG are disregarded.
2599 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2600
2601 if (tcpflags == TcpHeader::ACK)
2602 {
2603 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2604 { // This ACK corresponds to the FIN sent
2605 TimeWait();
2606 }
2607 }
2608 else
2609 { // CLOSING state means simultaneous close, i.e. no one is sending data to
2610 // anyone. If anything other than ACK is received, respond with a reset.
2611 if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
2612 { // FIN from the peer as well. We can close immediately.
2614 }
2615 else if (tcpflags != TcpHeader::RST)
2616 { // Receive of SYN or SYN+ACK or bad flags or pure data
2617 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2618 << " received. Reset packet is sent.");
2619 SendRST();
2620 }
2622 }
2623}
2624
2625/* Received a packet upon LAST_ACK */
2626void
2628{
2629 NS_LOG_FUNCTION(this << tcpHeader);
2630
2631 // Extract the flags. PSH and URG are disregarded.
2632 uint8_t tcpflags = tcpHeader.GetFlags() & ~(TcpHeader::PSH | TcpHeader::URG);
2633
2634 if (tcpflags == 0)
2635 {
2636 ReceivedData(packet, tcpHeader);
2637 }
2638 else if (tcpflags == TcpHeader::ACK)
2639 {
2640 if (tcpHeader.GetSequenceNumber() == m_tcb->m_rxBuffer->NextRxSequence())
2641 { // This ACK corresponds to the FIN sent. This socket closed peacefully.
2643 }
2644 }
2645 else if (tcpflags == TcpHeader::FIN)
2646 { // Received FIN again, the peer probably lost the FIN+ACK
2648 }
2649 else if (tcpflags == (TcpHeader::FIN | TcpHeader::ACK) || tcpflags == TcpHeader::RST)
2650 {
2652 }
2653 else
2654 { // Received a SYN or SYN+ACK or bad flags
2655 NS_LOG_LOGIC("Illegal flag " << TcpHeader::FlagsToString(tcpflags)
2656 << " received. Reset packet is sent.");
2657 SendRST();
2659 }
2660}
2661
2662/* Peer sent me a FIN. Remember its sequence in rx buffer. */
2663void
2665{
2666 NS_LOG_FUNCTION(this << tcpHeader);
2667
2668 // Ignore all out of range packets
2669 if (tcpHeader.GetSequenceNumber() < m_tcb->m_rxBuffer->NextRxSequence() ||
2670 tcpHeader.GetSequenceNumber() > m_tcb->m_rxBuffer->MaxRxSequence())
2671 {
2672 return;
2673 }
2674 // For any case, remember the FIN position in rx buffer first
2675 m_tcb->m_rxBuffer->SetFinSequence(tcpHeader.GetSequenceNumber() +
2676 SequenceNumber32(p->GetSize()));
2677 NS_LOG_LOGIC("Accepted FIN at seq "
2678 << tcpHeader.GetSequenceNumber() + SequenceNumber32(p->GetSize()));
2679 // If there is any piggybacked data, process it
2680 if (p->GetSize())
2681 {
2682 ReceivedData(p, tcpHeader);
2683 }
2684 // Return if FIN is out of sequence, otherwise move to CLOSE_WAIT state by DoPeerClose
2685 if (!m_tcb->m_rxBuffer->Finished())
2686 {
2687 return;
2688 }
2689
2690 // Simultaneous close: Application invoked Close() when we are processing this FIN packet
2691 if (m_state == FIN_WAIT_1)
2692 {
2693 NS_LOG_DEBUG("FIN_WAIT_1 -> CLOSING");
2694 m_state = CLOSING;
2695 return;
2696 }
2697
2698 DoPeerClose(); // Change state, respond with ACK
2699}
2700
2701/* Received a in-sequence FIN. Close down this socket. */
2702void
2704{
2706 m_state == FIN_WAIT_2);
2707
2708 // Move the state to CLOSE_WAIT
2709 NS_LOG_DEBUG(TcpStateName[m_state] << " -> CLOSE_WAIT");
2711
2712 if (!m_closeNotified)
2713 {
2714 // The normal behaviour for an application is that, when the peer sent a in-sequence
2715 // FIN, the app should prepare to close. The app has two choices at this point: either
2716 // respond with ShutdownSend() call to declare that it has nothing more to send and
2717 // the socket can be closed immediately; or remember the peer's close request, wait
2718 // until all its existing data are pushed into the TCP socket, then call Close()
2719 // explicitly.
2720 NS_LOG_LOGIC("TCP " << this << " calling NotifyNormalClose");
2722 m_closeNotified = true;
2723 }
2724 if (m_shutdownSend)
2725 { // The application declares that it would not sent any more, close this socket
2726 Close();
2727 }
2728 else
2729 { // Need to ack, the application will close later
2731 }
2732 if (m_state == LAST_ACK)
2733 {
2734 m_dataRetrCount = m_dataRetries; // prevent endless FINs
2735 NS_LOG_LOGIC("TcpSocketBase " << this << " scheduling LATO1");
2736 Time lastRto = m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4);
2738 }
2739}
2740
2741/* Kill this socket. This is a callback function configured to m_endpoint in
2742 SetupCallback(), invoked when the endpoint is destroyed. */
2743void
2745{
2746 NS_LOG_FUNCTION(this);
2747 m_endPoint = nullptr;
2748 if (m_tcp)
2749 {
2750 m_tcp->RemoveSocket(this);
2751 }
2752 NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2753 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2755}
2756
2757/* Kill this socket. This is a callback function configured to m_endpoint in
2758 SetupCallback(), invoked when the endpoint is destroyed. */
2759void
2761{
2762 NS_LOG_FUNCTION(this);
2763 m_endPoint6 = nullptr;
2764 if (m_tcp)
2765 {
2766 m_tcp->RemoveSocket(this);
2767 }
2768 NS_LOG_LOGIC(this << " Cancelled ReTxTimeout event which was set to expire at "
2769 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
2771}
2772
2773/* Send an empty packet with specified TCP flags */
2774void
2776{
2777 NS_LOG_FUNCTION(this << static_cast<uint32_t>(flags));
2778
2779 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
2780 {
2781 NS_LOG_WARN("Failed to send empty packet due to null endpoint");
2782 return;
2783 }
2784
2786 TcpHeader header;
2787 SequenceNumber32 s = m_tcb->m_nextTxSequence;
2788 TcpPacketType_t packetType = INVALID;
2789
2790 if (flags & TcpHeader::FIN)
2791 {
2792 packetType = TcpPacketType_t::FIN;
2793 flags |= TcpHeader::ACK;
2794 }
2795 else if (m_state == FIN_WAIT_1 || m_state == LAST_ACK || m_state == CLOSING)
2796 {
2797 ++s;
2798 }
2799
2800 if (flags & TcpHeader::SYN)
2801 {
2802 packetType = TcpPacketType_t::SYN;
2803 if (flags & TcpHeader::ACK)
2804 {
2805 packetType = TcpPacketType_t::SYN_ACK;
2806 }
2807 }
2808 else if (flags & TcpHeader::ACK)
2809 {
2810 packetType = TcpPacketType_t::PURE_ACK;
2811 }
2812
2813 if (flags & TcpHeader::RST)
2814 {
2815 packetType = TcpPacketType_t::RST;
2816 }
2817
2818 NS_ASSERT_MSG(packetType != TcpPacketType_t::INVALID, "Invalid TCP packet type");
2819 AddSocketTags(p, IsEct(packetType));
2820
2821 header.SetFlags(flags);
2822 header.SetSequenceNumber(s);
2823 header.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
2824 if (m_endPoint != nullptr)
2825 {
2828 }
2829 else
2830 {
2833 }
2834 AddOptions(header);
2835
2836 // RFC 6298, clause 2.4
2837 m_rto =
2838 Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4), m_minRto);
2839
2840 uint16_t windowSize = AdvertisedWindowSize();
2841 bool hasSyn = flags & TcpHeader::SYN;
2842 bool hasFin = flags & TcpHeader::FIN;
2843 bool isAck = flags == TcpHeader::ACK;
2844 if (hasSyn)
2845 {
2847 { // The window scaling option is set only on SYN packets
2848 AddOptionWScale(header);
2849 }
2850
2851 if (m_sackEnabled)
2852 {
2853 AddOptionSackPermitted(header);
2854 }
2855
2856 if (m_synCount == 0)
2857 { // No more connection retries, give up
2858 NS_LOG_LOGIC("Connection failed.");
2859 m_rtt->Reset(); // According to recommendation -> RFC 6298
2861 m_state = CLOSED;
2863 return;
2864 }
2865 else
2866 { // Exponential backoff of connection time out
2867 int backoffCount = 0x1 << (m_synRetries - m_synCount);
2868 m_rto = m_cnTimeout * backoffCount;
2869 m_synCount--;
2870 }
2871
2872 if (m_synRetries - 1 == m_synCount)
2873 {
2874 UpdateRttHistory(s, 0, false);
2875 }
2876 else
2877 { // This is SYN retransmission
2878 UpdateRttHistory(s, 0, true);
2879 }
2880
2881 windowSize = AdvertisedWindowSize(false);
2882 }
2883 header.SetWindowSize(windowSize);
2884
2885 if (flags & TcpHeader::ACK)
2886 { // If sending an ACK, cancel the delay ACK as well
2888 m_delAckCount = 0;
2889 if (m_highTxAck < header.GetAckNumber())
2890 {
2891 m_highTxAck = header.GetAckNumber();
2892 }
2893 if (m_sackEnabled && m_tcb->m_rxBuffer->GetSackListSize() > 0)
2894 {
2895 AddOptionSack(header);
2896 }
2897 NS_LOG_INFO("Sending a pure ACK, acking seq " << m_tcb->m_rxBuffer->NextRxSequence());
2898 }
2899
2900 m_txTrace(p, header, this);
2901
2902 if (m_endPoint != nullptr)
2903 {
2904 m_tcp->SendPacket(p,
2905 header,
2909 }
2910 else
2911 {
2912 m_tcp->SendPacket(p,
2913 header,
2917 }
2918
2919 if (m_retxEvent.IsExpired() && (hasSyn || hasFin) && !isAck)
2920 { // Retransmit SYN / SYN+ACK / FIN / FIN+ACK to guard against lost
2921 NS_LOG_LOGIC("Schedule retransmission timeout at time "
2922 << Simulator::Now().GetSeconds() << " to expire at time "
2923 << (Simulator::Now() + m_rto.Get()).GetSeconds());
2925 }
2926}
2927
2928/* This function closes the endpoint completely. Called upon RST_TX action. */
2929void
2937
2938/* Deallocate the end point and cancel all the timers */
2939void
2941{
2942 // note: it shouldn't be necessary to invalidate the callback and manually call
2943 // TcpL4Protocol::RemoveSocket. Alas, if one relies on the endpoint destruction
2944 // callback, there's a weird memory access to a free'd area. Harmless, but valgrind
2945 // considers it an error.
2946
2947 if (m_endPoint != nullptr)
2948 {
2951 m_tcp->DeAllocate(m_endPoint);
2952 m_endPoint = nullptr;
2953 m_tcp->RemoveSocket(this);
2954 }
2955 else if (m_endPoint6 != nullptr)
2956 {
2959 m_tcp->DeAllocate(m_endPoint6);
2960 m_endPoint6 = nullptr;
2961 m_tcp->RemoveSocket(this);
2962 }
2963}
2964
2965/* Configure the endpoint to a local address. Called by Connect() if Bind() didn't specify one. */
2966int
2968{
2969 NS_LOG_FUNCTION(this);
2970 Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4>();
2971 NS_ASSERT(ipv4);
2972 if (!ipv4->GetRoutingProtocol())
2973 {
2974 NS_FATAL_ERROR("No Ipv4RoutingProtocol in the node");
2975 }
2976 // Create a dummy packet, then ask the routing function for the best output
2977 // interface's address
2978 Ipv4Header header;
2980 Socket::SocketErrno errno_;
2981 Ptr<Ipv4Route> route;
2983 route = ipv4->GetRoutingProtocol()->RouteOutput(Ptr<Packet>(), header, oif, errno_);
2984 if (!route)
2985 {
2986 NS_LOG_LOGIC("Route to " << m_endPoint->GetPeerAddress() << " does not exist");
2987 NS_LOG_ERROR(errno_);
2988 m_errno = errno_;
2989 return -1;
2990 }
2991 NS_LOG_LOGIC("Route exists");
2992 m_endPoint->SetLocalAddress(route->GetSource());
2993 return 0;
2994}
2995
2996int
2998{
2999 NS_LOG_FUNCTION(this);
3001 NS_ASSERT(ipv6);
3002 if (!ipv6->GetRoutingProtocol())
3003 {
3004 NS_FATAL_ERROR("No Ipv6RoutingProtocol in the node");
3005 }
3006 // Create a dummy packet, then ask the routing function for the best output
3007 // interface's address
3008 Ipv6Header header;
3010 Socket::SocketErrno errno_;
3011 Ptr<Ipv6Route> route;
3013 route = ipv6->GetRoutingProtocol()->RouteOutput(Ptr<Packet>(), header, oif, errno_);
3014 if (!route)
3015 {
3016 NS_LOG_LOGIC("Route to " << m_endPoint6->GetPeerAddress() << " does not exist");
3017 NS_LOG_ERROR(errno_);
3018 m_errno = errno_;
3019 return -1;
3020 }
3021 NS_LOG_LOGIC("Route exists");
3022 m_endPoint6->SetLocalAddress(route->GetSource());
3023 return 0;
3024}
3025
3026/* This function is called only if a SYN received in LISTEN state. After
3027 TcpSocketBase cloned, allocate a new end point to handle the incoming
3028 connection and send a SYN+ACK to complete the handshake. */
3029void
3031 const TcpHeader& h,
3032 const Address& fromAddress,
3033 const Address& toAddress)
3034{
3035 NS_LOG_FUNCTION(this << p << h << fromAddress << toAddress);
3036 // Get port and address from peer (connecting host)
3037 if (InetSocketAddress::IsMatchingType(toAddress))
3038 {
3039 m_endPoint = m_tcp->Allocate(GetBoundNetDevice(),
3040 InetSocketAddress::ConvertFrom(toAddress).GetIpv4(),
3041 InetSocketAddress::ConvertFrom(toAddress).GetPort(),
3042 InetSocketAddress::ConvertFrom(fromAddress).GetIpv4(),
3043 InetSocketAddress::ConvertFrom(fromAddress).GetPort());
3044 m_endPoint6 = nullptr;
3045 }
3046 else if (Inet6SocketAddress::IsMatchingType(toAddress))
3047 {
3048 m_endPoint6 = m_tcp->Allocate6(GetBoundNetDevice(),
3049 Inet6SocketAddress::ConvertFrom(toAddress).GetIpv6(),
3050 Inet6SocketAddress::ConvertFrom(toAddress).GetPort(),
3051 Inet6SocketAddress::ConvertFrom(fromAddress).GetIpv6(),
3052 Inet6SocketAddress::ConvertFrom(fromAddress).GetPort());
3053 m_endPoint = nullptr;
3054 }
3055 m_tcp->AddSocket(this);
3056
3057 // Change the cloned socket from LISTEN state to SYN_RCVD
3058 NS_LOG_DEBUG("LISTEN -> SYN_RCVD");
3059 m_state = SYN_RCVD;
3062 SetupCallback();
3063 // Set the sequence number and send SYN+ACK
3064 m_tcb->m_rxBuffer->SetNextRxSequence(h.GetSequenceNumber() + SequenceNumber32(1));
3065
3066 /* Check if we received an ECN SYN packet. Change the ECN state of receiver to ECN_IDLE if
3067 * sender has sent an ECN SYN packet and the traffic is ECN Capable
3068 */
3069 if (m_tcb->m_useEcn != TcpSocketState::Off &&
3071 {
3073 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_IDLE");
3074 m_tcb->m_ecnState = TcpSocketState::ECN_IDLE;
3075 }
3076 else
3077 {
3079 m_tcb->m_ecnState = TcpSocketState::ECN_DISABLED;
3080 }
3081}
3082
3083void
3085{ // Wrapper to protected function NotifyConnectionSucceeded() so that it can
3086 // be called as a scheduled event
3088 // The if-block below was moved from ProcessSynSent() to here because we need
3089 // to invoke the NotifySend() only after NotifyConnectionSucceeded() to
3090 // reflect the behaviour in the real world.
3091 if (GetTxAvailable() > 0)
3092 {
3094 }
3095}
3096
3097void
3099{
3100 /*
3101 * Add tags for each socket option.
3102 * Note that currently the socket adds both IPv4 tag and IPv6 tag
3103 * if both options are set. Once the packet got to layer three, only
3104 * the corresponding tags will be read.
3105 */
3106 if (GetIpTos())
3107 {
3108 SocketIpTosTag ipTosTag;
3109 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !CheckNoEcn(GetIpTos()) && isEct)
3110 {
3111 ipTosTag.SetTos(MarkEcnCodePoint(GetIpTos(), m_tcb->m_ectCodePoint));
3112 }
3113 else
3114 {
3115 // Set the last received ipTos
3116 ipTosTag.SetTos(GetIpTos());
3117 }
3118 p->AddPacketTag(ipTosTag);
3119 }
3120 else
3121 {
3122 if ((m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && p->GetSize() > 0 && isEct) ||
3123 m_tcb->m_ecnMode == TcpSocketState::DctcpEcn)
3124 {
3125 SocketIpTosTag ipTosTag;
3126 ipTosTag.SetTos(MarkEcnCodePoint(GetIpTos(), m_tcb->m_ectCodePoint));
3127 p->AddPacketTag(ipTosTag);
3128 }
3129 }
3130
3131 if (IsManualIpv6Tclass())
3132 {
3133 SocketIpv6TclassTag ipTclassTag;
3134 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !CheckNoEcn(GetIpv6Tclass()) &&
3135 isEct)
3136 {
3137 ipTclassTag.SetTclass(MarkEcnCodePoint(GetIpv6Tclass(), m_tcb->m_ectCodePoint));
3138 }
3139 else
3140 {
3141 // Set the last received ipTos
3142 ipTclassTag.SetTclass(GetIpv6Tclass());
3143 }
3144 p->AddPacketTag(ipTclassTag);
3145 }
3146 else
3147 {
3148 if ((m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && p->GetSize() > 0 && isEct) ||
3149 m_tcb->m_ecnMode == TcpSocketState::DctcpEcn)
3150 {
3151 SocketIpv6TclassTag ipTclassTag;
3152 ipTclassTag.SetTclass(MarkEcnCodePoint(GetIpv6Tclass(), m_tcb->m_ectCodePoint));
3153 p->AddPacketTag(ipTclassTag);
3154 }
3155 }
3156
3157 if (IsManualIpTtl())
3158 {
3159 SocketIpTtlTag ipTtlTag;
3160 ipTtlTag.SetTtl(GetIpTtl());
3161 p->AddPacketTag(ipTtlTag);
3162 }
3163
3165 {
3166 SocketIpv6HopLimitTag ipHopLimitTag;
3167 ipHopLimitTag.SetHopLimit(GetIpv6HopLimit());
3168 p->AddPacketTag(ipHopLimitTag);
3169 }
3170
3171 uint8_t priority = GetPriority();
3172 if (priority)
3173 {
3174 SocketPriorityTag priorityTag;
3175 priorityTag.SetPriority(priority);
3176 p->ReplacePacketTag(priorityTag);
3177 }
3178}
3179
3180/* Extract at most maxSize bytes from the TxBuffer at sequence seq, add the
3181 TCP header, and send to TcpL4Protocol */
3184{
3185 NS_LOG_FUNCTION(this << seq << maxSize << withAck);
3186
3187 bool isStartOfTransmission = BytesInFlight() == 0U;
3188 TcpTxItem* outItem = m_txBuffer->CopyFromSequence(maxSize, seq);
3189
3190 m_rateOps->SkbSent(outItem, isStartOfTransmission);
3191
3192 bool isRetransmission = outItem->IsRetrans();
3193 Ptr<Packet> p = outItem->GetPacketCopy();
3194 uint32_t sz = p->GetSize(); // Size of packet
3195 uint8_t flags = withAck ? TcpHeader::ACK : 0;
3196 uint32_t remainingData = m_txBuffer->SizeFromSequence(seq + SequenceNumber32(sz));
3197
3198 // TCP sender should not send data out of the window advertised by the
3199 // peer when it is not retransmission.
3200 NS_ASSERT(isRetransmission ||
3201 ((m_highRxAckMark + SequenceNumber32(m_rWnd)) >= (seq + SequenceNumber32(maxSize))));
3202
3203 if (IsPacingEnabled())
3204 {
3205 NS_LOG_INFO("Pacing is enabled");
3207 {
3208 NS_LOG_DEBUG("Current Pacing Rate " << m_tcb->m_pacingRate);
3209 NS_LOG_DEBUG("Timer is in expired state, activate it "
3210 << m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3211 m_pacingTimer.Schedule(m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3212 }
3213 else
3214 {
3215 NS_LOG_INFO("Timer is already in running state");
3216 }
3217 }
3218 else
3219 {
3220 NS_LOG_INFO("Pacing is disabled");
3221 }
3222
3223 if (withAck)
3224 {
3226 m_delAckCount = 0;
3227 }
3228
3229 if (m_tcb->m_ecnState == TcpSocketState::ECN_ECE_RCVD &&
3230 m_ecnEchoSeq.Get() > m_ecnCWRSeq.Get() && !isRetransmission)
3231 {
3232 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CWR_SENT");
3233 m_tcb->m_ecnState = TcpSocketState::ECN_CWR_SENT;
3234 m_ecnCWRSeq = seq;
3235 flags |= TcpHeader::CWR;
3236 NS_LOG_INFO("CWR flags set");
3237 }
3238
3239 bool isEct = IsEct(isRetransmission ? TcpPacketType_t::RE_XMT : TcpPacketType_t::DATA);
3240 AddSocketTags(p, isEct);
3241
3242 if (m_closeOnEmpty && (remainingData == 0))
3243 {
3244 flags |= TcpHeader::FIN;
3245 if (m_state == ESTABLISHED)
3246 { // On active close: I am the first one to send FIN
3247 NS_LOG_DEBUG("ESTABLISHED -> FIN_WAIT_1");
3249 }
3250 else if (m_state == CLOSE_WAIT)
3251 { // On passive close: Peer sent me FIN already
3252 NS_LOG_DEBUG("CLOSE_WAIT -> LAST_ACK");
3253 m_state = LAST_ACK;
3254 }
3255 }
3256 TcpHeader header;
3257 header.SetFlags(flags);
3258 header.SetSequenceNumber(seq);
3259 header.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
3260 if (m_endPoint)
3261 {
3264 }
3265 else
3266 {
3269 }
3271 AddOptions(header);
3272
3273 if (m_retxEvent.IsExpired())
3274 {
3275 // Schedules retransmit timeout. m_rto should be already doubled.
3276
3277 NS_LOG_LOGIC(this << " SendDataPacket Schedule ReTxTimeout at time "
3278 << Simulator::Now().GetSeconds() << " to expire at time "
3279 << (Simulator::Now() + m_rto.Get()).GetSeconds());
3281 }
3282
3283 m_txTrace(p, header, this);
3284 if (isRetransmission)
3285 {
3286 if (m_endPoint)
3287 {
3289 header,
3292 this);
3293 }
3294 else
3295 {
3297 header,
3300 this);
3301 }
3302 }
3303
3304 if (m_endPoint)
3305 {
3306 m_tcp->SendPacket(p,
3307 header,
3311 NS_LOG_DEBUG("Send segment of size "
3312 << sz << " with remaining data " << remainingData << " via TcpL4Protocol to "
3313 << m_endPoint->GetPeerAddress() << ". Header " << header);
3314 }
3315 else
3316 {
3317 m_tcp->SendPacket(p,
3318 header,
3322 NS_LOG_DEBUG("Send segment of size "
3323 << sz << " with remaining data " << remainingData << " via TcpL4Protocol to "
3324 << m_endPoint6->GetPeerAddress() << ". Header " << header);
3325 }
3326
3327 // Signal to congestion control whether the cwnd is fully used
3328 // This is a simple version of Linux tcp_cwnd_validate() but following
3329 // the principle implemented in Linux that limits the updating of cwnd
3330 // (in the congestion controls) when flight size is >= cwnd
3331 // send will also be cwnd limited if less then one segment of cwnd is available
3332 m_tcb->m_isCwndLimited = (m_tcb->m_cWnd < BytesInFlight() + m_tcb->m_segmentSize);
3333
3334 UpdateRttHistory(seq, sz, isRetransmission);
3335
3336 // Update bytes sent during recovery phase
3337 if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY ||
3338 m_tcb->m_congState == TcpSocketState::CA_CWR)
3339 {
3340 m_recoveryOps->UpdateBytesSent(sz);
3341 }
3342
3343 // Notify the application of the data being sent unless this is a retransmit
3344 if (!isRetransmission)
3345 {
3347 this,
3348 (seq + sz - m_tcb->m_highTxMark.Get()));
3349 }
3350 // Update highTxMark
3351 m_tcb->m_highTxMark = std::max(seq + sz, m_tcb->m_highTxMark.Get());
3352 return sz;
3353}
3354
3355void
3356TcpSocketBase::UpdateRttHistory(const SequenceNumber32& seq, uint32_t sz, bool isRetransmission)
3357{
3358 NS_LOG_FUNCTION(this);
3359
3360 // update the history of sequence numbers used to calculate the RTT
3361 if (!isRetransmission)
3362 { // This is the next expected one, just log at end
3363 m_history.emplace_back(seq, sz, Simulator::Now());
3364 }
3365 else
3366 { // This is a retransmit, find in list and mark as re-tx
3367 for (auto i = m_history.begin(); i != m_history.end(); ++i)
3368 {
3369 if ((seq >= i->seq) && (seq < (i->seq + SequenceNumber32(i->count))))
3370 { // Found it
3371 i->retx = true;
3372 i->count = ((seq + SequenceNumber32(sz)) - i->seq); // And update count in hist
3373 break;
3374 }
3375 }
3376 }
3377}
3378
3379// Note that this function did not implement the PSH flag
3382{
3383 NS_LOG_FUNCTION(this << withAck);
3384 if (m_txBuffer->Size() == 0)
3385 {
3386 return 0; // Nothing to send
3387 }
3388 if (m_endPoint == nullptr && m_endPoint6 == nullptr)
3389 {
3391 "TcpSocketBase::SendPendingData: No endpoint; m_shutdownSend=" << m_shutdownSend);
3392 return 0; // Is this the right way to handle this condition?
3393 }
3394
3395 uint32_t nPacketsSent = 0;
3396 uint32_t availableWindow = AvailableWindow();
3397
3398 // RFC 6675, Section (C)
3399 // If cwnd - pipe >= 1 SMSS, the sender SHOULD transmit one or more
3400 // segments as follows:
3401 // (NOTE: We check > 0, and do the checks for segmentSize in the following
3402 // else branch to control silly window syndrome and Nagle)
3403 while (availableWindow > 0)
3404 {
3405 if (IsPacingEnabled())
3406 {
3407 NS_LOG_INFO("Pacing is enabled");
3409 {
3410 NS_LOG_INFO("Skipping Packet due to pacing" << m_pacingTimer.GetDelayLeft());
3411 break;
3412 }
3413 NS_LOG_INFO("Timer is not running");
3414 }
3415
3417 {
3418 NS_LOG_INFO("FIN_WAIT and OPEN state; no data to transmit");
3419 break;
3420 }
3421 // (C.1) The scoreboard MUST be queried via NextSeg () for the
3422 // sequence number range of the next segment to transmit (if
3423 // any), and the given segment sent. If NextSeg () returns
3424 // failure (no data to send), return without sending anything
3425 // (i.e., terminate steps C.1 -- C.5).
3426 SequenceNumber32 next;
3427 SequenceNumber32 nextHigh;
3428 bool enableRule3 = m_sackEnabled && m_tcb->m_congState == TcpSocketState::CA_RECOVERY;
3429 if (!m_txBuffer->NextSeg(&next, &nextHigh, enableRule3))
3430 {
3431 NS_LOG_INFO("no valid seq to transmit, or no data available");
3432 break;
3433 }
3434 else
3435 {
3436 // It's time to transmit, but before do silly window and Nagle's check
3437 uint32_t availableData = m_txBuffer->SizeFromSequence(next);
3438
3439 // If there's less app data than the full window, ask the app for more
3440 // data before trying to send
3441 if (availableData < availableWindow)
3442 {
3444 }
3445
3446 // Stop sending if we need to wait for a larger Tx window (prevent silly window
3447 // syndrome) but continue if we don't have data
3448 if (availableWindow < m_tcb->m_segmentSize && availableData > availableWindow)
3449 {
3450 NS_LOG_LOGIC("Preventing Silly Window Syndrome. Wait to send.");
3451 break; // No more
3452 }
3453 // Nagle's algorithm (RFC896): Hold off sending if there is unacked data
3454 // in the buffer and the amount of data to send is less than one segment
3455 if (!m_noDelay && UnAckDataCount() > 0 && availableData < m_tcb->m_segmentSize)
3456 {
3457 NS_LOG_DEBUG("Invoking Nagle's algorithm for seq "
3458 << next << ", SFS: " << m_txBuffer->SizeFromSequence(next)
3459 << ". Wait to send.");
3460 break;
3461 }
3462
3463 uint32_t s = std::min(availableWindow, m_tcb->m_segmentSize);
3464 // NextSeg () may have further constrained the segment size
3465 auto maxSizeToSend = static_cast<uint32_t>(nextHigh - next);
3466 s = std::min(s, maxSizeToSend);
3467
3468 // (C.2) If any of the data octets sent in (C.1) are below HighData,
3469 // HighRxt MUST be set to the highest sequence number of the
3470 // retransmitted segment unless NextSeg () rule (4) was
3471 // invoked for this retransmission.
3472 // (C.3) If any of the data octets sent in (C.1) are above HighData,
3473 // HighData must be updated to reflect the transmission of
3474 // previously unsent data.
3475 //
3476 // These steps are done in m_txBuffer with the tags.
3477 if (m_tcb->m_nextTxSequence != next)
3478 {
3479 m_tcb->m_nextTxSequence = next;
3480 }
3481 if (m_tcb->m_bytesInFlight.Get() == 0)
3482 {
3484 }
3485 uint32_t sz = SendDataPacket(m_tcb->m_nextTxSequence, s, withAck);
3486
3487 NS_LOG_LOGIC(" rxwin " << m_rWnd << " segsize " << m_tcb->m_segmentSize
3488 << " highestRxAck " << m_txBuffer->HeadSequence() << " pd->Size "
3489 << m_txBuffer->Size() << " pd->SFS "
3490 << m_txBuffer->SizeFromSequence(m_tcb->m_nextTxSequence));
3491
3492 NS_LOG_DEBUG("cWnd: " << m_tcb->m_cWnd << " total unAck: " << UnAckDataCount()
3493 << " sent seq " << m_tcb->m_nextTxSequence << " size " << sz);
3494 m_tcb->m_nextTxSequence += sz;
3495 ++nPacketsSent;
3496 if (IsPacingEnabled())
3497 {
3498 NS_LOG_INFO("Pacing is enabled");
3500 {
3501 NS_LOG_DEBUG("Current Pacing Rate " << m_tcb->m_pacingRate);
3502 NS_LOG_DEBUG("Timer is in expired state, activate it "
3503 << m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3504 m_pacingTimer.Schedule(m_tcb->m_pacingRate.Get().CalculateBytesTxTime(sz));
3505 break;
3506 }
3507 }
3508 }
3509
3510 // (C.4) The estimate of the amount of data outstanding in the
3511 // network must be updated by incrementing pipe by the number
3512 // of octets transmitted in (C.1).
3513 //
3514 // Done in BytesInFlight, inside AvailableWindow.
3515 availableWindow = AvailableWindow();
3516
3517 // (C.5) If cwnd - pipe >= 1 SMSS, return to (C.1)
3518 // loop again!
3519 }
3520
3521 if (nPacketsSent > 0)
3522 {
3523 if (!m_sackEnabled)
3524 {
3525 if (!m_limitedTx)
3526 {
3527 // We can't transmit in CA_DISORDER without limitedTx active
3529 }
3530 }
3531
3532 NS_LOG_DEBUG("SendPendingData sent " << nPacketsSent << " segments");
3533 }
3534 else
3535 {
3536 NS_LOG_DEBUG("SendPendingData no segments sent");
3537 }
3538 return nPacketsSent;
3539}
3540
3543{
3544 return m_tcb->m_highTxMark - m_txBuffer->HeadSequence();
3545}
3546
3549{
3550 uint32_t bytesInFlight = m_txBuffer->BytesInFlight();
3551 // Ugly, but we are not modifying the state; m_bytesInFlight is used
3552 // only for tracing purpose.
3553 m_tcb->m_bytesInFlight = bytesInFlight;
3554
3555 NS_LOG_DEBUG("Returning calculated bytesInFlight: " << bytesInFlight);
3556 return bytesInFlight;
3557}
3558
3561{
3562 return std::min(m_rWnd.Get(), m_tcb->m_cWnd.Get());
3563}
3564
3567{
3568 uint32_t win = Window(); // Number of bytes allowed to be outstanding
3569 uint32_t inflight = BytesInFlight(); // Number of outstanding bytes
3570 return (inflight > win) ? 0 : win - inflight;
3571}
3572
3573uint16_t
3575{
3576 NS_LOG_FUNCTION(this << scale);
3577 uint32_t w;
3578
3579 // We don't want to advertise 0 after a FIN is received. So, we just use
3580 // the previous value of the advWnd.
3581 if (m_tcb->m_rxBuffer->GotFin())
3582 {
3583 w = m_advWnd;
3584 }
3585 else
3586 {
3587 NS_ASSERT_MSG(m_tcb->m_rxBuffer->MaxRxSequence() - m_tcb->m_rxBuffer->NextRxSequence() >= 0,
3588 "Unexpected sequence number values");
3589 w = static_cast<uint32_t>(m_tcb->m_rxBuffer->MaxRxSequence() -
3590 m_tcb->m_rxBuffer->NextRxSequence());
3591 }
3592
3593 // Ugly, but we are not modifying the state, that variable
3594 // is used only for tracing purpose.
3595 if (w != m_advWnd)
3596 {
3597 const_cast<TcpSocketBase*>(this)->m_advWnd = w;
3598 }
3599 if (scale)
3600 {
3601 w >>= m_rcvWindShift;
3602 }
3603 if (w > m_maxWinSize)
3604 {
3605 w = m_maxWinSize;
3606 NS_LOG_WARN("Adv window size truncated to "
3607 << m_maxWinSize << "; possibly to avoid overflow of the 16-bit integer");
3608 }
3609 NS_LOG_LOGIC("Returning AdvertisedWindowSize of " << static_cast<uint16_t>(w));
3610 return static_cast<uint16_t>(w);
3611}
3612
3613// Receipt of new packet, put into Rx buffer
3614void
3616{
3617 NS_LOG_FUNCTION(this << tcpHeader);
3618 NS_LOG_DEBUG("Data segment, seq=" << tcpHeader.GetSequenceNumber()
3619 << " pkt size=" << p->GetSize());
3620
3621 // Put into Rx buffer
3622 SequenceNumber32 expectedSeq = m_tcb->m_rxBuffer->NextRxSequence();
3623 if (!m_tcb->m_rxBuffer->Add(p, tcpHeader))
3624 { // Insert failed: No data or RX buffer full
3625 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3627 {
3629 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
3631 }
3632 else
3633 {
3635 }
3636 return;
3637 }
3638 // Notify app to receive if necessary
3639 if (expectedSeq < m_tcb->m_rxBuffer->NextRxSequence())
3640 { // NextRxSeq advanced, we have something to send to the app
3641 if (!m_shutdownRecv)
3642 {
3644 }
3645 // Handle exceptions
3646 if (m_closeNotified)
3647 {
3648 NS_LOG_WARN("Why TCP " << this << " got data after close notification?");
3649 }
3650 // If we received FIN before and now completed all "holes" in rx buffer,
3651 // invoke peer close procedure
3652 if (m_tcb->m_rxBuffer->Finished() && (tcpHeader.GetFlags() & TcpHeader::FIN) == 0)
3653 {
3654 DoPeerClose();
3655 return;
3656 }
3657 }
3658 // Now send a new ACK packet acknowledging all received and delivered data
3659 if (m_tcb->m_rxBuffer->Size() > m_tcb->m_rxBuffer->Available() ||
3660 m_tcb->m_rxBuffer->NextRxSequence() > expectedSeq + p->GetSize())
3661 { // A gap exists in the buffer, or we filled a gap: Always ACK
3663 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3665 {
3667 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
3669 }
3670 else
3671 {
3673 }
3674 }
3675 else
3676 { // In-sequence packet: ACK if delayed ack count allows
3678 {
3680 m_delAckCount = 0;
3682 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
3684 {
3685 NS_LOG_DEBUG("Congestion algo " << m_congestionControl->GetName());
3688 << " -> ECN_SENDING_ECE");
3690 }
3691 else
3692 {
3694 }
3695 }
3696 else if (!m_delAckEvent.IsExpired())
3697 {
3699 }
3700 else if (m_delAckEvent.IsExpired())
3701 {
3706 this << " scheduled delayed ACK at "
3708 }
3709 }
3710}
3711
3712Time
3713TcpSocketBase::CalculateRttSample(const TcpHeader& tcpHeader, const RttHistory& rttHistory)
3714{
3715 NS_LOG_FUNCTION(this);
3716 SequenceNumber32 ackSeq = tcpHeader.GetAckNumber();
3717 Time rtt;
3718
3719 if (ackSeq >= (rttHistory.seq + SequenceNumber32(rttHistory.count)))
3720 {
3721 // As per RFC 6298 (Section 3)
3722 // RTT samples MUST NOT be made using segments that were
3723 // retransmitted (and thus for which it is ambiguous whether the reply
3724 // was for the first instance of the packet or a later instance). The
3725 // only case when TCP can safely take RTT samples from retransmitted
3726 // segments is when the TCP timestamp option is employed, since
3727 // the timestamp option removes the ambiguity regarding which instance
3728 // of the data segment triggered the acknowledgment.
3729 if (m_timestampEnabled && tcpHeader.HasOption(TcpOption::TS))
3730 {
3733 rtt = TcpOptionTS::ElapsedTimeFromTsValue(ts->GetEcho());
3734 if (rtt.IsZero())
3735 {
3736 NS_LOG_LOGIC("TcpSocketBase::EstimateRtt - RTT calculated from TcpOption::TS "
3737 "is zero, approximating to 1us.");
3738 NS_LOG_DEBUG("RTT calculated from TcpOption::TS is zero, updating rtt to 1us.");
3739 rtt = MicroSeconds(1);
3740 }
3741 }
3742 else if (!rttHistory.retx)
3743 {
3744 // Elapsed time since the packet was transmitted
3745 rtt = Simulator::Now() - rttHistory.time;
3746 }
3747 }
3748 return rtt;
3749}
3750
3751void
3753{
3754 NS_LOG_FUNCTION(this);
3755 SequenceNumber32 ackSeq = tcpHeader.GetAckNumber();
3756 Time rtt;
3757
3758 // An ack has been received, calculate rtt and log this measurement
3759 // Note we use a linear search (O(n)) for this since for the common
3760 // case the ack'ed packet will be at the head of the list
3761 if (!m_history.empty())
3762 {
3763 RttHistory& earliestTransmittedPktHistory = m_history.front();
3764 rtt = CalculateRttSample(tcpHeader, earliestTransmittedPktHistory);
3765
3766 // Store ACKed packet that has the latest transmission time to update `lastRtt`
3767 RttHistory latestTransmittedPktHistory = earliestTransmittedPktHistory;
3768
3769 // Delete all ACK history with seq <= ack
3770 while (!m_history.empty())
3771 {
3772 RttHistory& rttHistory = m_history.front();
3773 if ((rttHistory.seq + SequenceNumber32(rttHistory.count)) > ackSeq)
3774 {
3775 break; // Done removing
3776 }
3777
3778 latestTransmittedPktHistory = rttHistory;
3779 m_history.pop_front(); // Remove
3780 }
3781
3782 // In case of multiple packets being ACKed in a single acknowledgement, `m_lastRtt` is
3783 // RTT of the last (S)ACKed packet calculated using the data packet with the latest
3784 // transmission time
3785 Time lastRtt = CalculateRttSample(tcpHeader, latestTransmittedPktHistory);
3786 if (!lastRtt.IsZero())
3787 {
3788 NS_LOG_DEBUG("Last RTT sample updated to: " << lastRtt);
3789 m_tcb->m_lastRtt = lastRtt;
3790 }
3791 }
3792
3793 if (!rtt.IsZero())
3794 {
3795 m_rtt->Measurement(rtt); // Log the measurement
3796 // RFC 6298, clause 2.4
3797 m_rto = Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4),
3798 m_minRto);
3799 m_tcb->m_srtt = m_rtt->GetEstimate();
3800 m_tcb->m_minRtt = std::min(m_tcb->m_srtt.Get(), m_tcb->m_minRtt);
3801 NS_LOG_INFO(this << m_tcb->m_srtt << m_tcb->m_minRtt);
3802 }
3803}
3804
3805// Called by the ReceivedAck() when new ACK received and by ProcessSynRcvd()
3806// when the three-way handshake completed. This cancels retransmission timer
3807// and advances Tx window
3808void
3809TcpSocketBase::NewAck(const SequenceNumber32& ack, bool resetRTO)
3810{
3811 NS_LOG_FUNCTION(this << ack);
3812
3813 // Reset the data retransmission count. We got a new ACK!
3815
3816 if (m_state != SYN_RCVD && resetRTO)
3817 { // Set RTO unless the ACK is received in SYN_RCVD state
3819 this << " Cancelled ReTxTimeout event which was set to expire at "
3820 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
3822 // On receiving a "New" ack we restart retransmission timer .. RFC 6298
3823 // RFC 6298, clause 2.4
3824 m_rto = Max(m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4),
3825 m_minRto);
3826
3827 NS_LOG_LOGIC(this << " Schedule ReTxTimeout at time " << Simulator::Now().GetSeconds()
3828 << " to expire at time "
3829 << (Simulator::Now() + m_rto.Get()).GetSeconds());
3831 }
3832
3833 // Note the highest ACK and tell app to send more
3834 NS_LOG_LOGIC("TCP " << this << " NewAck " << ack << " numberAck "
3835 << (ack - m_txBuffer->HeadSequence())); // Number bytes ack'ed
3836
3837 if (GetTxAvailable() > 0)
3838 {
3840 }
3841 if (ack > m_tcb->m_nextTxSequence)
3842 {
3843 m_tcb->m_nextTxSequence = ack; // If advanced
3844 }
3845 if (m_txBuffer->Size() == 0 && m_state != FIN_WAIT_1 && m_state != CLOSING)
3846 { // No retransmit timer if no data to retransmit
3848 this << " Cancelled ReTxTimeout event which was set to expire at "
3849 << (Simulator::Now() + Simulator::GetDelayLeft(m_retxEvent)).GetSeconds());
3851 }
3852}
3853
3854// Retransmit timeout
3855void
3857{
3858 NS_LOG_FUNCTION(this);
3859 NS_LOG_LOGIC(this << " ReTxTimeout Expired at time " << Simulator::Now().GetSeconds());
3860 // If erroneous timeout in closed/timed-wait state, just return
3861 if (m_state == CLOSED || m_state == TIME_WAIT)
3862 {
3863 return;
3864 }
3865
3866 if (m_state == SYN_SENT)
3867 {
3868 NS_ASSERT(m_synCount > 0);
3869 if (m_tcb->m_useEcn == TcpSocketState::On)
3870 {
3872 }
3873 else
3874 {
3876 }
3877 return;
3878 }
3879
3880 // Retransmit non-data packet: Only if in FIN_WAIT_1 or CLOSING state
3881 if (m_txBuffer->Size() == 0)
3882 {
3883 if (m_state == FIN_WAIT_1 || m_state == CLOSING)
3884 { // Must have lost FIN, re-send
3886 }
3887 return;
3888 }
3889
3890 NS_LOG_DEBUG("Checking if Connection is Established");
3891 // If all data are received (non-closing socket and nothing to send), just return
3892 if (m_state <= ESTABLISHED && m_txBuffer->HeadSequence() >= m_tcb->m_highTxMark &&
3893 m_txBuffer->Size() == 0)
3894 {
3895 NS_LOG_DEBUG("Already Sent full data" << m_txBuffer->HeadSequence() << " "
3896 << m_tcb->m_highTxMark);
3897 return;
3898 }
3899
3900 if (m_dataRetrCount == 0)
3901 {
3902 NS_LOG_INFO("No more data retries available. Dropping connection");
3905 return;
3906 }
3907 else
3908 {
3910 }
3911
3912 uint32_t inFlightBeforeRto = BytesInFlight();
3913 bool resetSack = !m_sackEnabled; // Reset SACK information if SACK is not enabled.
3914 // The information in the TcpTxBuffer is guessed, in this case.
3915
3916 // Reset dupAckCount
3917 m_dupAckCount = 0;
3918 if (!m_sackEnabled)
3919 {
3920 m_txBuffer->ResetRenoSack();
3921 }
3922
3923 // From RFC 6675, Section 5.1
3924 // [RFC2018] suggests that a TCP sender SHOULD expunge the SACK
3925 // information gathered from a receiver upon a retransmission timeout
3926 // (RTO) "since the timeout might indicate that the data receiver has
3927 // reneged." Additionally, a TCP sender MUST "ignore prior SACK
3928 // information in determining which data to retransmit."
3929 // It has been suggested that, as long as robust tests for
3930 // reneging are present, an implementation can retain and use SACK
3931 // information across a timeout event [Errata1610].
3932 // The head of the sent list will not be marked as sacked, therefore
3933 // will be retransmitted, if the receiver renegotiate the SACK blocks
3934 // that we received.
3935 m_txBuffer->SetSentListLost(resetSack);
3936
3937 // From RFC 6675, Section 5.1
3938 // If an RTO occurs during loss recovery as specified in this document,
3939 // RecoveryPoint MUST be set to HighData. Further, the new value of
3940 // RecoveryPoint MUST be preserved and the loss recovery algorithm
3941 // outlined in this document MUST be terminated.
3942 m_recover = m_tcb->m_highTxMark;
3943 m_recoverActive = true;
3944
3945 // RFC 6298, clause 2.5, double the timer
3946 Time doubledRto = m_rto + m_rto;
3947 m_rto = Min(doubledRto, Time::FromDouble(60, Time::S));
3948
3949 // Empty RTT history
3950 m_history.clear();
3951
3952 // Please don't reset highTxMark, it is used for retransmission detection
3953
3954 // When a TCP sender detects segment loss using the retransmission timer
3955 // and the given segment has not yet been resent by way of the
3956 // retransmission timer, decrease ssThresh
3957 if (m_tcb->m_congState != TcpSocketState::CA_LOSS || !m_txBuffer->IsHeadRetransmitted())
3958 {
3959 m_tcb->m_ssThresh = m_congestionControl->GetSsThresh(m_tcb, inFlightBeforeRto);
3960 }
3961
3962 // Cwnd set to 1 MSS
3965 m_tcb->m_congState = TcpSocketState::CA_LOSS;
3966 m_tcb->m_cWnd = m_tcb->m_segmentSize;
3967 m_tcb->m_cWndInfl = m_tcb->m_cWnd;
3968
3970
3971 NS_LOG_DEBUG("RTO. Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to " << m_tcb->m_ssThresh
3972 << ", restart from seqnum " << m_txBuffer->HeadSequence()
3973 << " doubled rto to " << m_rto.Get().GetSeconds() << " s");
3974
3976 "There are some bytes in flight after an RTO: " << BytesInFlight());
3977
3979
3980 NS_ASSERT_MSG(BytesInFlight() <= m_tcb->m_segmentSize,
3981 "In flight (" << BytesInFlight() << ") there is more than one segment ("
3982 << m_tcb->m_segmentSize << ")");
3983}
3984
3985void
4001
4002void
4004{
4005 NS_LOG_FUNCTION(this);
4006
4008 if (m_state == LAST_ACK)
4009 {
4010 if (m_dataRetrCount == 0)
4011 {
4012 NS_LOG_INFO("LAST-ACK: No more data retries available. Dropping connection");
4015 return;
4016 }
4019 NS_LOG_LOGIC("TcpSocketBase " << this << " rescheduling LATO1");
4020 Time lastRto = m_rtt->GetEstimate() + Max(m_clockGranularity, m_rtt->GetVariation() * 4);
4022 }
4023}
4024
4025// Send 1-byte data to probe for the window size at the receiver when
4026// the local knowledge tells that the receiver has zero window size
4027// C.f.: RFC793 p.42, RFC1112 sec.4.2.2.17
4028void
4030{
4031 NS_LOG_LOGIC("PersistTimeout expired at " << Simulator::Now().GetSeconds());
4033 std::min(Seconds(60), Time(2 * m_persistTimeout)); // max persist timeout = 60s
4034 Ptr<Packet> p = m_txBuffer->CopyFromSequence(1, m_tcb->m_nextTxSequence)->GetPacketCopy();
4035 m_txBuffer->ResetLastSegmentSent();
4036 TcpHeader tcpHeader;
4037 tcpHeader.SetSequenceNumber(m_tcb->m_nextTxSequence);
4038 tcpHeader.SetAckNumber(m_tcb->m_rxBuffer->NextRxSequence());
4040 if (m_endPoint != nullptr)
4041 {
4044 }
4045 else
4046 {
4049 }
4050 AddOptions(tcpHeader);
4051 // Send a packet tag for setting ECT bits in IP header
4052 if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED)
4053 {
4055 }
4056 m_txTrace(p, tcpHeader, this);
4057
4058 if (m_endPoint != nullptr)
4059 {
4060 m_tcp->SendPacket(p,
4061 tcpHeader,
4065 }
4066 else
4067 {
4068 m_tcp->SendPacket(p,
4069 tcpHeader,
4073 }
4074
4075 NS_LOG_LOGIC("Schedule persist timeout at time "
4076 << Simulator::Now().GetSeconds() << " to expire at time "
4077 << (Simulator::Now() + m_persistTimeout).GetSeconds());
4079}
4080
4081void
4083{
4084 NS_LOG_FUNCTION(this);
4085 bool res;
4086 SequenceNumber32 seq;
4087 SequenceNumber32 seqHigh;
4088 uint32_t maxSizeToSend;
4089
4090 // Find the first segment marked as lost and not retransmitted. With Reno,
4091 // that should be the head
4092 res = m_txBuffer->NextSeg(&seq, &seqHigh, false);
4093 if (!res)
4094 {
4095 // We have already retransmitted the head. However, we still received
4096 // three dupacks, or the RTO expired, but no data to transmit.
4097 // Therefore, re-send again the head.
4098 seq = m_txBuffer->HeadSequence();
4099 maxSizeToSend = m_tcb->m_segmentSize;
4100 }
4101 else
4102 {
4103 // NextSeg() may constrain the segment size when res is true
4104 maxSizeToSend = static_cast<uint32_t>(seqHigh - seq);
4105 }
4106 NS_ASSERT(m_sackEnabled || seq == m_txBuffer->HeadSequence());
4107
4108 NS_LOG_INFO("Retransmitting " << seq);
4109 // Update the trace and retransmit the segment
4110 m_tcb->m_nextTxSequence = seq;
4111 uint32_t sz = SendDataPacket(m_tcb->m_nextTxSequence, maxSizeToSend, true);
4112
4113 NS_ASSERT(sz > 0);
4114}
4115
4116void
4127
4128/* Move TCP to Time_Wait state and schedule a transition to Closed state */
4129void
4131{
4132 NS_LOG_DEBUG(TcpStateName[m_state] << " -> TIME_WAIT");
4135 if (!m_closeNotified)
4136 {
4137 // Technically the connection is not fully closed, but we notify now
4138 // because an implementation (real socket) would behave as if closed.
4139 // Notify normal close when entering TIME_WAIT or leaving LAST_ACK.
4141 m_closeNotified = true;
4142 }
4143 // Move from TIME_WAIT to CLOSED after 2*MSL. Max segment lifetime is 2 min
4144 // according to RFC793, p.28
4146}
4147
4148/* Below are the attribute get/set functions */
4149
4150void
4152{
4153 NS_LOG_FUNCTION(this << size);
4154 m_txBuffer->SetMaxBufferSize(size);
4155}
4156
4159{
4160 return m_txBuffer->MaxBufferSize();
4161}
4162
4163void
4165{
4166 NS_LOG_FUNCTION(this << size);
4167 uint32_t oldSize = GetRcvBufSize();
4168
4169 m_tcb->m_rxBuffer->SetMaxBufferSize(size);
4170
4171 /* The size has (manually) increased. Actively inform the other end to prevent
4172 * stale zero-window states.
4173 */
4174 if (oldSize < size && m_connected)
4175 {
4176 if (m_tcb->m_ecnState == TcpSocketState::ECN_CE_RCVD ||
4178 {
4180 NS_LOG_DEBUG(TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_SENDING_ECE");
4182 }
4183 else
4184 {
4186 }
4187 }
4188}
4189
4192{
4193 return m_tcb->m_rxBuffer->MaxBufferSize();
4194}
4195
4196void
4198{
4199 NS_LOG_FUNCTION(this << size);
4200 m_tcb->m_segmentSize = size;
4201 m_txBuffer->SetSegmentSize(size);
4202
4203 NS_ABORT_MSG_UNLESS(m_state == CLOSED, "Cannot change segment size dynamically.");
4204}
4205
4208{
4209 return m_tcb->m_segmentSize;
4210}
4211
4212void
4218
4219Time
4221{
4222 return m_cnTimeout;
4223}
4224
4225void
4227{
4228 NS_LOG_FUNCTION(this << count);
4229 m_synRetries = count;
4230}
4231
4234{
4235 return m_synRetries;
4236}
4237
4238void
4240{
4241 NS_LOG_FUNCTION(this << retries);
4242 m_dataRetries = retries;
4243}
4244
4247{
4248 NS_LOG_FUNCTION(this);
4249 return m_dataRetries;
4250}
4251
4252void
4258
4259Time
4261{
4262 return m_delAckTimeout;
4263}
4264
4265void
4267{
4268 NS_LOG_FUNCTION(this << count);
4269 m_delAckMaxCount = count;
4270}
4271
4277
4278void
4280{
4281 NS_LOG_FUNCTION(this << noDelay);
4282 m_noDelay = noDelay;
4283}
4284
4285bool
4287{
4288 return m_noDelay;
4289}
4290
4291void
4297
4298Time
4303
4304bool
4306{
4307 // Broadcast is not implemented. Return true only if allowBroadcast==false
4308 return (!allowBroadcast);
4309}
4310
4311bool
4313{
4314 return false;
4315}
4316
4317void
4319{
4320 NS_LOG_FUNCTION(this << header);
4321
4323 {
4324 AddOptionTimestamp(header);
4325 }
4326}
4327
4328void
4330{
4331 NS_LOG_FUNCTION(this << option);
4332
4334
4335 // In naming, we do the contrary of RFC 1323. The received scaling factor
4336 // is Rcv.Wind.Scale (and not Snd.Wind.Scale)
4337 m_sndWindShift = ws->GetScale();
4338
4339 if (m_sndWindShift > 14)
4340 {
4341 NS_LOG_WARN("Possible error; m_sndWindShift exceeds 14: " << m_sndWindShift);
4342 m_sndWindShift = 14;
4343 }
4344
4345 NS_LOG_INFO(m_node->GetId() << " Received a scale factor of "
4346 << static_cast<int>(m_sndWindShift));
4347}
4348
4349uint8_t
4351{
4352 NS_LOG_FUNCTION(this);
4353 uint32_t maxSpace = m_tcb->m_rxBuffer->MaxBufferSize();
4354 uint8_t scale = 0;
4355
4356 while (maxSpace > m_maxWinSize)
4357 {
4358 maxSpace = maxSpace >> 1;
4359 ++scale;
4360 }
4361
4362 if (scale > 14)
4363 {
4364 NS_LOG_WARN("Possible error; scale exceeds 14: " << scale);
4365 scale = 14;
4366 }
4367
4368 NS_LOG_INFO("Node " << m_node->GetId() << " calculated wscale factor of "
4369 << static_cast<int>(scale) << " for buffer size "
4370 << m_tcb->m_rxBuffer->MaxBufferSize());
4371 return scale;
4372}
4373
4374void
4376{
4377 NS_LOG_FUNCTION(this << header);
4378 NS_ASSERT(header.GetFlags() & TcpHeader::SYN);
4379
4381
4382 // In naming, we do the contrary of RFC 1323. The sended scaling factor
4383 // is Snd.Wind.Scale (and not Rcv.Wind.Scale)
4384
4386 option->SetScale(m_rcvWindShift);
4387
4388 header.AppendOption(option);
4389
4390 NS_LOG_INFO(m_node->GetId() << " Send a scaling factor of "
4391 << static_cast<int>(m_rcvWindShift));
4392}
4393
4396{
4397 NS_LOG_FUNCTION(this << option);
4398
4400 return m_txBuffer->Update(s->GetSackList(), MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
4401}
4402
4403void
4405{
4406 NS_LOG_FUNCTION(this << option);
4407
4409
4410 NS_ASSERT(m_sackEnabled == true);
4411 NS_LOG_INFO(m_node->GetId() << " Received a SACK_PERMITTED option " << s);
4412}
4413
4414void
4416{
4417 NS_LOG_FUNCTION(this << header);
4418 NS_ASSERT(header.GetFlags() & TcpHeader::SYN);
4419
4421 header.AppendOption(option);
4422 NS_LOG_INFO(m_node->GetId() << " Add option SACK-PERMITTED");
4423}
4424
4425void
4427{
4428 NS_LOG_FUNCTION(this << header);
4429
4430 // Calculate the number of SACK blocks allowed in this packet
4431 uint8_t optionLenAvail = header.GetMaxOptionLength() - header.GetOptionLength();
4432 uint8_t allowedSackBlocks = (optionLenAvail - 2) / 8;
4433
4434 TcpOptionSack::SackList sackList = m_tcb->m_rxBuffer->GetSackList();
4435 if (allowedSackBlocks == 0 || sackList.empty())
4436 {
4437 NS_LOG_LOGIC("No space available or sack list empty, not adding sack blocks");
4438 return;
4439 }
4440
4441 // Append the allowed number of SACK blocks
4443
4444 for (auto i = sackList.begin(); allowedSackBlocks > 0 && i != sackList.end(); ++i)
4445 {
4446 option->AddSackBlock(*i);
4447 allowedSackBlocks--;
4448 }
4449
4450 header.AppendOption(option);
4451 NS_LOG_INFO(m_node->GetId() << " Add option SACK " << *option);
4452}
4453
4454void
4456 const SequenceNumber32& seq)
4457{
4458 NS_LOG_FUNCTION(this << option);
4459
4461
4462 // This is valid only when no overflow occurs. It happens
4463 // when a connection last longer than 50 days.
4464 if (m_tcb->m_rcvTimestampValue > ts->GetTimestamp())
4465 {
4466 // Do not save a smaller timestamp (probably there is reordering)
4467 return;
4468 }
4469
4470 m_tcb->m_rcvTimestampValue = ts->GetTimestamp();
4471 m_tcb->m_rcvTimestampEchoReply = ts->GetEcho();
4472
4473 if (seq == m_tcb->m_rxBuffer->NextRxSequence() && seq <= m_highTxAck)
4474 {
4475 m_timestampToEcho = ts->GetTimestamp();
4476 }
4477
4478 NS_LOG_INFO(m_node->GetId() << " Got timestamp=" << m_timestampToEcho
4479 << " and Echo=" << ts->GetEcho());
4480}
4481
4482void
4484{
4485 NS_LOG_FUNCTION(this << header);
4486
4488
4489 option->SetTimestamp(TcpOptionTS::NowToTsValue());
4490 option->SetEcho(m_timestampToEcho);
4491
4492 header.AppendOption(option);
4493 NS_LOG_INFO(m_node->GetId() << " Add option TS, ts=" << option->GetTimestamp()
4494 << " echo=" << m_timestampToEcho);
4495}
4496
4497void
4499{
4500 NS_LOG_FUNCTION(this << header);
4501 // If the connection is not established, the window size is always
4502 // updated
4503 uint32_t receivedWindow = header.GetWindowSize();
4504 receivedWindow <<= m_sndWindShift;
4505 NS_LOG_INFO("Received (scaled) window is " << receivedWindow << " bytes");
4506 if (m_state < ESTABLISHED)
4507 {
4508 m_rWnd = receivedWindow;
4509 NS_LOG_LOGIC("State less than ESTABLISHED; updating rWnd to " << m_rWnd);
4510 return;
4511 }
4512
4513 // Test for conditions that allow updating of the window
4514 // 1) segment contains new data (advancing the right edge of the receive
4515 // buffer),
4516 // 2) segment does not contain new data but the segment acks new data
4517 // (highest sequence number acked advances), or
4518 // 3) the advertised window is larger than the current send window
4519 bool update = false;
4520 if (header.GetAckNumber() == m_highRxAckMark && receivedWindow > m_rWnd)
4521 {
4522 // right edge of the send window is increased (window update)
4523 update = true;
4524 }
4525 if (header.GetAckNumber() > m_highRxAckMark)
4526 {
4527 m_highRxAckMark = header.GetAckNumber();
4528 update = true;
4529 }
4530 if (header.GetSequenceNumber() > m_highRxMark)
4531 {
4533 update = true;
4534 }
4535 if (update)
4536 {
4537 m_rWnd = receivedWindow;
4538 NS_LOG_LOGIC("updating rWnd to " << m_rWnd);
4539 }
4540}
4541
4542void
4544{
4545 NS_LOG_FUNCTION(this << minRto);
4546 m_minRto = minRto;
4547}
4548
4549Time
4551{
4552 return m_minRto;
4553}
4554
4555void
4557{
4558 NS_LOG_FUNCTION(this << clockGranularity);
4559 m_clockGranularity = clockGranularity;
4560}
4561
4562Time
4567
4570{
4571 return m_txBuffer;
4572}
4573
4576{
4577 return m_tcb->m_rxBuffer;
4578}
4579
4580void
4582{
4583 m_retxThresh = retxThresh;
4584 m_txBuffer->SetDupAckThresh(retxThresh);
4585}
4586
4587void
4589{
4590 m_pacingRateTrace(oldValue, newValue);
4591}
4592
4593void
4595{
4596 m_cWndTrace(oldValue, newValue);
4597}
4598
4599void
4601{
4602 m_cWndInflTrace(oldValue, newValue);
4603}
4604
4605void
4607{
4608 m_ssThTrace(oldValue, newValue);
4609}
4610
4611void
4617
4618void
4620 TcpSocketState::EcnState_t newValue) const
4621{
4622 m_ecnStateTrace(oldValue, newValue);
4623}
4624
4625void
4627
4628{
4629 m_nextTxSequenceTrace(oldValue, newValue);
4630}
4631
4632void
4634{
4635 m_highTxMarkTrace(oldValue, newValue);
4636}
4637
4638void
4640{
4641 m_bytesInFlightTrace(oldValue, newValue);
4642}
4643
4644void
4645TcpSocketBase::UpdateRtt(Time oldValue, Time newValue) const
4646{
4647 m_srttTrace(oldValue, newValue);
4648}
4649
4650void
4651TcpSocketBase::UpdateLastRtt(Time oldValue, Time newValue) const
4652{
4653 m_lastRttTrace(oldValue, newValue);
4654}
4655
4656void
4664
4665void
4667{
4668 NS_LOG_FUNCTION(this << recovery);
4669 m_recoveryOps = recovery;
4670}
4671
4674{
4675 return CopyObject<TcpSocketBase>(this);
4676}
4677
4680{
4681 if (a > b)
4682 {
4683 return a - b;
4684 }
4685
4686 return 0;
4687}
4688
4689void
4691{
4692 NS_LOG_FUNCTION(this);
4693 NS_LOG_INFO("Performing Pacing");
4695}
4696
4697bool
4699{
4700 if (!m_tcb->m_pacing)
4701 {
4702 return false;
4703 }
4704 else
4705 {
4706 if (m_tcb->m_paceInitialWindow)
4707 {
4708 return true;
4709 }
4710 SequenceNumber32 highTxMark = m_tcb->m_highTxMark; // cast traced value
4711 if (highTxMark.GetValue() > (GetInitialCwnd() * m_tcb->m_segmentSize))
4712 {
4713 return true;
4714 }
4715 }
4716 return false;
4717}
4718
4719void
4721{
4722 NS_LOG_FUNCTION(this << m_tcb);
4723
4724 // According to Linux, set base pacing rate to (cwnd * mss) / srtt
4725 //
4726 // In (early) slow start, multiply base by the slow start factor.
4727 // In late slow start and congestion avoidance, multiply base by
4728 // the congestion avoidance factor.
4729 // Comment from Linux code regarding early/late slow start:
4730 // Normal Slow Start condition is (tp->snd_cwnd < tp->snd_ssthresh)
4731 // If snd_cwnd >= (tp->snd_ssthresh / 2), we are approaching
4732 // end of slow start and should slow down.
4733
4734 // Similar to Linux, do not update pacing rate here if the
4735 // congestion control implements TcpCongestionOps::CongControl ()
4736 if (m_congestionControl->HasCongControl() || !m_tcb->m_pacing)
4737 {
4738 return;
4739 }
4740
4741 double factor;
4742 if (m_tcb->m_cWnd < m_tcb->m_ssThresh / 2)
4743 {
4744 NS_LOG_DEBUG("Pacing according to slow start factor; " << m_tcb->m_cWnd << " "
4745 << m_tcb->m_ssThresh);
4746 factor = static_cast<double>(m_tcb->m_pacingSsRatio) / 100;
4747 }
4748 else
4749 {
4750 NS_LOG_DEBUG("Pacing according to congestion avoidance factor; " << m_tcb->m_cWnd << " "
4751 << m_tcb->m_ssThresh);
4752 factor = static_cast<double>(m_tcb->m_pacingCaRatio) / 100;
4753 }
4754 Time srtt = m_tcb->m_srtt.Get(); // Get underlying Time value
4755 NS_LOG_DEBUG("Smoothed RTT is " << srtt.GetSeconds());
4756
4757 // Multiply by 8 to convert from bytes per second to bits per second
4758 DataRate pacingRate((std::max(m_tcb->m_cWnd, m_tcb->m_bytesInFlight) * 8 * factor) /
4759 srtt.GetSeconds());
4760 if (pacingRate < m_tcb->m_maxPacingRate)
4761 {
4762 NS_LOG_DEBUG("Pacing rate updated to: " << pacingRate);
4763 m_tcb->m_pacingRate = pacingRate;
4764 }
4765 else
4766 {
4767 NS_LOG_DEBUG("Pacing capped by max pacing rate: " << m_tcb->m_maxPacingRate);
4768 m_tcb->m_pacingRate = m_tcb->m_maxPacingRate;
4769 }
4770}
4771
4772void
4774{
4775 NS_LOG_FUNCTION(this << pacing);
4776 m_tcb->m_pacing = pacing;
4777}
4778
4779void
4781{
4782 NS_LOG_FUNCTION(this << paceWindow);
4783 m_tcb->m_paceInitialWindow = paceWindow;
4784}
4785
4786bool
4788{
4789 NS_LOG_FUNCTION(this << packetType);
4790 NS_ASSERT_MSG(packetType != TcpPacketType_t::INVALID, "Invalid TCP packet type");
4791 if (m_tcb->m_ecnState == TcpSocketState::ECN_DISABLED)
4792 {
4793 return false;
4794 }
4795
4796 NS_ABORT_MSG_IF(!ECN_RESTRICTION_MAP.contains(std::make_pair(packetType, m_tcb->m_ecnMode)),
4797 "Invalid packetType and ecnMode");
4798
4799 return ECN_RESTRICTION_MAP.at(std::make_pair(packetType, m_tcb->m_ecnMode));
4800}
4801
4802void
4804{
4805 NS_LOG_FUNCTION(this << useEcn);
4806 m_tcb->m_useEcn = useEcn;
4807}
4808
4811{
4812 return m_rWnd.Get();
4813}
4814
4817{
4818 return m_highRxAckMark.Get();
4819}
4820
4821// RttHistory methods
4823 : seq(s),
4824 count(c),
4825 time(t),
4826 retx(false)
4827{
4828}
4829
4831 : seq(h.seq),
4832 count(h.count),
4833 time(h.time),
4834 retx(h.retx)
4835{
4836}
4837
4838} // namespace ns3
#define Max(a, b)
#define Min(a, b)
a polymophic address class
Definition address.h:90
AttributeValue implementation for Boolean.
Definition boolean.h:26
Callback template class.
Definition callback.h:422
AttributeValue implementation for Callback.
Definition callback.h:786
Class for representing data rates.
Definition data-rate.h:78
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
Hold variables of type enum.
Definition enum.h:52
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsPending() const
This method is syntactic sugar for !IsExpired().
Definition event-id.cc:65
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition event-id.cc:58
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.
static Ipv4Address GetZero()
static Ipv4Address GetAny()
void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
void SetDestroyCallback(Callback< void > callback)
Set the default destroy callback.
Ipv4Address GetLocalAddress() const
Get the local address.
void SetLocalAddress(Ipv4Address address)
Set the local address.
uint16_t GetPeerPort() const
Get the peer port.
uint16_t GetLocalPort() const
Get the local port.
Ipv4Address GetPeerAddress() const
Get the peer address.
void SetIcmpCallback(Callback< void, Ipv4Address, uint8_t, uint8_t, uint8_t, uint32_t > callback)
Set the ICMP callback.
void SetPeer(Ipv4Address address, uint16_t port)
Set the peer information (address and port).
void SetRxCallback(Callback< void, Ptr< Packet >, Ipv4Header, uint16_t, Ptr< Ipv4Interface > > callback)
Set the reception callback.
Packet header for IPv4.
Definition ipv4-header.h:23
void SetDestination(Ipv4Address destination)
Ipv4Address GetSource() const
EcnType GetEcn() const
Ipv4Address GetDestination() const
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition ipv4.h:69
Describes an IPv6 address.
static Ipv6Address GetAny()
Get the "any" (::) Ipv6Address.
bool IsIpv4MappedAddress() const
If the address is an IPv4-mapped address.
Ipv4Address GetIpv4MappedAddress() const
Return the Ipv4 address.
uint16_t GetLocalPort() const
Get the local port.
void SetPeer(Ipv6Address addr, uint16_t port)
Set the peer information (address and port).
Ipv6Address GetPeerAddress() const
Get the peer address.
void SetIcmpCallback(Callback< void, Ipv6Address, uint8_t, uint8_t, uint8_t, uint32_t > callback)
Set the ICMP callback.
Ipv6Address GetLocalAddress() const
Get the local address.
void SetLocalAddress(Ipv6Address addr)
Set the local address.
void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
void SetRxCallback(Callback< void, Ptr< Packet >, Ipv6Header, uint16_t, Ptr< Ipv6Interface > > callback)
Set the reception callback.
uint16_t GetPeerPort() const
Get the peer port.
void SetDestroyCallback(Callback< void > callback)
Set the default destroy callback.
Packet header for IPv6.
Definition ipv6-header.h:24
void SetDestination(Ipv6Address dst)
Set the "Destination address" field.
Ipv6Address GetDestination() const
Get the "Destination address" field.
EcnType GetEcn() const
Ipv6Address GetSource() const
Get the "Source address" field.
IPv6 layer implementation.
uint32_t GetId() const
Definition node.cc:106
friend Ptr< T > CopyObject(Ptr< T > object)
Copy an Object.
Definition object.h:581
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:511
AttributeValue implementation for Pointer.
Smart pointer class similar to boost::intrusive_ptr.
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:561
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:595
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:206
Ptr< NetDevice > GetBoundNetDevice()
Returns socket's bound NetDevice, if any.
Definition socket.cc:336
Ptr< Packet > Recv()
Read a single packet from the socket.
Definition socket.cc:163
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:76
bool IsManualIpTtl() const
Checks if the socket has a specific IPv4 TTL set.
Definition socket.cc:363
void NotifySend(uint32_t spaceAvailable)
Notify through the callback (if set) that some data have been sent.
Definition socket.cc:281
void NotifyNewConnectionCreated(Ptr< Socket > socket, const Address &from)
Notify through the callback (if set) that a new connection has been created.
Definition socket.cc:261
virtual uint8_t GetIpTtl() const
Query the value of IP Time to Live field of this socket.
Definition socket.cc:506
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:243
uint8_t GetIpTos() const
Query the value of IP Type of Service of this socket.
Definition socket.cc:439
SocketType
Enumeration of the possible socket types.
Definition socket.h:96
@ NS3_SOCK_STREAM
Definition socket.h:97
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:103
void SetSendCallback(Callback< void, Ptr< Socket >, uint32_t > sendCb)
Notify application when space in transmit buffer is added.
Definition socket.cc:110
void NotifyErrorClose()
Notify through the callback (if set) that the connection has been closed due to an error.
Definition socket.cc:233
void NotifyDataRecv()
Notify through the callback (if set) that some data have been received.
Definition socket.cc:291
Ptr< NetDevice > m_boundnetdevice
the device this socket is bound to (might be null).
Definition socket.h:1070
virtual void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
Definition socket.cc:316
void NotifyNormalClose()
Notify through the callback (if set) that the connection has been closed.
Definition socket.cc:223
virtual uint8_t GetIpv6HopLimit() const
Query the value of IP Hop Limit field of this socket.
Definition socket.cc:531
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition socket.cc:117
SocketErrno
Enumeration of the possible errors returned by a socket.
Definition socket.h:73
@ ERROR_SHUTDOWN
Definition socket.h:79
@ ERROR_INVAL
Definition socket.h:82
@ ERROR_ADDRINUSE
Definition socket.h:87
@ ERROR_ADDRNOTAVAIL
Definition socket.h:86
@ ERROR_NOTCONN
Definition socket.h:76
@ ERROR_MSGSIZE
Definition socket.h:77
void NotifyDataSent(uint32_t size)
Notify through the callback (if set) that some data have been sent.
Definition socket.cc:271
void NotifyConnectionSucceeded()
Notify through the callback (if set) that the connection has been established.
Definition socket.cc:203
uint8_t GetPriority() const
Query the priority value of this socket.
Definition socket.cc:382
uint8_t GetIpv6Tclass() const
Query the value of IPv6 Traffic Class field of this socket.
Definition socket.cc:481
bool IsManualIpv6HopLimit() const
Checks if the socket has a specific IPv6 Hop Limit set.
Definition socket.cc:369
bool IsManualIpv6Tclass() const
Checks if the socket has a specific IPv6 Tclass set.
Definition socket.cc:357
void NotifyConnectionFailed()
Notify through the callback (if set) that the connection has not been established due to an error.
Definition socket.cc:213
indicates whether the socket has IP_TOS set.
Definition socket.h:1260
void SetTos(uint8_t tos)
Set the tag's TOS.
Definition socket.cc:787
This class implements a tag that carries the socket-specific TTL of a packet to the IP layer.
Definition socket.h:1113
void SetTtl(uint8_t ttl)
Set the tag's TTL.
Definition socket.cc:593
This class implements a tag that carries the socket-specific HOPLIMIT of a packet to the IPv6 layer.
Definition socket.h:1161
void SetHopLimit(uint8_t hopLimit)
Set the tag's Hop Limit.
Definition socket.cc:657
indicates whether the socket has IPV6_TCLASS set.
Definition socket.h:1355
void SetTclass(uint8_t tclass)
Set the tag's Tclass.
Definition socket.cc:899
indicates whether the socket has a priority set.
Definition socket.h:1307
void SetPriority(uint8_t priority)
Set the tag's priority.
Definition socket.cc:843
Header for the Transmission Control Protocol.
Definition tcp-header.h:36
void SetDestinationPort(uint16_t port)
Set the destination port.
Definition tcp-header.cc:59
void SetSequenceNumber(SequenceNumber32 sequenceNumber)
Set the sequence Number.
Definition tcp-header.cc:65
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
uint8_t GetMaxOptionLength() const
Get maximum option length.
uint16_t GetDestinationPort() const
Get the destination port.
Ptr< const TcpOption > GetOption(uint8_t kind) const
Get the option specified.
void SetFlags(uint8_t flags)
Set flags of the header.
Definition tcp-header.cc:77
void SetWindowSize(uint16_t windowSize)
Set the window size.
Definition tcp-header.cc:83
const TcpOptionList & GetOptionList() const
Get the list of option in this header.
uint16_t GetWindowSize() const
Get the window size.
uint8_t GetOptionLength() const
Get the total length of appended options.
bool AppendOption(Ptr< const TcpOption > option)
Append an option to the TCP header.
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:28
bool HasOption(uint8_t kind) const
Check if the header has the option specified.
uint16_t GetSourcePort() const
Get the source port.
Definition tcp-header.cc:95
void SetSourcePort(uint16_t port)
Set the source port.
Definition tcp-header.cc:53
void SetAckNumber(SequenceNumber32 ackNumber)
Set the ACK number.
Definition tcp-header.cc:71
uint8_t GetFlags() const
Get the flags.
SequenceNumber32 GetAckNumber() const
Get the ACK number.
@ SACKPERMITTED
SACKPERMITTED.
Definition tcp-option.h:49
@ WINSCALE
WINSCALE.
Definition tcp-option.h:48
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 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.
void AddSocketTags(const Ptr< Packet > &p, bool isEct) const
Add Tags for the Socket.
Ptr< TcpTxBuffer > GetTxBuffer() const
Get a pointer to the Tx buffer.
int SetupEndpoint()
Configure the endpoint to a local address.
virtual void LastAckTimeout()
Timeout at LAST_ACK, close the connection.
void ProcessEstablished(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon ESTABLISHED state.
Time m_minRto
minimum value of the Retransmit timeout
uint32_t SendPendingData(bool withAck=false)
Send as much pending data as possible according to the Tx window.
TracedValue< uint32_t > m_advWnd
Advertised Window size.
TracedCallback< Ptr< const Packet >, const TcpHeader &, Ptr< const TcpSocketBase > > m_txTrace
Trace of transmitted packets.
SequenceNumber32 m_recover
Previous highest Tx seqnum for fast recovery (set it to initial seq number)
bool m_recoverActive
Whether "m_recover" has been set/activated It is used to avoid comparing with the old m_recover value...
void DoRetransmit()
Retransmit the first segment marked as lost, without considering available window nor pacing.
bool CheckNoEcn(uint8_t tos) const
Checks if TOS has no ECN codepoints.
virtual void SetNode(Ptr< Node > node)
Set the associated node.
int ShutdownRecv() override
uint8_t m_sndWindShift
Window shift to apply to incoming segments.
Ptr< TcpL4Protocol > m_tcp
the associated TCP L4 protocol
Ptr< TcpSocketState > m_tcb
Congestion control information.
bool GetAllowBroadcast() const override
Query whether broadcast datagram transmissions are allowed.
void UpdateSsThresh(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState slow start threshold.
TracedCallback< Ptr< const Packet >, const TcpHeader &, Ptr< const TcpSocketBase > > m_rxTrace
Trace of received packets.
virtual void SetTcp(Ptr< TcpL4Protocol > tcp)
Set the associated TCP L4 protocol.
void EnterRecovery(uint32_t currentDelivered)
Enter the CA_RECOVERY, and retransmit the head.
Time GetMinRto() const
Get the Minimum RTO.
void ProcessSynSent(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon SYN_SENT.
void ForwardUp(Ptr< Packet > packet, Ipv4Header header, uint16_t port, Ptr< Ipv4Interface > incomingInterface)
Called by the L3 protocol when it received a packet to pass on to TCP.
bool SetAllowBroadcast(bool allowBroadcast) override
Configure whether broadcast datagram transmissions are allowed.
void CancelAllTimers()
Cancel all timer when endpoint is deleted.
Time GetDelAckTimeout() const override
Get the time to delay an ACK.
Ptr< TcpRecoveryOps > m_recoveryOps
Recovery Algorithm.
TracedCallback< uint32_t, uint32_t > m_bytesInFlightTrace
Callback pointer for bytesInFlight trace chaining.
uint32_t GetInitialSSThresh() const override
Get the initial Slow Start Threshold.
void NotifyPacingPerformed()
Notify Pacing.
void SetDelAckTimeout(Time timeout) override
Set the time to delay an ACK.
void CloseAndNotify()
Peacefully close the socket by notifying the upper layer and deallocate end point.
Ptr< TcpRateOps > m_rateOps
Rate operations.
void PeerClose(Ptr< Packet > p, const TcpHeader &tcpHeader)
Received a FIN from peer, notify rx buffer.
int Close() override
Close a socket.
bool m_shutdownSend
Send no longer allowed.
bool IsPacingEnabled() const
Return true if packets in the current window should be paced.
void ProcessOptionWScale(const Ptr< const TcpOption > option)
Read and parse the Window scale option.
bool m_closeOnEmpty
Close socket upon tx buffer emptied.
virtual void ReTxTimeout()
An RTO event happened.
void AddOptionSackPermitted(TcpHeader &header)
Add the SACK PERMITTED option to the header.
TracedValue< Time > m_rto
Retransmit timeout.
uint32_t GetSndBufSize() const override
Get the send buffer size.
virtual void ReceivedData(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Recv of a data, put into buffer, call L7 to get it if necessary.
EventId m_timewaitEvent
TIME_WAIT expiration event: Move this socket to CLOSED state.
Ptr< TcpTxBuffer > m_txBuffer
Tx buffer.
static TypeId GetTypeId()
Get the type ID.
uint32_t m_dupAckCount
Dupack counter.
void SetRetxThresh(uint32_t retxThresh)
Set the retransmission threshold (dup ack threshold for a fast retransmit)
int Send(Ptr< Packet > p, uint32_t flags) override
Send data (or dummy data) to the remote host.
TracedCallback< SequenceNumber32, SequenceNumber32 > m_nextTxSequenceTrace
Callback pointer for next tx sequence chaining.
void UpdateBytesInFlight(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState bytes inflight.
EventId m_delAckEvent
Delayed ACK timeout event.
TracedCallback< Time, Time > m_lastRttTrace
Callback pointer for Last 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.
virtual void ProcessAck(const SequenceNumber32 &ackNumber, bool scoreboardUpdated, uint32_t currentDelivered, const SequenceNumber32 &oldHeadSequence, bool receivedData)
Process a received ack.
int SendTo(Ptr< Packet > p, uint32_t flags, const Address &toAddress) override
Send data to a specified peer.
uint32_t m_dataRetries
Number of data retransmission attempts.
double m_msl
Max segment lifetime.
void ProcessLastAck(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon LAST_ACK.
bool m_limitedTx
perform limited transmit
virtual uint32_t SendDataPacket(SequenceNumber32 seq, uint32_t maxSize, bool withAck)
Extract at most maxSize bytes from the TxBuffer at sequence seq, add the TCP header,...
TracedCallback< TcpSocketState::TcpCongState_t, TcpSocketState::TcpCongState_t > m_congStateTrace
Callback pointer for congestion state trace chaining.
void ProcessSynRcvd(Ptr< Packet > packet, const TcpHeader &tcpHeader, const Address &fromAddress, const Address &toAddress)
Received a packet upon SYN_RCVD.
virtual void ReceivedAck(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received an ACK packet.
SocketType GetSocketType() const override
int ShutdownSend() override
TracedValue< SequenceNumber32 > m_ecnCWRSeq
Sequence number of the last sent CWR.
Time GetPersistTimeout() const override
Get the timeout for persistent connection.
void UpdateCwnd(uint32_t oldValue, uint32_t newValue) const
Callback function to hook to TcpSocketState congestion window.
void UpdateLastRtt(Time oldValue, Time newValue) const
Callback function to hook to TcpSocketState lastRtt.
TracedCallback< Ptr< const Packet >, const TcpHeader &, const Address &, const Address &, Ptr< const TcpSocketBase > > m_retransmissionTrace
Trace of retransmitted packets.
uint32_t m_delAckCount
Delayed ACK counter.
Ipv4EndPoint * m_endPoint
the IPv4 endpoint
TcpPacketType_t
Tcp Packet Types.
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)
bool IsEct(TcpPacketType_t packetType) const
Checks if a TCP packet should be ECN-capable (ECT) according to the TcpPacketType and ECN mode.
TracedValue< SequenceNumber32 > m_ecnCESeq
Sequence number of the last received Congestion Experienced.
void SetClockGranularity(Time clockGranularity)
Sets the Clock Granularity (used in RTO calcs).
bool IsValidTcpSegment(const SequenceNumber32 seq, const uint32_t tcpHeaderSize, const uint32_t tcpPayloadSize)
Checks whether the given TCP segment is valid or not.
Time m_clockGranularity
Clock Granularity used in RTO calcs.
void DupAck(uint32_t currentDelivered)
Dupack management.
bool m_shutdownRecv
Receive no longer allowed.
void UpdateCongState(TcpSocketState::TcpCongState_t oldValue, TcpSocketState::TcpCongState_t newValue) const
Callback function to hook to TcpSocketState congestion state.
virtual uint32_t Window() const
Return the max possible number of unacked bytes.
Callback< void, Ipv6Address, uint8_t, uint8_t, uint8_t, uint32_t > m_icmpCallback6
ICMPv6 callback.
std::deque< RttHistory > m_history
List of sent packet.
void ProcessOptionSackPermitted(const Ptr< const TcpOption > option)
Read the SACK PERMITTED option.
int Bind() override
Allocate a local IPv4 endpoint for this socket.
virtual uint32_t AvailableWindow() const
Return unfilled portion of window.
TracedValue< SequenceNumber32 > m_highRxMark
Highest seqno received.
void ReadOptions(const TcpHeader &tcpHeader, uint32_t *bytesSacked)
Read TCP options before Ack processing.
virtual uint16_t AdvertisedWindowSize(bool scale=true) const
The amount of Rx window announced to the peer.
void ForwardUp6(Ptr< Packet > packet, Ipv6Header header, uint16_t port, Ptr< Ipv6Interface > incomingInterface)
Called by the L3 protocol when it received a packet to pass on to TCP.
bool m_connected
Connection established.
TracedValue< SequenceNumber32 > m_highRxAckMark
Highest ack received.
void AddOptionWScale(TcpHeader &header)
Add the window scale option to the header.
virtual void SendEmptyPacket(uint8_t flags)
Send a empty packet that carries a flag, e.g., ACK.
void UpdateWindowSize(const TcpHeader &header)
Update the receiver window (RWND) based on the value of the window field in the header.
uint32_t GetRxAvailable() const override
Return number of bytes which can be returned from one or multiple calls to Recv.
uint32_t GetDataRetries() const override
Get the number of data transmission retries before giving up.
int SetupEndpoint6()
Configure the endpoint v6 to a local address.
uint32_t GetRetxThresh() const
Get the retransmission threshold (dup ack threshold for a fast retransmit)
void DeallocateEndPoint()
Deallocate m_endPoint and m_endPoint6.
void Destroy()
Kill this socket by zeroing its attributes (IPv4)
void UpdateHighTxMark(SequenceNumber32 oldValue, SequenceNumber32 newValue) const
Callback function to hook to TcpSocketState high tx mark.
TcpSocketBase()
Create an unbound TCP socket.
void SetInitialSSThresh(uint32_t threshold) override
Set the initial Slow Start Threshold.
TracedCallback< DataRate, DataRate > m_pacingRateTrace
Callback pointer for pacing rate trace chaining.
uint32_t m_timestampToEcho
Timestamp to echo.
Ipv6EndPoint * m_endPoint6
the IPv6 endpoint
void SetSndBufSize(uint32_t size) override
Set the send buffer size.
virtual Ptr< TcpSocketBase > Fork()
Call CopyObject<> to clone me.
TracedCallback< uint32_t, uint32_t > m_ssThTrace
Callback pointer for ssTh trace chaining.
SocketErrno m_errno
Socket error code.
SocketErrno GetErrno() const override
Get last error number.
virtual void CompleteFork(Ptr< Packet > p, const TcpHeader &tcpHeader, const Address &fromAddress, const Address &toAddress)
Complete a connection by forking the socket.
void ProcessClosing(Ptr< Packet > packet, const TcpHeader &tcpHeader)
Received a packet upon CLOSING.
TracedCallback< SequenceNumber32, SequenceNumber32 > m_highTxMarkTrace
Callback pointer for high tx mark chaining.
int Connect(const Address &address) override
Initiate a connection to a remote host.
Ptr< Node > m_node
the associated node
void SetSegSize(uint32_t size) override
Set the segment size.
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.
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.
TracedCallback< Time, Time > m_srttTrace
Callback pointer for RTT trace chaining.
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.
virtual Time CalculateRttSample(const TcpHeader &tcpHeader, const RttHistory &rttHistory)
Calculate RTT sample for the ACKed packet.
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.
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:37
static const char *const TcpStateName[TcpSocket::LAST_STATE]
Literal names of TCP states for use in log messages.
Definition tcp-socket.h:84
@ 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
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.
static INTERNET_EXPORT 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.
@ DctcpEcn
ECN functionality as described in RFC 8257.
@ ClassicEcn
ECN functionality as described in RFC 3168.
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.
static INTERNET_EXPORT const char *const EcnStateName[TcpSocketState::ECN_CWR_SENT+1]
Literal names of ECN states for use in log messages.
Item that encloses the application packet and some flags for it.
Definition tcp-tx-item.h:22
Ptr< Packet > GetPacketCopy() const
Get a copy of the Packet underlying this item.
bool IsRetrans() const
Is the item retransmitted?
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:392
@ S
second
Definition nstime.h:105
static Time FromDouble(double value, Unit unit)
Create a Time equal to value in unit unit.
Definition nstime.h:511
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
AttributeValue implementation for Time.
Definition nstime.h:1432
A simple virtual Timer class.
Definition timer.h:67
void SetFunction(FN fn)
Definition timer.h:268
bool IsExpired() const
Definition timer.cc:111
Time GetDelayLeft() const
Definition timer.cc:79
void Cancel()
Cancel the currently-running event if there is one.
Definition timer.cc:97
void Schedule()
Schedule a new event using the currently-configured delay, function, and arguments.
Definition timer.cc:151
bool IsRunning() const
Definition timer.cc:118
T Get() const
Get the underlying value.
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
uint16_t port
Definition dsdv-manet.cc:33
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
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:70
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:818
Ptr< const AttributeChecker > MakeCallbackChecker()
Definition callback.cc:77
Ptr< const AttributeChecker > MakeDoubleChecker()
Definition double.h: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:32
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:221
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:248
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:269
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:1433
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1453
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
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:35
Callback< R, Args... > MakeNullCallback()
Definition callback.h:727
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition abort.h:133
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:243
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#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:250
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
@ ESTABLISHED
Connection established
Definition tcp-socket.h:61
@ FIN_WAIT_2
All buffered data sent, waiting for remote to shutdown.
Definition tcp-socket.h:70
@ LISTEN
Listening for a connection
Definition tcp-socket.h:57
@ 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:62
@ SYN_SENT
Sent a connection request, waiting for ack
Definition tcp-socket.h:58
@ CLOSED
Socket is finished
Definition tcp-socket.h:56
@ FIN_WAIT_1
Our side has shutdown, waiting to complete transmission of remaining buffered data
Definition tcp-socket.h:68
@ TIME_WAIT
Timeout to catch resent junk before entering closed, can only be entered from FIN_WAIT2 or CLOSING.
Definition tcp-socket.h:73
@ SYN_RCVD
Received a connection request, sent ack, waiting for final ack in three-way handshake.
Definition tcp-socket.h:59
@ LAST_ACK
Our side has shutdown after remote has shutdown.
Definition tcp-socket.h:65
@ CLOSING
Both sides have shutdown but we still have data we have to finish sending
Definition tcp-socket.h:71
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
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 .
const std::map< std::pair< ns3::TcpSocketBase::TcpPacketType_t, ns3::TcpSocketState::EcnMode_t >, bool > ECN_RESTRICTION_MAP
map TcpPacketType and EcnMode to boolean value to check whether ECN-marking is allowed or not
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:684
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition enum.h:179
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
ns3::Time timeout