/*
 * Copyright (c) 2016 ResiliNets, ITTC, University of Kansas
 *
 * SPDX-License-Identifier: GPL-2.0-only
 *
 * Author: Truc Anh N. Nguyen <annguyen@ittc.ku.edu>
 *
 * James P.G. Sterbenz <jpgs@ittc.ku.edu>, director
 * ResiliNets Research Group  https://resilinets.org/
 * Information and Telecommunication Technology Center (ITTC)
 * and Department of Electrical Engineering and Computer Science
 * The University of Kansas Lawrence, KS USA.
 */

#ifndef TCPYEAH_H
#define TCPYEAH_H

#include "tcp-recovery-ops.h"
#include "tcp-scalable.h"

namespace ns3
{

/**
 * @ingroup congestionOps
 *
 * @brief An implementation of TCP YeAH
 *
 *  YeAH-TCP (Yet Another HighSpeed TCP) is a heuristic designed to balance various
 *  requirements of a state-of-the-art congestion control algorithm:
 *  1) fully exploit the link capacity of high BDP networks while inducing a small
 *  number of congestion events
 *  2) compete friendly with Reno flows
 *  3) achieve intra and RTT fairness
 *  4) robust to random losses
 *  5) achieve high performance regardless of buffer size
 *
 * YeAH operates between 2 modes: Fast and Slow mode.  In the Fast mode when the
 * queue occupancy is small and the network congestion level is low, YeAH
 * increments its congestion window according to the aggressive STCP rule.
 * When the number of packets in the queue grows beyond a threshold and the
 * network congestion level is high, YeAH enters its Slow mode, acting as Reno
 * with a decongestion algorithm.  YeAH employs Vegas' mechanism for calculating
 * the backlog as in Equation (1).  The estimation of the network congestion
 * level is shown in Equation (2).
 *
 *                      Q = (RTT - BaseRTT) (cwnd / RTT)    (1)
 *                      L = (RTT - BaseRTT) / BaseRTT       (2)
 *
 * To ensure TCP friendliness, YeAH also implements an algorithm to detect the
 * presence of legacy Reno flows. Upon the receipt of 3 duplicate ACKs,
 * YeAH decreases its slow start threshold according to Equation (3) if
 * it's not competing with Reno flows.  Otherwise,  the ssthresh is halved
 * as in Reno.
 *
 *                      ssthresh = min{max{cwnd/8, Q}, cwnd/2}
 *
 * More information: http://www.csc.lsu.edu/~sjpark/cs7601/4-YeAH_TCP.pdf
 */

class TcpYeah : public TcpNewReno
{
  public:
    /**
     * @brief Get the type ID.
     * @return the object TypeId
     */
    static TypeId GetTypeId();

    /**
     * Create an unbound tcp socket.
     */
    TcpYeah();

    /**
     * @brief Copy constructor
     * @param sock the object to copy
     */
    TcpYeah(const TcpYeah& sock);
    ~TcpYeah() override;

    std::string GetName() const override;

    /**
     * @brief Compute RTTs needed to execute YeAH algorithm
     *
     * The function filters RTT samples from the last RTT to find
     * the current smallest propagation delay + queueing delay (minRtt).
     * We take the minimum to avoid the effects of delayed ACKs.
     *
     * The function also min-filters all RTT measurements seen to find the
     * propagation delay (baseRtt).
     *
     * @param tcb internal congestion state
     * @param segmentsAcked count of segments ACKed
     * @param rtt last RTT
     *
     */
    void PktsAcked(Ptr<TcpSocketState> tcb, uint32_t segmentsAcked, const Time& rtt) override;

    /**
     * @brief Enable/disable YeAH algorithm depending on the congestion state
     *
     * We only start a YeAH cycle when we are in normal congestion state (CA_OPEN state).
     *
     * @param tcb internal congestion state
     * @param newState new congestion state to which the TCP is going to switch
     */
    void CongestionStateSet(Ptr<TcpSocketState> tcb,
                            const TcpSocketState::TcpCongState_t newState) override;

    /**
     * @brief Adjust cwnd following YeAH dual-mode algorithm
     *
     * @param tcb internal congestion state
     * @param segmentsAcked count of segments ACKed
     */
    void IncreaseWindow(Ptr<TcpSocketState> tcb, uint32_t segmentsAcked) override;

    /**
     * @brief Get slow start threshold upon the receipt of 3 dupACKs
     *
     * @param tcb internal congestion state
     * @param bytesInFlight number of outstanding bytes
     *
     * @return the slow start threshold value
     */
    uint32_t GetSsThresh(Ptr<const TcpSocketState> tcb, uint32_t bytesInFlight) override;

    Ptr<TcpCongestionOps> Fork() override;

  private:
    /**
     * @brief Enable YeAH algorithm to start taking YeAH samples
     *
     * YeAH algorithm is enabled in the following situations:
     * 1. at the establishment of a connection
     * 2. after an RTO
     * 3. after fast recovery
     * 4. when an idle connection is restarted
     *
     * @param nextTxSequence Sequence to transmit next
     */
    void EnableYeah(const SequenceNumber32& nextTxSequence);

    /**
     * @brief Stop taking YeAH samples
     */
    void DisableYeah();

  private:
    uint32_t m_alpha;   //!< Maximum backlog allowed at the bottleneck queue; Q_max in the paper
    uint32_t m_gamma;   //!< Fraction of queue to be removed per RTT when precautionary decongestion
                        //!< executed
    uint32_t m_delta;   //!< Log minimum fraction of cwnd to be removed on loss
    uint32_t m_epsilon; //!< Log maximum fraction to be removed on early decongestion
    uint32_t m_phy;     //!< Maximum delta from base
    uint32_t m_rho;  //!< Minimum number of consecutive RTT to consider competition with Reno flows
                     //!< on loss
    uint32_t m_zeta; //!< Minimum number of state switches to reset m_renoCount

    uint32_t m_stcpAiFactor;      //!< STCP additive increase parameter
    Ptr<TcpScalable> m_stcp;      //!< TcpScalable object
    Time m_baseRtt;               //!< Minimum of all YeAH RTT measurements seen during connection
    Time m_minRtt;                //!< Minimum of all RTTs measured within last RTT
    uint32_t m_cntRtt;            //!< Number of RTT measurements during last RTT
    bool m_doingYeahNow;          //!< If true, do YeAH for this RTT
    SequenceNumber32 m_begSndNxt; //!< Right edge during last RTT
    uint32_t m_lastQ;             //!< Last number of packets in the bottleneck queue
    uint32_t m_doingRenoNow;      //!< Number of RTTs in "Slow" mode
    uint32_t m_renoCount;         //!< Estimated cwnd of competing Reno flow
    uint32_t m_fastCount;         //!< Number of RTTs in "Fast" mode
};

} // namespace ns3

#endif // TCPYEAH_H
