Files
unison/src/internet/model/tcp-socket-base.h
Gabriel Ferreira 4e642e5d60 internet: Fix tcp flags check to determine packet type
(TcpHeader::ACK | TcpHeader::ECE) was not correctly tested, resulting in an uninitialized packetType value
2024-10-06 03:23:07 +02:00

1494 lines
50 KiB
C++

/*
* Copyright (c) 2007 Georgia Tech Research Corporation
* Copyright (c) 2010 Adrian Sai-wah Tam
*
* SPDX-License-Identifier: GPL-2.0-only
*
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
*/
#ifndef TCP_SOCKET_BASE_H
#define TCP_SOCKET_BASE_H
#include "ipv4-header.h"
#include "ipv6-header.h"
#include "tcp-socket-state.h"
#include "tcp-socket.h"
#include "ns3/data-rate.h"
#include "ns3/node.h"
#include "ns3/sequence-number.h"
#include "ns3/timer.h"
#include "ns3/traced-value.h"
#include <queue>
#include <stdint.h>
namespace ns3
{
class Ipv4EndPoint;
class Ipv6EndPoint;
class Node;
class Packet;
class TcpL4Protocol;
class TcpHeader;
class TcpCongestionOps;
class TcpRecoveryOps;
class RttEstimator;
class TcpRxBuffer;
class TcpTxBuffer;
class TcpOption;
class Ipv4Interface;
class Ipv6Interface;
class TcpRateOps;
/**
* \ingroup tcp
*
* \brief Helper class to store RTT measurements
*/
class RttHistory
{
public:
/**
* \brief Constructor - builds an RttHistory with the given parameters
* \param s First sequence number in packet sent
* \param c Number of bytes sent
* \param t Time this one was sent
*/
RttHistory(SequenceNumber32 s, uint32_t c, Time t);
/**
* \brief Copy constructor
* \param h the object to copy
*/
RttHistory(const RttHistory& h); // Copy constructor
public:
SequenceNumber32 seq; //!< First sequence number in packet sent
uint32_t count; //!< Number of bytes sent
Time time; //!< Time this one was sent
bool retx; //!< True if this has been retransmitted
};
/**
* \ingroup socket
* \ingroup tcp
*
* \brief A base class for implementation of a stream socket using TCP.
*
* This class contains the essential components of TCP, as well as a sockets
* interface for upper layers to call. This class provides connection orientation
* and sliding window flow control; congestion control is delegated to subclasses
* of TcpCongestionOps. Part of TcpSocketBase is modified from the original
* NS-3 TCP socket implementation (TcpSocketImpl) by
* Raj Bhattacharjea <raj.b@gatech.edu> of Georgia Tech.
*
* For IPv4 packets, the TOS set for the socket is used. The Bind and Connect
* operations set the TOS for the socket to the value specified in the provided
* address. A SocketIpTos tag is only added to the packet if the resulting
* TOS is non-null.
* Each packet is assigned the priority set for the socket. Setting a TOS
* for a socket also sets a priority for the socket (according to the
* Socket::IpTos2Priority function). A SocketPriority tag is only added to the
* packet if the priority is non-null.
*
* Congestion state machine
* ---------------------------
*
* The socket maintains two state machines; the TCP one, and another called
* "Congestion state machine", which keeps track of the phase we are in. Currently,
* ns-3 manages the states:
*
* - CA_OPEN
* - CA_DISORDER
* - CA_RECOVERY
* - CA_LOSS
* - CA_CWR
*
* For more information, see the TcpCongState_t documentation.
*
* Congestion control interface
* ---------------------------
*
* Congestion control, unlike older releases of ns-3, has been split from
* TcpSocketBase. In particular, each congestion control is now a subclass of
* the main TcpCongestionOps class. Switching between congestion algorithm is
* now a matter of setting a pointer into the TcpSocketBase class. The idea
* and the interfaces are inspired by the Linux operating system, and in
* particular from the structure tcp_congestion_ops. The reference paper is
* https://www.sciencedirect.com/science/article/abs/pii/S1569190X15300939.
*
* Transmission Control Block (TCB)
* --------------------------------
*
* The variables needed to congestion control classes to operate correctly have
* been moved inside the TcpSocketState class. It contains information on the
* congestion window, slow start threshold, segment size and the state of the
* Congestion state machine.
*
* To track the trace inside the TcpSocketState class, a "forward" technique is
* used, which consists in chaining callbacks from TcpSocketState to TcpSocketBase
* (see for example cWnd trace source).
*
* Fast retransmit
* ----------------
*
* The fast retransmit enhancement is introduced in RFC 2581 and updated in RFC
* 5681. It reduces the time a sender waits before retransmitting a lost segment,
* through the assumption that if it receives a certain number of duplicate ACKs,
* a segment has been lost and it can be retransmitted. Usually, it is coupled
* with the Limited Transmit algorithm, defined in RFC 3042. These algorithms
* are included in this class, and they are implemented inside the ProcessAck
* method. With the SACK option enabled, the LimitedTransmit algorithm will be
* always on, as a consequence of how the information in the received SACK block
* is managed.
*
* The attribute which manages the number of dup ACKs necessary to start the
* fast retransmit algorithm is named "ReTxThreshold", and by default is 3.
* The parameter is also used in TcpTxBuffer to determine if a packet is lost
* (please take a look at TcpTxBuffer documentation to see details) but,
* right now, it is assumed to be fixed. In future releases this parameter can
* be made dynamic, to reflect the reordering degree of the network. With SACK,
* the next sequence to transmit is given by the RFC 6675 algorithm. Without
* SACK option, the implementation adds "hints" to TcpTxBuffer to make sure it
* returns, as next transmittable sequence, the first lost (or presumed lost)
* segment.
*
* Fast recovery
* -------------
*
* The fast recovery algorithm is introduced RFC 2001, and it avoids to reset
* cWnd to 1 segment after sensing a loss on the channel. Instead, a new slow
* start threshold value is asked to the congestion control (for instance,
* with NewReno the returned amount is half of the previous), and the cWnd is
* set equal to such value. Ns-3 does not implement any inflation/deflation to
* the congestion window since it uses an evolved method (borrowed from Linux
* operating system) to calculate the number of bytes in flight. The fundamental
* idea is to subtract from the total bytes in flight the lost/sacked amount
* (the segments that have left the network) and to add the retransmitted count.
* In this way, congestion window represents the exact number of bytes that
* should be in flight. The implementation then decides what to transmit, it
* there is space, between new or already transmitted data portion. If a value
* of the congestion window with inflation and deflation is needed, there is a
* traced source named "CongestionWindowInflated". However, the variable behind
* it is not used in the code, but maintained for backward compatibility.
*
* RTO expiration
* --------------
*
* When the Retransmission Time Out expires, the TCP faces a significant
* performance drop. The expiration event is managed in the ReTxTimeout method,
* which set the cWnd to 1 segment and starts "from scratch" again. The list
* of sent packet is set as lost entirely, and the transmission is re-started
* from the SND.UNA sequence number.
*
* Options management
* ------------------
*
* SYN and SYN-ACK options, which are allowed only at the beginning of the
* connection, are managed in the DoForwardUp and SendEmptyPacket methods.
* To read all others, we have set up a cycle inside ReadOptions. For adding
* them, there is no a unique place, since the options (and the information
* available to build them) are scattered around the code. For instance,
* the SACK option is built in SendEmptyPacket only under certain conditions.
*
* SACK
* ----
*
* The SACK generation/management is delegated to the buffer classes, namely
* TcpTxBuffer and TcpRxBuffer. In TcpRxBuffer it is managed the creation
* of the SACK option from the receiver point of view. It must provide an
* accurate (and efficient) representation of the status of the receiver buffer.
* On the other side, inside TcpTxBuffer the received options (that contain
* the SACK block) are processed and a particular data structure, called Scoreboard,
* is filled. Please take a look at TcpTxBuffer and TcpRxBuffer documentation if
* you need more information. The reference paper is
* https://dl.acm.org/citation.cfm?id=3067666.
*
*/
class TcpSocketBase : public TcpSocket
{
public:
/**
* Get the type ID.
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId();
/**
* \brief Get the instance TypeId
* \return the instance TypeId
*/
TypeId GetInstanceTypeId() const override;
/**
* \brief TcpGeneralTest friend class (for tests).
* \relates TcpGeneralTest
*/
friend class TcpGeneralTest;
/**
* Create an unbound TCP socket
*/
TcpSocketBase();
/**
* Clone a TCP socket, for use upon receiving a connection request in LISTEN state
*
* \param sock the original Tcp Socket
*/
TcpSocketBase(const TcpSocketBase& sock);
~TcpSocketBase() override;
/**
* \brief Tcp Packet Types
*
* Taxonomy referred from Table 1 of
* https://www.ietf.org/archive/id/draft-ietf-tcpm-generalized-ecn-15.txt
*/
enum TcpPacketType_t
{
SYN,
SYN_ACK,
PURE_ACK,
WINDOW_PROBE,
FIN,
RST,
RE_XMT,
DATA,
INVALID
};
// Set associated Node, TcpL4Protocol, RttEstimator to this socket
/**
* \brief Set the associated node.
* \param node the node
*/
virtual void SetNode(Ptr<Node> node);
/**
* \brief Set the associated TCP L4 protocol.
* \param tcp the TCP L4 protocol
*/
virtual void SetTcp(Ptr<TcpL4Protocol> tcp);
/**
* \brief Set the associated RTT estimator.
* \param rtt the RTT estimator
*/
virtual void SetRtt(Ptr<RttEstimator> rtt);
/**
* \brief Sets the Minimum RTO.
* \param minRto The minimum RTO.
*/
void SetMinRto(Time minRto);
/**
* \brief Get the Minimum RTO.
* \return The minimum RTO.
*/
Time GetMinRto() const;
/**
* \brief Sets the Clock Granularity (used in RTO calcs).
* \param clockGranularity The Clock Granularity
*/
void SetClockGranularity(Time clockGranularity);
/**
* \brief Get the Clock Granularity (used in RTO calcs).
* \return The Clock Granularity.
*/
Time GetClockGranularity() const;
/**
* \brief Get a pointer to the Tx buffer
* \return a pointer to the tx buffer
*/
Ptr<TcpTxBuffer> GetTxBuffer() const;
/**
* \brief Get a pointer to the Rx buffer
* \return a pointer to the rx buffer
*/
Ptr<TcpRxBuffer> GetRxBuffer() const;
/**
* \brief Set the retransmission threshold (dup ack threshold for a fast retransmit)
* \param retxThresh the threshold
*/
void SetRetxThresh(uint32_t retxThresh);
/**
* \brief Get the retransmission threshold (dup ack threshold for a fast retransmit)
* \return the threshold
*/
uint32_t GetRetxThresh() const
{
return m_retxThresh;
}
/**
* \brief Callback pointer for pacing rate trace chaining
*/
TracedCallback<DataRate, DataRate> m_pacingRateTrace;
/**
* \brief Callback pointer for cWnd trace chaining
*/
TracedCallback<uint32_t, uint32_t> m_cWndTrace;
/**
* \brief Callback pointer for cWndInfl trace chaining
*/
TracedCallback<uint32_t, uint32_t> m_cWndInflTrace;
/**
* \brief Callback pointer for ssTh trace chaining
*/
TracedCallback<uint32_t, uint32_t> m_ssThTrace;
/**
* \brief Callback pointer for congestion state trace chaining
*/
TracedCallback<TcpSocketState::TcpCongState_t, TcpSocketState::TcpCongState_t> m_congStateTrace;
/**
* \brief Callback pointer for ECN state trace chaining
*/
TracedCallback<TcpSocketState::EcnState_t, TcpSocketState::EcnState_t> m_ecnStateTrace;
/**
* \brief Callback pointer for high tx mark chaining
*/
TracedCallback<SequenceNumber32, SequenceNumber32> m_highTxMarkTrace;
/**
* \brief Callback pointer for next tx sequence chaining
*/
TracedCallback<SequenceNumber32, SequenceNumber32> m_nextTxSequenceTrace;
/**
* \brief Callback pointer for bytesInFlight trace chaining
*/
TracedCallback<uint32_t, uint32_t> m_bytesInFlightTrace;
/**
* \brief Callback pointer for RTT trace chaining
*/
TracedCallback<Time, Time> m_srttTrace;
/**
* \brief Callback pointer for Last RTT trace chaining
*/
TracedCallback<Time, Time> m_lastRttTrace;
/**
* \brief Callback function to hook to TcpSocketState pacing rate
* \param oldValue old pacing rate value
* \param newValue new pacing rate value
*/
void UpdatePacingRateTrace(DataRate oldValue, DataRate newValue) const;
/**
* \brief Callback function to hook to TcpSocketState congestion window
* \param oldValue old cWnd value
* \param newValue new cWnd value
*/
void UpdateCwnd(uint32_t oldValue, uint32_t newValue) const;
/**
* \brief Callback function to hook to TcpSocketState inflated congestion window
* \param oldValue old cWndInfl value
* \param newValue new cWndInfl value
*/
void UpdateCwndInfl(uint32_t oldValue, uint32_t newValue) const;
/**
* \brief Callback function to hook to TcpSocketState slow start threshold
* \param oldValue old ssTh value
* \param newValue new ssTh value
*/
void UpdateSsThresh(uint32_t oldValue, uint32_t newValue) const;
/**
* \brief Callback function to hook to TcpSocketState congestion state
* \param oldValue old congestion state value
* \param newValue new congestion state value
*/
void UpdateCongState(TcpSocketState::TcpCongState_t oldValue,
TcpSocketState::TcpCongState_t newValue) const;
/**
* \brief Callback function to hook to EcnState state
* \param oldValue old ecn state value
* \param newValue new ecn state value
*/
void UpdateEcnState(TcpSocketState::EcnState_t oldValue,
TcpSocketState::EcnState_t newValue) const;
/**
* \brief Callback function to hook to TcpSocketState high tx mark
* \param oldValue old high tx mark
* \param newValue new high tx mark
*/
void UpdateHighTxMark(SequenceNumber32 oldValue, SequenceNumber32 newValue) const;
/**
* \brief Callback function to hook to TcpSocketState next tx sequence
* \param oldValue old nextTxSeq value
* \param newValue new nextTxSeq value
*/
void UpdateNextTxSequence(SequenceNumber32 oldValue, SequenceNumber32 newValue) const;
/**
* \brief Callback function to hook to TcpSocketState bytes inflight
* \param oldValue old bytesInFlight value
* \param newValue new bytesInFlight value
*/
void UpdateBytesInFlight(uint32_t oldValue, uint32_t newValue) const;
/**
* \brief Callback function to hook to TcpSocketState rtt
* \param oldValue old rtt value
* \param newValue new rtt value
*/
void UpdateRtt(Time oldValue, Time newValue) const;
/**
* \brief Callback function to hook to TcpSocketState lastRtt
* \param oldValue old lastRtt value
* \param newValue new lastRtt value
*/
void UpdateLastRtt(Time oldValue, Time newValue) const;
/**
* \brief Install a congestion control algorithm on this socket
*
* \param algo Algorithm to be installed
*/
void SetCongestionControlAlgorithm(Ptr<TcpCongestionOps> algo);
/**
* \brief Install a recovery algorithm on this socket
*
* \param recovery Algorithm to be installed
*/
void SetRecoveryAlgorithm(Ptr<TcpRecoveryOps> recovery);
/**
* \brief Mark ECT(0) codepoint
*
* \param tos the TOS byte to modify
* \return TOS with ECT(0) codepoint set
*/
inline uint8_t MarkEcnEct0(uint8_t tos) const
{
return ((tos & 0xfc) | 0x02);
}
/**
* \brief Mark ECT(1) codepoint
*
* \param tos the TOS byte to modify
* \return TOS with ECT(1) codepoint set
*/
inline uint8_t MarkEcnEct1(uint8_t tos) const
{
return ((tos & 0xfc) | 0x01);
}
/**
* \brief Mark CE codepoint
*
* \param tos the TOS byte to modify
* \return TOS with CE codepoint set
*/
inline uint8_t MarkEcnCe(uint8_t tos) const
{
return ((tos & 0xfc) | 0x03);
}
/**
* \brief Clears ECN bits from TOS
*
* \param tos the TOS byte to modify
* \return TOS without ECN bits
*/
inline uint8_t ClearEcnBits(uint8_t tos) const
{
return tos & 0xfc;
}
/**
* \brief Checks if TOS has no ECN codepoints
*
* \param tos the TOS byte to check
* \return true if TOS does not have any ECN codepoints set; otherwise false
*/
inline bool CheckNoEcn(uint8_t tos) const
{
return ((tos & 0x03) == 0x00);
}
/**
* \brief Checks for ECT(0) codepoint
*
* \param tos the TOS byte to check
* \return true if TOS has ECT(0) codepoint set; otherwise false
*/
inline bool CheckEcnEct0(uint8_t tos) const
{
return ((tos & 0x03) == 0x02);
}
/**
* \brief Checks for ECT(1) codepoint
*
* \param tos the TOS byte to check
* \return true if TOS has ECT(1) codepoint set; otherwise false
*/
inline bool CheckEcnEct1(uint8_t tos) const
{
return ((tos & 0x03) == 0x01);
}
/**
* \brief Checks for CE codepoint
*
* \param tos the TOS byte to check
* \return true if TOS has CE codepoint set; otherwise false
*/
inline bool CheckEcnCe(uint8_t tos) const
{
return ((tos & 0x03) == 0x03);
}
/**
* \brief mark ECN code point
*
* \param tos the TOS byte to modify
* \param codePoint the codepoint to use
* \return TOS with specified ECN code point
*/
inline uint8_t MarkEcnCodePoint(const uint8_t tos,
const TcpSocketState::EcnCodePoint_t codePoint) const
{
return ((tos & 0xfc) | codePoint);
}
/**
* \brief Set ECN mode of use on the socket
*
* \param useEcn Mode of ECN to use.
*/
void SetUseEcn(TcpSocketState::UseEcn_t useEcn);
/**
* \brief Enable or disable pacing
* \param pacing Boolean to enable or disable pacing
*/
void SetPacingStatus(bool pacing);
/**
* \brief Enable or disable pacing of the initial window
* \param paceWindow Boolean to enable or disable pacing of the initial window
*/
void SetPaceInitialWindow(bool paceWindow);
/**
* \brief Checks if a TCP packet should be ECN-capable (ECT) according to the TcpPacketType and
* ECN mode.
*
* Currently, only Classic ECN and DCTCP ECN modes are supported, with
* potential extensions for future modes (Ecnpp).
*
* \param packetType The type of the TCP packet, represented by an enum TcpPacketType.
* \return true if the packet is ECN-capable (ECT), false otherwise.
*
* Reference: https://www.ietf.org/archive/id/draft-ietf-tcpm-generalized-ecn-15.txt (Table 1)
*/
bool IsEct(TcpPacketType_t packetType) const;
// Necessary implementations of null functions from ns3::Socket
SocketErrno GetErrno() const override; // returns m_errno
SocketType GetSocketType() const override; // returns socket type
Ptr<Node> GetNode() const override; // returns m_node
int Bind() override; // Bind a socket by setting up endpoint in TcpL4Protocol
int Bind6() override; // Bind a socket by setting up endpoint in TcpL4Protocol
int Bind(const Address& address) override; // ... endpoint of specific addr or port
int Connect(
const Address& address) override; // Setup endpoint and call ProcessAction() to connect
int Listen()
override; // Verify the socket is in a correct state and call ProcessAction() to listen
int Close() override; // Close by app: Kill socket upon tx buffer emptied
int ShutdownSend() override; // Assert the m_shutdownSend flag to prevent send to network
int ShutdownRecv() override; // Assert the m_shutdownRecv flag to prevent forward to app
int Send(Ptr<Packet> p, uint32_t flags) override; // Call by app to send data to network
int SendTo(Ptr<Packet> p,
uint32_t flags,
const Address& toAddress) override; // Same as Send(), toAddress is insignificant
Ptr<Packet> Recv(uint32_t maxSize,
uint32_t flags) override; // Return a packet to be forwarded to app
Ptr<Packet> RecvFrom(uint32_t maxSize, uint32_t flags, Address& fromAddress)
override; // ... and write the remote address at fromAddress
uint32_t GetTxAvailable() const override; // Available Tx buffer size
uint32_t GetRxAvailable()
const override; // Available-to-read data size, i.e. value of m_rxAvailable
int GetSockName(Address& address) const override; // Return local addr:port in address
int GetPeerName(Address& address) const override;
void BindToNetDevice(Ptr<NetDevice> netdevice) override; // NetDevice with my m_endPoint
/**
* TracedCallback signature for TCP packet transmission or reception events.
*
* \param [in] packet The packet.
* \param [in] header The TcpHeader
* \param [in] socket This socket
*/
typedef void (*TcpTxRxTracedCallback)(const Ptr<const Packet> packet,
const TcpHeader& header,
const Ptr<const TcpSocketBase> socket);
/**
* TracedCallback signature for TCP packet retransmission events.
*
* \param [in] packet The packet.
* \param [in] header The TcpHeader
* \param [in] localAddr The local address
* \param [in] peerAddr The peer/remote address
* \param [in] socket This socket
*/
typedef void (*RetransmissionCallback)(const Ptr<const Packet> packet,
const TcpHeader& header,
const Address& localAddr,
const Address& peerAddr,
const Ptr<const TcpSocketBase> socket);
protected:
// Implementing ns3::TcpSocket -- Attribute get/set
// inherited, no need to doc
void SetSndBufSize(uint32_t size) override;
uint32_t GetSndBufSize() const override;
void SetRcvBufSize(uint32_t size) override;
uint32_t GetRcvBufSize() const override;
void SetSegSize(uint32_t size) override;
uint32_t GetSegSize() const override;
void SetInitialSSThresh(uint32_t threshold) override;
uint32_t GetInitialSSThresh() const override;
void SetInitialCwnd(uint32_t cwnd) override;
uint32_t GetInitialCwnd() const override;
void SetConnTimeout(Time timeout) override;
Time GetConnTimeout() const override;
void SetSynRetries(uint32_t count) override;
uint32_t GetSynRetries() const override;
void SetDataRetries(uint32_t retries) override;
uint32_t GetDataRetries() const override;
void SetDelAckTimeout(Time timeout) override;
Time GetDelAckTimeout() const override;
void SetDelAckMaxCount(uint32_t count) override;
uint32_t GetDelAckMaxCount() const override;
void SetTcpNoDelay(bool noDelay) override;
bool GetTcpNoDelay() const override;
void SetPersistTimeout(Time timeout) override;
Time GetPersistTimeout() const override;
bool SetAllowBroadcast(bool allowBroadcast) override;
bool GetAllowBroadcast() const override;
// Helper functions: Connection set up
/**
* \brief Common part of the two Bind(), i.e. set callback and remembering local addr:port
*
* \returns 0 on success, -1 on failure
*/
int SetupCallback();
/**
* \brief Perform the real connection tasks: Send SYN if allowed, RST if invalid
*
* \returns 0 on success
*/
int DoConnect();
/**
* \brief Schedule-friendly wrapper for Socket::NotifyConnectionSucceeded()
*/
void ConnectionSucceeded();
/**
* \brief Configure the endpoint to a local address. Called by Connect() if Bind() didn't
* specify one.
*
* \returns 0 on success
*/
int SetupEndpoint();
/**
* \brief Configure the endpoint v6 to a local address. Called by Connect() if Bind() didn't
* specify one.
*
* \returns 0 on success
*/
int SetupEndpoint6();
/**
* \brief Complete a connection by forking the socket
*
* This function is called only if a SYN received in LISTEN state. After
* TcpSocketBase cloned, allocate a new end point to handle the incoming
* connection and send a SYN+ACK to complete the handshake.
*
* \param p the packet triggering the fork
* \param tcpHeader the TCP header of the triggering packet
* \param fromAddress the address of the remote host
* \param toAddress the address the connection is directed to
*/
virtual void CompleteFork(Ptr<Packet> p,
const TcpHeader& tcpHeader,
const Address& fromAddress,
const Address& toAddress);
// Helper functions: Transfer operation
/**
* \brief Checks whether the given TCP segment is valid or not.
*
* \param seq the sequence number of packet's TCP header
* \param tcpHeaderSize the size of packet's TCP header
* \param tcpPayloadSize the size of TCP payload
* \return true if the TCP segment is valid
*/
bool IsValidTcpSegment(const SequenceNumber32 seq,
const uint32_t tcpHeaderSize,
const uint32_t tcpPayloadSize);
/**
* \brief Called by the L3 protocol when it received a packet to pass on to TCP.
*
* \param packet the incoming packet
* \param header the packet's IPv4 header
* \param port the remote port
* \param incomingInterface the incoming interface
*/
void ForwardUp(Ptr<Packet> packet,
Ipv4Header header,
uint16_t port,
Ptr<Ipv4Interface> incomingInterface);
/**
* \brief Called by the L3 protocol when it received a packet to pass on to TCP.
*
* \param packet the incoming packet
* \param header the packet's IPv6 header
* \param port the remote port
* \param incomingInterface the incoming interface
*/
void ForwardUp6(Ptr<Packet> packet,
Ipv6Header header,
uint16_t port,
Ptr<Ipv6Interface> incomingInterface);
/**
* \brief Called by TcpSocketBase::ForwardUp{,6}().
*
* Get a packet from L3. This is the real function to handle the
* incoming packet from lower layers. This is
* wrapped by ForwardUp() so that this function can be overloaded by daughter
* classes.
*
* \param packet the incoming packet
* \param fromAddress the address of the sender of packet
* \param toAddress the address of the receiver of packet (hopefully, us)
*/
virtual void DoForwardUp(Ptr<Packet> packet,
const Address& fromAddress,
const Address& toAddress);
/**
* \brief Called by the L3 protocol when it received an ICMP packet to pass on to TCP.
*
* \param icmpSource the ICMP source address
* \param icmpTtl the ICMP Time to Live
* \param icmpType the ICMP Type
* \param icmpCode the ICMP Code
* \param icmpInfo the ICMP Info
*/
void ForwardIcmp(Ipv4Address icmpSource,
uint8_t icmpTtl,
uint8_t icmpType,
uint8_t icmpCode,
uint32_t icmpInfo);
/**
* \brief Called by the L3 protocol when it received an ICMPv6 packet to pass on to TCP.
*
* \param icmpSource the ICMP source address
* \param icmpTtl the ICMP Time to Live
* \param icmpType the ICMP Type
* \param icmpCode the ICMP Code
* \param icmpInfo the ICMP Info
*/
void ForwardIcmp6(Ipv6Address icmpSource,
uint8_t icmpTtl,
uint8_t icmpType,
uint8_t icmpCode,
uint32_t icmpInfo);
/**
* \brief Send as much pending data as possible according to the Tx window.
*
* Note that this function did not implement the PSH flag.
*
* \param withAck forces an ACK to be sent
* \returns the number of packets sent
*/
uint32_t SendPendingData(bool withAck = false);
/**
* \brief Extract at most maxSize bytes from the TxBuffer at sequence seq, add the
* TCP header, and send to TcpL4Protocol
*
* \param seq the sequence number
* \param maxSize the maximum data block to be transmitted (in bytes)
* \param withAck forces an ACK to be sent
* \returns the number of bytes sent
*/
virtual uint32_t SendDataPacket(SequenceNumber32 seq, uint32_t maxSize, bool withAck);
/**
* \brief Send a empty packet that carries a flag, e.g., ACK
*
* \param flags the packet's flags
*/
virtual void SendEmptyPacket(uint8_t flags);
/**
* \brief Send reset and tear down this socket
*/
void SendRST();
/**
* \brief Check if a sequence number range is within the rx window
*
* \param head start of the Sequence window
* \param tail end of the Sequence window
* \returns true if it is in range
*/
bool OutOfRange(SequenceNumber32 head, SequenceNumber32 tail) const;
// Helper functions: Connection close
/**
* \brief Close a socket by sending RST, FIN, or FIN+ACK, depend on the current state
*
* \returns 0 on success
*/
int DoClose();
/**
* \brief Peacefully close the socket by notifying the upper layer and deallocate end point
*/
void CloseAndNotify();
/**
* \brief Kill this socket by zeroing its attributes (IPv4)
*
* This is a callback function configured to m_endpoint in
* SetupCallback(), invoked when the endpoint is destroyed.
*/
void Destroy();
/**
* \brief Kill this socket by zeroing its attributes (IPv6)
*
* This is a callback function configured to m_endpoint in
* SetupCallback(), invoked when the endpoint is destroyed.
*/
void Destroy6();
/**
* \brief Deallocate m_endPoint and m_endPoint6
*/
void DeallocateEndPoint();
/**
* \brief Received a FIN from peer, notify rx buffer
*
* \param p the packet
* \param tcpHeader the packet's TCP header
*/
void PeerClose(Ptr<Packet> p, const TcpHeader& tcpHeader);
/**
* \brief FIN is in sequence, notify app and respond with a FIN
*/
void DoPeerClose();
/**
* \brief Cancel all timer when endpoint is deleted
*/
void CancelAllTimers();
/**
* \brief Move from CLOSING or FIN_WAIT_2 to TIME_WAIT state
*/
void TimeWait();
// State transition functions
/**
* \brief Received a packet upon ESTABLISHED state.
*
* This function is mimicking the role of tcp_rcv_established() in tcp_input.c in Linux kernel.
*
* \param packet the packet
* \param tcpHeader the packet's TCP header
*/
void ProcessEstablished(Ptr<Packet> packet,
const TcpHeader& tcpHeader); // Received a packet upon ESTABLISHED state
/**
* \brief Received a packet upon LISTEN state.
*
* \param packet the packet
* \param tcpHeader the packet's TCP header
* \param fromAddress the source address
* \param toAddress the destination address
*/
void ProcessListen(Ptr<Packet> packet,
const TcpHeader& tcpHeader,
const Address& fromAddress,
const Address& toAddress);
/**
* \brief Received a packet upon SYN_SENT
*
* \param packet the packet
* \param tcpHeader the packet's TCP header
*/
void ProcessSynSent(Ptr<Packet> packet, const TcpHeader& tcpHeader);
/**
* \brief Received a packet upon SYN_RCVD.
*
* \param packet the packet
* \param tcpHeader the packet's TCP header
* \param fromAddress the source address
* \param toAddress the destination address
*/
void ProcessSynRcvd(Ptr<Packet> packet,
const TcpHeader& tcpHeader,
const Address& fromAddress,
const Address& toAddress);
/**
* \brief Received a packet upon CLOSE_WAIT, FIN_WAIT_1, FIN_WAIT_2
*
* \param packet the packet
* \param tcpHeader the packet's TCP header
*/
void ProcessWait(Ptr<Packet> packet, const TcpHeader& tcpHeader);
/**
* \brief Received a packet upon CLOSING
*
* \param packet the packet
* \param tcpHeader the packet's TCP header
*/
void ProcessClosing(Ptr<Packet> packet, const TcpHeader& tcpHeader);
/**
* \brief Received a packet upon LAST_ACK
*
* \param packet the packet
* \param tcpHeader the packet's TCP header
*/
void ProcessLastAck(Ptr<Packet> packet, const TcpHeader& tcpHeader);
// Window management
/**
* \brief Return count of number of unacked bytes
*
* The difference between SND.UNA and HighTx
*
* \returns count of number of unacked bytes
*/
virtual uint32_t UnAckDataCount() const;
/**
* \brief Return total bytes in flight
*
* Does not count segments lost and SACKed (or dupACKed)
*
* \returns total bytes in flight
*/
virtual uint32_t BytesInFlight() const;
/**
* \brief Return the max possible number of unacked bytes
* \returns the max possible number of unacked bytes
*/
virtual uint32_t Window() const;
/**
* \brief Return unfilled portion of window
* \return unfilled portion of window
*/
virtual uint32_t AvailableWindow() const;
/**
* \brief The amount of Rx window announced to the peer
* \param scale indicate if the window should be scaled. True for
* almost all cases, except when we are sending a SYN
* \returns size of Rx window announced to the peer
*/
virtual uint16_t AdvertisedWindowSize(bool scale = true) const;
/**
* \brief Update the receiver window (RWND) based on the value of the
* window field in the header.
*
* This method suppresses updates unless one of the following three
* conditions holds: 1) segment contains new data (advancing the right
* edge of the receive buffer), 2) segment does not contain new data
* but the segment acks new data (highest sequence number acked advances),
* or 3) the advertised window is larger than the current send window
*
* \param header TcpHeader from which to extract the new window value
*/
void UpdateWindowSize(const TcpHeader& header);
// Manage data tx/rx
/**
* \brief Call CopyObject<> to clone me
* \returns a copy of the socket
*/
virtual Ptr<TcpSocketBase> Fork();
/**
* \brief Received an ACK packet
* \param packet the packet
* \param tcpHeader the packet's TCP header
*/
virtual void ReceivedAck(Ptr<Packet> packet, const TcpHeader& tcpHeader);
/**
* \brief Process a received ack
* \param ackNumber ack number
* \param scoreboardUpdated if true indicates that the scoreboard has been
* \param oldHeadSequence value of HeadSequence before ack
* updated with SACK information
* \param currentDelivered The number of bytes (S)ACKed
* \param receivedData if true indicates that data is piggybacked with ACK
*/
virtual void ProcessAck(const SequenceNumber32& ackNumber,
bool scoreboardUpdated,
uint32_t currentDelivered,
const SequenceNumber32& oldHeadSequence,
bool receivedData);
/**
* \brief Recv of a data, put into buffer, call L7 to get it if necessary
* \param packet the packet
* \param tcpHeader the packet's TCP header
*/
virtual void ReceivedData(Ptr<Packet> packet, const TcpHeader& tcpHeader);
/**
* \brief Calculate RTT sample for the ACKed packet
*
* Per RFC 6298 (Section 3),
* If `m_timestampsEnabled` is true, calculate RTT using timestamps option.
* Otherwise, return RTT as the elapsed time since the packet was transmitted.
* If ACKed packed was a retrasmitted packet, return zero time.
*
* \param tcpHeader the packet's TCP header
* \param rttHistory the ACKed packet's RTT History
* \returns the RTT sample
*/
virtual Time CalculateRttSample(const TcpHeader& tcpHeader, const RttHistory& rttHistory);
/**
* \brief Take into account the packet for RTT estimation
* \param tcpHeader the packet's TCP header
*/
virtual void EstimateRtt(const TcpHeader& tcpHeader);
/**
* \brief Update the RTT history, when we send TCP segments
*
* \param seq The sequence number of the TCP segment
* \param sz The segment's size
* \param isRetransmission Whether or not the segment is a retransmission
*/
virtual void UpdateRttHistory(const SequenceNumber32& seq, uint32_t sz, bool isRetransmission);
/**
* \brief Update buffers w.r.t. ACK
* \param seq the sequence number
* \param resetRTO indicates if RTO should be reset
*/
virtual void NewAck(const SequenceNumber32& seq, bool resetRTO);
/**
* \brief Dupack management
*
* \param currentDelivered Current (S)ACKed bytes
*/
void DupAck(uint32_t currentDelivered);
/**
* \brief Enter CA_CWR state upon receipt of an ECN Echo
*
* \param currentDelivered Currently (S)ACKed bytes
*/
void EnterCwr(uint32_t currentDelivered);
/**
* \brief Enter the CA_RECOVERY, and retransmit the head
*
* \param currentDelivered Currently (S)ACKed bytes
*/
void EnterRecovery(uint32_t currentDelivered);
/**
* \brief An RTO event happened
*/
virtual void ReTxTimeout();
/**
* \brief Action upon delay ACK timeout, i.e. send an ACK
*/
virtual void DelAckTimeout();
/**
* \brief Timeout at LAST_ACK, close the connection
*/
virtual void LastAckTimeout();
/**
* \brief Send 1 byte probe to get an updated window size
*/
virtual void PersistTimeout();
/**
* \brief Retransmit the first segment marked as lost, without considering
* available window nor pacing.
*/
void DoRetransmit();
/**
* \brief Add options to TcpHeader
*
* Test each option, and if it is enabled on our side, add it
* to the header
*
* \param tcpHeader TcpHeader to add options to
*/
void AddOptions(TcpHeader& tcpHeader);
/**
* \brief Read TCP options before Ack processing
*
* Timestamp and Window scale are managed in other pieces of code.
*
* \param tcpHeader Header of the segment
* \param [out] bytesSacked Number of bytes SACKed, or 0
*/
void ReadOptions(const TcpHeader& tcpHeader, uint32_t* bytesSacked);
/**
* \brief Return true if the specified option is enabled
*
* \param kind kind of TCP option
* \return true if the option is enabled
*/
bool IsTcpOptionEnabled(uint8_t kind) const;
/**
* \brief Read and parse the Window scale option
*
* Read the window scale option (encoded logarithmically) and save it.
* Per RFC 1323, the value can't exceed 14.
*
* \param option Window scale option read from the header
*/
void ProcessOptionWScale(const Ptr<const TcpOption> option);
/**
* \brief Add the window scale option to the header
*
* Calculate our factor from the rxBuffer max size, and add it
* to the header.
*
* \param header TcpHeader where the method should add the window scale option
*/
void AddOptionWScale(TcpHeader& header);
/**
* \brief Calculate window scale value based on receive buffer space
*
* Calculate our factor from the rxBuffer max size
*
* \returns the Window Scale factor
*/
uint8_t CalculateWScale() const;
/**
* \brief Read the SACK PERMITTED option
*
* Currently this is a placeholder, since no operations should be done
* on such option.
*
* \param option SACK PERMITTED option from the header
*/
void ProcessOptionSackPermitted(const Ptr<const TcpOption> option);
/**
* \brief Read the SACK option
*
* \param option SACK option from the header
* \returns the number of bytes sacked by this option
*/
uint32_t ProcessOptionSack(const Ptr<const TcpOption> option);
/**
* \brief Add the SACK PERMITTED option to the header
*
* \param header TcpHeader where the method should add the option
*/
void AddOptionSackPermitted(TcpHeader& header);
/**
* \brief Add the SACK option to the header
*
* \param header TcpHeader where the method should add the option
*/
void AddOptionSack(TcpHeader& header);
/**
* \brief Process the timestamp option from other side
*
* Get the timestamp and the echo, then save timestamp (which will
* be the echo value in our out-packets) and save the echoed timestamp,
* to utilize later to calculate RTT.
*
* \see EstimateRtt
* \param option Option from the segment
* \param seq Sequence number of the segment
*/
void ProcessOptionTimestamp(const Ptr<const TcpOption> option, const SequenceNumber32& seq);
/**
* \brief Add the timestamp option to the header
*
* Set the timestamp as the lower bits of the Simulator::Now time,
* and the echo value as the last seen timestamp from the other part.
*
* \param header TcpHeader to which add the option to
*/
void AddOptionTimestamp(TcpHeader& header);
/**
* \brief Performs a safe subtraction between a and b (a-b)
*
* Safe is used to indicate that, if b>a, the results returned is 0.
*
* \param a first number
* \param b second number
* \return 0 if b>0, (a-b) otherwise
*/
static uint32_t SafeSubtraction(uint32_t a, uint32_t b);
/**
* \brief Notify Pacing
*/
void NotifyPacingPerformed();
/**
* \brief Return true if packets in the current window should be paced
* \return true if pacing is currently enabled
*/
bool IsPacingEnabled() const;
/**
* \brief Dynamically update the pacing rate
*/
void UpdatePacingRate();
/**
* \brief Add Tags for the Socket
* \param p Packet
* \param isEct Whether the packet is allowed to be ECT capable
*/
void AddSocketTags(const Ptr<Packet>& p, bool isEct) const;
/**
* Get the current value of the receiver's offered window (RCV.WND)
* \note This method exists to expose the value to the TcpTxBuffer
* \return value of receiver's offered window
*/
uint32_t GetRWnd() const;
/**
* Get the current value of the receiver's highest (in-sequence) sequence number acked.
* \note This method exists to expose the value to the TcpTxBuffer
* \return value of receiver's highest sequence number acked.
*/
SequenceNumber32 GetHighRxAck() const;
protected:
// Counters and events
EventId m_retxEvent{}; //!< Retransmission event
EventId m_lastAckEvent{}; //!< Last ACK timeout event
EventId m_delAckEvent{}; //!< Delayed ACK timeout event
EventId m_persistEvent{}; //!< Persist event: Send 1 byte to probe for a non-zero Rx window
EventId m_timewaitEvent{}; //!< TIME_WAIT expiration event: Move this socket to CLOSED state
// ACK management
uint32_t m_dupAckCount{0}; //!< Dupack counter
uint32_t m_delAckCount{0}; //!< Delayed ACK counter
uint32_t m_delAckMaxCount{0}; //!< Number of packet to fire an ACK before delay timeout
// Nagle algorithm
bool m_noDelay{false}; //!< Set to true to disable Nagle's algorithm
// Retries
uint32_t m_synCount{0}; //!< Count of remaining connection retries
uint32_t m_synRetries{0}; //!< Number of connection attempts
uint32_t m_dataRetrCount{0}; //!< Count of remaining data retransmission attempts
uint32_t m_dataRetries{0}; //!< Number of data retransmission attempts
// Timeouts
TracedValue<Time> m_rto{Seconds(0.0)}; //!< Retransmit timeout
Time m_minRto{Time::Max()}; //!< minimum value of the Retransmit timeout
Time m_clockGranularity{Seconds(0.001)}; //!< Clock Granularity used in RTO calcs
Time m_delAckTimeout{Seconds(0.0)}; //!< Time to delay an ACK
Time m_persistTimeout{Seconds(0.0)}; //!< Time between sending 1-byte probes
Time m_cnTimeout{Seconds(0.0)}; //!< Timeout for connection retry
// History of RTT
std::deque<RttHistory> m_history; //!< List of sent packet
// Connections to other layers of TCP/IP
Ipv4EndPoint* m_endPoint{nullptr}; //!< the IPv4 endpoint
Ipv6EndPoint* m_endPoint6{nullptr}; //!< the IPv6 endpoint
Ptr<Node> m_node; //!< the associated node
Ptr<TcpL4Protocol> m_tcp; //!< the associated TCP L4 protocol
Callback<void, Ipv4Address, uint8_t, uint8_t, uint8_t, uint32_t>
m_icmpCallback; //!< ICMP callback
Callback<void, Ipv6Address, uint8_t, uint8_t, uint8_t, uint32_t>
m_icmpCallback6; //!< ICMPv6 callback
Ptr<RttEstimator> m_rtt; //!< Round trip time estimator
// Tx buffer management
Ptr<TcpTxBuffer> m_txBuffer; //!< Tx buffer
// State-related attributes
TracedValue<TcpStates_t> m_state{CLOSED}; //!< TCP state
mutable SocketErrno m_errno{ERROR_NOTERROR}; //!< Socket error code
bool m_closeNotified{false}; //!< Told app to close socket
bool m_closeOnEmpty{false}; //!< Close socket upon tx buffer emptied
bool m_shutdownSend{false}; //!< Send no longer allowed
bool m_shutdownRecv{false}; //!< Receive no longer allowed
bool m_connected{false}; //!< Connection established
double m_msl{0.0}; //!< Max segment lifetime
// Window management
uint16_t m_maxWinSize{0}; //!< Maximum window size to advertise
uint32_t m_bytesAckedNotProcessed{0}; //!< Bytes acked, but not processed
SequenceNumber32 m_highTxAck{0}; //!< Highest ack sent
TracedValue<uint32_t> m_rWnd{0}; //!< Receiver window (RCV.WND in RFC793)
TracedValue<uint32_t> m_advWnd{0}; //!< Advertised Window size
TracedValue<SequenceNumber32> m_highRxMark{0}; //!< Highest seqno received
TracedValue<SequenceNumber32> m_highRxAckMark{0}; //!< Highest ack received
// Options
bool m_sackEnabled{true}; //!< RFC SACK option enabled
bool m_winScalingEnabled{true}; //!< Window Scale option enabled (RFC 7323)
uint8_t m_rcvWindShift{0}; //!< Window shift to apply to outgoing segments
uint8_t m_sndWindShift{0}; //!< Window shift to apply to incoming segments
bool m_timestampEnabled{true}; //!< Timestamp option enabled
uint32_t m_timestampToEcho{0}; //!< Timestamp to echo
EventId m_sendPendingDataEvent{}; //!< micro-delay event to send pending data
// Fast Retransmit and Recovery
SequenceNumber32 m_recover{
0}; //!< Previous highest Tx seqnum for fast recovery (set it to initial seq number)
bool m_recoverActive{false}; //!< Whether "m_recover" has been set/activated
//!< It is used to avoid comparing with the old m_recover value
//!< which was set for handling previous congestion event.
uint32_t m_retxThresh{3}; //!< Fast Retransmit threshold
bool m_limitedTx{true}; //!< perform limited transmit
// Transmission Control Block
Ptr<TcpSocketState> m_tcb; //!< Congestion control information
Ptr<TcpCongestionOps> m_congestionControl; //!< Congestion control
Ptr<TcpRecoveryOps> m_recoveryOps; //!< Recovery Algorithm
Ptr<TcpRateOps> m_rateOps; //!< Rate operations
// Guesses over the other connection end
bool m_isFirstPartialAck{true}; //!< First partial ACK during RECOVERY
// The following three traces pass a packet with a TCP header
TracedCallback<Ptr<const Packet>,
const TcpHeader&,
Ptr<const TcpSocketBase>>
m_txTrace; //!< Trace of transmitted packets
TracedCallback<Ptr<const Packet>,
const TcpHeader&,
const Address&,
const Address&,
Ptr<const TcpSocketBase>>
m_retransmissionTrace; //!< Trace of retransmitted packets
TracedCallback<Ptr<const Packet>,
const TcpHeader&,
Ptr<const TcpSocketBase>>
m_rxTrace; //!< Trace of received packets
// Pacing related variable
Timer m_pacingTimer{Timer::CANCEL_ON_DESTROY}; //!< Pacing Event
// Parameters related to Explicit Congestion Notification
TracedValue<SequenceNumber32> m_ecnEchoSeq{
0}; //!< Sequence number of the last received ECN Echo
TracedValue<SequenceNumber32> m_ecnCESeq{
0}; //!< Sequence number of the last received Congestion Experienced
TracedValue<SequenceNumber32> m_ecnCWRSeq{0}; //!< Sequence number of the last sent CWR
};
/**
* \ingroup tcp
* TracedValue Callback signature for TcpCongState_t
*
* \param [in] oldValue original value of the traced variable
* \param [in] newValue new value of the traced variable
*/
typedef void (*TcpCongStatesTracedValueCallback)(const TcpSocketState::TcpCongState_t oldValue,
const TcpSocketState::TcpCongState_t newValue);
/**
* \ingroup tcp
* TracedValue Callback signature for ECN state trace
*
* \param [in] oldValue original value of the traced variable
* \param [in] newValue new value of the traced variable
*/
typedef void (*EcnStatesTracedValueCallback)(const TcpSocketState::EcnState_t oldValue,
const TcpSocketState::EcnState_t newValue);
} // namespace ns3
#endif /* TCP_SOCKET_BASE_H */